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 BOOLEAN
DiskGetBootVolume(PUCHAR DriveNumber
, PULONGLONG StartSector
, PULONGLONG SectorCount
, int *FsType
)
75 BOOLEAN
Ext2OpenVolume(UCHAR DriveNumber
, ULONGLONG VolumeStartSector
, ULONGLONG PartitionSectorCount
)
78 TRACE("Ext2OpenVolume() DriveNumber = 0x%x VolumeStartSector = %d\n", DriveNumber
, VolumeStartSector
);
80 // Store the drive number and start sector
81 Ext2DriveNumber
= DriveNumber
;
82 Ext2VolumeStartSector
= VolumeStartSector
;
84 if (!MachDiskGetDriveGeometry(DriveNumber
, &Ext2DiskGeometry
))
90 // Initialize the disk cache for this drive
92 if (!CacheInitializeDrive(DriveNumber
))
97 // Read in the super block
98 if (!Ext2ReadSuperBlock())
103 // Read in the group descriptors
104 if (!Ext2ReadGroupDescriptors())
114 * Tries to open the file 'name' and returns true or false
115 * for success and failure respectively
117 PEXT2_FILE_INFO
Ext2OpenFile(PCSTR FileName
)
119 EXT2_FILE_INFO TempExt2FileInfo
;
120 PEXT2_FILE_INFO FileHandle
;
121 CHAR SymLinkPath
[EXT2_NAME_LEN
];
122 CHAR FullPath
[EXT2_NAME_LEN
* 2];
125 TRACE("Ext2OpenFile() FileName = %s\n", FileName
);
127 RtlZeroMemory(SymLinkPath
, sizeof(SymLinkPath
));
129 // Lookup the file in the file system
130 if (!Ext2LookupFile(FileName
, &TempExt2FileInfo
))
135 // If we got a symbolic link then fix up the path
136 // and re-call this function
137 if ((TempExt2FileInfo
.Inode
.mode
& EXT2_S_IFMT
) == EXT2_S_IFLNK
)
139 TRACE("File is a symbolic link\n");
141 // Now read in the symbolic link path
142 if (!Ext2ReadFileBig(&TempExt2FileInfo
, TempExt2FileInfo
.FileSize
, NULL
, SymLinkPath
))
144 if (TempExt2FileInfo
.FileBlockList
!= NULL
)
146 MmHeapFree(TempExt2FileInfo
.FileBlockList
);
152 TRACE("Symbolic link path = %s\n", SymLinkPath
);
155 if (SymLinkPath
[0] == '/' || SymLinkPath
[0] == '\\')
157 // Symbolic link is an absolute path
158 // So copy it to FullPath, but skip over
159 // the '/' char at the beginning
160 strcpy(FullPath
, &SymLinkPath
[1]);
164 // Symbolic link is a relative path
165 // Copy the first part of the path
166 strcpy(FullPath
, FileName
);
168 // Remove the last part of the path
169 for (Index
=strlen(FullPath
); Index
>0; )
172 if (FullPath
[Index
] == '/' || FullPath
[Index
] == '\\')
177 FullPath
[Index
] = '\0';
179 // Concatenate the symbolic link
180 strcat(FullPath
, Index
== 0 ? "" : "/");
181 strcat(FullPath
, SymLinkPath
);
184 TRACE("Full file path = %s\n", FullPath
);
186 if (TempExt2FileInfo
.FileBlockList
!= NULL
)
188 MmHeapFree(TempExt2FileInfo
.FileBlockList
);
191 return Ext2OpenFile(FullPath
);
195 FileHandle
= MmHeapAlloc(sizeof(EXT2_FILE_INFO
));
197 if (FileHandle
== NULL
)
199 if (TempExt2FileInfo
.FileBlockList
!= NULL
)
201 MmHeapFree(TempExt2FileInfo
.FileBlockList
);
207 RtlCopyMemory(FileHandle
, &TempExt2FileInfo
, sizeof(EXT2_FILE_INFO
));
215 * This function searches the file system for the
216 * specified filename and fills in a EXT2_FILE_INFO structure
217 * with info describing the file, etc. returns true
218 * if the file exists or false otherwise
220 BOOLEAN
Ext2LookupFile(PCSTR FileName
, PEXT2_FILE_INFO Ext2FileInfoPointer
)
223 ULONG NumberOfPathParts
;
225 PVOID DirectoryBuffer
;
226 ULONG DirectoryInode
= EXT2_ROOT_INO
;
227 EXT2_INODE InodeData
;
228 EXT2_DIR_ENTRY DirectoryEntry
;
230 TRACE("Ext2LookupFile() FileName = %s\n", FileName
);
232 RtlZeroMemory(Ext2FileInfoPointer
, sizeof(EXT2_FILE_INFO
));
235 // Figure out how many sub-directories we are nested in
237 NumberOfPathParts
= FsGetNumPathParts(FileName
);
240 // Loop once for each part
242 for (i
=0; i
<NumberOfPathParts
; i
++)
245 // Get first path part
247 FsGetFirstNameFromPath(PathPart
, FileName
);
250 // Advance to the next part of the path
252 for (; (*FileName
!= '\\') && (*FileName
!= '/') && (*FileName
!= '\0'); FileName
++)
258 // Buffer the directory contents
260 if (!Ext2ReadDirectory(DirectoryInode
, &DirectoryBuffer
, &InodeData
))
266 // Search for file name in directory
268 if (!Ext2SearchDirectoryBufferForFile(DirectoryBuffer
, (ULONG
)Ext2GetInodeFileSize(&InodeData
), PathPart
, &DirectoryEntry
))
270 MmHeapFree(DirectoryBuffer
);
274 MmHeapFree(DirectoryBuffer
);
276 DirectoryInode
= DirectoryEntry
.inode
;
279 if (!Ext2ReadInode(DirectoryInode
, &InodeData
))
284 if (((InodeData
.mode
& EXT2_S_IFMT
) != EXT2_S_IFREG
) &&
285 ((InodeData
.mode
& EXT2_S_IFMT
) != EXT2_S_IFLNK
))
287 FileSystemError("Inode is not a regular file or symbolic link.");
291 // Set the drive number
292 Ext2FileInfoPointer
->DriveNumber
= Ext2DriveNumber
;
294 // If it's a regular file or a regular symbolic link
295 // then get the block pointer list otherwise it must
296 // be a fast symbolic link which doesn't have a block list
297 if (((InodeData
.mode
& EXT2_S_IFMT
) == EXT2_S_IFREG
) ||
298 ((InodeData
.mode
& EXT2_S_IFMT
) == EXT2_S_IFLNK
&& InodeData
.size
> FAST_SYMLINK_MAX_NAME_SIZE
))
300 Ext2FileInfoPointer
->FileBlockList
= Ext2ReadBlockPointerList(&InodeData
);
302 if (Ext2FileInfoPointer
->FileBlockList
== NULL
)
309 Ext2FileInfoPointer
->FileBlockList
= NULL
;
312 Ext2FileInfoPointer
->FilePointer
= 0;
313 Ext2FileInfoPointer
->FileSize
= Ext2GetInodeFileSize(&InodeData
);
314 RtlCopyMemory(&Ext2FileInfoPointer
->Inode
, &InodeData
, sizeof(EXT2_INODE
));
319 BOOLEAN
Ext2SearchDirectoryBufferForFile(PVOID DirectoryBuffer
, ULONG DirectorySize
, PCHAR FileName
, PEXT2_DIR_ENTRY DirectoryEntry
)
322 PEXT2_DIR_ENTRY CurrentDirectoryEntry
;
324 TRACE("Ext2SearchDirectoryBufferForFile() DirectoryBuffer = 0x%x DirectorySize = %d FileName = %s\n", DirectoryBuffer
, DirectorySize
, FileName
);
326 for (CurrentOffset
=0; CurrentOffset
<DirectorySize
; )
328 CurrentDirectoryEntry
= (PEXT2_DIR_ENTRY
)((ULONG_PTR
)DirectoryBuffer
+ CurrentOffset
);
330 if (CurrentDirectoryEntry
->direntlen
== 0)
335 if ((CurrentDirectoryEntry
->direntlen
+ CurrentOffset
) > DirectorySize
)
337 FileSystemError("Directory entry extends past end of directory file.");
341 TRACE("Dumping directory entry at offset %d:\n", CurrentOffset
);
342 DbgDumpBuffer(DPRINT_FILESYSTEM
, CurrentDirectoryEntry
, CurrentDirectoryEntry
->direntlen
);
344 if ((_strnicmp(FileName
, CurrentDirectoryEntry
->name
, CurrentDirectoryEntry
->namelen
) == 0) &&
345 (strlen(FileName
) == CurrentDirectoryEntry
->namelen
))
347 RtlCopyMemory(DirectoryEntry
, CurrentDirectoryEntry
, sizeof(EXT2_DIR_ENTRY
));
349 TRACE("EXT2 Directory Entry:\n");
350 TRACE("inode = %d\n", DirectoryEntry
->inode
);
351 TRACE("direntlen = %d\n", DirectoryEntry
->direntlen
);
352 TRACE("namelen = %d\n", DirectoryEntry
->namelen
);
353 TRACE("filetype = %d\n", DirectoryEntry
->filetype
);
355 for (CurrentOffset
=0; CurrentOffset
<DirectoryEntry
->namelen
; CurrentOffset
++)
357 TRACE("%c", DirectoryEntry
->name
[CurrentOffset
]);
364 CurrentOffset
+= CurrentDirectoryEntry
->direntlen
;
372 * Reads BytesToRead from open file and
373 * returns the number of bytes read in BytesRead
375 BOOLEAN
Ext2ReadFileBig(PEXT2_FILE_INFO Ext2FileInfo
, ULONGLONG BytesToRead
, ULONGLONG
* BytesRead
, PVOID Buffer
)
378 ULONG BlockNumberIndex
;
381 ULONG NumberOfBlocks
;
383 TRACE("Ext2ReadFileBig() BytesToRead = %d Buffer = 0x%x\n", (ULONG
)BytesToRead
, Buffer
);
385 if (BytesRead
!= NULL
)
390 // Make sure we have the block pointer list if we need it
391 if (Ext2FileInfo
->FileBlockList
== NULL
)
393 // Block pointer list is NULL
394 // so this better be a fast symbolic link or else
395 if (((Ext2FileInfo
->Inode
.mode
& EXT2_S_IFMT
) != EXT2_S_IFLNK
) ||
396 (Ext2FileInfo
->FileSize
> FAST_SYMLINK_MAX_NAME_SIZE
))
398 FileSystemError("Block pointer list is NULL and file is not a fast symbolic link.");
404 // If they are trying to read past the
405 // end of the file then return success
406 // with BytesRead == 0
408 if (Ext2FileInfo
->FilePointer
>= Ext2FileInfo
->FileSize
)
414 // If they are trying to read more than there is to read
415 // then adjust the amount to read
417 if ((Ext2FileInfo
->FilePointer
+ BytesToRead
) > Ext2FileInfo
->FileSize
)
419 BytesToRead
= (Ext2FileInfo
->FileSize
- Ext2FileInfo
->FilePointer
);
422 // Check if this is a fast symbolic link
423 // if so then the read is easy
424 if (((Ext2FileInfo
->Inode
.mode
& EXT2_S_IFMT
) == EXT2_S_IFLNK
) &&
425 (Ext2FileInfo
->FileSize
<= FAST_SYMLINK_MAX_NAME_SIZE
))
427 TRACE("Reading fast symbolic link data\n");
429 // Copy the data from the link
430 RtlCopyMemory(Buffer
, (PVOID
)((ULONG_PTR
)Ext2FileInfo
->FilePointer
+ Ext2FileInfo
->Inode
.symlink
), (ULONG
)BytesToRead
);
432 if (BytesRead
!= NULL
)
434 *BytesRead
= BytesToRead
;
441 // Ok, now we have to perform at most 3 calculations
442 // I'll draw you a picture (using nifty ASCII art):
444 // CurrentFilePointer -+
446 // +----------------+
448 // +-----------+-----------+-----------+-----------+
449 // | Block 1 | Block 2 | Block 3 | Block 4 |
450 // +-----------+-----------+-----------+-----------+
452 // +---------------+--------------------+
454 // BytesToRead -------+
456 // 1 - The first calculation (and read) will align
457 // the file pointer with the next block.
458 // boundary (if we are supposed to read that much)
459 // 2 - The next calculation (and read) will read
460 // in all the full blocks that the requested
461 // amount of data would cover (in this case
463 // 3 - The last calculation (and read) would read
464 // in the remainder of the data requested out of
469 // Only do the first read if we
470 // aren't aligned on a block boundary
472 if (Ext2FileInfo
->FilePointer
% Ext2BlockSizeInBytes
)
475 // Do the math for our first read
477 BlockNumberIndex
= (ULONG
)(Ext2FileInfo
->FilePointer
/ Ext2BlockSizeInBytes
);
478 BlockNumber
= Ext2FileInfo
->FileBlockList
[BlockNumberIndex
];
479 OffsetInBlock
= (Ext2FileInfo
->FilePointer
% Ext2BlockSizeInBytes
);
480 LengthInBlock
= (ULONG
)((BytesToRead
> (Ext2BlockSizeInBytes
- OffsetInBlock
)) ? (Ext2BlockSizeInBytes
- OffsetInBlock
) : BytesToRead
);
483 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
485 if (!Ext2ReadPartialBlock(BlockNumber
, OffsetInBlock
, LengthInBlock
, Buffer
))
489 if (BytesRead
!= NULL
)
491 *BytesRead
+= LengthInBlock
;
493 BytesToRead
-= LengthInBlock
;
494 Ext2FileInfo
->FilePointer
+= LengthInBlock
;
495 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ LengthInBlock
);
499 // Do the math for our second read (if any data left)
504 // Determine how many full clusters we need to read
506 NumberOfBlocks
= (ULONG
)(BytesToRead
/ Ext2BlockSizeInBytes
);
508 while (NumberOfBlocks
> 0)
510 BlockNumberIndex
= (ULONG
)(Ext2FileInfo
->FilePointer
/ Ext2BlockSizeInBytes
);
511 BlockNumber
= Ext2FileInfo
->FileBlockList
[BlockNumberIndex
];
514 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
516 if (!Ext2ReadBlock(BlockNumber
, Buffer
))
520 if (BytesRead
!= NULL
)
522 *BytesRead
+= Ext2BlockSizeInBytes
;
524 BytesToRead
-= Ext2BlockSizeInBytes
;
525 Ext2FileInfo
->FilePointer
+= Ext2BlockSizeInBytes
;
526 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Ext2BlockSizeInBytes
);
532 // Do the math for our third read (if any data left)
536 BlockNumberIndex
= (ULONG
)(Ext2FileInfo
->FilePointer
/ Ext2BlockSizeInBytes
);
537 BlockNumber
= Ext2FileInfo
->FileBlockList
[BlockNumberIndex
];
540 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
542 if (!Ext2ReadPartialBlock(BlockNumber
, 0, (ULONG
)BytesToRead
, Buffer
))
546 if (BytesRead
!= NULL
)
548 *BytesRead
+= BytesToRead
;
550 Ext2FileInfo
->FilePointer
+= BytesToRead
;
551 BytesToRead
-= BytesToRead
;
552 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (ULONG_PTR
)BytesToRead
);
558 BOOLEAN
Ext2ReadVolumeSectors(UCHAR DriveNumber
, ULONGLONG SectorNumber
, ULONG SectorCount
, PVOID Buffer
)
560 //GEOMETRY DiskGeometry;
561 //BOOLEAN ReturnValue;
562 //if (!DiskGetDriveGeometry(DriveNumber, &DiskGeometry))
566 //ReturnValue = MachDiskReadLogicalSectors(DriveNumber, SectorNumber + Ext2VolumeStartSector, SectorCount, (PVOID)DISKREADBUFFER);
567 //RtlCopyMemory(Buffer, (PVOID)DISKREADBUFFER, SectorCount * DiskGeometry.BytesPerSector);
568 //return ReturnValue;
570 return CacheReadDiskSectors(DriveNumber
, SectorNumber
+ Ext2VolumeStartSector
, SectorCount
, Buffer
);
573 BOOLEAN
Ext2ReadSuperBlock(VOID
)
576 TRACE("Ext2ReadSuperBlock()\n");
579 // Free any memory previously allocated
581 if (Ext2SuperBlock
!= NULL
)
583 MmHeapFree(Ext2SuperBlock
);
585 Ext2SuperBlock
= NULL
;
589 // Now allocate the memory to hold the super block
591 Ext2SuperBlock
= (PEXT2_SUPER_BLOCK
)MmHeapAlloc(1024);
594 // Make sure we got the memory
596 if (Ext2SuperBlock
== NULL
)
598 FileSystemError("Out of memory.");
602 // Now try to read the super block
603 // If this fails then abort
604 if (!MachDiskReadLogicalSectors(Ext2DriveNumber
, Ext2VolumeStartSector
, 8, (PVOID
)DISKREADBUFFER
))
608 RtlCopyMemory(Ext2SuperBlock
, (PVOID
)((ULONG_PTR
)DISKREADBUFFER
+ 1024), 1024);
610 TRACE("Dumping super block:\n");
611 TRACE("total_inodes: %d\n", Ext2SuperBlock
->total_inodes
);
612 TRACE("total_blocks: %d\n", Ext2SuperBlock
->total_blocks
);
613 TRACE("reserved_blocks: %d\n", Ext2SuperBlock
->reserved_blocks
);
614 TRACE("free_blocks: %d\n", Ext2SuperBlock
->free_blocks
);
615 TRACE("free_inodes: %d\n", Ext2SuperBlock
->free_inodes
);
616 TRACE("first_data_block: %d\n", Ext2SuperBlock
->first_data_block
);
617 TRACE("log2_block_size: %d\n", Ext2SuperBlock
->log2_block_size
);
618 TRACE("log2_fragment_size: %d\n", Ext2SuperBlock
->log2_fragment_size
);
619 TRACE("blocks_per_group: %d\n", Ext2SuperBlock
->blocks_per_group
);
620 TRACE("fragments_per_group: %d\n", Ext2SuperBlock
->fragments_per_group
);
621 TRACE("inodes_per_group: %d\n", Ext2SuperBlock
->inodes_per_group
);
622 TRACE("mtime: %d\n", Ext2SuperBlock
->mtime
);
623 TRACE("utime: %d\n", Ext2SuperBlock
->utime
);
624 TRACE("mnt_count: %d\n", Ext2SuperBlock
->mnt_count
);
625 TRACE("max_mnt_count: %d\n", Ext2SuperBlock
->max_mnt_count
);
626 TRACE("magic: 0x%x\n", Ext2SuperBlock
->magic
);
627 TRACE("fs_state: %d\n", Ext2SuperBlock
->fs_state
);
628 TRACE("error_handling: %d\n", Ext2SuperBlock
->error_handling
);
629 TRACE("minor_revision_level: %d\n", Ext2SuperBlock
->minor_revision_level
);
630 TRACE("lastcheck: %d\n", Ext2SuperBlock
->lastcheck
);
631 TRACE("checkinterval: %d\n", Ext2SuperBlock
->checkinterval
);
632 TRACE("creator_os: %d\n", Ext2SuperBlock
->creator_os
);
633 TRACE("revision_level: %d\n", Ext2SuperBlock
->revision_level
);
634 TRACE("uid_reserved: %d\n", Ext2SuperBlock
->uid_reserved
);
635 TRACE("gid_reserved: %d\n", Ext2SuperBlock
->gid_reserved
);
636 TRACE("first_inode: %d\n", Ext2SuperBlock
->first_inode
);
637 TRACE("inode_size: %d\n", Ext2SuperBlock
->inode_size
);
638 TRACE("block_group_number: %d\n", Ext2SuperBlock
->block_group_number
);
639 TRACE("feature_compatibility: 0x%x\n", Ext2SuperBlock
->feature_compatibility
);
640 TRACE("feature_incompat: 0x%x\n", Ext2SuperBlock
->feature_incompat
);
641 TRACE("feature_ro_compat: 0x%x\n", Ext2SuperBlock
->feature_ro_compat
);
642 TRACE("unique_id = { 0x%x, 0x%x, 0x%x, 0x%x }\n",
643 Ext2SuperBlock
->unique_id
[0], Ext2SuperBlock
->unique_id
[1], Ext2SuperBlock
->unique_id
[2], Ext2SuperBlock
->unique_id
[3]);
644 TRACE("volume_name = '%.16s'\n", Ext2SuperBlock
->volume_name
);
645 TRACE("last_mounted_on = '%.64s'\n", Ext2SuperBlock
->last_mounted_on
);
646 TRACE("compression_info = 0x%x\n", Ext2SuperBlock
->compression_info
);
649 // Check the super block magic
651 if (Ext2SuperBlock
->magic
!= EXT2_MAGIC
)
653 FileSystemError("Invalid super block magic (0xef53)");
658 // Check the revision level
660 if (Ext2SuperBlock
->revision_level
> EXT2_DYNAMIC_REVISION
)
662 FileSystemError("FreeLoader does not understand the revision of this EXT2/EXT3 filesystem.\nPlease update FreeLoader.");
667 // Check the feature set
668 // Don't need to check the compatible or read-only compatible features
669 // because we only mount the filesystem as read-only
671 if ((Ext2SuperBlock
->revision_level
>= EXT2_DYNAMIC_REVISION
) &&
672 (/*((Ext2SuperBlock->s_feature_compat & ~EXT3_FEATURE_COMPAT_SUPP) != 0) ||*/
673 /*((Ext2SuperBlock->s_feature_ro_compat & ~EXT3_FEATURE_RO_COMPAT_SUPP) != 0) ||*/
674 ((Ext2SuperBlock
->feature_incompat
& ~EXT3_FEATURE_INCOMPAT_SUPP
) != 0)))
676 FileSystemError("FreeLoader does not understand features of this EXT2/EXT3 filesystem.\nPlease update FreeLoader.");
680 // Calculate the group count
681 Ext2GroupCount
= (Ext2SuperBlock
->total_blocks
- Ext2SuperBlock
->first_data_block
+ Ext2SuperBlock
->blocks_per_group
- 1) / Ext2SuperBlock
->blocks_per_group
;
682 TRACE("Ext2GroupCount: %d\n", Ext2GroupCount
);
684 // Calculate the block size
685 Ext2BlockSizeInBytes
= 1024 << Ext2SuperBlock
->log2_block_size
;
686 Ext2BlockSizeInSectors
= Ext2BlockSizeInBytes
/ Ext2DiskGeometry
.BytesPerSector
;
687 TRACE("Ext2BlockSizeInBytes: %d\n", Ext2BlockSizeInBytes
);
688 TRACE("Ext2BlockSizeInSectors: %d\n", Ext2BlockSizeInSectors
);
690 // Calculate the fragment size
691 if (Ext2SuperBlock
->log2_fragment_size
>= 0)
693 Ext2FragmentSizeInBytes
= 1024 << Ext2SuperBlock
->log2_fragment_size
;
697 Ext2FragmentSizeInBytes
= 1024 >> -(Ext2SuperBlock
->log2_fragment_size
);
699 Ext2FragmentSizeInSectors
= Ext2FragmentSizeInBytes
/ Ext2DiskGeometry
.BytesPerSector
;
700 TRACE("Ext2FragmentSizeInBytes: %d\n", Ext2FragmentSizeInBytes
);
701 TRACE("Ext2FragmentSizeInSectors: %d\n", Ext2FragmentSizeInSectors
);
703 // Verify that the fragment size and the block size are equal
704 if (Ext2BlockSizeInBytes
!= Ext2FragmentSizeInBytes
)
706 FileSystemError("The fragment size must be equal to the block size.");
710 // Calculate the number of inodes in one block
711 Ext2InodesPerBlock
= Ext2BlockSizeInBytes
/ EXT2_INODE_SIZE(Ext2SuperBlock
);
712 TRACE("Ext2InodesPerBlock: %d\n", Ext2InodesPerBlock
);
714 // Calculate the number of group descriptors in one block
715 Ext2GroupDescPerBlock
= EXT2_DESC_PER_BLOCK(Ext2SuperBlock
);
716 TRACE("Ext2GroupDescPerBlock: %d\n", Ext2GroupDescPerBlock
);
721 BOOLEAN
Ext2ReadGroupDescriptors(VOID
)
723 ULONG GroupDescBlockCount
;
725 PUCHAR CurrentGroupDescBlock
;
727 TRACE("Ext2ReadGroupDescriptors()\n");
730 // Free any memory previously allocated
732 if (Ext2GroupDescriptors
!= NULL
)
734 MmHeapFree(Ext2GroupDescriptors
);
736 Ext2GroupDescriptors
= NULL
;
740 // Now allocate the memory to hold the group descriptors
742 GroupDescBlockCount
= ROUND_UP(Ext2GroupCount
, Ext2GroupDescPerBlock
) / Ext2GroupDescPerBlock
;
743 Ext2GroupDescriptors
= (PEXT2_GROUP_DESC
)MmHeapAlloc(GroupDescBlockCount
* Ext2BlockSizeInBytes
);
746 // Make sure we got the memory
748 if (Ext2GroupDescriptors
== NULL
)
750 FileSystemError("Out of memory.");
754 // Now read the group descriptors
755 CurrentGroupDescBlock
= (PUCHAR
)Ext2GroupDescriptors
;
756 BlockNumber
= Ext2SuperBlock
->first_data_block
+ 1;
758 while (GroupDescBlockCount
--)
760 if (!Ext2ReadBlock(BlockNumber
, CurrentGroupDescBlock
))
766 CurrentGroupDescBlock
+= Ext2BlockSizeInBytes
;
772 BOOLEAN
Ext2ReadDirectory(ULONG Inode
, PVOID
* DirectoryBuffer
, PEXT2_INODE InodePointer
)
774 EXT2_FILE_INFO DirectoryFileInfo
;
776 TRACE("Ext2ReadDirectory() Inode = %d\n", Inode
);
778 // Read the directory inode
779 if (!Ext2ReadInode(Inode
, InodePointer
))
784 // Make sure it is a directory inode
785 if ((InodePointer
->mode
& EXT2_S_IFMT
) != EXT2_S_IFDIR
)
787 FileSystemError("Inode is not a directory.");
791 // Fill in file info struct so we can call Ext2ReadFileBig()
792 RtlZeroMemory(&DirectoryFileInfo
, sizeof(EXT2_FILE_INFO
));
793 DirectoryFileInfo
.DriveNumber
= Ext2DriveNumber
;
794 DirectoryFileInfo
.FileBlockList
= Ext2ReadBlockPointerList(InodePointer
);
795 DirectoryFileInfo
.FilePointer
= 0;
796 DirectoryFileInfo
.FileSize
= Ext2GetInodeFileSize(InodePointer
);
798 if (DirectoryFileInfo
.FileBlockList
== NULL
)
804 // Now allocate the memory to hold the group descriptors
806 ASSERT(DirectoryFileInfo
.FileSize
<= 0xFFFFFFFF);
807 *DirectoryBuffer
= (PEXT2_DIR_ENTRY
)MmHeapAlloc((ULONG
)DirectoryFileInfo
.FileSize
);
810 // Make sure we got the memory
812 if (*DirectoryBuffer
== NULL
)
814 MmHeapFree(DirectoryFileInfo
.FileBlockList
);
815 FileSystemError("Out of memory.");
819 // Now read the root directory data
820 if (!Ext2ReadFileBig(&DirectoryFileInfo
, DirectoryFileInfo
.FileSize
, NULL
, *DirectoryBuffer
))
822 MmHeapFree(*DirectoryBuffer
);
823 *DirectoryBuffer
= NULL
;
824 MmHeapFree(DirectoryFileInfo
.FileBlockList
);
828 MmHeapFree(DirectoryFileInfo
.FileBlockList
);
832 BOOLEAN
Ext2ReadBlock(ULONG BlockNumber
, PVOID Buffer
)
834 CHAR ErrorString
[80];
836 TRACE("Ext2ReadBlock() BlockNumber = %d Buffer = 0x%x\n", BlockNumber
, Buffer
);
838 // Make sure its a valid block
839 if (BlockNumber
> Ext2SuperBlock
->total_blocks
)
841 sprintf(ErrorString
, "Error reading block %d - block out of range.", (int) BlockNumber
);
842 FileSystemError(ErrorString
);
846 // Check to see if this is a sparse block
847 if (BlockNumber
== 0)
849 TRACE("Block is part of a sparse file. Zeroing input buffer.\n");
851 RtlZeroMemory(Buffer
, Ext2BlockSizeInBytes
);
856 return Ext2ReadVolumeSectors(Ext2DriveNumber
, (ULONGLONG
)BlockNumber
* Ext2BlockSizeInSectors
, Ext2BlockSizeInSectors
, Buffer
);
860 * Ext2ReadPartialBlock()
861 * Reads part of a block into memory
863 BOOLEAN
Ext2ReadPartialBlock(ULONG BlockNumber
, ULONG StartingOffset
, ULONG Length
, PVOID Buffer
)
867 TRACE("Ext2ReadPartialBlock() BlockNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", BlockNumber
, StartingOffset
, Length
, Buffer
);
869 TempBuffer
= HeapAllocate(FrLdrTempHeap
, Ext2BlockSizeInBytes
, '2TXE');
871 if (!Ext2ReadBlock(BlockNumber
, TempBuffer
))
876 memcpy(Buffer
, ((PUCHAR
)TempBuffer
+ StartingOffset
), Length
);
878 HeapFree(FrLdrTempHeap
, TempBuffer
, '2TXE');
883 ULONG
Ext2GetGroupDescBlockNumber(ULONG Group
)
885 return (((Group
* sizeof(EXT2_GROUP_DESC
)) / Ext2GroupDescPerBlock
) + Ext2SuperBlock
->first_data_block
+ 1);
888 ULONG
Ext2GetGroupDescOffsetInBlock(ULONG Group
)
890 return ((Group
* sizeof(EXT2_GROUP_DESC
)) % Ext2GroupDescPerBlock
);
893 ULONG
Ext2GetInodeGroupNumber(ULONG Inode
)
895 return ((Inode
- 1) / Ext2SuperBlock
->inodes_per_group
);
898 ULONG
Ext2GetInodeBlockNumber(ULONG Inode
)
900 return (((Inode
- 1) % Ext2SuperBlock
->inodes_per_group
) / Ext2InodesPerBlock
);
903 ULONG
Ext2GetInodeOffsetInBlock(ULONG Inode
)
905 return (((Inode
- 1) % Ext2SuperBlock
->inodes_per_group
) % Ext2InodesPerBlock
);
908 BOOLEAN
Ext2ReadInode(ULONG Inode
, PEXT2_INODE InodeBuffer
)
910 ULONG InodeGroupNumber
;
911 ULONG InodeBlockNumber
;
912 ULONG InodeOffsetInBlock
;
913 CHAR ErrorString
[80];
914 EXT2_GROUP_DESC GroupDescriptor
;
917 TRACE("Ext2ReadInode() Inode = %d\n", Inode
);
919 // Make sure its a valid inode
920 if ((Inode
< 1) || (Inode
> Ext2SuperBlock
->total_inodes
))
922 sprintf(ErrorString
, "Error reading inode %ld - inode out of range.", Inode
);
923 FileSystemError(ErrorString
);
927 // Get inode group & block number and offset in block
928 InodeGroupNumber
= Ext2GetInodeGroupNumber(Inode
);
929 InodeBlockNumber
= Ext2GetInodeBlockNumber(Inode
);
930 InodeOffsetInBlock
= Ext2GetInodeOffsetInBlock(Inode
);
931 TRACE("InodeGroupNumber = %d\n", InodeGroupNumber
);
932 TRACE("InodeBlockNumber = %d\n", InodeBlockNumber
);
933 TRACE("InodeOffsetInBlock = %d\n", InodeOffsetInBlock
);
935 // Read the group descriptor
936 if (!Ext2ReadGroupDescriptor(InodeGroupNumber
, &GroupDescriptor
))
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
);
946 Status
= Ext2ReadPartialBlock(InodeBlockNumber
,
947 (InodeOffsetInBlock
* EXT2_INODE_SIZE(Ext2SuperBlock
)),
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]);
985 BOOLEAN
Ext2ReadGroupDescriptor(ULONG Group
, PEXT2_GROUP_DESC GroupBuffer
)
987 TRACE("Ext2ReadGroupDescriptor()\n");
989 /*if (!Ext2ReadBlock(Ext2GetGroupDescBlockNumber(Group), (PVOID)FILESYSBUFFER))
994 RtlCopyMemory(GroupBuffer, (PVOID)(FILESYSBUFFER + Ext2GetGroupDescOffsetInBlock(Group)), sizeof(EXT2_GROUP_DESC));*/
996 RtlCopyMemory(GroupBuffer
, &Ext2GroupDescriptors
[Group
], sizeof(EXT2_GROUP_DESC
));
998 TRACE("Dumping group descriptor:\n");
999 TRACE("block_id = %d\n", GroupBuffer
->block_id
);
1000 TRACE("inode_id = %d\n", GroupBuffer
->inode_id
);
1001 TRACE("inode_table_id = %d\n", GroupBuffer
->inode_table_id
);
1002 TRACE("free_blocks = %d\n", GroupBuffer
->free_blocks
);
1003 TRACE("free_inodes = %d\n", GroupBuffer
->free_inodes
);
1004 TRACE("used_dirs = %d\n", GroupBuffer
->used_dirs
);
1009 ULONG
* Ext2ReadBlockPointerList(PEXT2_INODE Inode
)
1014 ULONG CurrentBlockInList
;
1017 TRACE("Ext2ReadBlockPointerList()\n");
1019 // Get the number of blocks this file occupies
1020 // I would just use Inode->i_blocks but it
1021 // doesn't seem to be the number of blocks
1022 // the file size corresponds to, but instead
1023 // it is much bigger.
1024 //BlockCount = Inode->i_blocks;
1025 FileSize
= Ext2GetInodeFileSize(Inode
);
1026 FileSize
= ROUND_UP(FileSize
, Ext2BlockSizeInBytes
);
1027 BlockCount
= (ULONG
)(FileSize
/ Ext2BlockSizeInBytes
);
1029 // Allocate the memory for the block list
1030 BlockList
= MmHeapAlloc(BlockCount
* sizeof(ULONG
));
1031 if (BlockList
== NULL
)
1036 RtlZeroMemory(BlockList
, BlockCount
* sizeof(ULONG
));
1038 // Copy the direct block pointers
1039 for (CurrentBlockInList
= CurrentBlock
= 0;
1040 CurrentBlockInList
< BlockCount
&& CurrentBlock
< INDIRECT_BLOCKS
;
1041 CurrentBlock
++, CurrentBlockInList
++)
1043 BlockList
[CurrentBlockInList
] = Inode
->blocks
.dir_blocks
[CurrentBlock
];
1046 // Copy the indirect block pointers
1047 if (CurrentBlockInList
< BlockCount
)
1049 if (!Ext2CopyIndirectBlockPointers(BlockList
, &CurrentBlockInList
, BlockCount
, Inode
->blocks
.indir_block
))
1051 MmHeapFree(BlockList
);
1056 // Copy the double indirect block pointers
1057 if (CurrentBlockInList
< BlockCount
)
1059 if (!Ext2CopyDoubleIndirectBlockPointers(BlockList
, &CurrentBlockInList
, BlockCount
, Inode
->blocks
.double_indir_block
))
1061 MmHeapFree(BlockList
);
1066 // Copy the triple indirect block pointers
1067 if (CurrentBlockInList
< BlockCount
)
1069 if (!Ext2CopyTripleIndirectBlockPointers(BlockList
, &CurrentBlockInList
, BlockCount
, Inode
->blocks
.tripple_indir_block
))
1071 MmHeapFree(BlockList
);
1079 ULONGLONG
Ext2GetInodeFileSize(PEXT2_INODE Inode
)
1081 if ((Inode
->mode
& EXT2_S_IFMT
) == EXT2_S_IFDIR
)
1083 return (ULONGLONG
)(Inode
->size
);
1087 return ((ULONGLONG
)(Inode
->size
) | ((ULONGLONG
)(Inode
->dir_acl
) << 32));
1091 BOOLEAN
Ext2CopyIndirectBlockPointers(ULONG
* BlockList
, ULONG
* CurrentBlockInList
, ULONG BlockCount
, ULONG IndirectBlock
)
1095 ULONG BlockPointersPerBlock
;
1097 TRACE("Ext2CopyIndirectBlockPointers() BlockCount = %d\n", BlockCount
);
1099 BlockPointersPerBlock
= Ext2BlockSizeInBytes
/ sizeof(ULONG
);
1101 BlockBuffer
= HeapAllocate(FrLdrTempHeap
,
1102 Ext2BlockSizeInBytes
,
1109 if (!Ext2ReadBlock(IndirectBlock
, BlockBuffer
))
1114 for (CurrentBlock
=0; (*CurrentBlockInList
)<BlockCount
&& CurrentBlock
<BlockPointersPerBlock
; CurrentBlock
++)
1116 BlockList
[(*CurrentBlockInList
)] = BlockBuffer
[CurrentBlock
];
1117 (*CurrentBlockInList
)++;
1120 HeapFree(FrLdrTempHeap
, BlockBuffer
, '2TXE');
1125 BOOLEAN
Ext2CopyDoubleIndirectBlockPointers(ULONG
* BlockList
, ULONG
* CurrentBlockInList
, ULONG BlockCount
, ULONG DoubleIndirectBlock
)
1129 ULONG BlockPointersPerBlock
;
1131 TRACE("Ext2CopyDoubleIndirectBlockPointers() BlockCount = %d\n", BlockCount
);
1133 BlockPointersPerBlock
= Ext2BlockSizeInBytes
/ sizeof(ULONG
);
1135 BlockBuffer
= (ULONG
*)MmHeapAlloc(Ext2BlockSizeInBytes
);
1136 if (BlockBuffer
== NULL
)
1141 if (!Ext2ReadBlock(DoubleIndirectBlock
, BlockBuffer
))
1143 MmHeapFree(BlockBuffer
);
1147 for (CurrentBlock
=0; (*CurrentBlockInList
)<BlockCount
&& CurrentBlock
<BlockPointersPerBlock
; CurrentBlock
++)
1149 if (!Ext2CopyIndirectBlockPointers(BlockList
, CurrentBlockInList
, BlockCount
, BlockBuffer
[CurrentBlock
]))
1151 MmHeapFree(BlockBuffer
);
1156 MmHeapFree(BlockBuffer
);
1160 BOOLEAN
Ext2CopyTripleIndirectBlockPointers(ULONG
* BlockList
, ULONG
* CurrentBlockInList
, ULONG BlockCount
, ULONG TripleIndirectBlock
)
1164 ULONG BlockPointersPerBlock
;
1166 TRACE("Ext2CopyTripleIndirectBlockPointers() BlockCount = %d\n", BlockCount
);
1168 BlockPointersPerBlock
= Ext2BlockSizeInBytes
/ sizeof(ULONG
);
1170 BlockBuffer
= (ULONG
*)MmHeapAlloc(Ext2BlockSizeInBytes
);
1171 if (BlockBuffer
== NULL
)
1176 if (!Ext2ReadBlock(TripleIndirectBlock
, BlockBuffer
))
1178 MmHeapFree(BlockBuffer
);
1182 for (CurrentBlock
=0; (*CurrentBlockInList
)<BlockCount
&& CurrentBlock
<BlockPointersPerBlock
; CurrentBlock
++)
1184 if (!Ext2CopyDoubleIndirectBlockPointers(BlockList
, CurrentBlockInList
, BlockCount
, BlockBuffer
[CurrentBlock
]))
1186 MmHeapFree(BlockBuffer
);
1191 MmHeapFree(BlockBuffer
);
1195 LONG
Ext2Close(ULONG FileId
)
1197 PEXT2_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1199 MmHeapFree(FileHandle
);
1204 LONG
Ext2GetFileInformation(ULONG FileId
, FILEINFORMATION
* Information
)
1206 PEXT2_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1208 RtlZeroMemory(Information
, sizeof(FILEINFORMATION
));
1209 Information
->EndingAddress
.QuadPart
= FileHandle
->FileSize
;
1210 Information
->CurrentAddress
.QuadPart
= FileHandle
->FilePointer
;
1212 TRACE("Ext2GetFileInformation() FileSize = %d\n",
1213 Information
->EndingAddress
.LowPart
);
1214 TRACE("Ext2GetFileInformation() FilePointer = %d\n",
1215 Information
->CurrentAddress
.LowPart
);
1220 LONG
Ext2Open(CHAR
* Path
, OPENMODE OpenMode
, ULONG
* FileId
)
1222 PEXT2_FILE_INFO FileHandle
;
1225 if (OpenMode
!= OpenReadOnly
)
1228 //DeviceId = FsGetDeviceId(*FileId);
1230 TRACE("Ext2Open() FileName = %s\n", Path
);
1233 // Call old open method
1235 FileHandle
= Ext2OpenFile(Path
);
1244 // Success. Remember the handle
1246 FsSetDeviceSpecific(*FileId
, FileHandle
);
1250 LONG
Ext2Read(ULONG FileId
, VOID
* Buffer
, ULONG N
, ULONG
* Count
)
1252 PEXT2_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1253 ULONGLONG BytesReadBig
;
1259 ret
= Ext2ReadFileBig(FileHandle
, N
, &BytesReadBig
, Buffer
);
1260 *Count
= (ULONG
)BytesReadBig
;
1263 // Check for success
1271 LONG
Ext2Seek(ULONG FileId
, LARGE_INTEGER
* Position
, SEEKMODE SeekMode
)
1273 PEXT2_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1275 TRACE("Ext2Seek() NewFilePointer = %lu\n", Position
->LowPart
);
1277 if (SeekMode
!= SeekAbsolute
)
1279 if (Position
->HighPart
!= 0)
1281 if (Position
->LowPart
>= FileHandle
->FileSize
)
1284 FileHandle
->FilePointer
= Position
->LowPart
;
1288 const DEVVTBL Ext2FuncTable
=
1291 Ext2GetFileInformation
,
1298 const DEVVTBL
* Ext2Mount(ULONG DeviceId
)
1300 EXT2_SUPER_BLOCK SuperBlock
;
1301 LARGE_INTEGER Position
;
1306 // Read the SuperBlock
1308 Position
.HighPart
= 0;
1309 Position
.LowPart
= 2 * 512;
1310 ret
= ArcSeek(DeviceId
, &Position
, SeekAbsolute
);
1311 if (ret
!= ESUCCESS
)
1313 ret
= ArcRead(DeviceId
, &SuperBlock
, sizeof(SuperBlock
), &Count
);
1314 if (ret
!= ESUCCESS
|| Count
!= sizeof(SuperBlock
))
1318 // Check if SuperBlock is valid. If yes, return Ext2 function table
1320 if (SuperBlock
.magic
== EXT2_MAGIC
)
1323 // Compatibility hack as long as FS is not using underlying device DeviceId
1326 ULONGLONG StartSector
;
1327 ULONGLONG SectorCount
;
1329 if (!DiskGetBootVolume(&DriveNumber
, &StartSector
, &SectorCount
, &Type
))
1331 Ext2OpenVolume(DriveNumber
, StartSector
, SectorCount
);
1332 return &Ext2FuncTable
;