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 BOOLEAN
Ext2OpenVolume(UCHAR DriveNumber
, ULONGLONG VolumeStartSector
, ULONGLONG PartitionSectorCount
);
25 PEXT2_FILE_INFO
Ext2OpenFile(PCSTR FileName
);
26 BOOLEAN
Ext2LookupFile(PCSTR FileName
, PEXT2_FILE_INFO Ext2FileInfoPointer
);
27 BOOLEAN
Ext2SearchDirectoryBufferForFile(PVOID DirectoryBuffer
, ULONG DirectorySize
, PCHAR FileName
, PEXT2_DIR_ENTRY DirectoryEntry
);
28 BOOLEAN
Ext2ReadVolumeSectors(UCHAR DriveNumber
, ULONGLONG SectorNumber
, ULONGLONG SectorCount
, PVOID Buffer
);
30 BOOLEAN
Ext2ReadFileBig(PEXT2_FILE_INFO Ext2FileInfo
, ULONGLONG BytesToRead
, ULONGLONG
* BytesRead
, PVOID Buffer
);
31 BOOLEAN
Ext2ReadSuperBlock(VOID
);
32 BOOLEAN
Ext2ReadGroupDescriptors(VOID
);
33 BOOLEAN
Ext2ReadDirectory(ULONG Inode
, PVOID
* DirectoryBuffer
, PEXT2_INODE InodePointer
);
34 BOOLEAN
Ext2ReadBlock(ULONG BlockNumber
, PVOID Buffer
);
35 BOOLEAN
Ext2ReadPartialBlock(ULONG BlockNumber
, ULONG StartingOffset
, ULONG Length
, PVOID Buffer
);
36 ULONG
Ext2GetGroupDescBlockNumber(ULONG Group
);
37 ULONG
Ext2GetGroupDescOffsetInBlock(ULONG Group
);
38 ULONG
Ext2GetInodeGroupNumber(ULONG Inode
);
39 ULONG
Ext2GetInodeBlockNumber(ULONG Inode
);
40 ULONG
Ext2GetInodeOffsetInBlock(ULONG Inode
);
41 BOOLEAN
Ext2ReadInode(ULONG Inode
, PEXT2_INODE InodeBuffer
);
42 BOOLEAN
Ext2ReadGroupDescriptor(ULONG Group
, PEXT2_GROUP_DESC GroupBuffer
);
43 ULONG
* Ext2ReadBlockPointerList(PEXT2_INODE Inode
);
44 ULONGLONG
Ext2GetInodeFileSize(PEXT2_INODE Inode
);
45 BOOLEAN
Ext2CopyIndirectBlockPointers(ULONG
* BlockList
, ULONG
* CurrentBlockInList
, ULONG BlockCount
, ULONG IndirectBlock
);
46 BOOLEAN
Ext2CopyDoubleIndirectBlockPointers(ULONG
* BlockList
, ULONG
* CurrentBlockInList
, ULONG BlockCount
, ULONG DoubleIndirectBlock
);
47 BOOLEAN
Ext2CopyTripleIndirectBlockPointers(ULONG
* BlockList
, ULONG
* CurrentBlockInList
, ULONG BlockCount
, ULONG TripleIndirectBlock
);
49 GEOMETRY Ext2DiskGeometry
; // Ext2 file system disk geometry
51 PEXT2_SUPER_BLOCK Ext2SuperBlock
= NULL
; // Ext2 file system super block
52 PEXT2_GROUP_DESC Ext2GroupDescriptors
= NULL
; // Ext2 file system group descriptors
54 UCHAR Ext2DriveNumber
= 0; // Ext2 file system drive number
55 ULONGLONG Ext2VolumeStartSector
= 0; // Ext2 file system starting sector
56 ULONG Ext2BlockSizeInBytes
= 0; // Block size in bytes
57 ULONG Ext2BlockSizeInSectors
= 0; // Block size in sectors
58 ULONG Ext2FragmentSizeInBytes
= 0; // Fragment size in bytes
59 ULONG Ext2FragmentSizeInSectors
= 0; // Fragment size in sectors
60 ULONG Ext2GroupCount
= 0; // Number of groups in this file system
61 ULONG Ext2InodesPerBlock
= 0; // Number of inodes in one block
62 ULONG Ext2GroupDescPerBlock
= 0; // Number of group descriptors in one block
64 BOOLEAN
DiskGetBootVolume(PULONG DriveNumber
, PULONGLONG StartSector
, PULONGLONG SectorCount
, int *FsType
)
73 BOOLEAN
Ext2OpenVolume(UCHAR DriveNumber
, ULONGLONG VolumeStartSector
, ULONGLONG PartitionSectorCount
)
76 DPRINTM(DPRINT_FILESYSTEM
, "Ext2OpenVolume() DriveNumber = 0x%x VolumeStartSector = %d\n", DriveNumber
, VolumeStartSector
);
78 // Store the drive number and start sector
79 Ext2DriveNumber
= DriveNumber
;
80 Ext2VolumeStartSector
= VolumeStartSector
;
82 if (!MachDiskGetDriveGeometry(DriveNumber
, &Ext2DiskGeometry
))
88 // Initialize the disk cache for this drive
90 if (!CacheInitializeDrive(DriveNumber
))
95 // Read in the super block
96 if (!Ext2ReadSuperBlock())
101 // Read in the group descriptors
102 if (!Ext2ReadGroupDescriptors())
112 * Tries to open the file 'name' and returns true or false
113 * for success and failure respectively
115 PEXT2_FILE_INFO
Ext2OpenFile(PCSTR FileName
)
117 EXT2_FILE_INFO TempExt2FileInfo
;
118 PEXT2_FILE_INFO FileHandle
;
119 CHAR SymLinkPath
[EXT2_NAME_LEN
];
120 CHAR FullPath
[EXT2_NAME_LEN
* 2];
123 DPRINTM(DPRINT_FILESYSTEM
, "Ext2OpenFile() FileName = %s\n", FileName
);
125 RtlZeroMemory(SymLinkPath
, sizeof(SymLinkPath
));
127 // Lookup the file in the file system
128 if (!Ext2LookupFile(FileName
, &TempExt2FileInfo
))
133 // If we got a symbolic link then fix up the path
134 // and re-call this function
135 if ((TempExt2FileInfo
.Inode
.mode
& EXT2_S_IFMT
) == EXT2_S_IFLNK
)
137 DPRINTM(DPRINT_FILESYSTEM
, "File is a symbolic link\n");
139 // Now read in the symbolic link path
140 if (!Ext2ReadFileBig(&TempExt2FileInfo
, TempExt2FileInfo
.FileSize
, NULL
, SymLinkPath
))
142 if (TempExt2FileInfo
.FileBlockList
!= NULL
)
144 MmHeapFree(TempExt2FileInfo
.FileBlockList
);
150 DPRINTM(DPRINT_FILESYSTEM
, "Symbolic link path = %s\n", SymLinkPath
);
153 if (SymLinkPath
[0] == '/' || SymLinkPath
[0] == '\\')
155 // Symbolic link is an absolute path
156 // So copy it to FullPath, but skip over
157 // the '/' char at the beginning
158 strcpy(FullPath
, &SymLinkPath
[1]);
162 // Symbolic link is a relative path
163 // Copy the first part of the path
164 strcpy(FullPath
, FileName
);
166 // Remove the last part of the path
167 for (Index
=strlen(FullPath
); Index
>0; )
170 if (FullPath
[Index
] == '/' || FullPath
[Index
] == '\\')
175 FullPath
[Index
] = '\0';
177 // Concatenate the symbolic link
178 strcat(FullPath
, Index
== 0 ? "" : "/");
179 strcat(FullPath
, SymLinkPath
);
182 DPRINTM(DPRINT_FILESYSTEM
, "Full file path = %s\n", FullPath
);
184 if (TempExt2FileInfo
.FileBlockList
!= NULL
)
186 MmHeapFree(TempExt2FileInfo
.FileBlockList
);
189 return Ext2OpenFile(FullPath
);
193 FileHandle
= MmHeapAlloc(sizeof(EXT2_FILE_INFO
));
195 if (FileHandle
== NULL
)
197 if (TempExt2FileInfo
.FileBlockList
!= NULL
)
199 MmHeapFree(TempExt2FileInfo
.FileBlockList
);
205 RtlCopyMemory(FileHandle
, &TempExt2FileInfo
, sizeof(EXT2_FILE_INFO
));
213 * This function searches the file system for the
214 * specified filename and fills in a EXT2_FILE_INFO structure
215 * with info describing the file, etc. returns true
216 * if the file exists or false otherwise
218 BOOLEAN
Ext2LookupFile(PCSTR FileName
, PEXT2_FILE_INFO Ext2FileInfoPointer
)
221 ULONG NumberOfPathParts
;
223 PVOID DirectoryBuffer
;
224 ULONG DirectoryInode
= EXT2_ROOT_INO
;
225 EXT2_INODE InodeData
;
226 EXT2_DIR_ENTRY DirectoryEntry
;
228 DPRINTM(DPRINT_FILESYSTEM
, "Ext2LookupFile() FileName = %s\n", FileName
);
230 RtlZeroMemory(Ext2FileInfoPointer
, sizeof(EXT2_FILE_INFO
));
233 // Figure out how many sub-directories we are nested in
235 NumberOfPathParts
= FsGetNumPathParts(FileName
);
238 // Loop once for each part
240 for (i
=0; i
<NumberOfPathParts
; i
++)
243 // Get first path part
245 FsGetFirstNameFromPath(PathPart
, FileName
);
248 // Advance to the next part of the path
250 for (; (*FileName
!= '\\') && (*FileName
!= '/') && (*FileName
!= '\0'); FileName
++)
256 // Buffer the directory contents
258 if (!Ext2ReadDirectory(DirectoryInode
, &DirectoryBuffer
, &InodeData
))
264 // Search for file name in directory
266 if (!Ext2SearchDirectoryBufferForFile(DirectoryBuffer
, (ULONG
)Ext2GetInodeFileSize(&InodeData
), PathPart
, &DirectoryEntry
))
268 MmHeapFree(DirectoryBuffer
);
272 MmHeapFree(DirectoryBuffer
);
274 DirectoryInode
= DirectoryEntry
.inode
;
277 if (!Ext2ReadInode(DirectoryInode
, &InodeData
))
282 if (((InodeData
.mode
& EXT2_S_IFMT
) != EXT2_S_IFREG
) &&
283 ((InodeData
.mode
& EXT2_S_IFMT
) != EXT2_S_IFLNK
))
285 FileSystemError("Inode is not a regular file or symbolic link.");
289 // Set the drive number
290 Ext2FileInfoPointer
->DriveNumber
= Ext2DriveNumber
;
292 // If it's a regular file or a regular symbolic link
293 // then get the block pointer list otherwise it must
294 // be a fast symbolic link which doesn't have a block list
295 if (((InodeData
.mode
& EXT2_S_IFMT
) == EXT2_S_IFREG
) ||
296 ((InodeData
.mode
& EXT2_S_IFMT
) == EXT2_S_IFLNK
&& InodeData
.size
> FAST_SYMLINK_MAX_NAME_SIZE
))
298 Ext2FileInfoPointer
->FileBlockList
= Ext2ReadBlockPointerList(&InodeData
);
300 if (Ext2FileInfoPointer
->FileBlockList
== NULL
)
307 Ext2FileInfoPointer
->FileBlockList
= NULL
;
310 Ext2FileInfoPointer
->FilePointer
= 0;
311 Ext2FileInfoPointer
->FileSize
= Ext2GetInodeFileSize(&InodeData
);
312 RtlCopyMemory(&Ext2FileInfoPointer
->Inode
, &InodeData
, sizeof(EXT2_INODE
));
317 BOOLEAN
Ext2SearchDirectoryBufferForFile(PVOID DirectoryBuffer
, ULONG DirectorySize
, PCHAR FileName
, PEXT2_DIR_ENTRY DirectoryEntry
)
320 PEXT2_DIR_ENTRY CurrentDirectoryEntry
;
322 DPRINTM(DPRINT_FILESYSTEM
, "Ext2SearchDirectoryBufferForFile() DirectoryBuffer = 0x%x DirectorySize = %d FileName = %s\n", DirectoryBuffer
, DirectorySize
, FileName
);
324 for (CurrentOffset
=0; CurrentOffset
<DirectorySize
; )
326 CurrentDirectoryEntry
= (PEXT2_DIR_ENTRY
)((ULONG_PTR
)DirectoryBuffer
+ CurrentOffset
);
328 if (CurrentDirectoryEntry
->direntlen
== 0)
333 if ((CurrentDirectoryEntry
->direntlen
+ CurrentOffset
) > DirectorySize
)
335 FileSystemError("Directory entry extends past end of directory file.");
339 DPRINTM(DPRINT_FILESYSTEM
, "Dumping directory entry at offset %d:\n", CurrentOffset
);
340 DbgDumpBuffer(DPRINT_FILESYSTEM
, CurrentDirectoryEntry
, CurrentDirectoryEntry
->direntlen
);
342 if ((_strnicmp(FileName
, CurrentDirectoryEntry
->name
, CurrentDirectoryEntry
->namelen
) == 0) &&
343 (strlen(FileName
) == CurrentDirectoryEntry
->namelen
))
345 RtlCopyMemory(DirectoryEntry
, CurrentDirectoryEntry
, sizeof(EXT2_DIR_ENTRY
));
347 DPRINTM(DPRINT_FILESYSTEM
, "EXT2 Directory Entry:\n");
348 DPRINTM(DPRINT_FILESYSTEM
, "inode = %d\n", DirectoryEntry
->inode
);
349 DPRINTM(DPRINT_FILESYSTEM
, "direntlen = %d\n", DirectoryEntry
->direntlen
);
350 DPRINTM(DPRINT_FILESYSTEM
, "namelen = %d\n", DirectoryEntry
->namelen
);
351 DPRINTM(DPRINT_FILESYSTEM
, "filetype = %d\n", DirectoryEntry
->filetype
);
352 DPRINTM(DPRINT_FILESYSTEM
, "name = ");
353 for (CurrentOffset
=0; CurrentOffset
<DirectoryEntry
->namelen
; CurrentOffset
++)
355 DPRINTM(DPRINT_FILESYSTEM
, "%c", DirectoryEntry
->name
[CurrentOffset
]);
357 DPRINTM(DPRINT_FILESYSTEM
, "\n");
362 CurrentOffset
+= CurrentDirectoryEntry
->direntlen
;
370 * Reads BytesToRead from open file and
371 * returns the number of bytes read in BytesRead
373 BOOLEAN
Ext2ReadFileBig(PEXT2_FILE_INFO Ext2FileInfo
, ULONGLONG BytesToRead
, ULONGLONG
* BytesRead
, PVOID Buffer
)
376 ULONG BlockNumberIndex
;
379 ULONG NumberOfBlocks
;
381 DPRINTM(DPRINT_FILESYSTEM
, "Ext2ReadFileBig() BytesToRead = %d Buffer = 0x%x\n", (ULONG
)BytesToRead
, Buffer
);
383 if (BytesRead
!= NULL
)
388 // Make sure we have the block pointer list if we need it
389 if (Ext2FileInfo
->FileBlockList
== NULL
)
391 // Block pointer list is NULL
392 // so this better be a fast symbolic link or else
393 if (((Ext2FileInfo
->Inode
.mode
& EXT2_S_IFMT
) != EXT2_S_IFLNK
) ||
394 (Ext2FileInfo
->FileSize
> FAST_SYMLINK_MAX_NAME_SIZE
))
396 FileSystemError("Block pointer list is NULL and file is not a fast symbolic link.");
402 // If they are trying to read past the
403 // end of the file then return success
404 // with BytesRead == 0
406 if (Ext2FileInfo
->FilePointer
>= Ext2FileInfo
->FileSize
)
412 // If they are trying to read more than there is to read
413 // then adjust the amount to read
415 if ((Ext2FileInfo
->FilePointer
+ BytesToRead
) > Ext2FileInfo
->FileSize
)
417 BytesToRead
= (Ext2FileInfo
->FileSize
- Ext2FileInfo
->FilePointer
);
420 // Check if this is a fast symbolic link
421 // if so then the read is easy
422 if (((Ext2FileInfo
->Inode
.mode
& EXT2_S_IFMT
) == EXT2_S_IFLNK
) &&
423 (Ext2FileInfo
->FileSize
<= FAST_SYMLINK_MAX_NAME_SIZE
))
425 DPRINTM(DPRINT_FILESYSTEM
, "Reading fast symbolic link data\n");
427 // Copy the data from the link
428 RtlCopyMemory(Buffer
, (PVOID
)((ULONG_PTR
)Ext2FileInfo
->FilePointer
+ Ext2FileInfo
->Inode
.symlink
), BytesToRead
);
430 if (BytesRead
!= NULL
)
432 *BytesRead
= BytesToRead
;
439 // Ok, now we have to perform at most 3 calculations
440 // I'll draw you a picture (using nifty ASCII art):
442 // CurrentFilePointer -+
444 // +----------------+
446 // +-----------+-----------+-----------+-----------+
447 // | Block 1 | Block 2 | Block 3 | Block 4 |
448 // +-----------+-----------+-----------+-----------+
450 // +---------------+--------------------+
452 // BytesToRead -------+
454 // 1 - The first calculation (and read) will align
455 // the file pointer with the next block.
456 // boundary (if we are supposed to read that much)
457 // 2 - The next calculation (and read) will read
458 // in all the full blocks that the requested
459 // amount of data would cover (in this case
461 // 3 - The last calculation (and read) would read
462 // in the remainder of the data requested out of
467 // Only do the first read if we
468 // aren't aligned on a block boundary
470 if (Ext2FileInfo
->FilePointer
% Ext2BlockSizeInBytes
)
473 // Do the math for our first read
475 BlockNumberIndex
= (Ext2FileInfo
->FilePointer
/ Ext2BlockSizeInBytes
);
476 BlockNumber
= Ext2FileInfo
->FileBlockList
[BlockNumberIndex
];
477 OffsetInBlock
= (Ext2FileInfo
->FilePointer
% Ext2BlockSizeInBytes
);
478 LengthInBlock
= (BytesToRead
> (Ext2BlockSizeInBytes
- OffsetInBlock
)) ? (Ext2BlockSizeInBytes
- OffsetInBlock
) : BytesToRead
;
481 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
483 if (!Ext2ReadPartialBlock(BlockNumber
, OffsetInBlock
, LengthInBlock
, Buffer
))
487 if (BytesRead
!= NULL
)
489 *BytesRead
+= LengthInBlock
;
491 BytesToRead
-= LengthInBlock
;
492 Ext2FileInfo
->FilePointer
+= LengthInBlock
;
493 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ LengthInBlock
);
497 // Do the math for our second read (if any data left)
502 // Determine how many full clusters we need to read
504 NumberOfBlocks
= (BytesToRead
/ Ext2BlockSizeInBytes
);
506 while (NumberOfBlocks
> 0)
508 BlockNumberIndex
= (Ext2FileInfo
->FilePointer
/ Ext2BlockSizeInBytes
);
509 BlockNumber
= Ext2FileInfo
->FileBlockList
[BlockNumberIndex
];
512 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
514 if (!Ext2ReadBlock(BlockNumber
, Buffer
))
518 if (BytesRead
!= NULL
)
520 *BytesRead
+= Ext2BlockSizeInBytes
;
522 BytesToRead
-= Ext2BlockSizeInBytes
;
523 Ext2FileInfo
->FilePointer
+= Ext2BlockSizeInBytes
;
524 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Ext2BlockSizeInBytes
);
530 // Do the math for our third read (if any data left)
534 BlockNumberIndex
= (Ext2FileInfo
->FilePointer
/ Ext2BlockSizeInBytes
);
535 BlockNumber
= Ext2FileInfo
->FileBlockList
[BlockNumberIndex
];
538 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
540 if (!Ext2ReadPartialBlock(BlockNumber
, 0, BytesToRead
, Buffer
))
544 if (BytesRead
!= NULL
)
546 *BytesRead
+= BytesToRead
;
548 Ext2FileInfo
->FilePointer
+= BytesToRead
;
549 BytesToRead
-= BytesToRead
;
550 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (ULONG_PTR
)BytesToRead
);
556 BOOLEAN
Ext2ReadVolumeSectors(UCHAR DriveNumber
, ULONGLONG SectorNumber
, ULONGLONG SectorCount
, PVOID Buffer
)
558 //GEOMETRY DiskGeometry;
559 //BOOLEAN ReturnValue;
560 //if (!DiskGetDriveGeometry(DriveNumber, &DiskGeometry))
564 //ReturnValue = MachDiskReadLogicalSectors(DriveNumber, SectorNumber + Ext2VolumeStartSector, SectorCount, (PVOID)DISKREADBUFFER);
565 //RtlCopyMemory(Buffer, (PVOID)DISKREADBUFFER, SectorCount * DiskGeometry.BytesPerSector);
566 //return ReturnValue;
568 return CacheReadDiskSectors(DriveNumber
, SectorNumber
+ Ext2VolumeStartSector
, SectorCount
, Buffer
);
571 BOOLEAN
Ext2ReadSuperBlock(VOID
)
574 DPRINTM(DPRINT_FILESYSTEM
, "Ext2ReadSuperBlock()\n");
577 // Free any memory previously allocated
579 if (Ext2SuperBlock
!= NULL
)
581 MmHeapFree(Ext2SuperBlock
);
583 Ext2SuperBlock
= NULL
;
587 // Now allocate the memory to hold the super block
589 Ext2SuperBlock
= (PEXT2_SUPER_BLOCK
)MmHeapAlloc(1024);
592 // Make sure we got the memory
594 if (Ext2SuperBlock
== NULL
)
596 FileSystemError("Out of memory.");
600 // Now try to read the super block
601 // If this fails then abort
602 if (!MachDiskReadLogicalSectors(Ext2DriveNumber
, Ext2VolumeStartSector
, 8, (PVOID
)DISKREADBUFFER
))
606 RtlCopyMemory(Ext2SuperBlock
, (PVOID
)((ULONG_PTR
)DISKREADBUFFER
+ 1024), 1024);
608 DPRINTM(DPRINT_FILESYSTEM
, "Dumping super block:\n");
609 DPRINTM(DPRINT_FILESYSTEM
, "total_inodes: %d\n", Ext2SuperBlock
->total_inodes
);
610 DPRINTM(DPRINT_FILESYSTEM
, "total_blocks: %d\n", Ext2SuperBlock
->total_blocks
);
611 DPRINTM(DPRINT_FILESYSTEM
, "reserved_blocks: %d\n", Ext2SuperBlock
->reserved_blocks
);
612 DPRINTM(DPRINT_FILESYSTEM
, "free_blocks: %d\n", Ext2SuperBlock
->free_blocks
);
613 DPRINTM(DPRINT_FILESYSTEM
, "free_inodes: %d\n", Ext2SuperBlock
->free_inodes
);
614 DPRINTM(DPRINT_FILESYSTEM
, "first_data_block: %d\n", Ext2SuperBlock
->first_data_block
);
615 DPRINTM(DPRINT_FILESYSTEM
, "log2_block_size: %d\n", Ext2SuperBlock
->log2_block_size
);
616 DPRINTM(DPRINT_FILESYSTEM
, "log2_fragment_size: %d\n", Ext2SuperBlock
->log2_fragment_size
);
617 DPRINTM(DPRINT_FILESYSTEM
, "blocks_per_group: %d\n", Ext2SuperBlock
->blocks_per_group
);
618 DPRINTM(DPRINT_FILESYSTEM
, "fragments_per_group: %d\n", Ext2SuperBlock
->fragments_per_group
);
619 DPRINTM(DPRINT_FILESYSTEM
, "inodes_per_group: %d\n", Ext2SuperBlock
->inodes_per_group
);
620 DPRINTM(DPRINT_FILESYSTEM
, "mtime: %d\n", Ext2SuperBlock
->mtime
);
621 DPRINTM(DPRINT_FILESYSTEM
, "utime: %d\n", Ext2SuperBlock
->utime
);
622 DPRINTM(DPRINT_FILESYSTEM
, "mnt_count: %d\n", Ext2SuperBlock
->mnt_count
);
623 DPRINTM(DPRINT_FILESYSTEM
, "max_mnt_count: %d\n", Ext2SuperBlock
->max_mnt_count
);
624 DPRINTM(DPRINT_FILESYSTEM
, "magic: 0x%x\n", Ext2SuperBlock
->magic
);
625 DPRINTM(DPRINT_FILESYSTEM
, "fs_state: %d\n", Ext2SuperBlock
->fs_state
);
626 DPRINTM(DPRINT_FILESYSTEM
, "error_handling: %d\n", Ext2SuperBlock
->error_handling
);
627 DPRINTM(DPRINT_FILESYSTEM
, "minor_revision_level: %d\n", Ext2SuperBlock
->minor_revision_level
);
628 DPRINTM(DPRINT_FILESYSTEM
, "lastcheck: %d\n", Ext2SuperBlock
->lastcheck
);
629 DPRINTM(DPRINT_FILESYSTEM
, "checkinterval: %d\n", Ext2SuperBlock
->checkinterval
);
630 DPRINTM(DPRINT_FILESYSTEM
, "creator_os: %d\n", Ext2SuperBlock
->creator_os
);
631 DPRINTM(DPRINT_FILESYSTEM
, "revision_level: %d\n", Ext2SuperBlock
->revision_level
);
632 DPRINTM(DPRINT_FILESYSTEM
, "uid_reserved: %d\n", Ext2SuperBlock
->uid_reserved
);
633 DPRINTM(DPRINT_FILESYSTEM
, "gid_reserved: %d\n", Ext2SuperBlock
->gid_reserved
);
634 DPRINTM(DPRINT_FILESYSTEM
, "first_inode: %d\n", Ext2SuperBlock
->first_inode
);
635 DPRINTM(DPRINT_FILESYSTEM
, "inode_size: %d\n", Ext2SuperBlock
->inode_size
);
636 DPRINTM(DPRINT_FILESYSTEM
, "block_group_number: %d\n", Ext2SuperBlock
->block_group_number
);
637 DPRINTM(DPRINT_FILESYSTEM
, "feature_compatibility: 0x%x\n", Ext2SuperBlock
->feature_compatibility
);
638 DPRINTM(DPRINT_FILESYSTEM
, "feature_incompat: 0x%x\n", Ext2SuperBlock
->feature_incompat
);
639 DPRINTM(DPRINT_FILESYSTEM
, "feature_ro_compat: 0x%x\n", Ext2SuperBlock
->feature_ro_compat
);
640 DPRINTM(DPRINT_FILESYSTEM
, "unique_id = { 0x%x, 0x%x, 0x%x, 0x%x }\n",
641 Ext2SuperBlock
->unique_id
[0], Ext2SuperBlock
->unique_id
[1], Ext2SuperBlock
->unique_id
[2], Ext2SuperBlock
->unique_id
[3]);
642 DPRINTM(DPRINT_FILESYSTEM
, "volume_name = '%.16s'\n", Ext2SuperBlock
->volume_name
);
643 DPRINTM(DPRINT_FILESYSTEM
, "last_mounted_on = '%.64s'\n", Ext2SuperBlock
->last_mounted_on
);
644 DPRINTM(DPRINT_FILESYSTEM
, "compression_info = 0x%x\n", Ext2SuperBlock
->compression_info
);
647 // Check the super block magic
649 if (Ext2SuperBlock
->magic
!= EXT2_MAGIC
)
651 FileSystemError("Invalid super block magic (0xef53)");
656 // Check the revision level
658 if (Ext2SuperBlock
->revision_level
> EXT2_DYNAMIC_REVISION
)
660 FileSystemError("FreeLoader does not understand the revision of this EXT2/EXT3 filesystem.\nPlease update FreeLoader.");
665 // Check the feature set
666 // Don't need to check the compatible or read-only compatible features
667 // because we only mount the filesystem as read-only
669 if ((Ext2SuperBlock
->revision_level
>= EXT2_DYNAMIC_REVISION
) &&
670 (/*((Ext2SuperBlock->s_feature_compat & ~EXT3_FEATURE_COMPAT_SUPP) != 0) ||*/
671 /*((Ext2SuperBlock->s_feature_ro_compat & ~EXT3_FEATURE_RO_COMPAT_SUPP) != 0) ||*/
672 ((Ext2SuperBlock
->feature_incompat
& ~EXT3_FEATURE_INCOMPAT_SUPP
) != 0)))
674 FileSystemError("FreeLoader does not understand features of this EXT2/EXT3 filesystem.\nPlease update FreeLoader.");
678 // Calculate the group count
679 Ext2GroupCount
= (Ext2SuperBlock
->total_blocks
- Ext2SuperBlock
->first_data_block
+ Ext2SuperBlock
->blocks_per_group
- 1) / Ext2SuperBlock
->blocks_per_group
;
680 DPRINTM(DPRINT_FILESYSTEM
, "Ext2GroupCount: %d\n", Ext2GroupCount
);
682 // Calculate the block size
683 Ext2BlockSizeInBytes
= 1024 << Ext2SuperBlock
->log2_block_size
;
684 Ext2BlockSizeInSectors
= Ext2BlockSizeInBytes
/ Ext2DiskGeometry
.BytesPerSector
;
685 DPRINTM(DPRINT_FILESYSTEM
, "Ext2BlockSizeInBytes: %d\n", Ext2BlockSizeInBytes
);
686 DPRINTM(DPRINT_FILESYSTEM
, "Ext2BlockSizeInSectors: %d\n", Ext2BlockSizeInSectors
);
688 // Calculate the fragment size
689 if (Ext2SuperBlock
->log2_fragment_size
>= 0)
691 Ext2FragmentSizeInBytes
= 1024 << Ext2SuperBlock
->log2_fragment_size
;
695 Ext2FragmentSizeInBytes
= 1024 >> -(Ext2SuperBlock
->log2_fragment_size
);
697 Ext2FragmentSizeInSectors
= Ext2FragmentSizeInBytes
/ Ext2DiskGeometry
.BytesPerSector
;
698 DPRINTM(DPRINT_FILESYSTEM
, "Ext2FragmentSizeInBytes: %d\n", Ext2FragmentSizeInBytes
);
699 DPRINTM(DPRINT_FILESYSTEM
, "Ext2FragmentSizeInSectors: %d\n", Ext2FragmentSizeInSectors
);
701 // Verify that the fragment size and the block size are equal
702 if (Ext2BlockSizeInBytes
!= Ext2FragmentSizeInBytes
)
704 FileSystemError("The fragment size must be equal to the block size.");
708 // Calculate the number of inodes in one block
709 Ext2InodesPerBlock
= Ext2BlockSizeInBytes
/ EXT2_INODE_SIZE(Ext2SuperBlock
);
710 DPRINTM(DPRINT_FILESYSTEM
, "Ext2InodesPerBlock: %d\n", Ext2InodesPerBlock
);
712 // Calculate the number of group descriptors in one block
713 Ext2GroupDescPerBlock
= EXT2_DESC_PER_BLOCK(Ext2SuperBlock
);
714 DPRINTM(DPRINT_FILESYSTEM
, "Ext2GroupDescPerBlock: %d\n", Ext2GroupDescPerBlock
);
719 BOOLEAN
Ext2ReadGroupDescriptors(VOID
)
721 ULONG GroupDescBlockCount
;
722 ULONG CurrentGroupDescBlock
;
724 DPRINTM(DPRINT_FILESYSTEM
, "Ext2ReadGroupDescriptors()\n");
727 // Free any memory previously allocated
729 if (Ext2GroupDescriptors
!= NULL
)
731 MmHeapFree(Ext2GroupDescriptors
);
733 Ext2GroupDescriptors
= NULL
;
737 // Now allocate the memory to hold the group descriptors
739 GroupDescBlockCount
= ROUND_UP(Ext2GroupCount
, Ext2GroupDescPerBlock
) / Ext2GroupDescPerBlock
;
740 Ext2GroupDescriptors
= (PEXT2_GROUP_DESC
)MmHeapAlloc(GroupDescBlockCount
* Ext2BlockSizeInBytes
);
743 // Make sure we got the memory
745 if (Ext2GroupDescriptors
== NULL
)
747 FileSystemError("Out of memory.");
751 // Now read the group descriptors
752 for (CurrentGroupDescBlock
=0; CurrentGroupDescBlock
<GroupDescBlockCount
; CurrentGroupDescBlock
++)
754 if (!Ext2ReadBlock(Ext2SuperBlock
->first_data_block
+ 1 + CurrentGroupDescBlock
, (PVOID
)FILESYSBUFFER
))
759 RtlCopyMemory((Ext2GroupDescriptors
+ (CurrentGroupDescBlock
* Ext2BlockSizeInBytes
)), (PVOID
)FILESYSBUFFER
, Ext2BlockSizeInBytes
);
765 BOOLEAN
Ext2ReadDirectory(ULONG Inode
, PVOID
* DirectoryBuffer
, PEXT2_INODE InodePointer
)
767 EXT2_FILE_INFO DirectoryFileInfo
;
769 DPRINTM(DPRINT_FILESYSTEM
, "Ext2ReadDirectory() Inode = %d\n", Inode
);
771 // Read the directory inode
772 if (!Ext2ReadInode(Inode
, InodePointer
))
777 // Make sure it is a directory inode
778 if ((InodePointer
->mode
& EXT2_S_IFMT
) != EXT2_S_IFDIR
)
780 FileSystemError("Inode is not a directory.");
784 // Fill in file info struct so we can call Ext2ReadFileBig()
785 RtlZeroMemory(&DirectoryFileInfo
, sizeof(EXT2_FILE_INFO
));
786 DirectoryFileInfo
.DriveNumber
= Ext2DriveNumber
;
787 DirectoryFileInfo
.FileBlockList
= Ext2ReadBlockPointerList(InodePointer
);
788 DirectoryFileInfo
.FilePointer
= 0;
789 DirectoryFileInfo
.FileSize
= Ext2GetInodeFileSize(InodePointer
);
791 if (DirectoryFileInfo
.FileBlockList
== NULL
)
797 // Now allocate the memory to hold the group descriptors
799 *DirectoryBuffer
= (PEXT2_DIR_ENTRY
)MmHeapAlloc(DirectoryFileInfo
.FileSize
);
802 // Make sure we got the memory
804 if (*DirectoryBuffer
== NULL
)
806 MmHeapFree(DirectoryFileInfo
.FileBlockList
);
807 FileSystemError("Out of memory.");
811 // Now read the root directory data
812 if (!Ext2ReadFileBig(&DirectoryFileInfo
, DirectoryFileInfo
.FileSize
, NULL
, *DirectoryBuffer
))
814 MmHeapFree(*DirectoryBuffer
);
815 *DirectoryBuffer
= NULL
;
816 MmHeapFree(DirectoryFileInfo
.FileBlockList
);
820 MmHeapFree(DirectoryFileInfo
.FileBlockList
);
824 BOOLEAN
Ext2ReadBlock(ULONG BlockNumber
, PVOID Buffer
)
826 CHAR ErrorString
[80];
828 DPRINTM(DPRINT_FILESYSTEM
, "Ext2ReadBlock() BlockNumber = %d Buffer = 0x%x\n", BlockNumber
, Buffer
);
830 // Make sure its a valid block
831 if (BlockNumber
> Ext2SuperBlock
->total_blocks
)
833 sprintf(ErrorString
, "Error reading block %d - block out of range.", (int) BlockNumber
);
834 FileSystemError(ErrorString
);
838 // Check to see if this is a sparse block
839 if (BlockNumber
== 0)
841 DPRINTM(DPRINT_FILESYSTEM
, "Block is part of a sparse file. Zeroing input buffer.\n");
843 RtlZeroMemory(Buffer
, Ext2BlockSizeInBytes
);
848 return Ext2ReadVolumeSectors(Ext2DriveNumber
, (ULONGLONG
)BlockNumber
* Ext2BlockSizeInSectors
, Ext2BlockSizeInSectors
, Buffer
);
852 * Ext2ReadPartialBlock()
853 * Reads part of a block into memory
855 BOOLEAN
Ext2ReadPartialBlock(ULONG BlockNumber
, ULONG StartingOffset
, ULONG Length
, PVOID Buffer
)
858 DPRINTM(DPRINT_FILESYSTEM
, "Ext2ReadPartialBlock() BlockNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", BlockNumber
, StartingOffset
, Length
, Buffer
);
860 if (!Ext2ReadBlock(BlockNumber
, (PVOID
)FILESYSBUFFER
))
865 memcpy(Buffer
, (PVOID
)((ULONG_PTR
)FILESYSBUFFER
+ StartingOffset
), Length
);
870 ULONG
Ext2GetGroupDescBlockNumber(ULONG Group
)
872 return (((Group
* sizeof(EXT2_GROUP_DESC
)) / Ext2GroupDescPerBlock
) + Ext2SuperBlock
->first_data_block
+ 1);
875 ULONG
Ext2GetGroupDescOffsetInBlock(ULONG Group
)
877 return ((Group
* sizeof(EXT2_GROUP_DESC
)) % Ext2GroupDescPerBlock
);
880 ULONG
Ext2GetInodeGroupNumber(ULONG Inode
)
882 return ((Inode
- 1) / Ext2SuperBlock
->inodes_per_group
);
885 ULONG
Ext2GetInodeBlockNumber(ULONG Inode
)
887 return (((Inode
- 1) % Ext2SuperBlock
->inodes_per_group
) / Ext2InodesPerBlock
);
890 ULONG
Ext2GetInodeOffsetInBlock(ULONG Inode
)
892 return (((Inode
- 1) % Ext2SuperBlock
->inodes_per_group
) % Ext2InodesPerBlock
);
895 BOOLEAN
Ext2ReadInode(ULONG Inode
, PEXT2_INODE InodeBuffer
)
897 ULONG InodeGroupNumber
;
898 ULONG InodeBlockNumber
;
899 ULONG InodeOffsetInBlock
;
900 CHAR ErrorString
[80];
901 EXT2_GROUP_DESC GroupDescriptor
;
903 DPRINTM(DPRINT_FILESYSTEM
, "Ext2ReadInode() Inode = %d\n", Inode
);
905 // Make sure its a valid inode
906 if ((Inode
< 1) || (Inode
> Ext2SuperBlock
->total_inodes
))
908 sprintf(ErrorString
, "Error reading inode %ld - inode out of range.", Inode
);
909 FileSystemError(ErrorString
);
913 // Get inode group & block number and offset in block
914 InodeGroupNumber
= Ext2GetInodeGroupNumber(Inode
);
915 InodeBlockNumber
= Ext2GetInodeBlockNumber(Inode
);
916 InodeOffsetInBlock
= Ext2GetInodeOffsetInBlock(Inode
);
917 DPRINTM(DPRINT_FILESYSTEM
, "InodeGroupNumber = %d\n", InodeGroupNumber
);
918 DPRINTM(DPRINT_FILESYSTEM
, "InodeBlockNumber = %d\n", InodeBlockNumber
);
919 DPRINTM(DPRINT_FILESYSTEM
, "InodeOffsetInBlock = %d\n", InodeOffsetInBlock
);
921 // Read the group descriptor
922 if (!Ext2ReadGroupDescriptor(InodeGroupNumber
, &GroupDescriptor
))
927 // Add the start block of the inode table to the inode block number
928 InodeBlockNumber
+= GroupDescriptor
.inode_table_id
;
929 DPRINTM(DPRINT_FILESYSTEM
, "InodeBlockNumber (after group desc correction) = %d\n", InodeBlockNumber
);
932 if (!Ext2ReadBlock(InodeBlockNumber
, (PVOID
)FILESYSBUFFER
))
937 // Copy the data to their buffer
938 RtlCopyMemory(InodeBuffer
, (PVOID
)((ULONG_PTR
)FILESYSBUFFER
+ (InodeOffsetInBlock
* EXT2_INODE_SIZE(Ext2SuperBlock
))), sizeof(EXT2_INODE
));
940 DPRINTM(DPRINT_FILESYSTEM
, "Dumping inode information:\n");
941 DPRINTM(DPRINT_FILESYSTEM
, "mode = 0x%x\n", InodeBuffer
->mode
);
942 DPRINTM(DPRINT_FILESYSTEM
, "uid = %d\n", InodeBuffer
->uid
);
943 DPRINTM(DPRINT_FILESYSTEM
, "size = %d\n", InodeBuffer
->size
);
944 DPRINTM(DPRINT_FILESYSTEM
, "atime = %d\n", InodeBuffer
->atime
);
945 DPRINTM(DPRINT_FILESYSTEM
, "ctime = %d\n", InodeBuffer
->ctime
);
946 DPRINTM(DPRINT_FILESYSTEM
, "mtime = %d\n", InodeBuffer
->mtime
);
947 DPRINTM(DPRINT_FILESYSTEM
, "dtime = %d\n", InodeBuffer
->dtime
);
948 DPRINTM(DPRINT_FILESYSTEM
, "gid = %d\n", InodeBuffer
->gid
);
949 DPRINTM(DPRINT_FILESYSTEM
, "nlinks = %d\n", InodeBuffer
->nlinks
);
950 DPRINTM(DPRINT_FILESYSTEM
, "blockcnt = %d\n", InodeBuffer
->blockcnt
);
951 DPRINTM(DPRINT_FILESYSTEM
, "flags = 0x%x\n", InodeBuffer
->flags
);
952 DPRINTM(DPRINT_FILESYSTEM
, "osd1 = 0x%x\n", InodeBuffer
->osd1
);
953 DPRINTM(DPRINT_FILESYSTEM
, "dir_blocks = { %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u }\n",
954 InodeBuffer
->blocks
.dir_blocks
[0], InodeBuffer
->blocks
.dir_blocks
[1], InodeBuffer
->blocks
.dir_blocks
[ 2], InodeBuffer
->blocks
.dir_blocks
[ 3],
955 InodeBuffer
->blocks
.dir_blocks
[4], InodeBuffer
->blocks
.dir_blocks
[5], InodeBuffer
->blocks
.dir_blocks
[ 6], InodeBuffer
->blocks
.dir_blocks
[ 7],
956 InodeBuffer
->blocks
.dir_blocks
[8], InodeBuffer
->blocks
.dir_blocks
[9], InodeBuffer
->blocks
.dir_blocks
[10], InodeBuffer
->blocks
.dir_blocks
[11]);
957 DPRINTM(DPRINT_FILESYSTEM
, "indir_block = %u\n", InodeBuffer
->blocks
.indir_block
);
958 DPRINTM(DPRINT_FILESYSTEM
, "double_indir_block = %u\n", InodeBuffer
->blocks
.double_indir_block
);
959 DPRINTM(DPRINT_FILESYSTEM
, "tripple_indir_block = %u\n", InodeBuffer
->blocks
.tripple_indir_block
);
960 DPRINTM(DPRINT_FILESYSTEM
, "version = %d\n", InodeBuffer
->version
);
961 DPRINTM(DPRINT_FILESYSTEM
, "acl = %d\n", InodeBuffer
->acl
);
962 DPRINTM(DPRINT_FILESYSTEM
, "dir_acl = %d\n", InodeBuffer
->dir_acl
);
963 DPRINTM(DPRINT_FILESYSTEM
, "fragment_addr = %d\n", InodeBuffer
->fragment_addr
);
964 DPRINTM(DPRINT_FILESYSTEM
, "osd2 = { %d, %d, %d }\n",
965 InodeBuffer
->osd2
[0], InodeBuffer
->osd2
[1], InodeBuffer
->osd2
[2]);
970 BOOLEAN
Ext2ReadGroupDescriptor(ULONG Group
, PEXT2_GROUP_DESC GroupBuffer
)
972 DPRINTM(DPRINT_FILESYSTEM
, "Ext2ReadGroupDescriptor()\n");
974 /*if (!Ext2ReadBlock(Ext2GetGroupDescBlockNumber(Group), (PVOID)FILESYSBUFFER))
979 RtlCopyMemory(GroupBuffer, (PVOID)(FILESYSBUFFER + Ext2GetGroupDescOffsetInBlock(Group)), sizeof(EXT2_GROUP_DESC));*/
981 RtlCopyMemory(GroupBuffer
, &Ext2GroupDescriptors
[Group
], sizeof(EXT2_GROUP_DESC
));
983 DPRINTM(DPRINT_FILESYSTEM
, "Dumping group descriptor:\n");
984 DPRINTM(DPRINT_FILESYSTEM
, "block_id = %d\n", GroupBuffer
->block_id
);
985 DPRINTM(DPRINT_FILESYSTEM
, "inode_id = %d\n", GroupBuffer
->inode_id
);
986 DPRINTM(DPRINT_FILESYSTEM
, "inode_table_id = %d\n", GroupBuffer
->inode_table_id
);
987 DPRINTM(DPRINT_FILESYSTEM
, "free_blocks = %d\n", GroupBuffer
->free_blocks
);
988 DPRINTM(DPRINT_FILESYSTEM
, "free_inodes = %d\n", GroupBuffer
->free_inodes
);
989 DPRINTM(DPRINT_FILESYSTEM
, "used_dirs = %d\n", GroupBuffer
->used_dirs
);
994 ULONG
* Ext2ReadBlockPointerList(PEXT2_INODE Inode
)
999 ULONG CurrentBlockInList
;
1002 DPRINTM(DPRINT_FILESYSTEM
, "Ext2ReadBlockPointerList()\n");
1004 // Get the number of blocks this file occupies
1005 // I would just use Inode->i_blocks but it
1006 // doesn't seem to be the number of blocks
1007 // the file size corresponds to, but instead
1008 // it is much bigger.
1009 //BlockCount = Inode->i_blocks;
1010 FileSize
= Ext2GetInodeFileSize(Inode
);
1011 FileSize
= ROUND_UP(FileSize
, Ext2BlockSizeInBytes
);
1012 BlockCount
= (FileSize
/ Ext2BlockSizeInBytes
);
1014 // Allocate the memory for the block list
1015 BlockList
= MmHeapAlloc(BlockCount
* sizeof(ULONG
));
1016 if (BlockList
== NULL
)
1021 RtlZeroMemory(BlockList
, BlockCount
* sizeof(ULONG
));
1023 // Copy the direct block pointers
1024 for (CurrentBlockInList
= CurrentBlock
= 0;
1025 CurrentBlockInList
< BlockCount
&& CurrentBlock
< INDIRECT_BLOCKS
;
1026 CurrentBlock
++, CurrentBlockInList
++)
1028 BlockList
[CurrentBlockInList
] = Inode
->blocks
.dir_blocks
[CurrentBlock
];
1031 // Copy the indirect block pointers
1032 if (CurrentBlockInList
< BlockCount
)
1034 if (!Ext2CopyIndirectBlockPointers(BlockList
, &CurrentBlockInList
, BlockCount
, Inode
->blocks
.indir_block
))
1036 MmHeapFree(BlockList
);
1041 // Copy the double indirect block pointers
1042 if (CurrentBlockInList
< BlockCount
)
1044 if (!Ext2CopyDoubleIndirectBlockPointers(BlockList
, &CurrentBlockInList
, BlockCount
, Inode
->blocks
.double_indir_block
))
1046 MmHeapFree(BlockList
);
1051 // Copy the triple indirect block pointers
1052 if (CurrentBlockInList
< BlockCount
)
1054 if (!Ext2CopyTripleIndirectBlockPointers(BlockList
, &CurrentBlockInList
, BlockCount
, Inode
->blocks
.tripple_indir_block
))
1056 MmHeapFree(BlockList
);
1064 ULONGLONG
Ext2GetInodeFileSize(PEXT2_INODE Inode
)
1066 if ((Inode
->mode
& EXT2_S_IFMT
) == EXT2_S_IFDIR
)
1068 return (ULONGLONG
)(Inode
->size
);
1072 return ((ULONGLONG
)(Inode
->size
) | ((ULONGLONG
)(Inode
->dir_acl
) << 32));
1076 BOOLEAN
Ext2CopyIndirectBlockPointers(ULONG
* BlockList
, ULONG
* CurrentBlockInList
, ULONG BlockCount
, ULONG IndirectBlock
)
1078 ULONG
* BlockBuffer
= (ULONG
*)FILESYSBUFFER
;
1080 ULONG BlockPointersPerBlock
;
1082 DPRINTM(DPRINT_FILESYSTEM
, "Ext2CopyIndirectBlockPointers() BlockCount = %d\n", BlockCount
);
1084 BlockPointersPerBlock
= Ext2BlockSizeInBytes
/ sizeof(ULONG
);
1086 if (!Ext2ReadBlock(IndirectBlock
, BlockBuffer
))
1091 for (CurrentBlock
=0; (*CurrentBlockInList
)<BlockCount
&& CurrentBlock
<BlockPointersPerBlock
; CurrentBlock
++)
1093 BlockList
[(*CurrentBlockInList
)] = BlockBuffer
[CurrentBlock
];
1094 (*CurrentBlockInList
)++;
1100 BOOLEAN
Ext2CopyDoubleIndirectBlockPointers(ULONG
* BlockList
, ULONG
* CurrentBlockInList
, ULONG BlockCount
, ULONG DoubleIndirectBlock
)
1104 ULONG BlockPointersPerBlock
;
1106 DPRINTM(DPRINT_FILESYSTEM
, "Ext2CopyDoubleIndirectBlockPointers() BlockCount = %d\n", BlockCount
);
1108 BlockPointersPerBlock
= Ext2BlockSizeInBytes
/ sizeof(ULONG
);
1110 BlockBuffer
= (ULONG
*)MmHeapAlloc(Ext2BlockSizeInBytes
);
1111 if (BlockBuffer
== NULL
)
1116 if (!Ext2ReadBlock(DoubleIndirectBlock
, BlockBuffer
))
1118 MmHeapFree(BlockBuffer
);
1122 for (CurrentBlock
=0; (*CurrentBlockInList
)<BlockCount
&& CurrentBlock
<BlockPointersPerBlock
; CurrentBlock
++)
1124 if (!Ext2CopyIndirectBlockPointers(BlockList
, CurrentBlockInList
, BlockCount
, BlockBuffer
[CurrentBlock
]))
1126 MmHeapFree(BlockBuffer
);
1131 MmHeapFree(BlockBuffer
);
1135 BOOLEAN
Ext2CopyTripleIndirectBlockPointers(ULONG
* BlockList
, ULONG
* CurrentBlockInList
, ULONG BlockCount
, ULONG TripleIndirectBlock
)
1139 ULONG BlockPointersPerBlock
;
1141 DPRINTM(DPRINT_FILESYSTEM
, "Ext2CopyTripleIndirectBlockPointers() BlockCount = %d\n", BlockCount
);
1143 BlockPointersPerBlock
= Ext2BlockSizeInBytes
/ sizeof(ULONG
);
1145 BlockBuffer
= (ULONG
*)MmHeapAlloc(Ext2BlockSizeInBytes
);
1146 if (BlockBuffer
== NULL
)
1151 if (!Ext2ReadBlock(TripleIndirectBlock
, BlockBuffer
))
1153 MmHeapFree(BlockBuffer
);
1157 for (CurrentBlock
=0; (*CurrentBlockInList
)<BlockCount
&& CurrentBlock
<BlockPointersPerBlock
; CurrentBlock
++)
1159 if (!Ext2CopyDoubleIndirectBlockPointers(BlockList
, CurrentBlockInList
, BlockCount
, BlockBuffer
[CurrentBlock
]))
1161 MmHeapFree(BlockBuffer
);
1166 MmHeapFree(BlockBuffer
);
1170 LONG
Ext2Close(ULONG FileId
)
1172 PEXT2_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1174 MmHeapFree(FileHandle
);
1179 LONG
Ext2GetFileInformation(ULONG FileId
, FILEINFORMATION
* Information
)
1181 PEXT2_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1183 RtlZeroMemory(Information
, sizeof(FILEINFORMATION
));
1184 Information
->EndingAddress
.LowPart
= FileHandle
->FileSize
;
1185 Information
->CurrentAddress
.LowPart
= FileHandle
->FilePointer
;
1187 DPRINTM(DPRINT_FILESYSTEM
, "Ext2GetFileInformation() FileSize = %d\n",
1188 Information
->EndingAddress
.LowPart
);
1189 DPRINTM(DPRINT_FILESYSTEM
, "Ext2GetFileInformation() FilePointer = %d\n",
1190 Information
->CurrentAddress
.LowPart
);
1195 LONG
Ext2Open(CHAR
* Path
, OPENMODE OpenMode
, ULONG
* FileId
)
1197 PEXT2_FILE_INFO FileHandle
;
1200 if (OpenMode
!= OpenReadOnly
)
1203 DeviceId
= FsGetDeviceId(*FileId
);
1205 DPRINTM(DPRINT_FILESYSTEM
, "Ext2Open() FileName = %s\n", Path
);
1208 // Call old open method
1210 FileHandle
= Ext2OpenFile(Path
);
1219 // Success. Remember the handle
1221 FsSetDeviceSpecific(*FileId
, FileHandle
);
1225 LONG
Ext2Read(ULONG FileId
, VOID
* Buffer
, ULONG N
, ULONG
* Count
)
1227 PEXT2_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1228 ULONGLONG BytesReadBig
;
1234 ret
= Ext2ReadFileBig(FileHandle
, N
, &BytesReadBig
, Buffer
);
1235 *Count
= (ULONG
)BytesReadBig
;
1238 // Check for success
1246 LONG
Ext2Seek(ULONG FileId
, LARGE_INTEGER
* Position
, SEEKMODE SeekMode
)
1248 PEXT2_FILE_INFO FileHandle
= FsGetDeviceSpecific(FileId
);
1250 DPRINTM(DPRINT_FILESYSTEM
, "Ext2Seek() NewFilePointer = %lu\n", Position
->LowPart
);
1252 if (SeekMode
!= SeekAbsolute
)
1254 if (Position
->HighPart
!= 0)
1256 if (Position
->LowPart
>= FileHandle
->FileSize
)
1259 FileHandle
->FilePointer
= Position
->LowPart
;
1263 const DEVVTBL Ext2FuncTable
=
1266 Ext2GetFileInformation
,
1273 const DEVVTBL
* Ext2Mount(ULONG DeviceId
)
1275 EXT2_SUPER_BLOCK SuperBlock
;
1276 LARGE_INTEGER Position
;
1281 // Read the SuperBlock
1283 Position
.HighPart
= 0;
1284 Position
.LowPart
= 2 * 512;
1285 ret
= ArcSeek(DeviceId
, &Position
, SeekAbsolute
);
1286 if (ret
!= ESUCCESS
)
1288 ret
= ArcRead(DeviceId
, &SuperBlock
, sizeof(SuperBlock
), &Count
);
1289 if (ret
!= ESUCCESS
|| Count
!= sizeof(SuperBlock
))
1293 // Check if SuperBlock is valid. If yes, return Ext2 function table
1295 if (SuperBlock
.magic
== EXT2_MAGIC
)
1298 // Compatibility hack as long as FS is not using underlying device DeviceId
1301 ULONGLONG StartSector
;
1302 ULONGLONG SectorCount
;
1304 if (!DiskGetBootVolume(&DriveNumber
, &StartSector
, &SectorCount
, &Type
))
1306 Ext2OpenVolume(DriveNumber
, StartSector
, SectorCount
);
1307 return &Ext2FuncTable
;