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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 GEOMETRY Ext2DiskGeometry
; // Ext2 file system disk geometry
25 PEXT2_SUPER_BLOCK Ext2SuperBlock
= NULL
; // Ext2 file system super block
26 PEXT2_GROUP_DESC Ext2GroupDescriptors
= NULL
; // Ext2 file system group descriptors
28 UCHAR Ext2DriveNumber
= 0; // Ext2 file system drive number
29 ULONGLONG Ext2VolumeStartSector
= 0; // Ext2 file system starting sector
30 ULONG Ext2BlockSizeInBytes
= 0; // Block size in bytes
31 ULONG Ext2BlockSizeInSectors
= 0; // Block size in sectors
32 ULONG Ext2FragmentSizeInBytes
= 0; // Fragment size in bytes
33 ULONG Ext2FragmentSizeInSectors
= 0; // Fragment size in sectors
34 ULONG Ext2GroupCount
= 0; // Number of groups in this file system
35 ULONG Ext2InodesPerBlock
= 0; // Number of inodes in one block
36 ULONG Ext2GroupDescPerBlock
= 0; // Number of group descriptors in one block
38 BOOLEAN
Ext2OpenVolume(UCHAR DriveNumber
, ULONGLONG VolumeStartSector
, ULONGLONG PartitionSectorCount
)
41 DbgPrint((DPRINT_FILESYSTEM
, "Ext2OpenVolume() DriveNumber = 0x%x VolumeStartSector = %d\n", DriveNumber
, VolumeStartSector
));
43 // Store the drive number and start sector
44 Ext2DriveNumber
= DriveNumber
;
45 Ext2VolumeStartSector
= VolumeStartSector
;
47 if (!MachDiskGetDriveGeometry(DriveNumber
, &Ext2DiskGeometry
))
53 // Initialize the disk cache for this drive
55 if (!CacheInitializeDrive(DriveNumber
))
60 // Read in the super block
61 if (!Ext2ReadSuperBlock())
66 // Read in the group descriptors
67 if (!Ext2ReadGroupDescriptors())
77 * Tries to open the file 'name' and returns true or false
78 * for success and failure respectively
80 FILE* Ext2OpenFile(PCSTR FileName
)
82 EXT2_FILE_INFO TempExt2FileInfo
;
83 PEXT2_FILE_INFO FileHandle
;
84 CHAR SymLinkPath
[EXT3_NAME_LEN
];
85 CHAR FullPath
[EXT3_NAME_LEN
* 2];
88 DbgPrint((DPRINT_FILESYSTEM
, "Ext2OpenFile() FileName = %s\n", FileName
));
90 RtlZeroMemory(SymLinkPath
, EXT3_NAME_LEN
);
92 // Lookup the file in the file system
93 if (!Ext2LookupFile(FileName
, &TempExt2FileInfo
))
98 // If we got a symbolic link then fix up the path
99 // and re-call this function
100 if ((TempExt2FileInfo
.Inode
.i_mode
& EXT2_S_IFMT
) == EXT2_S_IFLNK
)
102 DbgPrint((DPRINT_FILESYSTEM
, "File is a symbolic link\n"));
104 // Now read in the symbolic link path
105 if (!Ext2ReadFileBig(&TempExt2FileInfo
, TempExt2FileInfo
.FileSize
, NULL
, SymLinkPath
))
107 if (TempExt2FileInfo
.FileBlockList
!= NULL
)
109 MmHeapFree(TempExt2FileInfo
.FileBlockList
);
115 DbgPrint((DPRINT_FILESYSTEM
, "Symbolic link path = %s\n", SymLinkPath
));
118 if (SymLinkPath
[0] == '/' || SymLinkPath
[0] == '\\')
120 // Symbolic link is an absolute path
121 // So copy it to FullPath, but skip over
122 // the '/' char at the beginning
123 strcpy(FullPath
, &SymLinkPath
[1]);
127 // Symbolic link is a relative path
128 // Copy the first part of the path
129 strcpy(FullPath
, FileName
);
131 // Remove the last part of the path
132 for (Index
=strlen(FullPath
); Index
>0; )
135 if (FullPath
[Index
] == '/' || FullPath
[Index
] == '\\')
140 FullPath
[Index
] = '\0';
142 // Concatenate the symbolic link
143 strcat(FullPath
, Index
== 0 ? "" : "/");
144 strcat(FullPath
, SymLinkPath
);
147 DbgPrint((DPRINT_FILESYSTEM
, "Full file path = %s\n", FullPath
));
149 if (TempExt2FileInfo
.FileBlockList
!= NULL
)
151 MmHeapFree(TempExt2FileInfo
.FileBlockList
);
154 return Ext2OpenFile(FullPath
);
158 FileHandle
= MmHeapAlloc(sizeof(EXT2_FILE_INFO
));
160 if (FileHandle
== NULL
)
162 if (TempExt2FileInfo
.FileBlockList
!= NULL
)
164 MmHeapFree(TempExt2FileInfo
.FileBlockList
);
170 RtlCopyMemory(FileHandle
, &TempExt2FileInfo
, sizeof(EXT2_FILE_INFO
));
172 return (FILE*)FileHandle
;
178 * This function searches the file system for the
179 * specified filename and fills in a EXT2_FILE_INFO structure
180 * with info describing the file, etc. returns true
181 * if the file exists or false otherwise
183 BOOLEAN
Ext2LookupFile(PCSTR FileName
, PEXT2_FILE_INFO Ext2FileInfoPointer
)
186 ULONG NumberOfPathParts
;
188 PVOID DirectoryBuffer
;
189 ULONG DirectoryInode
= EXT3_ROOT_INO
;
190 EXT2_INODE InodeData
;
191 EXT2_DIR_ENTRY DirectoryEntry
;
193 DbgPrint((DPRINT_FILESYSTEM
, "Ext2LookupFile() FileName = %s\n", FileName
));
195 RtlZeroMemory(Ext2FileInfoPointer
, sizeof(EXT2_FILE_INFO
));
198 // Figure out how many sub-directories we are nested in
200 NumberOfPathParts
= FsGetNumPathParts(FileName
);
203 // Loop once for each part
205 for (i
=0; i
<NumberOfPathParts
; i
++)
208 // Get first path part
210 FsGetFirstNameFromPath(PathPart
, FileName
);
213 // Advance to the next part of the path
215 for (; (*FileName
!= '\\') && (*FileName
!= '/') && (*FileName
!= '\0'); FileName
++)
221 // Buffer the directory contents
223 if (!Ext2ReadDirectory(DirectoryInode
, &DirectoryBuffer
, &InodeData
))
229 // Search for file name in directory
231 if (!Ext2SearchDirectoryBufferForFile(DirectoryBuffer
, (ULONG
)Ext2GetInodeFileSize(&InodeData
), PathPart
, &DirectoryEntry
))
233 MmHeapFree(DirectoryBuffer
);
237 MmHeapFree(DirectoryBuffer
);
239 DirectoryInode
= DirectoryEntry
.inode
;
242 if (!Ext2ReadInode(DirectoryInode
, &InodeData
))
247 if (((InodeData
.i_mode
& EXT2_S_IFMT
) != EXT2_S_IFREG
) &&
248 ((InodeData
.i_mode
& EXT2_S_IFMT
) != EXT2_S_IFLNK
))
250 FileSystemError("Inode is not a regular file or symbolic link.");
254 // Set the drive number
255 Ext2FileInfoPointer
->DriveNumber
= Ext2DriveNumber
;
257 // If it's a regular file or a regular symbolic link
258 // then get the block pointer list otherwise it must
259 // be a fast symbolic link which doesn't have a block list
260 if (((InodeData
.i_mode
& EXT2_S_IFMT
) == EXT2_S_IFREG
) ||
261 ((InodeData
.i_mode
& EXT2_S_IFMT
) == EXT2_S_IFLNK
&& InodeData
.i_size
> FAST_SYMLINK_MAX_NAME_SIZE
))
263 Ext2FileInfoPointer
->FileBlockList
= Ext2ReadBlockPointerList(&InodeData
);
265 if (Ext2FileInfoPointer
->FileBlockList
== NULL
)
272 Ext2FileInfoPointer
->FileBlockList
= NULL
;
275 Ext2FileInfoPointer
->FilePointer
= 0;
276 Ext2FileInfoPointer
->FileSize
= Ext2GetInodeFileSize(&InodeData
);
277 RtlCopyMemory(&Ext2FileInfoPointer
->Inode
, &InodeData
, sizeof(EXT2_INODE
));
282 BOOLEAN
Ext2SearchDirectoryBufferForFile(PVOID DirectoryBuffer
, ULONG DirectorySize
, PCHAR FileName
, PEXT2_DIR_ENTRY DirectoryEntry
)
285 PEXT2_DIR_ENTRY CurrentDirectoryEntry
;
287 DbgPrint((DPRINT_FILESYSTEM
, "Ext2SearchDirectoryBufferForFile() DirectoryBuffer = 0x%x DirectorySize = %d FileName = %s\n", DirectoryBuffer
, DirectorySize
, FileName
));
289 for (CurrentOffset
=0; CurrentOffset
<DirectorySize
; )
291 CurrentDirectoryEntry
= (PEXT2_DIR_ENTRY
)((ULONG_PTR
)DirectoryBuffer
+ CurrentOffset
);
293 if (CurrentDirectoryEntry
->rec_len
== 0)
298 if ((CurrentDirectoryEntry
->rec_len
+ CurrentOffset
) > DirectorySize
)
300 FileSystemError("Directory entry extends past end of directory file.");
304 DbgPrint((DPRINT_FILESYSTEM
, "Dumping directory entry at offset %d:\n", CurrentOffset
));
305 DbgDumpBuffer(DPRINT_FILESYSTEM
, CurrentDirectoryEntry
, CurrentDirectoryEntry
->rec_len
);
307 if ((_strnicmp(FileName
, CurrentDirectoryEntry
->name
, CurrentDirectoryEntry
->name_len
) == 0) &&
308 (strlen(FileName
) == CurrentDirectoryEntry
->name_len
))
310 RtlCopyMemory(DirectoryEntry
, CurrentDirectoryEntry
, sizeof(EXT2_DIR_ENTRY
));
312 DbgPrint((DPRINT_FILESYSTEM
, "EXT2 Directory Entry:\n"));
313 DbgPrint((DPRINT_FILESYSTEM
, "inode = %d\n", DirectoryEntry
->inode
));
314 DbgPrint((DPRINT_FILESYSTEM
, "rec_len = %d\n", DirectoryEntry
->rec_len
));
315 DbgPrint((DPRINT_FILESYSTEM
, "name_len = %d\n", DirectoryEntry
->name_len
));
316 DbgPrint((DPRINT_FILESYSTEM
, "file_type = %d\n", DirectoryEntry
->file_type
));
317 DbgPrint((DPRINT_FILESYSTEM
, "name = "));
318 for (CurrentOffset
=0; CurrentOffset
<DirectoryEntry
->name_len
; CurrentOffset
++)
320 DbgPrint((DPRINT_FILESYSTEM
, "%c", DirectoryEntry
->name
[CurrentOffset
]));
322 DbgPrint((DPRINT_FILESYSTEM
, "\n"));
327 CurrentOffset
+= CurrentDirectoryEntry
->rec_len
;
335 * Reads BytesToRead from open file and
336 * returns the number of bytes read in BytesRead
338 BOOLEAN
Ext2ReadFileBig(FILE *FileHandle
, ULONGLONG BytesToRead
, ULONGLONG
* BytesRead
, PVOID Buffer
)
340 PEXT2_FILE_INFO Ext2FileInfo
= (PEXT2_FILE_INFO
)FileHandle
;
342 ULONG BlockNumberIndex
;
345 ULONG NumberOfBlocks
;
347 DbgPrint((DPRINT_FILESYSTEM
, "Ext2ReadFileBig() BytesToRead = %d Buffer = 0x%x\n", (ULONG
)BytesToRead
, Buffer
));
349 if (BytesRead
!= NULL
)
354 // Make sure we have the block pointer list if we need it
355 if (Ext2FileInfo
->FileBlockList
== NULL
)
357 // Block pointer list is NULL
358 // so this better be a fast symbolic link or else
359 if (((Ext2FileInfo
->Inode
.i_mode
& EXT2_S_IFMT
) != EXT2_S_IFLNK
) ||
360 (Ext2FileInfo
->FileSize
> FAST_SYMLINK_MAX_NAME_SIZE
))
362 FileSystemError("Block pointer list is NULL and file is not a fast symbolic link.");
368 // If they are trying to read past the
369 // end of the file then return success
370 // with BytesRead == 0
372 if (Ext2FileInfo
->FilePointer
>= Ext2FileInfo
->FileSize
)
378 // If they are trying to read more than there is to read
379 // then adjust the amount to read
381 if ((Ext2FileInfo
->FilePointer
+ BytesToRead
) > Ext2FileInfo
->FileSize
)
383 BytesToRead
= (Ext2FileInfo
->FileSize
- Ext2FileInfo
->FilePointer
);
386 // Check if this is a fast symbolic link
387 // if so then the read is easy
388 if (((Ext2FileInfo
->Inode
.i_mode
& EXT2_S_IFMT
) == EXT2_S_IFLNK
) &&
389 (Ext2FileInfo
->FileSize
<= FAST_SYMLINK_MAX_NAME_SIZE
))
391 DbgPrint((DPRINT_FILESYSTEM
, "Reading fast symbolic link data\n"));
393 // Copy the data from the link
394 RtlCopyMemory(Buffer
, (PVOID
)((ULONG_PTR
)Ext2FileInfo
->FilePointer
+ Ext2FileInfo
->Inode
.i_block
), BytesToRead
);
396 if (BytesRead
!= NULL
)
398 *BytesRead
= BytesToRead
;
405 // Ok, now we have to perform at most 3 calculations
406 // I'll draw you a picture (using nifty ASCII art):
408 // CurrentFilePointer -+
410 // +----------------+
412 // +-----------+-----------+-----------+-----------+
413 // | Block 1 | Block 2 | Block 3 | Block 4 |
414 // +-----------+-----------+-----------+-----------+
416 // +---------------+--------------------+
418 // BytesToRead -------+
420 // 1 - The first calculation (and read) will align
421 // the file pointer with the next block.
422 // boundary (if we are supposed to read that much)
423 // 2 - The next calculation (and read) will read
424 // in all the full blocks that the requested
425 // amount of data would cover (in this case
427 // 3 - The last calculation (and read) would read
428 // in the remainder of the data requested out of
433 // Only do the first read if we
434 // aren't aligned on a block boundary
436 if (Ext2FileInfo
->FilePointer
% Ext2BlockSizeInBytes
)
439 // Do the math for our first read
441 BlockNumberIndex
= (Ext2FileInfo
->FilePointer
/ Ext2BlockSizeInBytes
);
442 BlockNumber
= Ext2FileInfo
->FileBlockList
[BlockNumberIndex
];
443 OffsetInBlock
= (Ext2FileInfo
->FilePointer
% Ext2BlockSizeInBytes
);
444 LengthInBlock
= (BytesToRead
> (Ext2BlockSizeInBytes
- OffsetInBlock
)) ? (Ext2BlockSizeInBytes
- OffsetInBlock
) : BytesToRead
;
447 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
449 if (!Ext2ReadPartialBlock(BlockNumber
, OffsetInBlock
, LengthInBlock
, Buffer
))
453 if (BytesRead
!= NULL
)
455 *BytesRead
+= LengthInBlock
;
457 BytesToRead
-= LengthInBlock
;
458 Ext2FileInfo
->FilePointer
+= LengthInBlock
;
459 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ LengthInBlock
);
463 // Do the math for our second read (if any data left)
468 // Determine how many full clusters we need to read
470 NumberOfBlocks
= (BytesToRead
/ Ext2BlockSizeInBytes
);
472 while (NumberOfBlocks
> 0)
474 BlockNumberIndex
= (Ext2FileInfo
->FilePointer
/ Ext2BlockSizeInBytes
);
475 BlockNumber
= Ext2FileInfo
->FileBlockList
[BlockNumberIndex
];
478 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
480 if (!Ext2ReadBlock(BlockNumber
, Buffer
))
484 if (BytesRead
!= NULL
)
486 *BytesRead
+= Ext2BlockSizeInBytes
;
488 BytesToRead
-= Ext2BlockSizeInBytes
;
489 Ext2FileInfo
->FilePointer
+= Ext2BlockSizeInBytes
;
490 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Ext2BlockSizeInBytes
);
496 // Do the math for our third read (if any data left)
500 BlockNumberIndex
= (Ext2FileInfo
->FilePointer
/ Ext2BlockSizeInBytes
);
501 BlockNumber
= Ext2FileInfo
->FileBlockList
[BlockNumberIndex
];
504 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
506 if (!Ext2ReadPartialBlock(BlockNumber
, 0, BytesToRead
, Buffer
))
510 if (BytesRead
!= NULL
)
512 *BytesRead
+= BytesToRead
;
514 Ext2FileInfo
->FilePointer
+= BytesToRead
;
515 BytesToRead
-= BytesToRead
;
516 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (ULONG_PTR
)BytesToRead
);
522 BOOLEAN
Ext2ReadFile(FILE *FileHandle
, ULONG BytesToRead
, ULONG
* BytesRead
, PVOID Buffer
)
525 ULONGLONG BytesReadBig
;
527 Success
= Ext2ReadFileBig(FileHandle
, BytesToRead
, &BytesReadBig
, Buffer
);
528 *BytesRead
= (ULONG
)BytesReadBig
;
532 ULONG
Ext2GetFileSize(FILE *FileHandle
)
534 PEXT2_FILE_INFO Ext2FileHandle
= (PEXT2_FILE_INFO
)FileHandle
;
536 DbgPrint((DPRINT_FILESYSTEM
, "Ext2GetFileSize() FileSize = %d\n", Ext2FileHandle
->FileSize
));
538 return Ext2FileHandle
->FileSize
;
541 VOID
Ext2SetFilePointer(FILE *FileHandle
, ULONG NewFilePointer
)
543 PEXT2_FILE_INFO Ext2FileHandle
= (PEXT2_FILE_INFO
)FileHandle
;
545 DbgPrint((DPRINT_FILESYSTEM
, "Ext2SetFilePointer() NewFilePointer = %d\n", NewFilePointer
));
547 Ext2FileHandle
->FilePointer
= NewFilePointer
;
550 ULONG
Ext2GetFilePointer(FILE *FileHandle
)
552 PEXT2_FILE_INFO Ext2FileHandle
= (PEXT2_FILE_INFO
)FileHandle
;
554 DbgPrint((DPRINT_FILESYSTEM
, "Ext2GetFilePointer() FilePointer = %d\n", Ext2FileHandle
->FilePointer
));
556 return Ext2FileHandle
->FilePointer
;
559 BOOLEAN
Ext2ReadVolumeSectors(UCHAR DriveNumber
, ULONGLONG SectorNumber
, ULONGLONG SectorCount
, PVOID Buffer
)
561 //GEOMETRY DiskGeometry;
562 //BOOLEAN ReturnValue;
563 //if (!DiskGetDriveGeometry(DriveNumber, &DiskGeometry))
567 //ReturnValue = MachDiskReadLogicalSectors(DriveNumber, SectorNumber + Ext2VolumeStartSector, SectorCount, (PVOID)DISKREADBUFFER);
568 //RtlCopyMemory(Buffer, (PVOID)DISKREADBUFFER, SectorCount * DiskGeometry.BytesPerSector);
569 //return ReturnValue;
571 return CacheReadDiskSectors(DriveNumber
, SectorNumber
+ Ext2VolumeStartSector
, SectorCount
, Buffer
);
574 BOOLEAN
Ext2ReadSuperBlock(VOID
)
577 DbgPrint((DPRINT_FILESYSTEM
, "Ext2ReadSuperBlock()\n"));
580 // Free any memory previously allocated
582 if (Ext2SuperBlock
!= NULL
)
584 MmHeapFree(Ext2SuperBlock
);
586 Ext2SuperBlock
= NULL
;
590 // Now allocate the memory to hold the super block
592 Ext2SuperBlock
= (PEXT2_SUPER_BLOCK
)MmHeapAlloc(1024);
595 // Make sure we got the memory
597 if (Ext2SuperBlock
== NULL
)
599 FileSystemError("Out of memory.");
603 // Now try to read the super block
604 // If this fails then abort
605 if (!MachDiskReadLogicalSectors(Ext2DriveNumber
, Ext2VolumeStartSector
, 8, (PVOID
)DISKREADBUFFER
))
609 RtlCopyMemory(Ext2SuperBlock
, (PVOID
)(DISKREADBUFFER
+ 1024), 1024);
611 DbgPrint((DPRINT_FILESYSTEM
, "Dumping super block:\n"));
613 DbgPrint((DPRINT_FILESYSTEM
, "s_inodes_count: %d\n", Ext2SuperBlock
->s_inodes_count
));
614 DbgPrint((DPRINT_FILESYSTEM
, "s_blocks_count: %d\n", Ext2SuperBlock
->s_blocks_count
));
615 DbgPrint((DPRINT_FILESYSTEM
, "s_r_blocks_count: %d\n", Ext2SuperBlock
->s_r_blocks_count
));
616 DbgPrint((DPRINT_FILESYSTEM
, "s_free_blocks_count: %d\n", Ext2SuperBlock
->s_free_blocks_count
));
617 DbgPrint((DPRINT_FILESYSTEM
, "s_free_inodes_count: %d\n", Ext2SuperBlock
->s_free_inodes_count
));
618 DbgPrint((DPRINT_FILESYSTEM
, "s_first_data_block: %d\n", Ext2SuperBlock
->s_first_data_block
));
619 DbgPrint((DPRINT_FILESYSTEM
, "s_log_block_size: %d\n", Ext2SuperBlock
->s_log_block_size
));
620 DbgPrint((DPRINT_FILESYSTEM
, "s_log_frag_size: %d\n", Ext2SuperBlock
->s_log_frag_size
));
621 DbgPrint((DPRINT_FILESYSTEM
, "s_blocks_per_group: %d\n", Ext2SuperBlock
->s_blocks_per_group
));
622 DbgPrint((DPRINT_FILESYSTEM
, "s_frags_per_group: %d\n", Ext2SuperBlock
->s_frags_per_group
));
623 DbgPrint((DPRINT_FILESYSTEM
, "s_inodes_per_group: %d\n", Ext2SuperBlock
->s_inodes_per_group
));
624 DbgPrint((DPRINT_FILESYSTEM
, "s_mtime: %d\n", Ext2SuperBlock
->s_mtime
));
625 DbgPrint((DPRINT_FILESYSTEM
, "s_wtime: %d\n", Ext2SuperBlock
->s_wtime
));
626 DbgPrint((DPRINT_FILESYSTEM
, "s_mnt_count: %d\n", Ext2SuperBlock
->s_mnt_count
));
627 DbgPrint((DPRINT_FILESYSTEM
, "s_max_mnt_count: %d\n", Ext2SuperBlock
->s_max_mnt_count
));
628 DbgPrint((DPRINT_FILESYSTEM
, "s_magic: 0x%x\n", Ext2SuperBlock
->s_magic
));
629 DbgPrint((DPRINT_FILESYSTEM
, "s_state: %d\n", Ext2SuperBlock
->s_state
));
630 DbgPrint((DPRINT_FILESYSTEM
, "s_errors: %d\n", Ext2SuperBlock
->s_errors
));
631 DbgPrint((DPRINT_FILESYSTEM
, "s_minor_rev_level: %d\n", Ext2SuperBlock
->s_minor_rev_level
));
632 DbgPrint((DPRINT_FILESYSTEM
, "s_lastcheck: %d\n", Ext2SuperBlock
->s_lastcheck
));
633 DbgPrint((DPRINT_FILESYSTEM
, "s_checkinterval: %d\n", Ext2SuperBlock
->s_checkinterval
));
634 DbgPrint((DPRINT_FILESYSTEM
, "s_creator_os: %d\n", Ext2SuperBlock
->s_creator_os
));
635 DbgPrint((DPRINT_FILESYSTEM
, "s_rev_level: %d\n", Ext2SuperBlock
->s_rev_level
));
636 DbgPrint((DPRINT_FILESYSTEM
, "s_def_resuid: %d\n", Ext2SuperBlock
->s_def_resuid
));
637 DbgPrint((DPRINT_FILESYSTEM
, "s_def_resgid: %d\n", Ext2SuperBlock
->s_def_resgid
));
638 DbgPrint((DPRINT_FILESYSTEM
, "s_first_ino: %d\n", Ext2SuperBlock
->s_first_ino
));
639 DbgPrint((DPRINT_FILESYSTEM
, "s_inode_size: %d\n", Ext2SuperBlock
->s_inode_size
));
640 DbgPrint((DPRINT_FILESYSTEM
, "s_block_group_nr: %d\n", Ext2SuperBlock
->s_block_group_nr
));
641 DbgPrint((DPRINT_FILESYSTEM
, "s_feature_compat: 0x%x\n", Ext2SuperBlock
->s_feature_compat
));
642 DbgPrint((DPRINT_FILESYSTEM
, "s_feature_incompat: 0x%x\n", Ext2SuperBlock
->s_feature_incompat
));
643 DbgPrint((DPRINT_FILESYSTEM
, "s_feature_ro_compat: 0x%x\n", Ext2SuperBlock
->s_feature_ro_compat
));
644 DbgPrint((DPRINT_FILESYSTEM
, "s_uuid[16] = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", Ext2SuperBlock
->s_uuid
[0], Ext2SuperBlock
->s_uuid
[1], Ext2SuperBlock
->s_uuid
[2], Ext2SuperBlock
->s_uuid
[3], Ext2SuperBlock
->s_uuid
[4], Ext2SuperBlock
->s_uuid
[5], Ext2SuperBlock
->s_uuid
[6], Ext2SuperBlock
->s_uuid
[7], Ext2SuperBlock
->s_uuid
[8], Ext2SuperBlock
->s_uuid
[9], Ext2SuperBlock
->s_uuid
[10], Ext2SuperBlock
->s_uuid
[11], Ext2SuperBlock
->s_uuid
[12], Ext2SuperBlock
->s_uuid
[13], Ext2SuperBlock
->s_uuid
[14], Ext2SuperBlock
->s_uuid
[15]));
645 DbgPrint((DPRINT_FILESYSTEM
, "s_volume_name[16] = '%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c'\n", Ext2SuperBlock
->s_volume_name
[0], Ext2SuperBlock
->s_volume_name
[1], Ext2SuperBlock
->s_volume_name
[2], Ext2SuperBlock
->s_volume_name
[3], Ext2SuperBlock
->s_volume_name
[4], Ext2SuperBlock
->s_volume_name
[5], Ext2SuperBlock
->s_volume_name
[6], Ext2SuperBlock
->s_volume_name
[7], Ext2SuperBlock
->s_volume_name
[8], Ext2SuperBlock
->s_volume_name
[9], Ext2SuperBlock
->s_volume_name
[10], Ext2SuperBlock
->s_volume_name
[11], Ext2SuperBlock
->s_volume_name
[12], Ext2SuperBlock
->s_volume_name
[13], Ext2SuperBlock
->s_volume_name
[14], Ext2SuperBlock
->s_volume_name
[15]));
646 DbgPrint((DPRINT_FILESYSTEM
, "s_last_mounted[64]='%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c'\n", Ext2SuperBlock
->s_last_mounted
[0], Ext2SuperBlock
->s_last_mounted
[1], Ext2SuperBlock
->s_last_mounted
[2], Ext2SuperBlock
->s_last_mounted
[3], Ext2SuperBlock
->s_last_mounted
[4], Ext2SuperBlock
->s_last_mounted
[5], Ext2SuperBlock
->s_last_mounted
[6], Ext2SuperBlock
->s_last_mounted
[7], Ext2SuperBlock
->s_last_mounted
[8], Ext2SuperBlock
->s_last_mounted
[9],
647 Ext2SuperBlock
->s_last_mounted
[10], Ext2SuperBlock
->s_last_mounted
[11], Ext2SuperBlock
->s_last_mounted
[12], Ext2SuperBlock
->s_last_mounted
[13], Ext2SuperBlock
->s_last_mounted
[14], Ext2SuperBlock
->s_last_mounted
[15], Ext2SuperBlock
->s_last_mounted
[16], Ext2SuperBlock
->s_last_mounted
[17], Ext2SuperBlock
->s_last_mounted
[18], Ext2SuperBlock
->s_last_mounted
[19],
648 Ext2SuperBlock
->s_last_mounted
[20], Ext2SuperBlock
->s_last_mounted
[21], Ext2SuperBlock
->s_last_mounted
[22], Ext2SuperBlock
->s_last_mounted
[23], Ext2SuperBlock
->s_last_mounted
[24], Ext2SuperBlock
->s_last_mounted
[25], Ext2SuperBlock
->s_last_mounted
[26], Ext2SuperBlock
->s_last_mounted
[27], Ext2SuperBlock
->s_last_mounted
[28], Ext2SuperBlock
->s_last_mounted
[29],
649 Ext2SuperBlock
->s_last_mounted
[30], Ext2SuperBlock
->s_last_mounted
[31], Ext2SuperBlock
->s_last_mounted
[32], Ext2SuperBlock
->s_last_mounted
[33], Ext2SuperBlock
->s_last_mounted
[34], Ext2SuperBlock
->s_last_mounted
[35], Ext2SuperBlock
->s_last_mounted
[36], Ext2SuperBlock
->s_last_mounted
[37], Ext2SuperBlock
->s_last_mounted
[38], Ext2SuperBlock
->s_last_mounted
[39],
650 Ext2SuperBlock
->s_last_mounted
[40], Ext2SuperBlock
->s_last_mounted
[41], Ext2SuperBlock
->s_last_mounted
[42], Ext2SuperBlock
->s_last_mounted
[43], Ext2SuperBlock
->s_last_mounted
[44], Ext2SuperBlock
->s_last_mounted
[45], Ext2SuperBlock
->s_last_mounted
[46], Ext2SuperBlock
->s_last_mounted
[47], Ext2SuperBlock
->s_last_mounted
[48], Ext2SuperBlock
->s_last_mounted
[49],
651 Ext2SuperBlock
->s_last_mounted
[50], Ext2SuperBlock
->s_last_mounted
[51], Ext2SuperBlock
->s_last_mounted
[52], Ext2SuperBlock
->s_last_mounted
[53], Ext2SuperBlock
->s_last_mounted
[54], Ext2SuperBlock
->s_last_mounted
[55], Ext2SuperBlock
->s_last_mounted
[56], Ext2SuperBlock
->s_last_mounted
[57], Ext2SuperBlock
->s_last_mounted
[58], Ext2SuperBlock
->s_last_mounted
[59],
652 Ext2SuperBlock
->s_last_mounted
[60], Ext2SuperBlock
->s_last_mounted
[61], Ext2SuperBlock
->s_last_mounted
[62], Ext2SuperBlock
->s_last_mounted
[63]));
653 DbgPrint((DPRINT_FILESYSTEM
, "s_algorithm_usage_bitmap = 0x%x\n", Ext2SuperBlock
->s_algorithm_usage_bitmap
));
654 DbgPrint((DPRINT_FILESYSTEM
, "s_prealloc_blocks = %d\n", Ext2SuperBlock
->s_prealloc_blocks
));
655 DbgPrint((DPRINT_FILESYSTEM
, "s_prealloc_dir_blocks = %d\n", Ext2SuperBlock
->s_prealloc_dir_blocks
));
656 DbgPrint((DPRINT_FILESYSTEM
, "s_padding1 = %d\n", Ext2SuperBlock
->s_padding1
));
657 DbgPrint((DPRINT_FILESYSTEM
, "s_journal_uuid[16] = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", Ext2SuperBlock
->s_journal_uuid
[0], Ext2SuperBlock
->s_journal_uuid
[1], Ext2SuperBlock
->s_journal_uuid
[2], Ext2SuperBlock
->s_journal_uuid
[3], Ext2SuperBlock
->s_journal_uuid
[4], Ext2SuperBlock
->s_journal_uuid
[5], Ext2SuperBlock
->s_journal_uuid
[6], Ext2SuperBlock
->s_journal_uuid
[7], Ext2SuperBlock
->s_journal_uuid
[8], Ext2SuperBlock
->s_journal_uuid
[9], Ext2SuperBlock
->s_journal_uuid
[10], Ext2SuperBlock
->s_journal_uuid
[11], Ext2SuperBlock
->s_journal_uuid
[12], Ext2SuperBlock
->s_journal_uuid
[13], Ext2SuperBlock
->s_journal_uuid
[14], Ext2SuperBlock
->s_journal_uuid
[15]));
658 DbgPrint((DPRINT_FILESYSTEM
, "s_journal_inum = %d\n", Ext2SuperBlock
->s_journal_inum
));
659 DbgPrint((DPRINT_FILESYSTEM
, "s_journal_dev = %d\n", Ext2SuperBlock
->s_journal_dev
));
660 DbgPrint((DPRINT_FILESYSTEM
, "s_last_orphan = %d\n", Ext2SuperBlock
->s_last_orphan
));
663 // Check the super block magic
665 if (Ext2SuperBlock
->s_magic
!= EXT3_SUPER_MAGIC
)
667 FileSystemError("Invalid super block magic (0xef53)");
672 // Check the revision level
674 if (Ext2SuperBlock
->s_rev_level
> EXT3_DYNAMIC_REV
)
676 FileSystemError("FreeLoader does not understand the revision of this EXT2/EXT3 filesystem.\nPlease update FreeLoader.");
681 // Check the feature set
682 // Don't need to check the compatible or read-only compatible features
683 // because we only mount the filesystem as read-only
685 if ((Ext2SuperBlock
->s_rev_level
>= EXT3_DYNAMIC_REV
) &&
686 (/*((Ext2SuperBlock->s_feature_compat & ~EXT3_FEATURE_COMPAT_SUPP) != 0) ||*/
687 /*((Ext2SuperBlock->s_feature_ro_compat & ~EXT3_FEATURE_RO_COMPAT_SUPP) != 0) ||*/
688 ((Ext2SuperBlock
->s_feature_incompat
& ~EXT3_FEATURE_INCOMPAT_SUPP
) != 0)))
690 FileSystemError("FreeLoader does not understand features of this EXT2/EXT3 filesystem.\nPlease update FreeLoader.");
694 // Calculate the group count
695 Ext2GroupCount
= (Ext2SuperBlock
->s_blocks_count
- Ext2SuperBlock
->s_first_data_block
+ Ext2SuperBlock
->s_blocks_per_group
- 1) / Ext2SuperBlock
->s_blocks_per_group
;
696 DbgPrint((DPRINT_FILESYSTEM
, "Ext2GroupCount: %d\n", Ext2GroupCount
));
698 // Calculate the block size
699 Ext2BlockSizeInBytes
= 1024 << Ext2SuperBlock
->s_log_block_size
;
700 Ext2BlockSizeInSectors
= Ext2BlockSizeInBytes
/ Ext2DiskGeometry
.BytesPerSector
;
701 DbgPrint((DPRINT_FILESYSTEM
, "Ext2BlockSizeInBytes: %d\n", Ext2BlockSizeInBytes
));
702 DbgPrint((DPRINT_FILESYSTEM
, "Ext2BlockSizeInSectors: %d\n", Ext2BlockSizeInSectors
));
704 // Calculate the fragment size
705 if (Ext2SuperBlock
->s_log_frag_size
>= 0)
707 Ext2FragmentSizeInBytes
= 1024 << Ext2SuperBlock
->s_log_frag_size
;
711 Ext2FragmentSizeInBytes
= 1024 >> -(Ext2SuperBlock
->s_log_frag_size
);
713 Ext2FragmentSizeInSectors
= Ext2FragmentSizeInBytes
/ Ext2DiskGeometry
.BytesPerSector
;
714 DbgPrint((DPRINT_FILESYSTEM
, "Ext2FragmentSizeInBytes: %d\n", Ext2FragmentSizeInBytes
));
715 DbgPrint((DPRINT_FILESYSTEM
, "Ext2FragmentSizeInSectors: %d\n", Ext2FragmentSizeInSectors
));
717 // Verify that the fragment size and the block size are equal
718 if (Ext2BlockSizeInBytes
!= Ext2FragmentSizeInBytes
)
720 FileSystemError("The fragment size must be equal to the block size.");
724 // Calculate the number of inodes in one block
725 Ext2InodesPerBlock
= Ext2BlockSizeInBytes
/ EXT3_INODE_SIZE(Ext2SuperBlock
);
726 DbgPrint((DPRINT_FILESYSTEM
, "Ext2InodesPerBlock: %d\n", Ext2InodesPerBlock
));
728 // Calculate the number of group descriptors in one block
729 Ext2GroupDescPerBlock
= EXT3_DESC_PER_BLOCK(Ext2SuperBlock
);
730 DbgPrint((DPRINT_FILESYSTEM
, "Ext2GroupDescPerBlock: %d\n", Ext2GroupDescPerBlock
));
735 BOOLEAN
Ext2ReadGroupDescriptors(VOID
)
737 ULONG GroupDescBlockCount
;
738 ULONG CurrentGroupDescBlock
;
740 DbgPrint((DPRINT_FILESYSTEM
, "Ext2ReadGroupDescriptors()\n"));
743 // Free any memory previously allocated
745 if (Ext2GroupDescriptors
!= NULL
)
747 MmHeapFree(Ext2GroupDescriptors
);
749 Ext2GroupDescriptors
= NULL
;
753 // Now allocate the memory to hold the group descriptors
755 GroupDescBlockCount
= ROUND_UP(Ext2GroupCount
, Ext2GroupDescPerBlock
) / Ext2GroupDescPerBlock
;
756 Ext2GroupDescriptors
= (PEXT2_GROUP_DESC
)MmHeapAlloc(GroupDescBlockCount
* Ext2BlockSizeInBytes
);
759 // Make sure we got the memory
761 if (Ext2GroupDescriptors
== NULL
)
763 FileSystemError("Out of memory.");
767 // Now read the group descriptors
768 for (CurrentGroupDescBlock
=0; CurrentGroupDescBlock
<GroupDescBlockCount
; CurrentGroupDescBlock
++)
770 if (!Ext2ReadBlock(Ext2SuperBlock
->s_first_data_block
+ 1 + CurrentGroupDescBlock
, (PVOID
)FILESYSBUFFER
))
775 RtlCopyMemory((Ext2GroupDescriptors
+ (CurrentGroupDescBlock
* Ext2BlockSizeInBytes
)), (PVOID
)FILESYSBUFFER
, Ext2BlockSizeInBytes
);
781 BOOLEAN
Ext2ReadDirectory(ULONG Inode
, PVOID
* DirectoryBuffer
, PEXT2_INODE InodePointer
)
783 EXT2_FILE_INFO DirectoryFileInfo
;
785 DbgPrint((DPRINT_FILESYSTEM
, "Ext2ReadDirectory() Inode = %d\n", Inode
));
787 // Read the directory inode
788 if (!Ext2ReadInode(Inode
, InodePointer
))
793 // Make sure it is a directory inode
794 if ((InodePointer
->i_mode
& EXT2_S_IFMT
) != EXT2_S_IFDIR
)
796 FileSystemError("Inode is not a directory.");
800 // Fill in file info struct so we can call Ext2ReadFileBig()
801 RtlZeroMemory(&DirectoryFileInfo
, sizeof(EXT2_FILE_INFO
));
802 DirectoryFileInfo
.DriveNumber
= Ext2DriveNumber
;
803 DirectoryFileInfo
.FileBlockList
= Ext2ReadBlockPointerList(InodePointer
);
804 DirectoryFileInfo
.FilePointer
= 0;
805 DirectoryFileInfo
.FileSize
= Ext2GetInodeFileSize(InodePointer
);
807 if (DirectoryFileInfo
.FileBlockList
== NULL
)
813 // Now allocate the memory to hold the group descriptors
815 *DirectoryBuffer
= (PEXT2_DIR_ENTRY
)MmHeapAlloc(DirectoryFileInfo
.FileSize
);
818 // Make sure we got the memory
820 if (*DirectoryBuffer
== NULL
)
822 MmHeapFree(DirectoryFileInfo
.FileBlockList
);
823 FileSystemError("Out of memory.");
827 // Now read the root directory data
828 if (!Ext2ReadFileBig(&DirectoryFileInfo
, DirectoryFileInfo
.FileSize
, NULL
, *DirectoryBuffer
))
830 MmHeapFree(*DirectoryBuffer
);
831 *DirectoryBuffer
= NULL
;
832 MmHeapFree(DirectoryFileInfo
.FileBlockList
);
836 MmHeapFree(DirectoryFileInfo
.FileBlockList
);
840 BOOLEAN
Ext2ReadBlock(ULONG BlockNumber
, PVOID Buffer
)
842 CHAR ErrorString
[80];
844 DbgPrint((DPRINT_FILESYSTEM
, "Ext2ReadBlock() BlockNumber = %d Buffer = 0x%x\n", BlockNumber
, Buffer
));
846 // Make sure its a valid block
847 if (BlockNumber
> Ext2SuperBlock
->s_blocks_count
)
849 sprintf(ErrorString
, "Error reading block %d - block out of range.", (int) BlockNumber
);
850 FileSystemError(ErrorString
);
854 // Check to see if this is a sparse block
855 if (BlockNumber
== 0)
857 DbgPrint((DPRINT_FILESYSTEM
, "Block is part of a sparse file. Zeroing input buffer.\n"));
859 RtlZeroMemory(Buffer
, Ext2BlockSizeInBytes
);
864 return Ext2ReadVolumeSectors(Ext2DriveNumber
, (ULONGLONG
)BlockNumber
* Ext2BlockSizeInSectors
, Ext2BlockSizeInSectors
, Buffer
);
868 * Ext2ReadPartialBlock()
869 * Reads part of a block into memory
871 BOOLEAN
Ext2ReadPartialBlock(ULONG BlockNumber
, ULONG StartingOffset
, ULONG Length
, PVOID Buffer
)
874 DbgPrint((DPRINT_FILESYSTEM
, "Ext2ReadPartialBlock() BlockNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", BlockNumber
, StartingOffset
, Length
, Buffer
));
876 if (!Ext2ReadBlock(BlockNumber
, (PVOID
)FILESYSBUFFER
))
881 memcpy(Buffer
, (PVOID
)((ULONG_PTR
)FILESYSBUFFER
+ StartingOffset
), Length
);
886 ULONG
Ext2GetGroupDescBlockNumber(ULONG Group
)
888 return (((Group
* sizeof(EXT2_GROUP_DESC
)) / Ext2GroupDescPerBlock
) + Ext2SuperBlock
->s_first_data_block
+ 1);
891 ULONG
Ext2GetGroupDescOffsetInBlock(ULONG Group
)
893 return ((Group
* sizeof(EXT2_GROUP_DESC
)) % Ext2GroupDescPerBlock
);
896 ULONG
Ext2GetInodeGroupNumber(ULONG Inode
)
898 return ((Inode
- 1) / Ext2SuperBlock
->s_inodes_per_group
);
901 ULONG
Ext2GetInodeBlockNumber(ULONG Inode
)
903 return (((Inode
- 1) % Ext2SuperBlock
->s_inodes_per_group
) / Ext2InodesPerBlock
);
906 ULONG
Ext2GetInodeOffsetInBlock(ULONG Inode
)
908 return (((Inode
- 1) % Ext2SuperBlock
->s_inodes_per_group
) % Ext2InodesPerBlock
);
911 BOOLEAN
Ext2ReadInode(ULONG Inode
, PEXT2_INODE InodeBuffer
)
913 ULONG InodeGroupNumber
;
914 ULONG InodeBlockNumber
;
915 ULONG InodeOffsetInBlock
;
916 CHAR ErrorString
[80];
917 EXT2_GROUP_DESC GroupDescriptor
;
919 DbgPrint((DPRINT_FILESYSTEM
, "Ext2ReadInode() Inode = %d\n", Inode
));
921 // Make sure its a valid inode
922 if ((Inode
< 1) || (Inode
> Ext2SuperBlock
->s_inodes_count
))
924 sprintf(ErrorString
, "Error reading inode %ld - inode out of range.", Inode
);
925 FileSystemError(ErrorString
);
929 // Get inode group & block number and offset in block
930 InodeGroupNumber
= Ext2GetInodeGroupNumber(Inode
);
931 InodeBlockNumber
= Ext2GetInodeBlockNumber(Inode
);
932 InodeOffsetInBlock
= Ext2GetInodeOffsetInBlock(Inode
);
933 DbgPrint((DPRINT_FILESYSTEM
, "InodeGroupNumber = %d\n", InodeGroupNumber
));
934 DbgPrint((DPRINT_FILESYSTEM
, "InodeBlockNumber = %d\n", InodeBlockNumber
));
935 DbgPrint((DPRINT_FILESYSTEM
, "InodeOffsetInBlock = %d\n", InodeOffsetInBlock
));
937 // Read the group descriptor
938 if (!Ext2ReadGroupDescriptor(InodeGroupNumber
, &GroupDescriptor
))
943 // Add the start block of the inode table to the inode block number
944 InodeBlockNumber
+= GroupDescriptor
.bg_inode_table
;
945 DbgPrint((DPRINT_FILESYSTEM
, "InodeBlockNumber (after group desc correction) = %d\n", InodeBlockNumber
));
948 if (!Ext2ReadBlock(InodeBlockNumber
, (PVOID
)FILESYSBUFFER
))
953 // Copy the data to their buffer
954 RtlCopyMemory(InodeBuffer
, (PVOID
)(FILESYSBUFFER
+ (InodeOffsetInBlock
* EXT3_INODE_SIZE(Ext2SuperBlock
))), sizeof(EXT2_INODE
));
956 DbgPrint((DPRINT_FILESYSTEM
, "Dumping inode information:\n"));
957 DbgPrint((DPRINT_FILESYSTEM
, "i_mode = 0x%x\n", InodeBuffer
->i_mode
));
958 DbgPrint((DPRINT_FILESYSTEM
, "i_uid = %d\n", InodeBuffer
->i_uid
));
959 DbgPrint((DPRINT_FILESYSTEM
, "i_size = %d\n", InodeBuffer
->i_size
));
960 DbgPrint((DPRINT_FILESYSTEM
, "i_atime = %d\n", InodeBuffer
->i_atime
));
961 DbgPrint((DPRINT_FILESYSTEM
, "i_ctime = %d\n", InodeBuffer
->i_ctime
));
962 DbgPrint((DPRINT_FILESYSTEM
, "i_mtime = %d\n", InodeBuffer
->i_mtime
));
963 DbgPrint((DPRINT_FILESYSTEM
, "i_dtime = %d\n", InodeBuffer
->i_dtime
));
964 DbgPrint((DPRINT_FILESYSTEM
, "i_gid = %d\n", InodeBuffer
->i_gid
));
965 DbgPrint((DPRINT_FILESYSTEM
, "i_links_count = %d\n", InodeBuffer
->i_links_count
));
966 DbgPrint((DPRINT_FILESYSTEM
, "i_blocks = %d\n", InodeBuffer
->i_blocks
));
967 DbgPrint((DPRINT_FILESYSTEM
, "i_flags = 0x%x\n", InodeBuffer
->i_flags
));
968 DbgPrint((DPRINT_FILESYSTEM
, "i_block[EXT3_N_BLOCKS (%d)] =\n%d,\n%d,\n%d,\n%d,\n%d,\n%d,\n%d,\n%d,\n%d,\n%d,\n%d,\n%d,\n%d,\n%d,\n%d\n", EXT3_N_BLOCKS
, InodeBuffer
->i_block
[0], InodeBuffer
->i_block
[1], InodeBuffer
->i_block
[2], InodeBuffer
->i_block
[3], InodeBuffer
->i_block
[4], InodeBuffer
->i_block
[5], InodeBuffer
->i_block
[6], InodeBuffer
->i_block
[7], InodeBuffer
->i_block
[8], InodeBuffer
->i_block
[9], InodeBuffer
->i_block
[10], InodeBuffer
->i_block
[11], InodeBuffer
->i_block
[12], InodeBuffer
->i_block
[13], InodeBuffer
->i_block
[14]));
969 DbgPrint((DPRINT_FILESYSTEM
, "i_generation = %d\n", InodeBuffer
->i_generation
));
970 DbgPrint((DPRINT_FILESYSTEM
, "i_file_acl = %d\n", InodeBuffer
->i_file_acl
));
971 DbgPrint((DPRINT_FILESYSTEM
, "i_dir_acl = %d\n", InodeBuffer
->i_dir_acl
));
972 DbgPrint((DPRINT_FILESYSTEM
, "i_faddr = %d\n", InodeBuffer
->i_faddr
));
973 DbgPrint((DPRINT_FILESYSTEM
, "l_i_frag = %d\n", InodeBuffer
->osd2
.linux2
.l_i_frag
));
974 DbgPrint((DPRINT_FILESYSTEM
, "l_i_fsize = %d\n", InodeBuffer
->osd2
.linux2
.l_i_fsize
));
975 DbgPrint((DPRINT_FILESYSTEM
, "l_i_uid_high = %d\n", InodeBuffer
->osd2
.linux2
.l_i_uid_high
));
976 DbgPrint((DPRINT_FILESYSTEM
, "l_i_gid_high = %d\n", InodeBuffer
->osd2
.linux2
.l_i_gid_high
));
981 BOOLEAN
Ext2ReadGroupDescriptor(ULONG Group
, PEXT2_GROUP_DESC GroupBuffer
)
983 DbgPrint((DPRINT_FILESYSTEM
, "Ext2ReadGroupDescriptor()\n"));
985 /*if (!Ext2ReadBlock(Ext2GetGroupDescBlockNumber(Group), (PVOID)FILESYSBUFFER))
990 RtlCopyMemory(GroupBuffer, (PVOID)(FILESYSBUFFER + Ext2GetGroupDescOffsetInBlock(Group)), sizeof(EXT2_GROUP_DESC));*/
992 RtlCopyMemory(GroupBuffer
, &Ext2GroupDescriptors
[Group
], sizeof(EXT2_GROUP_DESC
));
994 DbgPrint((DPRINT_FILESYSTEM
, "Dumping group descriptor:\n"));
995 DbgPrint((DPRINT_FILESYSTEM
, "bg_block_bitmap = %d\n", GroupBuffer
->bg_block_bitmap
));
996 DbgPrint((DPRINT_FILESYSTEM
, "bg_inode_bitmap = %d\n", GroupBuffer
->bg_inode_bitmap
));
997 DbgPrint((DPRINT_FILESYSTEM
, "bg_inode_table = %d\n", GroupBuffer
->bg_inode_table
));
998 DbgPrint((DPRINT_FILESYSTEM
, "bg_free_blocks_count = %d\n", GroupBuffer
->bg_free_blocks_count
));
999 DbgPrint((DPRINT_FILESYSTEM
, "bg_free_inodes_count = %d\n", GroupBuffer
->bg_free_inodes_count
));
1000 DbgPrint((DPRINT_FILESYSTEM
, "bg_used_dirs_count = %d\n", GroupBuffer
->bg_used_dirs_count
));
1005 ULONG
* Ext2ReadBlockPointerList(PEXT2_INODE Inode
)
1010 ULONG CurrentBlockInList
;
1013 DbgPrint((DPRINT_FILESYSTEM
, "Ext2ReadBlockPointerList()\n"));
1015 // Get the number of blocks this file occupies
1016 // I would just use Inode->i_blocks but it
1017 // doesn't seem to be the number of blocks
1018 // the file size corresponds to, but instead
1019 // it is much bigger.
1020 //BlockCount = Inode->i_blocks;
1021 FileSize
= Ext2GetInodeFileSize(Inode
);
1022 FileSize
= ROUND_UP(FileSize
, Ext2BlockSizeInBytes
);
1023 BlockCount
= (FileSize
/ Ext2BlockSizeInBytes
);
1025 // Allocate the memory for the block list
1026 BlockList
= MmHeapAlloc(BlockCount
* sizeof(ULONG
));
1027 if (BlockList
== NULL
)
1032 RtlZeroMemory(BlockList
, BlockCount
* sizeof(ULONG
));
1033 CurrentBlockInList
= 0;
1035 // Copy the direct block pointers
1036 for (CurrentBlock
=0; CurrentBlockInList
<BlockCount
&& CurrentBlock
<EXT3_NDIR_BLOCKS
; CurrentBlock
++)
1038 BlockList
[CurrentBlockInList
] = Inode
->i_block
[CurrentBlock
];
1039 CurrentBlockInList
++;
1042 // Copy the indirect block pointers
1043 if (CurrentBlockInList
< BlockCount
)
1045 if (!Ext2CopyIndirectBlockPointers(BlockList
, &CurrentBlockInList
, BlockCount
, Inode
->i_block
[EXT3_IND_BLOCK
]))
1047 MmHeapFree(BlockList
);
1052 // Copy the double indirect block pointers
1053 if (CurrentBlockInList
< BlockCount
)
1055 if (!Ext2CopyDoubleIndirectBlockPointers(BlockList
, &CurrentBlockInList
, BlockCount
, Inode
->i_block
[EXT3_DIND_BLOCK
]))
1057 MmHeapFree(BlockList
);
1062 // Copy the triple indirect block pointers
1063 if (CurrentBlockInList
< BlockCount
)
1065 if (!Ext2CopyTripleIndirectBlockPointers(BlockList
, &CurrentBlockInList
, BlockCount
, Inode
->i_block
[EXT3_TIND_BLOCK
]))
1067 MmHeapFree(BlockList
);
1075 ULONGLONG
Ext2GetInodeFileSize(PEXT2_INODE Inode
)
1077 if ((Inode
->i_mode
& EXT2_S_IFMT
) == EXT2_S_IFDIR
)
1079 return (ULONGLONG
)(Inode
->i_size
);
1083 return ((ULONGLONG
)(Inode
->i_size
) | ((ULONGLONG
)(Inode
->i_dir_acl
) << 32));
1087 BOOLEAN
Ext2CopyIndirectBlockPointers(ULONG
* BlockList
, ULONG
* CurrentBlockInList
, ULONG BlockCount
, ULONG IndirectBlock
)
1089 ULONG
* BlockBuffer
= (ULONG
*)FILESYSBUFFER
;
1091 ULONG BlockPointersPerBlock
;
1093 DbgPrint((DPRINT_FILESYSTEM
, "Ext2CopyIndirectBlockPointers() BlockCount = %d\n", BlockCount
));
1095 BlockPointersPerBlock
= Ext2BlockSizeInBytes
/ sizeof(ULONG
);
1097 if (!Ext2ReadBlock(IndirectBlock
, BlockBuffer
))
1102 for (CurrentBlock
=0; (*CurrentBlockInList
)<BlockCount
&& CurrentBlock
<BlockPointersPerBlock
; CurrentBlock
++)
1104 BlockList
[(*CurrentBlockInList
)] = BlockBuffer
[CurrentBlock
];
1105 (*CurrentBlockInList
)++;
1111 BOOLEAN
Ext2CopyDoubleIndirectBlockPointers(ULONG
* BlockList
, ULONG
* CurrentBlockInList
, ULONG BlockCount
, ULONG DoubleIndirectBlock
)
1115 ULONG BlockPointersPerBlock
;
1117 DbgPrint((DPRINT_FILESYSTEM
, "Ext2CopyDoubleIndirectBlockPointers() BlockCount = %d\n", BlockCount
));
1119 BlockPointersPerBlock
= Ext2BlockSizeInBytes
/ sizeof(ULONG
);
1121 BlockBuffer
= (ULONG
*)MmHeapAlloc(Ext2BlockSizeInBytes
);
1122 if (BlockBuffer
== NULL
)
1127 if (!Ext2ReadBlock(DoubleIndirectBlock
, BlockBuffer
))
1129 MmHeapFree(BlockBuffer
);
1133 for (CurrentBlock
=0; (*CurrentBlockInList
)<BlockCount
&& CurrentBlock
<BlockPointersPerBlock
; CurrentBlock
++)
1135 if (!Ext2CopyIndirectBlockPointers(BlockList
, CurrentBlockInList
, BlockCount
, BlockBuffer
[CurrentBlock
]))
1137 MmHeapFree(BlockBuffer
);
1142 MmHeapFree(BlockBuffer
);
1146 BOOLEAN
Ext2CopyTripleIndirectBlockPointers(ULONG
* BlockList
, ULONG
* CurrentBlockInList
, ULONG BlockCount
, ULONG TripleIndirectBlock
)
1150 ULONG BlockPointersPerBlock
;
1152 DbgPrint((DPRINT_FILESYSTEM
, "Ext2CopyTripleIndirectBlockPointers() BlockCount = %d\n", BlockCount
));
1154 BlockPointersPerBlock
= Ext2BlockSizeInBytes
/ sizeof(ULONG
);
1156 BlockBuffer
= (ULONG
*)MmHeapAlloc(Ext2BlockSizeInBytes
);
1157 if (BlockBuffer
== NULL
)
1162 if (!Ext2ReadBlock(TripleIndirectBlock
, BlockBuffer
))
1164 MmHeapFree(BlockBuffer
);
1168 for (CurrentBlock
=0; (*CurrentBlockInList
)<BlockCount
&& CurrentBlock
<BlockPointersPerBlock
; CurrentBlock
++)
1170 if (!Ext2CopyDoubleIndirectBlockPointers(BlockList
, CurrentBlockInList
, BlockCount
, BlockBuffer
[CurrentBlock
]))
1172 MmHeapFree(BlockBuffer
);
1177 MmHeapFree(BlockBuffer
);
1181 const FS_VTBL Ext2Vtbl
= {