1 /*++ 2 3 Copyright (c) 1989-2000 Microsoft Corporation 4 5 Module Name: 6 7 Fat.h 8 9 Abstract: 10 11 This module defines the on-disk structure of the Fat file system. 12 13 14 --*/ 15 16 #ifndef _FAT_ 17 #define _FAT_ 18 19 // 20 // The following nomenclature is used to describe the Fat on-disk 21 // structure: 22 // 23 // LBN - is the number of a sector relative to the start of the disk. 24 // 25 // VBN - is the number of a sector relative to the start of a file, 26 // directory, or allocation. 27 // 28 // LBO - is a byte offset relative to the start of the disk. 29 // 30 // VBO - is a byte offset relative to the start of a file, directory 31 // or allocation. 32 // 33 34 typedef LONGLONG LBO; /* for Fat32, LBO is >32 bits */ 35 36 typedef LBO *PLBO; 37 38 typedef ULONG32 VBO; 39 typedef VBO *PVBO; 40 41 42 // 43 // The boot sector is the first physical sector (LBN == 0) on the volume. 44 // Part of the sector contains a BIOS Parameter Block. The BIOS in the 45 // sector is packed (i.e., unaligned) so we'll supply a unpacking macro 46 // to translate a packed BIOS into its unpacked equivalent. The unpacked 47 // BIOS structure is already defined in ntioapi.h so we only need to define 48 // the packed BIOS. 49 // 50 51 // 52 // Define the Packed and Unpacked BIOS Parameter Block 53 // 54 55 typedef struct _PACKED_BIOS_PARAMETER_BLOCK { 56 UCHAR BytesPerSector[2]; // offset = 0x000 0 57 UCHAR SectorsPerCluster[1]; // offset = 0x002 2 58 UCHAR ReservedSectors[2]; // offset = 0x003 3 59 UCHAR Fats[1]; // offset = 0x005 5 60 UCHAR RootEntries[2]; // offset = 0x006 6 61 UCHAR Sectors[2]; // offset = 0x008 8 62 UCHAR Media[1]; // offset = 0x00A 10 63 UCHAR SectorsPerFat[2]; // offset = 0x00B 11 64 UCHAR SectorsPerTrack[2]; // offset = 0x00D 13 65 UCHAR Heads[2]; // offset = 0x00F 15 66 UCHAR HiddenSectors[4]; // offset = 0x011 17 67 UCHAR LargeSectors[4]; // offset = 0x015 21 68 } PACKED_BIOS_PARAMETER_BLOCK; // sizeof = 0x019 25 69 typedef PACKED_BIOS_PARAMETER_BLOCK *PPACKED_BIOS_PARAMETER_BLOCK; 70 71 typedef struct _PACKED_BIOS_PARAMETER_BLOCK_EX { 72 UCHAR BytesPerSector[2]; // offset = 0x000 0 73 UCHAR SectorsPerCluster[1]; // offset = 0x002 2 74 UCHAR ReservedSectors[2]; // offset = 0x003 3 75 UCHAR Fats[1]; // offset = 0x005 5 76 UCHAR RootEntries[2]; // offset = 0x006 6 77 UCHAR Sectors[2]; // offset = 0x008 8 78 UCHAR Media[1]; // offset = 0x00A 10 79 UCHAR SectorsPerFat[2]; // offset = 0x00B 11 80 UCHAR SectorsPerTrack[2]; // offset = 0x00D 13 81 UCHAR Heads[2]; // offset = 0x00F 15 82 UCHAR HiddenSectors[4]; // offset = 0x011 17 83 UCHAR LargeSectors[4]; // offset = 0x015 21 84 UCHAR LargeSectorsPerFat[4]; // offset = 0x019 25 85 UCHAR ExtendedFlags[2]; // offset = 0x01D 29 86 UCHAR FsVersion[2]; // offset = 0x01F 31 87 UCHAR RootDirFirstCluster[4]; // offset = 0x021 33 88 UCHAR FsInfoSector[2]; // offset = 0x025 37 89 UCHAR BackupBootSector[2]; // offset = 0x027 39 90 UCHAR Reserved[12]; // offset = 0x029 41 91 } PACKED_BIOS_PARAMETER_BLOCK_EX; // sizeof = 0x035 53 92 93 typedef PACKED_BIOS_PARAMETER_BLOCK_EX *PPACKED_BIOS_PARAMETER_BLOCK_EX; 94 95 // 96 // The IsBpbFat32 macro is defined to work with both packed and unpacked 97 // BPB structures. Since we are only checking for zero, the byte order 98 // does not matter. 99 // 100 101 #define IsBpbFat32(bpb) (*(USHORT *)(&(bpb)->SectorsPerFat) == 0) 102 103 typedef struct BIOS_PARAMETER_BLOCK { 104 USHORT BytesPerSector; 105 UCHAR SectorsPerCluster; 106 USHORT ReservedSectors; 107 UCHAR Fats; 108 USHORT RootEntries; 109 USHORT Sectors; 110 UCHAR Media; 111 USHORT SectorsPerFat; 112 USHORT SectorsPerTrack; 113 USHORT Heads; 114 ULONG32 HiddenSectors; 115 ULONG32 LargeSectors; 116 ULONG32 LargeSectorsPerFat; 117 union { 118 USHORT ExtendedFlags; 119 struct { 120 ULONG ActiveFat:4; 121 ULONG Reserved0:3; 122 ULONG MirrorDisabled:1; 123 ULONG Reserved1:8; 124 }; 125 }; 126 USHORT FsVersion; 127 ULONG32 RootDirFirstCluster; 128 USHORT FsInfoSector; 129 USHORT BackupBootSector; 130 } BIOS_PARAMETER_BLOCK, *PBIOS_PARAMETER_BLOCK; 131 132 // 133 // This macro takes a Packed BIOS and fills in its Unpacked equivalent 134 // 135 136 #define FatUnpackBios(Bios,Pbios) { \ 137 CopyUchar2(&(Bios)->BytesPerSector, &(Pbios)->BytesPerSector[0] ); \ 138 CopyUchar1(&(Bios)->SectorsPerCluster, &(Pbios)->SectorsPerCluster[0]); \ 139 CopyUchar2(&(Bios)->ReservedSectors, &(Pbios)->ReservedSectors[0] ); \ 140 CopyUchar1(&(Bios)->Fats, &(Pbios)->Fats[0] ); \ 141 CopyUchar2(&(Bios)->RootEntries, &(Pbios)->RootEntries[0] ); \ 142 CopyUchar2(&(Bios)->Sectors, &(Pbios)->Sectors[0] ); \ 143 CopyUchar1(&(Bios)->Media, &(Pbios)->Media[0] ); \ 144 CopyUchar2(&(Bios)->SectorsPerFat, &(Pbios)->SectorsPerFat[0] ); \ 145 CopyUchar2(&(Bios)->SectorsPerTrack, &(Pbios)->SectorsPerTrack[0] ); \ 146 CopyUchar2(&(Bios)->Heads, &(Pbios)->Heads[0] ); \ 147 CopyUchar4(&(Bios)->HiddenSectors, &(Pbios)->HiddenSectors[0] ); \ 148 CopyUchar4(&(Bios)->LargeSectors, &(Pbios)->LargeSectors[0] ); \ 149 CopyUchar4(&(Bios)->LargeSectorsPerFat,&((PPACKED_BIOS_PARAMETER_BLOCK_EX)Pbios)->LargeSectorsPerFat[0] ); \ 150 CopyUchar2(&(Bios)->ExtendedFlags, &((PPACKED_BIOS_PARAMETER_BLOCK_EX)Pbios)->ExtendedFlags[0] ); \ 151 CopyUchar2(&(Bios)->FsVersion, &((PPACKED_BIOS_PARAMETER_BLOCK_EX)Pbios)->FsVersion[0] ); \ 152 CopyUchar4(&(Bios)->RootDirFirstCluster, \ 153 &((PPACKED_BIOS_PARAMETER_BLOCK_EX)Pbios)->RootDirFirstCluster[0] ); \ 154 CopyUchar2(&(Bios)->FsInfoSector, &((PPACKED_BIOS_PARAMETER_BLOCK_EX)Pbios)->FsInfoSector[0] ); \ 155 CopyUchar2(&(Bios)->BackupBootSector, &((PPACKED_BIOS_PARAMETER_BLOCK_EX)Pbios)->BackupBootSector[0] ); \ 156 } 157 158 // 159 // Define the boot sector 160 // 161 162 typedef struct _PACKED_BOOT_SECTOR { 163 UCHAR Jump[3]; // offset = 0x000 0 164 UCHAR Oem[8]; // offset = 0x003 3 165 PACKED_BIOS_PARAMETER_BLOCK PackedBpb; // offset = 0x00B 11 166 UCHAR PhysicalDriveNumber; // offset = 0x024 36 167 UCHAR CurrentHead; // offset = 0x025 37 168 UCHAR Signature; // offset = 0x026 38 169 UCHAR Id[4]; // offset = 0x027 39 170 UCHAR VolumeLabel[11]; // offset = 0x02B 43 171 UCHAR SystemId[8]; // offset = 0x036 54 172 } PACKED_BOOT_SECTOR; // sizeof = 0x03E 62 173 174 typedef PACKED_BOOT_SECTOR *PPACKED_BOOT_SECTOR; 175 176 typedef struct _PACKED_BOOT_SECTOR_EX { 177 UCHAR Jump[3]; // offset = 0x000 0 178 UCHAR Oem[8]; // offset = 0x003 3 179 PACKED_BIOS_PARAMETER_BLOCK_EX PackedBpb; // offset = 0x00B 11 180 UCHAR PhysicalDriveNumber; // offset = 0x040 64 181 UCHAR CurrentHead; // offset = 0x041 65 182 UCHAR Signature; // offset = 0x042 66 183 UCHAR Id[4]; // offset = 0x043 67 184 UCHAR VolumeLabel[11]; // offset = 0x047 71 185 UCHAR SystemId[8]; // offset = 0x058 88 186 } PACKED_BOOT_SECTOR_EX; // sizeof = 0x060 96 187 188 typedef PACKED_BOOT_SECTOR_EX *PPACKED_BOOT_SECTOR_EX; 189 190 // 191 // Define the FAT32 FsInfo sector. 192 // 193 194 typedef struct _FSINFO_SECTOR { 195 ULONG SectorBeginSignature; // offset = 0x000 0 196 UCHAR ExtraBootCode[480]; // offset = 0x004 4 197 ULONG FsInfoSignature; // offset = 0x1e4 484 198 ULONG FreeClusterCount; // offset = 0x1e8 488 199 ULONG NextFreeCluster; // offset = 0x1ec 492 200 UCHAR Reserved[12]; // offset = 0x1f0 496 201 ULONG SectorEndSignature; // offset = 0x1fc 508 202 } FSINFO_SECTOR, *PFSINFO_SECTOR; 203 204 #define FSINFO_SECTOR_BEGIN_SIGNATURE 0x41615252 205 #define FSINFO_SECTOR_END_SIGNATURE 0xAA550000 206 207 #define FSINFO_SIGNATURE 0x61417272 208 209 // 210 // We use the CurrentHead field for our dirty partition info. 211 // 212 213 #define FAT_BOOT_SECTOR_DIRTY 0x01 214 #define FAT_BOOT_SECTOR_TEST_SURFACE 0x02 215 216 // 217 // Define a Fat Entry type. 218 // 219 // This type is used when representing a fat table entry. It also used 220 // to be used when dealing with a fat table index and a count of entries, 221 // but the ensuing type casting nightmare sealed this fate. These other 222 // two types are represented as ULONGs. 223 // 224 225 typedef ULONG32 FAT_ENTRY; 226 227 #define FAT32_ENTRY_MASK 0x0FFFFFFFUL 228 229 // 230 // We use these special index values to set the dirty info for 231 // DOS/Win9x compatibility. 232 // 233 234 #define FAT_CLEAN_VOLUME (~FAT32_ENTRY_MASK | 0) 235 #define FAT_DIRTY_VOLUME (~FAT32_ENTRY_MASK | 1) 236 237 #define FAT_DIRTY_BIT_INDEX 1 238 239 // 240 // Physically, the entry is fully set if clean, and the high 241 // bit knocked out if it is dirty (i.e., it is really a clean 242 // bit). This means it is different per-FAT size. 243 // 244 245 #define FAT_CLEAN_ENTRY (~0) 246 247 #define FAT12_DIRTY_ENTRY 0x7ff 248 #define FAT16_DIRTY_ENTRY 0x7fff 249 #define FAT32_DIRTY_ENTRY 0x7fffffff 250 251 // 252 // The following constants the are the valid Fat index values. 253 // 254 255 #define FAT_CLUSTER_AVAILABLE (FAT_ENTRY)0x00000000 256 #define FAT_CLUSTER_RESERVED (FAT_ENTRY)0x0ffffff0 257 #define FAT_CLUSTER_BAD (FAT_ENTRY)0x0ffffff7 258 #define FAT_CLUSTER_LAST (FAT_ENTRY)0x0fffffff 259 260 // 261 // Fat files have the following time/date structures. Note that the 262 // following structure is a 32 bits long but USHORT aligned. 263 // 264 265 typedef struct _FAT_TIME { 266 267 USHORT DoubleSeconds : 5; 268 USHORT Minute : 6; 269 USHORT Hour : 5; 270 271 } FAT_TIME; 272 typedef FAT_TIME *PFAT_TIME; 273 274 typedef struct _FAT_DATE { 275 276 USHORT Day : 5; 277 USHORT Month : 4; 278 USHORT Year : 7; // Relative to 1980 279 280 } FAT_DATE; 281 typedef FAT_DATE *PFAT_DATE; 282 283 typedef struct _FAT_TIME_STAMP { 284 285 FAT_TIME Time; 286 FAT_DATE Date; 287 288 } FAT_TIME_STAMP; 289 typedef FAT_TIME_STAMP *PFAT_TIME_STAMP; 290 291 // 292 // Fat files have 8 character file names and 3 character extensions 293 // 294 295 typedef UCHAR FAT8DOT3[11]; 296 typedef FAT8DOT3 *PFAT8DOT3; 297 298 299 // 300 // The directory entry record exists for every file/directory on the 301 // disk except for the root directory. 302 // 303 304 typedef struct _PACKED_DIRENT { 305 FAT8DOT3 FileName; // offset = 0 306 UCHAR Attributes; // offset = 11 307 UCHAR NtByte; // offset = 12 308 UCHAR CreationMSec; // offset = 13 309 FAT_TIME_STAMP CreationTime; // offset = 14 310 FAT_DATE LastAccessDate; // offset = 18 311 union { 312 USHORT ExtendedAttributes; // offset = 20 313 USHORT FirstClusterOfFileHi; // offset = 20 314 }; 315 FAT_TIME_STAMP LastWriteTime; // offset = 22 316 USHORT FirstClusterOfFile; // offset = 26 317 ULONG32 FileSize; // offset = 28 318 } PACKED_DIRENT; // sizeof = 32 319 typedef PACKED_DIRENT *PPACKED_DIRENT; 320 321 // 322 // A packed dirent is already quadword aligned so simply declare a dirent as a 323 // packed dirent 324 // 325 326 typedef PACKED_DIRENT DIRENT; 327 typedef DIRENT *PDIRENT; 328 329 // 330 // The first byte of a dirent describes the dirent. There is also a routine 331 // to help in deciding how to interpret the dirent. 332 // 333 334 #define FAT_DIRENT_NEVER_USED 0x00 335 #define FAT_DIRENT_REALLY_0E5 0x05 336 #define FAT_DIRENT_DIRECTORY_ALIAS 0x2e 337 #define FAT_DIRENT_DELETED 0xe5 338 339 // 340 // Define the NtByte bits. 341 // 342 343 // 344 // These two bits are used for EFS on FAT 345 // 0x1 means the file contents are encrypted 346 // 347 // 0x2 means the EFS metadata header is big. 348 // (this optimization means we don't have to read 349 // in the first sector of the file stream to get 350 // the normal header size) 351 // 352 353 #define FAT_DIRENT_NT_BYTE_ENCRYPTED 0x01 354 #define FAT_DIRENT_NT_BYTE_BIG_HEADER 0x02 355 356 // 357 // These two bits optimize the case in which either the name 358 // or extension are all lower case. 359 // 360 361 #define FAT_DIRENT_NT_BYTE_8_LOWER_CASE 0x08 362 #define FAT_DIRENT_NT_BYTE_3_LOWER_CASE 0x10 363 364 // 365 // Define the various dirent attributes 366 // 367 368 #define FAT_DIRENT_ATTR_READ_ONLY 0x01 369 #define FAT_DIRENT_ATTR_HIDDEN 0x02 370 #define FAT_DIRENT_ATTR_SYSTEM 0x04 371 #define FAT_DIRENT_ATTR_VOLUME_ID 0x08 372 #define FAT_DIRENT_ATTR_DIRECTORY 0x10 373 #define FAT_DIRENT_ATTR_ARCHIVE 0x20 374 #define FAT_DIRENT_ATTR_DEVICE 0x40 375 #define FAT_DIRENT_ATTR_LFN (FAT_DIRENT_ATTR_READ_ONLY | \ 376 FAT_DIRENT_ATTR_HIDDEN | \ 377 FAT_DIRENT_ATTR_SYSTEM | \ 378 FAT_DIRENT_ATTR_VOLUME_ID) 379 380 // 381 // On-disk extension for EFS files. 382 // 383 384 #define FAT_EFS_EXTENSION L".PFILE" 385 #define FAT_EFS_EXTENSION_CHARCOUNT (6) 386 #define FAT_EFS_EXTENSION_BYTECOUNT (12) 387 388 389 // 390 // These macros convert a number of fields in the Bpb to bytes from sectors 391 // 392 // ULONG 393 // FatBytesPerCluster ( 394 // IN PBIOS_PARAMETER_BLOCK Bios 395 // ); 396 // 397 // ULONG 398 // FatBytesPerFat ( 399 // IN PBIOS_PARAMETER_BLOCK Bios 400 // ); 401 // 402 // ULONG 403 // FatReservedBytes ( 404 // IN PBIOS_PARAMETER_BLOCK Bios 405 // ); 406 // 407 408 #define FatBytesPerCluster(B) ((ULONG)((B)->BytesPerSector * (B)->SectorsPerCluster)) 409 410 #define FatBytesPerFat(B) (IsBpbFat32(B)? \ 411 ((ULONG)((B)->BytesPerSector * (B)->LargeSectorsPerFat)) : \ 412 ((ULONG)((B)->BytesPerSector * (B)->SectorsPerFat))) 413 414 #define FatReservedBytes(B) ((ULONG)((B)->BytesPerSector * (B)->ReservedSectors)) 415 416 // 417 // This macro returns the size of the root directory dirent area in bytes 418 // For Fat32, the root directory is variable in length. This macro returns 419 // 0 because it is also used to determine the location of cluster 2. 420 // 421 // ULONG 422 // FatRootDirectorySize ( 423 // IN PBIOS_PARAMETER_BLOCK Bios 424 // ); 425 // 426 427 #define FatRootDirectorySize(B) ((ULONG)((B)->RootEntries * sizeof(DIRENT))) 428 429 430 // 431 // This macro returns the first Lbo (zero based) of the root directory on 432 // the device. This area is after the reserved and fats. 433 // 434 // For Fat32, the root directory is moveable. This macro returns the LBO 435 // for cluster 2 because it is used to determine the location of cluster 2. 436 // FatRootDirectoryLbo32() returns the actual LBO of the beginning of the 437 // actual root directory. 438 // 439 // LBO 440 // FatRootDirectoryLbo ( 441 // IN PBIOS_PARAMETER_BLOCK Bios 442 // ); 443 // 444 445 #define FatRootDirectoryLbo(B) (FatReservedBytes(B) + ((B)->Fats * FatBytesPerFat(B))) 446 #define FatRootDirectoryLbo32(B) (FatFileAreaLbo(B)+((B)->RootDirFirstCluster-2)*FatBytesPerCluster(B)) 447 448 // 449 // This macro returns the first Lbo (zero based) of the file area on the 450 // the device. This area is after the reserved, fats, and root directory. 451 // 452 // LBO 453 // FatFirstFileAreaLbo ( 454 // IN PBIOS_PARAMTER_BLOCK Bios 455 // ); 456 // 457 458 #define FatFileAreaLbo(B) (FatRootDirectoryLbo(B) + FatRootDirectorySize(B)) 459 460 // 461 // This macro returns the number of clusters on the disk. This value is 462 // computed by taking the total sectors on the disk subtracting up to the 463 // first file area sector and then dividing by the sectors per cluster count. 464 // Note that I don't use any of the above macros since far too much 465 // superfluous sector/byte conversion would take place. 466 // 467 // ULONG 468 // FatNumberOfClusters ( 469 // IN PBIOS_PARAMETER_BLOCK Bios 470 // ); 471 // 472 473 // 474 // for prior to MS-DOS Version 3.2 475 // 476 // After DOS 4.0, at least one of these, Sectors or LargeSectors, will be zero. 477 // but DOS version 3.2 case, both of these value might contains some value, 478 // because, before 3.2, we don't have Large Sector entry, some disk might have 479 // unexpected value in the field, we will use LargeSectors if Sectors eqaul to zero. 480 // 481 482 #define FatNumberOfClusters(B) ( \ 483 \ 484 IsBpbFat32(B) ? \ 485 \ 486 ((((B)->Sectors ? (B)->Sectors : (B)->LargeSectors) \ 487 \ 488 - ((B)->ReservedSectors + \ 489 (B)->Fats * (B)->LargeSectorsPerFat )) \ 490 \ 491 / \ 492 \ 493 (B)->SectorsPerCluster) \ 494 : \ 495 ((((B)->Sectors ? (B)->Sectors : (B)->LargeSectors) \ 496 \ 497 - ((B)->ReservedSectors + \ 498 (B)->Fats * (B)->SectorsPerFat + \ 499 (B)->RootEntries * sizeof(DIRENT) / (B)->BytesPerSector ) ) \ 500 \ 501 / \ 502 \ 503 (B)->SectorsPerCluster) \ 504 ) 505 506 // 507 // This macro returns the fat table bit size (i.e., 12 or 16 bits) 508 // 509 // ULONG 510 // FatIndexBitSize ( 511 // IN PBIOS_PARAMETER_BLOCK Bios 512 // ); 513 // 514 515 #define FatIndexBitSize(B) \ 516 ((UCHAR)(IsBpbFat32(B) ? 32 : (FatNumberOfClusters(B) < 4087 ? 12 : 16))) 517 518 // 519 // This macro raises STATUS_FILE_CORRUPT and marks the Fcb bad if an 520 // index value is not within the proper range. 521 // Note that the first two index values are invalid (0, 1), so we must 522 // add two from the top end to make sure the everything is within range 523 // 524 // VOID 525 // FatVerifyIndexIsValid ( 526 // IN PIRP_CONTEXT IrpContext, 527 // IN PVCB Vcb, 528 // IN ULONG Index 529 // ); 530 // 531 532 #define FatVerifyIndexIsValid(IC,V,I) { \ 533 if (((I) < 2) || ((I) > ((V)->AllocationSupport.NumberOfClusters + 1))) { \ 534 FatRaiseStatus(IC,STATUS_FILE_CORRUPT_ERROR); \ 535 } \ 536 } 537 538 // 539 // These two macros are used to translate between Logical Byte Offsets, 540 // and fat entry indexes. Note the use of variables stored in the Vcb. 541 // These two macros are used at a higher level than the other macros 542 // above. 543 // 544 // Note, these indexes are true cluster numbers. 545 // 546 // LBO 547 // GetLboFromFatIndex ( 548 // IN FAT_ENTRY Fat_Index, 549 // IN PVCB Vcb 550 // ); 551 // 552 // FAT_ENTRY 553 // GetFatIndexFromLbo ( 554 // IN LBO Lbo, 555 // IN PVCB Vcb 556 // ); 557 // 558 559 #define FatGetLboFromIndex(VCB,FAT_INDEX) ( \ 560 ( (LBO) \ 561 (VCB)->AllocationSupport.FileAreaLbo + \ 562 (((LBO)((FAT_INDEX) - 2)) << (VCB)->AllocationSupport.LogOfBytesPerCluster) \ 563 ) \ 564 ) 565 566 #define FatGetIndexFromLbo(VCB,LBO) ( \ 567 (ULONG) ( \ 568 (((LBO) - (VCB)->AllocationSupport.FileAreaLbo) >> \ 569 (VCB)->AllocationSupport.LogOfBytesPerCluster) + 2 \ 570 ) \ 571 ) 572 573 // 574 // The following macro does the shifting and such to lookup an entry 575 // 576 // VOID 577 // FatLookup12BitEntry( 578 // IN PVOID Fat, 579 // IN FAT_ENTRY Index, 580 // OUT PFAT_ENTRY Entry 581 // ); 582 // 583 584 #define FatLookup12BitEntry(FAT,INDEX,ENTRY) { \ 585 \ 586 CopyUchar2((PUCHAR)(ENTRY), (PUCHAR)(FAT) + (INDEX) * 3 / 2); \ 587 \ 588 *ENTRY = (FAT_ENTRY)(0xfff & (((INDEX) & 1) ? (*(ENTRY) >> 4) : \ 589 *(ENTRY))); \ 590 } 591 592 // 593 // The following macro does the tmp shifting and such to store an entry 594 // 595 // VOID 596 // FatSet12BitEntry( 597 // IN PVOID Fat, 598 // IN FAT_ENTRY Index, 599 // IN FAT_ENTRY Entry 600 // ); 601 // 602 603 #define FatSet12BitEntry(FAT,INDEX,ENTRY) { \ 604 \ 605 FAT_ENTRY TmpFatEntry; \ 606 \ 607 CopyUchar2((PUCHAR)&TmpFatEntry, (PUCHAR)(FAT) + (INDEX) * 3 / 2); \ 608 \ 609 TmpFatEntry = (FAT_ENTRY) \ 610 (((INDEX) & 1) ? ((ENTRY) << 4) | (TmpFatEntry & 0xf) \ 611 : (ENTRY) | (TmpFatEntry & 0xf000)); \ 612 \ 613 *((UNALIGNED UCHAR2 *)((PUCHAR)(FAT) + (INDEX) * 3 / 2)) = *((UNALIGNED UCHAR2 *)(&TmpFatEntry)); \ 614 } 615 616 // 617 // The following macro compares two FAT_TIME_STAMPs 618 // 619 620 #define FatAreTimesEqual(TIME1,TIME2) ( \ 621 RtlEqualMemory((TIME1),(TIME2), sizeof(FAT_TIME_STAMP)) \ 622 ) 623 624 625 #define EA_FILE_SIGNATURE (0x4445) // "ED" 626 #define EA_SET_SIGNATURE (0x4145) // "EA" 627 628 // 629 // If the volume contains any ea data then there is one EA file called 630 // "EA DATA. SF" located in the root directory as Hidden, System and 631 // ReadOnly. 632 // 633 634 typedef struct _EA_FILE_HEADER { 635 USHORT Signature; // offset = 0 636 USHORT FormatType; // offset = 2 637 USHORT LogType; // offset = 4 638 USHORT Cluster1; // offset = 6 639 USHORT NewCValue1; // offset = 8 640 USHORT Cluster2; // offset = 10 641 USHORT NewCValue2; // offset = 12 642 USHORT Cluster3; // offset = 14 643 USHORT NewCValue3; // offset = 16 644 USHORT Handle; // offset = 18 645 USHORT NewHOffset; // offset = 20 646 UCHAR Reserved[10]; // offset = 22 647 USHORT EaBaseTable[240]; // offset = 32 648 } EA_FILE_HEADER; // sizeof = 512 649 650 typedef EA_FILE_HEADER *PEA_FILE_HEADER; 651 652 typedef USHORT EA_OFF_TABLE[128]; 653 654 typedef EA_OFF_TABLE *PEA_OFF_TABLE; 655 656 // 657 // Every file with an extended attribute contains in its dirent an index 658 // into the EaMapTable. The map table contains an offset within the ea 659 // file (cluster aligned) of the ea data for the file. The individual 660 // ea data for each file is prefaced with an Ea Data Header. 661 // 662 663 typedef struct _EA_SET_HEADER { 664 USHORT Signature; // offset = 0 665 USHORT OwnEaHandle; // offset = 2 666 ULONG32 NeedEaCount; // offset = 4 667 UCHAR OwnerFileName[14]; // offset = 8 668 UCHAR Reserved[4]; // offset = 22 669 UCHAR cbList[4]; // offset = 26 670 UCHAR PackedEas[1]; // offset = 30 671 } EA_SET_HEADER; // sizeof = 30 672 typedef EA_SET_HEADER *PEA_SET_HEADER; 673 674 #define SIZE_OF_EA_SET_HEADER 30 675 676 #define MAXIMUM_EA_SIZE 0x0000ffff 677 678 #define GetcbList(EASET) (((EASET)->cbList[0] << 0) + \ 679 ((EASET)->cbList[1] << 8) + \ 680 ((EASET)->cbList[2] << 16) + \ 681 ((EASET)->cbList[3] << 24)) 682 683 #define SetcbList(EASET,CB) { \ 684 (EASET)->cbList[0] = (CB >> 0) & 0x0ff; \ 685 (EASET)->cbList[1] = (CB >> 8) & 0x0ff; \ 686 (EASET)->cbList[2] = (CB >> 16) & 0x0ff; \ 687 (EASET)->cbList[3] = (CB >> 24) & 0x0ff; \ 688 } 689 690 // 691 // Every individual ea in an ea set is declared the following packed ea 692 // 693 694 typedef struct _PACKED_EA { 695 UCHAR Flags; 696 UCHAR EaNameLength; 697 UCHAR EaValueLength[2]; 698 CHAR EaName[1]; 699 } PACKED_EA; 700 typedef PACKED_EA *PPACKED_EA; 701 702 // 703 // The following two macros are used to get and set the ea value length 704 // field of a packed ea 705 // 706 // VOID 707 // GetEaValueLength ( 708 // IN PPACKED_EA Ea, 709 // OUT PUSHORT ValueLength 710 // ); 711 // 712 // VOID 713 // SetEaValueLength ( 714 // IN PPACKED_EA Ea, 715 // IN USHORT ValueLength 716 // ); 717 // 718 719 #define GetEaValueLength(EA,LEN) { \ 720 *(LEN) = 0; \ 721 CopyUchar2( (LEN), (EA)->EaValueLength ); \ 722 } 723 724 #define SetEaValueLength(EA,LEN) { \ 725 CopyUchar2( &((EA)->EaValueLength), (LEN) ); \ 726 } 727 728 // 729 // The following macro is used to get the size of a packed ea 730 // 731 // VOID 732 // SizeOfPackedEa ( 733 // IN PPACKED_EA Ea, 734 // OUT PUSHORT EaSize 735 // ); 736 // 737 738 #define SizeOfPackedEa(EA,SIZE) { \ 739 ULONG _NL,_DL; _NL = 0; _DL = 0; \ 740 CopyUchar1(&_NL, &(EA)->EaNameLength); \ 741 GetEaValueLength(EA, &_DL); \ 742 *(SIZE) = 1 + 1 + 2 + _NL + 1 + _DL; \ 743 } 744 745 #define EA_NEED_EA_FLAG 0x80 746 #define MIN_EA_HANDLE 1 747 #define MAX_EA_HANDLE 30719 748 #define UNUSED_EA_HANDLE 0xffff 749 #define EA_CBLIST_OFFSET 0x1a 750 #define MAX_EA_BASE_INDEX 240 751 #define MAX_EA_OFFSET_INDEX 128 752 753 754 #endif // _FAT_ 755 756