xref: /reactos/drivers/filesystems/fastfat/fat.h (revision 23b7c7b8)
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