ReactOS 0.4.15-dev-5664-g3bf4ef6
ext2.c
Go to the documentation of this file.
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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#ifndef _M_ARM
21#include <freeldr.h>
22
23#include <debug.h>
25
29BOOLEAN Ext2SearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PEXT2_DIR_ENTRY DirectoryEntry);
31
35BOOLEAN Ext2ReadDirectory(PEXT2_VOLUME_INFO Volume, ULONG Inode, PVOID* DirectoryBuffer, PEXT2_INODE InodePointer);
42BOOLEAN Ext2CopyIndirectBlockPointers(PEXT2_VOLUME_INFO Volume, ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG IndirectBlock);
43BOOLEAN Ext2CopyDoubleIndirectBlockPointers(PEXT2_VOLUME_INFO Volume, ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG DoubleIndirectBlock);
44BOOLEAN Ext2CopyTripleIndirectBlockPointers(PEXT2_VOLUME_INFO Volume, ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG TripleIndirectBlock);
45
46typedef struct _EXT2_VOLUME_INFO
47{
48 ULONG BytesPerSector; // Usually 512...
49
50 PEXT2_SUPER_BLOCK SuperBlock; // Ext2 file system super block
51 PEXT2_GROUP_DESC GroupDescriptors; // Ext2 file system group descriptors
52
53 ULONG BlockSizeInBytes; // Block size in bytes
54 ULONG BlockSizeInSectors; // Block size in sectors
55 ULONG FragmentSizeInBytes; // Fragment size in bytes
56 ULONG FragmentSizeInSectors; // Fragment size in sectors
57 ULONG GroupCount; // Number of groups in this file system
58 ULONG InodesPerBlock; // Number of inodes in one block
59 ULONG GroupDescPerBlock; // Number of group descriptors in one block
60
61 ULONG DeviceId; // Ext2 file system device ID
62
64
66
67#define TAG_EXT_BLOCK_LIST 'LtxE'
68#define TAG_EXT_FILE 'FtxE'
69#define TAG_EXT_BUFFER 'BtxE'
70#define TAG_EXT_SUPER_BLOCK 'StxE'
71#define TAG_EXT_GROUP_DESC 'GtxE'
72#define TAG_EXT_VOLUME 'VtxE'
73
75{
76 TRACE("Ext2OpenVolume() DeviceId = %d\n", Volume->DeviceId);
77
78#if 0
79 /* Initialize the disk cache for this drive */
80 if (!CacheInitializeDrive(DriveNumber))
81 {
82 return FALSE;
83 }
84#endif
85 Volume->BytesPerSector = SECTOR_SIZE;
86
87 /* Read in the super block */
89 return FALSE;
90
91 /* Read in the group descriptors */
93 return FALSE;
94
95 return TRUE;
96}
97
98/*
99 * Ext2OpenFile()
100 * Tries to open the file 'name' and returns true or false
101 * for success and failure respectively
102 */
104{
105 EXT2_FILE_INFO TempExt2FileInfo;
107 CHAR SymLinkPath[EXT2_NAME_LEN];
108 CHAR FullPath[EXT2_NAME_LEN * 2];
110
111 TRACE("Ext2OpenFile() FileName = %s\n", FileName);
112
113 RtlZeroMemory(SymLinkPath, sizeof(SymLinkPath));
114
115 // Lookup the file in the file system
116 if (!Ext2LookupFile(Volume, FileName, &TempExt2FileInfo))
117 {
118 return NULL;
119 }
120
121 // If we got a symbolic link then fix up the path
122 // and re-call this function
123 if ((TempExt2FileInfo.Inode.mode & EXT2_S_IFMT) == EXT2_S_IFLNK)
124 {
125 TRACE("File is a symbolic link\n");
126
127 // Now read in the symbolic link path
128 if (!Ext2ReadFileBig(&TempExt2FileInfo, TempExt2FileInfo.FileSize, NULL, SymLinkPath))
129 {
130 if (TempExt2FileInfo.FileBlockList != NULL)
131 {
133 }
134
135 return NULL;
136 }
137
138 TRACE("Symbolic link path = %s\n", SymLinkPath);
139
140 // Get the full path
141 if (SymLinkPath[0] == '/' || SymLinkPath[0] == '\\')
142 {
143 // Symbolic link is an absolute path
144 // So copy it to FullPath, but skip over
145 // the '/' char at the beginning
146 strcpy(FullPath, &SymLinkPath[1]);
147 }
148 else
149 {
150 // Symbolic link is a relative path
151 // Copy the first part of the path
152 strcpy(FullPath, FileName);
153
154 // Remove the last part of the path
155 for (Index=strlen(FullPath); Index>0; )
156 {
157 Index--;
158 if (FullPath[Index] == '/' || FullPath[Index] == '\\')
159 {
160 break;
161 }
162 }
163 FullPath[Index] = '\0';
164
165 // Concatenate the symbolic link
166 strcat(FullPath, Index == 0 ? "" : "/");
167 strcat(FullPath, SymLinkPath);
168 }
169
170 TRACE("Full file path = %s\n", FullPath);
171
172 if (TempExt2FileInfo.FileBlockList != NULL)
173 {
175 }
176
177 return Ext2OpenFile(Volume, FullPath);
178 }
179 else
180 {
182 if (FileHandle == NULL)
183 {
184 if (TempExt2FileInfo.FileBlockList != NULL)
185 {
187 }
188
189 return NULL;
190 }
191
192 RtlCopyMemory(FileHandle, &TempExt2FileInfo, sizeof(EXT2_FILE_INFO));
193
194 return FileHandle;
195 }
196}
197
198/*
199 * Ext2LookupFile()
200 * This function searches the file system for the
201 * specified filename and fills in a EXT2_FILE_INFO structure
202 * with info describing the file, etc. returns true
203 * if the file exists or false otherwise
204 */
206{
207 UINT32 i;
208 ULONG NumberOfPathParts;
209 CHAR PathPart[261];
210 PVOID DirectoryBuffer;
211 ULONG DirectoryInode = EXT2_ROOT_INO;
212 EXT2_INODE InodeData;
213 EXT2_DIR_ENTRY DirectoryEntry;
214
215 TRACE("Ext2LookupFile() FileName = %s\n", FileName);
216
217 RtlZeroMemory(Ext2FileInfo, sizeof(EXT2_FILE_INFO));
218
219 //
220 // Figure out how many sub-directories we are nested in
221 //
222 NumberOfPathParts = FsGetNumPathParts(FileName);
223
224 //
225 // Loop once for each part
226 //
227 for (i=0; i<NumberOfPathParts; i++)
228 {
229 //
230 // Get first path part
231 //
233
234 //
235 // Advance to the next part of the path
236 //
237 for (; (*FileName != '\\') && (*FileName != '/') && (*FileName != '\0'); FileName++)
238 {
239 }
240 FileName++;
241
242 //
243 // Buffer the directory contents
244 //
245 if (!Ext2ReadDirectory(Volume, DirectoryInode, &DirectoryBuffer, &InodeData))
246 {
247 return FALSE;
248 }
249
250 //
251 // Search for file name in directory
252 //
253 if (!Ext2SearchDirectoryBufferForFile(DirectoryBuffer, (ULONG)Ext2GetInodeFileSize(&InodeData), PathPart, &DirectoryEntry))
254 {
255 FrLdrTempFree(DirectoryBuffer, TAG_EXT_BUFFER);
256 return FALSE;
257 }
258
259 FrLdrTempFree(DirectoryBuffer, TAG_EXT_BUFFER);
260
261 DirectoryInode = DirectoryEntry.inode;
262 }
263
264 if (!Ext2ReadInode(Volume, DirectoryInode, &InodeData))
265 {
266 return FALSE;
267 }
268
269 if (((InodeData.mode & EXT2_S_IFMT) != EXT2_S_IFREG) &&
270 ((InodeData.mode & EXT2_S_IFMT) != EXT2_S_IFLNK))
271 {
272 FileSystemError("Inode is not a regular file or symbolic link.");
273 return FALSE;
274 }
275
276 // Set the associated volume
277 Ext2FileInfo->Volume = Volume;
278
279 // If it's a regular file or a regular symbolic link
280 // then get the block pointer list otherwise it must
281 // be a fast symbolic link which doesn't have a block list
282 if (((InodeData.mode & EXT2_S_IFMT) == EXT2_S_IFREG) ||
283 ((InodeData.mode & EXT2_S_IFMT) == EXT2_S_IFLNK && InodeData.size > FAST_SYMLINK_MAX_NAME_SIZE))
284 {
285 Ext2FileInfo->FileBlockList = Ext2ReadBlockPointerList(Volume, &InodeData);
286 if (Ext2FileInfo->FileBlockList == NULL)
287 {
288 return FALSE;
289 }
290 }
291 else
292 {
293 Ext2FileInfo->FileBlockList = NULL;
294 }
295
296 Ext2FileInfo->FilePointer = 0;
297 Ext2FileInfo->FileSize = Ext2GetInodeFileSize(&InodeData);
298 RtlCopyMemory(&Ext2FileInfo->Inode, &InodeData, sizeof(EXT2_INODE));
299
300 return TRUE;
301}
302
303BOOLEAN Ext2SearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PEXT2_DIR_ENTRY DirectoryEntry)
304{
305 ULONG CurrentOffset;
306 PEXT2_DIR_ENTRY CurrentDirectoryEntry;
307
308 TRACE("Ext2SearchDirectoryBufferForFile() DirectoryBuffer = 0x%x DirectorySize = %d FileName = %s\n", DirectoryBuffer, DirectorySize, FileName);
309
310 for (CurrentOffset=0; CurrentOffset<DirectorySize; )
311 {
312 CurrentDirectoryEntry = (PEXT2_DIR_ENTRY)((ULONG_PTR)DirectoryBuffer + CurrentOffset);
313
314 if (CurrentDirectoryEntry->direntlen == 0)
315 {
316 break;
317 }
318
319 if ((CurrentDirectoryEntry->direntlen + CurrentOffset) > DirectorySize)
320 {
321 FileSystemError("Directory entry extends past end of directory file.");
322 return FALSE;
323 }
324
325 TRACE("Dumping directory entry at offset %d:\n", CurrentOffset);
326 DbgDumpBuffer(DPRINT_FILESYSTEM, CurrentDirectoryEntry, CurrentDirectoryEntry->direntlen);
327
328 if ((_strnicmp(FileName, CurrentDirectoryEntry->name, CurrentDirectoryEntry->namelen) == 0) &&
329 (strlen(FileName) == CurrentDirectoryEntry->namelen))
330 {
331 RtlCopyMemory(DirectoryEntry, CurrentDirectoryEntry, sizeof(EXT2_DIR_ENTRY));
332
333 TRACE("EXT2 Directory Entry:\n");
334 TRACE("inode = %d\n", DirectoryEntry->inode);
335 TRACE("direntlen = %d\n", DirectoryEntry->direntlen);
336 TRACE("namelen = %d\n", DirectoryEntry->namelen);
337 TRACE("filetype = %d\n", DirectoryEntry->filetype);
338 TRACE("name = ");
339 for (CurrentOffset=0; CurrentOffset<DirectoryEntry->namelen; CurrentOffset++)
340 {
341 TRACE("%c", DirectoryEntry->name[CurrentOffset]);
342 }
343 TRACE("\n");
344
345 return TRUE;
346 }
347
348 CurrentOffset += CurrentDirectoryEntry->direntlen;
349 }
350
351 return FALSE;
352}
353
354/*
355 * Ext2ReadFileBig()
356 * Reads BytesToRead from open file and
357 * returns the number of bytes read in BytesRead
358 */
360{
361 PEXT2_VOLUME_INFO Volume = Ext2FileInfo->Volume;
362 ULONG BlockNumber;
363 ULONG BlockNumberIndex;
364 ULONG OffsetInBlock;
365 ULONG LengthInBlock;
366 ULONG NumberOfBlocks;
367
368 TRACE("Ext2ReadFileBig() BytesToRead = %d Buffer = 0x%x\n", (ULONG)BytesToRead, Buffer);
369
370 if (BytesRead != NULL)
371 {
372 *BytesRead = 0;
373 }
374
375 // Make sure we have the block pointer list if we need it
376 if (Ext2FileInfo->FileBlockList == NULL)
377 {
378 // Block pointer list is NULL
379 // so this better be a fast symbolic link or else
380 if (((Ext2FileInfo->Inode.mode & EXT2_S_IFMT) != EXT2_S_IFLNK) ||
381 (Ext2FileInfo->FileSize > FAST_SYMLINK_MAX_NAME_SIZE))
382 {
383 FileSystemError("Block pointer list is NULL and file is not a fast symbolic link.");
384 return FALSE;
385 }
386 }
387
388 //
389 // If the user is trying to read past the end of
390 // the file then return success with BytesRead == 0.
391 //
392 if (Ext2FileInfo->FilePointer >= Ext2FileInfo->FileSize)
393 {
394 return TRUE;
395 }
396
397 //
398 // If the user is trying to read more than there is to read
399 // then adjust the amount to read.
400 //
401 if ((Ext2FileInfo->FilePointer + BytesToRead) > Ext2FileInfo->FileSize)
402 {
403 BytesToRead = (Ext2FileInfo->FileSize - Ext2FileInfo->FilePointer);
404 }
405
406 // Check if this is a fast symbolic link
407 // if so then the read is easy
408 if (((Ext2FileInfo->Inode.mode & EXT2_S_IFMT) == EXT2_S_IFLNK) &&
409 (Ext2FileInfo->FileSize <= FAST_SYMLINK_MAX_NAME_SIZE))
410 {
411 TRACE("Reading fast symbolic link data\n");
412
413 // Copy the data from the link
414 RtlCopyMemory(Buffer, (PVOID)((ULONG_PTR)Ext2FileInfo->FilePointer + Ext2FileInfo->Inode.symlink), (ULONG)BytesToRead);
415
416 if (BytesRead != NULL)
417 {
418 *BytesRead = BytesToRead;
419 }
420 // Ext2FileInfo->FilePointer += BytesToRead;
421
422 return TRUE;
423 }
424
425 //
426 // Ok, now we have to perform at most 3 calculations
427 // I'll draw you a picture (using nifty ASCII art):
428 //
429 // CurrentFilePointer -+
430 // |
431 // +----------------+
432 // |
433 // +-----------+-----------+-----------+-----------+
434 // | Block 1 | Block 2 | Block 3 | Block 4 |
435 // +-----------+-----------+-----------+-----------+
436 // | |
437 // +---------------+--------------------+
438 // |
439 // BytesToRead -------+
440 //
441 // 1 - The first calculation (and read) will align
442 // the file pointer with the next block.
443 // boundary (if we are supposed to read that much)
444 // 2 - The next calculation (and read) will read
445 // in all the full blocks that the requested
446 // amount of data would cover (in this case
447 // blocks 2 & 3).
448 // 3 - The last calculation (and read) would read
449 // in the remainder of the data requested out of
450 // the last block.
451 //
452
453 //
454 // Only do the first read if we
455 // aren't aligned on a block boundary
456 //
457 if (Ext2FileInfo->FilePointer % Volume->BlockSizeInBytes)
458 {
459 //
460 // Do the math for our first read
461 //
462 BlockNumberIndex = (ULONG)(Ext2FileInfo->FilePointer / Volume->BlockSizeInBytes);
463 BlockNumber = Ext2FileInfo->FileBlockList[BlockNumberIndex];
464 OffsetInBlock = (Ext2FileInfo->FilePointer % Volume->BlockSizeInBytes);
465 LengthInBlock = (ULONG)((BytesToRead > (Volume->BlockSizeInBytes - OffsetInBlock)) ? (Volume->BlockSizeInBytes - OffsetInBlock) : BytesToRead);
466
467 //
468 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
469 //
470 if (!Ext2ReadPartialBlock(Volume, BlockNumber, OffsetInBlock, LengthInBlock, Buffer))
471 {
472 return FALSE;
473 }
474 if (BytesRead != NULL)
475 {
476 *BytesRead += LengthInBlock;
477 }
478 BytesToRead -= LengthInBlock;
479 Ext2FileInfo->FilePointer += LengthInBlock;
480 Buffer = (PVOID)((ULONG_PTR)Buffer + LengthInBlock);
481 }
482
483 //
484 // Do the math for our second read (if any data left)
485 //
486 if (BytesToRead > 0)
487 {
488 //
489 // Determine how many full clusters we need to read
490 //
491 NumberOfBlocks = (ULONG)(BytesToRead / Volume->BlockSizeInBytes);
492
493 while (NumberOfBlocks > 0)
494 {
495 BlockNumberIndex = (ULONG)(Ext2FileInfo->FilePointer / Volume->BlockSizeInBytes);
496 BlockNumber = Ext2FileInfo->FileBlockList[BlockNumberIndex];
497
498 //
499 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
500 //
501 if (!Ext2ReadBlock(Volume, BlockNumber, Buffer))
502 {
503 return FALSE;
504 }
505 if (BytesRead != NULL)
506 {
507 *BytesRead += Volume->BlockSizeInBytes;
508 }
509 BytesToRead -= Volume->BlockSizeInBytes;
510 Ext2FileInfo->FilePointer += Volume->BlockSizeInBytes;
511 Buffer = (PVOID)((ULONG_PTR)Buffer + Volume->BlockSizeInBytes);
512 NumberOfBlocks--;
513 }
514 }
515
516 //
517 // Do the math for our third read (if any data left)
518 //
519 if (BytesToRead > 0)
520 {
521 BlockNumberIndex = (ULONG)(Ext2FileInfo->FilePointer / Volume->BlockSizeInBytes);
522 BlockNumber = Ext2FileInfo->FileBlockList[BlockNumberIndex];
523
524 //
525 // Now do the read and update BytesRead & FilePointer
526 //
527 if (!Ext2ReadPartialBlock(Volume, BlockNumber, 0, (ULONG)BytesToRead, Buffer))
528 {
529 return FALSE;
530 }
531 if (BytesRead != NULL)
532 {
533 *BytesRead += BytesToRead;
534 }
535 Ext2FileInfo->FilePointer += BytesToRead;
536 }
537
538 return TRUE;
539}
540
542{
543#if 0
544 return CacheReadDiskSectors(DriveNumber, SectorNumber + Ext2VolumeStartSector, SectorCount, Buffer);
545#endif
546
548 ULONG Count;
550
551 /* Seek to right position */
552 Position.QuadPart = (ULONGLONG)SectorNumber * 512;
553 Status = ArcSeek(Volume->DeviceId, &Position, SeekAbsolute);
554 if (Status != ESUCCESS)
555 {
556 TRACE("Ext2ReadVolumeSectors() Failed to seek\n");
557 return FALSE;
558 }
559
560 /* Read data */
561 Status = ArcRead(Volume->DeviceId, Buffer, SectorCount * 512, &Count);
562 if (Status != ESUCCESS || Count != SectorCount * 512)
563 {
564 TRACE("Ext2ReadVolumeSectors() Failed to read\n");
565 return FALSE;
566 }
567
568 /* Return success */
569 return TRUE;
570}
571
573{
574 PEXT2_SUPER_BLOCK SuperBlock = Volume->SuperBlock;
576 ULONG Count;
578
579 TRACE("Ext2ReadSuperBlock()\n");
580
581#if 0
582 /* Free any memory previously allocated */
583 if (SuperBlock != NULL)
584 {
586 SuperBlock = NULL;
587 }
588#endif
589
590 /* Allocate the memory to hold the super block if needed */
591 if (SuperBlock == NULL)
592 {
594 if (SuperBlock == NULL)
595 {
596 FileSystemError("Out of memory.");
597 return FALSE;
598 }
599 }
600 Volume->SuperBlock = SuperBlock;
601
602 /* Reset its contents */
603 RtlZeroMemory(SuperBlock, 1024);
604
605 /* Read the SuperBlock */
606 Position.QuadPart = 2 * 512;
607 Status = ArcSeek(Volume->DeviceId, &Position, SeekAbsolute);
608 if (Status != ESUCCESS)
609 return FALSE;
610 Status = ArcRead(Volume->DeviceId, SuperBlock, 2 * 512, &Count);
611 if (Status != ESUCCESS || Count != 2 * 512)
612 return FALSE;
613
614 TRACE("Dumping super block:\n");
615 TRACE("total_inodes: %d\n", SuperBlock->total_inodes);
616 TRACE("total_blocks: %d\n", SuperBlock->total_blocks);
617 TRACE("reserved_blocks: %d\n", SuperBlock->reserved_blocks);
618 TRACE("free_blocks: %d\n", SuperBlock->free_blocks);
619 TRACE("free_inodes: %d\n", SuperBlock->free_inodes);
620 TRACE("first_data_block: %d\n", SuperBlock->first_data_block);
621 TRACE("log2_block_size: %d\n", SuperBlock->log2_block_size);
622 TRACE("log2_fragment_size: %d\n", SuperBlock->log2_fragment_size);
623 TRACE("blocks_per_group: %d\n", SuperBlock->blocks_per_group);
624 TRACE("fragments_per_group: %d\n", SuperBlock->fragments_per_group);
625 TRACE("inodes_per_group: %d\n", SuperBlock->inodes_per_group);
626 TRACE("mtime: %d\n", SuperBlock->mtime);
627 TRACE("utime: %d\n", SuperBlock->utime);
628 TRACE("mnt_count: %d\n", SuperBlock->mnt_count);
629 TRACE("max_mnt_count: %d\n", SuperBlock->max_mnt_count);
630 TRACE("magic: 0x%x\n", SuperBlock->magic);
631 TRACE("fs_state: %d\n", SuperBlock->fs_state);
632 TRACE("error_handling: %d\n", SuperBlock->error_handling);
633 TRACE("minor_revision_level: %d\n", SuperBlock->minor_revision_level);
634 TRACE("lastcheck: %d\n", SuperBlock->lastcheck);
635 TRACE("checkinterval: %d\n", SuperBlock->checkinterval);
636 TRACE("creator_os: %d\n", SuperBlock->creator_os);
637 TRACE("revision_level: %d\n", SuperBlock->revision_level);
638 TRACE("uid_reserved: %d\n", SuperBlock->uid_reserved);
639 TRACE("gid_reserved: %d\n", SuperBlock->gid_reserved);
640 TRACE("first_inode: %d\n", SuperBlock->first_inode);
641 TRACE("inode_size: %d\n", SuperBlock->inode_size);
642 TRACE("block_group_number: %d\n", SuperBlock->block_group_number);
643 TRACE("feature_compatibility: 0x%x\n", SuperBlock->feature_compatibility);
644 TRACE("feature_incompat: 0x%x\n", SuperBlock->feature_incompat);
645 TRACE("feature_ro_compat: 0x%x\n", SuperBlock->feature_ro_compat);
646 TRACE("unique_id = { 0x%x, 0x%x, 0x%x, 0x%x }\n",
647 SuperBlock->unique_id[0], SuperBlock->unique_id[1],
648 SuperBlock->unique_id[2], SuperBlock->unique_id[3]);
649 TRACE("volume_name = '%.16s'\n", SuperBlock->volume_name);
650 TRACE("last_mounted_on = '%.64s'\n", SuperBlock->last_mounted_on);
651 TRACE("compression_info = 0x%x\n", SuperBlock->compression_info);
652
653 //
654 // Check the super block magic
655 //
656 if (SuperBlock->magic != EXT2_MAGIC)
657 {
658 FileSystemError("Invalid super block magic (0xef53)");
659 return FALSE;
660 }
661
662 //
663 // Check the revision level
664 //
665 if (SuperBlock->revision_level > EXT2_DYNAMIC_REVISION)
666 {
667 FileSystemError("FreeLoader does not understand the revision of this EXT2/EXT3 filesystem.\nPlease update FreeLoader.");
668 return FALSE;
669 }
670
671 //
672 // Check the feature set
673 // Don't need to check the compatible or read-only compatible features
674 // because we only mount the filesystem as read-only
675 //
676 if ((SuperBlock->revision_level >= EXT2_DYNAMIC_REVISION) &&
677 (/*((SuperBlock->s_feature_compat & ~EXT3_FEATURE_COMPAT_SUPP) != 0) ||*/
678 /*((SuperBlock->s_feature_ro_compat & ~EXT3_FEATURE_RO_COMPAT_SUPP) != 0) ||*/
679 ((SuperBlock->feature_incompat & ~EXT3_FEATURE_INCOMPAT_SUPP) != 0)))
680 {
681 FileSystemError("FreeLoader does not understand features of this EXT2/EXT3 filesystem.\nPlease update FreeLoader.");
682 return FALSE;
683 }
684
685 // Calculate the group count
686 Volume->GroupCount = (SuperBlock->total_blocks - SuperBlock->first_data_block + SuperBlock->blocks_per_group - 1) / SuperBlock->blocks_per_group;
687 TRACE("Ext2GroupCount: %d\n", Volume->GroupCount);
688
689 // Calculate the block size
690 Volume->BlockSizeInBytes = 1024 << SuperBlock->log2_block_size;
691 Volume->BlockSizeInSectors = Volume->BlockSizeInBytes / Volume->BytesPerSector;
692 TRACE("Ext2BlockSizeInBytes: %d\n", Volume->BlockSizeInBytes);
693 TRACE("Ext2BlockSizeInSectors: %d\n", Volume->BlockSizeInSectors);
694
695 // Calculate the fragment size
696 if (SuperBlock->log2_fragment_size >= 0)
697 {
698 Volume->FragmentSizeInBytes = 1024 << SuperBlock->log2_fragment_size;
699 }
700 else
701 {
702 Volume->FragmentSizeInBytes = 1024 >> -(SuperBlock->log2_fragment_size);
703 }
704 Volume->FragmentSizeInSectors = Volume->FragmentSizeInBytes / Volume->BytesPerSector;
705 TRACE("Ext2FragmentSizeInBytes: %d\n", Volume->FragmentSizeInBytes);
706 TRACE("Ext2FragmentSizeInSectors: %d\n", Volume->FragmentSizeInSectors);
707
708 // Verify that the fragment size and the block size are equal
709 if (Volume->BlockSizeInBytes != Volume->FragmentSizeInBytes)
710 {
711 FileSystemError("The fragment size must be equal to the block size.");
712 return FALSE;
713 }
714
715 // Calculate the number of inodes in one block
716 Volume->InodesPerBlock = Volume->BlockSizeInBytes / EXT2_INODE_SIZE(SuperBlock);
717 TRACE("Ext2InodesPerBlock: %d\n", Volume->InodesPerBlock);
718
719 // Calculate the number of group descriptors in one block
720 Volume->GroupDescPerBlock = EXT2_DESC_PER_BLOCK(SuperBlock);
721 TRACE("Ext2GroupDescPerBlock: %d\n", Volume->GroupDescPerBlock);
722
723 return TRUE;
724}
725
727{
728 ULONG GroupDescBlockCount;
729 ULONG BlockNumber;
730 PUCHAR CurrentGroupDescBlock;
731
732 TRACE("Ext2ReadGroupDescriptors()\n");
733
734 /* Free any memory previously allocated */
735 if (Volume->GroupDescriptors != NULL)
736 {
737 FrLdrTempFree(Volume->GroupDescriptors, TAG_EXT_GROUP_DESC);
738 Volume->GroupDescriptors = NULL;
739 }
740
741 /* Now allocate the memory to hold the group descriptors */
742 GroupDescBlockCount = ROUND_UP(Volume->GroupCount, Volume->GroupDescPerBlock) / Volume->GroupDescPerBlock;
743 Volume->GroupDescriptors = (PEXT2_GROUP_DESC)FrLdrTempAlloc(GroupDescBlockCount * Volume->BlockSizeInBytes, TAG_EXT_GROUP_DESC);
744 if (Volume->GroupDescriptors == NULL)
745 {
746 FileSystemError("Out of memory.");
747 return FALSE;
748 }
749
750 // Now read the group descriptors
751 CurrentGroupDescBlock = (PUCHAR)Volume->GroupDescriptors;
752 BlockNumber = Volume->SuperBlock->first_data_block + 1;
753
754 while (GroupDescBlockCount--)
755 {
756 if (!Ext2ReadBlock(Volume, BlockNumber, CurrentGroupDescBlock))
757 {
758 return FALSE;
759 }
760
761 BlockNumber++;
762 CurrentGroupDescBlock += Volume->BlockSizeInBytes;
763 }
764
765 return TRUE;
766}
767
769{
770 EXT2_FILE_INFO DirectoryFileInfo;
771
772 TRACE("Ext2ReadDirectory() Inode = %d\n", Inode);
773
774 // Read the directory inode
775 if (!Ext2ReadInode(Volume, Inode, InodePointer))
776 {
777 return FALSE;
778 }
779
780 // Make sure it is a directory inode
781 if ((InodePointer->mode & EXT2_S_IFMT) != EXT2_S_IFDIR)
782 {
783 FileSystemError("Inode is not a directory.");
784 return FALSE;
785 }
786
787 // Fill in file info struct so we can call Ext2ReadFileBig()
788 RtlZeroMemory(&DirectoryFileInfo, sizeof(EXT2_FILE_INFO));
789 DirectoryFileInfo.Volume = Volume;
790 DirectoryFileInfo.FileBlockList = Ext2ReadBlockPointerList(Volume, InodePointer);
791 DirectoryFileInfo.FilePointer = 0;
792 DirectoryFileInfo.FileSize = Ext2GetInodeFileSize(InodePointer);
793
794 if (DirectoryFileInfo.FileBlockList == NULL)
795 {
796 return FALSE;
797 }
798
799 //
800 // Now allocate the memory to hold the group descriptors
801 //
802 ASSERT(DirectoryFileInfo.FileSize <= 0xFFFFFFFF);
803 *DirectoryBuffer = (PEXT2_DIR_ENTRY)FrLdrTempAlloc((ULONG)DirectoryFileInfo.FileSize, TAG_EXT_BUFFER);
804
805 //
806 // Make sure we got the memory
807 //
808 if (*DirectoryBuffer == NULL)
809 {
811 FileSystemError("Out of memory.");
812 return FALSE;
813 }
814
815 // Now read the root directory data
816 if (!Ext2ReadFileBig(&DirectoryFileInfo, DirectoryFileInfo.FileSize, NULL, *DirectoryBuffer))
817 {
818 FrLdrTempFree(*DirectoryBuffer, TAG_EXT_BUFFER);
819 *DirectoryBuffer = NULL;
821 return FALSE;
822 }
823
825 return TRUE;
826}
827
829{
830 CHAR ErrorString[80];
831
832 TRACE("Ext2ReadBlock() BlockNumber = %d Buffer = 0x%x\n", BlockNumber, Buffer);
833
834 // Make sure its a valid block
835 if (BlockNumber > Volume->SuperBlock->total_blocks)
836 {
837 sprintf(ErrorString, "Error reading block %d - block out of range.", (int) BlockNumber);
838 FileSystemError(ErrorString);
839 return FALSE;
840 }
841
842 // Check to see if this is a sparse block
843 if (BlockNumber == 0)
844 {
845 TRACE("Block is part of a sparse file. Zeroing input buffer.\n");
846
847 RtlZeroMemory(Buffer, Volume->BlockSizeInBytes);
848
849 return TRUE;
850 }
851
852 return Ext2ReadVolumeSectors(Volume, (ULONGLONG)BlockNumber * Volume->BlockSizeInSectors, Volume->BlockSizeInSectors, Buffer);
853}
854
855/*
856 * Ext2ReadPartialBlock()
857 * Reads part of a block into memory
858 */
860{
861 PVOID TempBuffer;
862
863 TRACE("Ext2ReadPartialBlock() BlockNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", BlockNumber, StartingOffset, Length, Buffer);
864
865 TempBuffer = FrLdrTempAlloc(Volume->BlockSizeInBytes, TAG_EXT_BUFFER);
866
867 if (!Ext2ReadBlock(Volume, BlockNumber, TempBuffer))
868 {
869 FrLdrTempFree(TempBuffer, TAG_EXT_BUFFER);
870 return FALSE;
871 }
872
874
875 FrLdrTempFree(TempBuffer, TAG_EXT_BUFFER);
876
877 return TRUE;
878}
879
880#if 0
881ULONG Ext2GetGroupDescBlockNumber(PEXT2_VOLUME_INFO Volume, ULONG Group)
882{
883 return (((Group * sizeof(EXT2_GROUP_DESC)) / Volume->GroupDescPerBlock) + Volume->SuperBlock->first_data_block + 1);
884}
885
886ULONG Ext2GetGroupDescOffsetInBlock(PEXT2_VOLUME_INFO Volume, ULONG Group)
887{
888 return ((Group * sizeof(EXT2_GROUP_DESC)) % Volume->GroupDescPerBlock);
889}
890#endif
891
893{
894 return ((Inode - 1) / Volume->SuperBlock->inodes_per_group);
895}
896
898{
899 return (((Inode - 1) % Volume->SuperBlock->inodes_per_group) / Volume->InodesPerBlock);
900}
901
903{
904 return (((Inode - 1) % Volume->SuperBlock->inodes_per_group) % Volume->InodesPerBlock);
905}
906
908{
909 ULONG InodeGroupNumber;
910 ULONG InodeBlockNumber;
911 ULONG InodeOffsetInBlock;
912 CHAR ErrorString[80];
913 EXT2_GROUP_DESC GroupDescriptor;
914
915 TRACE("Ext2ReadInode() Inode = %d\n", Inode);
916
917 // Make sure its a valid inode
918 if ((Inode < 1) || (Inode > Volume->SuperBlock->total_inodes))
919 {
920 sprintf(ErrorString, "Error reading inode %ld - inode out of range.", Inode);
921 FileSystemError(ErrorString);
922 return FALSE;
923 }
924
925 // Get inode group & block number and offset in block
926 InodeGroupNumber = Ext2GetInodeGroupNumber(Volume, Inode);
927 InodeBlockNumber = Ext2GetInodeBlockNumber(Volume, Inode);
928 InodeOffsetInBlock = Ext2GetInodeOffsetInBlock(Volume, Inode);
929 TRACE("InodeGroupNumber = %d\n", InodeGroupNumber);
930 TRACE("InodeBlockNumber = %d\n", InodeBlockNumber);
931 TRACE("InodeOffsetInBlock = %d\n", InodeOffsetInBlock);
932
933 // Read the group descriptor
934 if (!Ext2ReadGroupDescriptor(Volume, InodeGroupNumber, &GroupDescriptor))
935 {
936 return FALSE;
937 }
938
939 // Add the start block of the inode table to the inode block number
940 InodeBlockNumber += GroupDescriptor.inode_table_id;
941 TRACE("InodeBlockNumber (after group desc correction) = %d\n", InodeBlockNumber);
942
943 // Read the block
945 InodeBlockNumber,
946 (InodeOffsetInBlock * EXT2_INODE_SIZE(Volume->SuperBlock)),
947 sizeof(EXT2_INODE),
948 InodeBuffer))
949 {
950 return FALSE;
951 }
952
953 TRACE("Dumping inode information:\n");
954 TRACE("mode = 0x%x\n", InodeBuffer->mode);
955 TRACE("uid = %d\n", InodeBuffer->uid);
956 TRACE("size = %d\n", InodeBuffer->size);
957 TRACE("atime = %d\n", InodeBuffer->atime);
958 TRACE("ctime = %d\n", InodeBuffer->ctime);
959 TRACE("mtime = %d\n", InodeBuffer->mtime);
960 TRACE("dtime = %d\n", InodeBuffer->dtime);
961 TRACE("gid = %d\n", InodeBuffer->gid);
962 TRACE("nlinks = %d\n", InodeBuffer->nlinks);
963 TRACE("blockcnt = %d\n", InodeBuffer->blockcnt);
964 TRACE("flags = 0x%x\n", InodeBuffer->flags);
965 TRACE("osd1 = 0x%x\n", InodeBuffer->osd1);
966 TRACE("dir_blocks = { %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u }\n",
967 InodeBuffer->blocks.dir_blocks[0], InodeBuffer->blocks.dir_blocks[1], InodeBuffer->blocks.dir_blocks[ 2], InodeBuffer->blocks.dir_blocks[ 3],
968 InodeBuffer->blocks.dir_blocks[4], InodeBuffer->blocks.dir_blocks[5], InodeBuffer->blocks.dir_blocks[ 6], InodeBuffer->blocks.dir_blocks[ 7],
969 InodeBuffer->blocks.dir_blocks[8], InodeBuffer->blocks.dir_blocks[9], InodeBuffer->blocks.dir_blocks[10], InodeBuffer->blocks.dir_blocks[11]);
970 TRACE("indir_block = %u\n", InodeBuffer->blocks.indir_block);
971 TRACE("double_indir_block = %u\n", InodeBuffer->blocks.double_indir_block);
972 TRACE("tripple_indir_block = %u\n", InodeBuffer->blocks.tripple_indir_block);
973 TRACE("version = %d\n", InodeBuffer->version);
974 TRACE("acl = %d\n", InodeBuffer->acl);
975 TRACE("dir_acl = %d\n", InodeBuffer->dir_acl);
976 TRACE("fragment_addr = %d\n", InodeBuffer->fragment_addr);
977 TRACE("osd2 = { %d, %d, %d }\n",
978 InodeBuffer->osd2[0], InodeBuffer->osd2[1], InodeBuffer->osd2[2]);
979
980 return TRUE;
981}
982
984{
985 TRACE("Ext2ReadGroupDescriptor()\n");
986
987#if 0
988 if (!Ext2ReadBlock(Volume, Ext2GetGroupDescBlockNumber(Volume, Group), (PVOID)FILESYSBUFFER))
989 {
990 return FALSE;
991 }
992 RtlCopyMemory(GroupBuffer, (PVOID)(FILESYSBUFFER + Ext2GetGroupDescOffsetInBlock(Volume, Group)), sizeof(EXT2_GROUP_DESC));
993#endif
994
995 RtlCopyMemory(GroupBuffer, &Volume->GroupDescriptors[Group], sizeof(EXT2_GROUP_DESC));
996
997 TRACE("Dumping group descriptor:\n");
998 TRACE("block_id = %d\n", GroupBuffer->block_id);
999 TRACE("inode_id = %d\n", GroupBuffer->inode_id);
1000 TRACE("inode_table_id = %d\n", GroupBuffer->inode_table_id);
1001 TRACE("free_blocks = %d\n", GroupBuffer->free_blocks);
1002 TRACE("free_inodes = %d\n", GroupBuffer->free_inodes);
1003 TRACE("used_dirs = %d\n", GroupBuffer->used_dirs);
1004
1005 return TRUE;
1006}
1007
1009{
1011 ULONG BlockCount;
1012 ULONG* BlockList;
1013 ULONG CurrentBlockInList;
1014 ULONG CurrentBlock;
1015
1016 TRACE("Ext2ReadBlockPointerList()\n");
1017
1018 // Get the number of blocks this file occupies
1019 // I would just use Inode->i_blocks but it
1020 // doesn't seem to be the number of blocks
1021 // the file size corresponds to, but instead
1022 // it is much bigger.
1023 //BlockCount = Inode->i_blocks;
1025 FileSize = ROUND_UP(FileSize, Volume->BlockSizeInBytes);
1026 BlockCount = (ULONG)(FileSize / Volume->BlockSizeInBytes);
1027
1028 // Allocate the memory for the block list
1029 BlockList = FrLdrTempAlloc(BlockCount * sizeof(ULONG), TAG_EXT_BLOCK_LIST);
1030 if (BlockList == NULL)
1031 {
1032 return NULL;
1033 }
1034
1035 RtlZeroMemory(BlockList, BlockCount * sizeof(ULONG));
1036
1037 // Copy the direct block pointers
1038 for (CurrentBlockInList = CurrentBlock = 0;
1039 CurrentBlockInList < BlockCount && CurrentBlock < INDIRECT_BLOCKS;
1040 CurrentBlock++, CurrentBlockInList++)
1041 {
1042 BlockList[CurrentBlockInList] = Inode->blocks.dir_blocks[CurrentBlock];
1043 }
1044
1045 // Copy the indirect block pointers
1046 if (CurrentBlockInList < BlockCount)
1047 {
1048 if (!Ext2CopyIndirectBlockPointers(Volume, BlockList, &CurrentBlockInList, BlockCount, Inode->blocks.indir_block))
1049 {
1051 return NULL;
1052 }
1053 }
1054
1055 // Copy the double indirect block pointers
1056 if (CurrentBlockInList < BlockCount)
1057 {
1058 if (!Ext2CopyDoubleIndirectBlockPointers(Volume, BlockList, &CurrentBlockInList, BlockCount, Inode->blocks.double_indir_block))
1059 {
1061 return NULL;
1062 }
1063 }
1064
1065 // Copy the triple indirect block pointers
1066 if (CurrentBlockInList < BlockCount)
1067 {
1068 if (!Ext2CopyTripleIndirectBlockPointers(Volume, BlockList, &CurrentBlockInList, BlockCount, Inode->blocks.tripple_indir_block))
1069 {
1071 return NULL;
1072 }
1073 }
1074
1075 return BlockList;
1076}
1077
1079{
1080 if ((Inode->mode & EXT2_S_IFMT) == EXT2_S_IFDIR)
1081 {
1082 return (ULONGLONG)(Inode->size);
1083 }
1084 else
1085 {
1086 return ((ULONGLONG)(Inode->size) | ((ULONGLONG)(Inode->dir_acl) << 32));
1087 }
1088}
1089
1090BOOLEAN Ext2CopyIndirectBlockPointers(PEXT2_VOLUME_INFO Volume, ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG IndirectBlock)
1091{
1092 ULONG* BlockBuffer;
1093 ULONG CurrentBlock;
1094 ULONG BlockPointersPerBlock;
1095
1096 TRACE("Ext2CopyIndirectBlockPointers() BlockCount = %d\n", BlockCount);
1097
1098 BlockPointersPerBlock = Volume->BlockSizeInBytes / sizeof(ULONG);
1099
1100 BlockBuffer = FrLdrTempAlloc(Volume->BlockSizeInBytes, TAG_EXT_BUFFER);
1101 if (!BlockBuffer)
1102 {
1103 return FALSE;
1104 }
1105
1106 if (!Ext2ReadBlock(Volume, IndirectBlock, BlockBuffer))
1107 {
1108 return FALSE;
1109 }
1110
1111 for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++)
1112 {
1113 BlockList[(*CurrentBlockInList)] = BlockBuffer[CurrentBlock];
1114 (*CurrentBlockInList)++;
1115 }
1116
1117 FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1118
1119 return TRUE;
1120}
1121
1122BOOLEAN Ext2CopyDoubleIndirectBlockPointers(PEXT2_VOLUME_INFO Volume, ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG DoubleIndirectBlock)
1123{
1124 ULONG* BlockBuffer;
1125 ULONG CurrentBlock;
1126 ULONG BlockPointersPerBlock;
1127
1128 TRACE("Ext2CopyDoubleIndirectBlockPointers() BlockCount = %d\n", BlockCount);
1129
1130 BlockPointersPerBlock = Volume->BlockSizeInBytes / sizeof(ULONG);
1131
1132 BlockBuffer = (ULONG*)FrLdrTempAlloc(Volume->BlockSizeInBytes, TAG_EXT_BUFFER);
1133 if (BlockBuffer == NULL)
1134 {
1135 return FALSE;
1136 }
1137
1138 if (!Ext2ReadBlock(Volume, DoubleIndirectBlock, BlockBuffer))
1139 {
1140 FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1141 return FALSE;
1142 }
1143
1144 for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++)
1145 {
1146 if (!Ext2CopyIndirectBlockPointers(Volume, BlockList, CurrentBlockInList, BlockCount, BlockBuffer[CurrentBlock]))
1147 {
1148 FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1149 return FALSE;
1150 }
1151 }
1152
1153 FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1154 return TRUE;
1155}
1156
1157BOOLEAN Ext2CopyTripleIndirectBlockPointers(PEXT2_VOLUME_INFO Volume, ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG TripleIndirectBlock)
1158{
1159 ULONG* BlockBuffer;
1160 ULONG CurrentBlock;
1161 ULONG BlockPointersPerBlock;
1162
1163 TRACE("Ext2CopyTripleIndirectBlockPointers() BlockCount = %d\n", BlockCount);
1164
1165 BlockPointersPerBlock = Volume->BlockSizeInBytes / sizeof(ULONG);
1166
1167 BlockBuffer = (ULONG*)FrLdrTempAlloc(Volume->BlockSizeInBytes, TAG_EXT_BUFFER);
1168 if (BlockBuffer == NULL)
1169 {
1170 return FALSE;
1171 }
1172
1173 if (!Ext2ReadBlock(Volume, TripleIndirectBlock, BlockBuffer))
1174 {
1175 FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1176 return FALSE;
1177 }
1178
1179 for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++)
1180 {
1181 if (!Ext2CopyDoubleIndirectBlockPointers(Volume, BlockList, CurrentBlockInList, BlockCount, BlockBuffer[CurrentBlock]))
1182 {
1183 FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1184 return FALSE;
1185 }
1186 }
1187
1188 FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1189 return TRUE;
1190}
1191
1193{
1196 return ESUCCESS;
1197}
1198
1200{
1202
1204 Information->EndingAddress.QuadPart = FileHandle->FileSize;
1205 Information->CurrentAddress.QuadPart = FileHandle->FilePointer;
1206
1207 TRACE("Ext2GetFileInformation(%lu) -> FileSize = %llu, FilePointer = 0x%llx\n",
1208 FileId, Information->EndingAddress.QuadPart, Information->CurrentAddress.QuadPart);
1209
1210 return ESUCCESS;
1211}
1212
1214{
1217 ULONG DeviceId;
1218
1219 /* Check parameters */
1220 if (OpenMode != OpenReadOnly)
1221 return EACCES;
1222
1223 /* Get underlying device */
1224 DeviceId = FsGetDeviceId(*FileId);
1225 Volume = Ext2Volumes[DeviceId];
1226
1227 TRACE("Ext2Open() FileName = %s\n", Path);
1228
1229 /* Call the internal open method */
1230 // Status = Ext2OpenFile(Volume, Path, &FileHandle);
1232 if (!FileHandle)
1233 return ENOENT;
1234
1235 /* Success, remember the handle */
1237 return ESUCCESS;
1238}
1239
1241{
1243 ULONGLONG BytesReadBig;
1245
1246 //
1247 // Read data
1248 //
1249 Success = Ext2ReadFileBig(FileHandle, N, &BytesReadBig, Buffer);
1250 *Count = (ULONG)BytesReadBig;
1251
1252 //
1253 // Check for success
1254 //
1255 if (Success)
1256 return ESUCCESS;
1257 else
1258 return EIO;
1259}
1260
1262{
1264 LARGE_INTEGER NewPosition = *Position;
1265
1266 switch (SeekMode)
1267 {
1268 case SeekAbsolute:
1269 break;
1270 case SeekRelative:
1271 NewPosition.QuadPart += FileHandle->FilePointer;
1272 break;
1273 default:
1274 ASSERT(FALSE);
1275 return EINVAL;
1276 }
1277
1278 if (NewPosition.QuadPart >= FileHandle->FileSize)
1279 return EINVAL;
1280
1281 FileHandle->FilePointer = NewPosition.QuadPart;
1282 return ESUCCESS;
1283}
1284
1286{
1287 Ext2Close,
1289 Ext2Open,
1290 Ext2Read,
1291 Ext2Seek,
1292 L"ext2fs",
1293};
1294
1295const DEVVTBL* Ext2Mount(ULONG DeviceId)
1296{
1298 EXT2_SUPER_BLOCK SuperBlock;
1300 ULONG Count;
1302
1303 TRACE("Enter Ext2Mount(%lu)\n", DeviceId);
1304
1305 /* Allocate data for volume information */
1307 if (!Volume)
1308 return NULL;
1310
1311 /* Read the SuperBlock */
1312 Position.QuadPart = 2 * 512;
1313 Status = ArcSeek(DeviceId, &Position, SeekAbsolute);
1314 if (Status != ESUCCESS)
1315 {
1317 return NULL;
1318 }
1319 Status = ArcRead(DeviceId, &SuperBlock, sizeof(SuperBlock), &Count);
1320 if (Status != ESUCCESS || Count != sizeof(SuperBlock))
1321 {
1323 return NULL;
1324 }
1325
1326 /* Check if SuperBlock is valid. If yes, return Ext2 function table. */
1327 if (SuperBlock.magic != EXT2_MAGIC)
1328 {
1330 return NULL;
1331 }
1332
1333 Volume->DeviceId = DeviceId;
1334
1335 /* Really open the volume */
1336 if (!Ext2OpenVolume(Volume))
1337 {
1339 return NULL;
1340 }
1341
1342 /* Remember EXT2 volume information */
1343 Ext2Volumes[DeviceId] = Volume;
1344
1345 /* Return success */
1346 TRACE("Ext2Mount(%lu) success\n", DeviceId);
1347 return &Ext2FuncTable;
1348}
1349
1350#endif
#define N
Definition: crc32.c:57
unsigned char BOOLEAN
unsigned int UINT32
PRTL_UNICODE_STRING_BUFFER Path
#define ENOENT
Definition: acclib.h:79
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
#define EINVAL
Definition: acclib.h:90
#define EIO
Definition: acclib.h:81
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
#define EACCES
Definition: acclib.h:85
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
BOOLEAN CacheReadDiskSectors(UCHAR DiskNumber, ULONGLONG StartSector, ULONG SectorCount, PVOID Buffer)
Definition: cache.c:113
BOOLEAN CacheInitializeDrive(UCHAR DriveNumber)
Definition: cache.c:37
#define DbgDumpBuffer(mask, buf, len)
Definition: debug.h:119
#define DPRINT_FILESYSTEM
Definition: debug.h:26
#define DBG_DEFAULT_CHANNEL(ch)
Definition: debug.h:103
#define EXT2_S_IFMT
Definition: ext2.h:218
#define FAST_SYMLINK_MAX_NAME_SIZE
Definition: ext2.h:227
#define EXT2_INODE_SIZE(sb)
Definition: ext2.h:192
#define EXT2_NAME_LEN
Definition: ext2.h:156
#define EXT2_DESC_PER_BLOCK(s)
Definition: ext2.h:196
struct ext2_dirent * PEXT2_DIR_ENTRY
Definition: ext2.h:174
#define EXT2_S_IFDIR
Definition: ext2.h:221
struct ext2_block_group * PEXT2_GROUP_DESC
Definition: ext2.h:173
#define INDIRECT_BLOCKS
Definition: ext2.h:45
#define EXT2_MAGIC
Definition: ext2.h:43
struct ext2_sblock * PEXT2_SUPER_BLOCK
Definition: ext2.h:171
#define EXT2_S_IFREG
Definition: ext2.h:223
#define EXT2_ROOT_INO
Definition: ext2.h:177
#define EXT3_FEATURE_INCOMPAT_SUPP
Definition: ext2.h:180
#define EXT2_DYNAMIC_REVISION
Definition: ext2.h:53
#define EXT2_S_IFLNK
Definition: ext2.h:224
ARC_STATUS ArcSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: fs.c:243
ULONG FsGetNumPathParts(PCSTR Path)
Definition: fs.c:328
VOID FileSystemError(PCSTR ErrorString)
Definition: fs.c:259
ULONG FsGetDeviceId(ULONG FileId)
Definition: fs.c:423
VOID * FsGetDeviceSpecific(ULONG FileId)
Definition: fs.c:416
#define MAX_FDS
Definition: fs.h:34
#define SECTOR_SIZE
Definition: fs.h:22
ARC_STATUS ArcRead(ULONG FileId, VOID *Buffer, ULONG N, ULONG *Count)
Definition: fs.c:236
VOID FsSetDeviceSpecific(ULONG FileId, VOID *Specific)
Definition: fs.c:409
VOID FsGetFirstNameFromPath(PCHAR Buffer, PCSTR Path)
Definition: fs.c:356
FORCEINLINE PVOID FrLdrTempAlloc(_In_ SIZE_T Size, _In_ ULONG Tag)
Definition: mm.h:188
FORCEINLINE VOID FrLdrTempFree(PVOID Allocation, ULONG Tag)
Definition: mm.h:197
#define TAG_EXT_VOLUME
Definition: ext2.c:72
BOOLEAN Ext2ReadSuperBlock(PEXT2_VOLUME_INFO Volume)
Definition: ext2.c:572
BOOLEAN Ext2ReadDirectory(PEXT2_VOLUME_INFO Volume, ULONG Inode, PVOID *DirectoryBuffer, PEXT2_INODE InodePointer)
Definition: ext2.c:768
BOOLEAN Ext2CopyDoubleIndirectBlockPointers(PEXT2_VOLUME_INFO Volume, ULONG *BlockList, ULONG *CurrentBlockInList, ULONG BlockCount, ULONG DoubleIndirectBlock)
Definition: ext2.c:1122
ULONGLONG Ext2GetInodeFileSize(PEXT2_INODE Inode)
Definition: ext2.c:1078
BOOLEAN Ext2ReadVolumeSectors(PEXT2_VOLUME_INFO Volume, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer)
Definition: ext2.c:541
PEXT2_VOLUME_INFO Ext2Volumes[MAX_FDS]
Definition: ext2.c:65
BOOLEAN Ext2OpenVolume(PEXT2_VOLUME_INFO Volume)
Definition: ext2.c:74
#define TAG_EXT_BLOCK_LIST
Definition: ext2.c:67
struct _EXT2_VOLUME_INFO EXT2_VOLUME_INFO
ARC_STATUS Ext2Open(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
Definition: ext2.c:1213
ARC_STATUS Ext2Seek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: ext2.c:1261
ULONG Ext2GetInodeGroupNumber(PEXT2_VOLUME_INFO Volume, ULONG Inode)
Definition: ext2.c:892
ULONG * Ext2ReadBlockPointerList(PEXT2_VOLUME_INFO Volume, PEXT2_INODE Inode)
Definition: ext2.c:1008
BOOLEAN Ext2CopyIndirectBlockPointers(PEXT2_VOLUME_INFO Volume, ULONG *BlockList, ULONG *CurrentBlockInList, ULONG BlockCount, ULONG IndirectBlock)
Definition: ext2.c:1090
#define TAG_EXT_FILE
Definition: ext2.c:68
ARC_STATUS Ext2Close(ULONG FileId)
Definition: ext2.c:1192
BOOLEAN Ext2ReadFileBig(PEXT2_FILE_INFO Ext2FileInfo, ULONGLONG BytesToRead, ULONGLONG *BytesRead, PVOID Buffer)
Definition: ext2.c:359
BOOLEAN Ext2ReadBlock(PEXT2_VOLUME_INFO Volume, ULONG BlockNumber, PVOID Buffer)
Definition: ext2.c:828
ARC_STATUS Ext2Read(ULONG FileId, VOID *Buffer, ULONG N, ULONG *Count)
Definition: ext2.c:1240
ULONG Ext2GetInodeOffsetInBlock(PEXT2_VOLUME_INFO Volume, ULONG Inode)
Definition: ext2.c:902
ULONG Ext2GetInodeBlockNumber(PEXT2_VOLUME_INFO Volume, ULONG Inode)
Definition: ext2.c:897
BOOLEAN Ext2ReadGroupDescriptors(PEXT2_VOLUME_INFO Volume)
Definition: ext2.c:726
#define TAG_EXT_BUFFER
Definition: ext2.c:69
const DEVVTBL Ext2FuncTable
Definition: ext2.c:1285
ARC_STATUS Ext2GetFileInformation(ULONG FileId, FILEINFORMATION *Information)
Definition: ext2.c:1199
BOOLEAN Ext2ReadPartialBlock(PEXT2_VOLUME_INFO Volume, ULONG BlockNumber, ULONG StartingOffset, ULONG Length, PVOID Buffer)
Definition: ext2.c:859
BOOLEAN Ext2ReadInode(PEXT2_VOLUME_INFO Volume, ULONG Inode, PEXT2_INODE InodeBuffer)
Definition: ext2.c:907
BOOLEAN Ext2ReadGroupDescriptor(PEXT2_VOLUME_INFO Volume, ULONG Group, PEXT2_GROUP_DESC GroupBuffer)
Definition: ext2.c:983
PEXT2_FILE_INFO Ext2OpenFile(PEXT2_VOLUME_INFO Volume, PCSTR FileName)
Definition: ext2.c:103
BOOLEAN Ext2CopyTripleIndirectBlockPointers(PEXT2_VOLUME_INFO Volume, ULONG *BlockList, ULONG *CurrentBlockInList, ULONG BlockCount, ULONG TripleIndirectBlock)
Definition: ext2.c:1157
BOOLEAN Ext2SearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PEXT2_DIR_ENTRY DirectoryEntry)
Definition: ext2.c:303
BOOLEAN Ext2LookupFile(PEXT2_VOLUME_INFO Volume, PCSTR FileName, PEXT2_FILE_INFO Ext2FileInfo)
Definition: ext2.c:205
#define TAG_EXT_GROUP_DESC
Definition: ext2.c:71
#define TAG_EXT_SUPER_BLOCK
Definition: ext2.c:70
const DEVVTBL * Ext2Mount(ULONG DeviceId)
Definition: ext2.c:1295
while(CdLookupNextInitialFileDirent(IrpContext, Fcb, FileContext))
_In_ PFCB _In_ LONGLONG StartingOffset
Definition: cdprocs.h:291
Definition: bufpool.h:45
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define _strnicmp(_String1, _String2, _MaxCount)
Definition: compat.h:23
@ Success
Definition: eventcreate.c:712
#define ROUND_UP(n, align)
Definition: eventvwr.h:34
_Must_inspect_result_ _In_opt_ PFLT_INSTANCE _Out_ PHANDLE FileHandle
Definition: fltkernel.h:1231
_Must_inspect_result_ _Out_ PLARGE_INTEGER FileSize
Definition: fsrtlfuncs.h:108
Status
Definition: gdiplustypes.h:25
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
signed char * PCHAR
Definition: retypes.h:7
void * PVOID
Definition: retypes.h:9
unsigned char * PUCHAR
Definition: retypes.h:3
unsigned int ULONG
Definition: retypes.h:1
UNICODE_STRING Volume
Definition: fltkernel.h:1172
#define ASSERT(a)
Definition: mode.c:44
#define sprintf(buf, format,...)
Definition: sprintf.c:55
_In_opt_ PSID Group
Definition: rtlfuncs.h:1646
int Count
Definition: noreturn.cpp:7
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
#define L(x)
Definition: ntvdm.h:50
ULONG SectorCount
Definition: part_xbox.c:31
@ ESUCCESS
Definition: arc.h:32
ULONG ARC_STATUS
Definition: arc.h:4
@ SeekRelative
Definition: arc.h:60
@ SeekAbsolute
Definition: arc.h:59
enum _OPENMODE OPENMODE
enum _SEEKMODE SEEKMODE
@ OpenReadOnly
Definition: arc.h:65
#define TRACE(s)
Definition: solgame.cpp:4
ULONG * FileBlockList
Definition: ext2.h:235
PEXT2_VOLUME_INFO Volume
Definition: ext2.h:237
ULONGLONG FilePointer
Definition: ext2.h:234
ULONGLONG FileSize
Definition: ext2.h:233
EXT2_INODE Inode
Definition: ext2.h:236
ULONG InodesPerBlock
Definition: ext2.c:58
PEXT2_GROUP_DESC GroupDescriptors
Definition: ext2.c:51
ULONG BlockSizeInSectors
Definition: ext2.c:54
ULONG BlockSizeInBytes
Definition: ext2.c:53
PEXT2_SUPER_BLOCK SuperBlock
Definition: ext2.c:50
ULONG BytesPerSector
Definition: ext2.c:48
ULONG FragmentSizeInSectors
Definition: ext2.c:56
ULONG DeviceId
Definition: ext2.c:61
ULONG GroupCount
Definition: ext2.c:57
ULONG GroupDescPerBlock
Definition: ext2.c:59
ULONG FragmentSizeInBytes
Definition: ext2.c:55
ULONG inode_table_id
Definition: ext2.h:114
USHORT free_inodes
Definition: ext2.h:116
USHORT used_dirs
Definition: ext2.h:117
ULONG inode_id
Definition: ext2.h:113
USHORT free_blocks
Definition: ext2.h:115
ULONG block_id
Definition: ext2.h:112
UCHAR namelen
Definition: ext2.h:162
ULONG inode
Definition: ext2.h:160
UCHAR filetype
Definition: ext2.h:163
CHAR name[EXT2_NAME_LEN]
Definition: ext2.h:164
USHORT direntlen
Definition: ext2.h:161
ULONG osd2[3]
Definition: ext2.h:152
ULONG ctime
Definition: ext2.h:129
ULONG size
Definition: ext2.h:127
USHORT nlinks
Definition: ext2.h:133
ULONG version
Definition: ext2.h:148
struct ext2_inode::@163::datablocks blocks
ULONG acl
Definition: ext2.h:149
char symlink[60]
Definition: ext2.h:146
ULONG mtime
Definition: ext2.h:130
ULONG flags
Definition: ext2.h:135
USHORT gid
Definition: ext2.h:132
ULONG dir_acl
Definition: ext2.h:150
USHORT mode
Definition: ext2.h:125
ULONG blockcnt
Definition: ext2.h:134
ULONG osd1
Definition: ext2.h:136
ULONG fragment_addr
Definition: ext2.h:151
USHORT uid
Definition: ext2.h:126
ULONG atime
Definition: ext2.h:128
ULONG dtime
Definition: ext2.h:131
ULONG revision_level
Definition: ext2.h:93
USHORT max_mnt_count
Definition: ext2.h:85
ULONG feature_ro_compat
Definition: ext2.h:101
char last_mounted_on[64]
Definition: ext2.h:104
ULONG compression_info
Definition: ext2.h:105
ULONG feature_compatibility
Definition: ext2.h:99
ULONG free_blocks
Definition: ext2.h:74
ULONG reserved_blocks
Definition: ext2.h:73
USHORT block_group_number
Definition: ext2.h:98
ULONG mtime
Definition: ext2.h:82
ULONG utime
Definition: ext2.h:83
USHORT error_handling
Definition: ext2.h:88
ULONG first_inode
Definition: ext2.h:96
ULONG log2_block_size
Definition: ext2.h:77
USHORT fs_state
Definition: ext2.h:87
char volume_name[16]
Definition: ext2.h:103
ULONG total_inodes
Definition: ext2.h:71
USHORT inode_size
Definition: ext2.h:97
LONG log2_fragment_size
Definition: ext2.h:78
ULONG free_inodes
Definition: ext2.h:75
ULONG inodes_per_group
Definition: ext2.h:81
USHORT magic
Definition: ext2.h:86
USHORT gid_reserved
Definition: ext2.h:95
USHORT minor_revision_level
Definition: ext2.h:89
ULONG total_blocks
Definition: ext2.h:72
USHORT uid_reserved
Definition: ext2.h:94
ULONG fragments_per_group
Definition: ext2.h:80
ULONG checkinterval
Definition: ext2.h:91
ULONG unique_id[4]
Definition: ext2.h:102
ULONG feature_incompat
Definition: ext2.h:100
ULONG blocks_per_group
Definition: ext2.h:79
USHORT mnt_count
Definition: ext2.h:84
ULONG lastcheck
Definition: ext2.h:90
ULONG creator_os
Definition: ext2.h:92
ULONG first_data_block
Definition: ext2.h:76
Definition: fs.h:25
static COORD Position
Definition: mouse.c:34
const char * PCSTR
Definition: typedefs.h:52
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
uint64_t ULONGLONG
Definition: typedefs.h:67
LONGLONG QuadPart
Definition: typedefs.h:114
_In_ WDFCOLLECTION _In_ ULONG Index
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR _In_opt_ PLONGLONG _In_opt_ PWDF_REQUEST_SEND_OPTIONS _Out_opt_ PULONG_PTR BytesRead
Definition: wdfiotarget.h:870
_In_ WDFREQUEST _In_ NTSTATUS _In_ ULONG_PTR Information
Definition: wdfrequest.h:1049
char CHAR
Definition: xmlstorage.h:175