forgot this one: a stubbed out loader.c copied from i386
[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 #include <debug.h>
22
23 GEOMETRY Ext2DiskGeometry; // Ext2 file system disk geometry
24
25 PEXT2_SUPER_BLOCK Ext2SuperBlock = NULL; // Ext2 file system super block
26 PEXT2_GROUP_DESC Ext2GroupDescriptors = NULL; // Ext2 file system group descriptors
27
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
37
38 BOOLEAN Ext2OpenVolume(UCHAR DriveNumber, ULONGLONG VolumeStartSector, ULONGLONG PartitionSectorCount)
39 {
40
41 DbgPrint((DPRINT_FILESYSTEM, "Ext2OpenVolume() DriveNumber = 0x%x VolumeStartSector = %d\n", DriveNumber, VolumeStartSector));
42
43 // Store the drive number and start sector
44 Ext2DriveNumber = DriveNumber;
45 Ext2VolumeStartSector = VolumeStartSector;
46
47 if (!MachDiskGetDriveGeometry(DriveNumber, &Ext2DiskGeometry))
48 {
49 return FALSE;
50 }
51
52 //
53 // Initialize the disk cache for this drive
54 //
55 if (!CacheInitializeDrive(DriveNumber))
56 {
57 return FALSE;
58 }
59
60 // Read in the super block
61 if (!Ext2ReadSuperBlock())
62 {
63 return FALSE;
64 }
65
66 // Read in the group descriptors
67 if (!Ext2ReadGroupDescriptors())
68 {
69 return FALSE;
70 }
71
72 return TRUE;
73 }
74
75 /*
76 * Ext2OpenFile()
77 * Tries to open the file 'name' and returns true or false
78 * for success and failure respectively
79 */
80 FILE* Ext2OpenFile(PCSTR FileName)
81 {
82 EXT2_FILE_INFO TempExt2FileInfo;
83 PEXT2_FILE_INFO FileHandle;
84 CHAR SymLinkPath[EXT3_NAME_LEN];
85 CHAR FullPath[EXT3_NAME_LEN * 2];
86 ULONG Index;
87
88 DbgPrint((DPRINT_FILESYSTEM, "Ext2OpenFile() FileName = %s\n", FileName));
89
90 RtlZeroMemory(SymLinkPath, EXT3_NAME_LEN);
91
92 // Lookup the file in the file system
93 if (!Ext2LookupFile(FileName, &TempExt2FileInfo))
94 {
95 return NULL;
96 }
97
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)
101 {
102 DbgPrint((DPRINT_FILESYSTEM, "File is a symbolic link\n"));
103
104 // Now read in the symbolic link path
105 if (!Ext2ReadFileBig(&TempExt2FileInfo, TempExt2FileInfo.FileSize, NULL, SymLinkPath))
106 {
107 if (TempExt2FileInfo.FileBlockList != NULL)
108 {
109 MmHeapFree(TempExt2FileInfo.FileBlockList);
110 }
111
112 return NULL;
113 }
114
115 DbgPrint((DPRINT_FILESYSTEM, "Symbolic link path = %s\n", SymLinkPath));
116
117 // Get the full path
118 if (SymLinkPath[0] == '/' || SymLinkPath[0] == '\\')
119 {
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]);
124 }
125 else
126 {
127 // Symbolic link is a relative path
128 // Copy the first part of the path
129 strcpy(FullPath, FileName);
130
131 // Remove the last part of the path
132 for (Index=strlen(FullPath); Index>0; )
133 {
134 Index--;
135 if (FullPath[Index] == '/' || FullPath[Index] == '\\')
136 {
137 break;
138 }
139 }
140 FullPath[Index] = '\0';
141
142 // Concatenate the symbolic link
143 strcat(FullPath, Index == 0 ? "" : "/");
144 strcat(FullPath, SymLinkPath);
145 }
146
147 DbgPrint((DPRINT_FILESYSTEM, "Full file path = %s\n", FullPath));
148
149 if (TempExt2FileInfo.FileBlockList != NULL)
150 {
151 MmHeapFree(TempExt2FileInfo.FileBlockList);
152 }
153
154 return Ext2OpenFile(FullPath);
155 }
156 else
157 {
158 FileHandle = MmHeapAlloc(sizeof(EXT2_FILE_INFO));
159
160 if (FileHandle == NULL)
161 {
162 if (TempExt2FileInfo.FileBlockList != NULL)
163 {
164 MmHeapFree(TempExt2FileInfo.FileBlockList);
165 }
166
167 return NULL;
168 }
169
170 RtlCopyMemory(FileHandle, &TempExt2FileInfo, sizeof(EXT2_FILE_INFO));
171
172 return (FILE*)FileHandle;
173 }
174 }
175
176 /*
177 * Ext2LookupFile()
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
182 */
183 BOOLEAN Ext2LookupFile(PCSTR FileName, PEXT2_FILE_INFO Ext2FileInfoPointer)
184 {
185 UINT i;
186 ULONG NumberOfPathParts;
187 CHAR PathPart[261];
188 PVOID DirectoryBuffer;
189 ULONG DirectoryInode = EXT3_ROOT_INO;
190 EXT2_INODE InodeData;
191 EXT2_DIR_ENTRY DirectoryEntry;
192
193 DbgPrint((DPRINT_FILESYSTEM, "Ext2LookupFile() FileName = %s\n", FileName));
194
195 RtlZeroMemory(Ext2FileInfoPointer, sizeof(EXT2_FILE_INFO));
196
197 //
198 // Figure out how many sub-directories we are nested in
199 //
200 NumberOfPathParts = FsGetNumPathParts(FileName);
201
202 //
203 // Loop once for each part
204 //
205 for (i=0; i<NumberOfPathParts; i++)
206 {
207 //
208 // Get first path part
209 //
210 FsGetFirstNameFromPath(PathPart, FileName);
211
212 //
213 // Advance to the next part of the path
214 //
215 for (; (*FileName != '\\') && (*FileName != '/') && (*FileName != '\0'); FileName++)
216 {
217 }
218 FileName++;
219
220 //
221 // Buffer the directory contents
222 //
223 if (!Ext2ReadDirectory(DirectoryInode, &DirectoryBuffer, &InodeData))
224 {
225 return FALSE;
226 }
227
228 //
229 // Search for file name in directory
230 //
231 if (!Ext2SearchDirectoryBufferForFile(DirectoryBuffer, (ULONG)Ext2GetInodeFileSize(&InodeData), PathPart, &DirectoryEntry))
232 {
233 MmHeapFree(DirectoryBuffer);
234 return FALSE;
235 }
236
237 MmHeapFree(DirectoryBuffer);
238
239 DirectoryInode = DirectoryEntry.inode;
240 }
241
242 if (!Ext2ReadInode(DirectoryInode, &InodeData))
243 {
244 return FALSE;
245 }
246
247 if (((InodeData.i_mode & EXT2_S_IFMT) != EXT2_S_IFREG) &&
248 ((InodeData.i_mode & EXT2_S_IFMT) != EXT2_S_IFLNK))
249 {
250 FileSystemError("Inode is not a regular file or symbolic link.");
251 return FALSE;
252 }
253
254 // Set the drive number
255 Ext2FileInfoPointer->DriveNumber = Ext2DriveNumber;
256
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))
262 {
263 Ext2FileInfoPointer->FileBlockList = Ext2ReadBlockPointerList(&InodeData);
264
265 if (Ext2FileInfoPointer->FileBlockList == NULL)
266 {
267 return FALSE;
268 }
269 }
270 else
271 {
272 Ext2FileInfoPointer->FileBlockList = NULL;
273 }
274
275 Ext2FileInfoPointer->FilePointer = 0;
276 Ext2FileInfoPointer->FileSize = Ext2GetInodeFileSize(&InodeData);
277 RtlCopyMemory(&Ext2FileInfoPointer->Inode, &InodeData, sizeof(EXT2_INODE));
278
279 return TRUE;
280 }
281
282 BOOLEAN Ext2SearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PEXT2_DIR_ENTRY DirectoryEntry)
283 {
284 ULONG CurrentOffset;
285 PEXT2_DIR_ENTRY CurrentDirectoryEntry;
286
287 DbgPrint((DPRINT_FILESYSTEM, "Ext2SearchDirectoryBufferForFile() DirectoryBuffer = 0x%x DirectorySize = %d FileName = %s\n", DirectoryBuffer, DirectorySize, FileName));
288
289 for (CurrentOffset=0; CurrentOffset<DirectorySize; )
290 {
291 CurrentDirectoryEntry = (PEXT2_DIR_ENTRY)((ULONG_PTR)DirectoryBuffer + CurrentOffset);
292
293 if (CurrentDirectoryEntry->rec_len == 0)
294 {
295 break;
296 }
297
298 if ((CurrentDirectoryEntry->rec_len + CurrentOffset) > DirectorySize)
299 {
300 FileSystemError("Directory entry extends past end of directory file.");
301 return FALSE;
302 }
303
304 DbgPrint((DPRINT_FILESYSTEM, "Dumping directory entry at offset %d:\n", CurrentOffset));
305 DbgDumpBuffer(DPRINT_FILESYSTEM, CurrentDirectoryEntry, CurrentDirectoryEntry->rec_len);
306
307 if ((_strnicmp(FileName, CurrentDirectoryEntry->name, CurrentDirectoryEntry->name_len) == 0) &&
308 (strlen(FileName) == CurrentDirectoryEntry->name_len))
309 {
310 RtlCopyMemory(DirectoryEntry, CurrentDirectoryEntry, sizeof(EXT2_DIR_ENTRY));
311
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++)
319 {
320 DbgPrint((DPRINT_FILESYSTEM, "%c", DirectoryEntry->name[CurrentOffset]));
321 }
322 DbgPrint((DPRINT_FILESYSTEM, "\n"));
323
324 return TRUE;
325 }
326
327 CurrentOffset += CurrentDirectoryEntry->rec_len;
328 }
329
330 return FALSE;
331 }
332
333 /*
334 * Ext2ReadFileBig()
335 * Reads BytesToRead from open file and
336 * returns the number of bytes read in BytesRead
337 */
338 BOOLEAN Ext2ReadFileBig(FILE *FileHandle, ULONGLONG BytesToRead, ULONGLONG* BytesRead, PVOID Buffer)
339 {
340 PEXT2_FILE_INFO Ext2FileInfo = (PEXT2_FILE_INFO)FileHandle;
341 ULONG BlockNumber;
342 ULONG BlockNumberIndex;
343 ULONG OffsetInBlock;
344 ULONG LengthInBlock;
345 ULONG NumberOfBlocks;
346
347 DbgPrint((DPRINT_FILESYSTEM, "Ext2ReadFileBig() BytesToRead = %d Buffer = 0x%x\n", (ULONG)BytesToRead, Buffer));
348
349 if (BytesRead != NULL)
350 {
351 *BytesRead = 0;
352 }
353
354 // Make sure we have the block pointer list if we need it
355 if (Ext2FileInfo->FileBlockList == NULL)
356 {
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))
361 {
362 FileSystemError("Block pointer list is NULL and file is not a fast symbolic link.");
363 return FALSE;
364 }
365 }
366
367 //
368 // If they are trying to read past the
369 // end of the file then return success
370 // with BytesRead == 0
371 //
372 if (Ext2FileInfo->FilePointer >= Ext2FileInfo->FileSize)
373 {
374 return TRUE;
375 }
376
377 //
378 // If they are trying to read more than there is to read
379 // then adjust the amount to read
380 //
381 if ((Ext2FileInfo->FilePointer + BytesToRead) > Ext2FileInfo->FileSize)
382 {
383 BytesToRead = (Ext2FileInfo->FileSize - Ext2FileInfo->FilePointer);
384 }
385
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))
390 {
391 DbgPrint((DPRINT_FILESYSTEM, "Reading fast symbolic link data\n"));
392
393 // Copy the data from the link
394 RtlCopyMemory(Buffer, (PVOID)((ULONG_PTR)Ext2FileInfo->FilePointer + Ext2FileInfo->Inode.i_block), BytesToRead);
395
396 if (BytesRead != NULL)
397 {
398 *BytesRead = BytesToRead;
399 }
400
401 return TRUE;
402 }
403
404 //
405 // Ok, now we have to perform at most 3 calculations
406 // I'll draw you a picture (using nifty ASCII art):
407 //
408 // CurrentFilePointer -+
409 // |
410 // +----------------+
411 // |
412 // +-----------+-----------+-----------+-----------+
413 // | Block 1 | Block 2 | Block 3 | Block 4 |
414 // +-----------+-----------+-----------+-----------+
415 // | |
416 // +---------------+--------------------+
417 // |
418 // BytesToRead -------+
419 //
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
426 // blocks 2 & 3).
427 // 3 - The last calculation (and read) would read
428 // in the remainder of the data requested out of
429 // the last block.
430 //
431
432 //
433 // Only do the first read if we
434 // aren't aligned on a block boundary
435 //
436 if (Ext2FileInfo->FilePointer % Ext2BlockSizeInBytes)
437 {
438 //
439 // Do the math for our first read
440 //
441 BlockNumberIndex = (Ext2FileInfo->FilePointer / Ext2BlockSizeInBytes);
442 BlockNumber = Ext2FileInfo->FileBlockList[BlockNumberIndex];
443 OffsetInBlock = (Ext2FileInfo->FilePointer % Ext2BlockSizeInBytes);
444 LengthInBlock = (BytesToRead > (Ext2BlockSizeInBytes - OffsetInBlock)) ? (Ext2BlockSizeInBytes - OffsetInBlock) : BytesToRead;
445
446 //
447 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
448 //
449 if (!Ext2ReadPartialBlock(BlockNumber, OffsetInBlock, LengthInBlock, Buffer))
450 {
451 return FALSE;
452 }
453 if (BytesRead != NULL)
454 {
455 *BytesRead += LengthInBlock;
456 }
457 BytesToRead -= LengthInBlock;
458 Ext2FileInfo->FilePointer += LengthInBlock;
459 Buffer = (PVOID)((ULONG_PTR)Buffer + LengthInBlock);
460 }
461
462 //
463 // Do the math for our second read (if any data left)
464 //
465 if (BytesToRead > 0)
466 {
467 //
468 // Determine how many full clusters we need to read
469 //
470 NumberOfBlocks = (BytesToRead / Ext2BlockSizeInBytes);
471
472 while (NumberOfBlocks > 0)
473 {
474 BlockNumberIndex = (Ext2FileInfo->FilePointer / Ext2BlockSizeInBytes);
475 BlockNumber = Ext2FileInfo->FileBlockList[BlockNumberIndex];
476
477 //
478 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
479 //
480 if (!Ext2ReadBlock(BlockNumber, Buffer))
481 {
482 return FALSE;
483 }
484 if (BytesRead != NULL)
485 {
486 *BytesRead += Ext2BlockSizeInBytes;
487 }
488 BytesToRead -= Ext2BlockSizeInBytes;
489 Ext2FileInfo->FilePointer += Ext2BlockSizeInBytes;
490 Buffer = (PVOID)((ULONG_PTR)Buffer + Ext2BlockSizeInBytes);
491 NumberOfBlocks--;
492 }
493 }
494
495 //
496 // Do the math for our third read (if any data left)
497 //
498 if (BytesToRead > 0)
499 {
500 BlockNumberIndex = (Ext2FileInfo->FilePointer / Ext2BlockSizeInBytes);
501 BlockNumber = Ext2FileInfo->FileBlockList[BlockNumberIndex];
502
503 //
504 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
505 //
506 if (!Ext2ReadPartialBlock(BlockNumber, 0, BytesToRead, Buffer))
507 {
508 return FALSE;
509 }
510 if (BytesRead != NULL)
511 {
512 *BytesRead += BytesToRead;
513 }
514 Ext2FileInfo->FilePointer += BytesToRead;
515 BytesToRead -= BytesToRead;
516 Buffer = (PVOID)((ULONG_PTR)Buffer + (ULONG_PTR)BytesToRead);
517 }
518
519 return TRUE;
520 }
521
522 BOOLEAN Ext2ReadFile(FILE *FileHandle, ULONG BytesToRead, ULONG* BytesRead, PVOID Buffer)
523 {
524 BOOLEAN Success;
525 ULONGLONG BytesReadBig;
526
527 Success = Ext2ReadFileBig(FileHandle, BytesToRead, &BytesReadBig, Buffer);
528 *BytesRead = (ULONG)BytesReadBig;
529 return Success;
530 }
531
532 ULONG Ext2GetFileSize(FILE *FileHandle)
533 {
534 PEXT2_FILE_INFO Ext2FileHandle = (PEXT2_FILE_INFO)FileHandle;
535
536 DbgPrint((DPRINT_FILESYSTEM, "Ext2GetFileSize() FileSize = %d\n", Ext2FileHandle->FileSize));
537
538 return Ext2FileHandle->FileSize;
539 }
540
541 VOID Ext2SetFilePointer(FILE *FileHandle, ULONG NewFilePointer)
542 {
543 PEXT2_FILE_INFO Ext2FileHandle = (PEXT2_FILE_INFO)FileHandle;
544
545 DbgPrint((DPRINT_FILESYSTEM, "Ext2SetFilePointer() NewFilePointer = %d\n", NewFilePointer));
546
547 Ext2FileHandle->FilePointer = NewFilePointer;
548 }
549
550 ULONG Ext2GetFilePointer(FILE *FileHandle)
551 {
552 PEXT2_FILE_INFO Ext2FileHandle = (PEXT2_FILE_INFO)FileHandle;
553
554 DbgPrint((DPRINT_FILESYSTEM, "Ext2GetFilePointer() FilePointer = %d\n", Ext2FileHandle->FilePointer));
555
556 return Ext2FileHandle->FilePointer;
557 }
558
559 BOOLEAN Ext2ReadVolumeSectors(UCHAR DriveNumber, ULONGLONG SectorNumber, ULONGLONG SectorCount, PVOID Buffer)
560 {
561 //GEOMETRY DiskGeometry;
562 //BOOLEAN ReturnValue;
563 //if (!DiskGetDriveGeometry(DriveNumber, &DiskGeometry))
564 //{
565 // return FALSE;
566 //}
567 //ReturnValue = MachDiskReadLogicalSectors(DriveNumber, SectorNumber + Ext2VolumeStartSector, SectorCount, (PVOID)DISKREADBUFFER);
568 //RtlCopyMemory(Buffer, (PVOID)DISKREADBUFFER, SectorCount * DiskGeometry.BytesPerSector);
569 //return ReturnValue;
570
571 return CacheReadDiskSectors(DriveNumber, SectorNumber + Ext2VolumeStartSector, SectorCount, Buffer);
572 }
573
574 BOOLEAN Ext2ReadSuperBlock(VOID)
575 {
576
577 DbgPrint((DPRINT_FILESYSTEM, "Ext2ReadSuperBlock()\n"));
578
579 //
580 // Free any memory previously allocated
581 //
582 if (Ext2SuperBlock != NULL)
583 {
584 MmHeapFree(Ext2SuperBlock);
585
586 Ext2SuperBlock = NULL;
587 }
588
589 //
590 // Now allocate the memory to hold the super block
591 //
592 Ext2SuperBlock = (PEXT2_SUPER_BLOCK)MmHeapAlloc(1024);
593
594 //
595 // Make sure we got the memory
596 //
597 if (Ext2SuperBlock == NULL)
598 {
599 FileSystemError("Out of memory.");
600 return FALSE;
601 }
602
603 // Now try to read the super block
604 // If this fails then abort
605 if (!MachDiskReadLogicalSectors(Ext2DriveNumber, Ext2VolumeStartSector, 8, (PVOID)DISKREADBUFFER))
606 {
607 return FALSE;
608 }
609 RtlCopyMemory(Ext2SuperBlock, (PVOID)(DISKREADBUFFER + 1024), 1024);
610
611 DbgPrint((DPRINT_FILESYSTEM, "Dumping super block:\n"));
612
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));
661
662 //
663 // Check the super block magic
664 //
665 if (Ext2SuperBlock->s_magic != EXT3_SUPER_MAGIC)
666 {
667 FileSystemError("Invalid super block magic (0xef53)");
668 return FALSE;
669 }
670
671 //
672 // Check the revision level
673 //
674 if (Ext2SuperBlock->s_rev_level > EXT3_DYNAMIC_REV)
675 {
676 FileSystemError("FreeLoader does not understand the revision of this EXT2/EXT3 filesystem.\nPlease update FreeLoader.");
677 return FALSE;
678 }
679
680 //
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
684 //
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)))
689 {
690 FileSystemError("FreeLoader does not understand features of this EXT2/EXT3 filesystem.\nPlease update FreeLoader.");
691 return FALSE;
692 }
693
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));
697
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));
703
704 // Calculate the fragment size
705 if (Ext2SuperBlock->s_log_frag_size >= 0)
706 {
707 Ext2FragmentSizeInBytes = 1024 << Ext2SuperBlock->s_log_frag_size;
708 }
709 else
710 {
711 Ext2FragmentSizeInBytes = 1024 >> -(Ext2SuperBlock->s_log_frag_size);
712 }
713 Ext2FragmentSizeInSectors = Ext2FragmentSizeInBytes / Ext2DiskGeometry.BytesPerSector;
714 DbgPrint((DPRINT_FILESYSTEM, "Ext2FragmentSizeInBytes: %d\n", Ext2FragmentSizeInBytes));
715 DbgPrint((DPRINT_FILESYSTEM, "Ext2FragmentSizeInSectors: %d\n", Ext2FragmentSizeInSectors));
716
717 // Verify that the fragment size and the block size are equal
718 if (Ext2BlockSizeInBytes != Ext2FragmentSizeInBytes)
719 {
720 FileSystemError("The fragment size must be equal to the block size.");
721 return FALSE;
722 }
723
724 // Calculate the number of inodes in one block
725 Ext2InodesPerBlock = Ext2BlockSizeInBytes / EXT3_INODE_SIZE(Ext2SuperBlock);
726 DbgPrint((DPRINT_FILESYSTEM, "Ext2InodesPerBlock: %d\n", Ext2InodesPerBlock));
727
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));
731
732 return TRUE;
733 }
734
735 BOOLEAN Ext2ReadGroupDescriptors(VOID)
736 {
737 ULONG GroupDescBlockCount;
738 ULONG CurrentGroupDescBlock;
739
740 DbgPrint((DPRINT_FILESYSTEM, "Ext2ReadGroupDescriptors()\n"));
741
742 //
743 // Free any memory previously allocated
744 //
745 if (Ext2GroupDescriptors != NULL)
746 {
747 MmHeapFree(Ext2GroupDescriptors);
748
749 Ext2GroupDescriptors = NULL;
750 }
751
752 //
753 // Now allocate the memory to hold the group descriptors
754 //
755 GroupDescBlockCount = ROUND_UP(Ext2GroupCount, Ext2GroupDescPerBlock) / Ext2GroupDescPerBlock;
756 Ext2GroupDescriptors = (PEXT2_GROUP_DESC)MmHeapAlloc(GroupDescBlockCount * Ext2BlockSizeInBytes);
757
758 //
759 // Make sure we got the memory
760 //
761 if (Ext2GroupDescriptors == NULL)
762 {
763 FileSystemError("Out of memory.");
764 return FALSE;
765 }
766
767 // Now read the group descriptors
768 for (CurrentGroupDescBlock=0; CurrentGroupDescBlock<GroupDescBlockCount; CurrentGroupDescBlock++)
769 {
770 if (!Ext2ReadBlock(Ext2SuperBlock->s_first_data_block + 1 + CurrentGroupDescBlock, (PVOID)FILESYSBUFFER))
771 {
772 return FALSE;
773 }
774
775 RtlCopyMemory((Ext2GroupDescriptors + (CurrentGroupDescBlock * Ext2BlockSizeInBytes)), (PVOID)FILESYSBUFFER, Ext2BlockSizeInBytes);
776 }
777
778 return TRUE;
779 }
780
781 BOOLEAN Ext2ReadDirectory(ULONG Inode, PVOID* DirectoryBuffer, PEXT2_INODE InodePointer)
782 {
783 EXT2_FILE_INFO DirectoryFileInfo;
784
785 DbgPrint((DPRINT_FILESYSTEM, "Ext2ReadDirectory() Inode = %d\n", Inode));
786
787 // Read the directory inode
788 if (!Ext2ReadInode(Inode, InodePointer))
789 {
790 return FALSE;
791 }
792
793 // Make sure it is a directory inode
794 if ((InodePointer->i_mode & EXT2_S_IFMT) != EXT2_S_IFDIR)
795 {
796 FileSystemError("Inode is not a directory.");
797 return FALSE;
798 }
799
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);
806
807 if (DirectoryFileInfo.FileBlockList == NULL)
808 {
809 return FALSE;
810 }
811
812 //
813 // Now allocate the memory to hold the group descriptors
814 //
815 *DirectoryBuffer = (PEXT2_DIR_ENTRY)MmHeapAlloc(DirectoryFileInfo.FileSize);
816
817 //
818 // Make sure we got the memory
819 //
820 if (*DirectoryBuffer == NULL)
821 {
822 MmHeapFree(DirectoryFileInfo.FileBlockList);
823 FileSystemError("Out of memory.");
824 return FALSE;
825 }
826
827 // Now read the root directory data
828 if (!Ext2ReadFileBig(&DirectoryFileInfo, DirectoryFileInfo.FileSize, NULL, *DirectoryBuffer))
829 {
830 MmHeapFree(*DirectoryBuffer);
831 *DirectoryBuffer = NULL;
832 MmHeapFree(DirectoryFileInfo.FileBlockList);
833 return FALSE;
834 }
835
836 MmHeapFree(DirectoryFileInfo.FileBlockList);
837 return TRUE;
838 }
839
840 BOOLEAN Ext2ReadBlock(ULONG BlockNumber, PVOID Buffer)
841 {
842 CHAR ErrorString[80];
843
844 DbgPrint((DPRINT_FILESYSTEM, "Ext2ReadBlock() BlockNumber = %d Buffer = 0x%x\n", BlockNumber, Buffer));
845
846 // Make sure its a valid block
847 if (BlockNumber > Ext2SuperBlock->s_blocks_count)
848 {
849 sprintf(ErrorString, "Error reading block %d - block out of range.", (int) BlockNumber);
850 FileSystemError(ErrorString);
851 return FALSE;
852 }
853
854 // Check to see if this is a sparse block
855 if (BlockNumber == 0)
856 {
857 DbgPrint((DPRINT_FILESYSTEM, "Block is part of a sparse file. Zeroing input buffer.\n"));
858
859 RtlZeroMemory(Buffer, Ext2BlockSizeInBytes);
860
861 return TRUE;
862 }
863
864 return Ext2ReadVolumeSectors(Ext2DriveNumber, (ULONGLONG)BlockNumber * Ext2BlockSizeInSectors, Ext2BlockSizeInSectors, Buffer);
865 }
866
867 /*
868 * Ext2ReadPartialBlock()
869 * Reads part of a block into memory
870 */
871 BOOLEAN Ext2ReadPartialBlock(ULONG BlockNumber, ULONG StartingOffset, ULONG Length, PVOID Buffer)
872 {
873
874 DbgPrint((DPRINT_FILESYSTEM, "Ext2ReadPartialBlock() BlockNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", BlockNumber, StartingOffset, Length, Buffer));
875
876 if (!Ext2ReadBlock(BlockNumber, (PVOID)FILESYSBUFFER))
877 {
878 return FALSE;
879 }
880
881 memcpy(Buffer, (PVOID)((ULONG_PTR)FILESYSBUFFER + StartingOffset), Length);
882
883 return TRUE;
884 }
885
886 ULONG Ext2GetGroupDescBlockNumber(ULONG Group)
887 {
888 return (((Group * sizeof(EXT2_GROUP_DESC)) / Ext2GroupDescPerBlock) + Ext2SuperBlock->s_first_data_block + 1);
889 }
890
891 ULONG Ext2GetGroupDescOffsetInBlock(ULONG Group)
892 {
893 return ((Group * sizeof(EXT2_GROUP_DESC)) % Ext2GroupDescPerBlock);
894 }
895
896 ULONG Ext2GetInodeGroupNumber(ULONG Inode)
897 {
898 return ((Inode - 1) / Ext2SuperBlock->s_inodes_per_group);
899 }
900
901 ULONG Ext2GetInodeBlockNumber(ULONG Inode)
902 {
903 return (((Inode - 1) % Ext2SuperBlock->s_inodes_per_group) / Ext2InodesPerBlock);
904 }
905
906 ULONG Ext2GetInodeOffsetInBlock(ULONG Inode)
907 {
908 return (((Inode - 1) % Ext2SuperBlock->s_inodes_per_group) % Ext2InodesPerBlock);
909 }
910
911 BOOLEAN Ext2ReadInode(ULONG Inode, PEXT2_INODE InodeBuffer)
912 {
913 ULONG InodeGroupNumber;
914 ULONG InodeBlockNumber;
915 ULONG InodeOffsetInBlock;
916 CHAR ErrorString[80];
917 EXT2_GROUP_DESC GroupDescriptor;
918
919 DbgPrint((DPRINT_FILESYSTEM, "Ext2ReadInode() Inode = %d\n", Inode));
920
921 // Make sure its a valid inode
922 if ((Inode < 1) || (Inode > Ext2SuperBlock->s_inodes_count))
923 {
924 sprintf(ErrorString, "Error reading inode %ld - inode out of range.", Inode);
925 FileSystemError(ErrorString);
926 return FALSE;
927 }
928
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));
936
937 // Read the group descriptor
938 if (!Ext2ReadGroupDescriptor(InodeGroupNumber, &GroupDescriptor))
939 {
940 return FALSE;
941 }
942
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));
946
947 // Read the block
948 if (!Ext2ReadBlock(InodeBlockNumber, (PVOID)FILESYSBUFFER))
949 {
950 return FALSE;
951 }
952
953 // Copy the data to their buffer
954 RtlCopyMemory(InodeBuffer, (PVOID)(ULONG_PTR)(FILESYSBUFFER + (InodeOffsetInBlock * EXT3_INODE_SIZE(Ext2SuperBlock))), sizeof(EXT2_INODE));
955
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));
977
978 return TRUE;
979 }
980
981 BOOLEAN Ext2ReadGroupDescriptor(ULONG Group, PEXT2_GROUP_DESC GroupBuffer)
982 {
983 DbgPrint((DPRINT_FILESYSTEM, "Ext2ReadGroupDescriptor()\n"));
984
985 /*if (!Ext2ReadBlock(Ext2GetGroupDescBlockNumber(Group), (PVOID)FILESYSBUFFER))
986 {
987 return FALSE;
988 }
989
990 RtlCopyMemory(GroupBuffer, (PVOID)(FILESYSBUFFER + Ext2GetGroupDescOffsetInBlock(Group)), sizeof(EXT2_GROUP_DESC));*/
991
992 RtlCopyMemory(GroupBuffer, &Ext2GroupDescriptors[Group], sizeof(EXT2_GROUP_DESC));
993
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));
1001
1002 return TRUE;
1003 }
1004
1005 ULONG* Ext2ReadBlockPointerList(PEXT2_INODE Inode)
1006 {
1007 ULONGLONG FileSize;
1008 ULONG BlockCount;
1009 ULONG* BlockList;
1010 ULONG CurrentBlockInList;
1011 ULONG CurrentBlock;
1012
1013 DbgPrint((DPRINT_FILESYSTEM, "Ext2ReadBlockPointerList()\n"));
1014
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);
1024
1025 // Allocate the memory for the block list
1026 BlockList = MmHeapAlloc(BlockCount * sizeof(ULONG));
1027 if (BlockList == NULL)
1028 {
1029 return NULL;
1030 }
1031
1032 RtlZeroMemory(BlockList, BlockCount * sizeof(ULONG));
1033 CurrentBlockInList = 0;
1034
1035 // Copy the direct block pointers
1036 for (CurrentBlock=0; CurrentBlockInList<BlockCount && CurrentBlock<EXT3_NDIR_BLOCKS; CurrentBlock++)
1037 {
1038 BlockList[CurrentBlockInList] = Inode->i_block[CurrentBlock];
1039 CurrentBlockInList++;
1040 }
1041
1042 // Copy the indirect block pointers
1043 if (CurrentBlockInList < BlockCount)
1044 {
1045 if (!Ext2CopyIndirectBlockPointers(BlockList, &CurrentBlockInList, BlockCount, Inode->i_block[EXT3_IND_BLOCK]))
1046 {
1047 MmHeapFree(BlockList);
1048 return FALSE;
1049 }
1050 }
1051
1052 // Copy the double indirect block pointers
1053 if (CurrentBlockInList < BlockCount)
1054 {
1055 if (!Ext2CopyDoubleIndirectBlockPointers(BlockList, &CurrentBlockInList, BlockCount, Inode->i_block[EXT3_DIND_BLOCK]))
1056 {
1057 MmHeapFree(BlockList);
1058 return FALSE;
1059 }
1060 }
1061
1062 // Copy the triple indirect block pointers
1063 if (CurrentBlockInList < BlockCount)
1064 {
1065 if (!Ext2CopyTripleIndirectBlockPointers(BlockList, &CurrentBlockInList, BlockCount, Inode->i_block[EXT3_TIND_BLOCK]))
1066 {
1067 MmHeapFree(BlockList);
1068 return FALSE;
1069 }
1070 }
1071
1072 return BlockList;
1073 }
1074
1075 ULONGLONG Ext2GetInodeFileSize(PEXT2_INODE Inode)
1076 {
1077 if ((Inode->i_mode & EXT2_S_IFMT) == EXT2_S_IFDIR)
1078 {
1079 return (ULONGLONG)(Inode->i_size);
1080 }
1081 else
1082 {
1083 return ((ULONGLONG)(Inode->i_size) | ((ULONGLONG)(Inode->i_dir_acl) << 32));
1084 }
1085 }
1086
1087 BOOLEAN Ext2CopyIndirectBlockPointers(ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG IndirectBlock)
1088 {
1089 ULONG* BlockBuffer = (ULONG*)FILESYSBUFFER;
1090 ULONG CurrentBlock;
1091 ULONG BlockPointersPerBlock;
1092
1093 DbgPrint((DPRINT_FILESYSTEM, "Ext2CopyIndirectBlockPointers() BlockCount = %d\n", BlockCount));
1094
1095 BlockPointersPerBlock = Ext2BlockSizeInBytes / sizeof(ULONG);
1096
1097 if (!Ext2ReadBlock(IndirectBlock, BlockBuffer))
1098 {
1099 return FALSE;
1100 }
1101
1102 for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++)
1103 {
1104 BlockList[(*CurrentBlockInList)] = BlockBuffer[CurrentBlock];
1105 (*CurrentBlockInList)++;
1106 }
1107
1108 return TRUE;
1109 }
1110
1111 BOOLEAN Ext2CopyDoubleIndirectBlockPointers(ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG DoubleIndirectBlock)
1112 {
1113 ULONG* BlockBuffer;
1114 ULONG CurrentBlock;
1115 ULONG BlockPointersPerBlock;
1116
1117 DbgPrint((DPRINT_FILESYSTEM, "Ext2CopyDoubleIndirectBlockPointers() BlockCount = %d\n", BlockCount));
1118
1119 BlockPointersPerBlock = Ext2BlockSizeInBytes / sizeof(ULONG);
1120
1121 BlockBuffer = (ULONG*)MmHeapAlloc(Ext2BlockSizeInBytes);
1122 if (BlockBuffer == NULL)
1123 {
1124 return FALSE;
1125 }
1126
1127 if (!Ext2ReadBlock(DoubleIndirectBlock, BlockBuffer))
1128 {
1129 MmHeapFree(BlockBuffer);
1130 return FALSE;
1131 }
1132
1133 for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++)
1134 {
1135 if (!Ext2CopyIndirectBlockPointers(BlockList, CurrentBlockInList, BlockCount, BlockBuffer[CurrentBlock]))
1136 {
1137 MmHeapFree(BlockBuffer);
1138 return FALSE;
1139 }
1140 }
1141
1142 MmHeapFree(BlockBuffer);
1143 return TRUE;
1144 }
1145
1146 BOOLEAN Ext2CopyTripleIndirectBlockPointers(ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG TripleIndirectBlock)
1147 {
1148 ULONG* BlockBuffer;
1149 ULONG CurrentBlock;
1150 ULONG BlockPointersPerBlock;
1151
1152 DbgPrint((DPRINT_FILESYSTEM, "Ext2CopyTripleIndirectBlockPointers() BlockCount = %d\n", BlockCount));
1153
1154 BlockPointersPerBlock = Ext2BlockSizeInBytes / sizeof(ULONG);
1155
1156 BlockBuffer = (ULONG*)MmHeapAlloc(Ext2BlockSizeInBytes);
1157 if (BlockBuffer == NULL)
1158 {
1159 return FALSE;
1160 }
1161
1162 if (!Ext2ReadBlock(TripleIndirectBlock, BlockBuffer))
1163 {
1164 MmHeapFree(BlockBuffer);
1165 return FALSE;
1166 }
1167
1168 for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++)
1169 {
1170 if (!Ext2CopyDoubleIndirectBlockPointers(BlockList, CurrentBlockInList, BlockCount, BlockBuffer[CurrentBlock]))
1171 {
1172 MmHeapFree(BlockBuffer);
1173 return FALSE;
1174 }
1175 }
1176
1177 MmHeapFree(BlockBuffer);
1178 return TRUE;
1179 }
1180
1181 const FS_VTBL Ext2Vtbl = {
1182 Ext2OpenVolume,
1183 Ext2OpenFile,
1184 NULL,
1185 Ext2ReadFile,
1186 Ext2GetFileSize,
1187 Ext2SetFilePointer,
1188 Ext2GetFilePointer,
1189 };