3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
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.
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.
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.
24 DBG_DEFAULT_CHANNEL(FILESYSTEM
);
26 BOOLEAN
Ext2OpenVolume(UCHAR DriveNumber
, ULONGLONG VolumeStartSector
, ULONGLONG PartitionSectorCount
);
27 PEXT2_FILE_INFO
Ext2OpenFile(PCSTR FileName
);
28 BOOLEAN
Ext2LookupFile(PCSTR FileName
, PEXT2_FILE_INFO Ext2FileInfoPointer
);
29 BOOLEAN
Ext2SearchDirectoryBufferForFile(PVOID DirectoryBuffer
, ULONG DirectorySize
, PCHAR FileName
, PEXT2_DIR_ENTRY DirectoryEntry
);
30 BOOLEAN
Ext2ReadVolumeSectors(UCHAR DriveNumber
, ULONGLONG SectorNumber
, ULONG SectorCount
, PVOID Buffer
);
32 BOOLEAN
Ext2ReadFileBig(PEXT2_FILE_INFO Ext2FileInfo
, ULONGLONG BytesToRead
, ULONGLONG
* BytesRead
, PVOID Buffer
);
33 BOOLEAN
Ext2ReadSuperBlock(VOID
);
34 BOOLEAN
Ext2ReadGroupDescriptors(VOID
);
35 BOOLEAN
Ext2ReadDirectory(ULONG Inode
, PVOID
* DirectoryBuffer
, PEXT2_INODE InodePointer
);
36 BOOLEAN
Ext2ReadBlock(ULONG BlockNumber
, PVOID Buffer
);
37 BOOLEAN
Ext2ReadPartialBlock(ULONG BlockNumber
, ULONG StartingOffset
, ULONG Length
, PVOID Buffer
);
38 ULONG
Ext2GetGroupDescBlockNumber(ULONG Group
);
39 ULONG
Ext2GetGroupDescOffsetInBlock(ULONG Group
);
40 ULONG
Ext2GetInodeGroupNumber(ULONG Inode
);
41 ULONG
Ext2GetInodeBlockNumber(ULONG Inode
);
42 ULONG
Ext2GetInodeOffsetInBlock(ULONG Inode
);
43 BOOLEAN
Ext2ReadInode(ULONG Inode
, PEXT2_INODE InodeBuffer
);
44 BOOLEAN
Ext2ReadGroupDescriptor(ULONG Group
, PEXT2_GROUP_DESC GroupBuffer
);
45 ULONG
* Ext2ReadBlockPointerList(PEXT2_INODE Inode
);
46 ULONGLONG
Ext2GetInodeFileSize(PEXT2_INODE Inode
);
47 BOOLEAN
Ext2CopyIndirectBlockPointers(ULONG
* BlockList
, ULONG
* CurrentBlockInList
, ULONG BlockCount
, ULONG IndirectBlock
);
48 BOOLEAN
Ext2CopyDoubleIndirectBlockPointers(ULONG
* BlockList
, ULONG
* CurrentBlockInList
, ULONG BlockCount
, ULONG DoubleIndirectBlock
);
49 BOOLEAN
Ext2CopyTripleIndirectBlockPointers(ULONG
* BlockList
, ULONG
* CurrentBlockInList
, ULONG BlockCount
, ULONG TripleIndirectBlock
);
51 GEOMETRY Ext2DiskGeometry
; // Ext2 file system disk geometry
53 PEXT2_SUPER_BLOCK Ext2SuperBlock
= NULL
; // Ext2 file system super block
54 PEXT2_GROUP_DESC Ext2GroupDescriptors
= NULL
; // Ext2 file system group descriptors
56 UCHAR Ext2DriveNumber
= 0; // Ext2 file system drive number
57 ULONGLONG Ext2VolumeStartSector
= 0; // Ext2 file system starting sector
58 ULONG Ext2BlockSizeInBytes
= 0; // Block size in bytes
59 ULONG Ext2BlockSizeInSectors
= 0; // Block size in sectors
60 ULONG Ext2FragmentSizeInBytes
= 0; // Fragment size in bytes
61 ULONG Ext2FragmentSizeInSectors
= 0; // Fragment size in sectors
62 ULONG Ext2GroupCount
= 0; // Number of groups in this file system
63 ULONG Ext2InodesPerBlock
= 0; // Number of inodes in one block
64 ULONG Ext2GroupDescPerBlock
= 0; // Number of group descriptors in one block
66 #define TAG_EXT_BLOCK_LIST 'LtxE'
67 #define TAG_EXT_FILE 'FtxE'
68 #define TAG_EXT_BUFFER 'BtxE'
69 #define TAG_EXT_SUPER_BLOCK 'StxE'
70 #define TAG_EXT_GROUP_DESC 'GtxE'
72 BOOLEAN
DiskGetBootVolume(PUCHAR DriveNumber
, PULONGLONG StartSector
, PULONGLONG SectorCount
, int *FsType
)
81 BOOLEAN
Ext2OpenVolume(UCHAR DriveNumber
, ULONGLONG VolumeStartSector
, ULONGLONG PartitionSectorCount
)
84 TRACE("Ext2OpenVolume() DriveNumber = 0x%x VolumeStartSector = %d\n", DriveNumber
, VolumeStartSector
);
86 // Store the drive number and start sector
87 Ext2DriveNumber
= DriveNumber
;
88 Ext2VolumeStartSector
= VolumeStartSector
;
90 if (!MachDiskGetDriveGeometry(DriveNumber
, &Ext2DiskGeometry
))
96 // Initialize the disk cache for this drive
98 if (!CacheInitializeDrive(DriveNumber
))
103 // Read in the super block
104 if (!Ext2ReadSuperBlock())
109 // Read in the group descriptors
110 if (!Ext2ReadGroupDescriptors())
120 * Tries to open the file 'name' and returns true or false
121 * for success and failure respectively
123 PEXT2_FILE_INFO
Ext2OpenFile(PCSTR FileName
)
125 EXT2_FILE_INFO TempExt2FileInfo
;
126 PEXT2_FILE_INFO FileHandle
;
127 CHAR SymLinkPath
[EXT2_NAME_LEN
];
128 CHAR FullPath
[EXT2_NAME_LEN
* 2];
131 TRACE("Ext2OpenFile() FileName = %s\n", FileName
);
133 RtlZeroMemory(SymLinkPath
, sizeof(SymLinkPath
));
135 // Lookup the file in the file system
136 if (!Ext2LookupFile(FileName
, &TempExt2FileInfo
))
141 // If we got a symbolic link then fix up the path
142 // and re-call this function
143 if ((TempExt2FileInfo
.Inode
.mode
& EXT2_S_IFMT
) == EXT2_S_IFLNK
)
145 TRACE("File is a symbolic link\n");
147 // Now read in the symbolic link path
148 if (!Ext2ReadFileBig(&TempExt2FileInfo
, TempExt2FileInfo
.FileSize
, NULL
, SymLinkPath
))
150 if (TempExt2FileInfo
.FileBlockList
!= NULL
)
152 FrLdrTempFree(TempExt2FileInfo
.FileBlockList
, TAG_EXT_BLOCK_LIST
);
158 TRACE("Symbolic link path = %s\n", SymLinkPath
);
161 if (SymLinkPath
[0] == '/' || SymLinkPath
[0] == '\\')
163 // Symbolic link is an absolute path
164 // So copy it to FullPath, but skip over
165 // the '/' char at the beginning
166 strcpy(FullPath
, &SymLinkPath
[1]);
170 // Symbolic link is a relative path
171 // Copy the first part of the path
172 strcpy(FullPath
, FileName
);
174 // Remove the last part of the path
175 for (Index
=strlen(FullPath
); Index
>0; )
178 if (FullPath
[Index
] == '/' || FullPath
[Index
] == '\\')
183 FullPath
[Index
] = '\0';
185 // Concatenate the symbolic link
186 strcat(FullPath
, Index
== 0 ? "" : "/");
187 strcat(FullPath
, SymLinkPath
);
190 TRACE("Full file path = %s\n", FullPath
);
192 if (TempExt2FileInfo
.FileBlockList
!= NULL
)
194 FrLdrTempFree(TempExt2FileInfo
.FileBlockList
, TAG_EXT_BLOCK_LIST
);
197 return Ext2OpenFile(FullPath
);
201 FileHandle
= FrLdrTempAlloc(sizeof(EXT2_FILE_INFO
), TAG_EXT_FILE
);
203 if (FileHandle
== NULL
)
205 if (TempExt2FileInfo
.FileBlockList
!= NULL
)
207 FrLdrTempFree(TempExt2FileInfo
.FileBlockList
, TAG_EXT_BLOCK_LIST
);
213 RtlCopyMemory(FileHandle
, &TempExt2FileInfo
, sizeof(EXT2_FILE_INFO
));
221 * This function searches the file system for the
222 * specified filename and fills in a EXT2_FILE_INFO structure
223 * with info describing the file, etc. returns true
224 * if the file exists or false otherwise
226 BOOLEAN
Ext2LookupFile(PCSTR FileName
, PEXT2_FILE_INFO Ext2FileInfoPointer
)
229 ULONG NumberOfPathParts
;
231 PVOID DirectoryBuffer
;
232 ULONG DirectoryInode
= EXT2_ROOT_INO
;
233 EXT2_INODE InodeData
;
234 EXT2_DIR_ENTRY DirectoryEntry
;
236 TRACE("Ext2LookupFile() FileName = %s\n", FileName
);
238 RtlZeroMemory(Ext2FileInfoPointer
, sizeof(EXT2_FILE_INFO
));
241 // Figure out how many sub-directories we are nested in
243 NumberOfPathParts
= FsGetNumPathParts(FileName
);
246 // Loop once for each part
248 for (i
=0; i
<NumberOfPathParts
; i
++)
251 // Get first path part
253 FsGetFirstNameFromPath(PathPart
, FileName
);
256 // Advance to the next part of the path
258 for (; (*FileName
!= '\\') && (*FileName
!= '/') && (*FileName
!= '\0'); FileName
++)
264 // Buffer the directory contents
266 if (!Ext2ReadDirectory(DirectoryInode
, &DirectoryBuffer
, &InodeData
))
272 // Search for file name in directory
274 if (!Ext2SearchDirectoryBufferForFile(DirectoryBuffer
, (ULONG
)Ext2GetInodeFileSize(&InodeData
), PathPart
, &DirectoryEntry
))
276 FrLdrTempFree(DirectoryBuffer
, TAG_EXT_BUFFER
);
280 FrLdrTempFree(DirectoryBuffer
, TAG_EXT_BUFFER
);
282 DirectoryInode
= DirectoryEntry
.inode
;
285 if (!Ext2ReadInode(DirectoryInode
, &InodeData
))
290 if (((InodeData
.mode
& EXT2_S_IFMT
) != EXT2_S_IFREG
) &&
291 ((InodeData
.mode
& EXT2_S_IFMT
) != EXT2_S_IFLNK
))
293 FileSystemError("Inode is not a regular file or symbolic link.");
297 // Set the drive number
298 Ext2FileInfoPointer
->DriveNumber
= Ext2DriveNumber
;
300 // If it's a regular file or a regular symbolic link
301 // then get the block pointer list otherwise it must
302 // be a fast symbolic link which doesn't have a block list
303 if (((InodeData
.mode
& EXT2_S_IFMT
) == EXT2_S_IFREG
) ||
304 ((InodeData
.mode
& EXT2_S_IFMT
) == EXT2_S_IFLNK
&& InodeData
.size
> FAST_SYMLINK_MAX_NAME_SIZE
))
306 Ext2FileInfoPointer
->FileBlockList
= Ext2ReadBlockPointerList(&InodeData
);
308 if (Ext2FileInfoPointer
->FileBlockList
== NULL
)
315 Ext2FileInfoPointer
->FileBlockList
= NULL
;
318 Ext2FileInfoPointer
->FilePointer
= 0;
319 Ext2FileInfoPointer
->FileSize
= Ext2GetInodeFileSize(&InodeData
);
320 RtlCopyMemory(&Ext2FileInfoPointer
->Inode
, &InodeData
, sizeof(EXT2_INODE
));
325 BOOLEAN
Ext2SearchDirectoryBufferForFile(PVOID DirectoryBuffer
, ULONG DirectorySize
, PCHAR FileName
, PEXT2_DIR_ENTRY DirectoryEntry
)
328 PEXT2_DIR_ENTRY CurrentDirectoryEntry
;
330 TRACE("Ext2SearchDirectoryBufferForFile() DirectoryBuffer = 0x%x DirectorySize = %d FileName = %s\n", DirectoryBuffer
, DirectorySize
, FileName
);
332 for (CurrentOffset
=0; CurrentOffset
<DirectorySize
; )
334 CurrentDirectoryEntry
= (PEXT2_DIR_ENTRY
)((ULONG_PTR
)DirectoryBuffer
+ CurrentOffset
);
336 if (CurrentDirectoryEntry
->direntlen
== 0)
341 if ((CurrentDirectoryEntry
->direntlen
+ CurrentOffset
) > DirectorySize
)
343 FileSystemError("Directory entry extends past end of directory file.");
347 TRACE("Dumping directory entry at offset %d:\n", CurrentOffset
);
348 DbgDumpBuffer(DPRINT_FILESYSTEM
, CurrentDirectoryEntry
, CurrentDirectoryEntry
->direntlen
);
350 if ((_strnicmp(FileName
, CurrentDirectoryEntry
->name
, CurrentDirectoryEntry
->namelen
) == 0) &&
351 (strlen(FileName
) == CurrentDirectoryEntry
->namelen
))
353 RtlCopyMemory(DirectoryEntry
, CurrentDirectoryEntry
, sizeof(EXT2_DIR_ENTRY
));
355 TRACE("EXT2 Directory Entry:\n");
356 TRACE("inode = %d\n", DirectoryEntry
->inode
);
357 TRACE("direntlen = %d\n", DirectoryEntry
->direntlen
);
358 TRACE("namelen = %d\n", DirectoryEntry
->namelen
);
359 TRACE("filetype = %d\n", DirectoryEntry
->filetype
);
361 for (CurrentOffset
=0; CurrentOffset
<DirectoryEntry
->namelen
; CurrentOffset
++)
363 TRACE("%c", DirectoryEntry
->name
[CurrentOffset
]);
370 CurrentOffset
+= CurrentDirectoryEntry
->direntlen
;
378 * Reads BytesToRead from open file and
379 * returns the number of bytes read in BytesRead
381 BOOLEAN
Ext2ReadFileBig(PEXT2_FILE_INFO Ext2FileInfo
, ULONGLONG BytesToRead
, ULONGLONG
* BytesRead
, PVOID Buffer
)
384 ULONG BlockNumberIndex
;
387 ULONG NumberOfBlocks
;
389 TRACE("Ext2ReadFileBig() BytesToRead = %d Buffer = 0x%x\n", (ULONG
)BytesToRead
, Buffer
);
391 if (BytesRead
!= NULL
)
396 // Make sure we have the block pointer list if we need it
397 if (Ext2FileInfo
->FileBlockList
== NULL
)
399 // Block pointer list is NULL
400 // so this better be a fast symbolic link or else
401 if (((Ext2FileInfo
->Inode
.mode
& EXT2_S_IFMT
) != EXT2_S_IFLNK
) ||
402 (Ext2FileInfo
->FileSize
> FAST_SYMLINK_MAX_NAME_SIZE
))
404 FileSystemError("Block pointer list is NULL and file is not a fast symbolic link.");
410 // If they are trying to read past the
411 // end of the file then return success
412 // with BytesRead == 0
414 if (Ext2FileInfo
->FilePointer
>= Ext2FileInfo
->FileSize
)
420 // If they are trying to read more than there is to read
421 // then adjust the amount to read
423 if ((Ext2FileInfo
->FilePointer
+ BytesToRead
) > Ext2FileInfo
->FileSize
)
425 BytesToRead
= (Ext2FileInfo
->FileSize
- Ext2FileInfo
->FilePointer
);
428 // Check if this is a fast symbolic link
429 // if so then the read is easy
430 if (((Ext2FileInfo
->Inode
.mode
& EXT2_S_IFMT
) == EXT2_S_IFLNK
) &&
431 (Ext2FileInfo
->FileSize
<= FAST_SYMLINK_MAX_NAME_SIZE
))
433 TRACE("Reading fast symbolic link data\n");
435 // Copy the data from the link
436 RtlCopyMemory(Buffer
, (PVOID
)((ULONG_PTR
)Ext2FileInfo
->FilePointer
+ Ext2FileInfo
->Inode
.symlink
), (ULONG
)BytesToRead
);
438 if (BytesRead
!= NULL
)
440 *BytesRead
= BytesToRead
;
447 // Ok, now we have to perform at most 3 calculations
448 // I'll draw you a picture (using nifty ASCII art):
450 // CurrentFilePointer -+
452 // +----------------+
454 // +-----------+-----------+-----------+-----------+
455 // | Block 1 | Block 2 | Block 3 | Block 4 |
456 // +-----------+-----------+-----------+-----------+
458 // +---------------+--------------------+
460 // BytesToRead -------+
462 // 1 - The first calculation (and read) will align
463 // the file pointer with the next block.
464 // boundary (if we are supposed to read that much)
465 // 2 - The next calculation (and read) will read
466 // in all the full blocks that the requested
467 // amount of data would cover (in this case
469 // 3 - The last calculation (and read) would read
470 // in the remainder of the data requested out of
475 // Only do the first read if we
476 // aren't aligned on a block boundary
478 if (Ext2FileInfo
->FilePointer
% Ext2BlockSizeInBytes
)
481 // Do the math for our first read
483 BlockNumberIndex
= (ULONG
)(Ext2FileInfo
->FilePointer
/ Ext2BlockSizeInBytes
);
484 BlockNumber
= Ext2FileInfo
->FileBlockList
[BlockNumberIndex
];
485 OffsetInBlock
= (Ext2FileInfo
->FilePointer
% Ext2BlockSizeInBytes
);
486 LengthInBlock
= (ULONG
)((BytesToRead
> (Ext2BlockSizeInBytes
- OffsetInBlock
)) ? (Ext2BlockSizeInBytes
- OffsetInBlock
) : BytesToRead
);
489 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
491 if (!Ext2ReadPartialBlock(BlockNumber
, OffsetInBlock
, LengthInBlock
, Buffer
))
495 if (BytesRead
!= NULL
)
497 *BytesRead
+= LengthInBlock
;
499 BytesToRead
-= LengthInBlock
;
500 Ext2FileInfo
->FilePointer
+= LengthInBlock
;
501 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ LengthInBlock
);
505 // Do the math for our second read (if any data left)
510 // Determine how many full clusters we need to read
512 NumberOfBlocks
= (ULONG
)(BytesToRead
/ Ext2BlockSizeInBytes
);
514 while (NumberOfBlocks
> 0)
516 BlockNumberIndex
= (ULONG
)(Ext2FileInfo
->FilePointer
/ Ext2BlockSizeInBytes
);
517 BlockNumber
= Ext2FileInfo
->FileBlockList
[BlockNumberIndex
];
520 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
522 if (!Ext2ReadBlock(BlockNumber
, Buffer
))
526 if (BytesRead
!= NULL
)
528 *BytesRead
+= Ext2BlockSizeInBytes
;
530 BytesToRead
-= Ext2BlockSizeInBytes
;
531 Ext2FileInfo
->FilePointer
+= Ext2BlockSizeInBytes
;
532 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Ext2BlockSizeInBytes
);
538 // Do the math for our third read (if any data left)
542 BlockNumberIndex
= (ULONG
)(Ext2FileInfo
->FilePointer
/ Ext2BlockSizeInBytes
);
543 BlockNumber
= Ext2FileInfo
->FileBlockList
[BlockNumberIndex
];
546 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
548 if (!Ext2ReadPartialBlock(BlockNumber
, 0, (ULONG
)BytesToRead
, Buffer
))
552 if (BytesRead
!= NULL
)
554 *BytesRead
+= BytesToRead
;
556 Ext2FileInfo
->FilePointer
+= BytesToRead
;
557 BytesToRead
-= BytesToRead
;
558 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (ULONG_PTR
)BytesToRead
);
564 BOOLEAN
Ext2ReadVolumeSectors(UCHAR DriveNumber
, ULONGLONG SectorNumber
, ULONG SectorCount
, PVOID Buffer
)
566 //GEOMETRY DiskGeometry;
567 //BOOLEAN ReturnValue;
568 //if (!DiskGetDriveGeometry(DriveNumber, &DiskGeometry))
572 //ReturnValue = MachDiskReadLogicalSectors(DriveNumber, SectorNumber + Ext2VolumeStartSector, SectorCount, DiskReadBuffer);
573 //RtlCopyMemory(Buffer, DiskReadBuffer, SectorCount * DiskGeometry.BytesPerSector);
574 //return ReturnValue;
576 return CacheReadDiskSectors(DriveNumber
, SectorNumber
+ Ext2VolumeStartSector
, SectorCount
, Buffer
);
579 BOOLEAN
Ext2ReadSuperBlock(VOID
)
582 TRACE("Ext2ReadSuperBlock()\n");
585 // Free any memory previously allocated
587 if (Ext2SuperBlock
!= NULL
)
589 FrLdrTempFree(Ext2SuperBlock
, TAG_EXT_SUPER_BLOCK
);
591 Ext2SuperBlock
= NULL
;
595 // Now allocate the memory to hold the super block
597 Ext2SuperBlock
= (PEXT2_SUPER_BLOCK
)FrLdrTempAlloc(1024, TAG_EXT_SUPER_BLOCK
);
600 // Make sure we got the memory
602 if (Ext2SuperBlock
== NULL
)
604 FileSystemError("Out of memory.");
608 // Now try to read the super block
609 // If this fails then abort
610 if (!MachDiskReadLogicalSectors(Ext2DriveNumber
, Ext2VolumeStartSector
, 8, DiskReadBuffer
))
614 RtlCopyMemory(Ext2SuperBlock
, ((PUCHAR
)DiskReadBuffer
+ 1024), 1024);
616 TRACE("Dumping super block:\n");
617 TRACE("total_inodes: %d\n", Ext2SuperBlock
->total_inodes
);
618 TRACE("total_blocks: %d\n", Ext2SuperBlock
->total_blocks
);
619 TRACE("reserved_blocks: %d\n", Ext2SuperBlock
->reserved_blocks
);
620 TRACE("free_blocks: %d\n", Ext2SuperBlock
->free_blocks
);
621 TRACE("free_inodes: %d\n", Ext2SuperBlock
->free_inodes
);
622 TRACE("first_data_block: %d\n", Ext2SuperBlock
->first_data_block
);
623 TRACE("log2_block_size: %d\n", Ext2SuperBlock
->log2_block_size
);
624 TRACE("log2_fragment_size: %d\n", Ext2SuperBlock
->log2_fragment_size
);
625 TRACE("blocks_per_group: %d\n", Ext2SuperBlock
->blocks_per_group
);
626 TRACE("fragments_per_group: %d\n", Ext2SuperBlock
->fragments_per_group
);
627 TRACE("inodes_per_group: %d\n", Ext2SuperBlock
->inodes_per_group
);
628 TRACE("mtime: %d\n", Ext2SuperBlock
->mtime
);
629 TRACE("utime: %d\n", Ext2SuperBlock
->utime
);
630 TRACE("mnt_count: %d\n", Ext2SuperBlock
->mnt_count
);
631 TRACE("max_mnt_count: %d\n", Ext2SuperBlock
->max_mnt_count
);
632 TRACE("magic: 0x%x\n", Ext2SuperBlock
->magic
);
633 TRACE("fs_state: %d\n", Ext2SuperBlock
->fs_state
);
634 TRACE("error_handling: %d\n", Ext2SuperBlock
->error_handling
);
635 TRACE("minor_revision_level: %d\n", Ext2SuperBlock
->minor_revision_level
);
636 TRACE("lastcheck: %d\n", Ext2SuperBlock
->lastcheck
);
637 TRACE("checkinterval: %d\n", Ext2SuperBlock
->checkinterval
);
638 TRACE("creator_os: %d\n", Ext2SuperBlock
->creator_os
);
639 TRACE("revision_level: %d\n", Ext2SuperBlock
->revision_level
);
640 TRACE("uid_reserved: %d\n", Ext2SuperBlock
->uid_reserved
);
641 TRACE("gid_reserved: %d\n", Ext2SuperBlock
->gid_reserved
);
642 TRACE("first_inode: %d\n", Ext2SuperBlock
->first_inode
);
643 TRACE("inode_size: %d\n", Ext2SuperBlock
->inode_size
);
644 TRACE("block_group_number: %d\n", Ext2SuperBlock
->block_group_number
);
645 TRACE("feature_compatibility: 0x%x\n", Ext2SuperBlock
->feature_compatibility
);
646 TRACE("feature_incompat: 0x%x\n", Ext2SuperBlock
->feature_incompat
);
647 TRACE("feature_ro_compat: 0x%x\n", Ext2SuperBlock
->feature_ro_compat
);
648 TRACE("unique_id = { 0x%x, 0x%x, 0x%x, 0x%x }\n",
649 Ext2SuperBlock
->unique_id
[0], Ext2SuperBlock
->unique_id
[1], Ext2SuperBlock
->unique_id
[2], Ext2SuperBlock
->unique_id
[3]);
650 TRACE("volume_name = '%.16s'\n", Ext2SuperBlock
->volume_name
);
651 TRACE("last_mounted_on = '%.64s'\n", Ext2SuperBlock
->last_mounted_on
);
652 TRACE("compression_info = 0x%x\n", Ext2SuperBlock
->compression_info
);
655 // Check the super block magic
657 if (Ext2SuperBlock
->magic
!= EXT2_MAGIC
)
659 FileSystemError("Invalid super block magic (0xef53)");
664 // Check the revision level
666 if (Ext2SuperBlock
->revision_level
> EXT2_DYNAMIC_REVISION
)
668 FileSystemError("FreeLoader does not understand the revision of this EXT2/EXT3 filesystem.\nPlease update FreeLoader.");
673 // Check the feature set
674 // Don't need to check the compatible or read-only compatible features
675 // because we only mount the filesystem as read-only
677 if ((Ext2SuperBlock
->revision_level
>= EXT2_DYNAMIC_REVISION
) &&
678 (/*((Ext2SuperBlock->s_feature_compat & ~EXT3_FEATURE_COMPAT_SUPP) != 0) ||*/
679 /*((Ext2SuperBlock->s_feature_ro_compat & ~EXT3_FEATURE_RO_COMPAT_SUPP) != 0) ||*/
680 ((Ext2SuperBlock
->feature_incompat
& ~EXT3_FEATURE_INCOMPAT_SUPP
) != 0)))
682 FileSystemError("FreeLoader does not understand features of this EXT2/EXT3 filesystem.\nPlease update FreeLoader.");
686 // Calculate the group count
687 Ext2GroupCount
= (Ext2SuperBlock
->total_blocks
- Ext2SuperBlock
->first_data_block
+ Ext2SuperBlock
->blocks_per_group
- 1) / Ext2SuperBlock
->blocks_per_group
;
688 TRACE("Ext2GroupCount: %d\n", Ext2GroupCount
);
690 // Calculate the block size
691 Ext2BlockSizeInBytes
= 1024 << Ext2SuperBlock
->log2_block_size
;
692 Ext2BlockSizeInSectors
= Ext2BlockSizeInBytes
/ Ext2DiskGeometry
.BytesPerSector
;
693 TRACE("Ext2BlockSizeInBytes: %d\n", Ext2BlockSizeInBytes
);
694 TRACE("Ext2BlockSizeInSectors: %d\n", Ext2BlockSizeInSectors
);
696 // Calculate the fragment size
697 if (Ext2SuperBlock
->log2_fragment_size
>= 0)
699 Ext2FragmentSizeInBytes
= 1024 << Ext2SuperBlock
->log2_fragment_size
;
703 Ext2FragmentSizeInBytes
= 1024 >> -(Ext2SuperBlock
->log2_fragment_size
);
705 Ext2FragmentSizeInSectors
= Ext2FragmentSizeInBytes
/ Ext2DiskGeometry
.BytesPerSector
;
706 TRACE("Ext2FragmentSizeInBytes: %d\n", Ext2FragmentSizeInBytes
);
707 TRACE("Ext2FragmentSizeInSectors: %d\n", Ext2FragmentSizeInSectors
);
709 // Verify that the fragment size and the block size are equal
710 if (Ext2BlockSizeInBytes
!= Ext2FragmentSizeInBytes
)
712 FileSystemError("The fragment size must be equal to the block size.");
716 // Calculate the number of inodes in one block
717 Ext2InodesPerBlock
= Ext2BlockSizeInBytes
/ EXT2_INODE_SIZE(Ext2SuperBlock
);
718 TRACE("Ext2InodesPerBlock: %d\n", Ext2InodesPerBlock
);
720 // Calculate the number of group descriptors in one block
721 Ext2GroupDescPerBlock
= EXT2_DESC_PER_BLOCK(Ext2SuperBlock
);
722 TRACE("Ext2GroupDescPerBlock: %d\n", Ext2GroupDescPerBlock
);
727 BOOLEAN
Ext2ReadGroupDescriptors(VOID
)
729 ULONG GroupDescBlockCount
;
731 PUCHAR CurrentGroupDescBlock
;
733 TRACE("Ext2ReadGroupDescriptors()\n");
736 // Free any memory previously allocated
738 if (Ext2GroupDescriptors
!= NULL
)
740 FrLdrTempFree(Ext2GroupDescriptors
, TAG_EXT_GROUP_DESC
);
742 Ext2GroupDescriptors
= NULL
;
746 // Now allocate the memory to hold the group descriptors
748 GroupDescBlockCount
= ROUND_UP(Ext2GroupCount
, Ext2GroupDescPerBlock
) / Ext2GroupDescPerBlock
;
749 Ext2GroupDescriptors
= (PEXT2_GROUP_DESC
)FrLdrTempAlloc(GroupDescBlockCount
* Ext2BlockSizeInBytes
, TAG_EXT_GROUP_DESC
);
752 // Make sure we got the memory
754 if (Ext2GroupDescriptors
== NULL
)
756 FileSystemError("Out of memory.");
760 // Now read the group descriptors
761 CurrentGroupDescBlock
= (PUCHAR
)Ext2GroupDescriptors
;
762 BlockNumber
= Ext2SuperBlock
->first_data_block
+ 1;
764 while (GroupDescBlockCount
--)
766 if (!Ext2ReadBlock(BlockNumber
, CurrentGroupDescBlock
))
772 CurrentGroupDescBlock
+= Ext2BlockSizeInBytes
;
778 BOOLEAN
Ext2ReadDirectory(ULONG Inode
, PVOID
* DirectoryBuffer
, PEXT2_INODE InodePointer
)
780 EXT2_FILE_INFO DirectoryFileInfo
;
782 TRACE("Ext2ReadDirectory() Inode = %d\n", Inode
);
784 // Read the directory inode
785 if (!Ext2ReadInode(Inode
, InodePointer
))
790 // Make sure it is a directory inode
791 if ((InodePointer
->mode
& EXT2_S_IFMT
) != EXT2_S_IFDIR
)
793 FileSystemError("Inode is not a directory.");
797 // Fill in file info struct so we can call Ext2ReadFileBig()
798 RtlZeroMemory(&DirectoryFileInfo
, sizeof(EXT2_FILE_INFO
));
799 DirectoryFileInfo
.DriveNumber
= Ext2DriveNumber
;
800 DirectoryFileInfo
.FileBlockList
= Ext2ReadBlockPointerList(InodePointer
);
801 DirectoryFileInfo
.FilePointer
= 0;
802 DirectoryFileInfo
.FileSize
= Ext2GetInodeFileSize(InodePointer
);
804 if (DirectoryFileInfo
.FileBlockList
== NULL
)
810 // Now allocate the memory to hold the group descriptors
812 ASSERT(DirectoryFileInfo
.FileSize
<= 0xFFFFFFFF);
813 *DirectoryBuffer
= (PEXT2_DIR_ENTRY
)FrLdrTempAlloc((ULONG
)DirectoryFileInfo
.FileSize
, TAG_EXT_BUFFER
);
816 // Make sure we got the memory
818 if (*DirectoryBuffer
== NULL
)
820 FrLdrTempFree(DirectoryFileInfo
.FileBlockList
, TAG_EXT_BLOCK_LIST
);
821 FileSystemError("Out of memory.");
825 // Now read the root directory data
826 if (!Ext2ReadFileBig(&DirectoryFileInfo
, DirectoryFileInfo
.FileSize
, NULL
, *DirectoryBuffer
))
828 FrLdrTempFree(*DirectoryBuffer
, TAG_EXT_BUFFER
);
829 *DirectoryBuffer
= NULL
;
830 FrLdrTempFree(DirectoryFileInfo
.FileBlockList
, TAG_EXT_BLOCK_LIST
);
834 FrLdrTempFree(DirectoryFileInfo
.FileBlockList
, TAG_EXT_BLOCK_LIST
);
838 BOOLEAN
Ext2ReadBlock(ULONG BlockNumber
, PVOID Buffer
)
840 CHAR ErrorString
[80];
842 TRACE("Ext2ReadBlock() BlockNumber = %d Buffer = 0x%x\n", BlockNumber
, Buffer
);
844 // Make sure its a valid block
845 if (BlockNumber
> Ext2SuperBlock
->total_blocks
)
847 sprintf(ErrorString
, "Error reading block %d - block out of range.", (int) BlockNumber
);
848 FileSystemError(ErrorString
);
852 // Check to see if this is a sparse block
853 if (BlockNumber
== 0)
855 TRACE("Block is part of a sparse file. Zeroing input buffer.\n");
857 RtlZeroMemory(Buffer
, Ext2BlockSizeInBytes
);
862 return Ext2ReadVolumeSectors(Ext2DriveNumber
, (ULONGLONG
)BlockNumber
* Ext2BlockSizeInSectors
, Ext2BlockSizeInSectors
, Buffer
);
866 * Ext2ReadPartialBlock()
867 * Reads part of a block into memory
869 BOOLEAN
Ext2ReadPartialBlock(ULONG BlockNumber
, ULONG StartingOffset
, ULONG Length
, PVOID Buffer
)
873 TRACE("Ext2ReadPartialBlock() BlockNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", BlockNumber
, StartingOffset
, Length
, Buffer
);
875 TempBuffer
= FrLdrTempAlloc(Ext2BlockSizeInBytes
, TAG_EXT_BUFFER
);
877 if (!Ext2ReadBlock(BlockNumber
, TempBuffer
))
882 memcpy(Buffer
, ((PUCHAR
)TempBuffer
+ StartingOffset
), Length
);
884 FrLdrTempFree(TempBuffer
, TAG_EXT_BUFFER
);
889 ULONG
Ext2GetGroupDescBlockNumber(ULONG Group
)
891 return (((Group
* sizeof(EXT2_GROUP_DESC
)) / Ext2GroupDescPerBlock
) + Ext2SuperBlock
->first_data_block
+ 1);
894 ULONG
Ext2GetGroupDescOffsetInBlock(ULONG Group
)
896 return ((Group
* sizeof(EXT2_GROUP_DESC
)) % Ext2GroupDescPerBlock
);
899 ULONG
Ext2GetInodeGroupNumber(ULONG Inode
)
901 return ((Inode
- 1) / Ext2SuperBlock
->inodes_per_group
);
904 ULONG
Ext2GetInodeBlockNumber(ULONG Inode
)
906 return (((Inode
- 1) % Ext2SuperBlock
->inodes_per_group
) / Ext2InodesPerBlock
);
909 ULONG
Ext2GetInodeOffsetInBlock(ULONG Inode
)
911 return (((Inode
- 1) % Ext2SuperBlock
->inodes_per_group
) % Ext2InodesPerBlock
);
914 BOOLEAN
Ext2ReadInode(ULONG Inode
, PEXT2_INODE InodeBuffer
)
916 ULONG InodeGroupNumber
;
917 ULONG InodeBlockNumber
;
918 ULONG InodeOffsetInBlock
;
919 CHAR ErrorString
[80];
920 EXT2_GROUP_DESC GroupDescriptor
;
922 TRACE("Ext2ReadInode() Inode = %d\n", Inode
);
924 // Make sure its a valid inode
925 if ((Inode
< 1) || (Inode
> Ext2SuperBlock
->total_inodes
))
927 sprintf(ErrorString
, "Error reading inode %ld - inode out of range.", Inode
);
928 FileSystemError(ErrorString
);
932 // Get inode group & block number and offset in block
933 InodeGroupNumber
= Ext2GetInodeGroupNumber(Inode
);
934 InodeBlockNumber
= Ext2GetInodeBlockNumber(Inode
);
935 InodeOffsetInBlock
= Ext2GetInodeOffsetInBlock(Inode
);
936 TRACE("InodeGroupNumber = %d\n", InodeGroupNumber
);
937 TRACE("InodeBlockNumber = %d\n", InodeBlockNumber
);
938 TRACE("InodeOffsetInBlock = %d\n", InodeOffsetInBlock
);
940 // Read the group descriptor
941 if (!Ext2ReadGroupDescriptor(InodeGroupNumber
, &GroupDescriptor
))
946 // Add the start block of the inode table to the inode block number
947 InodeBlockNumber
+= GroupDescriptor
.inode_table_id
;
948 TRACE("InodeBlockNumber (after group desc correction) = %d\n", InodeBlockNumber
);
951 if (!Ext2ReadPartialBlock(InodeBlockNumber
,
952 (InodeOffsetInBlock
* EXT2_INODE_SIZE(Ext2SuperBlock
)),
959 TRACE("Dumping inode information:\n");
960 TRACE("mode = 0x%x\n", InodeBuffer
->mode
);
961 TRACE("uid = %d\n", InodeBuffer
->uid
);
962 TRACE("size = %d\n", InodeBuffer
->size
);
963 TRACE("atime = %d\n", InodeBuffer
->atime
);
964 TRACE("ctime = %d\n", InodeBuffer
->ctime
);
965 TRACE("mtime = %d\n", InodeBuffer
->mtime
);
966 TRACE("dtime = %d\n", InodeBuffer
->dtime
);
967 TRACE("gid = %d\n", InodeBuffer
->gid
);
968 TRACE("nlinks = %d\n", InodeBuffer
->nlinks
);
969 TRACE("blockcnt = %d\n", InodeBuffer
->blockcnt
);
970 TRACE("flags = 0x%x\n", InodeBuffer
->flags
);
971 TRACE("osd1 = 0x%x\n", InodeBuffer
->osd1
);
972 TRACE("dir_blocks = { %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u }\n",
973 InodeBuffer
->blocks
.dir_blocks
[0], InodeBuffer
->blocks
.dir_blocks
[1], InodeBuffer
->blocks
.dir_blocks
[ 2], InodeBuffer
->blocks
.dir_blocks
[ 3],
974 InodeBuffer
->blocks
.dir_blocks
[4], InodeBuffer
->blocks
.dir_blocks
[5], InodeBuffer
->blocks
.dir_blocks
[ 6], InodeBuffer
->blocks
.dir_blocks
[ 7],
975 InodeBuffer
->blocks
.dir_blocks
[8], InodeBuffer
->blocks
.dir_blocks
[9], InodeBuffer
->blocks
.dir_blocks
[10], InodeBuffer
->blocks
.dir_blocks
[11]);
976 TRACE("indir_block = %u\n", InodeBuffer
->blocks
.indir_block
);
977 TRACE("double_indir_block = %u\n", InodeBuffer
->blocks
.double_indir_block
);
978 TRACE("tripple_indir_block = %u\n", InodeBuffer
->blocks
.tripple_indir_block
);
979 TRACE("version = %d\n", InodeBuffer
->version
);
980 TRACE("acl = %d\n", InodeBuffer
->acl
);
981 TRACE("dir_acl = %d\n", InodeBuffer
->dir_acl
);
982 TRACE("fragment_addr = %d\n", InodeBuffer
->fragment_addr
);
983 TRACE("osd2 = { %d, %d, %d }\n",
984 InodeBuffer
->osd2
[0], InodeBuffer
->osd2
[1], InodeBuffer
->osd2
[2]);
989 BOOLEAN
Ext2ReadGroupDescriptor(ULONG Group
, PEXT2_GROUP_DESC GroupBuffer
)
991 TRACE("Ext2ReadGroupDescriptor()\n");
993 /*if (!Ext2ReadBlock(Ext2GetGroupDescBlockNumber(Group), (PVOID)FILESYSBUFFER))
998 RtlCopyMemory(GroupBuffer, (PVOID)(FILESYSBUFFER + Ext2GetGroupDescOffsetInBlock(Group)), sizeof(EXT2_GROUP_DESC));*/
1000 RtlCopyMemory(GroupBuffer
, &Ext2GroupDescriptors
[Group
], sizeof(EXT2_GROUP_DESC
));
1002 TRACE("Dumping group descriptor:\n");
1003 TRACE("block_id = %d\n", GroupBuffer
->block_id
);
1004 TRACE("inode_id = %d\n", GroupBuffer
->inode_id
);
1005 TRACE("inode_table_id = %d\n", GroupBuffer
->inode_table_id
);
1006 TRACE("free_blocks = %d\n", GroupBuffer
->free_blocks
);
1007 TRACE("free_inodes = %d\n", GroupBuffer
->free_inodes
);
1008 TRACE("used_dirs = %d\n", GroupBuffer
->used_dirs
);
1013 ULONG
* Ext2ReadBlockPointerList(PEXT2_INODE Inode
)
1018 ULONG CurrentBlockInList
;
1021 TRACE("Ext2ReadBlockPointerList()\n");
1023 // Get the number of blocks this file occupies
1024 // I would just use Inode->i_blocks but it
1025 // doesn't seem to be the number of blocks
1026 // the file size corresponds to, but instead
1027 // it is much bigger.
1028 //BlockCount = Inode->i_blocks;
1029 FileSize
= Ext2GetInodeFileSize(Inode
);
1030 FileSize
= ROUND_UP(FileSize
, Ext2BlockSizeInBytes
);
1031 BlockCount
= (ULONG
)(FileSize
/ Ext2BlockSizeInBytes
);
1033 // Allocate the memory for the block list
1034 BlockList
= FrLdrTempAlloc(BlockCount
* sizeof(ULONG
), TAG_EXT_BLOCK_LIST
);
1035 if (BlockList
== NULL
)
1040 RtlZeroMemory(BlockList
, BlockCount
* sizeof(ULONG
));
1042 // Copy the direct block pointers
1043 for (CurrentBlockInList
= CurrentBlock
= 0;
1044 CurrentBlockInList
< BlockCount
&& CurrentBlock
< INDIRECT_BLOCKS
;
1045 CurrentBlock
++, CurrentBlockInList
++)
1047 BlockList
[CurrentBlockInList
] = Inode
->blocks
.dir_blocks
[CurrentBlock
];
1050 // Copy the indirect block pointers
1051 if (CurrentBlockInList
< BlockCount
)
1053 if (!Ext2CopyIndirectBlockPointers(BlockList
, &CurrentBlockInList
, BlockCount
, Inode
->blocks
.indir_block
))
1055 FrLdrTempFree(BlockList
, TAG_EXT_BLOCK_LIST
);
1060 // Copy the double indirect block pointers
1061 if (CurrentBlockInList
< BlockCount
)
1063 if (!Ext2CopyDoubleIndirectBlockPointers(BlockList
, &CurrentBlockInList
, BlockCount
, Inode
->blocks
.double_indir_block
))
1065 FrLdrTempFree(BlockList
, TAG_EXT_BLOCK_LIST
);
1070 // Copy the triple indirect block pointers
1071 if (CurrentBlockInList
< BlockCount
)
1073 if (!Ext2CopyTripleIndirectBlockPointers(BlockList
, &CurrentBlockInList
, BlockCount
, Inode
->blocks
.tripple_indir_block
))
1075 FrLdrTempFree(BlockList
, TAG_EXT_BLOCK_LIST
);
1083 ULONGLONG
Ext2GetInodeFileSize(PEXT2_INODE Inode
)
1085 if ((Inode
->mode
& EXT2_S_IFMT
) == EXT2_S_IFDIR
)
1087 return (ULONGLONG
)(Inode
->size
);
1091 return ((ULONGLONG
)(Inode
->size
) | ((ULONGLONG
)(Inode
->dir_acl
) << 32));
1095 BOOLEAN
Ext2CopyIndirectBlockPointers(ULONG
* BlockList
, ULONG
* CurrentBlockInList
, ULONG BlockCount
, ULONG IndirectBlock
)
1099 ULONG BlockPointersPerBlock
;
1101 TRACE("Ext2CopyIndirectBlockPointers() BlockCount = %d\n", BlockCount
);
1103 BlockPointersPerBlock
= Ext2BlockSizeInBytes
/ sizeof(ULONG
);
1105 BlockBuffer
= FrLdrTempAlloc(Ext2BlockSizeInBytes
, TAG_EXT_BUFFER
);
1111 if (!Ext2ReadBlock(IndirectBlock
, BlockBuffer
))
1116 for (CurrentBlock
=0; (*CurrentBlockInList
)<BlockCount
&& CurrentBlock
<BlockPointersPerBlock
; CurrentBlock
++)
1118 BlockList
[(*CurrentBlockInList
)] = BlockBuffer
[CurrentBlock
];
1119 (*CurrentBlockInList
)++;
1122 FrLdrTempFree(BlockBuffer
, TAG_EXT_BUFFER
);
1127 BOOLEAN
Ext2CopyDoubleIndirectBlockPointers(ULONG
* BlockList
, ULONG
* CurrentBlockInList
, ULONG BlockCount
, ULONG DoubleIndirectBlock
)
1131 ULONG BlockPointersPerBlock
;
1133 TRACE("Ext2CopyDoubleIndirectBlockPointers() BlockCount = %d\n", BlockCount
);
1135 BlockPointersPerBlock
= Ext2BlockSizeInBytes
/ sizeof(ULONG
);
1137 BlockBuffer
= (ULONG
*)FrLdrTempAlloc(Ext2BlockSizeInBytes
, TAG_EXT_BUFFER
);
1138 if (BlockBuffer
== NULL
)
1143 if (!Ext2ReadBlock(DoubleIndirectBlock
, BlockBuffer
))
1145 FrLdrTempFree(BlockBuffer
, TAG_EXT_BUFFER
);
1149 for (CurrentBlock
=0; (*CurrentBlockInList
)<BlockCount
&& CurrentBlock
<BlockPointersPerBlock
; CurrentBlock
++)
1151 if (!Ext2CopyIndirectBlockPointers(BlockList
, CurrentBlockInList
, BlockCount
, BlockBuffer
[CurrentBlock
]))
1153 FrLdrTempFree(BlockBuffer
, TAG_EXT_BUFFER
);
1158 FrLdrTempFree(BlockBuffer
, TAG_EXT_BUFFER
);
1162 BOOLEAN
Ext2CopyTripleIndirectBlockPointers(ULONG
* BlockList
, ULONG
* CurrentBlockInList
, ULONG BlockCount
, ULONG TripleIndirectBlock
)
1166 ULONG BlockPointersPerBlock
;
1168 TRACE("Ext2CopyTripleIndirectBlockPointers() BlockCount = %d\n", BlockCount
);
1170 BlockPointersPerBlock
= Ext2BlockSizeInBytes
/ sizeof(ULONG
);
1172 BlockBuffer
= (ULONG
*)FrLdrTempAlloc(Ext2BlockSizeInBytes
, TAG_EXT_BUFFER
);
1173 if (BlockBuffer
== NULL
)
1178 if (!Ext2ReadBlock(TripleIndirectBlock
, BlockBuffer
))
1180 FrLdrTempFree(BlockBuffer
, TAG_EXT_BUFFER
);
1184 for (CurrentBlock
=0; (*CurrentBlockInList
)<BlockCount
&& CurrentBlock
<BlockPointersPerBlock
; CurrentBlock
++)
1186 if (!Ext2CopyDoubleIndirectBlockPointers(BlockList
, CurrentBlockInList
, BlockCount
, BlockBuffer
[CurrentBlock
]))
1188 FrLdrTempFree(BlockBuffer
, TAG_EXT_BUFFER
);
1193 FrLdrTempFree(BlockBuffer
, TAG_EXT_BUFFER
);
1197 ARC_STATUS
Ext2Close(ULONG FileId
)
1199 PEXT2_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1201 FrLdrTempFree(FileHandle
, TAG_EXT_FILE
);
1206 ARC_STATUS
Ext2GetFileInformation(ULONG FileId
, FILEINFORMATION
* Information
)
1208 PEXT2_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1210 RtlZeroMemory(Information
, sizeof(FILEINFORMATION
));
1211 Information
->EndingAddress
.QuadPart
= FileHandle
->FileSize
;
1212 Information
->CurrentAddress
.QuadPart
= FileHandle
->FilePointer
;
1214 TRACE("Ext2GetFileInformation() FileSize = %d\n",
1215 Information
->EndingAddress
.LowPart
);
1216 TRACE("Ext2GetFileInformation() FilePointer = %d\n",
1217 Information
->CurrentAddress
.LowPart
);
1222 ARC_STATUS
Ext2Open(CHAR
* Path
, OPENMODE OpenMode
, ULONG
* FileId
)
1224 PEXT2_FILE_INFO FileHandle
;
1227 if (OpenMode
!= OpenReadOnly
)
1230 //DeviceId = FsGetDeviceId(*FileId);
1232 TRACE("Ext2Open() FileName = %s\n", Path
);
1235 // Call old open method
1237 FileHandle
= Ext2OpenFile(Path
);
1246 // Success. Remember the handle
1248 FsSetDeviceSpecific(*FileId
, FileHandle
);
1252 ARC_STATUS
Ext2Read(ULONG FileId
, VOID
* Buffer
, ULONG N
, ULONG
* Count
)
1254 PEXT2_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1255 ULONGLONG BytesReadBig
;
1261 Success
= Ext2ReadFileBig(FileHandle
, N
, &BytesReadBig
, Buffer
);
1262 *Count
= (ULONG
)BytesReadBig
;
1265 // Check for success
1273 ARC_STATUS
Ext2Seek(ULONG FileId
, LARGE_INTEGER
* Position
, SEEKMODE SeekMode
)
1275 PEXT2_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1277 TRACE("Ext2Seek() NewFilePointer = %lu\n", Position
->LowPart
);
1279 if (SeekMode
!= SeekAbsolute
)
1281 if (Position
->HighPart
!= 0)
1283 if (Position
->LowPart
>= FileHandle
->FileSize
)
1286 FileHandle
->FilePointer
= Position
->LowPart
;
1290 const DEVVTBL Ext2FuncTable
=
1293 Ext2GetFileInformation
,
1300 const DEVVTBL
* Ext2Mount(ULONG DeviceId
)
1302 EXT2_SUPER_BLOCK SuperBlock
;
1303 LARGE_INTEGER Position
;
1308 // Read the SuperBlock
1310 Position
.HighPart
= 0;
1311 Position
.LowPart
= 2 * 512;
1312 Status
= ArcSeek(DeviceId
, &Position
, SeekAbsolute
);
1313 if (Status
!= ESUCCESS
)
1315 Status
= ArcRead(DeviceId
, &SuperBlock
, sizeof(SuperBlock
), &Count
);
1316 if (Status
!= ESUCCESS
|| Count
!= sizeof(SuperBlock
))
1320 // Check if SuperBlock is valid. If yes, return Ext2 function table
1322 if (SuperBlock
.magic
== EXT2_MAGIC
)
1325 // Compatibility hack as long as FS is not using underlying device DeviceId
1328 ULONGLONG StartSector
;
1329 ULONGLONG SectorCount
;
1331 if (!DiskGetBootVolume(&DriveNumber
, &StartSector
, &SectorCount
, &Type
))
1333 Ext2OpenVolume(DriveNumber
, StartSector
, SectorCount
);
1334 return &Ext2FuncTable
;