ReactOS  0.4.14-dev-49-gfb4591c
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, BytesToRead, FilePointer, & Buffer
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  BytesToRead -= BytesToRead;
537  Buffer = (PVOID)((ULONG_PTR)Buffer + (ULONG_PTR)BytesToRead);
538  }
539 
540  return TRUE;
541 }
542 
544 {
545 #if 0
546  return CacheReadDiskSectors(DriveNumber, SectorNumber + Ext2VolumeStartSector, SectorCount, Buffer);
547 #endif
548 
550  ULONG Count;
552 
553  /* Seek to right position */
554  Position.QuadPart = (ULONGLONG)SectorNumber * 512;
555  Status = ArcSeek(Volume->DeviceId, &Position, SeekAbsolute);
556  if (Status != ESUCCESS)
557  {
558  TRACE("Ext2ReadVolumeSectors() Failed to seek\n");
559  return FALSE;
560  }
561 
562  /* Read data */
563  Status = ArcRead(Volume->DeviceId, Buffer, SectorCount * 512, &Count);
564  if (Status != ESUCCESS || Count != SectorCount * 512)
565  {
566  TRACE("Ext2ReadVolumeSectors() Failed to read\n");
567  return FALSE;
568  }
569 
570  /* Return success */
571  return TRUE;
572 }
573 
575 {
576  PEXT2_SUPER_BLOCK SuperBlock = Volume->SuperBlock;
578  ULONG Count;
580 
581  TRACE("Ext2ReadSuperBlock()\n");
582 
583 #if 0
584  /* Free any memory previously allocated */
585  if (SuperBlock != NULL)
586  {
587  FrLdrTempFree(SuperBlock, TAG_EXT_SUPER_BLOCK);
588  SuperBlock = NULL;
589  }
590 #endif
591 
592  /* Allocate the memory to hold the super block if needed */
593  if (SuperBlock == NULL)
594  {
596  if (SuperBlock == NULL)
597  {
598  FileSystemError("Out of memory.");
599  return FALSE;
600  }
601  }
602  Volume->SuperBlock = SuperBlock;
603 
604  /* Reset its contents */
605  RtlZeroMemory(SuperBlock, 1024);
606 
607  /* Read the SuperBlock */
608  Position.QuadPart = 2 * 512;
609  Status = ArcSeek(Volume->DeviceId, &Position, SeekAbsolute);
610  if (Status != ESUCCESS)
611  return FALSE;
612  Status = ArcRead(Volume->DeviceId, SuperBlock, 2 * 512, &Count);
613  if (Status != ESUCCESS || Count != 2 * 512)
614  return FALSE;
615 
616  TRACE("Dumping super block:\n");
617  TRACE("total_inodes: %d\n", SuperBlock->total_inodes);
618  TRACE("total_blocks: %d\n", SuperBlock->total_blocks);
619  TRACE("reserved_blocks: %d\n", SuperBlock->reserved_blocks);
620  TRACE("free_blocks: %d\n", SuperBlock->free_blocks);
621  TRACE("free_inodes: %d\n", SuperBlock->free_inodes);
622  TRACE("first_data_block: %d\n", SuperBlock->first_data_block);
623  TRACE("log2_block_size: %d\n", SuperBlock->log2_block_size);
624  TRACE("log2_fragment_size: %d\n", SuperBlock->log2_fragment_size);
625  TRACE("blocks_per_group: %d\n", SuperBlock->blocks_per_group);
626  TRACE("fragments_per_group: %d\n", SuperBlock->fragments_per_group);
627  TRACE("inodes_per_group: %d\n", SuperBlock->inodes_per_group);
628  TRACE("mtime: %d\n", SuperBlock->mtime);
629  TRACE("utime: %d\n", SuperBlock->utime);
630  TRACE("mnt_count: %d\n", SuperBlock->mnt_count);
631  TRACE("max_mnt_count: %d\n", SuperBlock->max_mnt_count);
632  TRACE("magic: 0x%x\n", SuperBlock->magic);
633  TRACE("fs_state: %d\n", SuperBlock->fs_state);
634  TRACE("error_handling: %d\n", SuperBlock->error_handling);
635  TRACE("minor_revision_level: %d\n", SuperBlock->minor_revision_level);
636  TRACE("lastcheck: %d\n", SuperBlock->lastcheck);
637  TRACE("checkinterval: %d\n", SuperBlock->checkinterval);
638  TRACE("creator_os: %d\n", SuperBlock->creator_os);
639  TRACE("revision_level: %d\n", SuperBlock->revision_level);
640  TRACE("uid_reserved: %d\n", SuperBlock->uid_reserved);
641  TRACE("gid_reserved: %d\n", SuperBlock->gid_reserved);
642  TRACE("first_inode: %d\n", SuperBlock->first_inode);
643  TRACE("inode_size: %d\n", SuperBlock->inode_size);
644  TRACE("block_group_number: %d\n", SuperBlock->block_group_number);
645  TRACE("feature_compatibility: 0x%x\n", SuperBlock->feature_compatibility);
646  TRACE("feature_incompat: 0x%x\n", SuperBlock->feature_incompat);
647  TRACE("feature_ro_compat: 0x%x\n", SuperBlock->feature_ro_compat);
648  TRACE("unique_id = { 0x%x, 0x%x, 0x%x, 0x%x }\n",
649  SuperBlock->unique_id[0], SuperBlock->unique_id[1],
650  SuperBlock->unique_id[2], SuperBlock->unique_id[3]);
651  TRACE("volume_name = '%.16s'\n", SuperBlock->volume_name);
652  TRACE("last_mounted_on = '%.64s'\n", SuperBlock->last_mounted_on);
653  TRACE("compression_info = 0x%x\n", SuperBlock->compression_info);
654 
655  //
656  // Check the super block magic
657  //
658  if (SuperBlock->magic != EXT2_MAGIC)
659  {
660  FileSystemError("Invalid super block magic (0xef53)");
661  return FALSE;
662  }
663 
664  //
665  // Check the revision level
666  //
667  if (SuperBlock->revision_level > EXT2_DYNAMIC_REVISION)
668  {
669  FileSystemError("FreeLoader does not understand the revision of this EXT2/EXT3 filesystem.\nPlease update FreeLoader.");
670  return FALSE;
671  }
672 
673  //
674  // Check the feature set
675  // Don't need to check the compatible or read-only compatible features
676  // because we only mount the filesystem as read-only
677  //
678  if ((SuperBlock->revision_level >= EXT2_DYNAMIC_REVISION) &&
679  (/*((SuperBlock->s_feature_compat & ~EXT3_FEATURE_COMPAT_SUPP) != 0) ||*/
680  /*((SuperBlock->s_feature_ro_compat & ~EXT3_FEATURE_RO_COMPAT_SUPP) != 0) ||*/
681  ((SuperBlock->feature_incompat & ~EXT3_FEATURE_INCOMPAT_SUPP) != 0)))
682  {
683  FileSystemError("FreeLoader does not understand features of this EXT2/EXT3 filesystem.\nPlease update FreeLoader.");
684  return FALSE;
685  }
686 
687  // Calculate the group count
688  Volume->GroupCount = (SuperBlock->total_blocks - SuperBlock->first_data_block + SuperBlock->blocks_per_group - 1) / SuperBlock->blocks_per_group;
689  TRACE("Ext2GroupCount: %d\n", Volume->GroupCount);
690 
691  // Calculate the block size
692  Volume->BlockSizeInBytes = 1024 << SuperBlock->log2_block_size;
693  Volume->BlockSizeInSectors = Volume->BlockSizeInBytes / Volume->BytesPerSector;
694  TRACE("Ext2BlockSizeInBytes: %d\n", Volume->BlockSizeInBytes);
695  TRACE("Ext2BlockSizeInSectors: %d\n", Volume->BlockSizeInSectors);
696 
697  // Calculate the fragment size
698  if (SuperBlock->log2_fragment_size >= 0)
699  {
700  Volume->FragmentSizeInBytes = 1024 << SuperBlock->log2_fragment_size;
701  }
702  else
703  {
704  Volume->FragmentSizeInBytes = 1024 >> -(SuperBlock->log2_fragment_size);
705  }
706  Volume->FragmentSizeInSectors = Volume->FragmentSizeInBytes / Volume->BytesPerSector;
707  TRACE("Ext2FragmentSizeInBytes: %d\n", Volume->FragmentSizeInBytes);
708  TRACE("Ext2FragmentSizeInSectors: %d\n", Volume->FragmentSizeInSectors);
709 
710  // Verify that the fragment size and the block size are equal
711  if (Volume->BlockSizeInBytes != Volume->FragmentSizeInBytes)
712  {
713  FileSystemError("The fragment size must be equal to the block size.");
714  return FALSE;
715  }
716 
717  // Calculate the number of inodes in one block
718  Volume->InodesPerBlock = Volume->BlockSizeInBytes / EXT2_INODE_SIZE(SuperBlock);
719  TRACE("Ext2InodesPerBlock: %d\n", Volume->InodesPerBlock);
720 
721  // Calculate the number of group descriptors in one block
722  Volume->GroupDescPerBlock = EXT2_DESC_PER_BLOCK(SuperBlock);
723  TRACE("Ext2GroupDescPerBlock: %d\n", Volume->GroupDescPerBlock);
724 
725  return TRUE;
726 }
727 
729 {
730  ULONG GroupDescBlockCount;
731  ULONG BlockNumber;
732  PUCHAR CurrentGroupDescBlock;
733 
734  TRACE("Ext2ReadGroupDescriptors()\n");
735 
736  /* Free any memory previously allocated */
737  if (Volume->GroupDescriptors != NULL)
738  {
739  FrLdrTempFree(Volume->GroupDescriptors, TAG_EXT_GROUP_DESC);
740  Volume->GroupDescriptors = NULL;
741  }
742 
743  /* Now allocate the memory to hold the group descriptors */
744  GroupDescBlockCount = ROUND_UP(Volume->GroupCount, Volume->GroupDescPerBlock) / Volume->GroupDescPerBlock;
745  Volume->GroupDescriptors = (PEXT2_GROUP_DESC)FrLdrTempAlloc(GroupDescBlockCount * Volume->BlockSizeInBytes, TAG_EXT_GROUP_DESC);
746  if (Volume->GroupDescriptors == NULL)
747  {
748  FileSystemError("Out of memory.");
749  return FALSE;
750  }
751 
752  // Now read the group descriptors
753  CurrentGroupDescBlock = (PUCHAR)Volume->GroupDescriptors;
754  BlockNumber = Volume->SuperBlock->first_data_block + 1;
755 
756  while (GroupDescBlockCount--)
757  {
758  if (!Ext2ReadBlock(Volume, BlockNumber, CurrentGroupDescBlock))
759  {
760  return FALSE;
761  }
762 
763  BlockNumber++;
764  CurrentGroupDescBlock += Volume->BlockSizeInBytes;
765  }
766 
767  return TRUE;
768 }
769 
770 BOOLEAN Ext2ReadDirectory(PEXT2_VOLUME_INFO Volume, ULONG Inode, PVOID* DirectoryBuffer, PEXT2_INODE InodePointer)
771 {
772  EXT2_FILE_INFO DirectoryFileInfo;
773 
774  TRACE("Ext2ReadDirectory() Inode = %d\n", Inode);
775 
776  // Read the directory inode
777  if (!Ext2ReadInode(Volume, Inode, InodePointer))
778  {
779  return FALSE;
780  }
781 
782  // Make sure it is a directory inode
783  if ((InodePointer->mode & EXT2_S_IFMT) != EXT2_S_IFDIR)
784  {
785  FileSystemError("Inode is not a directory.");
786  return FALSE;
787  }
788 
789  // Fill in file info struct so we can call Ext2ReadFileBig()
790  RtlZeroMemory(&DirectoryFileInfo, sizeof(EXT2_FILE_INFO));
791  DirectoryFileInfo.Volume = Volume;
792  DirectoryFileInfo.FileBlockList = Ext2ReadBlockPointerList(Volume, InodePointer);
793  DirectoryFileInfo.FilePointer = 0;
794  DirectoryFileInfo.FileSize = Ext2GetInodeFileSize(InodePointer);
795 
796  if (DirectoryFileInfo.FileBlockList == NULL)
797  {
798  return FALSE;
799  }
800 
801  //
802  // Now allocate the memory to hold the group descriptors
803  //
804  ASSERT(DirectoryFileInfo.FileSize <= 0xFFFFFFFF);
805  *DirectoryBuffer = (PEXT2_DIR_ENTRY)FrLdrTempAlloc((ULONG)DirectoryFileInfo.FileSize, TAG_EXT_BUFFER);
806 
807  //
808  // Make sure we got the memory
809  //
810  if (*DirectoryBuffer == NULL)
811  {
812  FrLdrTempFree(DirectoryFileInfo.FileBlockList, TAG_EXT_BLOCK_LIST);
813  FileSystemError("Out of memory.");
814  return FALSE;
815  }
816 
817  // Now read the root directory data
818  if (!Ext2ReadFileBig(&DirectoryFileInfo, DirectoryFileInfo.FileSize, NULL, *DirectoryBuffer))
819  {
820  FrLdrTempFree(*DirectoryBuffer, TAG_EXT_BUFFER);
821  *DirectoryBuffer = NULL;
822  FrLdrTempFree(DirectoryFileInfo.FileBlockList, TAG_EXT_BLOCK_LIST);
823  return FALSE;
824  }
825 
826  FrLdrTempFree(DirectoryFileInfo.FileBlockList, TAG_EXT_BLOCK_LIST);
827  return TRUE;
828 }
829 
831 {
832  CHAR ErrorString[80];
833 
834  TRACE("Ext2ReadBlock() BlockNumber = %d Buffer = 0x%x\n", BlockNumber, Buffer);
835 
836  // Make sure its a valid block
837  if (BlockNumber > Volume->SuperBlock->total_blocks)
838  {
839  sprintf(ErrorString, "Error reading block %d - block out of range.", (int) BlockNumber);
840  FileSystemError(ErrorString);
841  return FALSE;
842  }
843 
844  // Check to see if this is a sparse block
845  if (BlockNumber == 0)
846  {
847  TRACE("Block is part of a sparse file. Zeroing input buffer.\n");
848 
849  RtlZeroMemory(Buffer, Volume->BlockSizeInBytes);
850 
851  return TRUE;
852  }
853 
854  return Ext2ReadVolumeSectors(Volume, (ULONGLONG)BlockNumber * Volume->BlockSizeInSectors, Volume->BlockSizeInSectors, Buffer);
855 }
856 
857 /*
858  * Ext2ReadPartialBlock()
859  * Reads part of a block into memory
860  */
862 {
863  PVOID TempBuffer;
864 
865  TRACE("Ext2ReadPartialBlock() BlockNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", BlockNumber, StartingOffset, Length, Buffer);
866 
867  TempBuffer = FrLdrTempAlloc(Volume->BlockSizeInBytes, TAG_EXT_BUFFER);
868 
869  if (!Ext2ReadBlock(Volume, BlockNumber, TempBuffer))
870  {
871  FrLdrTempFree(TempBuffer, TAG_EXT_BUFFER);
872  return FALSE;
873  }
874 
875  memcpy(Buffer, ((PUCHAR)TempBuffer + StartingOffset), Length);
876 
877  FrLdrTempFree(TempBuffer, TAG_EXT_BUFFER);
878 
879  return TRUE;
880 }
881 
882 #if 0
883 ULONG Ext2GetGroupDescBlockNumber(PEXT2_VOLUME_INFO Volume, ULONG Group)
884 {
885  return (((Group * sizeof(EXT2_GROUP_DESC)) / Volume->GroupDescPerBlock) + Volume->SuperBlock->first_data_block + 1);
886 }
887 
888 ULONG Ext2GetGroupDescOffsetInBlock(PEXT2_VOLUME_INFO Volume, ULONG Group)
889 {
890  return ((Group * sizeof(EXT2_GROUP_DESC)) % Volume->GroupDescPerBlock);
891 }
892 #endif
893 
895 {
896  return ((Inode - 1) / Volume->SuperBlock->inodes_per_group);
897 }
898 
900 {
901  return (((Inode - 1) % Volume->SuperBlock->inodes_per_group) / Volume->InodesPerBlock);
902 }
903 
905 {
906  return (((Inode - 1) % Volume->SuperBlock->inodes_per_group) % Volume->InodesPerBlock);
907 }
908 
910 {
911  ULONG InodeGroupNumber;
912  ULONG InodeBlockNumber;
913  ULONG InodeOffsetInBlock;
914  CHAR ErrorString[80];
915  EXT2_GROUP_DESC GroupDescriptor;
916 
917  TRACE("Ext2ReadInode() Inode = %d\n", Inode);
918 
919  // Make sure its a valid inode
920  if ((Inode < 1) || (Inode > Volume->SuperBlock->total_inodes))
921  {
922  sprintf(ErrorString, "Error reading inode %ld - inode out of range.", Inode);
923  FileSystemError(ErrorString);
924  return FALSE;
925  }
926 
927  // Get inode group & block number and offset in block
928  InodeGroupNumber = Ext2GetInodeGroupNumber(Volume, Inode);
929  InodeBlockNumber = Ext2GetInodeBlockNumber(Volume, Inode);
930  InodeOffsetInBlock = Ext2GetInodeOffsetInBlock(Volume, Inode);
931  TRACE("InodeGroupNumber = %d\n", InodeGroupNumber);
932  TRACE("InodeBlockNumber = %d\n", InodeBlockNumber);
933  TRACE("InodeOffsetInBlock = %d\n", InodeOffsetInBlock);
934 
935  // Read the group descriptor
936  if (!Ext2ReadGroupDescriptor(Volume, InodeGroupNumber, &GroupDescriptor))
937  {
938  return FALSE;
939  }
940 
941  // Add the start block of the inode table to the inode block number
942  InodeBlockNumber += GroupDescriptor.inode_table_id;
943  TRACE("InodeBlockNumber (after group desc correction) = %d\n", InodeBlockNumber);
944 
945  // Read the block
947  InodeBlockNumber,
948  (InodeOffsetInBlock * EXT2_INODE_SIZE(Volume->SuperBlock)),
949  sizeof(EXT2_INODE),
950  InodeBuffer))
951  {
952  return FALSE;
953  }
954 
955  TRACE("Dumping inode information:\n");
956  TRACE("mode = 0x%x\n", InodeBuffer->mode);
957  TRACE("uid = %d\n", InodeBuffer->uid);
958  TRACE("size = %d\n", InodeBuffer->size);
959  TRACE("atime = %d\n", InodeBuffer->atime);
960  TRACE("ctime = %d\n", InodeBuffer->ctime);
961  TRACE("mtime = %d\n", InodeBuffer->mtime);
962  TRACE("dtime = %d\n", InodeBuffer->dtime);
963  TRACE("gid = %d\n", InodeBuffer->gid);
964  TRACE("nlinks = %d\n", InodeBuffer->nlinks);
965  TRACE("blockcnt = %d\n", InodeBuffer->blockcnt);
966  TRACE("flags = 0x%x\n", InodeBuffer->flags);
967  TRACE("osd1 = 0x%x\n", InodeBuffer->osd1);
968  TRACE("dir_blocks = { %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u }\n",
969  InodeBuffer->blocks.dir_blocks[0], InodeBuffer->blocks.dir_blocks[1], InodeBuffer->blocks.dir_blocks[ 2], InodeBuffer->blocks.dir_blocks[ 3],
970  InodeBuffer->blocks.dir_blocks[4], InodeBuffer->blocks.dir_blocks[5], InodeBuffer->blocks.dir_blocks[ 6], InodeBuffer->blocks.dir_blocks[ 7],
971  InodeBuffer->blocks.dir_blocks[8], InodeBuffer->blocks.dir_blocks[9], InodeBuffer->blocks.dir_blocks[10], InodeBuffer->blocks.dir_blocks[11]);
972  TRACE("indir_block = %u\n", InodeBuffer->blocks.indir_block);
973  TRACE("double_indir_block = %u\n", InodeBuffer->blocks.double_indir_block);
974  TRACE("tripple_indir_block = %u\n", InodeBuffer->blocks.tripple_indir_block);
975  TRACE("version = %d\n", InodeBuffer->version);
976  TRACE("acl = %d\n", InodeBuffer->acl);
977  TRACE("dir_acl = %d\n", InodeBuffer->dir_acl);
978  TRACE("fragment_addr = %d\n", InodeBuffer->fragment_addr);
979  TRACE("osd2 = { %d, %d, %d }\n",
980  InodeBuffer->osd2[0], InodeBuffer->osd2[1], InodeBuffer->osd2[2]);
981 
982  return TRUE;
983 }
984 
986 {
987  TRACE("Ext2ReadGroupDescriptor()\n");
988 
989 #if 0
990  if (!Ext2ReadBlock(Volume, Ext2GetGroupDescBlockNumber(Volume, Group), (PVOID)FILESYSBUFFER))
991  {
992  return FALSE;
993  }
994  RtlCopyMemory(GroupBuffer, (PVOID)(FILESYSBUFFER + Ext2GetGroupDescOffsetInBlock(Volume, Group)), sizeof(EXT2_GROUP_DESC));
995 #endif
996 
997  RtlCopyMemory(GroupBuffer, &Volume->GroupDescriptors[Group], sizeof(EXT2_GROUP_DESC));
998 
999  TRACE("Dumping group descriptor:\n");
1000  TRACE("block_id = %d\n", GroupBuffer->block_id);
1001  TRACE("inode_id = %d\n", GroupBuffer->inode_id);
1002  TRACE("inode_table_id = %d\n", GroupBuffer->inode_table_id);
1003  TRACE("free_blocks = %d\n", GroupBuffer->free_blocks);
1004  TRACE("free_inodes = %d\n", GroupBuffer->free_inodes);
1005  TRACE("used_dirs = %d\n", GroupBuffer->used_dirs);
1006 
1007  return TRUE;
1008 }
1009 
1011 {
1013  ULONG BlockCount;
1014  ULONG* BlockList;
1015  ULONG CurrentBlockInList;
1016  ULONG CurrentBlock;
1017 
1018  TRACE("Ext2ReadBlockPointerList()\n");
1019 
1020  // Get the number of blocks this file occupies
1021  // I would just use Inode->i_blocks but it
1022  // doesn't seem to be the number of blocks
1023  // the file size corresponds to, but instead
1024  // it is much bigger.
1025  //BlockCount = Inode->i_blocks;
1026  FileSize = Ext2GetInodeFileSize(Inode);
1027  FileSize = ROUND_UP(FileSize, Volume->BlockSizeInBytes);
1028  BlockCount = (ULONG)(FileSize / Volume->BlockSizeInBytes);
1029 
1030  // Allocate the memory for the block list
1031  BlockList = FrLdrTempAlloc(BlockCount * sizeof(ULONG), TAG_EXT_BLOCK_LIST);
1032  if (BlockList == NULL)
1033  {
1034  return NULL;
1035  }
1036 
1037  RtlZeroMemory(BlockList, BlockCount * sizeof(ULONG));
1038 
1039  // Copy the direct block pointers
1040  for (CurrentBlockInList = CurrentBlock = 0;
1041  CurrentBlockInList < BlockCount && CurrentBlock < INDIRECT_BLOCKS;
1042  CurrentBlock++, CurrentBlockInList++)
1043  {
1044  BlockList[CurrentBlockInList] = Inode->blocks.dir_blocks[CurrentBlock];
1045  }
1046 
1047  // Copy the indirect block pointers
1048  if (CurrentBlockInList < BlockCount)
1049  {
1050  if (!Ext2CopyIndirectBlockPointers(Volume, BlockList, &CurrentBlockInList, BlockCount, Inode->blocks.indir_block))
1051  {
1052  FrLdrTempFree(BlockList, TAG_EXT_BLOCK_LIST);
1053  return NULL;
1054  }
1055  }
1056 
1057  // Copy the double indirect block pointers
1058  if (CurrentBlockInList < BlockCount)
1059  {
1060  if (!Ext2CopyDoubleIndirectBlockPointers(Volume, BlockList, &CurrentBlockInList, BlockCount, Inode->blocks.double_indir_block))
1061  {
1062  FrLdrTempFree(BlockList, TAG_EXT_BLOCK_LIST);
1063  return NULL;
1064  }
1065  }
1066 
1067  // Copy the triple indirect block pointers
1068  if (CurrentBlockInList < BlockCount)
1069  {
1070  if (!Ext2CopyTripleIndirectBlockPointers(Volume, BlockList, &CurrentBlockInList, BlockCount, Inode->blocks.tripple_indir_block))
1071  {
1072  FrLdrTempFree(BlockList, TAG_EXT_BLOCK_LIST);
1073  return NULL;
1074  }
1075  }
1076 
1077  return BlockList;
1078 }
1079 
1081 {
1082  if ((Inode->mode & EXT2_S_IFMT) == EXT2_S_IFDIR)
1083  {
1084  return (ULONGLONG)(Inode->size);
1085  }
1086  else
1087  {
1088  return ((ULONGLONG)(Inode->size) | ((ULONGLONG)(Inode->dir_acl) << 32));
1089  }
1090 }
1091 
1092 BOOLEAN Ext2CopyIndirectBlockPointers(PEXT2_VOLUME_INFO Volume, ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG IndirectBlock)
1093 {
1094  ULONG* BlockBuffer;
1095  ULONG CurrentBlock;
1096  ULONG BlockPointersPerBlock;
1097 
1098  TRACE("Ext2CopyIndirectBlockPointers() BlockCount = %d\n", BlockCount);
1099 
1100  BlockPointersPerBlock = Volume->BlockSizeInBytes / sizeof(ULONG);
1101 
1102  BlockBuffer = FrLdrTempAlloc(Volume->BlockSizeInBytes, TAG_EXT_BUFFER);
1103  if (!BlockBuffer)
1104  {
1105  return FALSE;
1106  }
1107 
1108  if (!Ext2ReadBlock(Volume, IndirectBlock, BlockBuffer))
1109  {
1110  return FALSE;
1111  }
1112 
1113  for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++)
1114  {
1115  BlockList[(*CurrentBlockInList)] = BlockBuffer[CurrentBlock];
1116  (*CurrentBlockInList)++;
1117  }
1118 
1119  FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1120 
1121  return TRUE;
1122 }
1123 
1124 BOOLEAN Ext2CopyDoubleIndirectBlockPointers(PEXT2_VOLUME_INFO Volume, ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG DoubleIndirectBlock)
1125 {
1126  ULONG* BlockBuffer;
1127  ULONG CurrentBlock;
1128  ULONG BlockPointersPerBlock;
1129 
1130  TRACE("Ext2CopyDoubleIndirectBlockPointers() BlockCount = %d\n", BlockCount);
1131 
1132  BlockPointersPerBlock = Volume->BlockSizeInBytes / sizeof(ULONG);
1133 
1134  BlockBuffer = (ULONG*)FrLdrTempAlloc(Volume->BlockSizeInBytes, TAG_EXT_BUFFER);
1135  if (BlockBuffer == NULL)
1136  {
1137  return FALSE;
1138  }
1139 
1140  if (!Ext2ReadBlock(Volume, DoubleIndirectBlock, BlockBuffer))
1141  {
1142  FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1143  return FALSE;
1144  }
1145 
1146  for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++)
1147  {
1148  if (!Ext2CopyIndirectBlockPointers(Volume, BlockList, CurrentBlockInList, BlockCount, BlockBuffer[CurrentBlock]))
1149  {
1150  FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1151  return FALSE;
1152  }
1153  }
1154 
1155  FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1156  return TRUE;
1157 }
1158 
1159 BOOLEAN Ext2CopyTripleIndirectBlockPointers(PEXT2_VOLUME_INFO Volume, ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG TripleIndirectBlock)
1160 {
1161  ULONG* BlockBuffer;
1162  ULONG CurrentBlock;
1163  ULONG BlockPointersPerBlock;
1164 
1165  TRACE("Ext2CopyTripleIndirectBlockPointers() BlockCount = %d\n", BlockCount);
1166 
1167  BlockPointersPerBlock = Volume->BlockSizeInBytes / sizeof(ULONG);
1168 
1169  BlockBuffer = (ULONG*)FrLdrTempAlloc(Volume->BlockSizeInBytes, TAG_EXT_BUFFER);
1170  if (BlockBuffer == NULL)
1171  {
1172  return FALSE;
1173  }
1174 
1175  if (!Ext2ReadBlock(Volume, TripleIndirectBlock, BlockBuffer))
1176  {
1177  FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1178  return FALSE;
1179  }
1180 
1181  for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++)
1182  {
1183  if (!Ext2CopyDoubleIndirectBlockPointers(Volume, BlockList, CurrentBlockInList, BlockCount, BlockBuffer[CurrentBlock]))
1184  {
1185  FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1186  return FALSE;
1187  }
1188  }
1189 
1190  FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1191  return TRUE;
1192 }
1193 
1195 {
1198  return ESUCCESS;
1199 }
1200 
1202 {
1204 
1206  Information->EndingAddress.QuadPart = FileHandle->FileSize;
1207  Information->CurrentAddress.QuadPart = FileHandle->FilePointer;
1208 
1209  TRACE("Ext2GetFileInformation(%lu) -> FileSize = %llu, FilePointer = 0x%llx\n",
1210  FileId, Information->EndingAddress.QuadPart, Information->CurrentAddress.QuadPart);
1211 
1212  return ESUCCESS;
1213 }
1214 
1216 {
1219  ULONG DeviceId;
1220 
1221  /* Check parameters */
1222  if (OpenMode != OpenReadOnly)
1223  return EACCES;
1224 
1225  /* Get underlying device */
1226  DeviceId = FsGetDeviceId(*FileId);
1227  Volume = Ext2Volumes[DeviceId];
1228 
1229  TRACE("Ext2Open() FileName = %s\n", Path);
1230 
1231  /* Call the internal open method */
1232  // Status = Ext2OpenFile(Volume, Path, &FileHandle);
1234  if (!FileHandle)
1235  return ENOENT;
1236 
1237  /* Success, remember the handle */
1238  FsSetDeviceSpecific(*FileId, FileHandle);
1239  return ESUCCESS;
1240 }
1241 
1243 {
1245  ULONGLONG BytesReadBig;
1246  BOOLEAN Success;
1247 
1248  //
1249  // Read data
1250  //
1251  Success = Ext2ReadFileBig(FileHandle, N, &BytesReadBig, Buffer);
1252  *Count = (ULONG)BytesReadBig;
1253 
1254  //
1255  // Check for success
1256  //
1257  if (Success)
1258  return ESUCCESS;
1259  else
1260  return EIO;
1261 }
1262 
1264 {
1266  LARGE_INTEGER NewPosition = *Position;
1267 
1268  switch (SeekMode)
1269  {
1270  case SeekAbsolute:
1271  break;
1272  case SeekRelative:
1273  NewPosition.QuadPart += FileHandle->FilePointer;
1274  break;
1275  default:
1276  ASSERT(FALSE);
1277  return EINVAL;
1278  }
1279 
1280  if (NewPosition.QuadPart >= FileHandle->FileSize)
1281  return EINVAL;
1282 
1283  FileHandle->FilePointer = NewPosition.QuadPart;
1284  return ESUCCESS;
1285 }
1286 
1288 {
1289  Ext2Close,
1291  Ext2Open,
1292  Ext2Read,
1293  Ext2Seek,
1294  L"ext2fs",
1295 };
1296 
1297 const DEVVTBL* Ext2Mount(ULONG DeviceId)
1298 {
1300  EXT2_SUPER_BLOCK SuperBlock;
1302  ULONG Count;
1304 
1305  TRACE("Enter Ext2Mount(%lu)\n", DeviceId);
1306 
1307  /* Allocate data for volume information */
1309  if (!Volume)
1310  return NULL;
1312 
1313  /* Read the SuperBlock */
1314  Position.QuadPart = 2 * 512;
1315  Status = ArcSeek(DeviceId, &Position, SeekAbsolute);
1316  if (Status != ESUCCESS)
1317  {
1319  return NULL;
1320  }
1321  Status = ArcRead(DeviceId, &SuperBlock, sizeof(SuperBlock), &Count);
1322  if (Status != ESUCCESS || Count != sizeof(SuperBlock))
1323  {
1325  return NULL;
1326  }
1327 
1328  /* Check if SuperBlock is valid. If yes, return Ext2 function table. */
1329  if (SuperBlock.magic != EXT2_MAGIC)
1330  {
1332  return NULL;
1333  }
1334 
1335  Volume->DeviceId = DeviceId;
1336 
1337  /* Really open the volume */
1338  if (!Ext2OpenVolume(Volume))
1339  {
1341  return NULL;
1342  }
1343 
1344  /* Remember EXT2 volume information */
1345  Ext2Volumes[DeviceId] = Volume;
1346 
1347  /* Return success */
1348  TRACE("Ext2Mount(%lu) success\n", DeviceId);
1349  return &Ext2FuncTable;
1350 }
1351 
1352 #endif
signed char * PCHAR
Definition: retypes.h:7
UCHAR filetype
Definition: ext2.h:163
ULONGLONG FilePointer
Definition: ext2.h:234
ULONG feature_incompat
Definition: ext2.h:100
BOOLEAN Ext2ReadInode(PEXT2_VOLUME_INFO Volume, ULONG Inode, PEXT2_INODE InodeBuffer)
Definition: ext2.c:909
ULONG free_blocks
Definition: ext2.h:74
ULONG BlockSizeInBytes
Definition: ext2.c:53
BOOLEAN Ext2ReadSuperBlock(PEXT2_VOLUME_INFO Volume)
Definition: ext2.c:574
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
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:282
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
struct ext2_sblock * PEXT2_SUPER_BLOCK
Definition: ext2.h:171
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:770
_In_opt_ PSID Group
Definition: rtlfuncs.h:1606
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:1080
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:985
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
_Inout_ __drv_aliasesMem PSLIST_ENTRY _Inout_ PSLIST_ENTRY _In_ ULONG Count
Definition: exfuncs.h:1015
ULONG Ext2GetInodeOffsetInBlock(PEXT2_VOLUME_INFO Volume, ULONG Inode)
Definition: ext2.c:904
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
VOID * FsGetDeviceSpecific(ULONG FileId)
Definition: fs.c:416
BOOLEAN Ext2ReadBlock(PEXT2_VOLUME_INFO Volume, ULONG BlockNumber, PVOID Buffer)
Definition: ext2.c:830
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
PEXT2_GROUP_DESC GroupDescriptors
Definition: ext2.c:51
uint32_t ULONG_PTR
Definition: typedefs.h:63
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
while(1)
Definition: macro.lex.yy.c:740
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
ULONG reserved_blocks
Definition: ext2.h:73
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:1201
ULONGLONG FileSize
Definition: ext2.h:233
_Check_return_ _CRTIMP int __cdecl _strnicmp(_In_reads_or_z_(_MaxCount) const char *_Str1, _In_reads_or_z_(_MaxCount) const char *_Str2, _In_ size_t _MaxCount)
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:177
unsigned char BOOLEAN
USHORT direntlen
Definition: ext2.h:161
ULONG utime
Definition: ext2.h:83
smooth NULL
Definition: ftsmooth.c:416
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
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
#define EXT2_S_IFDIR
Definition: ext2.h:221
ULONG * Ext2ReadBlockPointerList(PEXT2_VOLUME_INFO Volume, PEXT2_INODE Inode)
Definition: ext2.c:1010
ULONG blockcnt
Definition: ext2.h:134
#define EXT2_INODE_SIZE(sb)
Definition: ext2.h:192
ULONG inode_table_id
Definition: ext2.h:114
#define TRACE(s)
Definition: solgame.cpp:4
ULONG revision_level
Definition: ext2.h:93
#define TAG_EXT_BLOCK_LIST
Definition: ext2.c:67
uint64_t ULONGLONG
Definition: typedefs.h:65
ULONG DeviceId
Definition: ext2.c:61
#define EXT2_S_IFMT
Definition: ext2.h:218
struct ext2_dirent * PEXT2_DIR_ENTRY
Definition: ext2.h:174
static const UCHAR Index[8]
Definition: usbohci.c:18
ARC_STATUS Ext2Close(ULONG FileId)
Definition: ext2.c:1194
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:1159
BOOLEAN CacheInitializeDrive(UCHAR DriveNumber)
Definition: cache.c:37
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
#define MAX_FDS
Definition: fs.h:34
USHORT gid_reserved
Definition: ext2.h:95
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
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
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
_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:1215
ULONG SectorCount
Definition: part_xbox.c:32
#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:1124
Status
Definition: gdiplustypes.h:24
ULONG Ext2GetInodeBlockNumber(PEXT2_VOLUME_INFO Volume, ULONG Inode)
Definition: ext2.c:899
BOOLEAN Ext2ReadVolumeSectors(PEXT2_VOLUME_INFO Volume, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer)
Definition: ext2.c:543
ARC_STATUS Ext2Seek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: ext2.c:1263
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:1242
#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:1297
char symlink[60]
Definition: ext2.h:146
struct ext2_inode::@163::datablocks blocks
#define DbgDumpBuffer(mask, buf, len)
Definition: debug.h:118
#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:861
Definition: arc.h:46
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:894
#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:261
#define ULONG_PTR
Definition: config.h:101
#define SECTOR_SIZE
Definition: fs.h:22
const char * PCSTR
Definition: typedefs.h:51
const DEVVTBL Ext2FuncTable
Definition: ext2.c:1287
BOOLEAN Ext2CopyIndirectBlockPointers(PEXT2_VOLUME_INFO Volume, ULONG *BlockList, ULONG *CurrentBlockInList, ULONG BlockCount, ULONG IndirectBlock)
Definition: ext2.c:1092
PEXT2_SUPER_BLOCK SuperBlock
Definition: ext2.c:50
ULONG BlockSizeInSectors
Definition: ext2.c:54
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
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
_Must_inspect_result_ _In_ PFILE_OBJECT _In_opt_ PLARGE_INTEGER _In_ ULONG _In_ FLT_IO_OPERATION_FLAGS _Out_opt_ PULONG BytesRead
Definition: fltkernel.h:1255
ULONG fragments_per_group
Definition: ext2.h:80
USHORT block_group_number
Definition: ext2.h:98
USHORT error_handling
Definition: ext2.h:88
Iosb Information
Definition: create.c:4377
LONGLONG QuadPart
Definition: typedefs.h:112
BOOLEAN Ext2ReadGroupDescriptors(PEXT2_VOLUME_INFO Volume)
Definition: ext2.c:728
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:186