The Pedigree Project  0.1
Iso9660Filesystem.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "Iso9660Filesystem.h"
21 #include "Iso9660Directory.h"
22 #include "Iso9660File.h"
23 #include "iso9660.h"
24 #include "modules/Module.h"
25 #include "modules/system/vfs/File.h"
26 #include "modules/system/vfs/VFS.h"
27 #include "pedigree/kernel/Log.h"
28 #include "pedigree/kernel/machine/Disk.h"
29 #include "pedigree/kernel/utilities/StaticString.h"
30 #include "pedigree/kernel/utilities/utility.h"
31 
32 String WideToMultiByteStr(uint8_t *in, size_t inLen, size_t maxLen)
33 {
35  ret.clear();
36 
37  while ((*in || in[1]) && (inLen > 0) && (maxLen > 0))
38  {
39  uint16_t c = (*in << 8) | in[1];
40  if (c > 0x7f)
41  {
43  }
44  else
45  ret.append(static_cast<char>(c));
46 
47  in += 2;
48  inLen--;
49  }
50  ret.append('\0');
51 
52  return String(ret);
53 }
54 
55 Iso9660Filesystem::Iso9660Filesystem()
56  : m_pDisk(0), m_PrimaryVolDesc(), m_SuppVolDesc(), m_VolDesc(),
57  m_RootDir(0), m_JolietLevel(0), m_BlockSize(0), m_BlockNumber(0),
58  m_VolumeLabel(""), m_pRoot(0)
59 {
60 }
61 
62 Iso9660Filesystem::~Iso9660Filesystem()
63 {
64 }
65 
67 {
68  m_pDisk = pDisk;
69 
71  m_BlockSize = 2048;
72  m_BlockNumber = 0;
73 
74  // Read volume descriptors until the primary one is found
75  // Sector 16 is the first sector on the disk
76  bool bFound = false;
77  for (size_t i = 16; i < 256; i++)
78  {
79  uintptr_t buff = m_pDisk->read(i * m_BlockSize);
80 
81  // Get the descriptor for this entry
83  reinterpret_cast<Iso9660VolumeDescriptor *>(buff);
84  if (StringCompareN(
85  reinterpret_cast<const char *>(vDesc->Ident), "CD001", 5) != 0)
86  {
87  NOTICE("IDENT: " << reinterpret_cast<const char *>(vDesc->Ident));
88  return false;
89  }
90 
91  // Is this a primary descriptor?
92  if (vDesc->Type == PRIM_VOL_DESC)
93  {
94  MemoryCopy(
95  &m_PrimaryVolDesc, reinterpret_cast<uint8_t *>(buff),
97  bFound = true;
98  }
99  else if (vDesc->Type == SUPP_VOL_DESC)
100  {
101  MemoryCopy(
102  &m_SuppVolDesc, reinterpret_cast<uint8_t *>(buff),
104  bFound = true;
105 
106  // Figure out the Joliet level
107  if (m_SuppVolDesc.Unused3_EscSequences[0] == 0x25 &&
108  m_SuppVolDesc.Unused3_EscSequences[1] == 0x2F)
109  {
110  if (m_SuppVolDesc.Unused3_EscSequences[2] == 0x40)
111  m_JolietLevel = 1;
112  else if (m_SuppVolDesc.Unused3_EscSequences[2] == 0x43)
113  m_JolietLevel = 2;
114  else if (m_SuppVolDesc.Unused3_EscSequences[2] == 0x45)
115  m_JolietLevel = 3;
116  else
117  NOTICE("No Joliet level found");
118  }
119  else
120  NOTICE("Not handling Joliet level");
121  }
122  else if (vDesc->Type == TERM_VOL_DESC)
123  break;
124  }
125 
126  if (!bFound)
127  {
128  WARNING("ISO9660: Neither a primary or supplementary volume descriptor "
129  "was found");
130  return false;
131  }
132 
133  if (m_JolietLevel)
134  {
135  // In this case, the supplementary descriptor is actually the main one
136  m_PrimaryVolDesc = m_SuppVolDesc;
137  }
138 
139  // Grab the volume label, properly trimmed
140  char *volLabel = new char[32];
141  MemoryCopy(volLabel, m_PrimaryVolDesc.VolIdent, 32);
142  if (m_JolietLevel)
143  {
144  String volLabelString =
145  WideToMultiByteStr(reinterpret_cast<uint8_t *>(volLabel), 32, 32);
146  NormalStaticString str;
147  str.append(volLabelString);
148 
149  size_t i;
150  for (i = str.length() - 1; static_cast<int32_t>(i) >= 0; i--)
151  if (str[i] != ' ')
152  break;
153  str = str.left(i + 1);
154  m_VolumeLabel = String(str);
155  }
156  else
157  {
158  for (size_t i = 31; static_cast<int32_t>(i) >= 0; i--)
159  {
160  if (volLabel[i] != ' ')
161  {
162  volLabel[i + 1] = 0;
163  break;
164  }
165  }
166  m_VolumeLabel = String(volLabel);
167  }
168 
169  if (m_VolumeLabel.length() == 0)
170  {
171  // no volume label found, do a default
172  NormalStaticString str;
173  str += "no-volume-label@";
174  str.append(reinterpret_cast<uintptr_t>(this), 16);
175  m_VolumeLabel.assign(str, str.length(), true);
176  }
177 
178  delete[] volLabel;
179 
180  m_RootDir =
181  reinterpret_cast<Iso9660DirRecord *>(m_PrimaryVolDesc.RootDirRecord);
182  m_pRoot = fileFromDirRecord(*m_RootDir, 1, 0, true);
183 
184  m_bReadOnly = true;
185 
186  return true;
187 }
188 
189 Filesystem *Iso9660Filesystem::probe(Disk *pDisk)
190 {
192  if (!pFs->initialise(pDisk))
193  {
194  delete pFs;
195  return 0;
196  }
197  else
198  {
199  return pFs;
200  }
201 }
202 
204 {
205  return m_pRoot;
206 }
207 
209 {
210  return m_VolumeLabel;
211 }
212 
213 uintptr_t Iso9660Filesystem::readBlock(File *pFile, uint64_t location)
214 {
215  // Sanity check.
216  if (pFile->isDirectory())
217  return 0;
218 
219  Iso9660File *file = reinterpret_cast<Iso9660File *>(pFile);
220  Iso9660DirRecord rec = file->getDirRecord();
221 
222  // Attempting to read past the EOF?
223  if (location > pFile->getSize())
224  return 0; // Impossible
225 
226  size_t blockSkip = location / m_BlockSize;
227  size_t blockNum = LITTLE_TO_HOST32(rec.ExtentLocation_LE) + blockSkip;
228 
229  // Begin reading
230  uintptr_t buff = m_pDisk->read(blockNum * m_BlockSize);
231 
232  return buff;
233 }
234 
236  File *parent, const String &filename, uint32_t mask)
237 {
238  return false;
239 }
240 
242  File *parent, const String &filename, uint32_t mask)
243 {
244  return false;
245 }
246 
248  File *parent, const String &filename, const String &value)
249 {
250  return false;
251 }
252 
253 bool Iso9660Filesystem::remove(File *parent, File *file)
254 {
255  return false;
256 }
257 
258 String Iso9660Filesystem::parseName(Iso9660DirRecord &dirRecord)
259 {
260  if (m_JolietLevel)
261  return parseJolietName(dirRecord);
262 
263  NormalStaticString ret;
264  ret.clear();
265 
266  // ISO9660 maximum name length is 31 bytes
267  uint8_t *fileIdent = reinterpret_cast<uint8_t *>(
268  adjust_pointer(&dirRecord, sizeof(dirRecord)));
269  size_t len = (dirRecord.FileIdentLen < 31) ? dirRecord.FileIdentLen : 31;
270  size_t i;
271  for (i = 0; i < len; i++)
272  {
273  if (fileIdent[i] == ';')
274  break;
275  else
276  ret.append(toLower(static_cast<char>(fileIdent[i])));
277  }
278 
279  if (i && (fileIdent[i - 1] == '.'))
280  ret.stripLast();
281  ret.append('\0');
282 
283  return String(ret);
284 }
285 
286 String Iso9660Filesystem::parseJolietName(Iso9660DirRecord &name)
287 {
288  uint8_t *fileIdent =
289  reinterpret_cast<uint8_t *>(adjust_pointer(&name, sizeof(name)));
290  String s = WideToMultiByteStr(fileIdent, name.FileIdentLen >> 1, 64);
291  NormalStaticString str;
292  str.append(s);
293  size_t len = str.length();
294 
295  if ((len > 2) && (str[len - 2] == ';') && (str[len - 1] == '1'))
296  len -= 2;
297 
298  while (len >= 2 && (str[len - 1] == '.'))
299  len--;
300  str = str.left(len);
301 
302  return String(str);
303 }
304 
305 File *Iso9660Filesystem::fileFromDirRecord(
306  Iso9660DirRecord &dir, size_t inodeNum, File *parent, bool bDirectory)
307 {
308  String fileName = parseName(dir);
309  Time::Timestamp t = timeToUnix(dir.Time);
310  if (bDirectory)
311  {
313  fileName, inodeNum, this, parent, dir, t, t, t);
314  return ret;
315  }
316  else
317  {
318  Iso9660File *ret = new Iso9660File(
319  fileName, t, t, t, inodeNum, this, LITTLE_TO_HOST32(dir.DataLen_LE),
320  dir, parent);
321  return ret;
322  }
323 }
324 
325 static bool initIso9660()
326 {
327  VFS::instance().addProbeCallback(&Iso9660Filesystem::probe);
328  return true;
329 }
330 
331 static void destroyIso9660()
332 {
333 }
334 
335 MODULE_INFO("iso9660", &initIso9660, &destroyIso9660, "vfs");
virtual bool createSymlink(File *parent, const String &filename, const String &value)
virtual bool createDirectory(File *parent, const String &filename, uint32_t mask)
Iso9660File(const Iso9660File &)
virtual String getVolumeLabel() const
virtual bool remove(File *parent, File *file)
Definition: String.h:49
void addProbeCallback(Filesystem::ProbeCallback callback)
Definition: VFS.cc:298
virtual bool initialise(Disk *pDisk)
static VFS & instance()
Definition: VFS.cc:56
Definition: Disk.h:32
#define WARNING(text)
Definition: Log.h:78
#define NOTICE(text)
Definition: Log.h:74
virtual bool createFile(File *parent, const String &filename, uint32_t mask)
virtual File * getRoot() const
virtual bool isDirectory()
Definition: File.cc:436
Definition: File.h:66