- Remove duplicated code in "rtl" and use libstring and librtl instead (their code...
[reactos.git] / reactos / boot / freeldr / freeldr / fs / ext2.c
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <freeldr.h>
21
22 #define NDEBUG
23 #include <debug.h>
24
25 GEOMETRY Ext2DiskGeometry; // Ext2 file system disk geometry
26
27 PEXT2_SUPER_BLOCK Ext2SuperBlock = NULL; // Ext2 file system super block
28 PEXT2_GROUP_DESC Ext2GroupDescriptors = NULL; // Ext2 file system group descriptors
29
30 UCHAR Ext2DriveNumber = 0; // Ext2 file system drive number
31 ULONGLONG Ext2VolumeStartSector = 0; // Ext2 file system starting sector
32 ULONG Ext2BlockSizeInBytes = 0; // Block size in bytes
33 ULONG Ext2BlockSizeInSectors = 0; // Block size in sectors
34 ULONG Ext2FragmentSizeInBytes = 0; // Fragment size in bytes
35 ULONG Ext2FragmentSizeInSectors = 0; // Fragment size in sectors
36 ULONG Ext2GroupCount = 0; // Number of groups in this file system
37 ULONG Ext2InodesPerBlock = 0; // Number of inodes in one block
38 ULONG Ext2GroupDescPerBlock = 0; // Number of group descriptors in one block
39
40 BOOL Ext2OpenVolume(UCHAR DriveNumber, ULONGLONG VolumeStartSector)
41 {
42
43 DbgPrint((DPRINT_FILESYSTEM, "Ext2OpenVolume() DriveNumber = 0x%x VolumeStartSector = %d\n", DriveNumber, VolumeStartSector));
44
45 // Store the drive number and start sector
46 Ext2DriveNumber = DriveNumber;
47 Ext2VolumeStartSector = VolumeStartSector;
48
49 if (!MachDiskGetDriveGeometry(DriveNumber, &Ext2DiskGeometry))
50 {
51 return FALSE;
52 }
53
54 //
55 // Initialize the disk cache for this drive
56 //
57 if (!CacheInitializeDrive(DriveNumber))
58 {
59 return FALSE;
60 }
61
62 // Read in the super block
63 if (!Ext2ReadSuperBlock())
64 {
65 return FALSE;
66 }
67
68 // Read in the group descriptors
69 if (!Ext2ReadGroupDescriptors())
70 {
71 return FALSE;
72 }
73
74 return TRUE;
75 }
76
77 /*
78 * Ext2OpenFile()
79 * Tries to open the file 'name' and returns true or false
80 * for success and failure respectively
81 */
82 FILE* Ext2OpenFile(PCSTR FileName)
83 {
84 EXT2_FILE_INFO TempExt2FileInfo;
85 PEXT2_FILE_INFO FileHandle;
86 CHAR SymLinkPath[EXT3_NAME_LEN];
87 CHAR FullPath[EXT3_NAME_LEN * 2];
88 ULONG Index;
89
90 DbgPrint((DPRINT_FILESYSTEM, "Ext2OpenFile() FileName = %s\n", FileName));
91
92 RtlZeroMemory(SymLinkPath, EXT3_NAME_LEN);
93
94 // Lookup the file in the file system
95 if (!Ext2LookupFile(FileName, &TempExt2FileInfo))
96 {
97 return NULL;
98 }
99
100 // If we got a symbolic link then fix up the path
101 // and re-call this function
102 if ((TempExt2FileInfo.Inode.i_mode & EXT2_S_IFMT) == EXT2_S_IFLNK)
103 {
104 DbgPrint((DPRINT_FILESYSTEM, "File is a symbolic link\n"));
105
106 // Now read in the symbolic link path
107 if (!Ext2ReadFile(&TempExt2FileInfo, TempExt2FileInfo.FileSize, NULL, SymLinkPath))
108 {
109 if (TempExt2FileInfo.FileBlockList != NULL)
110 {
111 MmFreeMemory(TempExt2FileInfo.FileBlockList);
112 }
113
114 return NULL;
115 }
116
117 DbgPrint((DPRINT_FILESYSTEM, "Symbolic link path = %s\n", SymLinkPath));
118
119 // Get the full path
120 if (SymLinkPath[0] == '/' || SymLinkPath[0] == '\\')
121 {
122 // Symbolic link is an absolute path
123 // So copy it to FullPath, but skip over
124 // the '/' char at the beginning
125 strcpy(FullPath, &SymLinkPath[1]);
126 }
127 else
128 {
129 // Symbolic link is a relative path
130 // Copy the first part of the path
131 strcpy(FullPath, FileName);
132
133 // Remove the last part of the path
134 for (Index=strlen(FullPath); Index>0; )
135 {
136 Index--;
137 if (FullPath[Index] == '/' || FullPath[Index] == '\\')
138 {
139 break;
140 }
141 }
142 FullPath[Index] = '\0';
143
144 // Concatenate the symbolic link
145 strcat(FullPath, Index == 0 ? "" : "/");
146 strcat(FullPath, SymLinkPath);
147 }
148
149 DbgPrint((DPRINT_FILESYSTEM, "Full file path = %s\n", FullPath));
150
151 if (TempExt2FileInfo.FileBlockList != NULL)
152 {
153 MmFreeMemory(TempExt2FileInfo.FileBlockList);
154 }
155
156 return Ext2OpenFile(FullPath);
157 }
158 else
159 {
160 FileHandle = MmAllocateMemory(sizeof(EXT2_FILE_INFO));
161
162 if (FileHandle == NULL)
163 {
164 if (TempExt2FileInfo.FileBlockList != NULL)
165 {
166 MmFreeMemory(TempExt2FileInfo.FileBlockList);
167 }
168
169 return NULL;
170 }
171
172 RtlCopyMemory(FileHandle, &TempExt2FileInfo, sizeof(EXT2_FILE_INFO));
173
174 return (FILE*)FileHandle;
175 }
176 }
177
178 /*
179 * Ext2LookupFile()
180 * This function searches the file system for the
181 * specified filename and fills in a EXT2_FILE_INFO structure
182 * with info describing the file, etc. returns true
183 * if the file exists or false otherwise
184 */
185 BOOL Ext2LookupFile(PCSTR FileName, PEXT2_FILE_INFO Ext2FileInfoPointer)
186 {
187 UINT i;
188 ULONG NumberOfPathParts;
189 CHAR PathPart[261];
190 PVOID DirectoryBuffer;
191 ULONG DirectoryInode = EXT3_ROOT_INO;
192 EXT2_INODE InodeData;
193 EXT2_DIR_ENTRY DirectoryEntry;
194
195 DbgPrint((DPRINT_FILESYSTEM, "Ext2LookupFile() FileName = %s\n", FileName));
196
197 RtlZeroMemory(Ext2FileInfoPointer, sizeof(EXT2_FILE_INFO));
198
199 //
200 // Figure out how many sub-directories we are nested in
201 //
202 NumberOfPathParts = FsGetNumPathParts(FileName);
203
204 //
205 // Loop once for each part
206 //
207 for (i=0; i<NumberOfPathParts; i++)
208 {
209 //
210 // Get first path part
211 //
212 FsGetFirstNameFromPath(PathPart, FileName);
213
214 //
215 // Advance to the next part of the path
216 //
217 for (; (*FileName != '\\') && (*FileName != '/') && (*FileName != '\0'); FileName++)
218 {
219 }
220 FileName++;
221
222 //
223 // Buffer the directory contents
224 //
225 if (!Ext2ReadDirectory(DirectoryInode, &DirectoryBuffer, &InodeData))
226 {
227 return FALSE;
228 }
229
230 //
231 // Search for file name in directory
232 //
233 if (!Ext2SearchDirectoryBufferForFile(DirectoryBuffer, (ULONG)Ext2GetInodeFileSize(&InodeData), PathPart, &DirectoryEntry))
234 {
235 MmFreeMemory(DirectoryBuffer);
236 return FALSE;
237 }
238
239 MmFreeMemory(DirectoryBuffer);
240
241 DirectoryInode = DirectoryEntry.inode;
242 }
243
244 if (!Ext2ReadInode(DirectoryInode, &InodeData))
245 {
246 return FALSE;
247 }
248
249 if (((InodeData.i_mode & EXT2_S_IFMT) != EXT2_S_IFREG) &&
250 ((InodeData.i_mode & EXT2_S_IFMT) != EXT2_S_IFLNK))
251 {
252 FileSystemError("Inode is not a regular file or symbolic link.");
253 return FALSE;
254 }
255
256 // Set the drive number
257 Ext2FileInfoPointer->DriveNumber = Ext2DriveNumber;
258
259 // If it's a regular file or a regular symbolic link
260 // then get the block pointer list otherwise it must
261 // be a fast symbolic link which doesn't have a block list
262 if (((InodeData.i_mode & EXT2_S_IFMT) == EXT2_S_IFREG) ||
263 ((InodeData.i_mode & EXT2_S_IFMT) == EXT2_S_IFLNK && InodeData.i_size > FAST_SYMLINK_MAX_NAME_SIZE))
264 {
265 Ext2FileInfoPointer->FileBlockList = Ext2ReadBlockPointerList(&InodeData);
266
267 if (Ext2FileInfoPointer->FileBlockList == NULL)
268 {
269 return FALSE;
270 }
271 }
272 else
273 {
274 Ext2FileInfoPointer->FileBlockList = NULL;
275 }
276
277 Ext2FileInfoPointer->FilePointer = 0;
278 Ext2FileInfoPointer->FileSize = Ext2GetInodeFileSize(&InodeData);
279 RtlCopyMemory(&Ext2FileInfoPointer->Inode, &InodeData, sizeof(EXT2_INODE));
280
281 return TRUE;
282 }
283
284 BOOL Ext2SearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PEXT2_DIR_ENTRY DirectoryEntry)
285 {
286 ULONG CurrentOffset;
287 PEXT2_DIR_ENTRY CurrentDirectoryEntry;
288
289 DbgPrint((DPRINT_FILESYSTEM, "Ext2SearchDirectoryBufferForFile() DirectoryBuffer = 0x%x DirectorySize = %d FileName = %s\n", DirectoryBuffer, DirectorySize, FileName));
290
291 for (CurrentOffset=0; CurrentOffset<DirectorySize; )
292 {
293 CurrentDirectoryEntry = (PEXT2_DIR_ENTRY)((ULONG_PTR)DirectoryBuffer + CurrentOffset);
294
295 if (CurrentDirectoryEntry->rec_len == 0)
296 {
297 break;
298 }
299
300 if ((CurrentDirectoryEntry->rec_len + CurrentOffset) > DirectorySize)
301 {
302 FileSystemError("Directory entry extends past end of directory file.");
303 return FALSE;
304 }
305
306 DbgPrint((DPRINT_FILESYSTEM, "Dumping directory entry at offset %d:\n", CurrentOffset));
307 DbgDumpBuffer(DPRINT_FILESYSTEM, CurrentDirectoryEntry, CurrentDirectoryEntry->rec_len);
308
309 if ((_strnicmp(FileName, CurrentDirectoryEntry->name, CurrentDirectoryEntry->name_len) == 0) &&
310 (strlen(FileName) == CurrentDirectoryEntry->name_len))
311 {
312 RtlCopyMemory(DirectoryEntry, CurrentDirectoryEntry, sizeof(EXT2_DIR_ENTRY));
313
314 DbgPrint((DPRINT_FILESYSTEM, "EXT2 Directory Entry:\n"));
315 DbgPrint((DPRINT_FILESYSTEM, "inode = %d\n", DirectoryEntry->inode));
316 DbgPrint((DPRINT_FILESYSTEM, "rec_len = %d\n", DirectoryEntry->rec_len));
317 DbgPrint((DPRINT_FILESYSTEM, "name_len = %d\n", DirectoryEntry->name_len));
318 DbgPrint((DPRINT_FILESYSTEM, "file_type = %d\n", DirectoryEntry->file_type));
319 DbgPrint((DPRINT_FILESYSTEM, "name = "));
320 for (CurrentOffset=0; CurrentOffset<DirectoryEntry->name_len; CurrentOffset++)
321 {
322 DbgPrint((DPRINT_FILESYSTEM, "%c", DirectoryEntry->name[CurrentOffset]));
323 }
324 DbgPrint((DPRINT_FILESYSTEM, "\n"));
325
326 return TRUE;
327 }
328
329 CurrentOffset += CurrentDirectoryEntry->rec_len;
330 }
331
332 return FALSE;
333 }
334
335 /*
336 * Ext2ReadFile()
337 * Reads BytesToRead from open file and
338 * returns the number of bytes read in BytesRead
339 */
340 BOOL Ext2ReadFile(FILE *FileHandle, ULONGLONG BytesToRead, ULONGLONG* BytesRead, PVOID Buffer)
341 {
342 PEXT2_FILE_INFO Ext2FileInfo = (PEXT2_FILE_INFO)FileHandle;
343 ULONG BlockNumber;
344 ULONG BlockNumberIndex;
345 ULONG OffsetInBlock;
346 ULONG LengthInBlock;
347 ULONG NumberOfBlocks;
348
349 DbgPrint((DPRINT_FILESYSTEM, "Ext2ReadFile() BytesToRead = %d Buffer = 0x%x\n", (ULONG)BytesToRead, Buffer));
350
351 if (BytesRead != NULL)
352 {
353 *BytesRead = 0;
354 }
355
356 // Make sure we have the block pointer list if we need it
357 if (Ext2FileInfo->FileBlockList == NULL)
358 {
359 // Block pointer list is NULL
360 // so this better be a fast symbolic link or else
361 if (((Ext2FileInfo->Inode.i_mode & EXT2_S_IFMT) != EXT2_S_IFLNK) ||
362 (Ext2FileInfo->FileSize > FAST_SYMLINK_MAX_NAME_SIZE))
363 {
364 FileSystemError("Block pointer list is NULL and file is not a fast symbolic link.");
365 return FALSE;
366 }
367 }
368
369 //
370 // If they are trying to read past the
371 // end of the file then return success
372 // with BytesRead == 0
373 //
374 if (Ext2FileInfo->FilePointer >= Ext2FileInfo->FileSize)
375 {
376 return TRUE;
377 }
378
379 //
380 // If they are trying to read more than there is to read
381 // then adjust the amount to read
382 //
383 if ((Ext2FileInfo->FilePointer + BytesToRead) > Ext2FileInfo->FileSize)
384 {
385 BytesToRead = (Ext2FileInfo->FileSize - Ext2FileInfo->FilePointer);
386 }
387
388 // Check if this is a fast symbolic link
389 // if so then the read is easy
390 if (((Ext2FileInfo->Inode.i_mode & EXT2_S_IFMT) == EXT2_S_IFLNK) &&
391 (Ext2FileInfo->FileSize <= FAST_SYMLINK_MAX_NAME_SIZE))
392 {
393 DbgPrint((DPRINT_FILESYSTEM, "Reading fast symbolic link data\n"));
394
395 // Copy the data from the link
396 RtlCopyMemory(Buffer, (PVOID)((ULONG_PTR)Ext2FileInfo->FilePointer + Ext2FileInfo->Inode.i_block), BytesToRead);
397
398 if (BytesRead != NULL)
399 {
400 *BytesRead = BytesToRead;
401 }
402
403 return TRUE;
404 }
405
406 //
407 // Ok, now we have to perform at most 3 calculations
408 // I'll draw you a picture (using nifty ASCII art):
409 //
410 // CurrentFilePointer -+
411 // |
412 // +----------------+
413 // |
414 // +-----------+-----------+-----------+-----------+
415 // | Block 1 | Block 2 | Block 3 | Block 4 |
416 // +-----------+-----------+-----------+-----------+
417 // | |
418 // +---------------+--------------------+
419 // |
420 // BytesToRead -------+
421 //
422 // 1 - The first calculation (and read) will align
423 // the file pointer with the next block.
424 // boundary (if we are supposed to read that much)
425 // 2 - The next calculation (and read) will read
426 // in all the full blocks that the requested
427 // amount of data would cover (in this case
428 // blocks 2 & 3).
429 // 3 - The last calculation (and read) would read
430 // in the remainder of the data requested out of
431 // the last block.
432 //
433
434 //
435 // Only do the first read if we
436 // aren't aligned on a block boundary
437 //
438 if (Ext2FileInfo->FilePointer % Ext2BlockSizeInBytes)
439 {
440 //
441 // Do the math for our first read
442 //
443 BlockNumberIndex = (Ext2FileInfo->FilePointer / Ext2BlockSizeInBytes);
444 BlockNumber = Ext2FileInfo->FileBlockList[BlockNumberIndex];
445 OffsetInBlock = (Ext2FileInfo->FilePointer % Ext2BlockSizeInBytes);
446 LengthInBlock = (BytesToRead > (Ext2BlockSizeInBytes - OffsetInBlock)) ? (Ext2BlockSizeInBytes - OffsetInBlock) : BytesToRead;
447
448 //
449 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
450 //
451 if (!Ext2ReadPartialBlock(BlockNumber, OffsetInBlock, LengthInBlock, Buffer))
452 {
453 return FALSE;
454 }
455 if (BytesRead != NULL)
456 {
457 *BytesRead += LengthInBlock;
458 }
459 BytesToRead -= LengthInBlock;
460 Ext2FileInfo->FilePointer += LengthInBlock;
461 Buffer = (PVOID)((ULONG_PTR)Buffer + LengthInBlock);
462 }
463
464 //
465 // Do the math for our second read (if any data left)
466 //
467 if (BytesToRead > 0)
468 {
469 //
470 // Determine how many full clusters we need to read
471 //
472 NumberOfBlocks = (BytesToRead / Ext2BlockSizeInBytes);
473
474 while (NumberOfBlocks > 0)
475 {
476 BlockNumberIndex = (Ext2FileInfo->FilePointer / Ext2BlockSizeInBytes);
477 BlockNumber = Ext2FileInfo->FileBlockList[BlockNumberIndex];
478
479 //
480 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
481 //
482 if (!Ext2ReadBlock(BlockNumber, Buffer))
483 {
484 return FALSE;
485 }
486 if (BytesRead != NULL)
487 {
488 *BytesRead += Ext2BlockSizeInBytes;
489 }
490 BytesToRead -= Ext2BlockSizeInBytes;
491 Ext2FileInfo->FilePointer += Ext2BlockSizeInBytes;
492 Buffer = (PVOID)((ULONG_PTR)Buffer + Ext2BlockSizeInBytes);
493 NumberOfBlocks--;
494 }
495 }
496
497 //
498 // Do the math for our third read (if any data left)
499 //
500 if (BytesToRead > 0)
501 {
502 BlockNumberIndex = (Ext2FileInfo->FilePointer / Ext2BlockSizeInBytes);
503 BlockNumber = Ext2FileInfo->FileBlockList[BlockNumberIndex];
504
505 //
506 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
507 //
508 if (!Ext2ReadPartialBlock(BlockNumber, 0, BytesToRead, Buffer))
509 {
510 return FALSE;
511 }
512 if (BytesRead != NULL)
513 {
514 *BytesRead += BytesToRead;
515 }
516 Ext2FileInfo->FilePointer += BytesToRead;
517 BytesToRead -= BytesToRead;
518 Buffer = (PVOID)((ULONG_PTR)Buffer + (ULONG_PTR)BytesToRead);
519 }
520
521 return TRUE;
522 }
523
524 ULONGLONG Ext2GetFileSize(FILE *FileHandle)
525 {
526 PEXT2_FILE_INFO Ext2FileHandle = (PEXT2_FILE_INFO)FileHandle;
527
528 DbgPrint((DPRINT_FILESYSTEM, "Ext2GetFileSize() FileSize = %d\n", Ext2FileHandle->FileSize));
529
530 return Ext2FileHandle->FileSize;
531 }
532
533 VOID Ext2SetFilePointer(FILE *FileHandle, ULONGLONG NewFilePointer)
534 {
535 PEXT2_FILE_INFO Ext2FileHandle = (PEXT2_FILE_INFO)FileHandle;
536
537 DbgPrint((DPRINT_FILESYSTEM, "Ext2SetFilePointer() NewFilePointer = %d\n", NewFilePointer));
538
539 Ext2FileHandle->FilePointer = NewFilePointer;
540 }
541
542 ULONGLONG Ext2GetFilePointer(FILE *FileHandle)
543 {
544 PEXT2_FILE_INFO Ext2FileHandle = (PEXT2_FILE_INFO)FileHandle;
545
546 DbgPrint((DPRINT_FILESYSTEM, "Ext2GetFilePointer() FilePointer = %d\n", Ext2FileHandle->FilePointer));
547
548 return Ext2FileHandle->FilePointer;
549 }
550
551 BOOL Ext2ReadVolumeSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONGLONG SectorCount, PVOID Buffer)
552 {
553 //GEOMETRY DiskGeometry;
554 //BOOL ReturnValue;
555 //if (!DiskGetDriveGeometry(DriveNumber, &DiskGeometry))
556 //{
557 // return FALSE;
558 //}
559 //ReturnValue = MachDiskReadLogicalSectors(DriveNumber, SectorNumber + Ext2VolumeStartSector, SectorCount, (PVOID)DISKREADBUFFER);
560 //RtlCopyMemory(Buffer, (PVOID)DISKREADBUFFER, SectorCount * DiskGeometry.BytesPerSector);
561 //return ReturnValue;
562
563 return CacheReadDiskSectors(DriveNumber, SectorNumber + Ext2VolumeStartSector, SectorCount, Buffer);
564 }
565
566 BOOL Ext2ReadSuperBlock(VOID)
567 {
568
569 DbgPrint((DPRINT_FILESYSTEM, "Ext2ReadSuperBlock()\n"));
570
571 //
572 // Free any memory previously allocated
573 //
574 if (Ext2SuperBlock != NULL)
575 {
576 MmFreeMemory(Ext2SuperBlock);
577
578 Ext2SuperBlock = NULL;
579 }
580
581 //
582 // Now allocate the memory to hold the super block
583 //
584 Ext2SuperBlock = (PEXT2_SUPER_BLOCK)MmAllocateMemory(1024);
585
586 //
587 // Make sure we got the memory
588 //
589 if (Ext2SuperBlock == NULL)
590 {
591 FileSystemError("Out of memory.");
592 return FALSE;
593 }
594
595 // Now try to read the super block
596 // If this fails then abort
597 if (!MachDiskReadLogicalSectors(Ext2DriveNumber, Ext2VolumeStartSector, 8, (PVOID)DISKREADBUFFER))
598 {
599 return FALSE;
600 }
601 RtlCopyMemory(Ext2SuperBlock, (PVOID)(DISKREADBUFFER + 1024), 1024);
602
603 DbgPrint((DPRINT_FILESYSTEM, "Dumping super block:\n"));
604
605 DbgPrint((DPRINT_FILESYSTEM, "s_inodes_count: %d\n", Ext2SuperBlock->s_inodes_count));
606 DbgPrint((DPRINT_FILESYSTEM, "s_blocks_count: %d\n", Ext2SuperBlock->s_blocks_count));
607 DbgPrint((DPRINT_FILESYSTEM, "s_r_blocks_count: %d\n", Ext2SuperBlock->s_r_blocks_count));
608 DbgPrint((DPRINT_FILESYSTEM, "s_free_blocks_count: %d\n", Ext2SuperBlock->s_free_blocks_count));
609 DbgPrint((DPRINT_FILESYSTEM, "s_free_inodes_count: %d\n", Ext2SuperBlock->s_free_inodes_count));
610 DbgPrint((DPRINT_FILESYSTEM, "s_first_data_block: %d\n", Ext2SuperBlock->s_first_data_block));
611 DbgPrint((DPRINT_FILESYSTEM, "s_log_block_size: %d\n", Ext2SuperBlock->s_log_block_size));
612 DbgPrint((DPRINT_FILESYSTEM, "s_log_frag_size: %d\n", Ext2SuperBlock->s_log_frag_size));
613 DbgPrint((DPRINT_FILESYSTEM, "s_blocks_per_group: %d\n", Ext2SuperBlock->s_blocks_per_group));
614 DbgPrint((DPRINT_FILESYSTEM, "s_frags_per_group: %d\n", Ext2SuperBlock->s_frags_per_group));
615 DbgPrint((DPRINT_FILESYSTEM, "s_inodes_per_group: %d\n", Ext2SuperBlock->s_inodes_per_group));
616 DbgPrint((DPRINT_FILESYSTEM, "s_mtime: %d\n", Ext2SuperBlock->s_mtime));
617 DbgPrint((DPRINT_FILESYSTEM, "s_wtime: %d\n", Ext2SuperBlock->s_wtime));
618 DbgPrint((DPRINT_FILESYSTEM, "s_mnt_count: %d\n", Ext2SuperBlock->s_mnt_count));
619 DbgPrint((DPRINT_FILESYSTEM, "s_max_mnt_count: %d\n", Ext2SuperBlock->s_max_mnt_count));
620 DbgPrint((DPRINT_FILESYSTEM, "s_magic: 0x%x\n", Ext2SuperBlock->s_magic));
621 DbgPrint((DPRINT_FILESYSTEM, "s_state: %d\n", Ext2SuperBlock->s_state));
622 DbgPrint((DPRINT_FILESYSTEM, "s_errors: %d\n", Ext2SuperBlock->s_errors));
623 DbgPrint((DPRINT_FILESYSTEM, "s_minor_rev_level: %d\n", Ext2SuperBlock->s_minor_rev_level));
624 DbgPrint((DPRINT_FILESYSTEM, "s_lastcheck: %d\n", Ext2SuperBlock->s_lastcheck));
625 DbgPrint((DPRINT_FILESYSTEM, "s_checkinterval: %d\n", Ext2SuperBlock->s_checkinterval));
626 DbgPrint((DPRINT_FILESYSTEM, "s_creator_os: %d\n", Ext2SuperBlock->s_creator_os));
627 DbgPrint((DPRINT_FILESYSTEM, "s_rev_level: %d\n", Ext2SuperBlock->s_rev_level));
628 DbgPrint((DPRINT_FILESYSTEM, "s_def_resuid: %d\n", Ext2SuperBlock->s_def_resuid));
629 DbgPrint((DPRINT_FILESYSTEM, "s_def_resgid: %d\n", Ext2SuperBlock->s_def_resgid));
630 DbgPrint((DPRINT_FILESYSTEM, "s_first_ino: %d\n", Ext2SuperBlock->s_first_ino));
631 DbgPrint((DPRINT_FILESYSTEM, "s_inode_size: %d\n", Ext2SuperBlock->s_inode_size));
632 DbgPrint((DPRINT_FILESYSTEM, "s_block_group_nr: %d\n", Ext2SuperBlock->s_block_group_nr));
633 DbgPrint((DPRINT_FILESYSTEM, "s_feature_compat: 0x%x\n", Ext2SuperBlock->s_feature_compat));
634 DbgPrint((DPRINT_FILESYSTEM, "s_feature_incompat: 0x%x\n", Ext2SuperBlock->s_feature_incompat));
635 DbgPrint((DPRINT_FILESYSTEM, "s_feature_ro_compat: 0x%x\n", Ext2SuperBlock->s_feature_ro_compat));
636 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]));
637 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]));
638 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],
639 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],
640 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],
641 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],
642 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],
643 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],
644 Ext2SuperBlock->s_last_mounted[60], Ext2SuperBlock->s_last_mounted[61], Ext2SuperBlock->s_last_mounted[62], Ext2SuperBlock->s_last_mounted[63]));
645 DbgPrint((DPRINT_FILESYSTEM, "s_algorithm_usage_bitmap = 0x%x\n", Ext2SuperBlock->s_algorithm_usage_bitmap));
646 DbgPrint((DPRINT_FILESYSTEM, "s_prealloc_blocks = %d\n", Ext2SuperBlock->s_prealloc_blocks));
647 DbgPrint((DPRINT_FILESYSTEM, "s_prealloc_dir_blocks = %d\n", Ext2SuperBlock->s_prealloc_dir_blocks));
648 DbgPrint((DPRINT_FILESYSTEM, "s_padding1 = %d\n", Ext2SuperBlock->s_padding1));
649 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]));
650 DbgPrint((DPRINT_FILESYSTEM, "s_journal_inum = %d\n", Ext2SuperBlock->s_journal_inum));
651 DbgPrint((DPRINT_FILESYSTEM, "s_journal_dev = %d\n", Ext2SuperBlock->s_journal_dev));
652 DbgPrint((DPRINT_FILESYSTEM, "s_last_orphan = %d\n", Ext2SuperBlock->s_last_orphan));
653
654 //
655 // Check the super block magic
656 //
657 if (Ext2SuperBlock->s_magic != EXT3_SUPER_MAGIC)
658 {
659 FileSystemError("Invalid super block magic (0xef53)");
660 return FALSE;
661 }
662
663 //
664 // Check the revision level
665 //
666 if (Ext2SuperBlock->s_rev_level > EXT3_DYNAMIC_REV)
667 {
668 FileSystemError("FreeLoader does not understand the revision of this EXT2/EXT3 filesystem.\nPlease update FreeLoader.");
669 return FALSE;
670 }
671
672 //
673 // Check the feature set
674 // Don't need to check the compatible or read-only compatible features
675 // because we only mount the filesystem as read-only
676 //
677 if ((Ext2SuperBlock->s_rev_level >= EXT3_DYNAMIC_REV) &&
678 (/*((Ext2SuperBlock->s_feature_compat & ~EXT3_FEATURE_COMPAT_SUPP) != 0) ||*/
679 /*((Ext2SuperBlock->s_feature_ro_compat & ~EXT3_FEATURE_RO_COMPAT_SUPP) != 0) ||*/
680 ((Ext2SuperBlock->s_feature_incompat & ~EXT3_FEATURE_INCOMPAT_SUPP) != 0)))
681 {
682 FileSystemError("FreeLoader does not understand features of this EXT2/EXT3 filesystem.\nPlease update FreeLoader.");
683 return FALSE;
684 }
685
686 // Calculate the group count
687 Ext2GroupCount = (Ext2SuperBlock->s_blocks_count - Ext2SuperBlock->s_first_data_block + Ext2SuperBlock->s_blocks_per_group - 1) / Ext2SuperBlock->s_blocks_per_group;
688 DbgPrint((DPRINT_FILESYSTEM, "Ext2GroupCount: %d\n", Ext2GroupCount));
689
690 // Calculate the block size
691 Ext2BlockSizeInBytes = 1024 << Ext2SuperBlock->s_log_block_size;
692 Ext2BlockSizeInSectors = Ext2BlockSizeInBytes / Ext2DiskGeometry.BytesPerSector;
693 DbgPrint((DPRINT_FILESYSTEM, "Ext2BlockSizeInBytes: %d\n", Ext2BlockSizeInBytes));
694 DbgPrint((DPRINT_FILESYSTEM, "Ext2BlockSizeInSectors: %d\n", Ext2BlockSizeInSectors));
695
696 // Calculate the fragment size
697 if (Ext2SuperBlock->s_log_frag_size >= 0)
698 {
699 Ext2FragmentSizeInBytes = 1024 << Ext2SuperBlock->s_log_frag_size;
700 }
701 else
702 {
703 Ext2FragmentSizeInBytes = 1024 >> -(Ext2SuperBlock->s_log_frag_size);
704 }
705 Ext2FragmentSizeInSectors = Ext2FragmentSizeInBytes / Ext2DiskGeometry.BytesPerSector;
706 DbgPrint((DPRINT_FILESYSTEM, "Ext2FragmentSizeInBytes: %d\n", Ext2FragmentSizeInBytes));
707 DbgPrint((DPRINT_FILESYSTEM, "Ext2FragmentSizeInSectors: %d\n", Ext2FragmentSizeInSectors));
708
709 // Verify that the fragment size and the block size are equal
710 if (Ext2BlockSizeInBytes != Ext2FragmentSizeInBytes)
711 {
712 FileSystemError("The fragment size must be equal to the block size.");
713 return FALSE;
714 }
715
716 // Calculate the number of inodes in one block
717 Ext2InodesPerBlock = Ext2BlockSizeInBytes / EXT3_INODE_SIZE(Ext2SuperBlock);
718 DbgPrint((DPRINT_FILESYSTEM, "Ext2InodesPerBlock: %d\n", Ext2InodesPerBlock));
719
720 // Calculate the number of group descriptors in one block
721 Ext2GroupDescPerBlock = EXT3_DESC_PER_BLOCK(Ext2SuperBlock);
722 DbgPrint((DPRINT_FILESYSTEM, "Ext2GroupDescPerBlock: %d\n", Ext2GroupDescPerBlock));
723
724 return TRUE;
725 }
726
727 BOOL Ext2ReadGroupDescriptors(VOID)
728 {
729 ULONG GroupDescBlockCount;
730 ULONG CurrentGroupDescBlock;
731
732 DbgPrint((DPRINT_FILESYSTEM, "Ext2ReadGroupDescriptors()\n"));
733
734 //
735 // Free any memory previously allocated
736 //
737 if (Ext2GroupDescriptors != NULL)
738 {
739 MmFreeMemory(Ext2GroupDescriptors);
740
741 Ext2GroupDescriptors = NULL;
742 }
743
744 //
745 // Now allocate the memory to hold the group descriptors
746 //
747 GroupDescBlockCount = ROUND_UP(Ext2GroupCount, Ext2GroupDescPerBlock) / Ext2GroupDescPerBlock;
748 Ext2GroupDescriptors = (PEXT2_GROUP_DESC)MmAllocateMemory(GroupDescBlockCount * Ext2BlockSizeInBytes);
749
750 //
751 // Make sure we got the memory
752 //
753 if (Ext2GroupDescriptors == NULL)
754 {
755 FileSystemError("Out of memory.");
756 return FALSE;
757 }
758
759 // Now read the group descriptors
760 for (CurrentGroupDescBlock=0; CurrentGroupDescBlock<GroupDescBlockCount; CurrentGroupDescBlock++)
761 {
762 if (!Ext2ReadBlock(Ext2SuperBlock->s_first_data_block + 1 + CurrentGroupDescBlock, (PVOID)FILESYSBUFFER))
763 {
764 return FALSE;
765 }
766
767 RtlCopyMemory((Ext2GroupDescriptors + (CurrentGroupDescBlock * Ext2BlockSizeInBytes)), (PVOID)FILESYSBUFFER, Ext2BlockSizeInBytes);
768 }
769
770 return TRUE;
771 }
772
773 BOOL Ext2ReadDirectory(ULONG Inode, PVOID* DirectoryBuffer, PEXT2_INODE InodePointer)
774 {
775 EXT2_FILE_INFO DirectoryFileInfo;
776
777 DbgPrint((DPRINT_FILESYSTEM, "Ext2ReadDirectory() Inode = %d\n", Inode));
778
779 // Read the directory inode
780 if (!Ext2ReadInode(Inode, InodePointer))
781 {
782 return FALSE;
783 }
784
785 // Make sure it is a directory inode
786 if ((InodePointer->i_mode & EXT2_S_IFMT) != EXT2_S_IFDIR)
787 {
788 FileSystemError("Inode is not a directory.");
789 return FALSE;
790 }
791
792 // Fill in file info struct so we can call Ext2ReadFile()
793 RtlZeroMemory(&DirectoryFileInfo, sizeof(EXT2_FILE_INFO));
794 DirectoryFileInfo.DriveNumber = Ext2DriveNumber;
795 DirectoryFileInfo.FileBlockList = Ext2ReadBlockPointerList(InodePointer);
796 DirectoryFileInfo.FilePointer = 0;
797 DirectoryFileInfo.FileSize = Ext2GetInodeFileSize(InodePointer);
798
799 if (DirectoryFileInfo.FileBlockList == NULL)
800 {
801 return FALSE;
802 }
803
804 //
805 // Now allocate the memory to hold the group descriptors
806 //
807 *DirectoryBuffer = (PEXT2_DIR_ENTRY)MmAllocateMemory(DirectoryFileInfo.FileSize);
808
809 //
810 // Make sure we got the memory
811 //
812 if (*DirectoryBuffer == NULL)
813 {
814 MmFreeMemory(DirectoryFileInfo.FileBlockList);
815 FileSystemError("Out of memory.");
816 return FALSE;
817 }
818
819 // Now read the root directory data
820 if (!Ext2ReadFile(&DirectoryFileInfo, DirectoryFileInfo.FileSize, NULL, *DirectoryBuffer))
821 {
822 MmFreeMemory(*DirectoryBuffer);
823 *DirectoryBuffer = NULL;
824 MmFreeMemory(DirectoryFileInfo.FileBlockList);
825 return FALSE;
826 }
827
828 MmFreeMemory(DirectoryFileInfo.FileBlockList);
829 return TRUE;
830 }
831
832 BOOL Ext2ReadBlock(ULONG BlockNumber, PVOID Buffer)
833 {
834 CHAR ErrorString[80];
835
836 DbgPrint((DPRINT_FILESYSTEM, "Ext2ReadBlock() BlockNumber = %d Buffer = 0x%x\n", BlockNumber, Buffer));
837
838 // Make sure its a valid block
839 if (BlockNumber > Ext2SuperBlock->s_blocks_count)
840 {
841 sprintf(ErrorString, "Error reading block %d - block out of range.", (int) BlockNumber);
842 FileSystemError(ErrorString);
843 return FALSE;
844 }
845
846 // Check to see if this is a sparse block
847 if (BlockNumber == 0)
848 {
849 DbgPrint((DPRINT_FILESYSTEM, "Block is part of a sparse file. Zeroing input buffer.\n"));
850
851 RtlZeroMemory(Buffer, Ext2BlockSizeInBytes);
852
853 return TRUE;
854 }
855
856 return Ext2ReadVolumeSectors(Ext2DriveNumber, (ULONGLONG)BlockNumber * Ext2BlockSizeInSectors, Ext2BlockSizeInSectors, Buffer);
857 }
858
859 /*
860 * Ext2ReadPartialBlock()
861 * Reads part of a block into memory
862 */
863 BOOL Ext2ReadPartialBlock(ULONG BlockNumber, ULONG StartingOffset, ULONG Length, PVOID Buffer)
864 {
865
866 DbgPrint((DPRINT_FILESYSTEM, "Ext2ReadPartialBlock() BlockNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", BlockNumber, StartingOffset, Length, Buffer));
867
868 if (!Ext2ReadBlock(BlockNumber, (PVOID)FILESYSBUFFER))
869 {
870 return FALSE;
871 }
872
873 memcpy(Buffer, (PVOID)((ULONG_PTR)FILESYSBUFFER + StartingOffset), Length);
874
875 return TRUE;
876 }
877
878 ULONG Ext2GetGroupDescBlockNumber(ULONG Group)
879 {
880 return (((Group * sizeof(EXT2_GROUP_DESC)) / Ext2GroupDescPerBlock) + Ext2SuperBlock->s_first_data_block + 1);
881 }
882
883 ULONG Ext2GetGroupDescOffsetInBlock(ULONG Group)
884 {
885 return ((Group * sizeof(EXT2_GROUP_DESC)) % Ext2GroupDescPerBlock);
886 }
887
888 ULONG Ext2GetInodeGroupNumber(ULONG Inode)
889 {
890 return ((Inode - 1) / Ext2SuperBlock->s_inodes_per_group);
891 }
892
893 ULONG Ext2GetInodeBlockNumber(ULONG Inode)
894 {
895 return (((Inode - 1) % Ext2SuperBlock->s_inodes_per_group) / Ext2InodesPerBlock);
896 }
897
898 ULONG Ext2GetInodeOffsetInBlock(ULONG Inode)
899 {
900 return (((Inode - 1) % Ext2SuperBlock->s_inodes_per_group) % Ext2InodesPerBlock);
901 }
902
903 BOOL Ext2ReadInode(ULONG Inode, PEXT2_INODE InodeBuffer)
904 {
905 ULONG InodeGroupNumber;
906 ULONG InodeBlockNumber;
907 ULONG InodeOffsetInBlock;
908 CHAR ErrorString[80];
909 EXT2_GROUP_DESC GroupDescriptor;
910
911 DbgPrint((DPRINT_FILESYSTEM, "Ext2ReadInode() Inode = %d\n", Inode));
912
913 // Make sure its a valid inode
914 if ((Inode < 1) || (Inode > Ext2SuperBlock->s_inodes_count))
915 {
916 sprintf(ErrorString, "Error reading inode %ld - inode out of range.", Inode);
917 FileSystemError(ErrorString);
918 return FALSE;
919 }
920
921 // Get inode group & block number and offset in block
922 InodeGroupNumber = Ext2GetInodeGroupNumber(Inode);
923 InodeBlockNumber = Ext2GetInodeBlockNumber(Inode);
924 InodeOffsetInBlock = Ext2GetInodeOffsetInBlock(Inode);
925 DbgPrint((DPRINT_FILESYSTEM, "InodeGroupNumber = %d\n", InodeGroupNumber));
926 DbgPrint((DPRINT_FILESYSTEM, "InodeBlockNumber = %d\n", InodeBlockNumber));
927 DbgPrint((DPRINT_FILESYSTEM, "InodeOffsetInBlock = %d\n", InodeOffsetInBlock));
928
929 // Read the group descriptor
930 if (!Ext2ReadGroupDescriptor(InodeGroupNumber, &GroupDescriptor))
931 {
932 return FALSE;
933 }
934
935 // Add the start block of the inode table to the inode block number
936 InodeBlockNumber += GroupDescriptor.bg_inode_table;
937 DbgPrint((DPRINT_FILESYSTEM, "InodeBlockNumber (after group desc correction) = %d\n", InodeBlockNumber));
938
939 // Read the block
940 if (!Ext2ReadBlock(InodeBlockNumber, (PVOID)FILESYSBUFFER))
941 {
942 return FALSE;
943 }
944
945 // Copy the data to their buffer
946 RtlCopyMemory(InodeBuffer, (PVOID)(FILESYSBUFFER + (InodeOffsetInBlock * EXT3_INODE_SIZE(Ext2SuperBlock))), sizeof(EXT2_INODE));
947
948 DbgPrint((DPRINT_FILESYSTEM, "Dumping inode information:\n"));
949 DbgPrint((DPRINT_FILESYSTEM, "i_mode = 0x%x\n", InodeBuffer->i_mode));
950 DbgPrint((DPRINT_FILESYSTEM, "i_uid = %d\n", InodeBuffer->i_uid));
951 DbgPrint((DPRINT_FILESYSTEM, "i_size = %d\n", InodeBuffer->i_size));
952 DbgPrint((DPRINT_FILESYSTEM, "i_atime = %d\n", InodeBuffer->i_atime));
953 DbgPrint((DPRINT_FILESYSTEM, "i_ctime = %d\n", InodeBuffer->i_ctime));
954 DbgPrint((DPRINT_FILESYSTEM, "i_mtime = %d\n", InodeBuffer->i_mtime));
955 DbgPrint((DPRINT_FILESYSTEM, "i_dtime = %d\n", InodeBuffer->i_dtime));
956 DbgPrint((DPRINT_FILESYSTEM, "i_gid = %d\n", InodeBuffer->i_gid));
957 DbgPrint((DPRINT_FILESYSTEM, "i_links_count = %d\n", InodeBuffer->i_links_count));
958 DbgPrint((DPRINT_FILESYSTEM, "i_blocks = %d\n", InodeBuffer->i_blocks));
959 DbgPrint((DPRINT_FILESYSTEM, "i_flags = 0x%x\n", InodeBuffer->i_flags));
960 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]));
961 DbgPrint((DPRINT_FILESYSTEM, "i_generation = %d\n", InodeBuffer->i_generation));
962 DbgPrint((DPRINT_FILESYSTEM, "i_file_acl = %d\n", InodeBuffer->i_file_acl));
963 DbgPrint((DPRINT_FILESYSTEM, "i_dir_acl = %d\n", InodeBuffer->i_dir_acl));
964 DbgPrint((DPRINT_FILESYSTEM, "i_faddr = %d\n", InodeBuffer->i_faddr));
965 DbgPrint((DPRINT_FILESYSTEM, "l_i_frag = %d\n", InodeBuffer->osd2.linux2.l_i_frag));
966 DbgPrint((DPRINT_FILESYSTEM, "l_i_fsize = %d\n", InodeBuffer->osd2.linux2.l_i_fsize));
967 DbgPrint((DPRINT_FILESYSTEM, "l_i_uid_high = %d\n", InodeBuffer->osd2.linux2.l_i_uid_high));
968 DbgPrint((DPRINT_FILESYSTEM, "l_i_gid_high = %d\n", InodeBuffer->osd2.linux2.l_i_gid_high));
969
970 return TRUE;
971 }
972
973 BOOL Ext2ReadGroupDescriptor(ULONG Group, PEXT2_GROUP_DESC GroupBuffer)
974 {
975 DbgPrint((DPRINT_FILESYSTEM, "Ext2ReadGroupDescriptor()\n"));
976
977 /*if (!Ext2ReadBlock(Ext2GetGroupDescBlockNumber(Group), (PVOID)FILESYSBUFFER))
978 {
979 return FALSE;
980 }
981
982 RtlCopyMemory(GroupBuffer, (PVOID)(FILESYSBUFFER + Ext2GetGroupDescOffsetInBlock(Group)), sizeof(EXT2_GROUP_DESC));*/
983
984 RtlCopyMemory(GroupBuffer, &Ext2GroupDescriptors[Group], sizeof(EXT2_GROUP_DESC));
985
986 DbgPrint((DPRINT_FILESYSTEM, "Dumping group descriptor:\n"));
987 DbgPrint((DPRINT_FILESYSTEM, "bg_block_bitmap = %d\n", GroupBuffer->bg_block_bitmap));
988 DbgPrint((DPRINT_FILESYSTEM, "bg_inode_bitmap = %d\n", GroupBuffer->bg_inode_bitmap));
989 DbgPrint((DPRINT_FILESYSTEM, "bg_inode_table = %d\n", GroupBuffer->bg_inode_table));
990 DbgPrint((DPRINT_FILESYSTEM, "bg_free_blocks_count = %d\n", GroupBuffer->bg_free_blocks_count));
991 DbgPrint((DPRINT_FILESYSTEM, "bg_free_inodes_count = %d\n", GroupBuffer->bg_free_inodes_count));
992 DbgPrint((DPRINT_FILESYSTEM, "bg_used_dirs_count = %d\n", GroupBuffer->bg_used_dirs_count));
993
994 return TRUE;
995 }
996
997 ULONG* Ext2ReadBlockPointerList(PEXT2_INODE Inode)
998 {
999 ULONGLONG FileSize;
1000 ULONG BlockCount;
1001 ULONG* BlockList;
1002 ULONG CurrentBlockInList;
1003 ULONG CurrentBlock;
1004
1005 DbgPrint((DPRINT_FILESYSTEM, "Ext2ReadBlockPointerList()\n"));
1006
1007 // Get the number of blocks this file occupies
1008 // I would just use Inode->i_blocks but it
1009 // doesn't seem to be the number of blocks
1010 // the file size corresponds to, but instead
1011 // it is much bigger.
1012 //BlockCount = Inode->i_blocks;
1013 FileSize = Ext2GetInodeFileSize(Inode);
1014 FileSize = ROUND_UP(FileSize, Ext2BlockSizeInBytes);
1015 BlockCount = (FileSize / Ext2BlockSizeInBytes);
1016
1017 // Allocate the memory for the block list
1018 BlockList = MmAllocateMemory(BlockCount * sizeof(ULONG));
1019 if (BlockList == NULL)
1020 {
1021 return NULL;
1022 }
1023
1024 RtlZeroMemory(BlockList, BlockCount * sizeof(ULONG));
1025 CurrentBlockInList = 0;
1026
1027 // Copy the direct block pointers
1028 for (CurrentBlock=0; CurrentBlockInList<BlockCount && CurrentBlock<EXT3_NDIR_BLOCKS; CurrentBlock++)
1029 {
1030 BlockList[CurrentBlockInList] = Inode->i_block[CurrentBlock];
1031 CurrentBlockInList++;
1032 }
1033
1034 // Copy the indirect block pointers
1035 if (CurrentBlockInList < BlockCount)
1036 {
1037 if (!Ext2CopyIndirectBlockPointers(BlockList, &CurrentBlockInList, BlockCount, Inode->i_block[EXT3_IND_BLOCK]))
1038 {
1039 MmFreeMemory(BlockList);
1040 return FALSE;
1041 }
1042 }
1043
1044 // Copy the double indirect block pointers
1045 if (CurrentBlockInList < BlockCount)
1046 {
1047 if (!Ext2CopyDoubleIndirectBlockPointers(BlockList, &CurrentBlockInList, BlockCount, Inode->i_block[EXT3_DIND_BLOCK]))
1048 {
1049 MmFreeMemory(BlockList);
1050 return FALSE;
1051 }
1052 }
1053
1054 // Copy the triple indirect block pointers
1055 if (CurrentBlockInList < BlockCount)
1056 {
1057 if (!Ext2CopyTripleIndirectBlockPointers(BlockList, &CurrentBlockInList, BlockCount, Inode->i_block[EXT3_TIND_BLOCK]))
1058 {
1059 MmFreeMemory(BlockList);
1060 return FALSE;
1061 }
1062 }
1063
1064 return BlockList;
1065 }
1066
1067 ULONGLONG Ext2GetInodeFileSize(PEXT2_INODE Inode)
1068 {
1069 if ((Inode->i_mode & EXT2_S_IFMT) == EXT2_S_IFDIR)
1070 {
1071 return (ULONGLONG)(Inode->i_size);
1072 }
1073 else
1074 {
1075 return ((ULONGLONG)(Inode->i_size) | ((ULONGLONG)(Inode->i_dir_acl) << 32));
1076 }
1077 }
1078
1079 BOOL Ext2CopyIndirectBlockPointers(ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG IndirectBlock)
1080 {
1081 ULONG* BlockBuffer = (ULONG*)FILESYSBUFFER;
1082 ULONG CurrentBlock;
1083 ULONG BlockPointersPerBlock;
1084
1085 DbgPrint((DPRINT_FILESYSTEM, "Ext2CopyIndirectBlockPointers() BlockCount = %d\n", BlockCount));
1086
1087 BlockPointersPerBlock = Ext2BlockSizeInBytes / sizeof(ULONG);
1088
1089 if (!Ext2ReadBlock(IndirectBlock, BlockBuffer))
1090 {
1091 return FALSE;
1092 }
1093
1094 for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++)
1095 {
1096 BlockList[(*CurrentBlockInList)] = BlockBuffer[CurrentBlock];
1097 (*CurrentBlockInList)++;
1098 }
1099
1100 return TRUE;
1101 }
1102
1103 BOOL Ext2CopyDoubleIndirectBlockPointers(ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG DoubleIndirectBlock)
1104 {
1105 ULONG* BlockBuffer;
1106 ULONG CurrentBlock;
1107 ULONG BlockPointersPerBlock;
1108
1109 DbgPrint((DPRINT_FILESYSTEM, "Ext2CopyDoubleIndirectBlockPointers() BlockCount = %d\n", BlockCount));
1110
1111 BlockPointersPerBlock = Ext2BlockSizeInBytes / sizeof(ULONG);
1112
1113 BlockBuffer = (ULONG*)MmAllocateMemory(Ext2BlockSizeInBytes);
1114 if (BlockBuffer == NULL)
1115 {
1116 return FALSE;
1117 }
1118
1119 if (!Ext2ReadBlock(DoubleIndirectBlock, BlockBuffer))
1120 {
1121 MmFreeMemory(BlockBuffer);
1122 return FALSE;
1123 }
1124
1125 for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++)
1126 {
1127 if (!Ext2CopyIndirectBlockPointers(BlockList, CurrentBlockInList, BlockCount, BlockBuffer[CurrentBlock]))
1128 {
1129 MmFreeMemory(BlockBuffer);
1130 return FALSE;
1131 }
1132 }
1133
1134 MmFreeMemory(BlockBuffer);
1135 return TRUE;
1136 }
1137
1138 BOOL Ext2CopyTripleIndirectBlockPointers(ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG TripleIndirectBlock)
1139 {
1140 ULONG* BlockBuffer;
1141 ULONG CurrentBlock;
1142 ULONG BlockPointersPerBlock;
1143
1144 DbgPrint((DPRINT_FILESYSTEM, "Ext2CopyTripleIndirectBlockPointers() BlockCount = %d\n", BlockCount));
1145
1146 BlockPointersPerBlock = Ext2BlockSizeInBytes / sizeof(ULONG);
1147
1148 BlockBuffer = (ULONG*)MmAllocateMemory(Ext2BlockSizeInBytes);
1149 if (BlockBuffer == NULL)
1150 {
1151 return FALSE;
1152 }
1153
1154 if (!Ext2ReadBlock(TripleIndirectBlock, BlockBuffer))
1155 {
1156 MmFreeMemory(BlockBuffer);
1157 return FALSE;
1158 }
1159
1160 for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++)
1161 {
1162 if (!Ext2CopyDoubleIndirectBlockPointers(BlockList, CurrentBlockInList, BlockCount, BlockBuffer[CurrentBlock]))
1163 {
1164 MmFreeMemory(BlockBuffer);
1165 return FALSE;
1166 }
1167 }
1168
1169 MmFreeMemory(BlockBuffer);
1170 return TRUE;
1171 }