ReactOS 0.4.16-dev-1946-g52006dd
ext.c
Go to the documentation of this file.
1/*
2 * FreeLoader
3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 * Copyright (C) 2024-2025 Daniel Victor <ilauncherdeveloper@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#ifndef _M_ARM
22#include <freeldr.h>
23#include "fs/stat.h"
24
25#include <debug.h>
27
31BOOLEAN ExtSearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PEXT_DIR_ENTRY DirectoryEntry);
33
37BOOLEAN ExtReadDirectory(PEXT_VOLUME_INFO Volume, ULONG Inode, PVOID* DirectoryBuffer, PEXT_INODE InodePointer);
44BOOLEAN ExtCopyBlockPointersByExtents(PEXT_VOLUME_INFO Volume, ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, PEXT4_EXTENT_HEADER ExtentHeader);
45BOOLEAN ExtCopyIndirectBlockPointers(PEXT_VOLUME_INFO Volume, ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG IndirectBlock);
46BOOLEAN ExtCopyDoubleIndirectBlockPointers(PEXT_VOLUME_INFO Volume, ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG DoubleIndirectBlock);
47BOOLEAN ExtCopyTripleIndirectBlockPointers(PEXT_VOLUME_INFO Volume, ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG TripleIndirectBlock);
48
49typedef struct _EXT_VOLUME_INFO
50{
51 ULONG BytesPerSector; // Usually 512...
52
53 PEXT_SUPER_BLOCK SuperBlock; // Ext file system super block
54 PEXT_GROUP_DESC GroupDescriptors; // Ext file system group descriptors
55
56 ULONG BlockSizeInBytes; // Block size in bytes
57 ULONG BlockSizeInSectors; // Block size in sectors
58 ULONG FragmentSizeInBytes; // Fragment size in bytes
59 ULONG FragmentSizeInSectors; // Fragment size in sectors
60 ULONG InodeSizeInBytes; // Inode size in bytes
61 ULONG GroupDescSizeInBytes; // Group descriptor size in bytes
62 ULONG GroupCount; // Number of groups in this file system
63 ULONG InodesPerBlock; // Number of inodes in one block
64 ULONG GroupDescPerBlock; // Number of group descriptors in one block
65
66 ULONG DeviceId; // Ext file system device ID
67
69
71
72#define TAG_EXT_BLOCK_LIST 'LtxE'
73#define TAG_EXT_FILE 'FtxE'
74#define TAG_EXT_BUFFER 'BtxE'
75#define TAG_EXT_SUPER_BLOCK 'StxE'
76#define TAG_EXT_GROUP_DESC 'GtxE'
77#define TAG_EXT_VOLUME 'VtxE'
78
80{
81 TRACE("ExtOpenVolume() DeviceId = %d\n", Volume->DeviceId);
82
83#if 0
84 /* Initialize the disk cache for this drive */
85 if (!CacheInitializeDrive(DriveNumber))
86 {
87 return FALSE;
88 }
89#endif
90 Volume->BytesPerSector = SECTOR_SIZE;
91
92 /* Read in the super block */
94 return FALSE;
95
96 /* Read in the group descriptors */
98 return FALSE;
99
100 return TRUE;
101}
102
103/*
104 * ExtOpenFile()
105 * Tries to open the file 'name' and returns true or false
106 * for success and failure respectively
107 */
109{
110 EXT_FILE_INFO TempExtFileInfo;
115
116 TRACE("ExtOpenFile() FileName = \"%s\"\n", FileName);
117
118 RtlZeroMemory(SymLinkPath, sizeof(SymLinkPath));
119
120 // Lookup the file in the file system
121 if (!ExtLookupFile(Volume, FileName, &TempExtFileInfo))
122 {
123 return NULL;
124 }
125
126 // If we got a symbolic link then fix up the path
127 // and re-call this function
128 if (_S_ISLNK(TempExtFileInfo.Inode.Mode))
129 {
130 TRACE("File is a symbolic link\n");
131
132 // Now read in the symbolic link path
133 if (!ExtReadFileBig(&TempExtFileInfo, TempExtFileInfo.FileSize, NULL, SymLinkPath))
134 {
135 if (TempExtFileInfo.FileBlockList != NULL)
136 {
138 }
139
140 return NULL;
141 }
142
143 TRACE("Symbolic link path = \"%s\"\n", SymLinkPath);
144
145 // Get the full path
146 if (SymLinkPath[0] == '/' || SymLinkPath[0] == '\\')
147 {
148 // Symbolic link is an absolute path
149 // So copy it to FullPath, but skip over
150 // the '/' character at the beginning
151 strcpy(FullPath, &SymLinkPath[1]);
152 }
153 else
154 {
155 // Symbolic link is a relative path
156 // Copy the first part of the path
157 strcpy(FullPath, FileName);
158
159 // Remove the last part of the path
160 for (Index=strlen(FullPath); Index>0; )
161 {
162 Index--;
163 if (FullPath[Index] == '/' || FullPath[Index] == '\\')
164 {
165 break;
166 }
167 }
168 FullPath[Index] = '\0';
169
170 // Concatenate the symbolic link
171 strcat(FullPath, Index == 0 ? "" : "/");
172 strcat(FullPath, SymLinkPath);
173 }
174
175 TRACE("Full file path = \"%s\"\n", FullPath);
176
177 if (TempExtFileInfo.FileBlockList != NULL)
178 {
180 }
181
182 return ExtOpenFile(Volume, FullPath);
183 }
184 else
185 {
187 if (FileHandle == NULL)
188 {
189 if (TempExtFileInfo.FileBlockList != NULL)
190 {
192 }
193
194 return NULL;
195 }
196
197 RtlCopyMemory(FileHandle, &TempExtFileInfo, sizeof(EXT_FILE_INFO));
198
199 return FileHandle;
200 }
201}
202
203/*
204 * ExtLookupFile()
205 * This function searches the file system for the
206 * specified filename and fills in a EXT_FILE_INFO structure
207 * with info describing the file, etc. returns true
208 * if the file exists or false otherwise
209 */
211{
212 ULONG NumberOfPathParts;
213 ULONG i;
214 CHAR PathPart[261];
215 PVOID DirectoryBuffer;
216 ULONG DirectoryInode = EXT_ROOT_INODE;
217 EXT_INODE InodeData;
218 EXT_DIR_ENTRY DirectoryEntry;
219
220 TRACE("ExtLookupFile() FileName = \"%s\"\n", FileName);
221
222 RtlZeroMemory(ExtFileInfo, sizeof(EXT_FILE_INFO));
223
224 /* Skip leading path separator, if any */
225 if (*FileName == '\\' || *FileName == '/')
226 ++FileName;
227 //
228 // Figure out how many sub-directories we are nested in
229 //
230 NumberOfPathParts = FsGetNumPathParts(FileName);
231
232 //
233 // Loop once for each part
234 //
235 for (i=0; i<NumberOfPathParts; i++)
236 {
237 //
238 // Get first path part
239 //
241
242 //
243 // Advance to the next part of the path
244 //
245 for (; (*FileName != '\\') && (*FileName != '/') && (*FileName != '\0'); FileName++)
246 {
247 }
248 FileName++;
249
250 //
251 // Buffer the directory contents
252 //
253 if (!ExtReadDirectory(Volume, DirectoryInode, &DirectoryBuffer, &InodeData))
254 {
255 return FALSE;
256 }
257
258 //
259 // Search for file name in directory
260 //
261 if (!ExtSearchDirectoryBufferForFile(DirectoryBuffer, (ULONG)ExtGetInodeFileSize(&InodeData), PathPart, &DirectoryEntry))
262 {
263 FrLdrTempFree(DirectoryBuffer, TAG_EXT_BUFFER);
264 return FALSE;
265 }
266
267 FrLdrTempFree(DirectoryBuffer, TAG_EXT_BUFFER);
268
269 DirectoryInode = DirectoryEntry.Inode;
270 }
271
272 if (!ExtReadInode(Volume, DirectoryInode, &InodeData))
273 {
274 return FALSE;
275 }
276
277 if (!_S_ISREG(InodeData.Mode) && !_S_ISLNK(InodeData.Mode))
278 {
279 FileSystemError("Inode is not a regular file or symbolic link.");
280 return FALSE;
281 }
282
283 // Set the associated volume
284 ExtFileInfo->Volume = Volume;
285
286 // If it's a regular file or a regular symbolic link
287 // then get the block pointer list otherwise it must
288 // be a fast symbolic link which doesn't have a block list
289 if (_S_ISREG(InodeData.Mode) ||
290 (_S_ISLNK(InodeData.Mode) && InodeData.Size > FAST_SYMLINK_MAX_NAME_SIZE))
291 {
292 ExtFileInfo->FileBlockList = ExtReadBlockPointerList(Volume, &InodeData);
293 if (ExtFileInfo->FileBlockList == NULL)
294 {
295 return FALSE;
296 }
297 }
298 else
299 {
300 ExtFileInfo->FileBlockList = NULL;
301 }
302
303 ExtFileInfo->FilePointer = 0;
304 ExtFileInfo->FileSize = ExtGetInodeFileSize(&InodeData);
305 RtlCopyMemory(&ExtFileInfo->Inode, &InodeData, sizeof(InodeData));
306
307 /* Map the attributes to ARC file attributes */
308 ExtFileInfo->Attributes = 0;
309 if (!(InodeData.Mode & (_S_IWUSR | _S_IWGRP | _S_IWOTH)))
310 ExtFileInfo->Attributes |= ReadOnlyFile;
311 if (_S_ISDIR(InodeData.Mode))
312 ExtFileInfo->Attributes |= DirectoryFile;
313
314 /* Set hidden attribute for all entries starting with '.' */
315 if ((DirectoryEntry.NameLen >= 2 && DirectoryEntry.Name[0] == '.') &&
316 ((DirectoryEntry.NameLen == 2 && DirectoryEntry.Name[1] != '.') ||
317 DirectoryEntry.NameLen >= 3))
318 {
319 ExtFileInfo->Attributes |= HiddenFile;
320 }
321
322 /* Copy the file name, perhaps truncated */
323 ExtFileInfo->FileNameLength = DirectoryEntry.NameLen; // (ULONG)strlen(PathPart);
324 ExtFileInfo->FileNameLength = min(ExtFileInfo->FileNameLength, sizeof(ExtFileInfo->FileName) - 1);
325 RtlCopyMemory(ExtFileInfo->FileName, DirectoryEntry.Name /*PathPart*/, ExtFileInfo->FileNameLength);
326
327 return TRUE;
328}
329
330BOOLEAN ExtSearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PEXT_DIR_ENTRY DirectoryEntry)
331{
332 PEXT_DIR_ENTRY CurrentDirectoryEntry;
333 ULONG CurrentOffset = 0;
335
336 TRACE("ExtSearchDirectoryBufferForFile() DirectoryBuffer = 0x%x DirectorySize = %d FileName = \"%s\"\n", DirectoryBuffer, DirectorySize, FileName);
337
339
340 while (CurrentOffset < DirectorySize)
341 {
342 CurrentDirectoryEntry = (PEXT_DIR_ENTRY)((ULONG_PTR)DirectoryBuffer + CurrentOffset);
343
344 if (!CurrentDirectoryEntry->EntryLen)
345 break;
346
347 if ((CurrentDirectoryEntry->EntryLen + CurrentOffset) > DirectorySize)
348 {
349 FileSystemError("Directory entry extends past end of directory file.");
350 return FALSE;
351 }
352
353 if (!CurrentDirectoryEntry->Inode)
354 goto NextDirectoryEntry;
355
356 TRACE("EXT Directory Entry:\n");
357 TRACE("Inode = %d\n", CurrentDirectoryEntry->Inode);
358 TRACE("EntryLen = %d\n", CurrentDirectoryEntry->EntryLen);
359 TRACE("NameLen = %d\n", CurrentDirectoryEntry->NameLen);
360 TRACE("FileType = %d\n", CurrentDirectoryEntry->FileType);
361 TRACE("Name = \"");
362 for (ULONG NameOffset = 0; NameOffset < CurrentDirectoryEntry->NameLen; NameOffset++)
363 {
364 TRACE("%c", CurrentDirectoryEntry->Name[NameOffset]);
365 }
366 TRACE("\"\n\n");
367
368 if ((FileNameLen == CurrentDirectoryEntry->NameLen) &&
369 (_strnicmp(FileName, CurrentDirectoryEntry->Name, FileNameLen) == 0))
370 {
371 RtlCopyMemory(DirectoryEntry, CurrentDirectoryEntry, sizeof(EXT_DIR_ENTRY));
372 return TRUE;
373 }
374
375NextDirectoryEntry:
376 CurrentOffset += CurrentDirectoryEntry->EntryLen;
377 }
378
379 return FALSE;
380}
381
382/*
383 * ExtReadFileBig()
384 * Reads BytesToRead from open file and
385 * returns the number of bytes read in BytesRead
386 */
388{
389 PEXT_VOLUME_INFO Volume = ExtFileInfo->Volume;
390 ULONG BlockNumber;
391 ULONG BlockNumberIndex;
392 ULONG OffsetInBlock;
393 ULONG LengthInBlock;
394 ULONG NumberOfBlocks;
395
396 TRACE("ExtReadFileBig() BytesToRead = %d Buffer = 0x%x\n", (ULONG)BytesToRead, Buffer);
397
398 if (BytesRead != NULL)
399 {
400 *BytesRead = 0;
401 }
402
403 // Make sure we have the block pointer list if we need it
404 if (ExtFileInfo->FileBlockList == NULL)
405 {
406 // Block pointer list is NULL
407 // so this better be a fast symbolic link or else
408 if (!_S_ISLNK(ExtFileInfo->Inode.Mode) ||
409 (ExtFileInfo->FileSize > FAST_SYMLINK_MAX_NAME_SIZE))
410 {
411 FileSystemError("Block pointer list is NULL and file is not a fast symbolic link.");
412 return FALSE;
413 }
414 }
415
416 //
417 // If the user is trying to read past the end of
418 // the file then return success with BytesRead == 0.
419 //
420 if (ExtFileInfo->FilePointer >= ExtFileInfo->FileSize)
421 {
422 return TRUE;
423 }
424
425 //
426 // If the user is trying to read more than there is to read
427 // then adjust the amount to read.
428 //
429 if ((ExtFileInfo->FilePointer + BytesToRead) > ExtFileInfo->FileSize)
430 {
431 BytesToRead = (ExtFileInfo->FileSize - ExtFileInfo->FilePointer);
432 }
433
434 // Check if this is a fast symbolic link
435 // if so then the read is easy
436 if (_S_ISLNK(ExtFileInfo->Inode.Mode) &&
437 (ExtFileInfo->FileSize <= FAST_SYMLINK_MAX_NAME_SIZE))
438 {
439 TRACE("Reading fast symbolic link data\n");
440
441 // Copy the data from the link
442 RtlCopyMemory(Buffer, (PVOID)((ULONG_PTR)ExtFileInfo->FilePointer + ExtFileInfo->Inode.SymLink), (ULONG)BytesToRead);
443
444 if (BytesRead != NULL)
445 {
446 *BytesRead = BytesToRead;
447 }
448 // ExtFileInfo->FilePointer += BytesToRead;
449
450 return TRUE;
451 }
452
453 //
454 // Ok, now we have to perform at most 3 calculations
455 // I'll draw you a picture (using nifty ASCII art):
456 //
457 // CurrentFilePointer -+
458 // |
459 // +----------------+
460 // |
461 // +-----------+-----------+-----------+-----------+
462 // | Block 1 | Block 2 | Block 3 | Block 4 |
463 // +-----------+-----------+-----------+-----------+
464 // | |
465 // +---------------+--------------------+
466 // |
467 // BytesToRead -------+
468 //
469 // 1 - The first calculation (and read) will align
470 // the file pointer with the next block.
471 // boundary (if we are supposed to read that much)
472 // 2 - The next calculation (and read) will read
473 // in all the full blocks that the requested
474 // amount of data would cover (in this case
475 // blocks 2 & 3).
476 // 3 - The last calculation (and read) would read
477 // in the remainder of the data requested out of
478 // the last block.
479 //
480
481 //
482 // Only do the first read if we
483 // aren't aligned on a block boundary
484 //
485 if (ExtFileInfo->FilePointer % Volume->BlockSizeInBytes)
486 {
487 //
488 // Do the math for our first read
489 //
490 BlockNumberIndex = (ULONG)(ExtFileInfo->FilePointer / Volume->BlockSizeInBytes);
491 BlockNumber = ExtFileInfo->FileBlockList[BlockNumberIndex];
492 OffsetInBlock = (ExtFileInfo->FilePointer % Volume->BlockSizeInBytes);
493 LengthInBlock = (ULONG)((BytesToRead > (Volume->BlockSizeInBytes - OffsetInBlock)) ? (Volume->BlockSizeInBytes - OffsetInBlock) : BytesToRead);
494
495 //
496 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
497 //
498 if (!ExtReadPartialBlock(Volume, BlockNumber, OffsetInBlock, LengthInBlock, Buffer))
499 {
500 return FALSE;
501 }
502 if (BytesRead != NULL)
503 {
504 *BytesRead += LengthInBlock;
505 }
506 BytesToRead -= LengthInBlock;
507 ExtFileInfo->FilePointer += LengthInBlock;
508 Buffer = (PVOID)((ULONG_PTR)Buffer + LengthInBlock);
509 }
510
511 //
512 // Do the math for our second read (if any data left)
513 //
514 if (BytesToRead > 0)
515 {
516 //
517 // Determine how many full clusters we need to read
518 //
519 NumberOfBlocks = (ULONG)(BytesToRead / Volume->BlockSizeInBytes);
520
521 while (NumberOfBlocks > 0)
522 {
523 BlockNumberIndex = (ULONG)(ExtFileInfo->FilePointer / Volume->BlockSizeInBytes);
524 BlockNumber = ExtFileInfo->FileBlockList[BlockNumberIndex];
525
526 //
527 // Now do the read and update BytesRead, BytesToRead, FilePointer, & Buffer
528 //
529 if (!ExtReadBlock(Volume, BlockNumber, Buffer))
530 {
531 return FALSE;
532 }
533 if (BytesRead != NULL)
534 {
535 *BytesRead += Volume->BlockSizeInBytes;
536 }
537 BytesToRead -= Volume->BlockSizeInBytes;
538 ExtFileInfo->FilePointer += Volume->BlockSizeInBytes;
539 Buffer = (PVOID)((ULONG_PTR)Buffer + Volume->BlockSizeInBytes);
540 NumberOfBlocks--;
541 }
542 }
543
544 //
545 // Do the math for our third read (if any data left)
546 //
547 if (BytesToRead > 0)
548 {
549 BlockNumberIndex = (ULONG)(ExtFileInfo->FilePointer / Volume->BlockSizeInBytes);
550 BlockNumber = ExtFileInfo->FileBlockList[BlockNumberIndex];
551
552 //
553 // Now do the read and update BytesRead & FilePointer
554 //
555 if (!ExtReadPartialBlock(Volume, BlockNumber, 0, (ULONG)BytesToRead, Buffer))
556 {
557 return FALSE;
558 }
559 if (BytesRead != NULL)
560 {
561 *BytesRead += BytesToRead;
562 }
563 ExtFileInfo->FilePointer += BytesToRead;
564 }
565
566 return TRUE;
567}
568
570{
571#if 0
572 return CacheReadDiskSectors(DriveNumber, SectorNumber + ExtVolumeStartSector, SectorCount, Buffer);
573#endif
574
576 ULONG Count;
578
579 /* Seek to right position */
580 Position.QuadPart = (ULONGLONG)SectorNumber * 512;
581 Status = ArcSeek(Volume->DeviceId, &Position, SeekAbsolute);
582 if (Status != ESUCCESS)
583 {
584 TRACE("ExtReadVolumeSectors() Failed to seek\n");
585 return FALSE;
586 }
587
588 /* Read data */
589 Status = ArcRead(Volume->DeviceId, Buffer, SectorCount * 512, &Count);
590 if (Status != ESUCCESS || Count != SectorCount * 512)
591 {
592 TRACE("ExtReadVolumeSectors() Failed to read\n");
593 return FALSE;
594 }
595
596 /* Return success */
597 return TRUE;
598}
599
601{
602 PEXT_SUPER_BLOCK SuperBlock = Volume->SuperBlock;
604 ULONG Count;
606
607 TRACE("ExtReadSuperBlock()\n");
608
609#if 0
610 /* Free any memory previously allocated */
611 if (SuperBlock != NULL)
612 {
614 SuperBlock = NULL;
615 }
616#endif
617
618 /* Allocate the memory to hold the super block if needed */
619 if (SuperBlock == NULL)
620 {
622 if (SuperBlock == NULL)
623 {
624 FileSystemError("Out of memory.");
625 return FALSE;
626 }
627 }
628 Volume->SuperBlock = SuperBlock;
629
630 /* Reset its contents */
631 RtlZeroMemory(SuperBlock, 1024);
632
633 /* Read the SuperBlock */
634 Position.QuadPart = 2 * 512;
635 Status = ArcSeek(Volume->DeviceId, &Position, SeekAbsolute);
636 if (Status != ESUCCESS)
637 return FALSE;
638 Status = ArcRead(Volume->DeviceId, SuperBlock, 2 * 512, &Count);
639 if (Status != ESUCCESS || Count != 2 * 512)
640 return FALSE;
641
642 TRACE("Dumping super block:\n");
643 TRACE("InodesCount: %d\n", SuperBlock->InodesCount);
644 TRACE("BlocksCountLo: %d\n", SuperBlock->BlocksCountLo);
645 TRACE("RBlocksCountLo: %d\n", SuperBlock->RBlocksCountLo);
646 TRACE("FreeBlocksCountLo: %d\n", SuperBlock->FreeBlocksCountLo);
647 TRACE("FreeInodesCount: %d\n", SuperBlock->FreeInodesCount);
648 TRACE("FirstDataBlock: %d\n", SuperBlock->FirstDataBlock);
649 TRACE("LogBlockSize: %d\n", SuperBlock->LogBlockSize);
650 TRACE("LogFragSize: %d\n", SuperBlock->LogFragSize);
651 TRACE("BlocksPerGroup: %d\n", SuperBlock->BlocksPerGroup);
652 TRACE("FragsPerGroup: %d\n", SuperBlock->FragsPerGroup);
653 TRACE("InodesPerGroup: %d\n", SuperBlock->InodesPerGroup);
654 TRACE("MTime: %d\n", SuperBlock->MTime);
655 TRACE("WTime: %d\n", SuperBlock->WTime);
656 TRACE("MntCount: %d\n", SuperBlock->MntCount);
657 TRACE("MaxMntCount: %d\n", SuperBlock->MaxMntCount);
658 TRACE("Magic: 0x%x\n", SuperBlock->Magic);
659 TRACE("State: 0x%x\n", SuperBlock->State);
660 TRACE("Errors: 0x%x\n", SuperBlock->Errors);
661 TRACE("MinorRevisionLevel: %d\n", SuperBlock->MinorRevisionLevel);
662 TRACE("LastCheck: %d\n", SuperBlock->LastCheck);
663 TRACE("CheckInterval: %d\n", SuperBlock->CheckInterval);
664 TRACE("CreatorOS: %d\n", SuperBlock->CreatorOS);
665 TRACE("RevisionLevel: %d\n", SuperBlock->RevisionLevel);
666 TRACE("DefResUID: %d\n", SuperBlock->DefResUID);
667 TRACE("DefResGID: %d\n", SuperBlock->DefResGID);
668 TRACE("FirstInode: %d\n", SuperBlock->FirstInode);
669 TRACE("InodeSize: %d\n", SuperBlock->InodeSize);
670 TRACE("BlockGroupNr: %d\n", SuperBlock->BlockGroupNr);
671 TRACE("FeatureCompat: 0x%x\n", SuperBlock->FeatureCompat);
672 TRACE("FeatureIncompat: 0x%x\n", SuperBlock->FeatureIncompat);
673 TRACE("FeatureROCompat: 0x%x\n", SuperBlock->FeatureROCompat);
674 TRACE("UUID: { ");
675 for (ULONG i = 0; i < sizeof(SuperBlock->UUID); i++)
676 {
677 TRACE("0x%02x", SuperBlock->UUID[i]);
678 if (i < sizeof(SuperBlock->UUID) - 1)
679 TRACE(", ");
680 }
681 TRACE(" }\n");
682 TRACE("VolumeName: \"%s\"\n", SuperBlock->VolumeName);
683 TRACE("LastMounted: \"%s\"\n", SuperBlock->LastMounted);
684 TRACE("AlgorithmUsageBitmap: 0x%x\n", SuperBlock->AlgorithmUsageBitmap);
685 TRACE("PreallocBlocks: %d\n", SuperBlock->PreallocBlocks);
686 TRACE("PreallocDirBlocks: %d\n", SuperBlock->PreallocDirBlocks);
687 TRACE("ReservedGdtBlocks: %d\n", SuperBlock->ReservedGdtBlocks);
688 TRACE("JournalUUID: { ");
689 for (ULONG i = 0; i < sizeof(SuperBlock->JournalUUID); i++)
690 {
691 TRACE("0x%02x", SuperBlock->JournalUUID[i]);
692 if (i < sizeof(SuperBlock->JournalUUID) - 1)
693 TRACE(", ");
694 }
695 TRACE(" }\n");
696 TRACE("JournalInum: %d\n", SuperBlock->JournalInum);
697 TRACE("JournalDev: %d\n", SuperBlock->JournalDev);
698 TRACE("LastOrphan: %d\n", SuperBlock->LastOrphan);
699 TRACE("HashSeed: { 0x%02x, 0x%02x, 0x%02x, 0x%02x }\n",
700 SuperBlock->HashSeed[0], SuperBlock->HashSeed[1],
701 SuperBlock->HashSeed[2], SuperBlock->HashSeed[3]);
702 TRACE("DefHashVersion: %d\n", SuperBlock->DefHashVersion);
703 TRACE("JournalBackupType: %d\n", SuperBlock->JournalBackupType);
704 TRACE("GroupDescSize: %d\n", SuperBlock->GroupDescSize);
705 TRACE("DefaultMountOpts: %d\n", SuperBlock->DefaultMountOpts);
706 TRACE("FirstMetaBg: %d\n", SuperBlock->FirstMetaBg);
707 TRACE("MkfsTime: %d\n", SuperBlock->MkfsTime);
708 // ULONG JnlBlocks[17];
709 TRACE("BlocksCountHi: %d\n", SuperBlock->BlocksCountHi);
710 TRACE("RBlocksCountHi: %d\n", SuperBlock->RBlocksCountHi);
711 TRACE("FreeBlocksCountHi: %d\n", SuperBlock->FreeBlocksCountHi);
712
713 //
714 // Check the super block magic
715 //
716 if (SuperBlock->Magic != EXT_SUPERBLOCK_MAGIC)
717 {
718 FileSystemError("Invalid super block magic (0xef53)");
719 return FALSE;
720 }
721
722 // Calculate the group count
723 Volume->GroupCount = (SuperBlock->BlocksCountLo - SuperBlock->FirstDataBlock + SuperBlock->BlocksPerGroup - 1) / SuperBlock->BlocksPerGroup;
724 TRACE("ExtGroupCount: %d\n", Volume->GroupCount);
725
726 // Calculate the block size
727 Volume->BlockSizeInBytes = 1024 << SuperBlock->LogBlockSize;
728 Volume->BlockSizeInSectors = Volume->BlockSizeInBytes / Volume->BytesPerSector;
729 TRACE("ExtBlockSizeInBytes: %d\n", Volume->BlockSizeInBytes);
730 TRACE("ExtBlockSizeInSectors: %d\n", Volume->BlockSizeInSectors);
731
732 // Calculate the fragment size
733 if (SuperBlock->LogFragSize >= 0)
734 {
735 Volume->FragmentSizeInBytes = 1024 << SuperBlock->LogFragSize;
736 }
737 else
738 {
739 Volume->FragmentSizeInBytes = 1024 >> -(SuperBlock->LogFragSize);
740 }
741 Volume->FragmentSizeInSectors = Volume->FragmentSizeInBytes / Volume->BytesPerSector;
742 TRACE("ExtFragmentSizeInBytes: %d\n", Volume->FragmentSizeInBytes);
743 TRACE("ExtFragmentSizeInSectors: %d\n", Volume->FragmentSizeInSectors);
744
745 // Verify that the fragment size and the block size are equal
746 if (Volume->BlockSizeInBytes != Volume->FragmentSizeInBytes)
747 {
748 FileSystemError("The fragment size must be equal to the block size.");
749 return FALSE;
750 }
751
752 // Set the volume inode size in bytes
753 Volume->InodeSizeInBytes = EXT_INODE_SIZE(SuperBlock);
754 TRACE("InodeSizeInBytes: %d\n", Volume->InodeSizeInBytes);
755
756 // Set the volume group descriptor size in bytes
757 Volume->GroupDescSizeInBytes = EXT_GROUP_DESC_SIZE(SuperBlock);
758 TRACE("GroupDescSizeInBytes: %d\n", Volume->GroupDescSizeInBytes);
759
760 // Calculate the number of inodes in one block
761 Volume->InodesPerBlock = Volume->BlockSizeInBytes / Volume->InodeSizeInBytes;
762 TRACE("ExtInodesPerBlock: %d\n", Volume->InodesPerBlock);
763
764 // Calculate the number of group descriptors in one block
765 Volume->GroupDescPerBlock = Volume->BlockSizeInBytes / Volume->GroupDescSizeInBytes;
766 TRACE("ExtGroupDescPerBlock: %d\n", Volume->GroupDescPerBlock);
767
768 return TRUE;
769}
770
772{
773 ULONG GroupDescBlockCount;
774 ULONG BlockNumber;
775 PUCHAR CurrentGroupDescBlock;
776
777 TRACE("ExtReadGroupDescriptors()\n");
778
779 /* Free any memory previously allocated */
780 if (Volume->GroupDescriptors != NULL)
781 {
782 FrLdrTempFree(Volume->GroupDescriptors, TAG_EXT_GROUP_DESC);
783 Volume->GroupDescriptors = NULL;
784 }
785
786 /* Now allocate the memory to hold the group descriptors */
787 GroupDescBlockCount = ROUND_UP(Volume->GroupCount, Volume->GroupDescPerBlock) / Volume->GroupDescPerBlock;
788 Volume->GroupDescriptors = (PEXT_GROUP_DESC)FrLdrTempAlloc(GroupDescBlockCount * Volume->BlockSizeInBytes, TAG_EXT_GROUP_DESC);
789 if (Volume->GroupDescriptors == NULL)
790 {
791 FileSystemError("Out of memory.");
792 return FALSE;
793 }
794
795 // Now read the group descriptors
796 CurrentGroupDescBlock = (PUCHAR)Volume->GroupDescriptors;
797 BlockNumber = Volume->SuperBlock->FirstDataBlock + 1;
798
799 while (GroupDescBlockCount--)
800 {
801 if (!ExtReadBlock(Volume, BlockNumber, CurrentGroupDescBlock))
802 {
803 return FALSE;
804 }
805
806 BlockNumber++;
807 CurrentGroupDescBlock += Volume->BlockSizeInBytes;
808 }
809
810 return TRUE;
811}
812
813BOOLEAN ExtReadDirectory(PEXT_VOLUME_INFO Volume, ULONG Inode, PVOID* DirectoryBuffer, PEXT_INODE InodePointer)
814{
815 EXT_FILE_INFO DirectoryFileInfo;
816
817 TRACE("ExtReadDirectory() Inode = %d\n", Inode);
818
819 // Read the directory inode
820 if (!ExtReadInode(Volume, Inode, InodePointer))
821 {
822 return FALSE;
823 }
824
825 // Make sure it is a directory inode
826 if (!_S_ISDIR(InodePointer->Mode))
827 {
828 FileSystemError("Inode is not a directory.");
829 return FALSE;
830 }
831
832 // Fill in file info struct so we can call ExtReadFileBig()
833 RtlZeroMemory(&DirectoryFileInfo, sizeof(EXT_FILE_INFO));
834 DirectoryFileInfo.Volume = Volume;
835 DirectoryFileInfo.FileBlockList = ExtReadBlockPointerList(Volume, InodePointer);
836 DirectoryFileInfo.FilePointer = 0;
837 DirectoryFileInfo.FileSize = ExtGetInodeFileSize(InodePointer);
838
839 if (DirectoryFileInfo.FileBlockList == NULL)
840 {
841 return FALSE;
842 }
843
844 //
845 // Now allocate the memory to hold the group descriptors
846 //
847 ASSERT(DirectoryFileInfo.FileSize <= 0xFFFFFFFF);
848 *DirectoryBuffer = (PEXT_DIR_ENTRY)FrLdrTempAlloc((ULONG)DirectoryFileInfo.FileSize, TAG_EXT_BUFFER);
849
850 //
851 // Make sure we got the memory
852 //
853 if (*DirectoryBuffer == NULL)
854 {
856 FileSystemError("Out of memory.");
857 return FALSE;
858 }
859
860 // Now read the root directory data
861 if (!ExtReadFileBig(&DirectoryFileInfo, DirectoryFileInfo.FileSize, NULL, *DirectoryBuffer))
862 {
863 FrLdrTempFree(*DirectoryBuffer, TAG_EXT_BUFFER);
864 *DirectoryBuffer = NULL;
866 return FALSE;
867 }
868
870 return TRUE;
871}
872
874{
875 CHAR ErrorString[80];
876
877 TRACE("ExtReadBlock() BlockNumber = %d Buffer = 0x%x\n", BlockNumber, Buffer);
878
879 // Make sure its a valid block
880 if (BlockNumber > Volume->SuperBlock->BlocksCountLo)
881 {
882 sprintf(ErrorString, "Error reading block %d - block out of range.", (int) BlockNumber);
883 FileSystemError(ErrorString);
884 return FALSE;
885 }
886
887 // Check to see if this is a sparse block
888 if (BlockNumber == 0)
889 {
890 TRACE("Block is part of a sparse file. Zeroing input buffer.\n");
891
892 RtlZeroMemory(Buffer, Volume->BlockSizeInBytes);
893
894 return TRUE;
895 }
896
897 return ExtReadVolumeSectors(Volume, (ULONGLONG)BlockNumber * Volume->BlockSizeInSectors, Volume->BlockSizeInSectors, Buffer);
898}
899
900/*
901 * ExtReadPartialBlock()
902 * Reads part of a block into memory
903 */
905{
906 PVOID TempBuffer;
907
908 TRACE("ExtReadPartialBlock() BlockNumber = %d StartingOffset = %d Length = %d Buffer = 0x%x\n", BlockNumber, StartingOffset, Length, Buffer);
909
910 TempBuffer = FrLdrTempAlloc(Volume->BlockSizeInBytes, TAG_EXT_BUFFER);
911
912 if (!ExtReadBlock(Volume, BlockNumber, TempBuffer))
913 {
914 FrLdrTempFree(TempBuffer, TAG_EXT_BUFFER);
915 return FALSE;
916 }
917
919
920 FrLdrTempFree(TempBuffer, TAG_EXT_BUFFER);
921
922 return TRUE;
923}
924
926{
927 return ((Inode - 1) / Volume->SuperBlock->InodesPerGroup);
928}
929
931{
932 return (((Inode - 1) % Volume->SuperBlock->InodesPerGroup) / Volume->InodesPerBlock);
933}
934
936{
937 return (((Inode - 1) % Volume->SuperBlock->InodesPerGroup) % Volume->InodesPerBlock);
938}
939
941{
942 ULONG InodeGroupNumber;
943 ULONG InodeBlockNumber;
944 ULONG InodeOffsetInBlock;
945 CHAR ErrorString[80];
946 EXT_GROUP_DESC GroupDescriptor;
947
948 TRACE("ExtReadInode() Inode = %d\n", Inode);
949
950 // Make sure its a valid inode
951 if ((Inode < 1) || (Inode > Volume->SuperBlock->InodesCount))
952 {
953 sprintf(ErrorString, "Error reading inode %ld - inode out of range.", Inode);
954 FileSystemError(ErrorString);
955 return FALSE;
956 }
957
958 // Get inode group & block number and offset in block
959 InodeGroupNumber = ExtGetInodeGroupNumber(Volume, Inode);
960 InodeBlockNumber = ExtGetInodeBlockNumber(Volume, Inode);
961 InodeOffsetInBlock = ExtGetInodeOffsetInBlock(Volume, Inode);
962 TRACE("InodeGroupNumber = %d\n", InodeGroupNumber);
963 TRACE("InodeBlockNumber = %d\n", InodeBlockNumber);
964 TRACE("InodeOffsetInBlock = %d\n", InodeOffsetInBlock);
965
966 // Read the group descriptor
967 if (!ExtReadGroupDescriptor(Volume, InodeGroupNumber, &GroupDescriptor))
968 {
969 return FALSE;
970 }
971
972 // Add the start block of the inode table to the inode block number
973 InodeBlockNumber += GroupDescriptor.InodeTable;
974 TRACE("InodeBlockNumber (after group desc correction) = %d\n", InodeBlockNumber);
975
976 // Read the block
978 InodeBlockNumber,
979 (InodeOffsetInBlock * Volume->InodeSizeInBytes),
980 sizeof(EXT_INODE),
981 InodeBuffer))
982 {
983 return FALSE;
984 }
985
986 TRACE("Dumping inode information:\n");
987 TRACE("Mode = 0x%x\n", InodeBuffer->Mode);
988 TRACE("UID = %d\n", InodeBuffer->UID);
989 TRACE("Size = %d\n", InodeBuffer->Size);
990 TRACE("Atime = %d\n", InodeBuffer->Atime);
991 TRACE("Ctime = %d\n", InodeBuffer->Ctime);
992 TRACE("Mtime = %d\n", InodeBuffer->Mtime);
993 TRACE("Dtime = %d\n", InodeBuffer->Dtime);
994 TRACE("GID = %d\n", InodeBuffer->GID);
995 TRACE("LinksCount = %d\n", InodeBuffer->LinksCount);
996 TRACE("Blocks = %d\n", InodeBuffer->Blocks);
997 TRACE("Flags = 0x%x\n", InodeBuffer->Flags);
998 TRACE("OSD1 = 0x%x\n", InodeBuffer->OSD1);
999 TRACE("DirectBlocks = { %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u }\n",
1000 InodeBuffer->Blocks.DirectBlocks[0], InodeBuffer->Blocks.DirectBlocks[1], InodeBuffer->Blocks.DirectBlocks[2], InodeBuffer->Blocks.DirectBlocks[3],
1001 InodeBuffer->Blocks.DirectBlocks[4], InodeBuffer->Blocks.DirectBlocks[5], InodeBuffer->Blocks.DirectBlocks[6], InodeBuffer->Blocks.DirectBlocks[7],
1002 InodeBuffer->Blocks.DirectBlocks[8], InodeBuffer->Blocks.DirectBlocks[9], InodeBuffer->Blocks.DirectBlocks[10], InodeBuffer->Blocks.DirectBlocks[11]);
1003 TRACE("IndirectBlock = %u\n", InodeBuffer->Blocks.IndirectBlock);
1004 TRACE("DoubleIndirectBlock = %u\n", InodeBuffer->Blocks.DoubleIndirectBlock);
1005 TRACE("TripleIndirectBlock = %u\n", InodeBuffer->Blocks.TripleIndirectBlock);
1006 TRACE("Generation = %d\n", InodeBuffer->Generation);
1007 TRACE("FileACL = %d\n", InodeBuffer->FileACL);
1008 TRACE("DirACL = %d\n", InodeBuffer->DirACL);
1009 TRACE("FragAddress = %d\n", InodeBuffer->FragAddress);
1010 TRACE("OSD2 = { %d, %d, %d }\n",
1011 InodeBuffer->OSD2[0], InodeBuffer->OSD2[1], InodeBuffer->OSD2[2]);
1012
1013 return TRUE;
1014}
1015
1017{
1018 TRACE("ExtReadGroupDescriptor()\n");
1019
1020#if 0
1021 if (!ExtReadBlock(Volume, ExtGetGroupDescBlockNumber(Volume, Group), (PVOID)FILESYSBUFFER))
1022 {
1023 return FALSE;
1024 }
1025 RtlCopyMemory(GroupBuffer, (PVOID)(FILESYSBUFFER + ExtGetGroupDescOffsetInBlock(Volume, Group)), sizeof(EXT_GROUP_DESC));
1026#endif
1027
1028 RtlCopyMemory(GroupBuffer, &((PUCHAR)Volume->GroupDescriptors)[Volume->GroupDescSizeInBytes * Group], sizeof(EXT_GROUP_DESC));
1029
1030 TRACE("Dumping group descriptor:\n");
1031 TRACE("BlockBitmap = %d\n", GroupBuffer->BlockBitmap);
1032 TRACE("InodeBitmap = %d\n", GroupBuffer->InodeBitmap);
1033 TRACE("InodeTable = %d\n", GroupBuffer->InodeTable);
1034 TRACE("FreeBlocksCount = %d\n", GroupBuffer->FreeBlocksCount);
1035 TRACE("FreeInodesCount = %d\n", GroupBuffer->FreeInodesCount);
1036 TRACE("UsedDirsCount = %d\n", GroupBuffer->UsedDirsCount);
1037
1038 return TRUE;
1039}
1040
1042{
1044 ULONG BlockCount;
1045 ULONG* BlockList;
1046 ULONG CurrentBlockInList;
1047 ULONG CurrentBlock;
1048
1049 TRACE("ExtReadBlockPointerList()\n");
1050
1051 // Get the number of blocks this file occupies
1052 // I would just use Inode->i_blocks but it
1053 // doesn't seem to be the number of blocks
1054 // the file size corresponds to, but instead
1055 // it is much bigger.
1056 //BlockCount = Inode->i_blocks;
1058 FileSize = ROUND_UP(FileSize, Volume->BlockSizeInBytes);
1059 BlockCount = (ULONG)(FileSize / Volume->BlockSizeInBytes);
1060
1061 // Allocate the memory for the block list
1062 BlockList = FrLdrTempAlloc(BlockCount * sizeof(ULONG), TAG_EXT_BLOCK_LIST);
1063 if (BlockList == NULL)
1064 {
1065 return NULL;
1066 }
1067
1068 RtlZeroMemory(BlockList, BlockCount * sizeof(ULONG));
1069
1070 // If the file is stored in extents, copy the block pointers by reading the
1071 // extent entries.
1072 if (Inode->Flags & EXT4_INODE_FLAG_EXTENTS)
1073 {
1074 CurrentBlockInList = 0;
1075
1076 if (!ExtCopyBlockPointersByExtents(Volume, BlockList, &CurrentBlockInList, BlockCount, &Inode->ExtentHeader))
1077 {
1079 return NULL;
1080 }
1081
1082 return BlockList;
1083 }
1084
1085 // Copy the direct block pointers
1086 for (CurrentBlockInList = CurrentBlock = 0;
1087 CurrentBlockInList < BlockCount && CurrentBlock < sizeof(Inode->Blocks.DirectBlocks) / sizeof(*Inode->Blocks.DirectBlocks);
1088 CurrentBlock++, CurrentBlockInList++)
1089 {
1090 BlockList[CurrentBlockInList] = Inode->Blocks.DirectBlocks[CurrentBlock];
1091 }
1092
1093 // Copy the indirect block pointers
1094 if (CurrentBlockInList < BlockCount)
1095 {
1096 if (!ExtCopyIndirectBlockPointers(Volume, BlockList, &CurrentBlockInList, BlockCount, Inode->Blocks.IndirectBlock))
1097 {
1099 return NULL;
1100 }
1101 }
1102
1103 // Copy the double indirect block pointers
1104 if (CurrentBlockInList < BlockCount)
1105 {
1106 if (!ExtCopyDoubleIndirectBlockPointers(Volume, BlockList, &CurrentBlockInList, BlockCount, Inode->Blocks.DoubleIndirectBlock))
1107 {
1109 return NULL;
1110 }
1111 }
1112
1113 // Copy the triple indirect block pointers
1114 if (CurrentBlockInList < BlockCount)
1115 {
1116 if (!ExtCopyTripleIndirectBlockPointers(Volume, BlockList, &CurrentBlockInList, BlockCount, Inode->Blocks.TripleIndirectBlock))
1117 {
1119 return NULL;
1120 }
1121 }
1122
1123 return BlockList;
1124}
1125
1127{
1128 if (_S_ISDIR(Inode->Mode))
1129 return (ULONGLONG)(Inode->Size);
1130 else
1131 return ((ULONGLONG)(Inode->Size) | ((ULONGLONG)(Inode->DirACL) << 32));
1132}
1133
1134BOOLEAN ExtCopyBlockPointersByExtents(PEXT_VOLUME_INFO Volume, ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, PEXT4_EXTENT_HEADER ExtentHeader)
1135{
1136 TRACE("ExtCopyBlockPointersByExtents() BlockCount = 0x%p\n", BlockCount);
1137
1138 if (ExtentHeader->Magic != EXT4_EXTENT_HEADER_MAGIC ||
1139 ExtentHeader->Depth > EXT4_EXTENT_MAX_LEVEL)
1140 return FALSE;
1141
1142 ULONG Level = ExtentHeader->Depth;
1143 ULONG Entries = ExtentHeader->Entries;
1144
1145 TRACE("Level: %d\n", Level);
1146 TRACE("Entries: %d\n", Entries);
1147
1148 // If the level is 0, we have a direct extent block mapping
1149 if (!Level)
1150 {
1151 PEXT4_EXTENT Extent = (PVOID)&ExtentHeader[1];
1152
1153 while ((*CurrentBlockInList) < BlockCount && Entries--)
1154 {
1155 BOOLEAN SparseExtent = (Extent->Length > EXT4_EXTENT_MAX_LENGTH);
1156 ULONG Length = SparseExtent ? (Extent->Length - EXT4_EXTENT_MAX_LENGTH) : Extent->Length;
1157 ULONG CurrentBlock = SparseExtent ? 0 : Extent->Start;
1158
1159 // Copy the pointers to the block list
1160 while ((*CurrentBlockInList) < BlockCount && Length--)
1161 {
1162 BlockList[(*CurrentBlockInList)++] = CurrentBlock;
1163
1164 if (!SparseExtent)
1165 CurrentBlock++;
1166 }
1167
1168 Extent++;
1169 }
1170 }
1171 else
1172 {
1173 PEXT4_EXTENT_IDX Extent = (PVOID)&ExtentHeader[1];
1174
1175 PEXT4_EXTENT_HEADER BlockBuffer = FrLdrTempAlloc(Volume->BlockSizeInBytes, TAG_EXT_BUFFER);
1176 if (!BlockBuffer)
1177 {
1178 return FALSE;
1179 }
1180
1181 // Recursively copy the pointers to the block list
1182 while ((*CurrentBlockInList) < BlockCount && Entries--)
1183 {
1184 if (!(ExtReadBlock(Volume, Extent->Leaf, BlockBuffer) &&
1185 ExtCopyBlockPointersByExtents(Volume, BlockList, CurrentBlockInList, BlockCount, BlockBuffer)))
1186 {
1187 FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1188 return FALSE;
1189 }
1190
1191 Extent++;
1192 }
1193
1194 FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1195 }
1196
1197 return TRUE;
1198}
1199
1200BOOLEAN ExtCopyIndirectBlockPointers(PEXT_VOLUME_INFO Volume, ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG IndirectBlock)
1201{
1202 ULONG* BlockBuffer;
1203 ULONG CurrentBlock;
1204 ULONG BlockPointersPerBlock;
1205
1206 TRACE("ExtCopyIndirectBlockPointers() BlockCount = %d\n", BlockCount);
1207
1208 BlockPointersPerBlock = Volume->BlockSizeInBytes / sizeof(ULONG);
1209
1210 BlockBuffer = FrLdrTempAlloc(Volume->BlockSizeInBytes, TAG_EXT_BUFFER);
1211 if (!BlockBuffer)
1212 {
1213 return FALSE;
1214 }
1215
1216 if (!ExtReadBlock(Volume, IndirectBlock, BlockBuffer))
1217 {
1218 return FALSE;
1219 }
1220
1221 for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++)
1222 {
1223 BlockList[(*CurrentBlockInList)] = BlockBuffer[CurrentBlock];
1224 (*CurrentBlockInList)++;
1225 }
1226
1227 FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1228
1229 return TRUE;
1230}
1231
1232BOOLEAN ExtCopyDoubleIndirectBlockPointers(PEXT_VOLUME_INFO Volume, ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG DoubleIndirectBlock)
1233{
1234 ULONG* BlockBuffer;
1235 ULONG CurrentBlock;
1236 ULONG BlockPointersPerBlock;
1237
1238 TRACE("ExtCopyDoubleIndirectBlockPointers() BlockCount = %d\n", BlockCount);
1239
1240 BlockPointersPerBlock = Volume->BlockSizeInBytes / sizeof(ULONG);
1241
1242 BlockBuffer = (ULONG*)FrLdrTempAlloc(Volume->BlockSizeInBytes, TAG_EXT_BUFFER);
1243 if (BlockBuffer == NULL)
1244 {
1245 return FALSE;
1246 }
1247
1248 if (!ExtReadBlock(Volume, DoubleIndirectBlock, BlockBuffer))
1249 {
1250 FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1251 return FALSE;
1252 }
1253
1254 for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++)
1255 {
1256 if (!ExtCopyIndirectBlockPointers(Volume, BlockList, CurrentBlockInList, BlockCount, BlockBuffer[CurrentBlock]))
1257 {
1258 FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1259 return FALSE;
1260 }
1261 }
1262
1263 FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1264 return TRUE;
1265}
1266
1267BOOLEAN ExtCopyTripleIndirectBlockPointers(PEXT_VOLUME_INFO Volume, ULONG* BlockList, ULONG* CurrentBlockInList, ULONG BlockCount, ULONG TripleIndirectBlock)
1268{
1269 ULONG* BlockBuffer;
1270 ULONG CurrentBlock;
1271 ULONG BlockPointersPerBlock;
1272
1273 TRACE("ExtCopyTripleIndirectBlockPointers() BlockCount = %d\n", BlockCount);
1274
1275 BlockPointersPerBlock = Volume->BlockSizeInBytes / sizeof(ULONG);
1276
1277 BlockBuffer = (ULONG*)FrLdrTempAlloc(Volume->BlockSizeInBytes, TAG_EXT_BUFFER);
1278 if (BlockBuffer == NULL)
1279 {
1280 return FALSE;
1281 }
1282
1283 if (!ExtReadBlock(Volume, TripleIndirectBlock, BlockBuffer))
1284 {
1285 FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1286 return FALSE;
1287 }
1288
1289 for (CurrentBlock=0; (*CurrentBlockInList)<BlockCount && CurrentBlock<BlockPointersPerBlock; CurrentBlock++)
1290 {
1291 if (!ExtCopyDoubleIndirectBlockPointers(Volume, BlockList, CurrentBlockInList, BlockCount, BlockBuffer[CurrentBlock]))
1292 {
1293 FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1294 return FALSE;
1295 }
1296 }
1297
1298 FrLdrTempFree(BlockBuffer, TAG_EXT_BUFFER);
1299 return TRUE;
1300}
1301
1303{
1306 return ESUCCESS;
1307}
1308
1310{
1312
1314 Information->EndingAddress.QuadPart = FileHandle->FileSize;
1315 Information->CurrentAddress.QuadPart = FileHandle->FilePointer;
1316
1317 /* Set the ARC file attributes */
1318 Information->Attributes = FileHandle->Attributes;
1319
1320 /* Copy the file name, perhaps truncated, and NUL-terminated */
1321 Information->FileNameLength = min(FileHandle->FileNameLength, sizeof(Information->FileName) - 1);
1322 RtlCopyMemory(Information->FileName, FileHandle->FileName, Information->FileNameLength);
1323 Information->FileName[Information->FileNameLength] = ANSI_NULL;
1324
1325 TRACE("ExtGetFileInformation(%lu) -> FileSize = %llu, FilePointer = 0x%llx\n",
1326 FileId, Information->EndingAddress.QuadPart, Information->CurrentAddress.QuadPart);
1327
1328 return ESUCCESS;
1329}
1330
1332{
1335 ULONG DeviceId;
1336
1337 /* Check parameters */
1338 if (OpenMode != OpenReadOnly)
1339 return EACCES;
1340
1341 /* Get underlying device */
1342 DeviceId = FsGetDeviceId(*FileId);
1343 Volume = ExtVolumes[DeviceId];
1344
1345 TRACE("ExtOpen() FileName = \"%s\"\n", Path);
1346
1347 /* Call the internal open method */
1348 // Status = ExtOpenFile(Volume, Path, &FileHandle);
1350 if (!FileHandle)
1351 return ENOENT;
1352
1353 /* Success, remember the handle */
1355 return ESUCCESS;
1356}
1357
1359{
1361 ULONGLONG BytesReadBig;
1363
1364 /* Read data */
1365 Success = ExtReadFileBig(FileHandle, N, &BytesReadBig, Buffer);
1366 *Count = (ULONG)BytesReadBig;
1367 if (Success)
1368 return ESUCCESS;
1369 else
1370 return EIO;
1371}
1372
1374{
1376 LARGE_INTEGER NewPosition = *Position;
1377
1378 switch (SeekMode)
1379 {
1380 case SeekAbsolute:
1381 break;
1382 case SeekRelative:
1383 NewPosition.QuadPart += FileHandle->FilePointer;
1384 break;
1385 default:
1386 ASSERT(FALSE);
1387 return EINVAL;
1388 }
1389
1390 if (NewPosition.QuadPart >= FileHandle->FileSize)
1391 return EINVAL;
1392
1393 FileHandle->FilePointer = NewPosition.QuadPart;
1394 return ESUCCESS;
1395}
1396
1397
1405 _In_ ULONG DeviceId)
1406{
1408 ULARGE_INTEGER BlocksCount;
1409
1410 Volume = ExtVolumes[DeviceId];
1411 ASSERT(Volume);
1412
1413 BlocksCount.LowPart = Volume->SuperBlock->BlocksCountLo;
1414 BlocksCount.HighPart = Volume->SuperBlock->BlocksCountHi;
1415
1416 /* NOTE: Volume->BlockSizeInBytes == Volume->BlockSizeInSectors * Volume->BytesPerSector */
1417 return BlocksCount.QuadPart * Volume->BlockSizeInBytes;
1418}
1419
1420
1422{
1423 ExtClose,
1425 ExtOpen,
1426 ExtRead,
1427 ExtSeek,
1428 L"ext2fs",
1429};
1430
1431const DEVVTBL* ExtMount(ULONG DeviceId)
1432{
1434 EXT_SUPER_BLOCK SuperBlock;
1436 ULONG Count;
1438
1439 TRACE("Enter ExtMount(%lu)\n", DeviceId);
1440
1441 /* Allocate data for volume information */
1443 if (!Volume)
1444 return NULL;
1446
1447 /* Read the SuperBlock */
1448 Position.QuadPart = 2 * 512;
1449 Status = ArcSeek(DeviceId, &Position, SeekAbsolute);
1450 if (Status != ESUCCESS)
1451 {
1453 return NULL;
1454 }
1455 Status = ArcRead(DeviceId, &SuperBlock, sizeof(SuperBlock), &Count);
1456 if (Status != ESUCCESS || Count != sizeof(SuperBlock))
1457 {
1459 return NULL;
1460 }
1461
1462 /* Check if SuperBlock is valid. If yes, return Ext function table. */
1463 if (SuperBlock.Magic != EXT_SUPERBLOCK_MAGIC)
1464 {
1466 return NULL;
1467 }
1468
1469 Volume->DeviceId = DeviceId;
1470
1471 /* Really open the volume */
1472 if (!ExtOpenVolume(Volume))
1473 {
1475 return NULL;
1476 }
1477
1478 /* Remember EXT volume information */
1479 ExtVolumes[DeviceId] = Volume;
1480
1481 /* Return success */
1482 TRACE("ExtMount(%lu) success\n", DeviceId);
1483 return &ExtFuncTable;
1484}
1485
1486#endif // _M_ARM
#define N
Definition: crc32.c:57
unsigned char BOOLEAN
PRTL_UNICODE_STRING_BUFFER Path
#define ENOENT
Definition: acclib.h:79
#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
@ Group
Definition: help.c:22
BOOLEAN CacheReadDiskSectors(UCHAR DiskNumber, ULONGLONG StartSector, ULONG SectorCount, PVOID Buffer)
Definition: cache.c:113
BOOLEAN CacheInitializeDrive(UCHAR DriveNumber)
Definition: cache.c:37
#define DBG_DEFAULT_CHANNEL(ch)
Definition: debug.h:106
#define FAST_SYMLINK_MAX_NAME_SIZE
Definition: ext.h:229
#define EXT4_EXTENT_MAX_LEVEL
Definition: ext.h:218
#define EXT_GROUP_DESC_SIZE(sb)
Definition: ext.h:208
struct _ExtSuperBlock * PEXT_SUPER_BLOCK
#define EXT4_EXTENT_HEADER_MAGIC
Definition: ext.h:215
struct _ExtDirEntry * PEXT_DIR_ENTRY
#define EXT_DIR_ENTRY_MAX_NAME_LENGTH
Definition: ext.h:50
#define EXT_INODE_SIZE(sb)
Definition: ext.h:204
#define EXT_ROOT_INODE
Definition: ext.h:198
#define EXT_SUPERBLOCK_MAGIC
Definition: ext.h:45
struct _ExtGroupDescriptor * PEXT_GROUP_DESC
#define EXT4_EXTENT_MAX_LENGTH
Definition: ext.h:221
#define EXT4_INODE_FLAG_EXTENTS
Definition: ext.h:212
#define _S_ISLNK(m)
Definition: stat.h:56
#define _S_IWOTH
Definition: stat.h:99
#define _S_IWUSR
Definition: stat.h:89
#define _S_ISREG(m)
Definition: stat.h:50
#define _S_IWGRP
Definition: stat.h:94
#define _S_ISDIR(m)
Definition: stat.h:46
ARC_STATUS ArcSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: fs.c:455
PVOID FsGetDeviceSpecific(ULONG FileId)
Definition: fs.c:709
ULONG FsGetNumPathParts(PCSTR Path)
Definition: fs.c:617
VOID FsSetDeviceSpecific(ULONG FileId, PVOID Specific)
Definition: fs.c:702
VOID FileSystemError(PCSTR ErrorString)
Definition: fs.c:471
ULONG FsGetDeviceId(ULONG FileId)
Definition: fs.c:716
#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:448
VOID FsGetFirstNameFromPath(PCHAR Buffer, PCSTR Path)
Definition: fs.c:645
VOID FrLdrTempFree(PVOID Allocation, ULONG Tag)
Definition: heap.c:553
PVOID FrLdrTempAlloc(_In_ SIZE_T Size, _In_ ULONG Tag)
Definition: heap.c:545
BOOLEAN ExtCopyTripleIndirectBlockPointers(PEXT_VOLUME_INFO Volume, ULONG *BlockList, ULONG *CurrentBlockInList, ULONG BlockCount, ULONG TripleIndirectBlock)
Definition: ext.c:1267
#define TAG_EXT_VOLUME
Definition: ext.c:77
PEXT_FILE_INFO ExtOpenFile(PEXT_VOLUME_INFO Volume, PCSTR FileName)
Definition: ext.c:108
ULONG ExtGetInodeGroupNumber(PEXT_VOLUME_INFO Volume, ULONG Inode)
Definition: ext.c:925
ARC_STATUS ExtGetFileInformation(ULONG FileId, FILEINFORMATION *Information)
Definition: ext.c:1309
#define TAG_EXT_BLOCK_LIST
Definition: ext.c:72
BOOLEAN ExtCopyBlockPointersByExtents(PEXT_VOLUME_INFO Volume, ULONG *BlockList, ULONG *CurrentBlockInList, ULONG BlockCount, PEXT4_EXTENT_HEADER ExtentHeader)
Definition: ext.c:1134
ULONGLONG ExtGetVolumeSize(_In_ ULONG DeviceId)
Returns the size of the EXT2/3/4 volume laid on the storage media device opened via DeviceId.
Definition: ext.c:1404
BOOLEAN ExtReadGroupDescriptor(PEXT_VOLUME_INFO Volume, ULONG Group, PEXT_GROUP_DESC GroupBuffer)
Definition: ext.c:1016
BOOLEAN ExtCopyIndirectBlockPointers(PEXT_VOLUME_INFO Volume, ULONG *BlockList, ULONG *CurrentBlockInList, ULONG BlockCount, ULONG IndirectBlock)
Definition: ext.c:1200
BOOLEAN ExtReadFileBig(PEXT_FILE_INFO ExtFileInfo, ULONGLONG BytesToRead, ULONGLONG *BytesRead, PVOID Buffer)
Definition: ext.c:387
const DEVVTBL ExtFuncTable
Definition: ext.c:1421
ULONGLONG ExtGetInodeFileSize(PEXT_INODE Inode)
Definition: ext.c:1126
#define TAG_EXT_FILE
Definition: ext.c:73
BOOLEAN ExtReadVolumeSectors(PEXT_VOLUME_INFO Volume, ULONGLONG SectorNumber, ULONG SectorCount, PVOID Buffer)
Definition: ext.c:569
ULONG ExtGetInodeBlockNumber(PEXT_VOLUME_INFO Volume, ULONG Inode)
Definition: ext.c:930
BOOLEAN ExtReadDirectory(PEXT_VOLUME_INFO Volume, ULONG Inode, PVOID *DirectoryBuffer, PEXT_INODE InodePointer)
Definition: ext.c:813
BOOLEAN ExtLookupFile(PEXT_VOLUME_INFO Volume, PCSTR FileName, PEXT_FILE_INFO ExtFileInfo)
Definition: ext.c:210
BOOLEAN ExtReadBlock(PEXT_VOLUME_INFO Volume, ULONG BlockNumber, PVOID Buffer)
Definition: ext.c:873
BOOLEAN ExtCopyDoubleIndirectBlockPointers(PEXT_VOLUME_INFO Volume, ULONG *BlockList, ULONG *CurrentBlockInList, ULONG BlockCount, ULONG DoubleIndirectBlock)
Definition: ext.c:1232
BOOLEAN ExtOpenVolume(PEXT_VOLUME_INFO Volume)
Definition: ext.c:79
ARC_STATUS ExtSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: ext.c:1373
PEXT_VOLUME_INFO ExtVolumes[MAX_FDS]
Definition: ext.c:70
ULONG ExtGetInodeOffsetInBlock(PEXT_VOLUME_INFO Volume, ULONG Inode)
Definition: ext.c:935
#define TAG_EXT_BUFFER
Definition: ext.c:74
BOOLEAN ExtSearchDirectoryBufferForFile(PVOID DirectoryBuffer, ULONG DirectorySize, PCHAR FileName, PEXT_DIR_ENTRY DirectoryEntry)
Definition: ext.c:330
BOOLEAN ExtReadInode(PEXT_VOLUME_INFO Volume, ULONG Inode, PEXT_INODE InodeBuffer)
Definition: ext.c:940
BOOLEAN ExtReadPartialBlock(PEXT_VOLUME_INFO Volume, ULONG BlockNumber, ULONG StartingOffset, ULONG Length, PVOID Buffer)
Definition: ext.c:904
const DEVVTBL * ExtMount(ULONG DeviceId)
Definition: ext.c:1431
ARC_STATUS ExtRead(ULONG FileId, VOID *Buffer, ULONG N, ULONG *Count)
Definition: ext.c:1358
ARC_STATUS ExtClose(ULONG FileId)
Definition: ext.c:1302
ARC_STATUS ExtOpen(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
Definition: ext.c:1331
BOOLEAN ExtReadSuperBlock(PEXT_VOLUME_INFO Volume)
Definition: ext.c:600
#define TAG_EXT_GROUP_DESC
Definition: ext.c:76
ULONG * ExtReadBlockPointerList(PEXT_VOLUME_INFO Volume, PEXT_INODE Inode)
Definition: ext.c:1041
struct _EXT_VOLUME_INFO EXT_VOLUME_INFO
BOOLEAN ExtReadGroupDescriptors(PEXT_VOLUME_INFO Volume)
Definition: ext.c:771
#define TAG_EXT_SUPER_BLOCK
Definition: ext.c:75
while(CdLookupNextInitialFileDirent(IrpContext, Fcb, FileContext))
Dirent FileNameLen
Definition: dirsup.c:506
_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
#define L(x)
Definition: resources.c:13
@ Success
Definition: eventcreate.c:712
#define ROUND_UP(n, align)
Definition: eventvwr.h:34
@ DirectoryFile
Definition: fatprocs.h:1047
struct _FileName FileName
Definition: fatprocs.h:897
_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
UNICODE_STRING Volume
Definition: fltkernel.h:1172
#define ASSERT(a)
Definition: mode.c:44
#define sprintf
Definition: sprintf.c:45
static const ENTRY Entries[]
#define min(a, b)
Definition: monoChain.cc:55
#define _In_
Definition: no_sal2.h:158
int Count
Definition: noreturn.cpp:7
#define ANSI_NULL
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
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
@ ReadOnlyFile
Definition: arc.h:78
@ HiddenFile
Definition: arc.h:79
enum _SEEKMODE SEEKMODE
@ OpenReadOnly
Definition: arc.h:65
strcat
Definition: string.h:92
strcpy
Definition: string.h:131
#define TRACE(s)
Definition: solgame.cpp:4
uint64 Length
Definition: DriveVolume.h:48
EXT_INODE Inode
Definition: ext.h:237
PEXT_VOLUME_INFO Volume
Definition: ext.h:235
UCHAR Attributes
Definition: ext.h:241
PULONG FileBlockList
Definition: ext.h:236
CHAR FileName[RTL_FIELD_SIZE(FILEINFORMATION, FileName)]
Definition: ext.h:242
ULONG FileNameLength
Definition: ext.h:240
ULONGLONG FilePointer
Definition: ext.h:239
ULONGLONG FileSize
Definition: ext.h:238
ULONG BlockSizeInBytes
Definition: ext.c:56
ULONG FragmentSizeInSectors
Definition: ext.c:59
ULONG GroupDescSizeInBytes
Definition: ext.c:61
ULONG FragmentSizeInBytes
Definition: ext.c:58
ULONG DeviceId
Definition: ext.c:66
ULONG GroupCount
Definition: ext.c:62
ULONG BlockSizeInSectors
Definition: ext.c:57
ULONG GroupDescPerBlock
Definition: ext.c:64
PEXT_GROUP_DESC GroupDescriptors
Definition: ext.c:54
ULONG InodeSizeInBytes
Definition: ext.c:60
ULONG InodesPerBlock
Definition: ext.c:63
PEXT_SUPER_BLOCK SuperBlock
Definition: ext.c:53
ULONG BytesPerSector
Definition: ext.c:51
USHORT Magic
Definition: ext.h:130
USHORT Depth
Definition: ext.h:133
USHORT Entries
Definition: ext.h:131
USHORT EntryLen
Definition: ext.h:189
ULONG Inode
Definition: ext.h:188
UCHAR FileType
Definition: ext.h:191
CHAR Name[EXT_DIR_ENTRY_MAX_NAME_LENGTH]
Definition: ext.h:192
UCHAR NameLen
Definition: ext.h:190
USHORT FreeBlocksCount
Definition: ext.h:123
ULONG InodeBitmap
Definition: ext.h:121
ULONG InodeTable
Definition: ext.h:122
ULONG BlockBitmap
Definition: ext.h:120
USHORT FreeInodesCount
Definition: ext.h:124
USHORT UsedDirsCount
Definition: ext.h:125
Definition: ext.h:154
ULONG Dtime
Definition: ext.h:161
ULONG DirACL
Definition: ext.h:181
struct _ExtInode::@203::@205 Blocks
USHORT LinksCount
Definition: ext.h:163
EXT4_EXTENT_HEADER ExtentHeader
Definition: ext.h:177
CHAR SymLink[60]
Definition: ext.h:169
ULONG FragAddress
Definition: ext.h:182
ULONG Flags
Definition: ext.h:165
USHORT GID
Definition: ext.h:162
ULONG Generation
Definition: ext.h:179
ULONG Ctime
Definition: ext.h:159
USHORT Mode
Definition: ext.h:155
USHORT UID
Definition: ext.h:156
ULONG OSD1
Definition: ext.h:166
ULONG FileACL
Definition: ext.h:180
ULONG Size
Definition: ext.h:157
ULONG Mtime
Definition: ext.h:160
ULONG OSD2[3]
Definition: ext.h:183
ULONG Atime
Definition: ext.h:158
ULONG DefaultMountOpts
Definition: ext.h:104
ULONG FreeBlocksCountHi
Definition: ext.h:112
USHORT GroupDescSize
Definition: ext.h:102
ULONG FreeInodesCount
Definition: ext.h:59
UCHAR PreallocDirBlocks
Definition: ext.h:93
ULONG FeatureCompat
Definition: ext.h:85
UCHAR UUID[16]
Definition: ext.h:88
ULONG HashSeed[4]
Definition: ext.h:99
ULONG MkfsTime
Definition: ext.h:106
ULONG FirstMetaBg
Definition: ext.h:105
ULONG FeatureIncompat
Definition: ext.h:86
UCHAR DefHashVersion
Definition: ext.h:100
ULONG InodesCount
Definition: ext.h:55
UCHAR JournalBackupType
Definition: ext.h:101
ULONG BlocksCountLo
Definition: ext.h:56
USHORT MaxMntCount
Definition: ext.h:69
USHORT DefResUID
Definition: ext.h:78
ULONG InodesPerGroup
Definition: ext.h:65
ULONG MTime
Definition: ext.h:66
ULONG CreatorOS
Definition: ext.h:76
USHORT Magic
Definition: ext.h:70
ULONG LogBlockSize
Definition: ext.h:61
ULONG LastCheck
Definition: ext.h:74
ULONG RevisionLevel
Definition: ext.h:77
USHORT BlockGroupNr
Definition: ext.h:84
ULONG CheckInterval
Definition: ext.h:75
ULONG AlgorithmUsageBitmap
Definition: ext.h:91
LONG LogFragSize
Definition: ext.h:62
ULONG FragsPerGroup
Definition: ext.h:64
USHORT DefResGID
Definition: ext.h:79
CHAR VolumeName[16]
Definition: ext.h:89
ULONG BlocksPerGroup
Definition: ext.h:63
ULONG FirstInode
Definition: ext.h:82
ULONG BlocksCountHi
Definition: ext.h:110
ULONG RBlocksCountHi
Definition: ext.h:111
ULONG WTime
Definition: ext.h:67
ULONG LastOrphan
Definition: ext.h:98
ULONG RBlocksCountLo
Definition: ext.h:57
ULONG FeatureROCompat
Definition: ext.h:87
USHORT MntCount
Definition: ext.h:68
USHORT InodeSize
Definition: ext.h:83
USHORT State
Definition: ext.h:71
UCHAR JournalUUID[16]
Definition: ext.h:95
CHAR LastMounted[64]
Definition: ext.h:90
USHORT Errors
Definition: ext.h:72
ULONG FreeBlocksCountLo
Definition: ext.h:58
USHORT ReservedGdtBlocks
Definition: ext.h:94
USHORT MinorRevisionLevel
Definition: ext.h:73
ULONG FirstDataBlock
Definition: ext.h:60
UCHAR PreallocBlocks
Definition: ext.h:92
ULONG JournalDev
Definition: ext.h:97
ULONG JournalInum
Definition: ext.h:96
$ULONG LowPart
Definition: ntbasedef.h:581
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
$ULONG HighPart
Definition: ntbasedef.h:582
Definition: fs.h:25
static COORD Position
Definition: mouse.c:34
void * PVOID
Definition: typedefs.h:50
ULONG_PTR SIZE_T
Definition: typedefs.h:80
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
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
uint64_t ULONGLONG
Definition: typedefs.h:67
char * PCHAR
Definition: typedefs.h:51
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
_IRQL_requires_same_ typedef _In_ ULONG _In_ UCHAR Level
Definition: wmitypes.h:56
char CHAR
Definition: xmlstorage.h:175