ReactOS  0.4.15-dev-2329-g3ad573f
ext2.c
Go to the documentation of this file.
1 /*
2  * FreeLoader
3  * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 #ifndef _M_ARM
21 #include <freeldr.h>
22 
23 #include <debug.h>
24 DBG_DEFAULT_CHANNEL(FILESYSTEM);
25 
29 BOOLEAN Ext2SearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PEXT2_DIR_ENTRY DirectoryEntry);
31 
35 BOOLEAN Ext2ReadDirectory(PEXT2_VOLUME_INFO Volume, ULONG Inode, PVOID* DirectoryBuffer, PEXT2_INODE InodePointer);
42 BOOLEAN Ext2CopyIndirectBlockPointers(PEXT2_VOLUME_INFO Volume, ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG IndirectBlock);
43 BOOLEAN Ext2CopyDoubleIndirectBlockPointers(PEXT2_VOLUME_INFO Volume, ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG DoubleIndirectBlock);
44 BOOLEAN Ext2CopyTripleIndirectBlockPointers(PEXT2_VOLUME_INFO Volume, ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG TripleIndirectBlock);
45 
46 typedef struct _EXT2_VOLUME_INFO
47 {
48  ULONG BytesPerSector; // Usually 512...
49 
50  PEXT2_SUPER_BLOCK SuperBlock; // Ext2 file system super block
51  PEXT2_GROUP_DESC GroupDescriptors; // Ext2 file system group descriptors
52 
53  ULONG BlockSizeInBytes; // Block size in bytes
54  ULONG BlockSizeInSectors; // Block size in sectors
55  ULONG FragmentSizeInBytes; // Fragment size in bytes
56  ULONG FragmentSizeInSectors; // Fragment size in sectors
57  ULONG GroupCount; // Number of groups in this file system
58  ULONG InodesPerBlock; // Number of inodes in one block
59  ULONG GroupDescPerBlock; // Number of group descriptors in one block
60 
61  ULONG DeviceId; // Ext2 file system device ID
62 
64 
66 
67 #define TAG_EXT_BLOCK_LIST 'LtxE'
68 #define TAG_EXT_FILE 'FtxE'
69 #define TAG_EXT_BUFFER 'BtxE'
70 #define TAG_EXT_SUPER_BLOCK 'StxE'
71 #define TAG_EXT_GROUP_DESC 'GtxE'
72 #define TAG_EXT_VOLUME 'VtxE'
73 
75 {
76  TRACE("Ext2OpenVolume() DeviceId = %d\n", Volume->DeviceId);
77 
78 #if 0
79  /* Initialize the disk cache for this drive */
80  if (!CacheInitializeDrive(DriveNumber))
81  {
82  return FALSE;
83  }
84 #endif
85  Volume->BytesPerSector = SECTOR_SIZE;
86 
87  /* Read in the super block */
89  return FALSE;
90 
91  /* Read in the group descriptors */
93  return FALSE;
94 
95  return TRUE;
96 }
97 
98 /*
99  * Ext2OpenFile()
100  * Tries to open the file 'name' and returns true or false
101  * for success and failure respectively
102  */
104 {
105  EXT2_FILE_INFO TempExt2FileInfo;
107  CHAR SymLinkPath[EXT2_NAME_LEN];
108  CHAR FullPath[EXT2_NAME_LEN * 2];
110 
111  TRACE("Ext2OpenFile() FileName = %s\n", FileName);
112 
113  RtlZeroMemory(SymLinkPath, sizeof(SymLinkPath));
114 
115  // Lookup the file in the file system
116  if (!Ext2LookupFile(Volume, FileName, &TempExt2FileInfo))
117  {
118  return NULL;
119  }
120 
121  // If we got a symbolic link then fix up the path
122  // and re-call this function
123  if ((TempExt2FileInfo.Inode.mode & EXT2_S_IFMT) == EXT2_S_IFLNK)
124  {
125  TRACE("File is a symbolic link\n");
126 
127  // Now read in the symbolic link path
128  if (!Ext2ReadFileBig(&TempExt2FileInfo, TempExt2FileInfo.FileSize, NULL, SymLinkPath))
129  {
130  if (TempExt2FileInfo.FileBlockList != NULL)
131  {
133  }
134 
135  return NULL;
136  }
137 
138  TRACE("Symbolic link path = %s\n", SymLinkPath);
139 
140  // Get the full path
141  if (SymLinkPath[0] == '/' || SymLinkPath[0] == '\\')
142  {
143  // Symbolic link is an absolute path
144  // So copy it to FullPath, but skip over
145  // the '/' char at the beginning
146  strcpy(FullPath, &SymLinkPath[1]);
147  }
148  else
149  {
150  // Symbolic link is a relative path
151  // Copy the first part of the path
152  strcpy(FullPath, FileName);
153 
154  // Remove the last part of the path
155  for (Index=strlen(FullPath); Index>0; )
156  {
157  Index--;
158  if (FullPath[Index] == '/' || FullPath[Index] == '\\')
159  {
160  break;
161  }
162  }
163  FullPath[Index] = '\0';
164 
165  // Concatenate the symbolic link
166  strcat(FullPath, Index == 0 ? "" : "/");
167  strcat(FullPath, SymLinkPath);
168  }
169 
170  TRACE("Full file path = %s\n", FullPath);
171 
172  if (TempExt2FileInfo.FileBlockList != NULL)
173  {
175  }
176 
177  return Ext2OpenFile(Volume, FullPath);
178  }
179  else
180  {
182  if (FileHandle == NULL)
183  {
184  if (TempExt2FileInfo.FileBlockList != NULL)
185  {
187  }
188 
189  return NULL;
190  }
191 
192  RtlCopyMemory(FileHandle, &TempExt2FileInfo, sizeof(EXT2_FILE_INFO));
193 
194  return FileHandle;
195  }
196 }
197 
198 /*
199  * Ext2LookupFile()
200  * This function searches the file system for the
201  * specified filename and fills in a EXT2_FILE_INFO structure
202  * with info describing the file, etc. returns true
203  * if the file exists or false otherwise
204  */
206 {
207  UINT32 i;
208  ULONG NumberOfPathParts;
209  CHAR PathPart[261];
210  PVOID DirectoryBuffer;
211  ULONG DirectoryInode = EXT2_ROOT_INO;
212  EXT2_INODE InodeData;
213  EXT2_DIR_ENTRY DirectoryEntry;
214 
215  TRACE("Ext2LookupFile() FileName = %s\n", FileName);
216 
217  RtlZeroMemory(Ext2FileInfo, sizeof(EXT2_FILE_INFO));
218 
219  //
220  // Figure out how many sub-directories we are nested in
221  //
222  NumberOfPathParts = FsGetNumPathParts(FileName);
223 
224  //
225  // Loop once for each part
226  //
227  for (i=0; i<NumberOfPathParts; i++)
228  {
229  //
230  // Get first path part
231  //
232  FsGetFirstNameFromPath(PathPart, FileName);
233 
234  //
235  // Advance to the next part of the path
236  //
237  for (; (*FileName != '\\') && (*FileName != '/') && (*FileName != '\0'); FileName++)
238  {
239  }
240  FileName++;
241 
242  //
243  // Buffer the directory contents
244  //
245  if (!Ext2ReadDirectory(Volume, DirectoryInode, &DirectoryBuffer, &InodeData))
246  {
247  return FALSE;
248  }
249 
250  //
251  // Search for file name in directory
252  //
253  if (!Ext2SearchDirectoryBufferForFile(DirectoryBuffer, (ULONG)Ext2GetInodeFileSize(&InodeData), PathPart, &DirectoryEntry))
254  {
255  FrLdrTempFree(DirectoryBuffer, TAG_EXT_BUFFER);
256  return FALSE;
257  }
258 
259  FrLdrTempFree(DirectoryBuffer, TAG_EXT_BUFFER);
260 
261  DirectoryInode = DirectoryEntry.inode;
262  }
263 
264  if (!Ext2ReadInode(Volume, DirectoryInode, &InodeData))
265  {
266  return FALSE;
267  }
268 
269  if (((InodeData.mode & EXT2_S_IFMT) != EXT2_S_IFREG) &&
270  ((InodeData.mode & EXT2_S_IFMT) != EXT2_S_IFLNK))
271  {
272  FileSystemError("Inode is not a regular file or symbolic link.");
273  return FALSE;
274  }
275 
276  // Set the associated volume
277  Ext2FileInfo->Volume = Volume;
278 
279  // If it's a regular file or a regular symbolic link
280  // then get the block pointer list otherwise it must
281  // be a fast symbolic link which doesn't have a block list
282  if (((InodeData.mode & EXT2_S_IFMT) == EXT2_S_IFREG) ||
283  ((InodeData.mode & EXT2_S_IFMT) == EXT2_S_IFLNK && InodeData.size > FAST_SYMLINK_MAX_NAME_SIZE))
284  {
285  Ext2FileInfo->FileBlockList = Ext2ReadBlockPointerList(Volume, &InodeData);
286  if (Ext2FileInfo->FileBlockList == NULL)
287  {
288  return FALSE;
289  }
290  }
291  else
292  {
293  Ext2FileInfo->FileBlockList = NULL;
294  }
295 
296  Ext2FileInfo->FilePointer = 0;
297  Ext2FileInfo->FileSize = Ext2GetInodeFileSize(&InodeData);
298  RtlCopyMemory(&Ext2FileInfo->Inode, &InodeData, sizeof(EXT2_INODE));
299 
300  return TRUE;
301 }
302 
303 BOOLEAN Ext2SearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PEXT2_DIR_ENTRY DirectoryEntry)
304 {
305  ULONG CurrentOffset;
306  PEXT2_DIR_ENTRY CurrentDirectoryEntry;
307 
308  TRACE("Ext2SearchDirectoryBufferForFile() DirectoryBuffer = 0x%x DirectorySize = %d FileName = %s\n", DirectoryBuffer, DirectorySize, FileName);
309 
310  for (CurrentOffset=0; CurrentOffset<DirectorySize; )
311  {
312  CurrentDirectoryEntry = (PEXT2_DIR_ENTRY)((ULONG_PTR)DirectoryBuffer + CurrentOffset);
313 
314  if (CurrentDirectoryEntry->direntlen == 0)
315  {
316  break;
317  }
318 
319  if ((CurrentDirectoryEntry->direntlen + CurrentOffset) > DirectorySize)
320  {
321  FileSystemError("Directory entry extends past end of directory file.");
322  return FALSE;
323  }
324 
325  TRACE("Dumping directory entry at offset %d:\n", CurrentOffset);
326  DbgDumpBuffer(DPRINT_FILESYSTEM, CurrentDirectoryEntry, CurrentDirectoryEntry->direntlen);
327 
328  if ((_strnicmp(FileName, CurrentDirectoryEntry->name, CurrentDirectoryEntry->namelen) == 0) &&
329  (strlen(FileName) == CurrentDirectoryEntry->namelen))
330  {
331  RtlCopyMemory(DirectoryEntry, CurrentDirectoryEntry, sizeof(EXT2_DIR_ENTRY));
332 
333  TRACE("EXT2 Directory Entry:\n");
334  TRACE("inode = %d\n", DirectoryEntry->inode);
335  TRACE("direntlen = %d\n", DirectoryEntry->direntlen);
336  TRACE("namelen = %d\n", DirectoryEntry->namelen);
337  TRACE("filetype = %d\n", DirectoryEntry->filetype);
338  TRACE("name = ");
339  for (CurrentOffset=0; CurrentOffset<DirectoryEntry->namelen; CurrentOffset++)
340  {
341  TRACE("%c", DirectoryEntry->name[CurrentOffset]);
342  }
343  TRACE("\n");
344 
345  return TRUE;
346  }
347 
348  CurrentOffset += CurrentDirectoryEntry->direntlen;
349  }
350 
351  return FALSE;
352 }
353 
354 /*
355  * Ext2ReadFileBig()
356  * Reads BytesToRead from open file and
357  * returns the number of bytes read in BytesRead
358  */
360 {
361  PEXT2_VOLUME_INFO Volume = Ext2FileInfo->Volume;
362  ULONG BlockNumber;
363  ULONG BlockNumberIndex;
364  ULONG OffsetInBlock;
365  ULONG LengthInBlock;
366  ULONG NumberOfBlocks;
367 
368  TRACE("Ext2ReadFileBig() BytesToRead = %d Buffer = 0x%x\n", (ULONG)BytesToRead, Buffer);
369 
370  if (BytesRead != NULL)
371  {
372  *BytesRead = 0;
373  }
374 
375  // Make sure we have the block pointer list if we need it
376  if (Ext2FileInfo->FileBlockList == NULL)
377  {
378  // Block pointer list is NULL
379  // so this better be a fast symbolic link or else
380  if (((Ext2FileInfo->Inode.mode & EXT2_S_IFMT) != EXT2_S_IFLNK) ||
381  (Ext2FileInfo->FileSize > FAST_SYMLINK_MAX_NAME_SIZE))
382  {
383  FileSystemError("Block pointer list is NULL and file is not a fast symbolic link.");
384  return FALSE;
385  }
386  }
387 
388  //
389  // If the user is trying to read past the end of
390  // the file then return success with BytesRead == 0.
391  //
392  if (Ext2FileInfo->FilePointer >= Ext2FileInfo->FileSize)
393  {
394  return TRUE;
395  }
396 
397  //
398  // If the user is trying to read more than there is to read
399  // then adjust the amount to read.
400  //
401  if ((Ext2FileInfo->FilePointer + BytesToRead) > Ext2FileInfo->FileSize)
402  {
403  BytesToRead = (Ext2FileInfo->FileSize - Ext2FileInfo->FilePointer);
404  }
405 
406  // Check if this is a fast symbolic link
407  // if so then the read is easy
408  if (((Ext2FileInfo->Inode.mode & EXT2_S_IFMT) == EXT2_S_IFLNK) &&
409  (Ext2FileInfo->FileSize <= FAST_SYMLINK_MAX_NAME_SIZE))
410  {
411  TRACE("Reading fast symbolic link data\n");
412 
413  // Copy the data from the link
414  RtlCopyMemory(Buffer, (PVOID)((ULONG_PTR)Ext2FileInfo->FilePointer + Ext2FileInfo->Inode.symlink), (ULONG)BytesToRead);
415 
416  if (BytesRead != NULL)
417  {
418  *BytesRead = BytesToRead;
419  }
420  // Ext2FileInfo->FilePointer += BytesToRead;
421 
422  return TRUE;
423  }
424 
425  //
426  // Ok, now we have to perform at most 3 calculations
427  // I'll draw you a picture (using nifty ASCII art):
428  //
429  // CurrentFilePointer -+
430  // |
431  // +----------------+
432  // |
433  // +-----------+-----------+-----------+-----------+
434  // | Block 1 | Block 2 | Block 3 | Block 4 |
435  // +-----------+-----------+-----------+-----------+
436  // | |
437  // +---------------+--------------------+
438  // |
439  // BytesToRead -------+
440  //
441  // 1 - The first calculation (and read) will align
442  // the file pointer with the next block.
443  // boundary (if we are supposed to read that much)
444  // 2 - The next calculation (and read) will read
445  // in all the full blocks that the requested
446  // amount of data would cover (in this case
447  // blocks 2 & 3).
448  // 3 - The last calculation (and read) would read
449  // in the remainder of the data requested out of
450  // the last block.
451  //
452 
453  //
454  // Only do the first read if we
455  // aren't aligned on a block boundary
456  //
457  if (Ext2FileInfo->FilePointer % Volume->BlockSizeInBytes)
458  {
459  //
460  // Do the math for our first read
461  //
462  BlockNumberIndex = (ULONG)(Ext2FileInfo->FilePointer / Volume->BlockSizeInBytes);
463  BlockNumber = Ext2FileInfo->FileBlockList[BlockNumberIndex];
464  OffsetInBlock = (Ext2FileInfo->FilePointer % Volume->BlockSizeInBytes);
465  LengthInBlock = (ULONG)((BytesToRead > (Volume->BlockSizeInBytes - OffsetInBlock)) ? (Volume->BlockSizeInBytes - OffsetInBlock) : BytesToRead);
466 
467  //
468  // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
469  //
470  if (!Ext2ReadPartialBlock(Volume, BlockNumber, OffsetInBlock, LengthInBlock, Buffer))
471  {
472  return FALSE;
473  }
474  if (BytesRead != NULL)
475  {
476  *BytesRead += LengthInBlock;
477  }
478  BytesToRead -= LengthInBlock;
479  Ext2FileInfo->FilePointer += LengthInBlock;
480  Buffer = (PVOID)((ULONG_PTR)Buffer + LengthInBlock);
481  }
482 
483  //
484  // Do the math for our second read (if any data left)
485  //
486  if (BytesToRead > 0)
487  {
488  //
489  // Determine how many full clusters we need to read
490  //
491  NumberOfBlocks = (ULONG)(BytesToRead / Volume->BlockSizeInBytes);
492 
493  while (NumberOfBlocks > 0)
494  {
495  BlockNumberIndex = (ULONG)(Ext2FileInfo->FilePointer / Volume->BlockSizeInBytes);
496  BlockNumber = Ext2FileInfo->FileBlockList[BlockNumberIndex];
497 
498  //
499  // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
500  //
501  if (!Ext2ReadBlock(Volume, BlockNumber, Buffer))
502  {
503  return FALSE;
504  }
505  if (BytesRead != NULL)
506  {
507  *BytesRead += Volume->BlockSizeInBytes;
508  }
509  BytesToRead -= Volume->BlockSizeInBytes;
510  Ext2FileInfo->FilePointer += Volume->BlockSizeInBytes;
511  Buffer = (PVOID)((ULONG_PTR)Buffer + Volume->BlockSizeInBytes);
512  NumberOfBlocks--;
513  }
514  }
515 
516  //
517  // Do the math for our third read (if any data left)
518  //
519  if (BytesToRead > 0)
520  {
521  BlockNumberIndex = (ULONG)(Ext2FileInfo->FilePointer / Volume->BlockSizeInBytes);
522  BlockNumber = Ext2FileInfo->FileBlockList[BlockNumberIndex];
523 
524  //
525  // Now do the read and update BytesRead & FilePointer
526  //
527  if (!Ext2ReadPartialBlock(Volume, BlockNumber, 0, (ULONG)BytesToRead, Buffer))
528  {
529  return FALSE;
530  }
531  if (BytesRead != NULL)
532  {
533  *BytesRead += BytesToRead;
534  }
535  Ext2FileInfo->FilePointer += BytesToRead;
536  }
537 
538  return TRUE;
539 }
540 
542 {
543 #if 0
544  return CacheReadDiskSectors(DriveNumber, SectorNumber + Ext2VolumeStartSector, SectorCount, Buffer);
545 #endif
546 
548  ULONG Count;
550 
551  /* Seek to right position */
552  Position.QuadPart = (ULONGLONG)SectorNumber * 512;
553  Status = ArcSeek(Volume->DeviceId, &Position, SeekAbsolute);
554  if (Status != ESUCCESS)
555  {
556  TRACE("Ext2ReadVolumeSectors() Failed to seek\n");
557  return FALSE;
558  }
559 
560  /* Read data */
561  Status = ArcRead(Volume->DeviceId, Buffer, SectorCount * 512, &Count);
562  if (Status != ESUCCESS || Count != SectorCount * 512)
563  {
564  TRACE("Ext2ReadVolumeSectors() Failed to read\n");
565  return FALSE;
566  }
567 
568  /* Return success */
569  return TRUE;
570 }
571 
573 {
574  PEXT2_SUPER_BLOCK SuperBlock = Volume->SuperBlock;
576  ULONG Count;
578 
579  TRACE("Ext2ReadSuperBlock()\n");
580 
581 #if 0
582  /* Free any memory previously allocated */
583  if (SuperBlock != NULL)
584  {
585  FrLdrTempFree(SuperBlock, TAG_EXT_SUPER_BLOCK);
586  SuperBlock = NULL;
587  }
588 #endif
589 
590  /* Allocate the memory to hold the super block if needed */
591  if (SuperBlock == NULL)
592  {
594  if (SuperBlock == NULL)
595  {
596  FileSystemError("Out of memory.");
597  return FALSE;
598  }
599  }
600  Volume->SuperBlock = SuperBlock;
601 
602  /* Reset its contents */
603  RtlZeroMemory(SuperBlock, 1024);
604 
605  /* Read the SuperBlock */
606  Position.QuadPart = 2 * 512;
607  Status = ArcSeek(Volume->DeviceId, &Position, SeekAbsolute);
608  if (Status != ESUCCESS)
609  return FALSE;
610  Status = ArcRead(Volume->DeviceId, SuperBlock, 2 * 512, &Count);
611  if (Status != ESUCCESS || Count != 2 * 512)
612  return FALSE;
613 
614  TRACE("Dumping super block:\n");
615  TRACE("total_inodes: %d\n", SuperBlock->total_inodes);
616  TRACE("total_blocks: %d\n", SuperBlock->total_blocks);
617  TRACE("reserved_blocks: %d\n", SuperBlock->reserved_blocks);
618  TRACE("free_blocks: %d\n", SuperBlock->free_blocks);
619  TRACE("free_inodes: %d\n", SuperBlock->free_inodes);
620  TRACE("first_data_block: %d\n", SuperBlock->first_data_block);
621  TRACE("log2_block_size: %d\n", SuperBlock->log2_block_size);
622  TRACE("log2_fragment_size: %d\n", SuperBlock->log2_fragment_size);
623  TRACE("blocks_per_group: %d\n", SuperBlock->blocks_per_group);
624  TRACE("fragments_per_group: %d\n", SuperBlock->fragments_per_group);
625  TRACE("inodes_per_group: %d\n", SuperBlock->inodes_per_group);
626  TRACE("mtime: %d\n", SuperBlock->mtime);
627  TRACE("utime: %d\n", SuperBlock->utime);
628  TRACE("mnt_count: %d\n", SuperBlock->mnt_count);
629  TRACE("max_mnt_count: %d\n", SuperBlock->max_mnt_count);
630  TRACE("magic: 0x%x\n", SuperBlock->magic);
631  TRACE("fs_state: %d\n", SuperBlock->fs_state);
632  TRACE("error_handling: %d\n", SuperBlock->error_handling);
633  TRACE("minor_revision_level: %d\n", SuperBlock->minor_revision_level);
634  TRACE("lastcheck: %d\n", SuperBlock->lastcheck);
635  TRACE("checkinterval: %d\n", SuperBlock->checkinterval);
636  TRACE("creator_os: %d\n", SuperBlock->creator_os);
637  TRACE("revision_level: %d\n", SuperBlock->revision_level);
638  TRACE("uid_reserved: %d\n", SuperBlock->uid_reserved);
639  TRACE("gid_reserved: %d\n", SuperBlock->gid_reserved);
640  TRACE("first_inode: %d\n", SuperBlock->first_inode);
641  TRACE("inode_size: %d\n", SuperBlock->inode_size);
642  TRACE("block_group_number: %d\n", SuperBlock->block_group_number);
643  TRACE("feature_compatibility: 0x%x\n", SuperBlock->feature_compatibility);
644  TRACE("feature_incompat: 0x%x\n", SuperBlock->feature_incompat);
645  TRACE("feature_ro_compat: 0x%x\n", SuperBlock->feature_ro_compat);
646  TRACE("unique_id = { 0x%x, 0x%x, 0x%x, 0x%x }\n",
647  SuperBlock->unique_id[0], SuperBlock->unique_id[1],
648  SuperBlock->unique_id[2], SuperBlock->unique_id[3]);
649  TRACE("volume_name = '%.16s'\n", SuperBlock->volume_name);
650  TRACE("last_mounted_on = '%.64s'\n", SuperBlock->last_mounted_on);
651  TRACE("compression_info = 0x%x\n", SuperBlock->compression_info);
652 
653  //
654  // Check the super block magic
655  //
656  if (SuperBlock->magic != EXT2_MAGIC)
657  {
658  FileSystemError("Invalid super block magic (0xef53)");
659  return FALSE;
660  }
661 
662  //
663  // Check the revision level
664  //
665  if (SuperBlock->revision_level > EXT2_DYNAMIC_REVISION)
666  {
667  FileSystemError("FreeLoader does not understand the revision of this EXT2/EXT3 filesystem.\nPlease update FreeLoader.");
668  return FALSE;
669  }
670 
671  //
672  // Check the feature set
673  // Don't need to check the compatible or read-only compatible features
674  // because we only mount the filesystem as read-only
675  //
676  if ((SuperBlock->revision_level >= EXT2_DYNAMIC_REVISION) &&
677  (/*((SuperBlock->s_feature_compat & ~EXT3_FEATURE_COMPAT_SUPP) != 0) ||*/
678  /*((SuperBlock->s_feature_ro_compat & ~EXT3_FEATURE_RO_COMPAT_SUPP) != 0) ||*/
679  ((SuperBlock->feature_incompat & ~EXT3_FEATURE_INCOMPAT_SUPP) != 0)))
680  {
681  FileSystemError("FreeLoader does not understand features of this EXT2/EXT3 filesystem.\nPlease update FreeLoader.");
682  return FALSE;
683  }
684 
685  // Calculate the group count
686  Volume->GroupCount = (SuperBlock->total_blocks - SuperBlock->first_data_block + SuperBlock->blocks_per_group - 1) / SuperBlock->blocks_per_group;
687  TRACE("Ext2GroupCount: %d\n", Volume->GroupCount);
688 
689  // Calculate the block size
690  Volume->BlockSizeInBytes = 1024 << SuperBlock->log2_block_size;
691  Volume->BlockSizeInSectors = Volume->BlockSizeInBytes / Volume->BytesPerSector;
692  TRACE("Ext2BlockSizeInBytes: %d\n", Volume->BlockSizeInBytes);
693  TRACE("Ext2BlockSizeInSectors: %d\n", Volume->BlockSizeInSectors);
694 
695  // Calculate the fragment size
696  if (SuperBlock->log2_fragment_size >= 0)
697  {
698  Volume->FragmentSizeInBytes = 1024 << SuperBlock->log2_fragment_size;
699  }
700  else
701  {
702  Volume->FragmentSizeInBytes = 1024 >> -(SuperBlock->log2_fragment_size);
703  }
704  Volume->FragmentSizeInSectors = Volume->FragmentSizeInBytes / Volume->BytesPerSector;
705  TRACE("Ext2FragmentSizeInBytes: %d\n", Volume->FragmentSizeInBytes);
706  TRACE("Ext2FragmentSizeInSectors: %d\n", Volume->FragmentSizeInSectors);
707 
708  // Verify that the fragment size and the block size are equal
709  if (Volume->BlockSizeInBytes != Volume->FragmentSizeInBytes)
710  {
711  FileSystemError("The fragment size must be equal to the block size.");
712  return FALSE;
713  }
714 
715  // Calculate the number of inodes in one block
716  Volume->InodesPerBlock = Volume->BlockSizeInBytes / EXT2_INODE_SIZE(SuperBlock);
717  TRACE("Ext2InodesPerBlock: %d\n", Volume->InodesPerBlock);
718 
719  // Calculate the number of group descriptors in one block
720  Volume->GroupDescPerBlock = EXT2_DESC_PER_BLOCK(SuperBlock);
721  TRACE("Ext2GroupDescPerBlock: %d\n", Volume->GroupDescPerBlock);
722 
723  return TRUE;
724 }
725 
727 {
728  ULONG GroupDescBlockCount;
729  ULONG BlockNumber;
730  PUCHAR CurrentGroupDescBlock;
731 
732  TRACE("Ext2ReadGroupDescriptors()\n");
733 
734  /* Free any memory previously allocated */
735  if (Volume->GroupDescriptors != NULL)
736  {
737  FrLdrTempFree(Volume->GroupDescriptors, TAG_EXT_GROUP_DESC);
738  Volume->GroupDescriptors = NULL;
739  }
740 
741  /* Now allocate the memory to hold the group descriptors */
742  GroupDescBlockCount = ROUND_UP(Volume->GroupCount, Volume->GroupDescPerBlock) / Volume->GroupDescPerBlock;
743  Volume->GroupDescriptors = (PEXT2_GROUP_DESC)FrLdrTempAlloc(GroupDescBlockCount * Volume->BlockSizeInBytes, TAG_EXT_GROUP_DESC);
744  if (Volume->GroupDescriptors == NULL)
745  {
746  FileSystemError("Out of memory.");
747  return FALSE;
748  }
749 
750  // Now read the group descriptors
751  CurrentGroupDescBlock = (PUCHAR)Volume->GroupDescriptors;
752  BlockNumber = Volume->SuperBlock->first_data_block + 1;
753 
754  while (GroupDescBlockCount--)
755  {
756  if (!Ext2ReadBlock(Volume, BlockNumber, CurrentGroupDescBlock))
757  {
758  return FALSE;
759  }
760 
761  BlockNumber++;
762  CurrentGroupDescBlock += Volume->BlockSizeInBytes;
763  }
764 
765  return TRUE;
766 }
767 
768 BOOLEAN Ext2ReadDirectory(PEXT2_VOLUME_INFO Volume, ULONG Inode, PVOID* DirectoryBuffer, PEXT2_INODE InodePointer)
769 {
770  EXT2_FILE_INFO DirectoryFileInfo;
771 
772  TRACE("Ext2ReadDirectory() Inode = %d\n", Inode);
773 
774  // Read the directory inode
775  if (!Ext2ReadInode(Volume, Inode, InodePointer))
776  {
777  return FALSE;
778  }
779 
780  // Make sure it is a directory inode
781  if ((InodePointer->mode & EXT2_S_IFMT) != EXT2_S_IFDIR)
782  {
783  FileSystemError("Inode is not a directory.");
784  return FALSE;
785  }
786 
787  // Fill in file info struct so we can call Ext2ReadFileBig()
788  RtlZeroMemory(&DirectoryFileInfo, sizeof(EXT2_FILE_INFO));
789  DirectoryFileInfo.Volume = Volume;
790  DirectoryFileInfo.FileBlockList = Ext2ReadBlockPointerList(Volume, InodePointer);
791  DirectoryFileInfo.FilePointer = 0;
792  DirectoryFileInfo.FileSize = Ext2GetInodeFileSize(InodePointer);
793 
794  if (DirectoryFileInfo.FileBlockList == NULL)
795  {
796  return FALSE;
797  }
798 
799  //
800  // Now allocate the memory to hold the group descriptors
801  //
802  ASSERT(DirectoryFileInfo.FileSize <= 0xFFFFFFFF);
803  *DirectoryBuffer = (PEXT2_DIR_ENTRY)FrLdrTempAlloc((ULONG)DirectoryFileInfo.FileSize, TAG_EXT_BUFFER);
804 
805  //
806  // Make sure we got the memory
807  //
808  if (*DirectoryBuffer == NULL)
809  {
810  FrLdrTempFree(DirectoryFileInfo.FileBlockList, TAG_EXT_BLOCK_LIST);
811  FileSystemError("Out of memory.");
812  return FALSE;
813  }
814 
815  // Now read the root directory data
816  if (!Ext2ReadFileBig(&DirectoryFileInfo, DirectoryFileInfo.FileSize, NULL, *DirectoryBuffer))
817  {
818  FrLdrTempFree(*DirectoryBuffer, TAG_EXT_BUFFER);
819  *DirectoryBuffer = NULL;
820  FrLdrTempFree(DirectoryFileInfo.FileBlockList, TAG_EXT_BLOCK_LIST);
821  return FALSE;
822  }
823 
824  FrLdrTempFree(DirectoryFileInfo.FileBlockList, TAG_EXT_BLOCK_LIST);
825  return TRUE;
826 }
827 
829 {
830  CHAR ErrorString[80];
831 
832  TRACE("Ext2ReadBlock() BlockNumber = %d Buffer = 0x%x\n", BlockNumber, Buffer);
833 
834  // Make sure its a valid block
835  if (BlockNumber > Volume->SuperBlock->total_blocks)
836  {
837  sprintf(ErrorString, "Error reading block %d - block out of range.", (int) BlockNumber);
838  FileSystemError(ErrorString);
839  return FALSE;
840  }
841 
842  // Check to see if this is a sparse block
843  if (BlockNumber == 0)
844  {
845  TRACE("Block is part of a sparse file. Zeroing input buffer.\n");
846 
847  RtlZeroMemory(Buffer, Volume->BlockSizeInBytes);
848 
849  return TRUE;
850  }
851 
852  return Ext2ReadVolumeSectors(Volume, (ULONGLONG)BlockNumber * Volume->BlockSizeInSectors, Volume->BlockSizeInSectors, Buffer);
853 }
854 
855 /*
856  * Ext2ReadPartialBlock()
857  * Reads part of a block into memory
858  */
860 {
861  PVOID TempBuffer;
862 
863  TRACE("Ext2ReadPartialBlock() BlockNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", BlockNumber, StartingOffset, Length, Buffer);
864 
865  TempBuffer = FrLdrTempAlloc(Volume->BlockSizeInBytes, TAG_EXT_BUFFER);
866 
867  if (!Ext2ReadBlock(Volume, BlockNumber, TempBuffer))
868  {
869  FrLdrTempFree(TempBuffer, TAG_EXT_BUFFER);
870  return FALSE;
871  }
872 
873  RtlCopyMemory(Buffer, ((PUCHAR)TempBuffer + StartingOffset), Length);
874 
875  FrLdrTempFree(TempBuffer, TAG_EXT_BUFFER);
876 
877  return TRUE;
878 }
879 
880 #if 0
881 ULONG Ext2GetGroupDescBlockNumber(PEXT2_VOLUME_INFO Volume, ULONG Group)
882 {
883  return (((Group * sizeof(EXT2_GROUP_DESC)) / Volume->GroupDescPerBlock) + Volume->SuperBlock->first_data_block + 1);
884 }
885 
886 ULONG Ext2GetGroupDescOffsetInBlock(PEXT2_VOLUME_INFO Volume, ULONG Group)
887 {
888  return ((Group * sizeof(EXT2_GROUP_DESC)) % Volume->GroupDescPerBlock);
889 }
890 #endif
891 
893 {
894  return ((Inode - 1) / Volume->SuperBlock->inodes_per_group);
895 }
896 
898 {
899  return (((Inode - 1) % Volume->SuperBlock->inodes_per_group) / Volume->InodesPerBlock);
900 }
901 
903 {
904  return (((Inode - 1) % Volume->SuperBlock->inodes_per_group) % Volume->InodesPerBlock);
905 }
906 
908 {
909  ULONG InodeGroupNumber;
910  ULONG InodeBlockNumber;
911  ULONG InodeOffsetInBlock;
912  CHAR ErrorString[80];
913  EXT2_GROUP_DESC GroupDescriptor;
914 
915  TRACE("Ext2ReadInode() Inode = %d\n", Inode);
916 
917  // Make sure its a valid inode
918  if ((Inode < 1) || (Inode > Volume->SuperBlock->total_inodes))
919  {
920  sprintf(ErrorString, "Error reading inode %ld - inode out of range.", Inode);
921  FileSystemError(ErrorString);
922  return FALSE;
923  }
924 
925  // Get inode group & block number and offset in block
926  InodeGroupNumber = Ext2GetInodeGroupNumber(Volume, Inode);
927  InodeBlockNumber = Ext2GetInodeBlockNumber(Volume, Inode);
928  InodeOffsetInBlock = Ext2GetInodeOffsetInBlock(Volume, Inode);
929  TRACE("InodeGroupNumber = %d\n", InodeGroupNumber);
930  TRACE("InodeBlockNumber = %d\n", InodeBlockNumber);
931  TRACE("InodeOffsetInBlock = %d\n", InodeOffsetInBlock);
932 
933  // Read the group descriptor
934  if (!Ext2ReadGroupDescriptor(Volume, InodeGroupNumber, &GroupDescriptor))
935  {
936  return FALSE;
937  }
938 
939  // Add the start block of the inode table to the inode block number
940  InodeBlockNumber += GroupDescriptor.inode_table_id;
941  TRACE("InodeBlockNumber (after group desc correction) = %d\n", InodeBlockNumber);
942 
943  // Read the block
945  InodeBlockNumber,
946  (InodeOffsetInBlock * EXT2_INODE_SIZE(Volume->SuperBlock)),
947  sizeof(EXT2_INODE),
948  InodeBuffer))
949  {
950  return FALSE;
951  }
952 
953  TRACE("Dumping inode information:\n");
954  TRACE("mode = 0x%x\n", InodeBuffer->mode);
955  TRACE("uid = %d\n", InodeBuffer->uid);
956  TRACE("size = %d\n", InodeBuffer->size);
957  TRACE("atime = %d\n", InodeBuffer->atime);
958  TRACE("ctime = %d\n", InodeBuffer->ctime);
959  TRACE("mtime = %d\n", InodeBuffer->mtime);
960  TRACE("dtime = %d\n", InodeBuffer->dtime);
961  TRACE("gid = %d\n", InodeBuffer->gid);
962  TRACE("nlinks = %d\n", InodeBuffer->nlinks);
963  TRACE("blockcnt = %d\n", InodeBuffer->blockcnt);
964  TRACE("flags = 0x%x\n", InodeBuffer->flags);
965  TRACE("osd1 = 0x%x\n", InodeBuffer->osd1);
966  TRACE("dir_blocks = { %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u }\n",
967  InodeBuffer->blocks.dir_blocks[0], InodeBuffer->blocks.dir_blocks[1], InodeBuffer->blocks.dir_blocks[ 2], InodeBuffer->blocks.dir_blocks[ 3],
968  InodeBuffer->blocks.dir_blocks[4], InodeBuffer->blocks.dir_blocks[5], InodeBuffer->blocks.dir_blocks[ 6], InodeBuffer->blocks.dir_blocks[ 7],
969  InodeBuffer->blocks.dir_blocks[8], InodeBuffer->blocks.dir_blocks[9], InodeBuffer->blocks.dir_blocks[10], InodeBuffer->blocks.dir_blocks[11]);
970  TRACE("indir_block = %u\n", InodeBuffer->blocks.indir_block);
971  TRACE("double_indir_block = %u\n", InodeBuffer->blocks.double_indir_block);
972  TRACE("tripple_indir_block = %u\n", InodeBuffer->blocks.tripple_indir_block);
973  TRACE("version = %d\n", InodeBuffer->version);
974  TRACE("acl = %d\n", InodeBuffer->acl);
975  TRACE("dir_acl = %d\n", InodeBuffer->dir_acl);
976  TRACE("fragment_addr = %d\n", InodeBuffer->fragment_addr);
977  TRACE("osd2 = { %d, %d, %d }\n",
978  InodeBuffer->osd2[0], InodeBuffer->osd2[1], InodeBuffer->osd2[2]);
979 
980  return TRUE;
981 }
982 
984 {
985  TRACE("Ext2ReadGroupDescriptor()\n");
986 
987 #if 0
988  if (!Ext2ReadBlock(Volume, Ext2GetGroupDescBlockNumber(Volume, Group), (PVOID)FILESYSBUFFER))
989  {
990  return FALSE;
991  }
992  RtlCopyMemory(GroupBuffer, (PVOID)(FILESYSBUFFER + Ext2GetGroupDescOffsetInBlock(Volume, Group)), sizeof(EXT2_GROUP_DESC));
993 #endif
994 
995  RtlCopyMemory(GroupBuffer, &Volume->GroupDescriptors[Group], sizeof(EXT2_GROUP_DESC));
996 
997  TRACE("Dumping group descriptor:\n");
998  TRACE("block_id = %d\n", GroupBuffer->block_id);
999  TRACE("inode_id = %d\n", GroupBuffer->inode_id);
1000  TRACE("inode_table_id = %d\n", GroupBuffer->inode_table_id);
1001  TRACE("free_blocks = %d\n", GroupBuffer->free_blocks);
1002  TRACE("free_inodes = %d\n", GroupBuffer->free_inodes);
1003  TRACE("used_dirs = %d\n", GroupBuffer->used_dirs);
1004 
1005  return TRUE;
1006 }
1007 
1009 {
1011  ULONG BlockCount;
1012  ULONG* BlockList;
1013  ULONG CurrentBlockInList;
1014  ULONG CurrentBlock;
1015 
1016  TRACE("Ext2ReadBlockPointerList()\n");
1017 
1018  // Get the number of blocks this file occupies
1019  // I would just use Inode->i_blocks but it
1020  // doesn't seem to be the number of blocks
1021  // the file size corresponds to, but instead
1022  // it is much bigger.
1023  //BlockCount = Inode->i_blocks;
1024  FileSize = Ext2GetInodeFileSize(Inode);
1025  FileSize = ROUND_UP(FileSize, Volume->BlockSizeInBytes);
1026  BlockCount = (ULONG)(FileSize / Volume->BlockSizeInBytes);
1027 
1028  // Allocate the memory for the block list
1029  BlockList = FrLdrTempAlloc(BlockCount * sizeof(ULONG), TAG_EXT_BLOCK_LIST);
1030  if (BlockList == NULL)
1031  {
1032  return NULL;
1033  }
1034 
1035  RtlZeroMemory(BlockList, BlockCount * sizeof(ULONG));
1036 
1037  // Copy the direct block pointers
1038  for (CurrentBlockInList = CurrentBlock = 0;
1039  CurrentBlockInList < BlockCount && CurrentBlock < INDIRECT_BLOCKS;
1040  CurrentBlock++, CurrentBlockInList++)
1041  {
1042  BlockList[CurrentBlockInList] = Inode->blocks.dir_blocks[CurrentBlock];
1043  }
1044 
1045  // Copy the indirect block pointers
1046  if (CurrentBlockInList < BlockCount)
1047  {
1048  if (!Ext2CopyIndirectBlockPointers(Volume, BlockList, &CurrentBlockInList, BlockCount, Inode->blocks.indir_block))
1049  {
1050  FrLdrTempFree(BlockList, TAG_EXT_BLOCK_LIST);
1051  return NULL;
1052  }
1053  }
1054 
1055  // Copy the double indirect block pointers
1056  if (CurrentBlockInList < BlockCount)
1057  {
1058  if (!Ext2CopyDoubleIndirectBlockPointers(Volume, BlockList, &CurrentBlockInList, BlockCount, Inode->blocks.double_indir_block))
1059  {
1060  FrLdrTempFree(BlockList, TAG_EXT_BLOCK_LIST);
1061  return NULL;
1062  }
1063  }
1064 
1065  // Copy the triple indirect block pointers
1066  if (CurrentBlockInList < BlockCount)
1067  {
1068  if (!Ext2CopyTripleIndirectBlockPointers(Volume, BlockList, &CurrentBlockInList, BlockCount, Inode->blocks.tripple_indir_block))
1069  {
1070  FrLdrTempFree(BlockList, TAG_EXT_BLOCK_LIST);
1071  return NULL;
1072  }
1073  }
1074 
1075  return BlockList;
1076 }
1077 
1079 {
1080  if ((Inode->mode & EXT2_S_IFMT) == EXT2_S_IFDIR)
1081  {
1082  return (ULONGLONG)(Inode->size);
1083  }
1084  else
1085  {
1086  return ((ULONGLONG)(Inode->size) | ((ULONGLONG)(Inode->dir_acl) << 32));
1087  }
1088 }
1089 
1090 BOOLEAN Ext2CopyIndirectBlockPointers(PEXT2_VOLUME_INFO Volume, ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG IndirectBlock)
1091 {
1092  ULONG* BlockBuffer;
1093  ULONG CurrentBlock;
1094  ULONG BlockPointersPerBlock;
1095 
1096  TRACE("Ext2CopyIndirectBlockPointers() BlockCount = %d\n", BlockCount);
1097 
1098  BlockPointersPerBlock = Volume->BlockSizeInBytes / sizeof(ULONG);
1099 
1100  BlockBuffer = FrLdrTempAlloc(Volume->BlockSizeInBytes, TAG_EXT_BUFFER);
1101  if (!BlockBuffer)
1102  {
1103  return FALSE;
1104  }
1105 
1106  if (!Ext2ReadBlock(Volume, IndirectBlock, BlockBuffer))
1107  {
1108  return FALSE;
1109  }
1110 
1111  for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++)
1112  {
1113  BlockList[(*CurrentBlockInList)] = BlockBuffer[CurrentBlock];
1114  (*CurrentBlockInList)++;
1115  }
1116 
1117  FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1118 
1119  return TRUE;
1120 }
1121 
1122 BOOLEAN Ext2CopyDoubleIndirectBlockPointers(PEXT2_VOLUME_INFO Volume, ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG DoubleIndirectBlock)
1123 {
1124  ULONG* BlockBuffer;
1125  ULONG CurrentBlock;
1126  ULONG BlockPointersPerBlock;
1127 
1128  TRACE("Ext2CopyDoubleIndirectBlockPointers() BlockCount = %d\n", BlockCount);
1129 
1130  BlockPointersPerBlock = Volume->BlockSizeInBytes / sizeof(ULONG);
1131 
1132  BlockBuffer = (ULONG*)FrLdrTempAlloc(Volume->BlockSizeInBytes, TAG_EXT_BUFFER);
1133  if (BlockBuffer == NULL)
1134  {
1135  return FALSE;
1136  }
1137 
1138  if (!Ext2ReadBlock(Volume, DoubleIndirectBlock, BlockBuffer))
1139  {
1140  FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1141  return FALSE;
1142  }
1143 
1144  for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++)
1145  {
1146  if (!Ext2CopyIndirectBlockPointers(Volume, BlockList, CurrentBlockInList, BlockCount, BlockBuffer[CurrentBlock]))
1147  {
1148  FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1149  return FALSE;
1150  }
1151  }
1152 
1153  FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1154  return TRUE;
1155 }
1156 
1157 BOOLEAN Ext2CopyTripleIndirectBlockPointers(PEXT2_VOLUME_INFO Volume, ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG TripleIndirectBlock)
1158 {
1159  ULONG* BlockBuffer;
1160  ULONG CurrentBlock;
1161  ULONG BlockPointersPerBlock;
1162 
1163  TRACE("Ext2CopyTripleIndirectBlockPointers() BlockCount = %d\n", BlockCount);
1164 
1165  BlockPointersPerBlock = Volume->BlockSizeInBytes / sizeof(ULONG);
1166 
1167  BlockBuffer = (ULONG*)FrLdrTempAlloc(Volume->BlockSizeInBytes, TAG_EXT_BUFFER);
1168  if (BlockBuffer == NULL)
1169  {
1170  return FALSE;
1171  }
1172 
1173  if (!Ext2ReadBlock(Volume, TripleIndirectBlock, BlockBuffer))
1174  {
1175  FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1176  return FALSE;
1177  }
1178 
1179  for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++)
1180  {
1181  if (!Ext2CopyDoubleIndirectBlockPointers(Volume, BlockList, CurrentBlockInList, BlockCount, BlockBuffer[CurrentBlock]))
1182  {
1183  FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1184  return FALSE;
1185  }
1186  }
1187 
1188  FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1189  return TRUE;
1190 }
1191 
1193 {
1196  return ESUCCESS;
1197 }
1198 
1200 {
1202 
1204  Information->EndingAddress.QuadPart = FileHandle->FileSize;
1205  Information->CurrentAddress.QuadPart = FileHandle->FilePointer;
1206 
1207  TRACE("Ext2GetFileInformation(%lu) -> FileSize = %llu, FilePointer = 0x%llx\n",
1208  FileId, Information->EndingAddress.QuadPart, Information->CurrentAddress.QuadPart);
1209 
1210  return ESUCCESS;
1211 }
1212 
1214 {
1217  ULONG DeviceId;
1218 
1219  /* Check parameters */
1220  if (OpenMode != OpenReadOnly)
1221  return EACCES;
1222 
1223  /* Get underlying device */
1224  DeviceId = FsGetDeviceId(*FileId);
1225  Volume = Ext2Volumes[DeviceId];
1226 
1227  TRACE("Ext2Open() FileName = %s\n", Path);
1228 
1229  /* Call the internal open method */
1230  // Status = Ext2OpenFile(Volume, Path, &FileHandle);
1232  if (!FileHandle)
1233  return ENOENT;
1234 
1235  /* Success, remember the handle */
1236  FsSetDeviceSpecific(*FileId, FileHandle);
1237  return ESUCCESS;
1238 }
1239 
1241 {
1243  ULONGLONG BytesReadBig;
1244  BOOLEAN Success;
1245 
1246  //
1247  // Read data
1248  //
1249  Success = Ext2ReadFileBig(FileHandle, N, &BytesReadBig, Buffer);
1250  *Count = (ULONG)BytesReadBig;
1251 
1252  //
1253  // Check for success
1254  //
1255  if (Success)
1256  return ESUCCESS;
1257  else
1258  return EIO;
1259 }
1260 
1262 {
1264  LARGE_INTEGER NewPosition = *Position;
1265 
1266  switch (SeekMode)
1267  {
1268  case SeekAbsolute:
1269  break;
1270  case SeekRelative:
1271  NewPosition.QuadPart += FileHandle->FilePointer;
1272  break;
1273  default:
1274  ASSERT(FALSE);
1275  return EINVAL;
1276  }
1277 
1278  if (NewPosition.QuadPart >= FileHandle->FileSize)
1279  return EINVAL;
1280 
1281  FileHandle->FilePointer = NewPosition.QuadPart;
1282  return ESUCCESS;
1283 }
1284 
1286 {
1287  Ext2Close,
1289  Ext2Open,
1290  Ext2Read,
1291  Ext2Seek,
1292  L"ext2fs",
1293 };
1294 
1295 const DEVVTBL* Ext2Mount(ULONG DeviceId)
1296 {
1298  EXT2_SUPER_BLOCK SuperBlock;
1300  ULONG Count;
1302 
1303  TRACE("Enter Ext2Mount(%lu)\n", DeviceId);
1304 
1305  /* Allocate data for volume information */
1307  if (!Volume)
1308  return NULL;
1310 
1311  /* Read the SuperBlock */
1312  Position.QuadPart = 2 * 512;
1313  Status = ArcSeek(DeviceId, &Position, SeekAbsolute);
1314  if (Status != ESUCCESS)
1315  {
1317  return NULL;
1318  }
1319  Status = ArcRead(DeviceId, &SuperBlock, sizeof(SuperBlock), &Count);
1320  if (Status != ESUCCESS || Count != sizeof(SuperBlock))
1321  {
1323  return NULL;
1324  }
1325 
1326  /* Check if SuperBlock is valid. If yes, return Ext2 function table. */
1327  if (SuperBlock.magic != EXT2_MAGIC)
1328  {
1330  return NULL;
1331  }
1332 
1333  Volume->DeviceId = DeviceId;
1334 
1335  /* Really open the volume */
1336  if (!Ext2OpenVolume(Volume))
1337  {
1339  return NULL;
1340  }
1341 
1342  /* Remember EXT2 volume information */
1343  Ext2Volumes[DeviceId] = Volume;
1344 
1345  /* Return success */
1346  TRACE("Ext2Mount(%lu) success\n", DeviceId);
1347  return &Ext2FuncTable;
1348 }
1349 
1350 #endif
signed char * PCHAR
Definition: retypes.h:7
UCHAR filetype
Definition: ext2.h:163
ULONGLONG FilePointer
Definition: ext2.h:234
while(CdLookupNextInitialFileDirent(IrpContext, Fcb, FileContext))
ULONG feature_incompat
Definition: ext2.h:100
BOOLEAN Ext2ReadInode(PEXT2_VOLUME_INFO Volume, ULONG Inode, PEXT2_INODE InodeBuffer)
Definition: ext2.c:907
ULONG free_blocks
Definition: ext2.h:74
ULONG BlockSizeInBytes
Definition: ext2.c:53
BOOLEAN Ext2ReadSuperBlock(PEXT2_VOLUME_INFO Volume)
Definition: ext2.c:572
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
ULONG * FileBlockList
Definition: ext2.h:235
USHORT uid_reserved
Definition: ext2.h:94
#define ROUND_UP(n, align)
Definition: eventvwr.h:31
USHORT inode_size
Definition: ext2.h:97
VOID FsGetFirstNameFromPath(PCHAR Buffer, PCSTR Path)
Definition: fs.c:356
BOOLEAN Ext2ReadFileBig(PEXT2_FILE_INFO Ext2FileInfo, ULONGLONG BytesToRead, ULONGLONG *BytesRead, PVOID Buffer)
Definition: ext2.c:359
_In_ PFCB _In_ LONGLONG StartingOffset
Definition: cdprocs.h:290
BOOLEAN Ext2LookupFile(PEXT2_VOLUME_INFO Volume, PCSTR FileName, PEXT2_FILE_INFO Ext2FileInfo)
Definition: ext2.c:205
ULONG mtime
Definition: ext2.h:130
ULONG first_inode
Definition: ext2.h:96
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
#define EXT2_S_IFLNK
Definition: ext2.h:224
USHORT fs_state
Definition: ext2.h:87
ULONG atime
Definition: ext2.h:128
ULONG checkinterval
Definition: ext2.h:91
ULONG block_id
Definition: ext2.h:112
ULONG inode_id
Definition: ext2.h:113
Definition: arc.h:32
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
struct ext2_sblock * PEXT2_SUPER_BLOCK
Definition: ext2.h:171
#define TRUE
Definition: types.h:120
USHORT free_inodes
Definition: ext2.h:116
ULONG fragment_addr
Definition: ext2.h:151
Definition: arc.h:39
ULONG dtime
Definition: ext2.h:131
#define EXT3_FEATURE_INCOMPAT_SUPP
Definition: ext2.h:180
BOOLEAN Ext2ReadDirectory(PEXT2_VOLUME_INFO Volume, ULONG Inode, PVOID *DirectoryBuffer, PEXT2_INODE InodePointer)
Definition: ext2.c:768
_In_opt_ PSID Group
Definition: rtlfuncs.h:1605
static COORD Position
Definition: mouse.c:34
unsigned char * PUCHAR
Definition: retypes.h:3
char CHAR
Definition: xmlstorage.h:175
ULONGLONG Ext2GetInodeFileSize(PEXT2_INODE Inode)
Definition: ext2.c:1078
ULONG feature_ro_compat
Definition: ext2.h:101
UCHAR namelen
Definition: ext2.h:162
ULONG BytesPerSector
Definition: ext2.c:48
Definition: fs.h:24
BOOLEAN Ext2ReadGroupDescriptor(PEXT2_VOLUME_INFO Volume, ULONG Group, PEXT2_GROUP_DESC GroupBuffer)
Definition: ext2.c:983
struct ext2_block_group * PEXT2_GROUP_DESC
Definition: ext2.h:173
EXT2_INODE Inode
Definition: ext2.h:236
ULONG FsGetNumPathParts(PCSTR Path)
Definition: fs.c:328
#define TAG_EXT_BUFFER
Definition: ext2.c:69
ULONG Ext2GetInodeOffsetInBlock(PEXT2_VOLUME_INFO Volume, ULONG Inode)
Definition: ext2.c:902
ULONG inode
Definition: ext2.h:160
ULONG ARC_STATUS
Definition: arc.h:4
#define INDIRECT_BLOCKS
Definition: ext2.h:45
#define FAST_SYMLINK_MAX_NAME_SIZE
Definition: ext2.h:227
ULONG dir_acl
Definition: ext2.h:150
USHORT uid
Definition: ext2.h:126
USHORT max_mnt_count
Definition: ext2.h:85
ULONG free_inodes
Definition: ext2.h:75
ULONG unique_id[4]
Definition: ext2.h:102
ULONG total_inodes
Definition: ext2.h:71
ULONG mtime
Definition: ext2.h:82
_In_ WDFREQUEST _In_ NTSTATUS _In_ ULONG_PTR Information
Definition: wdfrequest.h:1044
VOID * FsGetDeviceSpecific(ULONG FileId)
Definition: fs.c:416
BOOLEAN Ext2ReadBlock(PEXT2_VOLUME_INFO Volume, ULONG BlockNumber, PVOID Buffer)
Definition: ext2.c:828
ULONG feature_compatibility
Definition: ext2.h:99
ULONG acl
Definition: ext2.h:149
ULONG GroupCount
Definition: ext2.c:57
char volume_name[16]
Definition: ext2.h:103
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR _In_opt_ PLONGLONG _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_opt_ PULONG_PTR BytesRead
Definition: wdfiotarget.h:859
PEXT2_GROUP_DESC GroupDescriptors
Definition: ext2.c:51
uint32_t ULONG_PTR
Definition: typedefs.h:65
struct _EXT2_VOLUME_INFO EXT2_VOLUME_INFO
ULONG ctime
Definition: ext2.h:129
#define EXT2_MAGIC
Definition: ext2.h:43
#define sprintf(buf, format,...)
Definition: sprintf.c:55
USHORT gid
Definition: ext2.h:132
PEXT2_VOLUME_INFO Volume
Definition: ext2.h:237
HANDLE FileHandle
Definition: stats.c:38
ULONG size
Definition: ext2.h:127
ULONG reserved_blocks
Definition: ext2.h:73
#define FALSE
Definition: types.h:117
unsigned int UINT32
BOOLEAN CacheReadDiskSectors(UCHAR DiskNumber, ULONGLONG StartSector, ULONG SectorCount, PVOID Buffer)
Definition: cache.c:113
VOID FileSystemError(PCSTR ErrorString)
Definition: fs.c:259
ULONG compression_info
Definition: ext2.h:105
ARC_STATUS Ext2GetFileInformation(ULONG FileId, FILEINFORMATION *Information)
Definition: ext2.c:1199
ULONGLONG FileSize
Definition: ext2.h:233
ULONG version
Definition: ext2.h:148
BOOLEAN Ext2SearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PEXT2_DIR_ENTRY DirectoryEntry)
Definition: ext2.c:303
FORCEINLINE PVOID FrLdrTempAlloc(_In_ SIZE_T Size, _In_ ULONG Tag)
Definition: mm.h:182
unsigned char BOOLEAN
USHORT direntlen
Definition: ext2.h:161
ULONG utime
Definition: ext2.h:83
PEXT2_FILE_INFO Ext2OpenFile(PEXT2_VOLUME_INFO Volume, PCSTR FileName)
Definition: ext2.c:103
enum _SEEKMODE SEEKMODE
Definition: bufpool.h:45
void * PVOID
Definition: retypes.h:9
USHORT magic
Definition: ext2.h:86
ULONG flags
Definition: ext2.h:135
struct ext2_inode::@161::datablocks blocks
DBG_DEFAULT_CHANNEL(FILESYSTEM)
ULONG log2_block_size
Definition: ext2.h:77
#define EXT2_ROOT_INO
Definition: ext2.h:177
USHORT mnt_count
Definition: ext2.h:84
Status
Definition: gdiplustypes.h:24
#define EXT2_S_IFDIR
Definition: ext2.h:221
ULONG * Ext2ReadBlockPointerList(PEXT2_VOLUME_INFO Volume, PEXT2_INODE Inode)
Definition: ext2.c:1008
ULONG blockcnt
Definition: ext2.h:134
#define EXT2_INODE_SIZE(sb)
Definition: ext2.h:192
int Count
Definition: noreturn.cpp:7
ULONG inode_table_id
Definition: ext2.h:114
#define TRACE(s)
Definition: solgame.cpp:4
ULONG revision_level
Definition: ext2.h:93
#define ASSERT(a)
Definition: mode.c:45
#define TAG_EXT_BLOCK_LIST
Definition: ext2.c:67
_In_ WDFCOLLECTION _In_ ULONG Index
uint64_t ULONGLONG
Definition: typedefs.h:67
ULONG DeviceId
Definition: ext2.c:61
#define EXT2_S_IFMT
Definition: ext2.h:218
struct ext2_dirent * PEXT2_DIR_ENTRY
Definition: ext2.h:174
ARC_STATUS Ext2Close(ULONG FileId)
Definition: ext2.c:1192
VOID FsSetDeviceSpecific(ULONG FileId, VOID *Specific)
Definition: fs.c:409
ULONG osd2[3]
Definition: ext2.h:152
#define DPRINT_FILESYSTEM
Definition: debug.h:26
ULONG first_data_block
Definition: ext2.h:76
BOOLEAN Ext2CopyTripleIndirectBlockPointers(PEXT2_VOLUME_INFO Volume, ULONG *BlockList, ULONG *CurrentBlockInList, ULONG BlockCount, ULONG TripleIndirectBlock)
Definition: ext2.c:1157
#define _strnicmp(_String1, _String2, _MaxCount)
Definition: compat.h:23
BOOLEAN CacheInitializeDrive(UCHAR DriveNumber)
Definition: cache.c:37
#define MAX_FDS
Definition: fs.h:34
USHORT gid_reserved
Definition: ext2.h:95
ARC_STATUS ArcRead(ULONG FileId, VOID *Buffer, ULONG N, ULONG *Count)
Definition: fs.c:236
#define EXT2_DESC_PER_BLOCK(s)
Definition: ext2.h:196
Definition: arc.h:34
ULONG blocks_per_group
Definition: ext2.h:79
static const WCHAR L[]
Definition: oid.c:1250
#define EXT2_NAME_LEN
Definition: ext2.h:156
ARC_STATUS ArcSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: fs.c:243
ULONG InodesPerBlock
Definition: ext2.c:58
_Must_inspect_result_ _Out_ PLARGE_INTEGER FileSize
Definition: fsrtlfuncs.h:108
USHORT free_blocks
Definition: ext2.h:115
char last_mounted_on[64]
Definition: ext2.h:104
ARC_STATUS Ext2Open(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
Definition: ext2.c:1213
ULONG SectorCount
Definition: part_xbox.c:31
#define EXT2_S_IFREG
Definition: ext2.h:223
ULONG GroupDescPerBlock
Definition: ext2.c:59
BOOLEAN Ext2CopyDoubleIndirectBlockPointers(PEXT2_VOLUME_INFO Volume, ULONG *BlockList, ULONG *CurrentBlockInList, ULONG BlockCount, ULONG DoubleIndirectBlock)
Definition: ext2.c:1122
ULONG Ext2GetInodeBlockNumber(PEXT2_VOLUME_INFO Volume, ULONG Inode)
Definition: ext2.c:897
BOOLEAN Ext2ReadVolumeSectors(PEXT2_VOLUME_INFO Volume, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer)
Definition: ext2.c:541
ARC_STATUS Ext2Seek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: ext2.c:1261
ULONG FragmentSizeInBytes
Definition: ext2.c:55
ULONG FragmentSizeInSectors
Definition: ext2.c:56
PRTL_UNICODE_STRING_BUFFER Path
ARC_STATUS Ext2Read(ULONG FileId, VOID *Buffer, ULONG N, ULONG *Count)
Definition: ext2.c:1240
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define TAG_EXT_FILE
Definition: ext2.c:68
ULONG total_blocks
Definition: ext2.h:72
USHORT nlinks
Definition: ext2.h:133
const DEVVTBL * Ext2Mount(ULONG DeviceId)
Definition: ext2.c:1295
char symlink[60]
Definition: ext2.h:146
#define DbgDumpBuffer(mask, buf, len)
Definition: debug.h:119
#define TAG_EXT_SUPER_BLOCK
Definition: ext2.c:70
BOOLEAN Ext2ReadPartialBlock(PEXT2_VOLUME_INFO Volume, ULONG BlockNumber, ULONG StartingOffset, ULONG Length, PVOID Buffer)
Definition: ext2.c:859
Definition: arc.h:46
#define NULL
Definition: types.h:112
CHAR name[EXT2_NAME_LEN]
Definition: ext2.h:164
USHORT mode
Definition: ext2.h:125
Definition: arc.h:40
ULONG osd1
Definition: ext2.h:136
#define EXT2_DYNAMIC_REVISION
Definition: ext2.h:53
ULONG Ext2GetInodeGroupNumber(PEXT2_VOLUME_INFO Volume, ULONG Inode)
Definition: ext2.c:892
#define TAG_EXT_VOLUME
Definition: ext2.c:72
USHORT used_dirs
Definition: ext2.h:117
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
ULONG FsGetDeviceId(ULONG FileId)
Definition: fs.c:423
ULONG lastcheck
Definition: ext2.h:90
PEXT2_VOLUME_INFO Ext2Volumes[MAX_FDS]
Definition: ext2.c:65
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define SECTOR_SIZE
Definition: fs.h:22
const char * PCSTR
Definition: typedefs.h:52
const DEVVTBL Ext2FuncTable
Definition: ext2.c:1285
BOOLEAN Ext2CopyIndirectBlockPointers(PEXT2_VOLUME_INFO Volume, ULONG *BlockList, ULONG *CurrentBlockInList, ULONG BlockCount, ULONG IndirectBlock)
Definition: ext2.c:1090
PEXT2_SUPER_BLOCK SuperBlock
Definition: ext2.c:50
ULONG BlockSizeInSectors
Definition: ext2.c:54
ULONG inodes_per_group
Definition: ext2.h:81
ULONG creator_os
Definition: ext2.h:92
enum _OPENMODE OPENMODE
LONG log2_fragment_size
Definition: ext2.h:78
ULONG fragments_per_group
Definition: ext2.h:80
USHORT block_group_number
Definition: ext2.h:98
USHORT error_handling
Definition: ext2.h:88
LONGLONG QuadPart
Definition: typedefs.h:114
BOOLEAN Ext2ReadGroupDescriptors(PEXT2_VOLUME_INFO Volume)
Definition: ext2.c:726
USHORT minor_revision_level
Definition: ext2.h:89
BOOLEAN Ext2OpenVolume(PEXT2_VOLUME_INFO Volume)
Definition: ext2.c:74
#define TAG_EXT_GROUP_DESC
Definition: ext2.c:71
FORCEINLINE VOID FrLdrTempFree(PVOID Allocation, ULONG Tag)
Definition: mm.h:191