1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3 // All rights reserved
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*
7         Module name:
8 
9    udf_info.cpp
10 
11         Abstract:
12 
13    This file contains filesystem-specific routines
14 
15 */
16 
17 #include "udf.h"
18 
19 #define         UDF_BUG_CHECK_ID                UDF_FILE_UDF_INFO
20 
21 #ifdef _X86_
22 static const int8 valid_char_arr[] =
23               {1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
24                1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
25                1,0,1,0, 0,0,0,0, 0,0,1,1, 1,0,0,1,
26                0,0,0,0, 0,0,0,0, 0,0,1,1, 1,1,1,1,
27                0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,  // @ABCDE....
28                0,0,0,0, 0,0,0,0, 0,0,0,1, 1,1,0,0,  // ....Z[/]^_
29                0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,  // `abcde....
30                0,0,0,0, 0,0,0,0, 0,0,0,1, 1,1,0,1,  // ....z{|}~
31 
32                0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
33                0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
34                0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
35                0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
36                0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
37                1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
38                0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
39                0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
40 #else   // NO X86 optimization , use generic C/C++
41 static const char valid_char_arr[] = {"*/:?\"<>|\\"};
42 #endif // _X86_
43 
44 #define DOS_CRC_MODULUS 41
45 #define hexChar crcChar
46 static const char crcChar[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ#_~-@";
47 
48 /* Used to convert hex digits to ASCII for readability. */
49 //static const char hexChar[] = "0123456789ABCDEF";
50 
51 static const uint16 CrcTable[256] = {
52     0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50a5U, 0x60c6U, 0x70e7U,
53     0x8108U, 0x9129U, 0xa14aU, 0xb16bU, 0xc18cU, 0xd1adU, 0xe1ceU, 0xf1efU,
54     0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52b5U, 0x4294U, 0x72f7U, 0x62d6U,
55     0x9339U, 0x8318U, 0xb37bU, 0xa35aU, 0xd3bdU, 0xc39cU, 0xf3ffU, 0xe3deU,
56     0x2462U, 0x3443U, 0x0420U, 0x1401U, 0x64e6U, 0x74c7U, 0x44a4U, 0x5485U,
57     0xa56aU, 0xb54bU, 0x8528U, 0x9509U, 0xe5eeU, 0xf5cfU, 0xc5acU, 0xd58dU,
58     0x3653U, 0x2672U, 0x1611U, 0x0630U, 0x76d7U, 0x66f6U, 0x5695U, 0x46b4U,
59     0xb75bU, 0xa77aU, 0x9719U, 0x8738U, 0xf7dfU, 0xe7feU, 0xd79dU, 0xc7bcU,
60     0x48c4U, 0x58e5U, 0x6886U, 0x78a7U, 0x0840U, 0x1861U, 0x2802U, 0x3823U,
61     0xc9ccU, 0xd9edU, 0xe98eU, 0xf9afU, 0x8948U, 0x9969U, 0xa90aU, 0xb92bU,
62     0x5af5U, 0x4ad4U, 0x7ab7U, 0x6a96U, 0x1a71U, 0x0a50U, 0x3a33U, 0x2a12U,
63     0xdbfdU, 0xcbdcU, 0xfbbfU, 0xeb9eU, 0x9b79U, 0x8b58U, 0xbb3bU, 0xab1aU,
64     0x6ca6U, 0x7c87U, 0x4ce4U, 0x5cc5U, 0x2c22U, 0x3c03U, 0x0c60U, 0x1c41U,
65     0xedaeU, 0xfd8fU, 0xcdecU, 0xddcdU, 0xad2aU, 0xbd0bU, 0x8d68U, 0x9d49U,
66     0x7e97U, 0x6eb6U, 0x5ed5U, 0x4ef4U, 0x3e13U, 0x2e32U, 0x1e51U, 0x0e70U,
67     0xff9fU, 0xefbeU, 0xdfddU, 0xcffcU, 0xbf1bU, 0xaf3aU, 0x9f59U, 0x8f78U,
68     0x9188U, 0x81a9U, 0xb1caU, 0xa1ebU, 0xd10cU, 0xc12dU, 0xf14eU, 0xe16fU,
69     0x1080U, 0x00a1U, 0x30c2U, 0x20e3U, 0x5004U, 0x4025U, 0x7046U, 0x6067U,
70     0x83b9U, 0x9398U, 0xa3fbU, 0xb3daU, 0xc33dU, 0xd31cU, 0xe37fU, 0xf35eU,
71     0x02b1U, 0x1290U, 0x22f3U, 0x32d2U, 0x4235U, 0x5214U, 0x6277U, 0x7256U,
72     0xb5eaU, 0xa5cbU, 0x95a8U, 0x8589U, 0xf56eU, 0xe54fU, 0xd52cU, 0xc50dU,
73     0x34e2U, 0x24c3U, 0x14a0U, 0x0481U, 0x7466U, 0x6447U, 0x5424U, 0x4405U,
74     0xa7dbU, 0xb7faU, 0x8799U, 0x97b8U, 0xe75fU, 0xf77eU, 0xc71dU, 0xd73cU,
75     0x26d3U, 0x36f2U, 0x0691U, 0x16b0U, 0x6657U, 0x7676U, 0x4615U, 0x5634U,
76     0xd94cU, 0xc96dU, 0xf90eU, 0xe92fU, 0x99c8U, 0x89e9U, 0xb98aU, 0xa9abU,
77     0x5844U, 0x4865U, 0x7806U, 0x6827U, 0x18c0U, 0x08e1U, 0x3882U, 0x28a3U,
78     0xcb7dU, 0xdb5cU, 0xeb3fU, 0xfb1eU, 0x8bf9U, 0x9bd8U, 0xabbbU, 0xbb9aU,
79     0x4a75U, 0x5a54U, 0x6a37U, 0x7a16U, 0x0af1U, 0x1ad0U, 0x2ab3U, 0x3a92U,
80     0xfd2eU, 0xed0fU, 0xdd6cU, 0xcd4dU, 0xbdaaU, 0xad8bU, 0x9de8U, 0x8dc9U,
81     0x7c26U, 0x6c07U, 0x5c64U, 0x4c45U, 0x3ca2U, 0x2c83U, 0x1ce0U, 0x0cc1U,
82     0xef1fU, 0xff3eU, 0xcf5dU, 0xdf7cU, 0xaf9bU, 0xbfbaU, 0x8fd9U, 0x9ff8U,
83     0x6e17U, 0x7e36U, 0x4e55U, 0x5e74U, 0x2e93U, 0x3eb2U, 0x0ed1U, 0x1ef0U
84 };
85 
86 static const uint32 crc32_tab[] = {
87       0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
88       0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
89       0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
90       0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
91       0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
92       0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
93       0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
94       0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
95       0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
96       0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
97       0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
98       0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
99       0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
100       0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
101       0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
102       0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
103       0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
104       0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
105       0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
106       0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
107       0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
108       0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
109       0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
110       0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
111       0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
112       0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
113       0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
114       0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
115       0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
116       0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
117       0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
118       0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
119       0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
120       0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
121       0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
122       0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
123       0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
124       0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
125       0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
126       0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
127       0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
128       0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
129       0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
130       0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
131       0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
132       0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
133       0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
134       0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
135       0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
136       0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
137       0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
138       0x2d02ef8dL
139 };
140 
141 /*
142    This routine allocates new memory block, copies data there & free old one
143 */
144 /*uint32
145 UDFMemRealloc(
146     int8* OldBuff,
147     uint32 OldLength,
148     int8** NewBuff,
149     uint32 NewLength
150     )
151 {
152     int8* new_buff;
153 
154     (*NewBuff) = OldBuff;
155     if(OldLength == NewLength) return OldLength;
156     new_buff = (int8*)MyAllocatePool__(NonPagedPool, NewLength);
157     if(!new_buff) return 0;
158     if(OldLength > NewLength) OldLength = NewLength;
159     RtlCopyMemory(new_buff, OldBuff, OldLength);
160     MyFreePool__(OldBuff);
161     (*NewBuff) = new_buff;
162     return OldLength;
163 } // end UDFMemRealloc()*/
164 
165 /*
166     This routine converts compressed Unicode to standard
167  */
168 void
169 __fastcall
170 UDFDecompressUnicode(
171     IN OUT PUNICODE_STRING UName,
172     IN uint8* CS0,
173     IN uint32 Length,
174     OUT uint16* valueCRC
175     )
176 {
177     uint16 compID = CS0[0];
178     uint32 unicodeIndex = 0;
179     uint32 byteIndex = 1;
180     PWCHAR buff;
181     uint8* _CS0 = CS0+1;
182 
183     if(!Length) goto return_empty_str;
184     // First check for valid compID.
185     switch(compID) {
186     case UDF_COMP_ID_8: {
187 
188         buff = (PWCHAR)MyAllocatePoolTag__(UDF_FILENAME_MT, (Length)*sizeof(WCHAR), MEM_FNAME_TAG);
189         if(!buff) goto return_empty_str;
190         UName->Buffer = buff;
191 
192         // Loop through all the bytes.
193         while (byteIndex < Length) {
194             (*buff) = (*_CS0);
195             _CS0++;
196             byteIndex++;
197             buff++;
198         }
199         unicodeIndex = byteIndex-1;
200         break;
201     }
202     case UDF_COMP_ID_16: {
203 
204         buff = (PWCHAR)MyAllocatePoolTag__(UDF_FILENAME_MT, (Length-1)+sizeof(WCHAR), MEM_FNAME16_TAG);
205         if(!buff) goto return_empty_str;
206         UName->Buffer = buff;
207 
208         // Loop through all the bytes.
209         while (byteIndex < Length) {
210             // Move the first byte to the high bits of the unicode char.
211             *buff = ((*_CS0) << 8) | (*(_CS0+1));
212             _CS0+=2;
213             byteIndex+=2;
214             unicodeIndex++;
215             buff++;
216             ASSERT(byteIndex <= Length);
217         }
218         break;
219     }
220     default: {
221 return_empty_str:
222         UName->Buffer = NULL;
223         UName->MaximumLength =
224         UName->Length = 0;
225         return;
226     }
227     }
228     UName->MaximumLength = (UName->Length = (((uint16)unicodeIndex)*sizeof(WCHAR))) + sizeof(WCHAR);
229     UName->Buffer[unicodeIndex] = 0;
230     if(valueCRC) {
231         *valueCRC = UDFCrc(CS0+1, Length-1);
232     }
233 } // end UDFDecompressUnicode()
234 
235 /*
236     This routine converts standard Unicode to compressed
237  */
238 void
239 __fastcall
240 UDFCompressUnicode(
241     IN PUNICODE_STRING UName,
242     IN OUT uint8** _CS0,
243     IN OUT uint32* Length
244     )
245 {
246     uint8* CS0;
247     uint8 compID;
248     uint16 unicodeIndex;
249     uint32 i, len;
250     PWCHAR Buff;
251 
252     len = (UName->Length) / sizeof(WCHAR);
253     compID = (!len) ? 0 : UDF_COMP_ID_8;
254     // check for uncompressable characters
255     Buff = UName->Buffer;
256     for(i=0; i<len; i++, Buff++) {
257         if((*Buff) & 0xff00) {
258             compID = UDF_COMP_ID_16;
259             break;
260         }
261     }
262 
263     CS0 = (uint8*)MyAllocatePool__(NonPagedPool, *Length = (((compID==UDF_COMP_ID_8) ? 1 : 2)*len + 1) );
264     if(!CS0) return;
265 
266     CS0[0] = compID;
267     *_CS0 = CS0;
268     // init loop
269     CS0++;
270     unicodeIndex = 0;
271     Buff = UName->Buffer;
272     if(compID == UDF_COMP_ID_16) {
273         // Loop through all the bytes.
274         while (unicodeIndex < len) {
275             // Move the 2nd byte to the low bits of the compressed unicode char.
276             *CS0 = (uint8)((*Buff) >> 8);
277             CS0++;
278             *CS0 = (uint8)(*Buff);
279             CS0++;
280             Buff++;
281             unicodeIndex++;
282         }
283     } else {
284         // Loop through all the bytes.
285         while (unicodeIndex < len) {
286             *CS0 = (uint8)(*Buff);
287             CS0++;
288             Buff++;
289             unicodeIndex++;
290         }
291     }
292 } // end UDFCompressUnicode()
293 
294 /*
295 OSSTATUS UDFFindFile__(IN PVCB Vcb,
296                                 IN BOOLEAN IgnoreCase,
297                                 IN PUNICODE_STRING Name,
298                                 IN PUDF_FILE_INFO DirInfo)
299           see 'Udf_info.h'
300 */
301 
302 /*
303     This routine reads (Extended)FileEntry according to FileDesc
304  */
305 OSSTATUS
306 UDFReadFileEntry(
307     IN PVCB Vcb,
308     IN long_ad* Icb,
309  IN OUT PFILE_ENTRY FileEntry, // here we can also get ExtendedFileEntry
310  IN OUT uint16* Ident
311     )
312 {
313     OSSTATUS status;
314 
315     if(!OS_SUCCESS(status = UDFReadTagged(Vcb, (int8*)FileEntry,
316                          UDFPartLbaToPhys(Vcb,&(Icb->extLocation)),
317                          Icb->extLocation.logicalBlockNum,
318                          Ident))) return status;
319     if((FileEntry->descTag.tagIdent != TID_FILE_ENTRY) &&
320        (FileEntry->descTag.tagIdent != TID_EXTENDED_FILE_ENTRY)) {
321         UDFPrint(("  Not a FileEntry (lbn=%x, tag=%x)\n", Icb->extLocation.logicalBlockNum, FileEntry->descTag.tagIdent));
322         return STATUS_FILE_CORRUPT_ERROR;
323     }
324     return STATUS_SUCCESS;
325 } // UDFReadFileEntry()
326 
327 #if !defined (_X86_) || !defined (_MSC_VER)
328 /*
329     Decides if a Unicode character matches one of a list
330     of ASCII characters.
331     Used by DOS version of UDFIsIllegalChar for readability, since all of the
332     illegal characters above 0x0020 are in the ASCII subset of Unicode.
333     Works very similarly to the standard C function strchr().
334  */
335 BOOLEAN
336 UDFUnicodeInString(
337     IN uint8* string, // String to search through.
338     IN WCHAR ch       // Unicode char to search for.
339     )
340 {
341     BOOLEAN found = FALSE;
342 
343     while(*string != '\0' && !found) {
344         // These types should compare, since both are unsigned numbers.
345         if(*string == ch) {
346             found = TRUE;
347         }
348         string++;
349     }
350     return(found);
351 } // end UDFUnicodeInString()
352 #endif // _X86_
353 
354 /*
355     Decides whether character passed is an illegal character for a
356     DOS file name.
357 */
358 #ifdef _MSC_VER
359 #pragma warning(push)
360 #pragma warning(disable:4035)               // re-enable below
361 #endif
362 
363 #ifdef _X86_
364 #ifdef _MSC_VER
365 __declspec (naked)
366 #endif
367 #endif // _X86_
368 BOOLEAN
369 __fastcall
370 UDFIsIllegalChar(
371     IN WCHAR chr  // ECX
372     )
373 {
374     // Genuine illegal char's for DOS.
375 #if defined (_X86_) && defined (_MSC_VER)
376   _asm {
377     push ebx
378 
379     xor  eax,eax
380 //  mov  ax,chr
381     mov  ax,cx
382     or   ah,ah
383     jnz  ERR_IIC
384 
385     lea  ebx,[valid_char_arr]
386     xlatb
387     jmp  short ERR_IIC2
388 ERR_IIC:
389     mov  al,1
390 ERR_IIC2:
391 
392     pop  ebx
393     ret
394   }
395 
396 #else   // NO X86 optimization , use generic C/C++
397     /* FIXME */
398     //return ((ch < 0x20) || UDFUnicodeInString((uint8*)&valid_char_arr, ch));
399     return ((chr < 0x20) || UDFUnicodeInString((uint8*)&valid_char_arr, chr));
400 #endif // _X86_
401 } // end UDFIsIllegalChar()
402 
403 #ifdef _MSC_VER
404 #pragma warning(pop)  // re-enable warning #4035
405 #endif
406 
407 /*
408     Translate udfName to dosName using OSTA compliant.
409     dosName must be a unicode string with min length of 12.
410  */
411 
412 /*void UDFDOSName__(
413     IN PVCB Vcb,
414     IN OUT PUNICODE_STRING DosName,
415     IN PUNICODE_STRING UdfName,
416     IN PUDF_FILE_INFO FileInfo
417     )
418 {
419     BOOLEAN         KeepIntact;
420 
421     KeepIntact = (FileInfo && (FileInfo->Index < 2));
422     UDFDOSName(Vcb, DosName, UdfName, KeepIntact);
423 }*/
424 
425 void
426 __fastcall
427 UDFDOSName(
428     IN PVCB Vcb,
429     IN OUT PUNICODE_STRING DosName,
430     IN PUNICODE_STRING UdfName,
431     IN BOOLEAN KeepIntact
432     )
433 {
434 #ifndef _CONSOLE
435     if(Vcb->CompatFlags & UDF_VCB_IC_OS_NATIVE_DOS_NAME) {
436         UDFDOSNameOsNative(DosName, UdfName, KeepIntact);
437         return;
438     }
439 #endif //_CONSOLE
440 
441     switch(Vcb->CurrentUDFRev) {
442     case 0x0100:
443     case 0x0101:
444     case 0x0102:
445         UDFDOSName100(DosName, UdfName, KeepIntact);
446         break;
447 
448     case 0x0150:
449         // in general, we need bytes-from-media to
450         // create valid UDF 1.50 name.
451         // Curently it is impossible, thus,  we'll use
452         // UDF 2.00 translation algorithm
453     case 0x0200:
454         UDFDOSName200(DosName, UdfName, KeepIntact, Vcb->CurrentUDFRev == 0x0150);
455         break;
456 
457     case 0x0201:
458     default:
459         UDFDOSName201(DosName, UdfName, KeepIntact);
460     }
461 }
462 
463 void
464 __fastcall
465 UDFDOSName100(
466     IN OUT PUNICODE_STRING DosName,
467     IN PUNICODE_STRING UdfName,
468     IN BOOLEAN KeepIntact
469     )
470 {
471     PWCHAR dosName = DosName->Buffer;
472     PWCHAR udfName = UdfName->Buffer;
473     uint32 udfLen = UdfName->Length / sizeof(WCHAR);
474 
475     uint32 index, dosIndex = 0, extIndex = 0, lastPeriodIndex;
476     BOOLEAN needsCRC = FALSE, hasExt = FALSE, writingExt = FALSE, isParent = FALSE;
477     uint32 valueCRC;
478     WCHAR ext[DOS_EXT_LEN], current;
479 
480     if(KeepIntact &&
481        (udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) {
482         isParent = TRUE;
483         if((udfLen == 2) && (udfName[1] != UNICODE_PERIOD))
484             isParent = FALSE;
485     }
486 
487     for (index = 0 ; index < udfLen ; index++) {
488         current = udfName[index];
489         if (current == UNICODE_PERIOD && !isParent) {
490             if (dosIndex==0 || hasExt) {
491                 // Ignore leading periods or any other than used for extension.
492                 needsCRC = TRUE;
493             } else {
494                 // First, find last character which is NOT a period or space.
495                 lastPeriodIndex = udfLen - 1;
496                 while(lastPeriodIndex >=0 &&
497                      (udfName[lastPeriodIndex] == UNICODE_PERIOD ||
498                       udfName[lastPeriodIndex] == UNICODE_SPACE))
499                     lastPeriodIndex--;
500                 // Now search for last remaining period.
501                 while(lastPeriodIndex >= 0 &&
502                       udfName[lastPeriodIndex] != UNICODE_PERIOD)
503                     lastPeriodIndex--;
504                 // See if the period we found was the last or not.
505                 if (lastPeriodIndex != index)
506                     needsCRC = TRUE; // If not, name needs translation.
507                 // As long as the period was not trailing,
508                 // the file name has an extension.
509                 if (lastPeriodIndex >= 0) hasExt = TRUE;
510             }
511         } else {
512             if ((!hasExt && dosIndex == DOS_NAME_LEN) ||
513                  extIndex == DOS_EXT_LEN) {
514                 // File name or extension is too long for DOS.
515                 needsCRC = TRUE;
516             } else {
517                 if (current == UNICODE_SPACE) { // Ignore spaces.
518                     needsCRC = TRUE;
519                 } else {
520                     // Look for illegal or unprintable characters.
521                     if (UDFIsIllegalChar(current) /*|| !UnicodeIsPrint(current)*/) {
522                         needsCRC = TRUE;
523                         current = ILLEGAL_CHAR_MARK;
524                         /* Skip Illegal characters(even spaces),
525                         * but not periods.
526                         */
527                         while(index+1 < udfLen &&
528                               (UDFIsIllegalChar(udfName[index+1]) /*||
529                               !UnicodeIsPrint(udfName[index+1])*/) &&
530                               udfName[index+1] != UNICODE_PERIOD)
531                             index++;
532                     }
533                     // Add current char to either file name or ext.
534                     if (writingExt) {
535                         ext[extIndex] = current;
536                         extIndex++;
537                     } else {
538                         dosName[dosIndex] = current;
539                         dosIndex++;
540                     }
541                 }
542             }
543         }
544         // See if we are done with file name, either because we reached
545         // the end of the file name length, or the final period.
546         if (!writingExt && hasExt && (dosIndex == DOS_NAME_LEN ||
547             index == lastPeriodIndex)) {
548             // If so, and the name has an extension, start reading it.
549             writingExt = TRUE;
550             // Extension starts after last period.
551             index = lastPeriodIndex;
552         }
553     }
554     //
555     if (needsCRC) {
556         // Add CRC to end of file name or at position 4.
557         if (dosIndex >4) dosIndex = 4;
558         valueCRC = UDFUnicodeCksum(udfName, udfLen);
559         // set CRC prefix
560         dosName[dosIndex] = UNICODE_CRC_MARK;
561         // Convert 12-bit CRC to hex characters.
562         dosName[dosIndex+1] = hexChar[(valueCRC & 0x0f00) >> 8];
563         dosName[dosIndex+2] = hexChar[(valueCRC & 0x00f0) >> 4];
564         dosName[dosIndex+3] = hexChar[(valueCRC & 0x000f)];
565         dosIndex+=4;
566     }
567     // Add extension, if any.
568     if (extIndex != 0) {
569         dosName[dosIndex] = UNICODE_PERIOD;
570         dosIndex++;
571         for (index = 0; index < extIndex; index++) {
572             dosName[dosIndex] = ext[index];
573             dosIndex++;
574         }
575     }
576     DosName->Length = (uint16)dosIndex*sizeof(WCHAR);
577     RtlUpcaseUnicodeString(DosName, DosName, FALSE);
578 } // end UDFDOSName100()
579 
580 void
581 __fastcall
582 UDFDOSName200(
583     IN OUT PUNICODE_STRING DosName,
584     IN PUNICODE_STRING UdfName,
585     IN BOOLEAN KeepIntact,
586     IN BOOLEAN Mode150
587     )
588 {
589     PWCHAR dosName = DosName->Buffer;
590     PWCHAR udfName = UdfName->Buffer;
591     uint32 udfLen = UdfName->Length / sizeof(WCHAR);
592 
593     uint32 index, dosIndex = 0, extIndex = 0, lastPeriodIndex;
594     BOOLEAN needsCRC = FALSE, hasExt = FALSE, writingExt = FALSE, isParent = FALSE;
595     uint32 valueCRC;
596     WCHAR ext[DOS_EXT_LEN], current;
597 
598     if(KeepIntact &&
599        (udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) {
600         isParent = TRUE;
601         if((udfLen == 2) && (udfName[1] != UNICODE_PERIOD))
602             isParent = FALSE;
603     }
604 
605     for (index = 0 ; index < udfLen ; index++) {
606         current = udfName[index];
607         if (current == UNICODE_PERIOD && !isParent) {
608             if (dosIndex==0 || hasExt) {
609                 // Ignore leading periods or any other than used for extension.
610                 needsCRC = TRUE;
611             } else {
612                 // First, find last character which is NOT a period or space.
613                 lastPeriodIndex = udfLen - 1;
614                 while(lastPeriodIndex >=0 &&
615                      (udfName[lastPeriodIndex] == UNICODE_PERIOD ||
616                       udfName[lastPeriodIndex] == UNICODE_SPACE))
617                     lastPeriodIndex--;
618                 // Now search for last remaining period.
619                 while(lastPeriodIndex >= 0 &&
620                       udfName[lastPeriodIndex] != UNICODE_PERIOD)
621                     lastPeriodIndex--;
622                 // See if the period we found was the last or not.
623                 if (lastPeriodIndex != index)
624                     needsCRC = TRUE; // If not, name needs translation.
625                 // As long as the period was not trailing,
626                 // the file name has an extension.
627                 if (lastPeriodIndex >= 0) hasExt = TRUE;
628             }
629         } else {
630             if ((!hasExt && dosIndex == DOS_NAME_LEN) ||
631                  extIndex == DOS_EXT_LEN) {
632                 // File name or extension is too long for DOS.
633                 needsCRC = TRUE;
634             } else {
635                 if (current == UNICODE_SPACE) { // Ignore spaces.
636                     needsCRC = TRUE;
637                 } else {
638                     // Look for illegal or unprintable characters.
639                     if (UDFIsIllegalChar(current) /*|| !UnicodeIsPrint(current)*/) {
640                         needsCRC = TRUE;
641                         current = ILLEGAL_CHAR_MARK;
642                         /* Skip Illegal characters(even spaces),
643                         * but not periods.
644                         */
645                         while(index+1 < udfLen &&
646                               (UDFIsIllegalChar(udfName[index+1]) /*||
647                               !UnicodeIsPrint(udfName[index+1])*/) &&
648                               udfName[index+1] != UNICODE_PERIOD)
649                             index++;
650                     }
651                     // Add current char to either file name or ext.
652                     if (writingExt) {
653                         ext[extIndex] = current;
654                         extIndex++;
655                     } else {
656                         dosName[dosIndex] = current;
657                         dosIndex++;
658                     }
659                 }
660             }
661         }
662         // See if we are done with file name, either because we reached
663         // the end of the file name length, or the final period.
664         if (!writingExt && hasExt && (dosIndex == DOS_NAME_LEN ||
665             index == lastPeriodIndex)) {
666             // If so, and the name has an extension, start reading it.
667             writingExt = TRUE;
668             // Extension starts after last period.
669             index = lastPeriodIndex;
670         }
671     }
672     // Now handle CRC if needed.
673     if (needsCRC) {
674         // Add CRC to end of file name or at position 4.
675         if (dosIndex >4) dosIndex = 4;
676         valueCRC = Mode150 ? UDFUnicodeCksum150(udfName, udfLen) : UDFUnicodeCksum(udfName, udfLen);
677         // Convert 16-bit CRC to hex characters.
678         dosName[dosIndex] = hexChar[(valueCRC & 0xf000) >> 12];
679         dosName[dosIndex+1] = hexChar[(valueCRC & 0x0f00) >> 8];
680         dosName[dosIndex+2] = hexChar[(valueCRC & 0x00f0) >> 4];
681         dosName[dosIndex+3] = hexChar[(valueCRC & 0x000f)];
682         dosIndex+=4;
683     }
684     // Add extension, if any.
685     if (extIndex != 0) {
686         dosName[dosIndex] = UNICODE_PERIOD;
687         dosIndex++;
688         for (index = 0; index < extIndex; index++) {
689             dosName[dosIndex] = ext[index];
690             dosIndex++;
691         }
692     }
693     DosName->Length = (uint16)dosIndex*sizeof(WCHAR);
694     RtlUpcaseUnicodeString(DosName, DosName, FALSE);
695 } // end UDFDOSName200()
696 
697 
698 void
699 __fastcall
700 UDFDOSName201(
701     IN OUT PUNICODE_STRING DosName,
702     IN PUNICODE_STRING UdfName,
703     IN BOOLEAN KeepIntact
704     )
705 {
706     PWCHAR dosName = DosName->Buffer;
707     PWCHAR udfName = UdfName->Buffer;
708     uint16 udfLen = UdfName->Length / sizeof(WCHAR);
709 
710     uint16 index, dosIndex = 0;
711     //uint16 extIndex = 0;
712     BOOLEAN needsCRC = FALSE, isParent = FALSE;
713     //BOOLEAN hasExt = FALSE, writingExt = FALSE;
714     uint16 valueCRC;
715     WCHAR ext[DOS_EXT_LEN];
716     WCHAR current;
717 
718     if(KeepIntact &&
719        (udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) {
720         isParent = TRUE;
721         if((udfLen == 2) && (udfName[1] != UNICODE_PERIOD))
722             isParent = FALSE;
723     }
724 
725     #define DOS_CRC_LEN 4
726     #define DOS_CRC_MODULUS 41
727 
728     int16 crcIndex;
729     uint16 extLen;
730     uint16 nameLen;
731     uint16 charLen;
732     int16 overlayBytes;
733     int16 bytesLeft;
734 
735     /* Start at the end of the UDF file name and scan for a period */
736     /* ('.'). This will be where the DOS extension starts (if */
737     /* any). */
738     index = udfLen;
739     while (index-- > 0) {
740         if (udfName[index] == '.')
741             break;
742     }
743     if ((index < 0) || isParent) {
744         /* There name was scanned to the beginning of the buffer */
745         /* and no extension was found. */
746         extLen = 0;
747         nameLen = udfLen;
748     } else {
749         /* A DOS extension was found, process it first. */
750         extLen = udfLen - index - 1;
751         nameLen = index;
752         dosIndex = 0;
753         bytesLeft = DOS_EXT_LEN;
754         while (++index < udfLen && bytesLeft > 0) {
755             /* Get the current character and convert it to upper */
756             /* case. */
757             current = udfName[index];
758             if (current == ' ') {
759                 /* If a space is found, a CRC must be appended to */
760                 /* the mangled file name. */
761                 needsCRC = TRUE;
762             } else {
763                 /* Determine if this is a valid file name char and */
764                 /* calculate its corresponding BCS character byte */
765                 /* length (zero if the char is not legal or */
766                 /* undisplayable on this system). */
767 
768                 charLen = (UDFIsIllegalChar(current)
769                            /*|| !UnicodeIsPrint(current)*/) ? 0 : 1;
770 
771                 /* If the char is larger than the available space */
772                 /* in the buffer, pretend it is undisplayable. */
773                 if (charLen > bytesLeft)
774                     charLen = 0;
775                 if (charLen == 0) {
776                 /* Undisplayable or illegal characters are */
777                 /* substituted with an underscore ("_"), and */
778                 /* required a CRC code appended to the mangled */
779                 /* file name. */
780                 needsCRC = TRUE;
781                 charLen = 1;
782                 current = '_';
783                 /* Skip over any following undiplayable or */
784                 /* illegal chars. */
785                 while (index +1 <udfLen &&
786                         (UDFIsIllegalChar(udfName[index+1])
787                        /*|| !UnicodeIsPrint(udfName[index+1])*/))
788                     index++;
789                 }
790                 /* Assign the resulting char to the next index in */
791                 /* the extension buffer and determine how many BCS */
792                 /* bytes are left. */
793                 ext[dosIndex++] = current;
794                 bytesLeft -= charLen;
795             }
796         }
797         /* Save the number of Unicode characters in the extension */
798         extLen = dosIndex;
799         /* If the extension was too large, or it was zero length */
800         /* (i.e. the name ended in a period), a CRC code must be */
801         /* appended to the mangled name. */
802         if (index < udfLen || extLen == 0)
803             needsCRC = TRUE;
804     }
805     /* Now process the actual file name. */
806     index = 0;
807     dosIndex = 0;
808     crcIndex = 0;
809     overlayBytes = -1;
810     bytesLeft = DOS_NAME_LEN;
811     while (index < nameLen && bytesLeft > 0) {
812         /* Get the current character and convert it to upper case. */
813         current = udfName[index];
814         if (current ==' ' || (current == '.' && !isParent) ) {
815             /* Spaces and periods are just skipped, a CRC code */
816             /* must be added to the mangled file name. */
817             needsCRC = TRUE;
818         } else {
819             /* Determine if this is a valid file name char and */
820             /* calculate its corresponding BCS character byte */
821             /* length (zero if the char is not legal or */
822             /* undisplayable on this system). */
823 
824             charLen = (UDFIsIllegalChar(current)
825                        /*|| !UnicodeIsPrint(current)*/) ? 0 : 1;
826 
827             /* If the char is larger than the available space in */
828             /* the buffer, pretend it is undisplayable. */
829             if (charLen > bytesLeft)
830                 charLen = 0;
831 
832             if (charLen == 0) {
833                 /* Undisplayable or illegal characters are */
834                 /* substituted with an underscore ("_"), and */
835                 /* required a CRC code appended to the mangled */
836                 /* file name. */
837                 needsCRC = TRUE;
838                 charLen = 1;
839                 current = '_';
840                 /* Skip over any following undisplayable or illegal */
841                 /* chars. */
842                 while (index +1 <nameLen &&
843                        (UDFIsIllegalChar(udfName[index+1])
844                         /*|| !UnicodeIsPrint(udfName[index+1])*/))
845                     index++;
846                 /* Terminate loop if at the end of the file name. */
847                 if (index >= nameLen)
848                     break;
849             }
850             /* Assign the resulting char to the next index in the */
851             /* file name buffer and determine how many BCS bytes */
852             /* are left. */
853             dosName[dosIndex++] = current;
854             bytesLeft -= charLen;
855             /* This figures out where the CRC code needs to start */
856             /* in the file name buffer. */
857             if (bytesLeft >= DOS_CRC_LEN) {
858                 /* If there is enough space left, just tack it */
859                 /* onto the end. */
860                 crcIndex = dosIndex;
861             } else {
862                 /* If there is not enough space left, the CRC */
863                 /* must overlay a character already in the file */
864                 /* name buffer. Once this condition has been */
865                 /* met, the value will not change. */
866                 if (overlayBytes < 0) {
867                     /* Determine the index and save the length of */
868                     /* the BCS character that is overlayed. It */
869                     /* is possible that the CRC might overlay */
870                     /* half of a two-byte BCS character depending */
871                     /* upon how the character boundaries line up. */
872                     overlayBytes = (bytesLeft + charLen > DOS_CRC_LEN)?1 :0;
873                     crcIndex = dosIndex - 1;
874                 }
875             }
876         }
877         /* Advance to the next character. */
878         index++;
879     }
880     /* If the scan did not reach the end of the file name, or the */
881     /* length of the file name is zero, a CRC code is needed. */
882     if (index < nameLen || index == 0)
883         needsCRC = TRUE;
884 
885     /* If the name has illegal characters or and extension, it */
886     /* is not a DOS device name. */
887 
888 /*    if (needsCRC == FALSE && extLen == 0) { */
889         /* If this is the name of a DOS device, a CRC code should */
890         /* be appended to the file name.
891         if (IsDeviceName(udfName, udfLen))
892             needsCRC = TRUE;
893     }*/
894 
895     /* Append the CRC code to the file name, if needed. */
896     if (needsCRC) {
897         /* Get the CRC value for the original Unicode string */
898         valueCRC = UDFUnicodeCksum(udfName, udfLen);
899 
900         /* begin. */
901         dosIndex = crcIndex;
902         /* If the character being overlayed is a two-byte BCS */
903         /* character, replace the first byte with an underscore. */
904         if (overlayBytes > 0)
905             dosName[dosIndex++] = '_';
906         /* Append the encoded CRC value with delimiter. */
907         dosName[dosIndex++] = '#';
908         dosName[dosIndex++] =
909             crcChar[valueCRC / (DOS_CRC_MODULUS * DOS_CRC_MODULUS)];
910         valueCRC %= DOS_CRC_MODULUS * DOS_CRC_MODULUS;
911             dosName[dosIndex++] =
912         crcChar[valueCRC / DOS_CRC_MODULUS];
913             valueCRC %= DOS_CRC_MODULUS;
914         dosName[dosIndex++] = crcChar[valueCRC];
915     }
916     /* Append the extension, if any. */
917     if (extLen > 0) {
918         /* Tack on a period and each successive byte in the */
919         /* extension buffer. */
920         dosName[dosIndex++] = '.';
921         for (index = 0; index < extLen; index++)
922             dosName[dosIndex++] = ext[index];
923     }
924     /* Return the length of the resulting Unicode string. */
925     DosName->Length = (uint16)dosIndex*sizeof(WCHAR);
926     RtlUpcaseUnicodeString(DosName, DosName, FALSE);
927 
928 } // end UDFDOSName201()
929 
930 #ifndef UDF_READ_ONLY_BUILD
931 /*
932     This routine initializes Tag structure. It must be called after all
933     manual settings to generate valid CRC & Checksum
934  */
935 void
936 UDFSetUpTag(
937     IN PVCB Vcb,
938     IN tag* Tag,
939     IN uint16 DataLen,  // total length of descriptor _including_ icbTag
940     IN uint32 TagLoc
941     )
942 {
943     uint32 i;
944     int8* tb;
945 
946     AdPrint(("UDF: SetTag Loc=%x(%x), tagIdent=%x\n", TagLoc, Tag->tagLocation, Tag->tagIdent));
947 
948     if(DataLen) DataLen -= sizeof(tag);
949 //    int8* Data = ((int8*)Tag) + sizeof(tag);
950     // Ecma-167 states, that all implementations
951     // shall set this field to '3' even if
952     // disc contains descriptors recorded with
953     // value '2'
954     // But we should ignore this to make happy othe UDF implementations :(
955     Tag->descVersion = (Vcb->NSRDesc & VRS_NSR03_FOUND) ? 3 : 2;
956     Tag->tagLocation = TagLoc;
957     Tag->tagSerialNum = (uint16)(Vcb->SerialNumber + 1);
958     Tag->descCRCLength = DataLen;
959     Tag->descCRC = UDFCrc((uint8*)(Tag+1), DataLen);
960     Tag->tagChecksum = 0;
961     tb = ((int8*)Tag);
962     for (i=0; i<sizeof(tag); i++,tb++)
963         Tag->tagChecksum += (i!=4) ? (*tb) : 0;
964 } // end UDFSetUpTag()
965 
966 /*
967     This routine builds FileEntry & associated AllocDescs for specified
968     extent.
969  */
970 OSSTATUS
971 UDFBuildFileEntry(
972     IN PVCB Vcb,
973     IN PUDF_FILE_INFO DirInfo,
974     IN PUDF_FILE_INFO FileInfo,
975     IN uint32 PartNum,
976     IN uint16 AllocMode, // short/long/ext/in-icb
977     IN uint32 ExtAttrSz,
978     IN BOOLEAN Extended
979     )
980 {
981     PFILE_ENTRY FileEntry;
982     OSSTATUS status;
983 //    EntityID* eID;
984     uint32 l;
985     EXTENT_INFO _FEExtInfo;
986     uint16* lcp;
987 
988     ASSERT(!PartNum);
989     ASSERT(!ExtAttrSz);
990     // calculate the length required
991     l = (Extended ? sizeof(EXTENDED_FILE_ENTRY) : sizeof(FILE_ENTRY)) + ExtAttrSz;
992     if(l > Vcb->LBlockSize) return STATUS_INVALID_PARAMETER;
993     // allocate block for FE
994     if(!OS_SUCCESS(status = UDFAllocateFESpace(Vcb, DirInfo, PartNum, &_FEExtInfo, l) ))
995         return status;
996     // remember FE location for future hard link creation
997     ASSERT(UDFFindDloc(Vcb, _FEExtInfo.Mapping[0].extLocation) == (-1));
998     if(!OS_SUCCESS(status = UDFStoreDloc(Vcb, FileInfo, _FEExtInfo.Mapping[0].extLocation))) {
999         ASSERT(status != STATUS_SHARING_PAUSED);
1000         UDFFreeFESpace(Vcb, DirInfo, &_FEExtInfo); // free
1001         MyFreePool__(_FEExtInfo.Mapping);
1002         return status;
1003     }
1004     FileEntry = (PFILE_ENTRY)MyAllocatePoolTag__(NonPagedPool, l, MEM_FE_TAG);
1005     if(!FileEntry) {
1006         UDFRemoveDloc(Vcb, FileInfo->Dloc);
1007         FileInfo->Dloc = NULL;
1008         UDFFreeFESpace(Vcb, DirInfo, &_FEExtInfo); // free
1009         MyFreePool__(_FEExtInfo.Mapping);
1010         return STATUS_INSUFFICIENT_RESOURCES;
1011     }
1012     FileInfo->Dloc->FELoc = _FEExtInfo;
1013 
1014     RtlZeroMemory((int8*)FileEntry, l);
1015     // set up in-memory FE structure
1016     FileEntry->icbTag.flags = AllocMode;
1017     FileEntry->icbTag.fileType = UDF_FILE_TYPE_REGULAR;
1018     FileEntry->icbTag.numEntries = 1;
1019 //    if(DirInfo && DirInfo->Dloc && DirInfo->Dloc
1020     FileEntry->icbTag.strategyType = 4;
1021 //    FileEntry->icbTag.strategyParameter = 0;
1022     FileEntry->descTag.tagIdent = Extended ? TID_EXTENDED_FILE_ENTRY : TID_FILE_ENTRY;
1023     FileEntry->descTag.tagLocation = UDFPhysLbaToPart(Vcb, PartNum, _FEExtInfo.Mapping[0].extLocation);
1024     FileEntry->uid = Vcb->DefaultUID;
1025     FileEntry->gid = Vcb->DefaultGID;
1026 
1027     if(Extended) {
1028 //        eID = &(((PEXTENDED_FILE_ENTRY)FileEntry)->impIdent);
1029         lcp = &(((PEXTENDED_FILE_ENTRY)FileEntry)->fileLinkCount);
1030         ((PEXTENDED_FILE_ENTRY)FileEntry)->checkpoint = 1;
1031     } else {
1032 //        eID = &(FileEntry->impIdent);
1033         lcp = &(FileEntry->fileLinkCount);
1034         ((PFILE_ENTRY)FileEntry)->checkpoint = 1;
1035     }
1036 
1037 #if 0
1038     UDFSetEntityID_imp(eID, UDF_ID_DEVELOPER);
1039 #endif
1040 
1041     /*RtlCopyMemory((int8*)&(eID->ident), UDF_ID_DEVELOPER, sizeof(UDF_ID_DEVELOPER) );
1042     iis = (impIdentSuffix*)&(eID->identSuffix);
1043     iis->OSClass = UDF_OS_CLASS_WINNT;
1044     iis->OSIdent = UDF_OS_ID_WINNT;*/
1045 
1046     *lcp = 0xffff;
1047 
1048     FileInfo->Dloc->FileEntry = (tag*)FileEntry;
1049     FileInfo->Dloc->FileEntryLen = l;
1050 
1051     FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1052 
1053     return STATUS_SUCCESS;
1054 } // end UDFBuildFileEntry()
1055 #endif //UDF_READ_ONLY_BUILD
1056 
1057 /*
1058     This routine builds ExtentInfo for specified (Ex)FileEntry & associated
1059     AllocDescs
1060  */
1061 OSSTATUS
1062 UDFLoadExtInfo(
1063     IN PVCB Vcb,
1064     IN PFILE_ENTRY fe,
1065     IN PLONG_AD fe_loc,
1066  IN OUT PEXTENT_INFO FExtInfo,  // user data
1067  IN OUT PEXTENT_INFO AExtInfo   // alloc descs
1068     )
1069 {
1070     EXTENT_AD TmpExt;
1071 
1072     UDFPrint(("  UDFLoadExtInfo:\n"));
1073     FExtInfo->Mapping = UDFReadMappingFromXEntry(Vcb, fe_loc->extLocation.partitionReferenceNum,
1074                                        (tag*)fe, &(FExtInfo->Offset), AExtInfo);
1075     if(!(FExtInfo->Mapping)) {
1076         if(!(FExtInfo->Offset))
1077             return STATUS_UNSUCCESSFUL;
1078         TmpExt.extLength = fe_loc->extLength;
1079         TmpExt.extLocation = UDFPartLbaToPhys(Vcb, &(fe_loc->extLocation));
1080         if(TmpExt.extLocation == LBA_OUT_OF_EXTENT)
1081             return STATUS_FILE_CORRUPT_ERROR;
1082         FExtInfo->Mapping = UDFExtentToMapping(&TmpExt);
1083     }
1084     if(fe->descTag.tagIdent == TID_FILE_ENTRY) {
1085 //        UDFPrint(("Standard FileEntry\n"));
1086         FExtInfo->Length = fe->informationLength;
1087     } else /*if(fe->descTag.tagIdent == TID_EXTENDED_FILE_ENTRY) */ {
1088         FExtInfo->Length = ((PEXTENDED_FILE_ENTRY)fe)->informationLength;
1089     }
1090     UDFPrint(("  FExtInfo->Length %x\n", FExtInfo->Length));
1091     ASSERT(FExtInfo->Length <= UDFGetExtentLength(FExtInfo->Mapping));
1092     FExtInfo->Modified = FALSE;
1093 
1094     return STATUS_SUCCESS;
1095 } // end UDFLoadExtInfo()
1096 
1097 /*
1098     This routine builds FileIdent for specified FileEntry.
1099     We shall call UDFSetUpTag after all other initializations
1100     This structure is a precise copy of on-disk FileIdent
1101     structure. All modifications of it (including memory block
1102     size) are reflected on Directory extent. This, allocation of
1103     too long block (without changes in ImpUseLen) will lead to
1104     unreadable Directory
1105  */
1106 OSSTATUS
1107 UDFBuildFileIdent(
1108     IN PVCB Vcb,
1109     IN PUNICODE_STRING fn,
1110     IN PLONG_AD FileEntryIcb,       // virtual address of FileEntry
1111     IN uint32 ImpUseLen,
1112     OUT PFILE_IDENT_DESC* _FileId,
1113     OUT uint32* FileIdLen
1114     )
1115 {
1116     PFILE_IDENT_DESC FileId;
1117     uint8* CS0;
1118     uint32 Nlen, l;
1119     // prepare filename
1120     UDFCompressUnicode(fn, &CS0, &Nlen);
1121     if(!CS0) return STATUS_INSUFFICIENT_RESOURCES;
1122     if(Nlen < 2) {
1123         Nlen = 0;
1124     } else
1125     if(Nlen > UDF_NAME_LEN) {
1126         if(CS0) MyFreePool__(CS0);
1127         return STATUS_OBJECT_NAME_INVALID;
1128     }
1129     // allocate memory for FI
1130     l = (sizeof(FILE_IDENT_DESC) + Nlen + ImpUseLen + 3) & ~((uint32)3);
1131     FileId = (PFILE_IDENT_DESC)MyAllocatePoolTag__(NonPagedPool, l, MEM_FID_TAG);
1132     if(!FileId) {
1133         if(CS0) MyFreePool__(CS0);
1134         return STATUS_INSUFFICIENT_RESOURCES;
1135     }
1136     // fill FI structure
1137     RtlZeroMemory( (int8*)FileId, l);
1138     RtlCopyMemory( ((int8*)(FileId+1))+ImpUseLen, CS0, Nlen);
1139     FileId->descTag.tagIdent = TID_FILE_IDENT_DESC;
1140     FileId->fileVersionNum = 1;
1141     FileId->lengthOfImpUse = (uint16)ImpUseLen;
1142     FileId->lengthFileIdent = (uint8)Nlen;
1143     FileId->icb = *FileEntryIcb;
1144     *_FileId = FileId;
1145     *FileIdLen = l;
1146 
1147     if(CS0) MyFreePool__(CS0);
1148     return STATUS_SUCCESS;
1149 } // end UDFBuildFileIdent()
1150 
1151 #ifndef UDF_READ_ONLY_BUILD
1152 /*
1153     This routine sets informationLength field in (Ext)FileEntry
1154  */
1155 void
1156 UDFSetFileSize(
1157     IN PUDF_FILE_INFO FileInfo,
1158     IN int64 Size
1159     )
1160 {
1161     uint16 Ident;
1162 //    PDIR_INDEX_ITEM DirIndex;
1163 
1164     ValidateFileInfo(FileInfo);
1165     AdPrint(("UDFSetFileSize: %I64x, FI %x\n", Size, FileInfo));
1166 
1167     //AdPrint(("  Dloc %x\n", FileInfo->Dloc));
1168     FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1169     //AdPrint(("  FileEntry %x\n", FileInfo->Dloc->FileEntry));
1170     Ident = FileInfo->Dloc->FileEntry->tagIdent;
1171     //AdPrint(("  Ident %x\n", Ident));
1172     if(Ident == TID_FILE_ENTRY) {
1173         PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1174         //AdPrint(("  fe %x\n", fe));
1175         fe->informationLength = Size;
1176     } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1177         PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1178         //AdPrint(("  ext-fe %x\n", fe));
1179         fe->informationLength = Size;
1180     }
1181 /*    if(DirIndex = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index) ) {
1182         DirIndex->FileSize = Size;
1183     }*/
1184     //AdPrint(("UDFSetFileSize: ok\n"));
1185     return;
1186 } // end UDFSetFileSize()
1187 
1188 void
1189 UDFSetFileSizeInDirNdx(
1190     IN PVCB Vcb,
1191     IN PUDF_FILE_INFO FileInfo,
1192     IN int64* ASize
1193     )
1194 {
1195     uint16 Ident;
1196     PDIR_INDEX_ITEM DirIndex;
1197 
1198     ValidateFileInfo(FileInfo);
1199     if(ASize) {
1200         AdPrint(("UDFSetFileSizeInDirNdx: %I64x\n", *ASize));
1201     } else {
1202         AdPrint(("UDFSetFileSizeInDirNdx: sync\n"));
1203     }
1204 
1205     DirIndex = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index);
1206     if(!DirIndex)
1207        return;
1208 
1209     Ident = FileInfo->Dloc->FileEntry->tagIdent;
1210     if(Ident == TID_FILE_ENTRY) {
1211         PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1212         DirIndex->FileSize = fe->informationLength;
1213         if(ASize) {
1214             DirIndex->AllocationSize = *ASize;
1215 //        } else {
1216 //            DirIndex->AllocationSize = (fe->informationLength + Vcb->LBlockSize - 1) & ~(Vcb->LBlockSize - 1);
1217         }
1218     } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1219         PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1220         DirIndex->FileSize = fe->informationLength;
1221         if(ASize) {
1222             DirIndex->AllocationSize = *ASize;
1223 //        } else {
1224 //            DirIndex->AllocationSize = (fe->informationLength + Vcb->LBlockSize - 1) & ~(Vcb->LBlockSize - 1);
1225         }
1226     }
1227     return;
1228 } // end UDFSetFileSizeInDirNdx()
1229 #endif //UDF_READ_ONLY_BUILD
1230 
1231 /*
1232     This routine gets informationLength field in (Ext)FileEntry
1233  */
1234 int64
1235 UDFGetFileSize(
1236     IN PUDF_FILE_INFO FileInfo
1237     )
1238 {
1239     uint16 Ident;
1240 
1241     ValidateFileInfo(FileInfo);
1242 
1243     Ident = FileInfo->Dloc->FileEntry->tagIdent;
1244     if(Ident == TID_FILE_ENTRY) {
1245         PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1246         return fe->informationLength;
1247     } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1248         PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1249         return fe->informationLength;
1250     }
1251     return (-1);
1252 } // end UDFGetFileSize()
1253 
1254 int64
1255 UDFGetFileSizeFromDirNdx(
1256     IN PVCB Vcb,
1257     IN PUDF_FILE_INFO FileInfo
1258     )
1259 {
1260     PDIR_INDEX_ITEM DirIndex;
1261 
1262     ValidateFileInfo(FileInfo);
1263 
1264     DirIndex = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index);
1265     if(!DirIndex)
1266        return -1;
1267 
1268     return DirIndex->FileSize;
1269 } // end UDFGetFileSizeFromDirNdx()
1270 
1271 #ifndef UDF_READ_ONLY_BUILD
1272 /*
1273     This routine sets lengthAllocDesc field in (Ext)FileEntry
1274  */
1275 void
1276 UDFSetAllocDescLen(
1277     IN PVCB Vcb,
1278     IN PUDF_FILE_INFO FileInfo
1279     )
1280 {
1281     uint16 Ident;
1282 
1283     ValidateFileInfo(FileInfo);
1284 
1285     FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1286     Ident = FileInfo->Dloc->FileEntry->tagIdent;
1287     if(Ident == TID_FILE_ENTRY) {
1288         PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1289         if(FileInfo->Dloc->AllocLoc.Length) {
1290             fe->lengthAllocDescs = min(FileInfo->Dloc->AllocLoc.Mapping[0].extLength -
1291                                        FileInfo->Dloc->AllocLoc.Offset,
1292                                        (uint32)(FileInfo->Dloc->AllocLoc.Length));
1293         } else
1294         if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
1295             fe->lengthAllocDescs = (uint32)(FileInfo->Dloc->DataLoc.Length);
1296         }
1297     } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1298         PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1299         if(FileInfo->Dloc->AllocLoc.Length) {
1300             fe->lengthAllocDescs = min(FileInfo->Dloc->AllocLoc.Mapping[0].extLength -
1301                                        FileInfo->Dloc->AllocLoc.Offset,
1302                                        (uint32)(FileInfo->Dloc->AllocLoc.Length));
1303         } else
1304         if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
1305             fe->lengthAllocDescs = (uint32)(FileInfo->Dloc->DataLoc.Length);
1306         }
1307     }
1308 } // end UDFSetAllocDescLen()
1309 
1310 /*
1311     This routine changes fileLinkCount field in (Ext)FileEntry
1312  */
1313 void
1314 UDFChangeFileLinkCount(
1315     IN PUDF_FILE_INFO FileInfo,
1316     IN BOOLEAN Increase
1317     )
1318 {
1319     uint16 Ident;
1320 
1321     ValidateFileInfo(FileInfo);
1322 
1323     FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1324     Ident = FileInfo->Dloc->FileEntry->tagIdent;
1325     if(Ident == TID_FILE_ENTRY) {
1326         PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1327         if(Increase) {
1328             fe->fileLinkCount++;
1329         } else {
1330             fe->fileLinkCount--;
1331         }
1332         if(fe->fileLinkCount & 0x8000)
1333             fe->fileLinkCount = 0xffff;
1334         return;
1335     } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1336         PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1337         if(Increase) {
1338             fe->fileLinkCount++;
1339         } else {
1340             fe->fileLinkCount--;
1341         }
1342         if(fe->fileLinkCount & 0x8000)
1343             fe->fileLinkCount = 0xffff;
1344         return;
1345     }
1346     return;
1347 } // end UDFChangeFileLinkCount()
1348 #endif //UDF_READ_ONLY_BUILD
1349 
1350 /*
1351     This routine gets fileLinkCount field from (Ext)FileEntry
1352  */
1353 uint16
1354 UDFGetFileLinkCount(
1355     IN PUDF_FILE_INFO FileInfo
1356     )
1357 {
1358     uint16 Ident;
1359     uint16 d;
1360 
1361     ValidateFileInfo(FileInfo);
1362 
1363     if(!FileInfo->Dloc->FileEntry)
1364         return 1;
1365     Ident = FileInfo->Dloc->FileEntry->tagIdent;
1366     // UDF engine assumes that LinkCount is a counter
1367     // of FileIdents, referencing this FE.
1368     // UDF 2.0 states, that it should be counter of ALL
1369     // references (including SDir) - 1.
1370     // Thus we'll write to media UDF-required value, but return
1371     // cooked value to callers
1372     d = UDFHasAStreamDir(FileInfo) ? 0 : 1;
1373     if(Ident == TID_FILE_ENTRY) {
1374         return ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount + d;
1375     } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1376         return ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount + d;
1377     }
1378     return UDF_INVALID_LINK_COUNT;
1379 } // end UDFGetFileLinkCount()
1380 
1381 #ifdef UDF_CHECK_UTIL
1382 /*
1383     This routine sets fileLinkCount field in (Ext)FileEntry
1384  */
1385 void
1386 UDFSetFileLinkCount(
1387     IN PUDF_FILE_INFO FileInfo,
1388     uint16 LinkCount
1389     )
1390 {
1391     uint16 Ident;
1392     uint16 d;
1393 
1394     ValidateFileInfo(FileInfo);
1395 
1396     if(!FileInfo->Dloc->FileEntry)
1397         return;
1398     Ident = FileInfo->Dloc->FileEntry->tagIdent;
1399     // UDF engine assumes that LinkCount is a counter
1400     // of FileIdents, referencing this FE.
1401     // UDF 2.0 states, that it should be counter of ALL
1402     // references (including SDir) - 1.
1403     // Thus we'll write to media UDF-required value, but return
1404     // cooked value to callers
1405     d = UDFHasAStreamDir(FileInfo) ? 0 : 1;
1406     if(Ident == TID_FILE_ENTRY) {
1407         ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount = LinkCount - d;
1408     } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1409         ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount = LinkCount - d;
1410     }
1411     return;
1412 } // end UDFGetFileLinkCount()
1413 #endif //UDF_CHECK_UTIL
1414 
1415 /*
1416     This routine gets lengthExtendedAttr field in (Ext)FileEntry
1417  */
1418 uint32
1419 UDFGetFileEALength(
1420     IN PUDF_FILE_INFO FileInfo
1421     )
1422 {
1423     uint16 Ident;
1424 
1425     ValidateFileInfo(FileInfo);
1426 
1427     if(!FileInfo->Dloc->FileEntry)
1428         return 1;
1429     Ident = FileInfo->Dloc->FileEntry->tagIdent;
1430 
1431     if(Ident == TID_FILE_ENTRY) {
1432         return ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->lengthExtendedAttr;
1433     } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1434         return ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->lengthExtendedAttr;
1435     }
1436     return 0;
1437 } // end UDFGetFileEALength()
1438 
1439 #ifndef UDF_READ_ONLY_BUILD
1440 /*
1441     This routine sets UniqueID field in (Ext)FileEntry
1442  */
1443 int64
1444 UDFAssingNewFUID(
1445     IN PVCB Vcb
1446     )
1447 {
1448     Vcb->NextUniqueId++;
1449     if(!((uint32)(Vcb->NextUniqueId)))
1450         Vcb->NextUniqueId += 16;
1451     return Vcb->NextUniqueId;
1452 }
1453 
1454 void
1455 UDFSetFileUID(
1456     IN PVCB Vcb,
1457     IN PUDF_FILE_INFO FileInfo
1458     )
1459 {
1460     uint16 Ident;
1461     int64 UID;
1462 
1463     ValidateFileInfo(FileInfo);
1464 
1465     UID = UDFAssingNewFUID(Vcb);
1466 
1467 /*    UID = FileInfo->Dloc->FELoc.Mapping[0].extLocation |
1468           ( FileInfo->ParentFile ? (((int64)(FileInfo->ParentFile->Dloc->FELoc.Mapping[0].extLocation)) << 32) : 0);*/
1469 
1470     FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1471     Ident = FileInfo->Dloc->FileEntry->tagIdent;
1472     if(Ident == TID_FILE_ENTRY) {
1473         PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1474         fe->uniqueID = UID;
1475     } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1476         PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1477         fe->uniqueID = UID;
1478     }
1479     if(FileInfo->FileIdent)
1480         ((FidADImpUse*)&(FileInfo->FileIdent->icb.impUse))->uniqueID = (uint32)UID;
1481     return;
1482 } // end UDFSetFileUID()
1483 #endif //UDF_READ_ONLY_BUILD
1484 
1485 /*
1486     This routine gets UniqueID field in (Ext)FileEntry
1487  */
1488 __inline
1489 int64
1490 UDFGetFileUID_(
1491     IN tag* FileEntry
1492     )
1493 {
1494     uint16 Ident;
1495 
1496     Ident = FileEntry->tagIdent;
1497     if(Ident == TID_FILE_ENTRY) {
1498         PFILE_ENTRY fe = (PFILE_ENTRY)(FileEntry);
1499         return fe->uniqueID;
1500     } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1501         PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileEntry);
1502         return fe->uniqueID;
1503     }
1504     return (-1);
1505 } // end UDFGetFileUID()
1506 
1507 int64
1508 UDFGetFileUID(
1509     IN PUDF_FILE_INFO FileInfo
1510     )
1511 {
1512     ValidateFileInfo(FileInfo);
1513 
1514     return UDFGetFileUID_(FileInfo->Dloc->FileEntry);
1515 } // end UDFGetFileUID()
1516 
1517 #ifndef UDF_READ_ONLY_BUILD
1518 void
1519 UDFChangeFileCounter(
1520     IN PVCB Vcb,
1521     IN BOOLEAN FileCounter,
1522     IN BOOLEAN Increase
1523     )
1524 {
1525     uint32* counter;
1526 
1527     counter = FileCounter ?
1528         &(Vcb->numFiles) :
1529         &(Vcb->numDirs);
1530     if(*counter == (ULONG)-1)
1531         return;
1532     if(Increase) {
1533         UDFInterlockedIncrement((int32*)counter);
1534     } else {
1535         UDFInterlockedDecrement((int32*)counter);
1536     }
1537 
1538 } // end UDFChangeFileCounter()
1539 
1540 void
1541 UDFSetEntityID_imp_(
1542     IN EntityID* eID,
1543     IN uint8* Str,
1544     IN uint32 Len
1545     )
1546 {
1547     impIdentSuffix* iis;
1548 
1549     RtlCopyMemory( (int8*)&(eID->ident), Str, Len );
1550     iis = (impIdentSuffix*)&(eID->identSuffix);
1551     iis->OSClass = UDF_OS_CLASS_WINNT;
1552     iis->OSIdent = UDF_OS_ID_WINNT;
1553 
1554 } // end UDFSetEntityID_imp_()
1555 #endif //UDF_READ_ONLY_BUILD
1556 
1557 void
1558 UDFReadEntityID_Domain(
1559     PVCB Vcb,
1560     EntityID* eID
1561     )
1562 {
1563     domainIdentSuffix* dis;
1564     uint8 flags;
1565 
1566     dis = (domainIdentSuffix*)&(eID->identSuffix);
1567 
1568     UDFPrint(("UDF: Entity Id:\n"));
1569     UDFPrint(("flags: %x\n", eID->flags));
1570     UDFPrint(("ident[0]: %x\n", eID->ident[0]));
1571     UDFPrint(("ident[1]: %x\n", eID->ident[1]));
1572     UDFPrint(("ident[2]: %x\n", eID->ident[2]));
1573     UDFPrint(("ident[3]: %x\n", eID->ident[3]));
1574     UDFPrint(("UDF: Entity Id Domain:\n"));
1575     // Get current UDF revision
1576     Vcb->CurrentUDFRev = max(dis->currentRev, Vcb->CurrentUDFRev);
1577     UDFPrint(("Effective Revision: %x\n", Vcb->CurrentUDFRev));
1578     // Get Read-Only flags
1579     flags = dis->flags;
1580     UDFPrint(("Flags: %x\n", flags));
1581     if((flags & ENTITYID_FLAGS_SOFT_RO) &&
1582         (Vcb->CompatFlags & UDF_VCB_IC_SOFT_RO)) {
1583         Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY;
1584         Vcb->UserFSFlags |= UDF_USER_FS_FLAGS_SOFT_RO;
1585         UDFPrint(("       Soft-RO\n"));
1586     }
1587     if((flags & ENTITYID_FLAGS_HARD_RO) &&
1588        (Vcb->CompatFlags & UDF_VCB_IC_HW_RO)) {
1589         Vcb->VCBFlags |= UDF_VCB_FLAGS_MEDIA_READ_ONLY;
1590         Vcb->UserFSFlags |= UDF_USER_FS_FLAGS_HW_RO;
1591         UDFPrint(("       Hard-RO\n"));
1592     }
1593 
1594 } // end UDFReadEntityID_Domain()
1595 
1596 #ifndef UDF_READ_ONLY_BUILD
1597 /*
1598     This routine writes data to file & increases it if necessary.
1599     In case of increasing AllocDescs will be rebuilt & flushed to disc
1600     (via driver's cache, of cource). Free space map will be updated only
1601     durring global media flush.
1602  */
1603 OSSTATUS
1604 UDFWriteFile__(
1605     IN PVCB Vcb,
1606     IN PUDF_FILE_INFO FileInfo,
1607     IN int64 Offset,
1608     IN uint32 Length,
1609     IN BOOLEAN Direct,
1610     IN int8* Buffer,
1611     OUT uint32* WrittenBytes
1612     )
1613 {
1614     int64 t, elen;
1615     OSSTATUS status;
1616     int8* OldInIcb = NULL;
1617     ValidateFileInfo(FileInfo);
1618     uint32 ReadBytes;
1619     uint32 _WrittenBytes;
1620     PUDF_DATALOC_INFO Dloc;
1621     // unwind staff
1622     BOOLEAN WasInIcb = FALSE;
1623     uint64 OldLen;
1624 
1625 //    ASSERT(FileInfo->RefCount >= 1);
1626 
1627     Dloc = FileInfo->Dloc;
1628     ASSERT(Dloc->FELoc.Mapping[0].extLocation);
1629     uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, Dloc->FELoc.Mapping[0].extLocation);
1630     (*WrittenBytes) = 0;
1631 
1632     AdPrint(("UDFWriteFile__ FE %x, FileInfo %x, ExtInfo %x, Mapping %x\n",
1633         Dloc->FELoc.Mapping[0].extLocation, FileInfo, &(Dloc->DataLoc), Dloc->DataLoc.Mapping));
1634 
1635     t = Offset + Length;
1636 //    UDFUpdateModifyTime(Vcb, FileInfo);
1637     if(t <= Dloc->DataLoc.Length) {
1638         // write Alloc-Rec area
1639         ExtPrint(("  WAlloc-Rec: %I64x <= %I64x\n", t, Dloc->DataLoc.Length));
1640         status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), Offset, Length, Direct, Buffer, WrittenBytes);
1641         return status;
1642     }
1643     elen = UDFGetExtentLength(Dloc->DataLoc.Mapping);
1644     ExtPrint(("  DataLoc Offs %x, Len %I64x\n",
1645         Dloc->DataLoc.Offset, Dloc->DataLoc.Length));
1646     if(t <= (elen - Dloc->DataLoc.Offset)) {
1647         // write Alloc-Not-Rec area
1648         ExtPrint(("  WAlloc-Not-Rec: %I64x <= %I64x (%I64x - %I64x)\n",
1649             t, elen - Dloc->DataLoc.Offset - Dloc->DataLoc.Length,
1650             elen - Dloc->DataLoc.Offset,
1651             Dloc->DataLoc.Length));
1652         UDFSetFileSize(FileInfo, t);
1653         if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
1654             ExtPrint(("  w2k-compat -> rebuild allocs\n"));
1655             Dloc->DataLoc.Modified = TRUE;
1656         } else
1657         if((ULONG)((elen+Vcb->LBlockSize-1) >> Vcb->LBlockSizeBits) != (ULONG)((t+Vcb->LBlockSize-1) >> Vcb->LBlockSizeBits)) {
1658             ExtPrint(("  LBS boundary crossed -> rebuild allocs\n"));
1659             Dloc->DataLoc.Modified = TRUE;
1660         }
1661         Dloc->DataLoc.Length = t;
1662         return UDFWriteExtent(Vcb, &(Dloc->DataLoc), Offset, Length, Direct, Buffer, WrittenBytes);
1663     }
1664     // We should not get here if Direct=TRUE
1665     if(Direct) return STATUS_INVALID_PARAMETER;
1666     OldLen = Dloc->DataLoc.Length;
1667     if(Dloc->DataLoc.Offset && Dloc->DataLoc.Length) {
1668         // read in-icb data. it'll be replaced after resize
1669         ExtPrint(("  read in-icb data\n"));
1670         OldInIcb = (int8*)MyAllocatePool__(NonPagedPool, (uint32)(Dloc->DataLoc.Length));
1671         if(!OldInIcb) return STATUS_INSUFFICIENT_RESOURCES;
1672         status = UDFReadExtent(Vcb, &(Dloc->DataLoc), 0, (uint32)OldLen, FALSE, OldInIcb, &ReadBytes);
1673         if(!OS_SUCCESS(status)) {
1674             MyFreePool__(OldInIcb);
1675             return status;
1676         }
1677     }
1678     // init Alloc mode
1679     ExtPrint(("  init Alloc mode\n"));
1680     if((((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) {
1681         ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK;
1682         ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= Vcb->DefaultAllocMode;
1683         WasInIcb = TRUE;
1684     }
1685     // increase extent
1686     ExtPrint(("  %s %s %s\n",
1687         UDFIsADirectory(FileInfo) ? "DIR" : "FILE",
1688         WasInIcb ? "In-Icb" : "",
1689         Vcb->LowFreeSpace ? "LowSpace" : ""));
1690     if(UDFIsADirectory(FileInfo) && !WasInIcb && !Vcb->LowFreeSpace) {
1691         FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_ALLOC_SEQUENTIAL;
1692         status = UDFResizeExtent(Vcb, PartNum, (t*2+Vcb->WriteBlockSize-1) & ~(Vcb->WriteBlockSize-1), FALSE, &(Dloc->DataLoc));
1693         if(OS_SUCCESS(status)) {
1694             AdPrint(("  preallocated space for Dir\n"));
1695             FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_PREALLOCATED;
1696             //UDFSetFileSize(FileInfo, t);
1697             Dloc->DataLoc.Length = t;
1698         } else
1699         if(status == STATUS_DISK_FULL) {
1700             status = UDFResizeExtent(Vcb, PartNum, t, FALSE, &(Dloc->DataLoc));
1701         }
1702     } else {
1703         status = UDFResizeExtent(Vcb, PartNum, t, FALSE, &(Dloc->DataLoc));
1704     }
1705     ExtPrint(("  DataLoc Offs %x, Len %I64x\n",
1706         Dloc->DataLoc.Offset, Dloc->DataLoc.Length));
1707     AdPrint(("UDFWriteFile__ (2) FileInfo %x, ExtInfo %x, Mapping %x\n", FileInfo, &(Dloc->DataLoc), Dloc->DataLoc.Mapping));
1708     if(!OS_SUCCESS(status)) {
1709         // rollback
1710         ExtPrint(("  err -> rollback\n"));
1711         if(WasInIcb) {
1712             // restore Alloc mode
1713             ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK;
1714             ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= ICB_FLAG_AD_IN_ICB;
1715             if(Dloc->AllocLoc.Mapping) {
1716                 MyFreePool__(Dloc->AllocLoc.Mapping);
1717                 Dloc->AllocLoc.Mapping = NULL;
1718             }
1719         }
1720         if(OldInIcb) {
1721             MyFreePool__(OldInIcb);
1722             UDFWriteExtent(Vcb, &(Dloc->DataLoc), 0, (uint32)OldLen, FALSE, OldInIcb, &_WrittenBytes);
1723         }
1724         if((int64)OldLen != Dloc->DataLoc.Length) {
1725             // restore file size
1726             AdPrint(("  restore alloc\n"));
1727             FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_CUT_PREALLOCATED;
1728             UDFResizeExtent(Vcb, PartNum, OldLen, FALSE, &(Dloc->DataLoc));
1729             FileInfo->Dloc->DataLoc.Flags &= ~EXTENT_FLAG_CUT_PREALLOCATED;
1730         }
1731         return status;
1732     }
1733     if(OldInIcb) {
1734         // replace data from ICB (if any) & free buffer
1735         ExtPrint(("  write old in-icd data\n"));
1736         status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), 0, (uint32)OldLen, FALSE, OldInIcb, &_WrittenBytes);
1737         MyFreePool__(OldInIcb);
1738         if(!OS_SUCCESS(status))
1739             return status;
1740     }
1741     // ufff...
1742     // & now we'll write out data to well prepared extent...
1743     // ... like all normal people do...
1744     ExtPrint(("  write user data\n"));
1745     if(!OS_SUCCESS(status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), Offset, Length, FALSE, Buffer, WrittenBytes)))
1746         return status;
1747     UDFSetFileSize(FileInfo, t);
1748     Dloc->DataLoc.Modified = TRUE;
1749 #ifdef UDF_DBG
1750     if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
1751         ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping));
1752     } else {
1753         ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) ==
1754                ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)));
1755     }
1756 #endif // UDF_DBG
1757     return STATUS_SUCCESS;
1758 } // end UDFWriteFile__()
1759 
1760 /*
1761     This routine marks file as deleted & decrements file link counter.
1762     It can optionaly free allocation space
1763  */
1764 OSSTATUS
1765 UDFUnlinkFile__(
1766     IN PVCB Vcb,
1767     IN PUDF_FILE_INFO FileInfo,
1768     IN BOOLEAN FreeSpace
1769     )
1770 {
1771     uint_di Index;   // index of file to be deleted
1772     uint16 lc;
1773     PUDF_DATALOC_INFO Dloc;
1774     PUDF_FILE_INFO DirInfo;
1775     PUDF_FILE_INFO SDirInfo;
1776     PDIR_INDEX_HDR hDirNdx;
1777     PDIR_INDEX_HDR hCurDirNdx;
1778     PDIR_INDEX_ITEM DirNdx;
1779     OSSTATUS status;
1780     BOOLEAN IsSDir;
1781 
1782     AdPrint(("UDFUnlinkFile__:\n"));
1783     if(!FileInfo) return STATUS_SUCCESS;
1784 
1785     ValidateFileInfo(FileInfo);
1786 
1787 #ifndef _CONSOLE
1788     // now we can't call this if there is no OS-specific File Desc. present
1789     if(FileInfo->Fcb)
1790         UDFRemoveFileId__(Vcb, FileInfo);
1791 #endif //_CONSOLE
1792     // check references
1793     Dloc = FileInfo->Dloc;
1794     if((FileInfo->OpenCount /*> (uint32)(UDFHasAStreamDir(FileInfo) ? 1 : 0)*/) ||
1795        (FileInfo->RefCount>1)) return STATUS_CANNOT_DELETE;
1796     if(Dloc->SDirInfo)
1797         return STATUS_CANNOT_DELETE;
1798     ASSERT(FileInfo->RefCount == 1);
1799     DirInfo = FileInfo->ParentFile;
1800     // root dir or self
1801     if(!DirInfo || ((FileInfo->Index < 2) && !UDFIsAStreamDir(FileInfo))) return STATUS_CANNOT_DELETE;
1802     hDirNdx = DirInfo->Dloc->DirIndex;
1803     Index = FileInfo->Index;
1804     // we can't delete modified file
1805     // it should be closed & reopened (or flushed) before deletion
1806     DirNdx = UDFDirIndex(hDirNdx,Index);
1807 #if defined UDF_DBG || defined PRINT_ALWAYS
1808     if(DirNdx && DirNdx->FName.Buffer) {
1809         AdPrint(("Unlink: %ws\n",DirNdx->FName.Buffer));
1810     }
1811 #endif // UDF_DBG
1812     if(FreeSpace &&
1813        ((Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) ||
1814          Dloc->DataLoc.Modified ||
1815          Dloc->AllocLoc.Modified ||
1816          Dloc->FELoc.Modified ||
1817         (DirNdx && (DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) )) {
1818 //        BrutePoint();
1819         return STATUS_CANNOT_DELETE;
1820     }
1821     SDirInfo = Dloc->SDirInfo;
1822 /*    if(FreeSpace && SDirInfo) {
1823         UDFPrint(("Unlink: SDirInfo should be NULL !!!\n"));
1824         BrutePoint();
1825         return STATUS_CANNOT_DELETE;
1826     }*/
1827     // stream directory can be deleted even being not empty
1828     // otherwise we should perform some checks
1829     if(!(IsSDir = UDFIsAStreamDir(FileInfo))) {
1830         // check if not empty direcory
1831         if((DirNdx->FileCharacteristics & FILE_DIRECTORY) &&
1832            (hCurDirNdx = Dloc->DirIndex) &&
1833             FreeSpace) {
1834             if(!UDFIsDirEmpty(hCurDirNdx))
1835                 return STATUS_DIRECTORY_NOT_EMPTY;
1836         }
1837         DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
1838         DirNdx->FileCharacteristics |= FILE_DELETED;
1839         FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED;
1840         hDirNdx->DelCount++;
1841         UDFChangeFileCounter(Vcb, !UDFIsADirectory(FileInfo), FALSE);
1842     }
1843     UDFDecFileLinkCount(FileInfo); // decrease
1844     lc = UDFGetFileLinkCount(FileInfo);
1845     if(DirNdx && FreeSpace) {
1846         // FileIdent marked as 'deleted' should have an empty ICB
1847         // We shall do it only if object has parent Dir
1848         // (for ex. SDir has parent object, but has no parent Dir)
1849         DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
1850         DirNdx->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR;
1851         // Root Files (Root/SDir/Vat/etc.) has no FileIdent...
1852         if(FileInfo->FileIdent)
1853             RtlZeroMemory(&(FileInfo->FileIdent->icb), sizeof(long_ad));
1854     }
1855     // caller wishes to free allocation, but we can't do it due to
1856     // alive links. In this case we should just remove reference
1857     if(FreeSpace && lc) {
1858         ((icbtag*)(Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum = 0;
1859         ((icbtag*)(Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum = 0;
1860         Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1861     } else
1862     // if caller wishes to free file allocation &
1863     // there are no more references(links) to this file, lets do it >;->
1864     if(FreeSpace && !lc) {
1865         if(UDFHasAStreamDir(FileInfo) &&
1866            !UDFIsSDirDeleted(Dloc->SDirInfo) ) {
1867             // we have a Stream Dir associated...
1868             PUDF_FILE_INFO SFileInfo;
1869             // ... try to open it
1870             if(Dloc->SDirInfo) {
1871                 UDFFlushFile__(Vcb, FileInfo);
1872                 return STATUS_CANNOT_DELETE;
1873             }
1874             // open SDir
1875             status = UDFOpenStreamDir__(Vcb, FileInfo, &(Dloc->SDirInfo));
1876             if(!OS_SUCCESS(status)) {
1877                 // abort Unlink on error
1878                 SFileInfo = Dloc->SDirInfo;
1879 cleanup_SDir:
1880                 UDFCleanUpFile__(Vcb, SFileInfo);
1881                 if(SFileInfo) MyFreePool__(SFileInfo);
1882                 UDFFlushFile__(Vcb, FileInfo);
1883                 return status;
1884             }
1885             SDirInfo = Dloc->SDirInfo;
1886             // try to perform deltree for Streams
1887             status = UDFUnlinkAllFilesInDir(Vcb, SDirInfo);
1888             if(!OS_SUCCESS(status)) {
1889                 // abort Unlink on error
1890                 UDFCloseFile__(Vcb, SDirInfo);
1891                 SFileInfo = SDirInfo;
1892                 BrutePoint();
1893                 goto cleanup_SDir;
1894             }
1895             // delete SDir
1896             UDFFlushFile__(Vcb, SDirInfo);
1897             AdPrint(("  "));
1898             UDFUnlinkFile__(Vcb, SDirInfo, TRUE);
1899             // close SDir
1900             UDFCloseFile__(Vcb, SDirInfo);
1901             if(UDFCleanUpFile__(Vcb, SDirInfo)) {
1902                 MyFreePool__(SDirInfo);
1903 #ifdef UDF_DBG
1904             } else {
1905                 BrutePoint();
1906 #endif // UDF_DBG
1907             }
1908             // update FileInfo
1909             ASSERT(Dloc->FileEntry);
1910             RtlZeroMemory( &(((PEXTENDED_FILE_ENTRY)(Dloc->FileEntry))->streamDirectoryICB), sizeof(long_ad));
1911             FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1912         } else
1913         if(IsSDir) {
1914             // do deltree for Streams
1915             status = UDFUnlinkAllFilesInDir(Vcb, FileInfo);
1916             if(!OS_SUCCESS(status)) {
1917                 UDFFlushFile__(Vcb, FileInfo);
1918                 return status;
1919             }
1920             // update parent FileInfo
1921             ASSERT(FileInfo->ParentFile->Dloc->FileEntry);
1922             RtlZeroMemory( &(((PEXTENDED_FILE_ENTRY)(FileInfo->ParentFile->Dloc->FileEntry))->streamDirectoryICB), sizeof(long_ad));
1923             FileInfo->ParentFile->Dloc->FE_Flags &= ~UDF_FE_FLAG_HAS_SDIR;
1924             FileInfo->ParentFile->Dloc->FE_Flags |= (UDF_FE_FLAG_FE_MODIFIED |
1925                                                      UDF_FE_FLAG_HAS_DEL_SDIR);
1926             FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_IS_DEL_SDIR;
1927             UDFDecFileLinkCount(FileInfo->ParentFile);
1928         }
1929         if(Dloc->DirIndex) {
1930             UDFFlushFESpace(Vcb, Dloc, FLUSH_FE_FOR_DEL);
1931         }
1932         // flush file
1933         UDFFlushFile__(Vcb, FileInfo);
1934         UDFUnlinkDloc(Vcb, Dloc);
1935         // free allocation
1936         UDFFreeFileAllocation(Vcb, DirInfo, FileInfo);
1937         ASSERT(!(FileInfo->Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED));
1938         FileInfo->Dloc->FE_Flags &= ~UDF_FE_FLAG_FE_MODIFIED;
1939     }
1940     return STATUS_SUCCESS;
1941 } // end UDFUnlinkFile__()
1942 
1943 OSSTATUS
1944 UDFUnlinkAllFilesInDir(
1945     IN PVCB Vcb,
1946     IN PUDF_FILE_INFO DirInfo
1947     )
1948 {
1949     PDIR_INDEX_HDR hCurDirNdx;
1950     PDIR_INDEX_ITEM CurDirNdx;
1951     PUDF_FILE_INFO FileInfo;
1952     OSSTATUS status;
1953     uint_di i;
1954 
1955     hCurDirNdx = DirInfo->Dloc->DirIndex;
1956     // check if we can delete all files
1957     for(i=2; (CurDirNdx = UDFDirIndex(hCurDirNdx,i)); i++) {
1958         // try to open Stream
1959         if(CurDirNdx->FileInfo)
1960             return STATUS_CANNOT_DELETE;
1961     }
1962     // start deletion
1963     for(i=2; (CurDirNdx = UDFDirIndex(hCurDirNdx,i)); i++) {
1964         // try to open Stream
1965         status = UDFOpenFile__(Vcb, FALSE, TRUE, NULL, DirInfo, &FileInfo, &i);
1966         if(status == STATUS_FILE_DELETED) {
1967             // we should not release on-disk allocation for
1968             // deleted streams twice
1969             if(CurDirNdx->FileInfo) {
1970                 BrutePoint();
1971                 goto err_del_stream;
1972             }
1973             goto skip_del_stream;
1974         } else
1975         if(!OS_SUCCESS(status)) {
1976             // Error :(((
1977 err_del_stream:
1978             UDFCleanUpFile__(Vcb, FileInfo);
1979             if(FileInfo)
1980                 MyFreePool__(FileInfo);
1981             return status;
1982         }
1983 
1984         UDFFlushFile__(Vcb, FileInfo);
1985         AdPrint(("    "));
1986         UDFUnlinkFile__(Vcb, FileInfo, TRUE);
1987         UDFCloseFile__(Vcb, FileInfo);
1988 skip_del_stream:
1989         if(FileInfo && UDFCleanUpFile__(Vcb, FileInfo)) {
1990             MyFreePool__(FileInfo);
1991         }
1992     }
1993     return STATUS_SUCCESS;
1994 } // end UDFUnlinkAllFilesInDir()
1995 #endif //UDF_READ_ONLY_BUILD
1996 
1997 /*
1998     This routine inits UDF_FILE_INFO structure for specified file
1999     If it returns status != STATUS_SUCCESS caller should call UDFCleanUpFile__
2000     for returned pointer *WITHOUT* using UDFCloseFile__
2001  */
2002 OSSTATUS
2003 UDFOpenFile__(
2004     IN PVCB Vcb,
2005     IN BOOLEAN IgnoreCase,
2006     IN BOOLEAN NotDeleted,
2007     IN PUNICODE_STRING fn,
2008     IN PUDF_FILE_INFO DirInfo,
2009     OUT PUDF_FILE_INFO* _FileInfo,// this is to be filled & doesn't contain
2010                                 // any pointers
2011     IN uint_di* IndexToOpen
2012     )
2013 {
2014     OSSTATUS status;
2015     uint_di i=0;
2016     EXTENT_AD FEExt;
2017     uint16 Ident;
2018     PDIR_INDEX_HDR hDirNdx = DirInfo->Dloc->DirIndex;
2019     PDIR_INDEX_ITEM DirNdx;
2020     PUDF_FILE_INFO FileInfo;
2021     PUDF_FILE_INFO ParFileInfo;
2022     uint32 ReadBytes;
2023     *_FileInfo = NULL;
2024     if(!hDirNdx) return STATUS_NOT_A_DIRECTORY;
2025 
2026     // find specified file in directory index
2027     // if it is already known, skip this foolish code
2028     if(IndexToOpen) {
2029         i=*IndexToOpen;
2030     } else
2031         if(!OS_SUCCESS(status = UDFFindFile(Vcb, IgnoreCase, NotDeleted, fn, DirInfo, &i)))
2032             return status;
2033     // do this check for OpenByIndex
2034     // some routines may send invalid Index
2035     if(!(DirNdx = UDFDirIndex(hDirNdx,i)))
2036         return STATUS_OBJECT_NAME_NOT_FOUND;
2037     if((FileInfo = DirNdx->FileInfo)) {
2038         // file is already opened.
2039         if((DirNdx->FileCharacteristics & FILE_DELETED) && NotDeleted) {
2040             AdPrint(("  FILE_DELETED on open\n"));
2041             return STATUS_FILE_DELETED;
2042         }
2043         if((FileInfo->ParentFile != DirInfo) &&
2044            (FileInfo->Index >= 2)) {
2045             ParFileInfo = UDFLocateParallelFI(DirInfo, i, FileInfo);
2046             BrutePoint();
2047             if(ParFileInfo->ParentFile != DirInfo) {
2048                 FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_FINF_TAG);
2049                 *_FileInfo = FileInfo;
2050                 if(!FileInfo) return STATUS_INSUFFICIENT_RESOURCES;
2051                 RtlCopyMemory(FileInfo, DirNdx->FileInfo, sizeof(UDF_FILE_INFO));
2052     //          FileInfo->NextLinkedFile = DirNdx->FileInfo->NextLinkedFile; // is already done
2053                 UDFInsertLinkedFile(FileInfo, DirNdx->FileInfo);
2054                 DirNdx->FI_Flags |= UDF_FI_FLAG_LINKED;
2055                 FileInfo->RefCount = 0;
2056                 FileInfo->ParentFile = DirInfo;
2057                 FileInfo->Fcb = NULL;
2058             } else {
2059                 FileInfo = ParFileInfo;
2060             }
2061         }
2062         // Just increase some counters & exit
2063         UDFReferenceFile__(FileInfo);
2064 
2065         ASSERT(FileInfo->ParentFile == DirInfo);
2066         ValidateFileInfo(FileInfo);
2067 
2068         *_FileInfo = FileInfo;
2069         return STATUS_SUCCESS;
2070     } else
2071     if(IndexToOpen) {
2072         if((DirNdx->FileCharacteristics & FILE_DELETED) && NotDeleted) {
2073             AdPrint(("  FILE_DELETED on open (2)\n"));
2074             return STATUS_FILE_DELETED;
2075         }
2076     }
2077     FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_FINF_TAG);
2078     *_FileInfo = FileInfo;
2079     if(!FileInfo) return STATUS_INSUFFICIENT_RESOURCES;
2080     RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO));
2081     // init horizontal links
2082     FileInfo->NextLinkedFile =
2083     FileInfo->PrevLinkedFile = FileInfo;
2084     // read FileIdent
2085     FileInfo->FileIdent = (PFILE_IDENT_DESC)MyAllocatePoolTag__(NonPagedPool, DirNdx->Length, MEM_FID_TAG);
2086     if(!(FileInfo->FileIdent)) return STATUS_INSUFFICIENT_RESOURCES;
2087     FileInfo->FileIdentLen = DirNdx->Length;
2088     if(!OS_SUCCESS(status = UDFReadExtent(Vcb, &(DirInfo->Dloc->DataLoc), DirNdx->Offset,
2089                              DirNdx->Length, FALSE, (int8*)(FileInfo->FileIdent), &ReadBytes) ))
2090         return status;
2091     if(FileInfo->FileIdent->descTag.tagIdent != TID_FILE_IDENT_DESC) {
2092         BrutePoint();
2093         return STATUS_FILE_CORRUPT_ERROR;
2094     }
2095     // check for opened links
2096     if(!OS_SUCCESS(status = UDFStoreDloc(Vcb, FileInfo, UDFPartLbaToPhys(Vcb, &(FileInfo->FileIdent->icb.extLocation)))))
2097         return status;
2098     // init pointer to parent object
2099     FileInfo->Index = i;
2100     FileInfo->ParentFile = DirInfo;
2101     // init pointers to linked files (if any)
2102     if(FileInfo->Dloc->LinkedFileInfo != FileInfo)
2103         UDFInsertLinkedFile(FileInfo, FileInfo->Dloc->LinkedFileInfo);
2104     if(FileInfo->Dloc->FileEntry)
2105         goto init_tree_entry;
2106     // read (Ex)FileEntry
2107     FileInfo->Dloc->FileEntry = (tag*)MyAllocatePoolTag__(NonPagedPool, Vcb->LBlockSize, MEM_FE_TAG);
2108     if(!(FileInfo->Dloc->FileEntry)) return STATUS_INSUFFICIENT_RESOURCES;
2109     if(!OS_SUCCESS(status = UDFReadFileEntry(Vcb, &(FileInfo->FileIdent->icb), (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &Ident)))
2110         return status;
2111     // build mappings for Data & AllocDescs
2112     if(!FileInfo->Dloc->AllocLoc.Mapping) {
2113         FEExt.extLength = FileInfo->FileIdent->icb.extLength;
2114         FEExt.extLocation = UDFPartLbaToPhys(Vcb, &(FileInfo->FileIdent->icb.extLocation) );
2115         if(FEExt.extLocation == LBA_OUT_OF_EXTENT)
2116             return STATUS_FILE_CORRUPT_ERROR;
2117         FileInfo->Dloc->AllocLoc.Mapping = UDFExtentToMapping(&FEExt);
2118         if(!(FileInfo->Dloc->AllocLoc.Mapping))
2119             return STATUS_INSUFFICIENT_RESOURCES;
2120     }
2121     // read location info
2122     status = UDFLoadExtInfo(Vcb, (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &(FileInfo->FileIdent->icb),
2123                            &(FileInfo->Dloc->DataLoc), &(FileInfo->Dloc->AllocLoc) );
2124     if(!OS_SUCCESS(status))
2125         return status;
2126     // init (Ex)FileEntry mapping
2127     FileInfo->Dloc->FELoc.Length = (FileInfo->Dloc->DataLoc.Offset) ? FileInfo->Dloc->DataLoc.Offset :
2128                                                           FileInfo->Dloc->AllocLoc.Offset;
2129 //    FileInfo->Dloc->FELoc.Offset = 0;
2130     FileInfo->Dloc->FELoc.Mapping = UDFExtentToMapping(&FEExt);
2131     FileInfo->Dloc->FileEntryLen = (uint32)(FileInfo->Dloc->FELoc.Length);
2132     // we get here immediately when opened link encountered
2133 init_tree_entry:
2134     // init back pointer from parent object
2135     ASSERT(!DirNdx->FileInfo);
2136     DirNdx->FileInfo = FileInfo;
2137     // init DirIndex
2138     if(UDFGetFileLinkCount(FileInfo) > 1) {
2139         DirNdx->FI_Flags |= UDF_FI_FLAG_LINKED;
2140     } else {
2141         DirNdx->FI_Flags &= ~UDF_FI_FLAG_LINKED;
2142     }
2143     // resize FE cache (0x800 instead of 0x40 is not a good idea)
2144     if(!MyReallocPool__((int8*)((FileInfo->Dloc->FileEntry)), Vcb->LBlockSize,
2145                      (int8**)&((FileInfo->Dloc->FileEntry)), FileInfo->Dloc->FileEntryLen))
2146         return STATUS_INSUFFICIENT_RESOURCES;
2147     // check if this file has a SDir
2148     if((FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY) &&
2149        ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLength )
2150         FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_HAS_SDIR;
2151     if(!(FileInfo->FileIdent->fileCharacteristics & FILE_DIRECTORY)) {
2152         UDFReferenceFile__(FileInfo);
2153         ASSERT(FileInfo->ParentFile == DirInfo);
2154         UDFReleaseDloc(Vcb, FileInfo->Dloc);
2155         return STATUS_SUCCESS;
2156     }
2157 
2158     UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used
2159 
2160     // build index for directories
2161     if(!FileInfo->Dloc->DirIndex) {
2162         status = UDFIndexDirectory(Vcb, FileInfo);
2163         if(!OS_SUCCESS(status))
2164             return status;
2165 #ifndef UDF_READ_ONLY_BUILD
2166         if((FileInfo->Dloc->DirIndex->DelCount > Vcb->PackDirThreshold) &&
2167            !(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)) {
2168             status = UDFPackDirectory__(Vcb, FileInfo);
2169             if(!OS_SUCCESS(status))
2170                 return status;
2171         }
2172 #endif //UDF_READ_ONLY_BUILD
2173     }
2174     UDFReferenceFile__(FileInfo);
2175     UDFReleaseDloc(Vcb, FileInfo->Dloc);
2176     ASSERT(FileInfo->ParentFile == DirInfo);
2177 
2178     return status;
2179 } // end UDFOpenFile__()
2180 
2181 
2182 /*
2183     This routine inits UDF_FILE_INFO structure for root directory
2184  */
2185 OSSTATUS
2186 UDFOpenRootFile__(
2187     IN PVCB Vcb,
2188     IN lb_addr* RootLoc,
2189     OUT PUDF_FILE_INFO FileInfo
2190     )
2191 {
2192     uint32 RootLBA;
2193     OSSTATUS status;
2194 //    uint32 PartNum = RootLoc->partitionReferenceNum;
2195     uint32 LBS = Vcb->LBlockSize;
2196     uint16 Ident;
2197     LONG_AD FELoc;
2198     EXTENT_AD FEExt;
2199     uint8 FileType;
2200 
2201     RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO));
2202     RootLBA = UDFPartLbaToPhys(Vcb,RootLoc);
2203     if(RootLBA == LBA_OUT_OF_EXTENT)
2204         return STATUS_FILE_CORRUPT_ERROR;
2205     FELoc.extLocation = *RootLoc;
2206     FELoc.extLength = LBS;
2207     // init horizontal links
2208     FileInfo->NextLinkedFile =
2209     FileInfo->PrevLinkedFile = FileInfo;
2210     // check for opened links
2211     if(!OS_SUCCESS(status = UDFStoreDloc(Vcb, FileInfo, RootLBA)))
2212         return status;
2213     if(FileInfo->Dloc->FileEntry)
2214         goto init_tree_entry;
2215     // read (Ex)FileEntry
2216     FileInfo->Dloc->FileEntry = (tag*)MyAllocatePoolTag__(NonPagedPool, LBS, MEM_FE_TAG);
2217     if(!(FileInfo->Dloc->FileEntry)) return STATUS_INSUFFICIENT_RESOURCES;
2218 
2219     if(!OS_SUCCESS(status = UDFReadFileEntry(Vcb, &FELoc, (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &Ident)))
2220         return status;
2221     // build mappings for Data & AllocDescs
2222     FEExt.extLength = LBS;
2223     FEExt.extLocation = UDFPartLbaToPhys(Vcb, &(FELoc.extLocation) );
2224     if(FEExt.extLocation == LBA_OUT_OF_EXTENT)
2225         return STATUS_FILE_CORRUPT_ERROR;
2226     FileInfo->Dloc->FELoc.Mapping = UDFExtentToMapping(&FEExt);
2227     if(!(FileInfo->Dloc->FELoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES;
2228     // build mappings for AllocDescs
2229     if(!FileInfo->Dloc->AllocLoc.Mapping) {
2230         FileInfo->Dloc->AllocLoc.Mapping = UDFExtentToMapping(&FEExt);
2231         if(!(FileInfo->Dloc->AllocLoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES;
2232     }
2233     if(!OS_SUCCESS(status = UDFLoadExtInfo(Vcb, (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &FELoc,
2234                        &(FileInfo->Dloc->DataLoc), &(FileInfo->Dloc->AllocLoc) ) ))
2235         return status;
2236     FileInfo->Dloc->FileEntryLen = (uint32)
2237     (FileInfo->Dloc->FELoc.Length = (FileInfo->Dloc->DataLoc.Offset) ? FileInfo->Dloc->DataLoc.Offset :
2238                                                           FileInfo->Dloc->AllocLoc.Offset);
2239 init_tree_entry:
2240     // resize FE cache (0x800 instead of 0x40 is not a good idea)
2241     if(!MyReallocPool__((int8*)((FileInfo->Dloc->FileEntry)), LBS,
2242                      (int8**)&((FileInfo->Dloc->FileEntry)), FileInfo->Dloc->FileEntryLen))
2243         return STATUS_INSUFFICIENT_RESOURCES;
2244     // init DirIndex
2245     if( (FileType = ((icbtag*)((FileInfo->Dloc->FileEntry)+1))->fileType) != UDF_FILE_TYPE_DIRECTORY &&
2246         (FileType != UDF_FILE_TYPE_STREAMDIR) ) {
2247         UDFReferenceFile__(FileInfo);
2248         UDFReleaseDloc(Vcb, FileInfo->Dloc);
2249         return STATUS_SUCCESS;
2250     }
2251     // build index for directories
2252     if(!FileInfo->Dloc->DirIndex) {
2253         status = UDFIndexDirectory(Vcb, FileInfo);
2254         if(!OS_SUCCESS(status))
2255             return status;
2256 #ifndef UDF_READ_ONLY_BUILD
2257         if((FileInfo->Dloc->DirIndex->DelCount > Vcb->PackDirThreshold) &&
2258            !(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)) {
2259             status = UDFPackDirectory__(Vcb, FileInfo);
2260             if(!OS_SUCCESS(status))
2261                 return status;
2262         }
2263 #endif //UDF_READ_ONLY_BUILD
2264     }
2265     UDFReferenceFile__(FileInfo);
2266     UDFReleaseDloc(Vcb, FileInfo->Dloc);
2267 
2268     return status;
2269 } // end UDFOpenRootFile__()
2270 
2271 /*
2272     This routine frees all memory blocks referenced by given FileInfo
2273  */
2274 uint32
2275 UDFCleanUpFile__(
2276     IN PVCB Vcb,
2277     IN PUDF_FILE_INFO FileInfo
2278     )
2279 {
2280     PUDF_DATALOC_INFO Dloc;
2281     uint32 lc = 0;
2282     BOOLEAN IsASDir;
2283     BOOLEAN KeepDloc;
2284     PDIR_INDEX_ITEM DirNdx, DirNdx2;
2285     BOOLEAN Parallel = FALSE;
2286     BOOLEAN Linked = FALSE;
2287 #ifdef UDF_DBG
2288     BOOLEAN Modified = FALSE;
2289     PDIR_INDEX_HDR hDirNdx;
2290     uint_di Index;
2291     PUDF_FILE_INFO DirInfo;
2292 #endif // UDF_DBG
2293 
2294     if(!FileInfo) return UDF_FREE_FILEINFO;
2295 
2296     ValidateFileInfo(FileInfo);
2297 
2298     if(FileInfo->OpenCount || FileInfo->RefCount) {
2299         UDFPrint(("UDF: not all references are closed\n"));
2300         UDFPrint(("     Skipping cleanup\n"));
2301         UDFPrint(("UDF: OpenCount = %x, RefCount = %x, LinkRefCount = %x\n",
2302                               FileInfo->OpenCount,FileInfo->RefCount,FileInfo->Dloc->LinkRefCount));
2303         return UDF_FREE_NOTHING;
2304     }
2305     if(FileInfo->Fcb) {
2306         UDFPrint(("Operating System still has references to this file\n"));
2307         UDFPrint(("     Skipping cleanup\n"));
2308 //        BrutePoint();
2309         return UDF_FREE_NOTHING;
2310     }
2311 
2312     IsASDir = UDFIsAStreamDir(FileInfo);
2313 
2314     if((Dloc = FileInfo->Dloc)) {
2315 
2316 #ifdef UDF_DBG
2317         DirInfo = FileInfo->ParentFile;
2318         if(DirInfo) {
2319             hDirNdx = DirInfo->Dloc->DirIndex;
2320             Index = FileInfo->Index;
2321             // we can't delete modified file
2322             // it should be closed & reopened (or flushed) before deletion
2323             DirNdx = UDFDirIndex(hDirNdx,Index);
2324             UDFPrint(("Cleanup Mod: %s%s%s%s%s%s\n",
2325                                  (Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) ? "FE "       : "",
2326                                  (Dloc->DataLoc.Modified)                   ? "DataLoc "  : "",
2327                                  (Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) ? "Data-PreAlloc " : "",
2328                                  (Dloc->AllocLoc.Modified)                  ? "AllocLoc " : "",
2329                                  (Dloc->FELoc.Modified)                     ? "FELoc "    : "",
2330                                  (DirNdx && (DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) ? "FI " : ""
2331                                  ));
2332             Modified = ((Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) ||
2333                          Dloc->DataLoc.Modified ||
2334                         (Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) ||
2335                          Dloc->AllocLoc.Modified ||
2336                          Dloc->FELoc.Modified ||
2337                         (DirNdx && (DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) );
2338         }
2339 #endif // UDF_DBG
2340 
2341         PUDF_FILE_INFO ParFileInfo = UDFLocateAnyParallelFI(FileInfo);
2342 
2343         Parallel = (ParFileInfo != NULL);
2344         Linked = (FileInfo->NextLinkedFile != FileInfo);
2345 
2346 //        Parallel = (FileInfo->NextLinkedFile != FileInfo);
2347         ASSERT(FileInfo->NextLinkedFile);
2348 //        ASSERT(!Parallel);
2349         KeepDloc = (Dloc->LinkRefCount ||
2350                     Dloc->CommonFcb ||
2351                     Linked ) ?
2352                     TRUE : FALSE;
2353 
2354         if(Dloc->DirIndex) {
2355             uint_di i;
2356             for(i=2; (DirNdx = UDFDirIndex(Dloc->DirIndex,i)); i++) {
2357                 if(DirNdx->FileInfo) {
2358                     if(!KeepDloc) {
2359                         BrutePoint();
2360                         UDFPrint(("UDF: Found not cleaned up reference.\n"));
2361                         UDFPrint(("     Skipping cleanup (1)\n"));
2362 //                        BrutePoint();
2363                         return UDF_FREE_NOTHING;
2364                     }
2365                     // The file being cleaned up may have not closed Dirs
2366                     // (linked Dir). In this case each of them may have
2367                     // reference to FileInfo in DirIndex[1]
2368                     // Here we'll check it and change for valid value if
2369                     // necessary (Update Child Objects - I)
2370                     if(DirNdx->FileInfo->Dloc) {
2371                         // we can get here only when (Parallel == TRUE)
2372                         DirNdx2 = UDFDirIndex(DirNdx->FileInfo->Dloc->DirIndex, 1);
2373                         // It is enough to check DirNdx2->FileInfo only.
2374                         // If one of Parallel FI's has reference (and equal)
2375                         // to the FI being removed, it'll be removed from
2376                         // the chain & nothing wrong will happen.
2377                         if(DirNdx2 && (DirNdx2->FileInfo == FileInfo)) {
2378                             if(FileInfo->PrevLinkedFile == FileInfo) {
2379                                 BrutePoint();
2380                                 DirNdx2->FileInfo = NULL;
2381                             } else {
2382                                 DirNdx2->FileInfo = Parallel ?
2383                                     ParFileInfo : FileInfo->PrevLinkedFile;
2384                             }
2385                             ASSERT(!DirNdx2->FileInfo->RefCount);
2386                         }
2387                     }
2388                 }
2389             }
2390         }
2391         if(Dloc->SDirInfo) {
2392             UDFPrint(("UDF: Found not cleaned up reference (SDir).\n"));
2393 
2394             // (Update Child Objects - II)
2395             if(Dloc->SDirInfo->ParentFile == FileInfo) {
2396                 BrutePoint();
2397                 ASSERT(ParFileInfo);
2398                 Dloc->SDirInfo->ParentFile = ParFileInfo;
2399             }
2400             // We should break Cleanup process if alive reference detected
2401             // and there is no possibility to store pointer in some other
2402             // place (in parallel object)
2403             if(!KeepDloc) {
2404                 BrutePoint();
2405                 UDFPrint(("     Skipping cleanup\n"));
2406                 return UDF_FREE_NOTHING;
2407             }
2408 
2409             if(!UDFIsSDirDeleted(Dloc->SDirInfo) &&
2410                Dloc->SDirInfo->Dloc) {
2411                 DirNdx2 = UDFDirIndex(Dloc->SDirInfo->Dloc->DirIndex, 1);
2412                 if(DirNdx2 && (DirNdx2->FileInfo == FileInfo)) {
2413                     DirNdx2->FileInfo =
2414                         Parallel ? ParFileInfo : NULL;
2415                     ASSERT(!DirNdx2->FileInfo->RefCount);
2416                 }
2417             }
2418         }
2419 
2420         if(!KeepDloc) {
2421 
2422 #ifdef UDF_DBG
2423             ASSERT(!Modified);
2424 #endif
2425 
2426 #ifndef UDF_TRACK_ONDISK_ALLOCATION
2427             if(Dloc->DataLoc.Mapping)  MyFreePool__(Dloc->DataLoc.Mapping);
2428             if(Dloc->AllocLoc.Mapping) MyFreePool__(Dloc->AllocLoc.Mapping);
2429             if(Dloc->FELoc.Mapping)    MyFreePool__(Dloc->FELoc.Mapping);
2430             if(Dloc->FileEntry) {
2431                 // plain file
2432                 lc = UDFGetFileLinkCount(FileInfo);
2433                 MyFreePool__(Dloc->FileEntry);
2434                 Dloc->FileEntry = NULL;
2435             } else if(FileInfo->Index >= 2) {
2436                 // error durring open operation
2437                 lc = UDF_INVALID_LINK_COUNT;
2438             }
2439 #endif //UDF_TRACK_ONDISK_ALLOCATION
2440             if(FileInfo->Dloc->DirIndex) {
2441                 uint_di i;
2442                 for(i=2; (DirNdx = UDFDirIndex(Dloc->DirIndex,i)); i++) {
2443                     ASSERT(!DirNdx->FileInfo);
2444                     if(DirNdx->FName.Buffer)
2445                         MyFreePool__(DirNdx->FName.Buffer);
2446                 }
2447                 // The only place where we can free FE_Charge extent is here
2448                 UDFFlushFESpace(Vcb, Dloc);
2449                 UDFDirIndexFree(Dloc->DirIndex);
2450                 Dloc->DirIndex = NULL;
2451 #ifdef UDF_TRACK_ONDISK_ALLOCATION
2452                 UDFIndexDirectory(Vcb, FileInfo);
2453                 if(FileInfo->Dloc->DirIndex) {
2454                     for(i=2; DirNdx = UDFDirIndex(Dloc->DirIndex,i); i++) {
2455                         ASSERT(!DirNdx->FileInfo);
2456                         if(DirNdx->FName.Buffer)
2457                             MyFreePool__(DirNdx->FName.Buffer);
2458                     }
2459                     UDFDirIndexFree(Dloc->DirIndex);
2460                     Dloc->DirIndex = NULL;
2461                 }
2462 #endif //UDF_TRACK_ONDISK_ALLOCATION
2463             }
2464 
2465 #ifdef UDF_TRACK_ONDISK_ALLOCATION
2466             if(Dloc->AllocLoc.Mapping) MyFreePool__(Dloc->AllocLoc.Mapping);
2467             if(Dloc->FELoc.Mapping)    MyFreePool__(Dloc->FELoc.Mapping);
2468             if(Dloc->FileEntry) {
2469                 // plain file
2470                 lc = UDFGetFileLinkCount(FileInfo);
2471                 MyFreePool__(Dloc->FileEntry);
2472                 Dloc->FileEntry = NULL;
2473             } else if(FileInfo->Index >= 2) {
2474                 // error durring open operation
2475                 lc = UDF_INVALID_LINK_COUNT;
2476             }
2477             if(Dloc->DataLoc.Mapping) {
2478                 if(lc && (lc != UDF_INVALID_LINK_COUNT)) {
2479                     UDFCheckSpaceAllocation(Vcb, 0, Dloc->DataLoc.Mapping, AS_USED); // check if used
2480                 } else {
2481                     UDFCheckSpaceAllocation(Vcb, 0, Dloc->DataLoc.Mapping, AS_FREE); // check if free
2482                 }
2483                 MyFreePool__(Dloc->DataLoc.Mapping);
2484             }
2485 #endif //UDF_TRACK_ONDISK_ALLOCATION
2486 
2487             if(lc && (lc != UDF_INVALID_LINK_COUNT)) {
2488                 UDFRemoveDloc(Vcb, Dloc);
2489             } else {
2490                 UDFFreeDloc(Vcb, Dloc);
2491             }
2492         } else // KeepDloc cannot be FALSE if (Linked == TRUE)
2493         if(Linked) {
2494 //            BrutePoint();
2495             // Update pointers in ParentObject (if any)
2496             if(FileInfo->ParentFile->Dloc->SDirInfo == FileInfo)
2497                 FileInfo->ParentFile->Dloc->SDirInfo = FileInfo->PrevLinkedFile;
2498             DirNdx = UDFDirIndex(FileInfo->Dloc->DirIndex, 0);
2499             if(DirNdx && (DirNdx->FileInfo == FileInfo))
2500                 DirNdx->FileInfo = FileInfo->PrevLinkedFile;
2501             DirNdx = UDFDirIndex(FileInfo->ParentFile->Dloc->DirIndex, FileInfo->Index);
2502             if(DirNdx && (DirNdx->FileInfo == FileInfo))
2503                 DirNdx->FileInfo = ParFileInfo;
2504             // remove from linked chain
2505             FileInfo->NextLinkedFile->PrevLinkedFile = FileInfo->PrevLinkedFile;
2506             FileInfo->PrevLinkedFile->NextLinkedFile = FileInfo->NextLinkedFile;
2507             // update pointer in Dloc
2508             if(FileInfo->Dloc->LinkedFileInfo == FileInfo)
2509                 FileInfo->Dloc->LinkedFileInfo = FileInfo->PrevLinkedFile;
2510         }
2511         FileInfo->Dloc = NULL;
2512     } else {
2513         KeepDloc = FALSE;
2514     }
2515 
2516     // Cleanup pointers in ParentObject (if any)
2517     if(IsASDir) {
2518         if(FileInfo->ParentFile->Dloc->SDirInfo == FileInfo) {
2519             ASSERT(!Linked);
2520             FileInfo->ParentFile->Dloc->SDirInfo = NULL;
2521             FileInfo->ParentFile->Dloc->FE_Flags &= ~UDF_FE_FLAG_HAS_DEL_SDIR;
2522         }
2523     } else
2524     if(FileInfo->ParentFile) {
2525         ASSERT(FileInfo->ParentFile->Dloc);
2526         DirNdx = UDFDirIndex(FileInfo->ParentFile->Dloc->DirIndex, FileInfo->Index);
2527         ASSERT(DirNdx);
2528 #ifdef UDF_DBG
2529         PUDF_FILE_INFO OldFI;
2530         if(Parallel) {
2531             ASSERT(!DirNdx || !(OldFI = DirNdx->FileInfo) ||
2532                     !(OldFI == FileInfo));
2533         } else {
2534             ASSERT(!DirNdx || !(OldFI = DirNdx->FileInfo) ||
2535                      (OldFI == FileInfo));
2536         }
2537 #endif
2538         if( DirNdx && (DirNdx->FileInfo == FileInfo) ) {
2539             if(!Parallel)
2540                 DirNdx->FileInfo = NULL;
2541 #ifdef UDF_DBG
2542         } else {
2543             // We can get here after incomplete Open
2544             if(!Parallel && DirNdx->FileInfo)
2545                 BrutePoint();
2546 #endif
2547         }
2548 #ifdef UDF_DBG
2549     } else {
2550 //        BrutePoint();
2551 #endif
2552     }
2553 
2554     if(!Parallel && FileInfo->FileIdent)
2555         MyFreePool__(FileInfo->FileIdent);
2556     FileInfo->FileIdent = NULL;
2557     // Kill reference to parent object
2558     FileInfo->ParentFile = NULL;
2559     // Kill references to parallel object(s) since it has no reference to
2560     // this one now
2561     FileInfo->NextLinkedFile =
2562     FileInfo->PrevLinkedFile = FileInfo;
2563     if(FileInfo->ListPtr)
2564         FileInfo->ListPtr->FileInfo = NULL;;
2565     return KeepDloc ? UDF_FREE_FILEINFO : (UDF_FREE_FILEINFO | UDF_FREE_DLOC);
2566 } // end UDFCleanUpFile__()
2567 
2568 #ifndef UDF_READ_ONLY_BUILD
2569 /*
2570     This routine creates FileIdent record in destination directory &
2571     allocates FileEntry with in-ICB zero-sized data
2572     If it returns status != STATUS_SUCCESS caller should call UDFCleanUpFile__
2573     for returned pointer *WITHOUT* using UDFCloseFile__
2574  */
2575 OSSTATUS
2576 UDFCreateFile__(
2577     IN PVCB Vcb,
2578 //    IN uint16 AllocMode, // short/long/ext/in-icb  // always in-ICB
2579     IN BOOLEAN IgnoreCase,
2580     IN PUNICODE_STRING _fn,
2581     IN uint32 ExtAttrSz,
2582     IN uint32 ImpUseLen,
2583     IN BOOLEAN Extended,
2584     IN BOOLEAN CreateNew,
2585  IN OUT PUDF_FILE_INFO DirInfo,
2586     OUT PUDF_FILE_INFO* _FileInfo
2587     )
2588 {
2589     uint32 l, d;
2590     uint_di i, j;
2591     OSSTATUS status;
2592     LONG_AD FEicb;
2593     UDF_DIR_SCAN_CONTEXT ScanContext;
2594     PDIR_INDEX_HDR hDirNdx = DirInfo->Dloc->DirIndex;
2595     PDIR_INDEX_ITEM DirNdx;
2596     uint32 LBS = Vcb->LBlockSize;
2597     PUDF_FILE_INFO FileInfo;
2598     *_FileInfo = NULL;
2599     BOOLEAN undel = FALSE;
2600     uint32 ReadBytes;
2601 //    BOOLEAN PackDir = FALSE;
2602     BOOLEAN FEAllocated = FALSE;
2603 
2604     ValidateFileInfo(DirInfo);
2605     *_FileInfo = NULL;
2606 
2607     ASSERT(DirInfo->Dloc->FELoc.Mapping[0].extLocation);
2608     uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, DirInfo->Dloc->FELoc.Mapping[0].extLocation);
2609     if(!hDirNdx) return STATUS_NOT_A_DIRECTORY;
2610     i = 0;
2611 
2612     _SEH2_TRY {
2613 
2614         // check if exists
2615         status = UDFFindFile(Vcb, IgnoreCase, FALSE, _fn, DirInfo, &i);
2616         DirNdx = UDFDirIndex(hDirNdx,i);
2617         if(OS_SUCCESS(status)) {
2618             // file is a Cur(Parent)Dir
2619             if(i<2) try_return (status = STATUS_ACCESS_DENIED);
2620             // file deleted
2621             if(UDFIsDeleted(DirNdx)) {
2622                 j=0;
2623                 if(OS_SUCCESS(UDFFindFile(Vcb, IgnoreCase, TRUE, _fn, DirInfo, &j))) {
2624                    i=j;
2625                    DirNdx = UDFDirIndex(hDirNdx,i);
2626                    goto CreateBothFound;
2627                 }
2628                 // we needn't allocating new FileIdent inside Dir stream
2629                 // perform 'undel'
2630                 if(DirNdx->FileInfo) {
2631     //                BrutePoint();
2632                     status = UDFPretendFileDeleted__(Vcb, DirNdx->FileInfo);
2633                     if(!OS_SUCCESS(status))
2634                         try_return (status = STATUS_FILE_DELETED);
2635                 } else {
2636                     undel = TRUE;
2637                 }
2638     //            BrutePoint();
2639                 goto CreateUndel;
2640             }
2641 CreateBothFound:
2642             // file already exists
2643             if(CreateNew) try_return (status = STATUS_ACCESS_DENIED);
2644             // try to open it
2645             BrutePoint();
2646             status = UDFOpenFile__(Vcb, IgnoreCase, TRUE, _fn, DirInfo, _FileInfo,&i);
2647     //        *_FileInfo = FileInfo; // OpenFile__ has already done it, so update it...
2648             DirNdx = UDFDirIndex(hDirNdx,i);
2649             DirNdx->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR;
2650             FileInfo = *_FileInfo;
2651             if(!OS_SUCCESS(status)) {
2652                 // :(( can't open....
2653                 if(FileInfo && UDFCleanUpFile__(Vcb, FileInfo)) {
2654                     MyFreePool__(FileInfo);
2655                     *_FileInfo = NULL;
2656                 }
2657                 BrutePoint();
2658                 try_return (status);
2659             }
2660             // check if we can delete this file
2661             if(FileInfo->OpenCount || (FileInfo->RefCount > 1)) {
2662                 BrutePoint();
2663                 UDFCloseFile__(Vcb, FileInfo);
2664                 try_return (status = STATUS_CANNOT_DELETE);
2665             }
2666             BrutePoint();
2667             // remove DIRECTORY flag
2668             DirNdx->FileCharacteristics &= ~FILE_DIRECTORY;
2669             FileInfo->FileIdent->fileCharacteristics &= ~FILE_DIRECTORY;
2670             DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
2671             // truncate file size to ZERO
2672             status = UDFResizeFile__(Vcb, FileInfo, 0);
2673             if(!OS_SUCCESS(status)) {
2674                 BrutePoint();
2675                 UDFCloseFile__(Vcb, FileInfo);
2676             }
2677             // set NORMAL flag
2678             FileInfo->FileIdent->fileCharacteristics = 0;
2679             DirNdx->FileCharacteristics = 0;
2680             // update DeletedFiles counter in Directory... (for PackDir)
2681             if(undel && OS_SUCCESS(status))
2682                 hDirNdx->DelCount--;
2683             try_return (status);
2684         }
2685 
2686 CreateUndel:
2687 
2688         // allocate FileInfo
2689         FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_FE_TAG);
2690         *_FileInfo = FileInfo;
2691         if(!FileInfo)
2692             try_return (status = STATUS_INSUFFICIENT_RESOURCES);
2693         ImpUseLen = (ImpUseLen + 3) & ~((uint16)3);
2694 
2695         RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO));
2696         // init horizontal links
2697         FileInfo->NextLinkedFile =
2698         FileInfo->PrevLinkedFile = FileInfo;
2699         // allocate space for FileEntry
2700         if(!OS_SUCCESS(status =
2701             UDFBuildFileEntry(Vcb, DirInfo, FileInfo, PartNum, ICB_FLAG_AD_IN_ICB, ExtAttrSz, Extended) )) {
2702             BrutePoint();
2703             try_return (status);
2704         }
2705         FEAllocated = TRUE;
2706         FEicb.extLength = LBS;
2707         ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
2708         FEicb.extLocation.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
2709         FEicb.extLocation.partitionReferenceNum = (uint16)PartNum;
2710         RtlZeroMemory(&(FEicb.impUse), sizeof(FEicb.impUse));
2711 
2712         if(!undel) {
2713             // build FileIdent
2714             if(!OS_SUCCESS(status =
2715                 UDFBuildFileIdent(Vcb, _fn, &FEicb, ImpUseLen,
2716                         &(FileInfo->FileIdent), &(FileInfo->FileIdentLen)) ))
2717                 try_return (status);
2718         } else {
2719             // read FileIdent
2720             FileInfo->FileIdent = (PFILE_IDENT_DESC)MyAllocatePoolTag__(NonPagedPool, DirNdx->Length, MEM_FID_TAG);
2721             if(!(FileInfo->FileIdent)) try_return (status = STATUS_INSUFFICIENT_RESOURCES);
2722             FileInfo->FileIdentLen = DirNdx->Length;
2723             if(!OS_SUCCESS(status = UDFReadExtent(Vcb, &(DirInfo->Dloc->DataLoc), DirNdx->Offset,
2724                                      DirNdx->Length, FALSE, (int8*)(FileInfo->FileIdent), &ReadBytes) ))
2725                 try_return (status);
2726             FileInfo->FileIdent->fileCharacteristics = 0;
2727             FileInfo->FileIdent->icb = FEicb;
2728             ImpUseLen = FileInfo->FileIdent->lengthOfImpUse;
2729             DirNdx->FileCharacteristics = 0;
2730         }
2731         // init 'parentICBLocation' & so on in FE
2732         ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum =
2733              UDFPhysLbaToPart(Vcb, PartNum, DirInfo->Dloc->FELoc.Mapping[0].extLocation);
2734         ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum = (uint16)PartNum;
2735     //    ((icbtag*)(FileInfo->Dloc->FileEntry+1))->strategyType = 4;
2736     //    ((icbtag*)(FileInfo->Dloc->FileEntry+1))->numEntries = 1;
2737         // try to find suitable unused FileIdent in DirIndex
2738         l = FileInfo->FileIdentLen;
2739         if(undel) goto CrF__2;
2740 #ifndef UDF_LIMIT_DIR_SIZE
2741         if(Vcb->CDR_Mode) {
2742 #endif // UDF_LIMIT_DIR_SIZE
2743             // search for suitable unused entry
2744             if(UDFDirIndexInitScan(DirInfo, &ScanContext, 2)) {
2745                 while((DirNdx = UDFDirIndexScan(&ScanContext, NULL))) {
2746                     if((DirNdx->Length == l) && UDFIsDeleted(DirNdx) &&
2747                        !DirNdx->FileInfo ) {
2748                         // free unicode-buffer with old name
2749                         if(DirNdx->FName.Buffer) {
2750                             MyFreePool__(DirNdx->FName.Buffer);
2751                             DirNdx->FName.Buffer = NULL;
2752                         }
2753                         i = ScanContext.i;
2754                         goto CrF__1;
2755                     }
2756                 }
2757             }
2758 #ifndef UDF_LIMIT_DIR_SIZE
2759         } else {
2760 #endif // UDF_LIMIT_DIR_SIZE
2761             i = UDFDirIndexGetLastIndex(hDirNdx); // 'i' points beyond EO DirIndex
2762 #ifndef UDF_LIMIT_DIR_SIZE
2763         }
2764 #endif // UDF_LIMIT_DIR_SIZE
2765 
2766         // append entry
2767         if(!OS_SUCCESS(status = UDFDirIndexGrow(&(DirInfo->Dloc->DirIndex), 1))) {
2768             try_return (status);
2769         }
2770 
2771         // init offset of new FileIdent in directory Data extent
2772         hDirNdx = DirInfo->Dloc->DirIndex;
2773         if(i-1) {
2774             DirNdx = UDFDirIndex(hDirNdx,i-1);
2775             UDFDirIndex(hDirNdx,i)->Offset = DirNdx->Offset + DirNdx->Length;
2776             DirNdx = UDFDirIndex(hDirNdx,i);
2777         } else {
2778             DirNdx = UDFDirIndex(hDirNdx,i);
2779             DirNdx->Offset = 0;
2780         }
2781         // new terminator is recorded by UDFDirIndexGrow()
2782         if( ((d = ((LBS - (DirNdx->Offset + l + DirInfo->Dloc->DataLoc.Offset)) & (LBS-1) )) < sizeof(FILE_IDENT_DESC)) &&
2783               d ) {
2784             // insufficient space at the end of last sector for
2785             // next FileIdent's tag. fill it with ImpUse data
2786 
2787             // generally, all data should be DWORD-aligned, but if it is not so
2788             // this opearation will help us to avoid glitches
2789             d = (d+3) & ~((uint32)3);
2790 
2791             uint32 IUl, FIl;
2792             if(!MyReallocPool__((int8*)(FileInfo->FileIdent), l,
2793                          (int8**)&(FileInfo->FileIdent), (l+d+3) & ~((uint32)(3)) ))
2794                 try_return (status = STATUS_INSUFFICIENT_RESOURCES);
2795             l += d;
2796             IUl = FileInfo->FileIdent->lengthOfImpUse;
2797             FIl = FileInfo->FileIdent->lengthFileIdent;
2798             // move filename to higher addr
2799             RtlMoveMemory(((int8*)(FileInfo->FileIdent+1))+IUl+d,
2800                           ((int8*)(FileInfo->FileIdent+1))+IUl, FIl);
2801             RtlZeroMemory(((int8*)(FileInfo->FileIdent+1))+IUl, d);
2802             FileInfo->FileIdent->lengthOfImpUse += (uint16)d;
2803             FileInfo->FileIdentLen = l;
2804         }
2805         DirNdx->Length = l;
2806 CrF__1:
2807         // clone unicode string
2808         // it  **<<MUST>>**  be allocated with internal memory manager
2809         DirNdx->FName.Buffer = (PWCHAR)MyAllocatePoolTag__(UDF_FILENAME_MT, (DirNdx->FName.MaximumLength = _fn->Length + sizeof(WCHAR)), MEM_FNAMECPY_TAG);
2810         DirNdx->FName.Length = _fn->Length;
2811         if(!DirNdx->FName.Buffer)
2812             try_return (status = STATUS_INSUFFICIENT_RESOURCES);
2813         RtlCopyMemory(DirNdx->FName.Buffer, _fn->Buffer, _fn->Length);
2814         DirNdx->FName.Buffer[_fn->Length/sizeof(WCHAR)] = 0;
2815 CrF__2:
2816         DirNdx->FI_Flags |= UDFBuildHashEntry(Vcb, &(DirNdx->FName), &(DirNdx->hashes), HASH_ALL);
2817         // we get here immediately when 'undel' occured
2818         FileInfo->Index = i;
2819         DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
2820         DirNdx->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR;
2821         ASSERT(!DirNdx->FileInfo);
2822         DirNdx->FileInfo = FileInfo;
2823         DirNdx->FileEntryLoc = FEicb.extLocation;
2824         // mark file as 'deleted' for now
2825         DirNdx->FileCharacteristics = FILE_DELETED;
2826         FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED;
2827         FileInfo->Dloc->DataLoc.Mapping = UDFExtentToMapping(&(FileInfo->Dloc->FELoc.Mapping[0]));
2828         if(!(FileInfo->Dloc->DataLoc.Mapping)) {
2829             UDFFlushFI(Vcb, FileInfo, PartNum);
2830             try_return (status = STATUS_INSUFFICIENT_RESOURCES);
2831         }
2832         FileInfo->Dloc->DataLoc.Length = 0;
2833         FileInfo->Dloc->DataLoc.Offset = FileInfo->Dloc->FileEntryLen;
2834         FileInfo->ParentFile = DirInfo;
2835         // init FileEntry
2836         UDFSetFileUID(Vcb, FileInfo);
2837         UDFSetFileSize(FileInfo, 0);
2838         UDFIncFileLinkCount(FileInfo); // increase to 1
2839         UDFUpdateCreateTime(Vcb, FileInfo);
2840         UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index),
2841                              FileInfo->Dloc->FileEntry, Vcb->DefaultAttr);
2842         FileInfo->Dloc->DataLoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK;
2843         FileInfo->Dloc->DataLoc.Modified = TRUE;
2844         FileInfo->Dloc->FELoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK;
2845         // zero sector for FileEntry
2846         if(!Vcb->CDR_Mode) {
2847             status = UDFWriteData(Vcb, TRUE, ((int64)(FileInfo->Dloc->FELoc.Mapping[0].extLocation)) << Vcb->BlockSizeBits, LBS, FALSE, Vcb->ZBuffer, &ReadBytes);
2848             if(!OS_SUCCESS(status)) {
2849                 UDFFlushFI(Vcb, FileInfo, PartNum);
2850                 try_return (status);
2851             }
2852         }
2853 #if 0
2854         if((i >= 2) && (DirNdx->FName.Buffer[0] == L'.')) {
2855             BrutePoint();
2856         }
2857 #endif
2858 
2859 #ifdef UDF_CHECK_DISK_ALLOCATION
2860         if(  /*FileInfo->Fcb &&*/
2861              UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) {
2862 
2863             if(!FileInfo->FileIdent ||
2864                !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED)) {
2865                 AdPrint(("Flushing to Discarded block %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation));
2866                 BrutePoint();
2867             }
2868         }
2869 #endif // UDF_CHECK_DISK_ALLOCATION
2870 
2871         // make FileIdent valid
2872         FileInfo->FileIdent->fileCharacteristics = 0;
2873         DirNdx->FileCharacteristics = 0;
2874         UDFReferenceFile__(FileInfo);
2875         UDFFlushFE(Vcb, FileInfo, PartNum);
2876         if(undel)
2877             hDirNdx->DelCount--;
2878         UDFReleaseDloc(Vcb, FileInfo->Dloc);
2879         UDFIncFileCounter(Vcb);
2880 
2881         UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used
2882 
2883         try_return (status = STATUS_SUCCESS);
2884 
2885 try_exit:   NOTHING;
2886 
2887     } _SEH2_FINALLY {
2888         if(!OS_SUCCESS(status)) {
2889             if(FEAllocated)
2890                 UDFFreeFESpace(Vcb, DirInfo, &(FileInfo->Dloc->FELoc));
2891         }
2892     } _SEH2_END
2893     return status;
2894 
2895 } // end UDFCreateFile__()
2896 #endif //UDF_READ_ONLY_BUILD
2897 
2898 /*
2899     This routine reads data from file described by FileInfo
2900  */
2901 /*__inline
2902 OSSTATUS
2903 UDFReadFile__(
2904     IN PVCB Vcb,
2905     IN PUDF_FILE_INFO FileInfo,
2906     IN int64 Offset,   // offset in extent
2907     IN uint32 Length,
2908     IN BOOLEAN Direct,
2909     OUT int8* Buffer,
2910     OUT uint32* ReadBytes
2911     )
2912 {
2913     ValidateFileInfo(FileInfo);
2914 
2915     return UDFReadExtent(Vcb, &(FileInfo->Dloc->DataLoc), Offset, Length, Direct, Buffer, ReadBytes);
2916 } // end UDFReadFile__()*/
2917 
2918 #ifndef UDF_READ_ONLY_BUILD
2919 /*
2920     This routine zeros data in file described by FileInfo
2921  */
2922 __inline
2923 OSSTATUS
2924 UDFZeroFile__(
2925     IN PVCB Vcb,
2926     IN PUDF_FILE_INFO FileInfo,
2927     IN int64 Offset,   // offset in extent
2928     IN uint32 Length,
2929     IN BOOLEAN Direct,
2930     OUT uint32* ReadBytes
2931     )
2932 {
2933     ValidateFileInfo(FileInfo);
2934 
2935     return UDFZeroExtent__(Vcb, &(FileInfo->Dloc->DataLoc), Offset, Length, Direct, ReadBytes);
2936 } // end UDFZeroFile__()*/
2937 
2938 /*
2939     This routine makes sparse area in file described by FileInfo
2940  */
2941 __inline
2942 OSSTATUS
2943 UDFSparseFile__(
2944     IN PVCB Vcb,
2945     IN PUDF_FILE_INFO FileInfo,
2946     IN int64 Offset,   // offset in extent
2947     IN uint32 Length,
2948     IN BOOLEAN Direct,
2949     OUT uint32* ReadBytes
2950     )
2951 {
2952     ValidateFileInfo(FileInfo);
2953 
2954     return UDFSparseExtent__(Vcb, &(FileInfo->Dloc->DataLoc), Offset, Length, Direct, ReadBytes);
2955 } // end UDFSparseFile__()*/
2956 
2957 /*
2958     This routine fills tails of the last sector in extent with ZEROs
2959  */
2960 OSSTATUS
2961 UDFPadLastSector(
2962     IN PVCB Vcb,
2963     IN PEXTENT_INFO ExtInfo
2964     )
2965 {
2966     if(!ExtInfo || !(ExtInfo->Mapping) || !(ExtInfo->Length)) return STATUS_INVALID_PARAMETER;
2967 
2968     PEXTENT_MAP Extent = ExtInfo->Mapping;   // Extent array
2969     uint32 to_write, Lba, sect_offs, flags, WrittenBytes;
2970     OSSTATUS status;
2971     // Length should not be zero
2972     int64 Offset = ExtInfo->Length + ExtInfo->Offset;
2973     // data is sector-size-aligned, we needn't any padding
2974     if(Offset && !((uint32)Offset & (Vcb->LBlockSize-1) )) return STATUS_SUCCESS;
2975     // get Lba of the last sector
2976     Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
2977     // EOF check. If we have valid ExtInfo this will not happen, but who knows..
2978     if((Lba == (uint32)-1) ||
2979        (flags == EXTENT_NOT_RECORDED_NOT_ALLOCATED))
2980         return STATUS_END_OF_FILE;
2981     // write tail
2982     status = UDFWriteData(Vcb, TRUE, (((int64)Lba) << Vcb->BlockSizeBits) + sect_offs, to_write, FALSE, Vcb->ZBuffer, &WrittenBytes);
2983     return status;
2984 } // UDFPadLastSector()
2985 #endif //UDF_READ_ONLY_BUILD
2986 
2987 /*
2988     This routine updates AllocDesc sequence, FileIdent & FileEntry
2989     for given file
2990  */
2991 OSSTATUS
2992 UDFCloseFile__(
2993     IN PVCB Vcb,
2994     IN PUDF_FILE_INFO FileInfo
2995     )
2996 {
2997     ValidateFileInfo(FileInfo);
2998 
2999     if(!FileInfo) return STATUS_SUCCESS;
3000     if(FileInfo->Index<2 && (FileInfo->ParentFile) && !UDFIsAStreamDir(FileInfo)) {
3001         UDFPrint(("Closing Current or Parent Directory... :-\\\n"));
3002         if(FileInfo->RefCount) {
3003             UDFInterlockedDecrement((PLONG)&(FileInfo->RefCount));
3004             ASSERT(FileInfo->Dloc);
3005             if(FileInfo->Dloc)
3006                 UDFInterlockedDecrement((PLONG)&(FileInfo->Dloc->LinkRefCount));
3007 #ifdef UDF_DBG
3008         } else {
3009             BrutePoint();
3010             UDFPrint(("ERROR: Closing unreferenced file!\n"));
3011 #endif // UDF_DBG
3012         }
3013         if(FileInfo->ParentFile->OpenCount) {
3014             UDFInterlockedDecrement((PLONG)&(FileInfo->ParentFile->OpenCount));
3015 #ifdef UDF_DBG
3016         } else {
3017             BrutePoint();
3018             UDFPrint(("ERROR: Closing unopened file!\n"));
3019 #endif // UDF_DBG
3020         }
3021         return STATUS_SUCCESS;
3022     }
3023     PUDF_FILE_INFO DirInfo = FileInfo->ParentFile;
3024     OSSTATUS status;
3025     uint32 PartNum;
3026     if(FileInfo->RefCount) {
3027         UDFInterlockedDecrement((PLONG)&(FileInfo->RefCount));
3028         ASSERT(FileInfo->Dloc);
3029         if(FileInfo->Dloc)
3030             UDFInterlockedDecrement((PLONG)&(FileInfo->Dloc->LinkRefCount));
3031 #ifdef UDF_DBG
3032     } else {
3033         BrutePoint();
3034         UDFPrint(("ERROR: Closing unreferenced file!\n"));
3035 #endif // UDF_DBG
3036     }
3037     if(DirInfo) {
3038         // validate DirInfo
3039         ValidateFileInfo(DirInfo);
3040 
3041         if(DirInfo->OpenCount) {
3042             UDFInterlockedDecrement((PLONG)&(DirInfo->OpenCount));
3043 #ifdef UDF_DBG
3044         } else {
3045             BrutePoint();
3046             UDFPrint(("ERROR: Closing unopened file!\n"));
3047 #endif // UDF_DBG
3048         }
3049     }
3050     // If the file has gone (unlinked) we should return STATUS_SUCCESS here.
3051     if(!FileInfo->Dloc) return STATUS_SUCCESS;
3052 
3053     if(FileInfo->RefCount ||
3054        FileInfo->OpenCount ||
3055        !(FileInfo->Dloc->FELoc.Mapping)) return STATUS_SUCCESS;
3056 //    ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3057     PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3058     if(PartNum == (uint32)-1) {
3059         UDFPrint(("  Is DELETED ?\n"));
3060         if(DirInfo) {
3061             PartNum = UDFGetPartNumByPhysLba(Vcb, DirInfo->Dloc->FELoc.Mapping[0].extLocation);
3062         } else {
3063             BrutePoint();
3064         }
3065     }
3066 #ifdef UDF_CHECK_DISK_ALLOCATION
3067     if(  FileInfo->Fcb &&
3068          UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) {
3069 
3070         //ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3071         if(UDFIsAStreamDir(FileInfo)) {
3072             if(!UDFIsSDirDeleted(FileInfo)) {
3073                 UDFPrint(("  Not DELETED SDir\n"));
3074                 BrutePoint();
3075             }
3076             ASSERT(!FileInfo->Dloc->FELoc.Modified);
3077         } else
3078         if(!FileInfo->FileIdent ||
3079            !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED)) {
3080             if(!FileInfo->FileIdent) {
3081                 AdPrint(("  No FileIdent\n"));
3082             }
3083             if(FileInfo->FileIdent &&
3084                !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED))
3085                 AdPrint(("  Not DELETED\n"));
3086             ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3087             AdPrint(("Flushing to Discarded block %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation));
3088             BrutePoint();
3089         } else {
3090             UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_FREE); // check if free
3091             UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->FELoc.Mapping, AS_FREE); // check if free
3092         }
3093     } else {
3094         if(!FileInfo->Dloc->FELoc.Mapping[0].extLocation ||
3095             UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) {
3096             UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_FREE); // check if free
3097         } else {
3098             UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used
3099         }
3100     }
3101 #endif // UDF_CHECK_DISK_ALLOCATION
3102     // check if we should update parentICBLocation
3103     if( !((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum &&
3104         !((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum &&
3105         DirInfo &&
3106         !Vcb->CDR_Mode &&
3107         Vcb->Modified &&
3108         UDFGetFileLinkCount(FileInfo) ) {
3109         ASSERT(DirInfo->Dloc->FELoc.Mapping[0].extLocation);
3110         ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum =
3111              UDFPhysLbaToPart(Vcb, PartNum, DirInfo->Dloc->FELoc.Mapping[0].extLocation);
3112         ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum = (uint16)PartNum;
3113         FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
3114     }
3115 
3116     // we needn't flushing FE & Allocs untill all links are closed...
3117     if(!FileInfo->Dloc->LinkRefCount) {
3118 
3119         // flush FE and pre-allocation charge for directories
3120         if(FileInfo->Dloc &&
3121            FileInfo->Dloc->DirIndex) {
3122 
3123             UDFFlushFESpace(Vcb, FileInfo->Dloc);
3124             if(FileInfo->Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) {
3125                 FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_CUT_PREALLOCATED;
3126                 status = UDFResizeExtent(Vcb, PartNum, UDFGetFileSize(FileInfo), FALSE, &(FileInfo->Dloc->DataLoc));
3127                 FileInfo->Dloc->DataLoc.Flags &= ~(EXTENT_FLAG_PREALLOCATED | EXTENT_FLAG_CUT_PREALLOCATED);
3128                 if(OS_SUCCESS(status)) {
3129                     AdPrint(("Dir pre-alloc truncated (Close)\n"));
3130                     FileInfo->Dloc->DataLoc.Modified = TRUE;
3131                 }
3132             }
3133         }
3134 
3135         if(!OS_SUCCESS(status = UDFFlushFE(Vcb, FileInfo, PartNum))) {
3136             UDFPrint(("Error flushing FE\n"));
3137 //flush_recovery:
3138             BrutePoint();
3139             if(FileInfo->Index >= 2) {
3140                 PDIR_INDEX_ITEM DirNdx;
3141                 DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index);
3142                 if(DirNdx) {
3143                     UDFPrint(("Recovery: mark as deleted & flush FI\n"));
3144                     DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
3145                     DirNdx->FileCharacteristics |= FILE_DELETED;
3146                     FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED;
3147                     UDFFlushFI(Vcb, FileInfo, PartNum);
3148                 }
3149             }
3150             return status;
3151         }
3152     }
3153     // ... but FI must be updated (if any)
3154     if(!OS_SUCCESS(status = UDFFlushFI(Vcb, FileInfo, PartNum))) {
3155         UDFPrint(("Error flushing FI\n"));
3156         return status;
3157     }
3158 #ifdef UDF_DBG
3159 //    ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3160     if((FileInfo->Dloc->FileEntry->descVersion != 2) &&
3161        (FileInfo->Dloc->FileEntry->descVersion != 3)) {
3162         ASSERT(UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation));
3163     }
3164 #endif // UDF_DBG
3165     return STATUS_SUCCESS;
3166 } // end UDFCloseFile__()
3167 
3168 
3169 #ifndef UDF_READ_ONLY_BUILD
3170 /*
3171     This routine moves file from DirInfo1 to DirInfo2 & renames it to fn
3172  */
3173 OSSTATUS
3174 UDFRenameMoveFile__(
3175     IN PVCB Vcb,
3176     IN BOOLEAN IgnoreCase,
3177  IN OUT BOOLEAN* Replace,        // replace if destination file exists
3178     IN PUNICODE_STRING fn,       // destination
3179  IN OUT PUDF_FILE_INFO DirInfo1,
3180  IN OUT PUDF_FILE_INFO DirInfo2,
3181  IN OUT PUDF_FILE_INFO FileInfo  // source (opened)
3182     )
3183 {
3184     PUDF_FILE_INFO FileInfo2;
3185     OSSTATUS status;
3186     PDIR_INDEX_ITEM DirNdx1;
3187     PDIR_INDEX_ITEM DirNdx2;
3188     uint_di i,j;
3189     BOOLEAN Recovery = FALSE;
3190     BOOLEAN SameFE = FALSE;
3191     uint32 NTAttr = 0;
3192 
3193     // validate FileInfo
3194     ValidateFileInfo(DirInfo1);
3195     ValidateFileInfo(DirInfo2);
3196     ValidateFileInfo(FileInfo);
3197 
3198     i = j = 0;
3199     if(DirInfo1 == DirInfo2) {
3200         if(OS_SUCCESS(status = UDFFindFile(Vcb, IgnoreCase, TRUE, fn, DirInfo2, &j)) &&
3201            (j==FileInfo->Index) ) {
3202             // case-only rename
3203             uint8* CS0;
3204             uint32 Nlen, /* l, FIXME ReactOS */ IUl;
3205 
3206             // prepare filename
3207             UDFCompressUnicode(fn, &CS0, &Nlen);
3208             if(!CS0) return STATUS_INSUFFICIENT_RESOURCES;
3209 /*            if(Nlen > UDF_NAME_LEN) {
3210                 if(CS0) MyFreePool__(CS0);
3211                 return STATUS_OBJECT_NAME_INVALID;
3212             }*/
3213             // allocate memory for FI
3214             DirNdx2 = UDFDirIndex(DirInfo2->Dloc->DirIndex,j);
3215             IUl = DirNdx2->FileInfo->FileIdent->lengthOfImpUse;
3216 #if 0
3217             l = (sizeof(FILE_IDENT_DESC) + Nlen + IUl + 3) & ~((uint32)3);
3218 #endif
3219 
3220             RtlCopyMemory( ((uint8*)(DirNdx2->FileInfo->FileIdent+1))+IUl, CS0, Nlen);
3221             RtlCopyMemory(DirNdx2->FName.Buffer, fn->Buffer, fn->Length);
3222 
3223             if(CS0) MyFreePool__(CS0);
3224 
3225             DirNdx2->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
3226             UDFBuildHashEntry(Vcb, &(DirNdx2->FName), &(DirNdx2->hashes), HASH_ALL);
3227             return STATUS_SUCCESS;
3228 /*        } else
3229         if(!OS_SUCCESS(status) && (fn->Length == UDFDirIndex(DirInfo2->Dloc->DirIndex, j=FileInfo->Index)->FName.Length)) {
3230             // target file doesn't exist, but name lengthes are equal
3231             RtlCopyMemory((DirNdx1 = UDFDirIndex(DirInfo1->Dloc->DirIndex,j))->FName.Buffer, fn->Buffer, fn->Length);
3232             DirNdx1->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
3233             UDFBuildHashEntry(Vcb, &(DirNdx1->FName), &(DirNdx1->hashes), HASH_ALL);
3234             return STATUS_SUCCESS;*/
3235         }
3236     }
3237 
3238     // PHASE 0
3239     // try to create new FileIdent & FileEntry in Dir2
3240 
3241 RenameRetry:
3242     if(!OS_SUCCESS(status = UDFCreateFile__(Vcb, IgnoreCase, fn, UDFGetFileEALength(FileInfo),
3243                     0, (FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY),
3244                     TRUE, DirInfo2, &FileInfo2))) {
3245         UDFCleanUpFile__(Vcb, FileInfo2);
3246         if(FileInfo2) MyFreePool__(FileInfo2);
3247         if(status == STATUS_ACCESS_DENIED) {
3248             // try to recover >;->
3249             if((*Replace) && !Recovery) {
3250                 Recovery = TRUE;
3251                 status = UDFOpenFile__(Vcb, IgnoreCase, TRUE, fn, DirInfo2, &FileInfo2, NULL);
3252                 if(OS_SUCCESS(status)) {
3253                     status = UDFDoesOSAllowFileToBeTargetForRename__(FileInfo2);
3254                     if(!OS_SUCCESS(status)) {
3255                         UDFCloseFile__(Vcb, FileInfo2);
3256                         goto cleanup_and_abort_rename;
3257                     }
3258                     status = UDFUnlinkFile__(Vcb, FileInfo2, TRUE);
3259 //                    UDFPretendFileDeleted__(Vcb, FileInfo2);
3260                     UDFCloseFile__(Vcb, FileInfo2);
3261                     if(UDFCleanUpFile__(Vcb, FileInfo2)) {
3262                         MyFreePool__(FileInfo2);
3263                         FileInfo2 = NULL;
3264                         if(SameFE)
3265                             return status;
3266                     } else {
3267                         // we get here if the FileInfo has associated
3268                         // system-specific Fcb
3269                         // Such fact means that not all system references
3270                         // has already gone (except Linked file case)
3271 /*                        if(SameFE)
3272                             return status;*/
3273 //                        UDFRemoveOSReferences__(FileInfo2);
3274                         if(!OS_SUCCESS(status) ||
3275                            (UDFGetFileLinkCount(FileInfo2) < 1))
3276                             status = STATUS_ACCESS_DENIED;
3277                     }
3278                     if(OS_SUCCESS(status)) goto RenameRetry;
3279                 }
3280 cleanup_and_abort_rename:
3281                 if(FileInfo2 && UDFCleanUpFile__(Vcb, FileInfo2)) {
3282                     MyFreePool__(FileInfo2);
3283                     FileInfo2 = NULL;
3284                 }
3285             } else {
3286                 status = STATUS_OBJECT_NAME_COLLISION;
3287             }
3288         }
3289         return status;
3290     }
3291     // update pointers
3292     DirNdx1 = UDFDirIndex(DirInfo1->Dloc->DirIndex, i = FileInfo->Index);
3293     DirNdx2 = UDFDirIndex(DirInfo2->Dloc->DirIndex, j = FileInfo2->Index);
3294 
3295     // copy file attributes to newly created FileIdent
3296     NTAttr = UDFAttributesToNT(DirNdx1, FileInfo->Dloc->FileEntry);
3297     FileInfo2->FileIdent->fileVersionNum = FileInfo->FileIdent->fileVersionNum;
3298     // unlink source FileIdent
3299     if(!OS_SUCCESS(status = UDFUnlinkFile__(Vcb, FileInfo, FALSE))) {
3300         // kill newly created entry
3301         UDFFlushFile__(Vcb, FileInfo2);
3302         UDFUnlinkFile__(Vcb, FileInfo2, TRUE);
3303         UDFCloseFile__(Vcb, FileInfo2);
3304         UDFCleanUpFile__(Vcb, FileInfo2);
3305         MyFreePool__(FileInfo2);
3306         return status;
3307     }
3308 
3309     // PHASE 1
3310     // drop all unnecessary info from FileInfo & flush FI
3311 
3312     DirNdx1->FileInfo = NULL;
3313     ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3314     UDFFlushFI(Vcb, FileInfo, UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation));
3315     UDFInterlockedExchangeAdd((PLONG)&(DirInfo1->OpenCount),
3316                             -((LONG)(FileInfo->RefCount)));
3317     // PHASE 2
3318     // copy all necessary info from FileInfo to FileInfo2
3319 
3320     FileInfo2->FileIdent->icb = FileInfo->FileIdent->icb;
3321     FileInfo2->FileIdent->fileCharacteristics = FileInfo->FileIdent->fileCharacteristics;
3322     FileInfo2->FileIdent->fileVersionNum = FileInfo->FileIdent->fileVersionNum;
3323     MyFreePool__(FileInfo->FileIdent);
3324     FileInfo->FileIdent = NULL;
3325 
3326     // PHASE 3
3327     // copy all necessary info from FileInfo2 to FileInfo
3328 
3329     DirNdx2->FileInfo = FileInfo;
3330     DirNdx2->FileCharacteristics = DirNdx1->FileCharacteristics & ~FILE_DELETED;
3331     DirNdx2->FileEntryLoc = DirNdx1->FileEntryLoc;
3332     DirNdx2->FI_Flags = (DirNdx1->FI_Flags & ~UDF_FI_FLAG_SYS_ATTR) | UDF_FI_FLAG_FI_MODIFIED;
3333     UDFInterlockedExchangeAdd((PLONG)&(DirInfo2->OpenCount),
3334                             FileInfo->RefCount - FileInfo2->RefCount);
3335 
3336     UDFAttributesToUDF(DirNdx2, FileInfo2->Dloc->FileEntry, NTAttr);
3337 
3338     FileInfo->Index = j;
3339     FileInfo->FileIdent = FileInfo2->FileIdent;
3340     FileInfo->FileIdentLen = FileInfo2->FileIdentLen;
3341     FileInfo->ParentFile = DirInfo2;
3342     FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
3343 
3344     ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation =
3345         ((icbtag*)(FileInfo2->Dloc->FileEntry+1))->parentICBLocation;
3346 
3347     UDFIncFileLinkCount(FileInfo); // increase to 1
3348 
3349 //    UDFUpdateModifyTime(Vcb, FileInfo);
3350 
3351     // PHASE 4
3352     // drop all unnecessary info from FileInfo2
3353 
3354     UDFFreeFESpace(Vcb, DirInfo2, &(FileInfo2->Dloc->FELoc));
3355     UDFUnlinkDloc(Vcb, FileInfo2->Dloc);
3356     UDFDecFileLinkCount(FileInfo2);
3357 
3358     FileInfo2->Dloc->FE_Flags &= ~UDF_FE_FLAG_FE_MODIFIED;
3359 /*    MyFreePool__(FileInfo2->Dloc->FileEntry);
3360     FileInfo2->Dloc->FileEntry = NULL;*/
3361     FileInfo2->ParentFile = NULL;
3362     FileInfo2->FileIdent = NULL;
3363     FileInfo2->RefCount = 0;
3364     FileInfo2->Dloc->LinkRefCount = 0;
3365     ASSERT(FileInfo2->Dloc->DataLoc.Mapping);
3366     FileInfo2->Dloc->DataLoc.Mapping[0].extLocation = 0;
3367     FileInfo2->Dloc->DataLoc.Mapping[0].extLength = 0;
3368 
3369     UDFCleanUpFile__(Vcb, FileInfo2);
3370     MyFreePool__(FileInfo2);
3371 
3372     // return 'delete target' status
3373     (*Replace) = Recovery;
3374 
3375     return STATUS_SUCCESS;
3376 } // end UDFRenameMoveFile__()
3377 
3378 /*
3379     This routine transforms zero-sized file to directory
3380  */
3381 OSSTATUS
3382 UDFRecordDirectory__(
3383     IN PVCB Vcb,
3384  IN OUT PUDF_FILE_INFO DirInfo   // source (opened)
3385     )
3386 {
3387     OSSTATUS status;
3388     LONG_AD FEicb;
3389     UDF_FILE_INFO FileInfo;
3390     UDF_DATALOC_INFO Dloc;
3391     UNICODE_STRING PName;
3392     uint32 PartNum;
3393     uint32 WrittenBytes;
3394     PDIR_INDEX_ITEM CurDirNdx;
3395     uint32 lba;
3396 
3397     // validate DirInfo
3398     ValidateFileInfo(DirInfo);
3399     if(DirInfo->ParentFile && UDFIsAStreamDir(DirInfo->ParentFile))
3400         return STATUS_ACCESS_DENIED;
3401     // file should be empty
3402     if(UDFGetFileSize(DirInfo)) {
3403         if( DirInfo->FileIdent &&
3404            (DirInfo->FileIdent->fileCharacteristics & FILE_DIRECTORY)) return STATUS_FILE_IS_A_DIRECTORY;
3405         return STATUS_NOT_A_DIRECTORY;
3406     }
3407     if(DirInfo->Dloc->DirIndex) return STATUS_FILE_IS_A_DIRECTORY;
3408     // create empty DirIndex
3409     if(DirInfo->FileIdent) DirInfo->FileIdent->fileCharacteristics |= FILE_DIRECTORY;
3410     if((CurDirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(DirInfo),DirInfo->Index)))
3411         CurDirNdx->FileCharacteristics |= FILE_DIRECTORY;
3412     ((icbtag*)(DirInfo->Dloc->FileEntry+1))->fileType = UDF_FILE_TYPE_DIRECTORY;
3413     // init temporary FileInfo
3414     RtlZeroMemory(&FileInfo, sizeof(UDF_FILE_INFO));
3415     FileInfo.Dloc = &Dloc;
3416     FileInfo.Dloc->FileEntry = DirInfo->ParentFile->Dloc->FileEntry;
3417     FileInfo.Dloc->FileEntryLen = DirInfo->ParentFile->Dloc->FileEntryLen;
3418     FileInfo.Dloc->DataLoc = DirInfo->Dloc->DataLoc;
3419     FileInfo.Dloc->FELoc = DirInfo->Dloc->FELoc;
3420     FileInfo.ParentFile = DirInfo;
3421     // prepare FileIdent for 'parent Dir'
3422     lba = DirInfo->Dloc->FELoc.Mapping[0].extLocation;
3423     ASSERT(lba);
3424     PartNum = UDFGetPartNumByPhysLba(Vcb, lba);
3425     FEicb.extLength = Vcb->LBlockSize;
3426     FEicb.extLocation.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, lba);
3427     FEicb.extLocation.partitionReferenceNum = (uint16)PartNum;
3428     RtlZeroMemory(&(FEicb.impUse), sizeof(FEicb.impUse));
3429     PName.Buffer = (PWCH)L"";
3430     PName.Length = (PName.MaximumLength = sizeof(L"")) - sizeof(WCHAR);
3431     if(!OS_SUCCESS(status =
3432         UDFBuildFileIdent(Vcb, &PName, &FEicb, 0,
3433                 &(FileInfo.FileIdent), &(FileInfo.FileIdentLen)) ))
3434         return status;
3435     FileInfo.FileIdent->fileCharacteristics |= (FILE_PARENT | FILE_DIRECTORY);
3436     UDFDecFileCounter(Vcb);
3437     UDFIncDirCounter(Vcb);
3438     // init structure
3439     UDFSetUpTag(Vcb, &(FileInfo.FileIdent->descTag), (uint16)(FileInfo.FileIdentLen),
3440               FEicb.extLocation.logicalBlockNum);
3441     FileInfo.Dloc->DataLoc.Flags |= EXTENT_FLAG_VERIFY; // for metadata
3442     // flush
3443     status = UDFWriteFile__(Vcb, DirInfo, 0, FileInfo.FileIdentLen, FALSE, (int8*)(FileInfo.FileIdent), &WrittenBytes);
3444 //    status = UDFFlushFI(Vcb, &FileInfo, PartNum);
3445 
3446 #ifdef UDF_DBG
3447     if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
3448         ASSERT(UDFGetFileSize(DirInfo) <= UDFGetExtentLength(DirInfo->Dloc->DataLoc.Mapping));
3449     } else {
3450         ASSERT(((UDFGetFileSize(DirInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) ==
3451                ((UDFGetExtentLength(DirInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)));
3452     }
3453 #endif // UDF_DBG
3454 
3455     MyFreePool__(FileInfo.FileIdent);
3456     if(!OS_SUCCESS(status)) return status;
3457     if(CurDirNdx) CurDirNdx->FileCharacteristics =
3458         DirInfo->FileIdent->fileCharacteristics;
3459     return UDFIndexDirectory(Vcb, DirInfo);
3460 } // end UDFRecordDirectory__()
3461 
3462 /*
3463     This routine changes file size (on disc)
3464  */
3465 OSSTATUS
3466 UDFResizeFile__(
3467     IN PVCB Vcb,
3468  IN OUT PUDF_FILE_INFO FileInfo,
3469     IN int64 NewLength
3470     )
3471 {
3472     uint32 WrittenBytes;
3473     OSSTATUS status;
3474     uint32 PartNum;
3475     int8* OldInIcb = NULL;
3476     PEXTENT_MAP NewMap;
3477 
3478     UDFPrint(("UDFResizeFile__: FI %x, -> %I64x\n", FileInfo, NewLength));
3479     ValidateFileInfo(FileInfo);
3480 //    ASSERT(FileInfo->RefCount >= 1);
3481 
3482     if((NewLength >> Vcb->LBlockSizeBits) > Vcb->TotalAllocUnits) {
3483         UDFPrint(("STATUS_DISK_FULL\n"));
3484         return STATUS_DISK_FULL;
3485     }
3486     if (NewLength == FileInfo->Dloc->DataLoc.Length) return STATUS_SUCCESS;
3487     if(FileInfo->ParentFile && (FileInfo->Index >= 2)) {
3488         UDFDirIndex(FileInfo->ParentFile->Dloc->DirIndex,FileInfo->Index)->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR;
3489     }
3490     if(NewLength > FileInfo->Dloc->DataLoc.Length) {
3491         // grow file
3492         return UDFWriteFile__(Vcb, FileInfo, NewLength, 0, FALSE, NULL, &WrittenBytes);
3493     }
3494     // truncate file
3495     if(NewLength <= (Vcb->LBlockSize - FileInfo->Dloc->FileEntryLen)) {
3496         // check if we are already in IN_ICB mode
3497         if((((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) != ICB_FLAG_AD_IN_ICB) {
3498             // read data from old location
3499             if(NewLength) {
3500                 OldInIcb = (int8*)MyAllocatePool__(NonPagedPool, (uint32)NewLength);
3501                 if(!OldInIcb) return STATUS_INSUFFICIENT_RESOURCES;
3502                 status = UDFReadExtent(Vcb, &(FileInfo->Dloc->DataLoc), 0, (uint32)NewLength, FALSE, OldInIcb, &WrittenBytes);
3503                 if(!OS_SUCCESS(status)) {
3504                     MyFreePool__(OldInIcb);
3505                     return status;
3506                 }
3507             } else {
3508                 OldInIcb = NULL;
3509             }
3510             // allocate storage for new mapping
3511             NewMap = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , 2*sizeof(EXTENT_MAP),
3512                                                                MEM_EXTMAP_TAG);
3513             if(!(NewMap)) {
3514                 MyFreePool__(OldInIcb);
3515                 return STATUS_INSUFFICIENT_RESOURCES;
3516             }
3517             // free old location...
3518             if(FileInfo->Dloc->DataLoc.Mapping[0].extLocation !=
3519                FileInfo->Dloc->FELoc.Mapping[0].extLocation) {
3520                ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3521 mark_data_map_0:
3522                 UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, FileInfo->Dloc->DataLoc.Mapping, AS_DISCARDED); // free
3523             } else {
3524                 if((FileInfo->Dloc->DataLoc.Mapping[0].extLength & UDF_EXTENT_LENGTH_MASK)
3525                        > Vcb->LBlockSize) {
3526                     BrutePoint();
3527                     FileInfo->Dloc->DataLoc.Mapping[0].extLength -= Vcb->LBlockSize;
3528                     FileInfo->Dloc->DataLoc.Mapping[0].extLocation += (1 << Vcb->LB2B_Bits);
3529                     goto mark_data_map_0;
3530                 }
3531                 UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->DataLoc.Mapping[1]), AS_DISCARDED); // free
3532             }
3533             if(FileInfo->Dloc->AllocLoc.Mapping) {
3534                 if((FileInfo->Dloc->AllocLoc.Mapping[0].extLength & UDF_EXTENT_LENGTH_MASK)
3535                        > Vcb->LBlockSize) {
3536                     FileInfo->Dloc->AllocLoc.Mapping[0].extLength -= Vcb->LBlockSize;
3537                     FileInfo->Dloc->AllocLoc.Mapping[0].extLocation += (1 << Vcb->LB2B_Bits);
3538                     UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, FileInfo->Dloc->AllocLoc.Mapping, AS_DISCARDED); // free
3539                 } else {
3540                     UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->AllocLoc.Mapping[1]), AS_DISCARDED); // free
3541                 }
3542                 MyFreePool__(FileInfo->Dloc->AllocLoc.Mapping);
3543             }
3544             MyFreePool__(FileInfo->Dloc->DataLoc.Mapping);
3545             FileInfo->Dloc->AllocLoc.Mapping = NULL;
3546             FileInfo->Dloc->AllocLoc.Length = 0;
3547             FileInfo->Dloc->AllocLoc.Offset = 0;
3548             FileInfo->Dloc->AllocLoc.Modified = TRUE;
3549             // switch to IN_ICB mode
3550             ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK;
3551             ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags |= ICB_FLAG_AD_IN_ICB;
3552             // init new data location descriptors
3553             FileInfo->Dloc->DataLoc.Mapping = NewMap;
3554             RtlZeroMemory((int8*)(FileInfo->Dloc->DataLoc.Mapping), 2*sizeof(EXTENT_MAP));
3555             FileInfo->Dloc->DataLoc.Mapping[0] = FileInfo->Dloc->FELoc.Mapping[0];
3556             FileInfo->Dloc->DataLoc.Length = NewLength;
3557             FileInfo->Dloc->DataLoc.Offset = FileInfo->Dloc->FileEntryLen;
3558             // write data to new location
3559             if(OldInIcb) {
3560                 status = UDFWriteExtent(Vcb, &(FileInfo->Dloc->DataLoc), 0, (uint32)NewLength, FALSE, OldInIcb, &WrittenBytes);
3561             } else {
3562                 status = STATUS_SUCCESS;
3563             }
3564             FileInfo->Dloc->DataLoc.Modified = TRUE;
3565             if(OldInIcb) MyFreePool__(OldInIcb);
3566         } else {
3567             // just modify Length field
3568             FileInfo->Dloc->DataLoc.Length = NewLength;
3569             status = STATUS_SUCCESS;
3570         }
3571     } else {
3572         // resize extent
3573         ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3574         PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3575         status = UDFResizeExtent(Vcb, PartNum, NewLength, FALSE, &(FileInfo->Dloc->DataLoc));
3576         FileInfo->Dloc->DataLoc.Modified = TRUE;
3577         FileInfo->Dloc->AllocLoc.Modified = TRUE;
3578     }
3579     if(OS_SUCCESS(status)) {
3580         UDFSetFileSize(FileInfo, NewLength);
3581     }
3582 
3583 #ifdef UDF_DBG
3584     if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
3585         ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping));
3586     } else {
3587         ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) ==
3588                ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)));
3589     }
3590 #endif // UDF_DBG
3591 
3592     return status;
3593 } // end UDFResizeFile__()
3594 #endif //UDF_READ_ONLY_BUILD
3595 
3596 /*
3597     This routine loads VAT.
3598  */
3599 OSSTATUS
3600 UDFLoadVAT(
3601     IN PVCB Vcb,
3602     IN uint32 PartNdx
3603     )
3604 {
3605     lb_addr VatFELoc;
3606     OSSTATUS status;
3607     PUDF_FILE_INFO VatFileInfo;
3608     uint32 len, i=0, j, to_read;
3609     uint32 Offset, hdrOffset;
3610     uint32 ReadBytes;
3611     uint32 root;
3612     uint16 PartNum;
3613 //    uint32 VatFirstLba = 0;
3614     int8* VatOldData;
3615     uint32 VatLba[6] = { Vcb->LastLBA,
3616                         Vcb->LastLBA - 2,
3617                         Vcb->LastLBA - 3,
3618                         Vcb->LastLBA - 5,
3619                         Vcb->LastLBA - 7,
3620                         0 };
3621 
3622     if(Vcb->Vat) return STATUS_SUCCESS;
3623     if(!Vcb->CDR_Mode) return STATUS_SUCCESS;
3624     // disable VAT for now. We'll reenable it if VAT is successfuly loaded
3625     Vcb->CDR_Mode = FALSE;
3626     PartNum = Vcb->Partitions[PartNdx].PartitionNum;
3627     root = Vcb->Partitions[PartNdx].PartitionRoot;
3628     if(Vcb->LBlockSize != Vcb->BlockSize) {
3629         // don't know how to operate... :(((
3630         return STATUS_UNRECOGNIZED_VOLUME;
3631     }
3632     if((Vcb->LastTrackNum > 1) &&
3633        (Vcb->LastLBA == Vcb->TrackMap[Vcb->LastTrackNum-1].LastLba)) {
3634         UDFPrint(("Hardware Read-only volume\n"));
3635         Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY;
3636     }
3637 
3638     VatFileInfo = Vcb->VatFileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT, sizeof(UDF_FILE_INFO), MEM_VATFINF_TAG);
3639     if(!VatFileInfo) return STATUS_INSUFFICIENT_RESOURCES;
3640     // load VAT FE (we know its location)
3641     VatFELoc.partitionReferenceNum = PartNum;
3642 retry_load_vat:
3643     VatFELoc.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, VatLba[i]);
3644     if(!OS_SUCCESS(status = UDFOpenRootFile__(Vcb, &VatFELoc, VatFileInfo))) {
3645         UDFCleanUpFile__(Vcb, VatFileInfo);
3646         // try another location
3647         i++;
3648         if( VatLba[i] &&
3649            (status != STATUS_FILE_CORRUPT_ERROR) &&
3650            (status != STATUS_CRC_ERROR)) goto retry_load_vat;
3651         MyFreePool__(VatFileInfo);
3652         Vcb->VatFileInfo = NULL;
3653         return status;
3654     }
3655     len = (uint32)UDFGetFileSize(VatFileInfo);
3656     if(Vcb->Partitions[PartNdx].PartitionType == UDF_VIRTUAL_MAP15) {
3657         // load Vat 1.50 header
3658         UDFPrint(("Load VAT 1.50\n"));
3659         VirtualAllocationTable15* Buf;
3660         if(((icbtag*)(VatFileInfo->Dloc->FileEntry+1))->fileType != UDF_FILE_TYPE_VAT15) {
3661             status = STATUS_FILE_CORRUPT_ERROR;
3662             goto err_vat_15;
3663         }
3664         Buf = (VirtualAllocationTable15*)MyAllocatePool__(NonPagedPool, sizeof(VirtualAllocationTable15));
3665         if(!Buf) {
3666 err_vat_15_2:
3667             status = STATUS_INSUFFICIENT_RESOURCES;
3668 err_vat_15:
3669             UDFCloseFile__(Vcb, VatFileInfo);
3670             UDFCleanUpFile__(Vcb, VatFileInfo);
3671             MyFreePool__(VatFileInfo);
3672             Vcb->VatFileInfo = NULL;
3673             return status;
3674         }
3675         Offset = 0;
3676         to_read =
3677         hdrOffset = len - sizeof(VirtualAllocationTable15);
3678         MyFreePool__(Buf);
3679 
3680         Vcb->minUDFReadRev  =
3681         Vcb->minUDFWriteRev =
3682         Vcb->maxUDFWriteRev = 0x0150;
3683 
3684         Vcb->numFiles =
3685         Vcb->numDirs  = -1;
3686 
3687     } else
3688     if(Vcb->Partitions[PartNdx].PartitionType == UDF_VIRTUAL_MAP20) {
3689         // load Vat 2.00 header
3690         UDFPrint(("Load VAT 2.00\n"));
3691         VirtualAllocationTable20* Buf;
3692         if(((icbtag*)(VatFileInfo->Dloc->FileEntry+1))->fileType != UDF_FILE_TYPE_VAT20) {
3693             status = STATUS_FILE_CORRUPT_ERROR;
3694             goto err_vat_15;
3695         }
3696         Buf = (VirtualAllocationTable20*)MyAllocatePool__(NonPagedPool, sizeof(VirtualAllocationTable20));
3697         if(!Buf) goto err_vat_15_2;
3698         Offset = Buf->lengthHeader;
3699         to_read = len - Offset;
3700         hdrOffset = 0;
3701         MyFreePool__(Buf);
3702 
3703         Vcb->minUDFReadRev  = Buf->minReadRevision;
3704         Vcb->minUDFWriteRev = Buf->minWriteRevision;
3705         Vcb->maxUDFWriteRev = Buf->maxWriteRevision;
3706 
3707         Vcb->numFiles = Buf->numFIDSFiles;
3708         Vcb->numDirs  = Buf->numFIDSDirectories;
3709 
3710     } else {
3711         // unknown (or wrong) VAT format
3712         UDFPrint(("unknown (or wrong) VAT format\n"));
3713         status = STATUS_FILE_CORRUPT_ERROR;
3714         goto err_vat_15;
3715     }
3716     // read VAT & remember old version
3717     Vcb->Vat = (uint32*)DbgAllocatePool(NonPagedPool, (Vcb->LastPossibleLBA+1)*sizeof(uint32) );
3718     if(!Vcb->Vat) {
3719         goto err_vat_15_2;
3720     }
3721     // store base version of VAT in memory
3722     VatOldData = (int8*)DbgAllocatePool(PagedPool, len);
3723     if(!VatOldData) {
3724         DbgFreePool(Vcb->Vat);
3725         Vcb->Vat = NULL;
3726         goto err_vat_15_2;
3727     }
3728     status = UDFReadFile__(Vcb, VatFileInfo, 0, len, FALSE, VatOldData, &ReadBytes);
3729     if(!OS_SUCCESS(status)) {
3730         UDFCloseFile__(Vcb, VatFileInfo);
3731         UDFCleanUpFile__(Vcb, VatFileInfo);
3732         MyFreePool__(VatFileInfo);
3733         DbgFreePool(Vcb->Vat);
3734         DbgFreePool(VatOldData);
3735         Vcb->Vat = NULL;
3736         Vcb->VatFileInfo = NULL;
3737     } else {
3738         // initialize VAT
3739         // !!! NOTE !!!
3740         // Both VAT copies - in-memory & on-disc
3741         // contain _relative_ addresses
3742         len = Vcb->NWA - root;
3743         for(i=0; i<=len; i++) {
3744             Vcb->Vat[i] = i;
3745         }
3746         RtlCopyMemory(Vcb->Vat, VatOldData+Offset, to_read);
3747         Vcb->InitVatCount =
3748         Vcb->VatCount = to_read/sizeof(uint32);
3749         Vcb->VatPartNdx = PartNdx;
3750         Vcb->CDR_Mode = TRUE;
3751         len = Vcb->VatCount;
3752         RtlFillMemory(&(Vcb->Vat[Vcb->NWA-root]), (Vcb->LastPossibleLBA-Vcb->NWA+1)*sizeof(uint32), 0xff);
3753         // sync VAT and FSBM
3754         for(i=0; i<len; i++) {
3755             if(Vcb->Vat[i] == UDF_VAT_FREE_ENTRY) {
3756                 UDFSetFreeBit(Vcb->FSBM_Bitmap, root+i);
3757             }
3758         }
3759         len = Vcb->LastPossibleLBA;
3760         // "pre-format" reserved area
3761         for(i=Vcb->NWA; i<len;) {
3762             for(j=0; (j<PACKETSIZE_UDF) && (i<len); j++, i++)
3763                 UDFSetFreeBit(Vcb->FSBM_Bitmap, i);
3764             for(j=0; (j<7) && (i<len); j++, i++)
3765                 UDFSetUsedBit(Vcb->FSBM_Bitmap, i);
3766         }
3767         DbgFreePool(VatOldData);
3768     }
3769     return status;
3770 } // end UDFLoadVAT()
3771 
3772 /*
3773     Reads Extended Attributes
3774     Caller should use UDFGetFileEALength to allocate Buffer of sufficient
3775     size
3776  *//*
3777 OSSTATUS
3778 UDFReadFileEA(
3779     IN PVCB Vcb,
3780     IN PDIR_INDEX FileDirNdx,
3781     OUT int8* Buffer
3782     )
3783 {
3784     PFILE_ENTRY FileEntry;
3785     OSSTATUS status;
3786 
3787     if(FileDirNdx->FileInfo) {
3788         FileEntry = (PFILE_ENTRY)(FileDirNdx->FileInfo->Dloc->FileEntry);
3789     } else {
3790         FileEntry = (PFILE_ENTRY)MyAllocatePool__(NonPagedPool, Vcb->BlockSize);
3791         if(!FileEntry) return;
3792         if(!OS_SUCCESS(status = UDFReadFileEntry(Vcb, &(FileDirNdx->FileEntry), FileEntry, &Ident))) {
3793             MyFreePool__(FileEntry);
3794             return status;
3795         }
3796     }
3797 }*/
3798 /*
3799     This dumb routine checks if the file has been found is deleted
3800     It is introduced to make main modules FS-type independent
3801  */
3802 /*BOOLEAN
3803 UDFIsDeleted(
3804     IN PDIR_INDEX DirNdx
3805     )
3806 {
3807     return (DirNdx->FileCharacteristics & FILE_DELETED);
3808 } */
3809 
3810 /*BOOLEAN
3811 UDFIsADirectory(
3812     IN PUDF_FILE_INFO FileInfo
3813     )
3814 {
3815     ValidateFileInfo(FileInfo);
3816 
3817     if(!FileInfo) return FALSE;
3818     if(FileInfo->Dloc->DirIndex) return TRUE;
3819     if(!(FileInfo->FileIdent)) return FALSE;
3820     return (FileInfo->FileIdent->fileCharacteristics & FILE_DIRECTORY);
3821 } */
3822 /*
3823     This routine calculates actual allocation size
3824  */
3825 /*int64
3826 UDFGetFileAllocationSize(
3827     IN PVCB Vcb,
3828     IN PUDF_FILE_INFO FileInfo
3829     )
3830 {
3831     ValidateFileInfo(FileInfo);
3832 
3833     return UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping);// +
3834 //           UDFGetExtentLength(FileInfo->Dloc->FELoc.Mapping) +
3835 //           UDFGetExtentLength(FileInfo->Dloc->AllocLoc.Mapping) - Vcb->BlockSize;
3836 }*/
3837 
3838 /*
3839     This routine checks if the directory is empty
3840  */
3841 BOOLEAN
3842 UDFIsDirEmpty(
3843     IN PDIR_INDEX_HDR hCurDirNdx
3844     )
3845 {
3846     uint32 fc;
3847     uint_di i;
3848     PDIR_INDEX_ITEM CurDirNdx;
3849     // not empty
3850     for(i=2; (CurDirNdx = UDFDirIndex(hCurDirNdx,i)); i++) {
3851         fc = CurDirNdx->FileCharacteristics;
3852         if(!(fc & (FILE_PARENT | FILE_DELETED)) &&
3853            CurDirNdx->Length)
3854             return FALSE;
3855     }
3856     return TRUE;
3857 } // end UDFIsDirEmpty()
3858 
3859 /*
3860  */
3861 OSSTATUS
3862 UDFFlushFE(
3863     IN PVCB Vcb,
3864     IN PUDF_FILE_INFO FileInfo,
3865     IN uint32 PartNum
3866     )
3867 {
3868     int8* NewAllocDescs;
3869     OSSTATUS status;
3870     uint32 WrittenBytes;
3871     uint16 AllocMode;
3872     uint32 lba;
3873 
3874     AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK;
3875 #ifdef UDF_DBG
3876 /*    if(UDFIsADirectory(FileInfo) && (UDFGetFileSize(FileInfo) < 0x28) &&
3877        !UDFIsDeleted(UDFDirIndex(DirInfo->Dloc->DirIndex, FileInfo->Index)) ) {
3878         BrutePoint();
3879     }*/
3880 //    ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3881     if(FileInfo->Dloc->FELoc.Offset) {
3882         BrutePoint();
3883     }
3884     if(FileInfo->Dloc->AllocLoc.Mapping) {
3885         ASSERT(AllocMode != ICB_FLAG_AD_IN_ICB);
3886     }
3887 #endif // UDF_DBG
3888 retry_flush_FE:
3889     UDFPrint(("  FlushFE: %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation));
3890 #ifndef UDF_READ_ONLY_BUILD
3891     UDFReTagDirectory(Vcb, FileInfo);
3892     if(FileInfo->Dloc->DataLoc.Modified ||
3893        FileInfo->Dloc->AllocLoc.Modified) {
3894         ASSERT(PartNum != (uint32)(-1));
3895         // prepare new AllocDescs for flushing...
3896         if(!OS_SUCCESS(status = UDFBuildAllocDescs(Vcb, PartNum, FileInfo, &NewAllocDescs))) {
3897             UDFPrint(("  FlushFE: UDFBuildAllocDescs() faliled (%x)\n", status));
3898             if(NewAllocDescs)
3899                 MyFreePool__(NewAllocDescs);
3900             return status;
3901         }
3902 #ifdef UDF_DBG
3903         if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
3904             ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping));
3905         } else {
3906             ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) ==
3907                    ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)));
3908         }
3909         AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK;
3910 #endif // UDF_DBG
3911         // initiate update of lengthAllocDescs
3912         FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
3913         if(NewAllocDescs) {
3914             ASSERT(AllocMode != ICB_FLAG_AD_IN_ICB);
3915             status = UDFPadLastSector(Vcb, &(FileInfo->Dloc->AllocLoc));
3916             // ... and flush it
3917             status = UDFWriteExtent(Vcb, &(FileInfo->Dloc->AllocLoc), 0, (uint32)(FileInfo->Dloc->AllocLoc.Length), FALSE, NewAllocDescs, &WrittenBytes);
3918             MyFreePool__(NewAllocDescs);
3919             if(!OS_SUCCESS(status)) {
3920                 UDFPrint(("  FlushFE: UDFWriteExtent() faliled (%x)\n", status));
3921                 return status;
3922             }
3923 #ifdef UDF_DBG
3924         } else {
3925             ASSERT(AllocMode == ICB_FLAG_AD_IN_ICB);
3926 #endif // UDF_DBG
3927         }
3928         FileInfo->Dloc->DataLoc.Modified = FALSE;
3929         FileInfo->Dloc->AllocLoc.Modified = FALSE;
3930     } else {
3931 #if defined(UDF_DBG) && !defined(UDF_CHECK_UTIL)
3932         if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
3933             ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping));
3934         } else {
3935             ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) ==
3936                    ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)));
3937         }
3938 #endif // UDF_DBG
3939     }
3940 /*    if(FileInfo->Fcb &&
3941        ((FileInfo->Dloc->FELoc.Mapping[0].extLocation > Vcb->LastLBA) ||
3942         UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) ) {
3943         BrutePoint();
3944     }*/
3945 /*    if(FileInfo->Dloc->FELoc.Mapping[0].extLocation) {
3946         ASSERT( FileInfo->Dloc->FileEntry->tagLocation ==
3947                (FileInfo->Dloc->FELoc.Mapping[0].extLocation - 0x580));
3948     }*/
3949     if((FileInfo->Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) ||
3950         FileInfo->Dloc->FELoc.Modified) {
3951         ASSERT(PartNum != (uint32)(-1));
3952         ASSERT(!PartNum);
3953         if(PartNum == (uint32)(-1) || PartNum == (uint32)(-2)) {
3954             UDFPrint(("  bad PartNum: %d\n", PartNum));
3955         }
3956         // update lengthAllocDescs in FE
3957         UDFSetAllocDescLen(Vcb, FileInfo);
3958 /*        ASSERT( FileInfo->Dloc->FileEntry->tagLocation ==
3959                (FileInfo->Dloc->FELoc.Mapping[0].extLocation - 0x580));*/
3960         // flush FileEntry
3961 
3962         // if FE is located in remapped block, place it to reliable space
3963         lba = FileInfo->Dloc->FELoc.Mapping[0].extLocation;
3964         if(Vcb->BSBM_Bitmap) {
3965             if(UDFGetBadBit((uint32*)(Vcb->BSBM_Bitmap), lba)) {
3966                 AdPrint(("  bad block under FE @%x\n", lba));
3967                 goto relocate_FE;
3968             }
3969         }
3970 
3971         AdPrint(("  setup tag: @%x\n", lba));
3972         ASSERT( lba );
3973         UDFSetUpTag(Vcb, FileInfo->Dloc->FileEntry, (uint16)(FileInfo->Dloc->FileEntryLen),
3974                   UDFPhysLbaToPart(Vcb, PartNum, lba));
3975         status = UDFWriteExtent(Vcb, &(FileInfo->Dloc->FELoc), 0,
3976                   (uint32)(FileInfo->Dloc->FELoc.Length), FALSE,
3977                   (int8*)(FileInfo->Dloc->FileEntry), &WrittenBytes);
3978         if(!OS_SUCCESS(status)) {
3979             UDFPrint(("  FlushFE: UDFWriteExtent(2) faliled (%x)\n", status));
3980             if(status == STATUS_DEVICE_DATA_ERROR) {
3981 relocate_FE:
3982                 UDFPrint(("  try to relocate\n"));
3983 
3984                 EXTENT_INFO _FEExtInfo;
3985                 // calculate the length required
3986 
3987                 // allocate block for FE
3988                 if(OS_SUCCESS(UDFAllocateFESpace(Vcb, FileInfo->ParentFile, PartNum, &_FEExtInfo, (uint32)(FileInfo->Dloc->FELoc.Length)) )) {
3989                     UDFPrint(("  relocate %x -> %x\n",
3990                         lba,
3991                         _FEExtInfo.Mapping[0].extLocation));
3992 
3993                     UDFMarkSpaceAsXXX(Vcb, 0, FileInfo->Dloc->FELoc.Mapping, AS_BAD);
3994 
3995                     UDFRelocateDloc(Vcb, FileInfo->Dloc, _FEExtInfo.Mapping[0].extLocation);
3996                     MyFreePool__(FileInfo->Dloc->FELoc.Mapping);
3997                     FileInfo->Dloc->FELoc.Mapping = _FEExtInfo.Mapping;
3998 
3999                     FileInfo->Dloc->FELoc.Modified = TRUE;
4000                     FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
4001 
4002                     AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK;
4003                     if(AllocMode == ICB_FLAG_AD_IN_ICB) {
4004                         UDFPrint(("  IN-ICB data lost\n"));
4005                         FileInfo->Dloc->DataLoc.Mapping[0].extLocation = _FEExtInfo.Mapping[0].extLocation;
4006                         FileInfo->Dloc->DataLoc.Modified = TRUE;
4007                     } else {
4008                         FileInfo->Dloc->AllocLoc.Mapping[0].extLocation = _FEExtInfo.Mapping[0].extLocation;
4009                         FileInfo->Dloc->AllocLoc.Modified = TRUE;
4010                     }
4011 
4012                     if(FileInfo->Index >= 2) {
4013                         PDIR_INDEX_ITEM DirNdx;
4014                         DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index);
4015                         if(DirNdx) {
4016                             UDFPrint(("  update reference in FI\n"));
4017                             DirNdx->FileEntryLoc.logicalBlockNum =
4018                                 FileInfo->FileIdent->icb.extLocation.logicalBlockNum =
4019                                 UDFPhysLbaToPart(Vcb, PartNum, _FEExtInfo.Mapping[0].extLocation);
4020                             DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
4021                         }
4022                     }
4023                     // this will update
4024                     UDFPrint(("  retry flush...\n"));
4025                     goto retry_flush_FE;
4026                 }
4027             }
4028             BrutePoint();
4029             return status;
4030         }
4031         FileInfo->Dloc->FE_Flags &= ~UDF_FE_FLAG_FE_MODIFIED;
4032         FileInfo->Dloc->FELoc.Modified = FALSE;
4033     } else {
4034         ASSERT((FileInfo->Dloc->FileEntry->descVersion == 2) ||
4035                (FileInfo->Dloc->FileEntry->descVersion == 3));
4036     }
4037 #endif //UDF_READ_ONLY_BUILD
4038 #ifdef UDF_DBG
4039     if(FileInfo->Dloc->AllocLoc.Mapping) {
4040         ASSERT(AllocMode != ICB_FLAG_AD_IN_ICB);
4041     } else {
4042         ASSERT(AllocMode == ICB_FLAG_AD_IN_ICB);
4043     }
4044 #endif // UDF_DBG
4045     return STATUS_SUCCESS;
4046 } // end UDFFlushFE()
4047 
4048 OSSTATUS
4049 UDFFlushFI(
4050     IN PVCB Vcb,
4051     IN PUDF_FILE_INFO FileInfo,
4052     IN uint32 PartNum
4053     )
4054 {
4055     PUDF_FILE_INFO DirInfo = FileInfo->ParentFile;
4056     PDIR_INDEX_ITEM DirNdx;
4057     OSSTATUS status;
4058     uint32 WrittenBytes;
4059     // use WrittenBytes variable to store LBA of FI to be recorded
4060     #define lba   WrittenBytes
4061 
4062 //    ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
4063     // some files has no FI
4064     if(!DirInfo || UDFIsAStreamDir(FileInfo))
4065         return STATUS_SUCCESS;
4066     DirNdx = UDFDirIndex(DirInfo->Dloc->DirIndex, FileInfo->Index);
4067 //    ASSERT(FileInfo->FileIdent->lengthFileIdent < 0x80);
4068 #ifdef UDF_DBG
4069     if(DirNdx->FileCharacteristics & FILE_DELETED) {
4070         ASSERT(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED);
4071     }
4072 #endif // UDF_DBG
4073     UDFPrint(("  FlushFI: offs %x\n", (ULONG)(DirNdx->Offset)));
4074 #ifndef UDF_READ_ONLY_BUILD
4075     if((DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) {
4076         // flush FileIdent
4077         ASSERT(PartNum != (uint32)(-1));
4078         FileInfo->FileIdent->fileCharacteristics = DirNdx->FileCharacteristics;
4079         lba = UDFExtentOffsetToLba(Vcb, DirInfo->Dloc->DataLoc.Mapping,
4080                                         DirNdx->Offset, NULL, NULL, NULL, NULL);
4081         AdPrint(("  FI lba %x\n", lba));
4082         // check if requested Offset is allocated
4083         if(lba == (uint32)LBA_OUT_OF_EXTENT) {
4084             // write 1 byte
4085             if(!OS_SUCCESS(status = UDFWriteFile__(Vcb, DirInfo, DirNdx->Offset, 1, FALSE, (int8*)(FileInfo->FileIdent), &WrittenBytes) )) {
4086                 BrutePoint();
4087                 return status;
4088             }
4089             lba = UDFExtentOffsetToLba(Vcb, DirInfo->Dloc->DataLoc.Mapping,
4090                                             DirNdx->Offset, NULL, NULL, NULL, NULL);
4091             AdPrint(("  allocated FI lba %x\n", lba));
4092             // check if requested Offset is allocated
4093             if(lba == (uint32)LBA_OUT_OF_EXTENT) {
4094                 BrutePoint();
4095                 return STATUS_UNSUCCESSFUL;
4096             }
4097         }
4098         // init structure
4099         UDFSetUpTag(Vcb, &(FileInfo->FileIdent->descTag), (uint16)(FileInfo->FileIdentLen),
4100                   UDFPhysLbaToPart(Vcb, PartNum, lba));
4101         // record data
4102         if(!OS_SUCCESS(status = UDFWriteFile__(Vcb, DirInfo, DirNdx->Offset, FileInfo->FileIdentLen, FALSE, (int8*)(FileInfo->FileIdent), &WrittenBytes) )) {
4103             BrutePoint();
4104             return status;
4105         }
4106         DirNdx->FI_Flags &= ~UDF_FI_FLAG_FI_MODIFIED;
4107     }
4108 #endif //UDF_READ_ONLY_BUILD
4109     return STATUS_SUCCESS;
4110 } // end UDFFlushFI()
4111 
4112 /*
4113     This routine updates AllocDesc sequence, FileIdent & FileEntry
4114     for given file
4115  */
4116 OSSTATUS
4117 UDFFlushFile__(
4118     IN PVCB Vcb,
4119     IN PUDF_FILE_INFO FileInfo,
4120     IN ULONG FlushFlags
4121     )
4122 {
4123     ValidateFileInfo(FileInfo);
4124 
4125     if(!FileInfo) return STATUS_SUCCESS;
4126     OSSTATUS status;
4127     uint32 PartNum;
4128 
4129     ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
4130     PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
4131     if(PartNum == (uint32)-1) {
4132         UDFPrint(("  Is DELETED ?\n"));
4133         if(FileInfo->ParentFile) {
4134             PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->ParentFile->Dloc->FELoc.Mapping[0].extLocation);
4135         } else {
4136             BrutePoint();
4137         }
4138     }
4139 #ifdef UDF_CHECK_DISK_ALLOCATION
4140     if( FileInfo->Fcb &&
4141         UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) {
4142 
4143         if(UDFIsAStreamDir(FileInfo)) {
4144             if(!UDFIsSDirDeleted(FileInfo)) {
4145                 UDFPrint(("  Not DELETED SDir\n"));
4146                 BrutePoint();
4147             }
4148             ASSERT(!FileInfo->Dloc->FELoc.Modified);
4149         } else
4150         if(!FileInfo->FileIdent ||
4151            !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED)) {
4152             if(!FileInfo->FileIdent)
4153                 AdPrint(("  No FileIdent\n"));
4154             if(FileInfo->FileIdent &&
4155                !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED))
4156                 AdPrint(("  Not DELETED\n"));
4157             AdPrint(("Flushing to Discarded block %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation));
4158             BrutePoint();
4159         }
4160     }
4161 #endif // UDF_CHECK_DISK_ALLOCATION
4162 
4163     // flush FE and pre-allocation charge for directories
4164     if(FileInfo->Dloc &&
4165        FileInfo->Dloc->DirIndex) {
4166         // if Lite Flush is used, keep preallocations
4167         if(!(FlushFlags & UDF_FLUSH_FLAGS_LITE)) {
4168 full_flush:
4169             UDFFlushFESpace(Vcb, FileInfo->Dloc);
4170             if(FileInfo->Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) {
4171                 FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_CUT_PREALLOCATED;
4172                 status = UDFResizeExtent(Vcb, PartNum, UDFGetFileSize(FileInfo), FALSE, &(FileInfo->Dloc->DataLoc));
4173                 FileInfo->Dloc->DataLoc.Flags &= ~(EXTENT_FLAG_PREALLOCATED | EXTENT_FLAG_CUT_PREALLOCATED);
4174                 if(OS_SUCCESS(status)) {
4175                     AdPrint(("Dir pre-alloc truncated (Flush)\n"));
4176                     FileInfo->Dloc->DataLoc.Modified = TRUE;
4177                 }
4178             }
4179         }
4180     }
4181     // flush FE
4182     if(!OS_SUCCESS(status = UDFFlushFE(Vcb, FileInfo, PartNum))) {
4183         UDFPrint(("Error flushing FE\n"));
4184         BrutePoint();
4185         if(FlushFlags & UDF_FLUSH_FLAGS_LITE) {
4186             UDFPrint(("  flush pre-alloc\n"));
4187             FlushFlags &= ~UDF_FLUSH_FLAGS_LITE;
4188             goto full_flush;
4189         }
4190         if(FileInfo->Index >= 2) {
4191             PDIR_INDEX_ITEM DirNdx;
4192             DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index);
4193             if(DirNdx) {
4194                 UDFPrint(("Recovery: mark as deleted & flush FI\n"));
4195                 DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
4196                 DirNdx->FileCharacteristics |= FILE_DELETED;
4197                 FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED;
4198                 UDFFlushFI(Vcb, FileInfo, PartNum);
4199             }
4200         }
4201         return status;
4202     }
4203     if(!OS_SUCCESS(status = UDFFlushFI(Vcb, FileInfo, PartNum)))
4204         return status;
4205 
4206     ASSERT((FileInfo->Dloc->FileEntry->descVersion == 2) ||
4207            (FileInfo->Dloc->FileEntry->descVersion == 3));
4208 
4209     return STATUS_SUCCESS;
4210 } // end UDFFlushFile__()
4211 
4212 /*
4213     This routine compares 2 FileInfo structures
4214  */
4215 BOOLEAN
4216 UDFCompareFileInfo(
4217     IN PUDF_FILE_INFO f1,
4218     IN PUDF_FILE_INFO f2
4219     )
4220 {
4221     uint_di i;
4222     PDIR_INDEX_HDR hDirIndex1;
4223     PDIR_INDEX_HDR hDirIndex2;
4224     PDIR_INDEX_ITEM DirIndex1;
4225     PDIR_INDEX_ITEM DirIndex2;
4226 
4227     if(!f1 || !f2) return FALSE;
4228     if(f1->Dloc->FileEntryLen != f2->Dloc->FileEntryLen) return FALSE;
4229 //    if(f1->FileIdentLen != f2->FileIdentLen) return FALSE;
4230 /*    if(f1->Dloc->DirIndex && !f2->Dloc->DirIndex) return FALSE;
4231     if(f2->Dloc->DirIndex && !f1->Dloc->DirIndex) return FALSE;
4232     if((f1->Dloc->DirIndex) &&
4233        (f1->Dloc->DirIndex->LastFrameCount != f2->Dloc->DirIndex->LastFrameCount)) return FALSE;*/
4234     if(f1->Index != f2->Index) return FALSE;
4235     if(!(f1->Dloc->DataLoc.Mapping)) return FALSE;
4236     if(!(f2->Dloc->DataLoc.Mapping)) return FALSE;
4237     if(f1->Dloc->DataLoc.Mapping[0].extLocation != f2->Dloc->DataLoc.Mapping[0].extLocation) return FALSE;
4238     if(f1->Dloc->DataLoc.Mapping[0].extLength != f2->Dloc->DataLoc.Mapping[0].extLength) return FALSE;
4239 //    if(f1-> != f2->) return FALSE;
4240 //    if(f1-> != f2->) return FALSE;
4241 //    if(f1-> != f2->) return FALSE;
4242     if(!(f1->Dloc->FileEntry)) return FALSE;
4243     if(!(f2->Dloc->FileEntry)) return FALSE;
4244     if(RtlCompareMemory(f1->Dloc->FileEntry, f2->Dloc->FileEntry, f2->Dloc->FileEntryLen) != f2->Dloc->FileEntryLen)
4245         return FALSE;
4246     if(!(hDirIndex1 = f1->Dloc->DirIndex)) return FALSE;
4247     if(!(hDirIndex2 = f2->Dloc->DirIndex)) return FALSE;
4248 
4249     for(i=2; (DirIndex1 = UDFDirIndex(hDirIndex1,i)) &&
4250              (DirIndex2 = UDFDirIndex(hDirIndex2,i)); i++) {
4251         if( DirIndex1->FName.Buffer &&
4252            !DirIndex2->FName.Buffer)
4253             return FALSE;
4254         if( DirIndex2->FName.Buffer &&
4255            !DirIndex1->FName.Buffer)
4256             return FALSE;
4257         if(!DirIndex2->FName.Buffer &&
4258            !DirIndex1->FName.Buffer)
4259             continue;
4260         if(RtlCompareUnicodeString(&(DirIndex1->FName),
4261                                    &(DirIndex2->FName),FALSE)) {
4262             return FALSE;
4263         }
4264 //        if(DirIndex1[i].FileEntry != DirIndex2[i].FileEntry)
4265 //            return FALSE;
4266         if(RtlCompareMemory(&(DirIndex1->FileEntryLoc),
4267                             &(DirIndex2->FileEntryLoc), sizeof(lb_addr)) != sizeof(lb_addr))
4268             return FALSE;
4269     }
4270 
4271     return TRUE;
4272 } // end UDFCompareFileInfo()
4273 
4274 /*
4275     This routine computes 32-bit hash based on CRC-32 from SSH
4276  */
4277 
4278 #ifdef _MSC_VER
4279 #pragma warning(push)
4280 #pragma warning(disable:4035)               // re-enable below
4281 #endif
4282 
4283 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
4284 __declspec (naked)
4285 #endif // _X86_
4286 uint32
4287 __fastcall
4288 crc32(
4289     IN uint8* s,  // ECX
4290     IN uint32 len // EDX
4291     )
4292 {
4293 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
4294 //    uint32 _Size = len;
4295 
4296     __asm {
4297         push  ebx
4298         push  ecx
4299         push  edx
4300         push  esi
4301 
4302         xor   eax,eax
4303         mov   esi,ecx  // ESI <- s
4304         mov   ecx,edx  // ECX <- len
4305 
4306         jecxz EO_CRC
4307 
4308         lea   ebx,[crc32_tab]
4309         xor   edx,edx
4310 
4311 CRC_loop:
4312 
4313         mov   dl,al
4314         xor   dl,[esi]
4315         shr   eax,8
4316         xor   eax,[dword ptr ebx+edx*4]
4317         inc   esi
4318         loop  CRC_loop
4319 
4320 EO_CRC:
4321 
4322         pop   esi
4323         pop   edx
4324         pop   ecx
4325         pop   ebx
4326 
4327         ret
4328     }
4329 #else  // NO X86 optimization , use generic C/C++
4330     uint32 i;
4331     uint32 crc32val = 0;
4332 
4333     for(i=0; i<len; i++, s++) {
4334         crc32val =
4335             crc32_tab[(crc32val ^ (*s)) & 0xff] ^ (crc32val >> 8);
4336     }
4337     return crc32val;
4338 #endif // _X86_
4339 } // end crc32()
4340 
4341 /*
4342     Calculate a 16-bit CRC checksum for unicode strings
4343     using ITU-T V.41 polynomial.
4344 
4345     The OSTA-UDF(tm) 1.50 standard states that using CRCs is mandatory.
4346     The polynomial used is: x^16 + x^12 + x^15 + 1
4347 */
4348 
4349 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
4350 __declspec (naked)
4351 #endif // _X86_
4352 uint16
4353 __fastcall
4354 UDFUnicodeCksum(
4355     PWCHAR s, // ECX
4356     uint32 n  // EDX
4357     )
4358 {
4359 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
4360 //    uint32 _Size = n;
4361 
4362     __asm {
4363         push  ebx
4364         push  ecx
4365         push  edx
4366         push  esi
4367 
4368         xor   eax,eax
4369         mov   esi,ecx
4370         mov   ecx,edx
4371 
4372         jecxz EO_uCRC
4373 
4374         lea   ebx,[CrcTable]
4375         xor   edx,edx
4376 
4377 uCRC_loop:
4378 
4379         mov   dl,ah            // dl = (Crc >> 8)
4380         xor   dl,[esi+1]       // dl = ((Crc >> 8) ^ (*s >> 8)) & 0xff
4381         mov   ah,al
4382         mov   al,dh            // ax = (Crc << 8)
4383         xor   ax,[word ptr ebx+edx*2]  // ax = ...........
4384 
4385         mov   dl,ah
4386         xor   dl,[esi]
4387         mov   ah,al
4388         mov   al,dh
4389         xor   ax,[word ptr ebx+edx*2]
4390 
4391         inc   esi
4392         inc   esi
4393         loop  uCRC_loop
4394 
4395 EO_uCRC:
4396 
4397         pop   esi
4398         pop   edx
4399         pop   ecx
4400         pop   ebx
4401 
4402         ret
4403     }
4404 #else  // NO X86 optimization , use generic C/C++
4405     uint16 Crc = 0;
4406     while (n--) {
4407         Crc = CrcTable[(Crc >> 8 ^ (*s >> 8)) & 0xff] ^ (Crc << 8);
4408         Crc = CrcTable[(Crc >> 8 ^ (*s++ & 0xff)) & 0xff] ^ (Crc << 8);
4409     }
4410     return Crc;
4411 
4412 #endif // _X86_
4413 } // end UDFUnicodeCksum()
4414 
4415 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
4416 __declspec (naked)
4417 #endif // _X86_
4418 uint16
4419 __fastcall
4420 UDFUnicodeCksum150(
4421     PWCHAR s, // ECX
4422     uint32 n  // EDX
4423     )
4424 {
4425 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
4426 //    uint32 _Size = n;
4427 
4428     __asm {
4429         push  ebx
4430         push  ecx
4431         push  edx
4432         push  esi
4433         push  edi
4434 
4435         xor   eax,eax
4436         mov   esi,ecx
4437         mov   ecx,edx
4438         xor   edi,edi
4439 
4440         jecxz EO_uCRC
4441 
4442         //lea   ebx,[CrcTable]
4443         xor   edx,edx
4444         xor   ebx,ebx
4445 
4446 uCRC_loop:
4447 
4448         mov   dl,ah            // dl = (Crc >> 8)
4449         or    edi,edx          // if(*s & 0xff00) Use16 = TRUE;
4450         xor   dl,[esi+1]       // dl = ((Crc >> 8) ^ (*s >> 8)) & 0xff
4451         mov   ah,al
4452         mov   al,0             // ax = (Crc << 8)
4453         xor   ax,[word ptr CrcTable+edx*2]  // ax = ...........
4454 
4455         mov   dl,ah
4456         xor   dl,[esi]
4457         mov   ah,al
4458         mov   al,0
4459         xor   ax,[word ptr CrcTable+edx*2]
4460 
4461         or    edi,edi          // if(!Use16) {
4462         jnz   use16_1
4463 
4464         rol   eax,16
4465 
4466         mov   bl,ah            // dl = (Crc >> 8)
4467         xor   bl,[esi]         // dl = ((Crc >> 8) ^ (*s >> 8)) & 0xff
4468         mov   ah,al
4469         mov   al,0             // ax = (Crc << 8)
4470         xor   ax,[word ptr CrcTable+ebx*2]  // ax = ...........
4471 
4472         rol   eax,16
4473 use16_1:
4474         inc   esi
4475         inc   esi
4476         loop  uCRC_loop
4477 
4478 EO_uCRC:
4479 
4480         or    edi,edi          // if(!Use16) {
4481         jnz   use16_2
4482 
4483         rol   eax,16           // }
4484 use16_2:
4485         and   eax,0xffff
4486 
4487         pop   edi
4488         pop   esi
4489         pop   edx
4490         pop   ecx
4491         pop   ebx
4492 
4493         ret
4494     }
4495 #else  // NO X86 optimization , use generic C/C++
4496     uint16 Crc = 0;
4497     uint16 Crc2 = 0;
4498     BOOLEAN Use16 = FALSE;
4499     while (n--) {
4500         if(!Use16) {
4501             if((*s) & 0xff00) {
4502                 Use16 = TRUE;
4503             } else {
4504                 Crc2 = CrcTable[(Crc2 >> 8 ^ (*s >> 8)) & 0xff] ^ (Crc2 << 8);
4505             }
4506         }
4507         Crc = CrcTable[(Crc >> 8 ^ (*s >> 8)) & 0xff] ^ (Crc << 8);
4508         Crc = CrcTable[(Crc >> 8 ^ (*s++ & 0xff)) & 0xff] ^ (Crc << 8);
4509     }
4510     return Use16 ? Crc : Crc2;
4511 #endif // _X86_
4512 } // end UDFUnicodeCksum150()
4513 
4514 /*
4515     Calculate a 16-bit CRC checksum using ITU-T V.41 polynomial.
4516 
4517     The OSTA-UDF(tm) 1.50 standard states that using CRCs is mandatory.
4518     The polynomial used is: x^16 + x^12 + x^15 + 1
4519 */
4520 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
4521 __declspec (naked)
4522 #endif // _X86_
4523 uint16
4524 __fastcall
4525 UDFCrc(
4526     IN uint8* Data, // ECX
4527     IN uint32 Size  // EDX
4528     )
4529 {
4530 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
4531 //    uint32 _Size = Size;
4532 
4533     __asm {
4534         push  ebx
4535         push  ecx
4536         push  edx
4537         push  esi
4538 
4539         mov   esi,ecx
4540         mov   ecx,edx
4541         xor   eax,eax
4542 
4543         jecxz EO_CRC
4544 
4545         lea   ebx,[CrcTable]
4546         xor   edx,edx
4547 
4548 CRC_loop:
4549 
4550         mov   dl,ah
4551         xor   dl,[esi]
4552         mov   ah,al
4553         mov   al,dh
4554         xor   ax,[word ptr ebx+edx*2]
4555         inc   esi
4556         loop  CRC_loop
4557 
4558 EO_CRC:
4559 
4560         pop   esi
4561         pop   edx
4562         pop   ecx
4563         pop   ebx
4564 
4565         ret
4566     }
4567 #else  // NO X86 optimization , use generic C/C++
4568     uint16 Crc = 0;
4569     while (Size--)
4570         Crc = CrcTable[(Crc >> 8 ^ *Data++) & 0xff] ^ (Crc << 8);
4571     return Crc;
4572 #endif // _X86_
4573 
4574 } // end UDFCrc()
4575 
4576 #ifdef _MSC_VER
4577 #pragma warning(pop)    // re-enable warning #4035
4578 #endif
4579 
4580 /*
4581     Read the first block of a tagged descriptor & check it.
4582 */
4583 OSSTATUS
4584 UDFReadTagged(
4585     PVCB Vcb,
4586     int8* Buf,
4587     uint32 Block,
4588     uint32 Location,
4589     uint16 *Ident
4590     )
4591 {
4592     OSSTATUS RC;
4593     tag* PTag = (tag*)Buf;
4594 //    icbtag* Icb = (icbtag*)(Buf+1);
4595     uint8 checksum;
4596     unsigned int i;
4597     uint32 ReadBytes;
4598     int8* tb;
4599 
4600     // Read the block
4601     if(Block == 0xFFFFFFFF)
4602         return NULL;
4603 
4604     _SEH2_TRY {
4605         RC = UDFReadSectors(Vcb, FALSE, Block, 1, FALSE, Buf, &ReadBytes);
4606         if(!OS_SUCCESS(RC)) {
4607             UDFPrint(("UDF: Block=%x, Location=%x: read failed\n", Block, Location));
4608             try_return(RC);
4609         }
4610 
4611         *Ident = PTag->tagIdent;
4612 
4613         if(Location != PTag->tagLocation) {
4614             UDFPrint(("UDF: location mismatch block %x, tag %x != %x\n",
4615                 Block, PTag->tagLocation, Location));
4616             try_return(RC = STATUS_FILE_CORRUPT_ERROR);
4617         }
4618 
4619         /* Verify the tag checksum */
4620         checksum = 0;
4621         tb = Buf;
4622         for (i=0; i<sizeof(tag); i++, tb++)
4623             checksum += (uint8)((i!=4) ? (*tb) : 0);
4624 
4625         if(checksum != PTag->tagChecksum) {
4626             UDFPrint(("UDF: tag checksum failed block %x\n", Block));
4627             try_return(RC = STATUS_CRC_ERROR);
4628         }
4629 
4630         // Verify the tag version
4631         if((PTag->descVersion != 2) &&
4632            (PTag->descVersion != 3)) {
4633             UDFPrint(("UDF: Tag version 0x%04x != 0x0002 || 0x0003 block %x\n",
4634                 (PTag->descVersion), Block));
4635             try_return(RC = STATUS_FILE_CORRUPT_ERROR);
4636         }
4637 
4638         // Verify the descriptor CRC
4639         if(((PTag->descCRCLength) + sizeof(tag) > Vcb->BlockSize) ||
4640            ((PTag->descCRC) == UDFCrc((uint8*)Buf + sizeof(tag), PTag->descCRCLength)) ||
4641            !(PTag->descCRC) ) {
4642     /*        UDFPrint(("Tag ID: %x, ver %x\t", PTag->tagIdent, PTag->descVersion ));
4643             if((i == TID_FILE_ENTRY) ||
4644                (i == TID_EXTENDED_FILE_ENTRY)) {
4645                 UDFPrint(("StrategType: %x, ", Icb->strategyType ));
4646                 UDFPrint(("FileType: %x\t", Icb->fileType ));
4647             }
4648             UDFPrint(("\n"));*/
4649             try_return(RC = STATUS_SUCCESS);
4650         }
4651         UDFPrint(("UDF: Crc failure block %x: crc = %x, crclen = %x\n",
4652             Block, PTag->descCRC, PTag->descCRCLength));
4653         RC = STATUS_CRC_ERROR;
4654 
4655 try_exit:    NOTHING;
4656 
4657     } _SEH2_FINALLY {
4658         ;
4659     } _SEH2_END
4660 
4661     return RC;
4662 } // end UDFReadTagged()
4663 
4664 #ifndef UDF_READ_ONLY_BUILD
4665 /*
4666     This routine creates hard link for the file from DirInfo1
4667     to DirInfo2 & names it as fn
4668  */
4669 OSSTATUS
4670 UDFHardLinkFile__(
4671     IN PVCB Vcb,
4672     IN BOOLEAN IgnoreCase,
4673  IN OUT BOOLEAN* Replace,        // replace if destination file exists
4674     IN PUNICODE_STRING fn,       // destination
4675  IN OUT PUDF_FILE_INFO DirInfo1,
4676  IN OUT PUDF_FILE_INFO DirInfo2,
4677  IN OUT PUDF_FILE_INFO FileInfo  // source (opened)
4678     )
4679 {
4680     PUDF_FILE_INFO FileInfo2;
4681     OSSTATUS status;
4682     PDIR_INDEX_ITEM DirNdx1;
4683     PDIR_INDEX_ITEM DirNdx2;
4684     uint_di i;
4685     BOOLEAN Recovery = FALSE;
4686     BOOLEAN SameFE = FALSE;
4687     uint32 NTAttr = 0;
4688 
4689     // validate FileInfo
4690     ValidateFileInfo(DirInfo1);
4691     ValidateFileInfo(DirInfo2);
4692     ValidateFileInfo(FileInfo);
4693 
4694     if(UDFGetFileLinkCount(FileInfo) >= UDF_MAX_LINK_COUNT) {
4695         // too many links to file...
4696         return STATUS_TOO_MANY_LINKS;
4697     }
4698 
4699     i = 0;
4700     if(DirInfo1 == DirInfo2) {
4701         if(OS_SUCCESS(status = UDFFindFile(Vcb, IgnoreCase, TRUE, fn, DirInfo2, &i)) &&
4702            (i==FileInfo->Index) ) {
4703             // case-only difference
4704             return STATUS_OBJECT_NAME_COLLISION;
4705         }
4706     }
4707 
4708     // PHASE 0
4709     // try to create new FileIdent & FileEntry in Dir2
4710 
4711 HLinkRetry:
4712     if(!OS_SUCCESS(status = UDFCreateFile__(Vcb, IgnoreCase, fn, UDFGetFileEALength(FileInfo),
4713                     0, (FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY),
4714                     TRUE, DirInfo2, &FileInfo2))) {
4715         if(UDFCleanUpFile__(Vcb, FileInfo2) && FileInfo2)
4716             MyFreePool__(FileInfo2);
4717         if(status == STATUS_ACCESS_DENIED) {
4718             // try to recover >;->
4719             if((*Replace) && !Recovery) {
4720                 Recovery = TRUE;
4721                 status = UDFOpenFile__(Vcb, IgnoreCase, TRUE, fn, DirInfo2, &FileInfo2, NULL);
4722                 if(OS_SUCCESS(status)) {
4723                     status = UDFDoesOSAllowFileToBeTargetForHLink__(FileInfo2);
4724                     if(!OS_SUCCESS(status)) {
4725                         UDFCloseFile__(Vcb, FileInfo2);
4726                         goto cleanup_and_abort_hlink;
4727                     }
4728                     if((FileInfo->Dloc == FileInfo2->Dloc)  &&
4729                        (FileInfo != FileInfo2)) {
4730                         SameFE = TRUE;
4731                         // 'status' is already STATUS_SUCCESS here
4732                     } else {
4733                         status = UDFUnlinkFile__(Vcb, FileInfo2, TRUE);
4734                     }
4735                     UDFCloseFile__(Vcb, FileInfo2);
4736                     if(UDFCleanUpFile__(Vcb, FileInfo2)) {
4737                         MyFreePool__(FileInfo2);
4738                         FileInfo2 = NULL;
4739                         if(SameFE)
4740                             return STATUS_SUCCESS;
4741                     } else {
4742                         // we get here if the FileInfo has associated
4743                         // system-specific Fcb
4744                         // Such fact means that not all system references
4745                         // has already gone (except Linked file case)
4746                         if(SameFE)
4747                             return STATUS_SUCCESS;
4748                         if(!OS_SUCCESS(status) ||
4749                            (UDFGetFileLinkCount(FileInfo) < 1))
4750                             status = STATUS_ACCESS_DENIED;
4751                     }
4752                     if(OS_SUCCESS(status)) goto HLinkRetry;
4753                 }
4754 cleanup_and_abort_hlink:
4755                 if(FileInfo2 && UDFCleanUpFile__(Vcb, FileInfo2)) {
4756                     MyFreePool__(FileInfo2);
4757                     FileInfo2 = NULL;
4758                 }
4759             } else {
4760                 status = STATUS_OBJECT_NAME_COLLISION;
4761             }
4762         }
4763         return status;
4764     }
4765     // update pointers
4766     DirNdx1 = UDFDirIndex(DirInfo1->Dloc->DirIndex, FileInfo->Index);
4767     DirNdx2 = UDFDirIndex(DirInfo2->Dloc->DirIndex, FileInfo2->Index);
4768 
4769     // copy file attributes to newly created FileIdent
4770     NTAttr = UDFAttributesToNT(DirNdx1, FileInfo->Dloc->FileEntry);
4771     FileInfo2->FileIdent->fileVersionNum = FileInfo->FileIdent->fileVersionNum;
4772 
4773     // PHASE 1
4774     // copy all necessary info from FileInfo to FileInfo2
4775 
4776     FileInfo2->FileIdent->icb = FileInfo->FileIdent->icb;
4777     FileInfo2->FileIdent->fileCharacteristics = FileInfo->FileIdent->fileCharacteristics;
4778     FileInfo2->FileIdent->fileVersionNum = FileInfo->FileIdent->fileVersionNum;
4779 
4780     DirNdx2->FileCharacteristics = DirNdx1->FileCharacteristics & ~FILE_DELETED;
4781     DirNdx2->FileEntryLoc = DirNdx1->FileEntryLoc;
4782     DirNdx2->FI_Flags = (DirNdx1->FI_Flags & ~UDF_FI_FLAG_SYS_ATTR) | UDF_FI_FLAG_FI_MODIFIED | UDF_FI_FLAG_LINKED;
4783 
4784     UDFAttributesToUDF(DirNdx2, FileInfo2->Dloc->FileEntry, NTAttr);
4785 
4786     // PHASE 2
4787     // update FileInfo
4788 
4789     FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
4790     DirNdx1->FI_Flags = DirNdx2->FI_Flags;
4791     UDFIncFileLinkCount(FileInfo); // increase to 1
4792 //    UDFUpdateModifyTime(Vcb, FileInfo);
4793     FileInfo->Dloc->LinkRefCount += FileInfo2->Dloc->LinkRefCount;
4794     if(FileInfo2->FileIdent)
4795         ((FidADImpUse*)&(FileInfo2->FileIdent->icb.impUse))->uniqueID = (uint32)UDFAssingNewFUID(Vcb);
4796 
4797     // PHASE 3
4798     // drop all unnecessary info from FileInfo2
4799 
4800     UDFFreeFESpace(Vcb, DirInfo2, &(FileInfo2->Dloc->FELoc));
4801     UDFRemoveDloc(Vcb, FileInfo2->Dloc);
4802 
4803     // PHASE 4
4804     // perform in-memory linkage (update driver's tree structures) and flush
4805 
4806     FileInfo2->Dloc = FileInfo->Dloc;
4807     UDFInsertLinkedFile(FileInfo2, FileInfo);
4808 
4809     UDFCloseFile__(Vcb, FileInfo2);
4810     if(UDFCleanUpFile__(Vcb, FileInfo2)) {
4811         MyFreePool__(FileInfo2);
4812     }
4813     // return 'delete target' status
4814     (*Replace) = Recovery;
4815 
4816     return STATUS_SUCCESS;
4817 } // end UDFHardLinkFile__()
4818 
4819 /*
4820     This routine allocates FileEntry with in-ICB zero-sized data
4821     If it returns status != STATUS_SUCCESS caller should call UDFCleanUpFile__
4822     for returned pointer *WITHOUT* using UDFCloseFile__
4823  */
4824 OSSTATUS
4825 UDFCreateRootFile__(
4826     IN PVCB Vcb,
4827 //    IN uint16 AllocMode, // short/long/ext/in-icb  // always in-ICB
4828     IN uint32 PartNum,
4829     IN uint32 ExtAttrSz,
4830     IN uint32 ImpUseLen,
4831     IN BOOLEAN Extended,
4832     OUT PUDF_FILE_INFO* _FileInfo
4833     )
4834 {
4835     OSSTATUS status;
4836     LONG_AD FEicb;
4837     PUDF_FILE_INFO FileInfo;
4838     *_FileInfo = NULL;
4839     uint32 ReadBytes;
4840 
4841     FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_FINF_TAG);
4842     *_FileInfo = FileInfo;
4843     if(!FileInfo)
4844         return STATUS_INSUFFICIENT_RESOURCES;
4845     ImpUseLen = (ImpUseLen + 3) & ~((uint16)3);
4846 
4847     RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO));
4848     // init horizontal links
4849     FileInfo->NextLinkedFile =
4850     FileInfo->PrevLinkedFile = FileInfo;
4851     // allocate space for FileEntry
4852     if(!OS_SUCCESS(status =
4853         UDFBuildFileEntry(Vcb, NULL, FileInfo, PartNum, ICB_FLAG_AD_IN_ICB, ExtAttrSz, Extended) ))
4854         return status;
4855     FEicb.extLength = Vcb->LBlockSize;
4856     FEicb.extLocation.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
4857     FEicb.extLocation.partitionReferenceNum = (uint16)PartNum;
4858     RtlZeroMemory(&(FEicb.impUse), sizeof(FEicb.impUse));
4859 
4860     FileInfo->Dloc->DataLoc.Mapping = UDFExtentToMapping(&(FileInfo->Dloc->FELoc.Mapping[0]));
4861     if(!(FileInfo->Dloc->DataLoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES;
4862     FileInfo->Dloc->DataLoc.Length = 0;
4863     FileInfo->Dloc->DataLoc.Offset = FileInfo->Dloc->FileEntryLen;
4864     // init FileEntry
4865     UDFSetFileUID(Vcb, FileInfo);
4866     UDFSetFileSize(FileInfo, 0);
4867     UDFIncFileLinkCount(FileInfo); // increase to 1
4868     UDFUpdateCreateTime(Vcb, FileInfo);
4869     // zero sector for FileEntry
4870     FileInfo->Dloc->DataLoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK;
4871     FileInfo->Dloc->FELoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK;
4872     status = UDFWriteData(Vcb, TRUE, ((int64)(FileInfo->Dloc->FELoc.Mapping[0].extLocation)) << Vcb->BlockSizeBits, Vcb->LBlockSize, FALSE, Vcb->ZBuffer, &ReadBytes);
4873     if(!OS_SUCCESS(status))
4874         return status;
4875 
4876     UDFReferenceFile__(FileInfo);
4877     UDFReleaseDloc(Vcb, FileInfo->Dloc);
4878     return STATUS_SUCCESS;
4879 } // end UDFCreateRootFile__()
4880 
4881 /*
4882     This routine tries to create StreamDirectory associated with given file
4883     Caller should use UDFCleanUpFile__ if returned status != STATUS_SUCCESS
4884  */
4885 OSSTATUS
4886 UDFCreateStreamDir__(
4887     IN PVCB Vcb,
4888     IN PUDF_FILE_INFO FileInfo,    // file containing stream-dir
4889     OUT PUDF_FILE_INFO* _SDirInfo  // this is to be filled & doesn't contain
4890                                    // any pointers
4891     )
4892 {
4893     OSSTATUS status;
4894     PUDF_FILE_INFO SDirInfo;
4895     uint16 Ident;
4896 
4897     *_SDirInfo = NULL;
4898     ValidateFileInfo(FileInfo);
4899     // check currently recorded UDF revision
4900     if(!UDFStreamsSupported(Vcb))
4901         return STATUS_INVALID_PARAMETER;
4902     // check if we are allowed to associate Stream Dir with this file
4903     if((FileInfo->ParentFile && UDFIsAStreamDir(FileInfo->ParentFile)) ||
4904         UDFHasAStreamDir(FileInfo))
4905         return STATUS_FILE_DELETED;
4906     // check if we have Deleted SDir
4907     if(FileInfo->Dloc->SDirInfo &&
4908        UDFIsSDirDeleted(FileInfo->Dloc->SDirInfo))
4909         return STATUS_ACCESS_DENIED;
4910     // check if this file has ExtendedFileEntry
4911     if((Ident = FileInfo->Dloc->FileEntry->tagIdent) != TID_EXTENDED_FILE_ENTRY) {
4912         if(!OS_SUCCESS(status = UDFConvertFEToExtended(Vcb, FileInfo)))
4913             return status;
4914     }
4915 
4916     uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
4917     // create stream directory file
4918     if(!OS_SUCCESS(status = UDFCreateRootFile__(Vcb, PartNum, 0,0,FALSE, &SDirInfo)))
4919         return status;
4920     // link objects
4921     SDirInfo->ParentFile = FileInfo;
4922     // record directory structure
4923     SDirInfo->Dloc->FE_Flags |= (UDF_FE_FLAG_FE_MODIFIED | UDF_FE_FLAG_IS_SDIR);
4924 
4925     FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_HAS_SDIR;
4926     UDFIncFileLinkCount(FileInfo);
4927     FileInfo->Dloc->FE_Flags &= ~UDF_FE_FLAG_HAS_SDIR;
4928 
4929     status = UDFRecordDirectory__(Vcb, SDirInfo);
4930     UDFDecDirCounter(Vcb);
4931 
4932     UDFInterlockedIncrement((PLONG)&(FileInfo->OpenCount));
4933     if(!OS_SUCCESS(status)) {
4934         UDFUnlinkFile__(Vcb, SDirInfo, TRUE);
4935         UDFCloseFile__(Vcb, SDirInfo);
4936         UDFCleanUpFile__(Vcb, SDirInfo);
4937         MyFreePool__(SDirInfo);
4938         ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLength = 0;
4939         ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation.partitionReferenceNum = 0;
4940         ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation.logicalBlockNum = 0;
4941         return status;
4942     }
4943     *_SDirInfo = SDirInfo;
4944     // do some init
4945     ((PEXTENDED_FILE_ENTRY)(SDirInfo->Dloc->FileEntry))->icbTag.fileType = UDF_FILE_TYPE_STREAMDIR;
4946     ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLength = Vcb->LBlockSize;
4947     ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation.partitionReferenceNum = (uint16)PartNum;
4948     ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation.logicalBlockNum =
4949         UDFPhysLbaToPart(Vcb, PartNum, SDirInfo->Dloc->FELoc.Mapping[0].extLocation);
4950     ((PEXTENDED_FILE_ENTRY)(SDirInfo->Dloc->FileEntry))->uniqueID =
4951         ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->uniqueID;
4952     FileInfo->Dloc->FE_Flags |= (UDF_FE_FLAG_FE_MODIFIED | UDF_FE_FLAG_HAS_SDIR);
4953     // open & finalize linkage
4954     FileInfo->Dloc->SDirInfo = SDirInfo;
4955     return STATUS_SUCCESS;
4956 } // end UDFCreateStreamDir__()
4957 #endif //UDF_READ_ONLY_BUILD
4958 
4959 /*
4960     This routine opens Stream Directory associated with file specified
4961  */
4962 OSSTATUS
4963 UDFOpenStreamDir__(
4964     IN PVCB Vcb,
4965     IN PUDF_FILE_INFO FileInfo,    // file containing stream-dir
4966     OUT PUDF_FILE_INFO* _SDirInfo  // this is to be filled & doesn't contain
4967                                    // any pointers
4968     )
4969 {
4970     OSSTATUS status;
4971     PUDF_FILE_INFO SDirInfo;
4972     PUDF_FILE_INFO ParSDirInfo;
4973     uint16 Ident;
4974 
4975     *_SDirInfo = NULL;
4976     ValidateFileInfo(FileInfo);
4977     // check if this file has ExtendedFileEntry
4978     if((Ident = FileInfo->Dloc->FileEntry->tagIdent) != TID_EXTENDED_FILE_ENTRY) {
4979         return STATUS_NOT_FOUND;
4980     }
4981     if((SDirInfo = FileInfo->Dloc->SDirInfo)) {
4982         // it is already opened. Good...
4983 
4984         // check if we have Deleted SDir
4985         if(FileInfo->Dloc->SDirInfo &&
4986            UDFIsSDirDeleted(FileInfo->Dloc->SDirInfo))
4987             return STATUS_FILE_DELETED;
4988         // All right. Look for parallel SDir (if any)
4989         if(SDirInfo->ParentFile != FileInfo) {
4990             ParSDirInfo = UDFLocateParallelFI(FileInfo, 0, SDirInfo);
4991             BrutePoint();
4992             if(ParSDirInfo->ParentFile != FileInfo) {
4993                 SDirInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_SDFINF_TAG);
4994                 *_SDirInfo = SDirInfo;
4995                 if(!SDirInfo) return STATUS_INSUFFICIENT_RESOURCES;
4996                 RtlCopyMemory(SDirInfo, FileInfo->Dloc->SDirInfo, sizeof(UDF_FILE_INFO));
4997     //          SDirInfo->NextLinkedFile = FileInfo->Dloc->SDirInfo->NextLinkedFile; // is already done
4998                 UDFInsertLinkedFile(SDirInfo, FileInfo->Dloc->SDirInfo);
4999                 SDirInfo->RefCount = 0;
5000                 SDirInfo->ParentFile = FileInfo;
5001                 SDirInfo->Fcb = NULL;
5002             } else {
5003                 SDirInfo = ParSDirInfo;
5004             }
5005         }
5006         UDFReferenceFile__(SDirInfo);
5007         *_SDirInfo = SDirInfo;
5008         return STATUS_SUCCESS;
5009     }
5010     // normal open
5011     if(!((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLength)
5012         return STATUS_NOT_FOUND;
5013     SDirInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_SDFINF_TAG);
5014     if(!SDirInfo) return STATUS_INSUFFICIENT_RESOURCES;
5015     *_SDirInfo = SDirInfo;
5016     status = UDFOpenRootFile__(Vcb, &(((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation) ,SDirInfo);
5017     if(!OS_SUCCESS(status)) return status;
5018     // open & finalize linkage
5019     FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_HAS_SDIR;
5020     SDirInfo->Dloc->FE_Flags |= UDF_FE_FLAG_IS_SDIR;
5021     FileInfo->Dloc->SDirInfo = SDirInfo;
5022     SDirInfo->ParentFile = FileInfo;
5023 
5024     UDFInterlockedIncrement((PLONG)&(FileInfo->OpenCount));
5025 
5026     return STATUS_SUCCESS;
5027 } // end UDFOpenStreamDir__()
5028 
5029 #ifndef UDF_READ_ONLY_BUILD
5030 /*
5031     This routine records VAT & VAT Icb at the end of session
5032  */
5033 OSSTATUS
5034 UDFRecordVAT(
5035     IN PVCB Vcb
5036     )
5037 {
5038     uint32 Offset;
5039     uint32 to_read;
5040     uint32 hdrOffset, hdrOffsetNew;
5041     uint32 hdrLen;
5042     OSSTATUS status;
5043     uint32 ReadBytes;
5044     uint32 len;
5045     uint16 PartNdx = (uint16)Vcb->VatPartNdx;
5046     uint16 PartNum = UDFGetPartNumByPartNdx(Vcb, PartNdx);
5047     uint32 root = UDFPartStart(Vcb, PartNum);
5048     PUDF_FILE_INFO VatFileInfo = Vcb->VatFileInfo;
5049     uint32 i;
5050     PEXTENT_MAP Mapping;
5051     uint32 off, BS, NWA;
5052     int8* Old;
5053     int8* New;
5054     uint32* Vat;
5055     uint8 AllocMode;
5056     uint32 VatLen;
5057     uint32 PacketOffset;
5058     uint32 BSh = Vcb->BlockSizeBits;
5059     uint32 MaxPacket = Vcb->WriteBlockSize >> BSh;
5060     uint32 OldLen;
5061     EntityID* eID;
5062 
5063     if(!(Vat = Vcb->Vat) || !VatFileInfo) return STATUS_INVALID_PARAMETER;
5064     // Disable VAT-based translation
5065     Vcb->Vat = NULL;
5066     // sync VAT and FSBM
5067     len = min(UDFPartLen(Vcb, PartNum), Vcb->FSBM_BitCount - root);
5068     len = min(Vcb->VatCount, len);
5069     for(i=0; i<len; i++) {
5070         if(UDFGetFreeBit(Vcb->FSBM_Bitmap, root+i))
5071             Vat[i] = UDF_VAT_FREE_ENTRY;
5072     }
5073     // Ok, now we shall construct new VAT image...
5074     // !!! NOTE !!!
5075     // Both VAT copies - in-memory & on-disc
5076     // contain _relative_ addresses
5077     OldLen = len = (uint32)UDFGetFileSize(Vcb->VatFileInfo);
5078     VatLen = (Vcb->LastLBA - root + 1) * sizeof(uint32);
5079     Old = (int8*)DbgAllocatePool(PagedPool, OldLen);
5080     if(!Old) {
5081         DbgFreePool(Vat);
5082         return STATUS_INSUFFICIENT_RESOURCES;
5083     }
5084     // read old one
5085     status = UDFReadFile__(Vcb, VatFileInfo, 0, OldLen, FALSE, Old, &ReadBytes);
5086     if(!OS_SUCCESS(status)) {
5087         DbgFreePool(Vat);
5088         DbgFreePool(Old);
5089         return status;
5090     }
5091     // prepare some pointers
5092     // and fill headers
5093     if(Vcb->Partitions[PartNdx].PartitionType == UDF_VIRTUAL_MAP15) {
5094         Offset = 0;
5095         to_read =
5096         hdrOffset = len - sizeof(VirtualAllocationTable15);
5097         hdrLen = sizeof(VirtualAllocationTable15);
5098         hdrOffsetNew = VatLen;
5099         New = (int8*)DbgAllocatePool(PagedPool, VatLen + hdrLen);
5100         if(!New) {
5101             DbgFreePool(Vat);
5102             return STATUS_INSUFFICIENT_RESOURCES;
5103         }
5104         RtlCopyMemory(New+hdrOffsetNew, Old+hdrOffset, hdrLen);
5105         ((VirtualAllocationTable15*)(New + hdrOffset))->previousVATICB =
5106             VatFileInfo->Dloc->FELoc.Mapping[0].extLocation - root;
5107         eID = &(((VirtualAllocationTable15*)(New + hdrOffset))->ident);
5108 
5109         UDFSetEntityID_imp(eID, UDF_ID_ALLOC);
5110 
5111 /*        RtlCopyMemory((int8*)&(eID->ident), UDF_ID_ALLOC, sizeof(UDF_ID_ALLOC) );
5112         iis = (impIdentSuffix*)&(eID->identSuffix);
5113         iis->OSClass = UDF_OS_CLASS_WINNT;
5114         iis->OSIdent = UDF_OS_ID_WINNT;*/
5115     } else {
5116         VirtualAllocationTable20* Buf;
5117 
5118         Offset = ((VirtualAllocationTable20*)Old)->lengthHeader;
5119         to_read = len - Offset;
5120         hdrOffset = 0;
5121         hdrLen = sizeof(VirtualAllocationTable20);
5122         hdrOffsetNew = 0;
5123         New = (int8*)DbgAllocatePool(PagedPool, VatLen + hdrLen);
5124         if(!New) {
5125             DbgFreePool(Vat);
5126             return STATUS_INSUFFICIENT_RESOURCES;
5127         }
5128         RtlCopyMemory(New+hdrOffsetNew, Old+hdrOffset, hdrLen);
5129         ((VirtualAllocationTable20*)New)->previousVatICBLoc =
5130             VatFileInfo->Dloc->FELoc.Mapping[0].extLocation - root;
5131 
5132         Buf = (VirtualAllocationTable20*)New;
5133 
5134         Buf->minReadRevision  = Vcb->minUDFReadRev;
5135         Buf->minWriteRevision = Vcb->minUDFWriteRev;
5136         Buf->maxWriteRevision = Vcb->maxUDFWriteRev;
5137 
5138         Buf->numFIDSFiles       = Vcb->numFiles;
5139         Buf->numFIDSDirectories = Vcb->numDirs;
5140     }
5141 
5142     RtlCopyMemory(New+Offset, Vat, VatLen);
5143     //
5144     if(VatFileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY) {
5145         eID = &(((PEXTENDED_FILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->impIdent);
5146     } else {
5147         eID = &(((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->impIdent);
5148     }
5149 
5150 #if 0
5151     UDFSetEntityID_imp(eID, UDF_ID_DEVELOPER);
5152 #endif
5153 
5154 /*    RtlCopyMemory((int8*)&(eID->ident), UDF_ID_DEVELOPER, sizeof(UDF_ID_DEVELOPER) );
5155     iis = (impIdentSuffix*)&(eID->identSuffix);
5156     iis->OSClass = UDF_OS_CLASS_WINNT;
5157     iis->OSIdent = UDF_OS_ID_WINNT;*/
5158 
5159     VatFileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
5160     // drop VAT
5161     DbgFreePool(Vat);
5162     len = VatLen;
5163     // the operation of resize can modifiy WriteCount in WCache due to movement
5164     // of the data from FE. That's why we should remember PacketOffset now
5165     if(to_read < VatLen) {
5166         status = UDFResizeFile__(Vcb, VatFileInfo, len = hdrLen + VatLen);
5167         if(!OS_SUCCESS(status)) {
5168             return status;
5169         }
5170         UDFMarkSpaceAsXXX(Vcb, VatFileInfo->Dloc, VatFileInfo->Dloc->DataLoc.Mapping, AS_DISCARDED); //free
5171     }
5172     PacketOffset = WCacheGetWriteBlockCount__(&(Vcb->FastCache));
5173     if( ((((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) ) {
5174         // now we'll place FE & built-in data to the last sector of
5175         // the last packet will be recorded
5176         if(!PacketOffset) {
5177             // add padding
5178             UDFWriteData(Vcb, TRUE, ((uint64)Vcb->NWA) << Vcb->BlockSizeBits, 1, FALSE, Old, &ReadBytes);
5179             PacketOffset++;
5180         } else {
5181             Vcb->Vat = (uint32*)(New+Offset);
5182             WCacheSyncReloc__(&(Vcb->FastCache), Vcb);
5183             Vcb->Vat = NULL;
5184         }
5185         VatFileInfo->Dloc->FELoc.Mapping[0].extLocation =
5186         VatFileInfo->Dloc->DataLoc.Mapping[0].extLocation =
5187             Vcb->NWA+PacketOffset;
5188         VatFileInfo->Dloc->FELoc.Modified = TRUE;
5189         // setup descTag
5190         ((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->descTag.tagLocation =
5191             UDFPhysLbaToPart(Vcb, PartNum, VatFileInfo->Dloc->DataLoc.Mapping[0].extLocation);
5192         // record data
5193         if(OS_SUCCESS(status = UDFWriteFile__(Vcb, VatFileInfo, 0, VatLen + hdrLen, FALSE, New, &ReadBytes))) {
5194             status = UDFFlushFile__(Vcb, VatFileInfo);
5195         }
5196         return status;
5197     }
5198     // We can't fit the whole VAT in FE tail
5199     // Now lets 'unpack' VAT's mapping to make updating easier
5200     status = UDFUnPackMapping(Vcb, &(VatFileInfo->Dloc->DataLoc));
5201     if(!OS_SUCCESS(status)) return status;
5202     // update VAT with locations of not flushed blocks
5203     if(PacketOffset) {
5204         Vcb->Vat = (uint32*)(New+Offset);
5205         WCacheSyncReloc__(&(Vcb->FastCache), Vcb);
5206         Vcb->Vat = NULL;
5207     }
5208 
5209     Mapping = VatFileInfo->Dloc->DataLoc.Mapping;
5210     off=0;
5211     BS = Vcb->BlockSize;
5212     NWA = Vcb->NWA;
5213     VatLen += hdrLen;
5214     // record modified parts of VAT & update mapping
5215     for(i=0; Mapping[i].extLength; i++) {
5216         to_read = (VatLen>=BS) ? BS : VatLen;
5217         if((OldLen < off) || (RtlCompareMemory(Old+off, New+off, to_read) != to_read)) {
5218             // relocate frag
5219             Mapping[i].extLocation = NWA+PacketOffset;
5220             Mapping[i].extLength &= UDF_EXTENT_LENGTH_MASK;
5221             PacketOffset++;
5222             if(PacketOffset >= MaxPacket) {
5223                 NWA += (MaxPacket + 7);
5224                 PacketOffset = 0;
5225             }
5226             status = UDFWriteFile__(Vcb, VatFileInfo, off, to_read, FALSE, New+off, &ReadBytes);
5227             if(!OS_SUCCESS(status)) {
5228                 return status;
5229             }
5230         }
5231         VatLen-=BS;
5232         off+=BS;
5233     }
5234     // pack mapping
5235     UDFPackMapping(Vcb, &(VatFileInfo->Dloc->DataLoc));
5236     len = UDFGetMappingLength(VatFileInfo->Dloc->DataLoc.Mapping)/sizeof(EXTENT_MAP) - 1;
5237     // obtain AllocMode
5238     AllocMode = ((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK;
5239     switch(AllocMode) {
5240     case ICB_FLAG_AD_SHORT: {
5241         AllocMode = sizeof(SHORT_AD);
5242         break;
5243     }
5244     case ICB_FLAG_AD_LONG: {
5245         AllocMode = sizeof(LONG_AD);
5246         break;
5247     }
5248     case ICB_FLAG_AD_EXTENDED: {
5249 //            break;
5250     }
5251     default: {
5252         return STATUS_INVALID_PARAMETER;
5253     }
5254     }
5255     // calculate actual AllocSequence length (in blocks)
5256     len = (len*AllocMode+BS-1+VatFileInfo->Dloc->AllocLoc.Offset) /
5257 //          (((BS - sizeof(ALLOC_EXT_DESC))/sizeof(SHORT_AD))*sizeof(SHORT_AD));
5258         ((BS - sizeof(ALLOC_EXT_DESC) + AllocMode - 1) & ~(AllocMode-1));
5259     // Re-init AllocLoc
5260     if(VatFileInfo->Dloc->AllocLoc.Mapping) MyFreePool__(VatFileInfo->Dloc->AllocLoc.Mapping);
5261     VatFileInfo->Dloc->AllocLoc.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , (len+1)*sizeof(EXTENT_MAP),
5262                                                        MEM_EXTMAP_TAG);
5263     if(!(VatFileInfo->Dloc->AllocLoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES;
5264 
5265     VatFileInfo->Dloc->AllocLoc.Offset = (uint32)(VatFileInfo->Dloc->FELoc.Length);
5266     VatFileInfo->Dloc->AllocLoc.Length = 0;
5267     Mapping = VatFileInfo->Dloc->AllocLoc.Mapping;
5268     Mapping[0].extLength = BS-VatFileInfo->Dloc->AllocLoc.Offset;
5269 //  Mapping[0].extLocation = ???;
5270     for(i=1; i<len; i++) {
5271         // relocate frag
5272         Mapping[i].extLocation = NWA+PacketOffset;
5273         Mapping[i].extLength = BS;
5274         PacketOffset++;
5275         if(PacketOffset >= MaxPacket) {
5276             NWA += (MaxPacket + 7);
5277             PacketOffset = 0;
5278         }
5279     }
5280     // Terminator
5281     Mapping[i].extLocation =
5282     Mapping[i].extLength = 0;
5283 
5284     if( !PacketOffset &&
5285         (VatFileInfo->Dloc->AllocLoc.Length <= (Vcb->BlockSize - (uint32)(VatFileInfo->Dloc->AllocLoc.Offset)) ) ) {
5286         // add padding
5287         UDFWriteData(Vcb, TRUE, ((uint64)NWA) << Vcb->BlockSizeBits, 1, FALSE, Old, &ReadBytes);
5288         PacketOffset++;
5289     }
5290     // now we'll place FE & built-in data to the last sector of
5291     // the last packet will be recorded
5292     VatFileInfo->Dloc->FELoc.Mapping[0].extLocation =
5293     VatFileInfo->Dloc->AllocLoc.Mapping[0].extLocation =
5294         NWA+PacketOffset;
5295     VatFileInfo->Dloc->FELoc.Modified = TRUE;
5296     // setup descTag
5297     ((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->descTag.tagLocation =
5298         UDFPhysLbaToPart(Vcb, PartNum, VatFileInfo->Dloc->FELoc.Mapping[0].extLocation);
5299     VatFileInfo->Dloc->DataLoc.Modified = TRUE;
5300 
5301     status = UDFFlushFile__(Vcb, VatFileInfo);
5302     if(!OS_SUCCESS(status))
5303         return status;
5304     WCacheFlushAll__(&(Vcb->FastCache), Vcb);
5305     return STATUS_SUCCESS;
5306 } // end UDFRecordVAT()
5307 #endif //UDF_READ_ONLY_BUILD
5308 
5309 /*
5310     This routine updates VAT according to RequestedLbaTable (RelocTab) &
5311     actual physical address where this data will be stored
5312  */
5313 OSSTATUS
5314 UDFUpdateVAT(
5315     IN void* _Vcb,
5316     IN uint32 Lba,
5317     IN uint32* RelocTab,  // can be NULL
5318     IN uint32 BCount
5319     )
5320 {
5321 #ifndef UDF_READ_ONLY_BUILD
5322     PVCB Vcb = (PVCB)_Vcb;
5323     uint16 PartNdx = (uint16)(Vcb->VatPartNdx);
5324     uint16 PartNum = (uint16)(Lba ? UDFGetPartNumByPhysLba(Vcb, Lba) : UDFGetPartNumByPartNdx(Vcb, PartNdx));
5325     if(PartNum != UDFGetPartNumByPartNdx(Vcb, PartNdx)) {
5326         UDFPrint(("UDFUpdateVAT: Write to Write-Protected partition\n"));
5327         return STATUS_MEDIA_WRITE_PROTECTED;
5328     }
5329     // !!! NOTE !!!
5330     // Both VAT copies - in-memory & on-disc
5331     // contain _relative_ addresses
5332     uint32 root = Vcb->Partitions[PartNdx].PartitionRoot;
5333     uint32 NWA = Vcb->NWA-root;
5334     uint32 i;
5335     uint32 CurLba;
5336 
5337     if(!Vcb->Vat) return STATUS_SUCCESS;
5338 
5339     for(i=0; i<BCount; i++, NWA++) {
5340         if((CurLba = (RelocTab ? RelocTab[i] : (Lba+i)) - root) >= Vcb->VatCount)
5341             Vcb->VatCount = CurLba+1;
5342         Vcb->Vat[CurLba] = NWA;
5343     }
5344     return STATUS_SUCCESS;
5345 #else //UDF_READ_ONLY_BUILD
5346     return STATUS_MEDIA_WRITE_PROTECTED;
5347 #endif //UDF_READ_ONLY_BUILD
5348 } // end UDFUpdateVAT()
5349 
5350 #ifndef UDF_READ_ONLY_BUILD
5351 /*
5352     This routine rebuilds file's FE in order to move data from
5353     ICB to separate Block.
5354  */
5355 OSSTATUS
5356 UDFConvertFEToNonInICB(
5357     IN PVCB Vcb,
5358     IN PUDF_FILE_INFO FileInfo,
5359     IN uint8 NewAllocMode
5360     )
5361 {
5362     OSSTATUS status;
5363     int8* OldInIcb = NULL;
5364     uint32 OldLen;
5365     ValidateFileInfo(FileInfo);
5366     uint32 ReadBytes;
5367     uint32 _WrittenBytes;
5368     PUDF_DATALOC_INFO Dloc;
5369 
5370 //    ASSERT(FileInfo->RefCount >= 1);
5371 
5372     Dloc = FileInfo->Dloc;
5373     ASSERT(Dloc->FELoc.Mapping[0].extLocation);
5374     uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, Dloc->FELoc.Mapping[0].extLocation);
5375 
5376     if(NewAllocMode == ICB_FLAG_AD_DEFAULT_ALLOC_MODE) {
5377         NewAllocMode = (uint8)(Vcb->DefaultAllocMode);
5378     }
5379     // we do not support recording of extended AD now
5380     if(NewAllocMode != ICB_FLAG_AD_SHORT &&
5381        NewAllocMode != ICB_FLAG_AD_LONG)
5382         return STATUS_INVALID_PARAMETER;
5383     if(!Dloc->DataLoc.Offset || !Dloc->DataLoc.Length)
5384         return STATUS_SUCCESS;
5385     ASSERT(!Dloc->AllocLoc.Mapping);
5386     // read in-icb data. it'll be replaced after resize
5387     OldInIcb = (int8*)MyAllocatePool__(NonPagedPool, (uint32)(Dloc->DataLoc.Length));
5388     if(!OldInIcb)
5389         return STATUS_INSUFFICIENT_RESOURCES;
5390     OldLen = (uint32)(Dloc->DataLoc.Length);
5391     status = UDFReadExtent(Vcb, &(Dloc->DataLoc), 0, OldLen, FALSE, OldInIcb, &ReadBytes);
5392     if(!OS_SUCCESS(status)) {
5393         MyFreePool__(OldInIcb);
5394         return status;
5395     }
5396 /*    if(!Dloc->AllocLoc.Mapping) {
5397         Dloc->AllocLoc.Mapping = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, sizeof(EXTENT_MAP)*2);
5398         if(!Dloc->AllocLoc.Mapping) {
5399             MyFreePool__(OldInIcb);
5400             return STATUS_INSUFFICIENT_RESOURCES;
5401         }
5402     }
5403     // init Alloc mode
5404     if((((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) {
5405         ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK;
5406         ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= Vcb->DefaultAllocMode;
5407     } else {
5408         BrutePoint();
5409     }
5410     RtlZeroMemory(Dloc->AllocLoc.Mapping, sizeof(EXTENT_MAP)*2);
5411 //    Dloc->AllocLoc.Mapping[0].extLocation = 0;
5412     Dloc->AllocLoc.Mapping[0].extLength   = Vcb->LBlockSize | EXTENT_NOT_RECORDED_NOT_ALLOCATED;
5413 //    Dloc->AllocLoc.Mapping[1].extLocation = 0;
5414 //    Dloc->AllocLoc.Mapping[1].extLength = 0;
5415 */
5416 
5417     // grow extent in order to force space allocation
5418     status = UDFResizeExtent(Vcb, PartNum, Vcb->LBlockSize, FALSE, &Dloc->DataLoc);
5419     if(!OS_SUCCESS(status)) {
5420         MyFreePool__(OldInIcb);
5421         return status;
5422     }
5423 
5424     // set Alloc mode
5425     if((((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) {
5426         ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK;
5427         ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= NewAllocMode;
5428     } else {
5429         BrutePoint();
5430     }
5431 
5432     // revert to initial extent size. This will not cause NonInICB->InICB transform
5433     status = UDFResizeExtent(Vcb, PartNum, OldLen, FALSE, &Dloc->DataLoc);
5434     if(!OS_SUCCESS(status)) {
5435         MyFreePool__(OldInIcb);
5436         return status;
5437     }
5438 
5439     // replace data from ICB (if any) & free buffer
5440     status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), 0, OldLen, FALSE, OldInIcb, &_WrittenBytes);
5441     MyFreePool__(OldInIcb);
5442     if(!OS_SUCCESS(status)) {
5443         return status;
5444     }
5445     // inform UdfInfo, that AllocDesc's must be rebuilt on flush/close
5446     Dloc->AllocLoc.Modified = TRUE;
5447     Dloc->DataLoc.Modified = TRUE;
5448     return STATUS_SUCCESS;
5449 } // end UDFConvertFEToNonInICB()
5450 
5451 /*
5452     This routine converts file's FE to extended form.
5453     It is needed for stream creation.
5454  */
5455 OSSTATUS
5456 UDFConvertFEToExtended(
5457     IN PVCB Vcb,
5458     IN PUDF_FILE_INFO FileInfo
5459     )
5460 {
5461     PEXTENDED_FILE_ENTRY ExFileEntry;
5462     PFILE_ENTRY FileEntry;
5463     uint32 Length, NewLength, l;
5464     OSSTATUS status;
5465     uint32 ReadBytes;
5466 
5467     if(!FileInfo) return STATUS_INVALID_PARAMETER;
5468     ValidateFileInfo(FileInfo);
5469     if(FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY) return STATUS_SUCCESS;
5470     if(FileInfo->Dloc->FileEntry->tagIdent != TID_FILE_ENTRY) return STATUS_INVALID_PARAMETER;
5471 
5472 /*    if(!OS_SUCCESS(status = UDFFlushFile__(Vcb, FileInfo)))
5473         return status;*/
5474 
5475     Length = FileInfo->Dloc->FileEntryLen;
5476     NewLength = Length - sizeof(FILE_ENTRY) + sizeof(EXTENDED_FILE_ENTRY);
5477     ExFileEntry = (PEXTENDED_FILE_ENTRY)MyAllocatePoolTag__(NonPagedPool, NewLength, MEM_XFE_TAG);
5478     if(!ExFileEntry) return STATUS_INSUFFICIENT_RESOURCES;
5479     FileEntry = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
5480     RtlZeroMemory(ExFileEntry, NewLength);
5481 
5482     ExFileEntry->descTag.tagIdent = TID_EXTENDED_FILE_ENTRY;
5483     ExFileEntry->icbTag = FileEntry->icbTag;
5484     ExFileEntry->uid = FileEntry->uid;
5485     ExFileEntry->gid = FileEntry->gid;
5486     ExFileEntry->permissions = FileEntry->permissions;
5487     ExFileEntry->fileLinkCount = FileEntry->fileLinkCount;
5488     ExFileEntry->recordFormat = FileEntry->recordFormat;
5489     ExFileEntry->recordDisplayAttr = FileEntry->recordDisplayAttr;
5490     ExFileEntry->recordLength = FileEntry->recordLength;
5491     ExFileEntry->informationLength = FileEntry->informationLength;
5492     ExFileEntry->logicalBlocksRecorded = FileEntry->logicalBlocksRecorded;
5493     ExFileEntry->accessTime = FileEntry->accessTime;
5494     ExFileEntry->modificationTime = FileEntry->modificationTime;
5495     ExFileEntry->attrTime = FileEntry->attrTime;
5496     ExFileEntry->checkpoint = FileEntry->checkpoint;
5497     ExFileEntry->extendedAttrICB = FileEntry->extendedAttrICB;
5498     ExFileEntry->impIdent = FileEntry->impIdent;
5499     ExFileEntry->uniqueID = FileEntry->uniqueID;
5500     ExFileEntry->lengthExtendedAttr = FileEntry->lengthExtendedAttr;
5501     ExFileEntry->lengthAllocDescs = FileEntry->lengthAllocDescs;
5502     RtlCopyMemory(ExFileEntry+1, FileEntry+1, FileEntry->lengthExtendedAttr);
5503     RtlCopyMemory((int8*)(ExFileEntry+1)+FileEntry->lengthExtendedAttr, (int8*)(ExFileEntry+1)+FileEntry->lengthExtendedAttr, FileEntry->lengthAllocDescs);
5504 
5505     if((((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) {
5506 
5507         if((l = (uint32)(FileInfo->Dloc->DataLoc.Length))) {
5508 
5509             int8* tmp_buff = (int8*)MyAllocatePool__(NonPagedPool, l);
5510             if(!tmp_buff) {
5511                 MyFreePool__(ExFileEntry);
5512                 return STATUS_INSUFFICIENT_RESOURCES;
5513             }
5514             if(!OS_SUCCESS(status = UDFReadFile__(Vcb, FileInfo, 0, l, FALSE, tmp_buff, &ReadBytes)) ||
5515                !OS_SUCCESS(status = UDFResizeFile__(Vcb, FileInfo, 0)) ) {
5516                 MyFreePool__(ExFileEntry);
5517                 MyFreePool__(tmp_buff);
5518                 return status;
5519             }
5520             FileInfo->Dloc->FELoc.Length =
5521             FileInfo->Dloc->DataLoc.Offset = NewLength;
5522             FileInfo->Dloc->FELoc.Modified =
5523             FileInfo->Dloc->DataLoc.Modified = TRUE;
5524             MyFreePool__(FileInfo->Dloc->FileEntry);
5525             FileInfo->Dloc->FileEntry = (tag*)ExFileEntry;
5526             if(!OS_SUCCESS(status = UDFResizeFile__(Vcb, FileInfo, l)) ||
5527                !OS_SUCCESS(status = UDFWriteFile__(Vcb, FileInfo, 0, l, FALSE, tmp_buff, &ReadBytes)) ) {
5528                 MyFreePool__(ExFileEntry);
5529                 MyFreePool__(tmp_buff);
5530                 return status;
5531             }
5532             MyFreePool__(tmp_buff);
5533         } else {
5534             FileInfo->Dloc->FELoc.Length =
5535             FileInfo->Dloc->DataLoc.Offset = NewLength;
5536             FileInfo->Dloc->FELoc.Modified =
5537             FileInfo->Dloc->DataLoc.Modified = TRUE;
5538             MyFreePool__(FileInfo->Dloc->FileEntry);
5539             FileInfo->Dloc->FileEntry = (tag*)ExFileEntry;
5540         }
5541     } else {
5542         FileInfo->Dloc->FELoc.Length =
5543         FileInfo->Dloc->AllocLoc.Offset = NewLength;
5544         FileInfo->Dloc->FELoc.Modified =
5545         FileInfo->Dloc->AllocLoc.Modified = TRUE;
5546         MyFreePool__(FileInfo->Dloc->FileEntry);
5547         FileInfo->Dloc->FileEntry = (tag*)ExFileEntry;
5548     }
5549     FileInfo->Dloc->FileEntryLen = NewLength;
5550     FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
5551     if(Vcb->minUDFReadRev < 0x0200)
5552         Vcb->minUDFReadRev = 0x0200;
5553     return STATUS_SUCCESS;
5554 } // end UDFConvertFEToExtended()
5555 
5556 /*
5557     This routine makes file almost unavailable for external callers.
5558     The only way to access Hidden with this routine file is OpenByIndex.
5559     It is usefull calling this routine to pretend file to be deleted,
5560     for ex. when we have UDFCleanUp__() or smth. like this in progress,
5561     but we want to create file with the same name.
5562  */
5563 OSSTATUS
5564 UDFPretendFileDeleted__(
5565     IN PVCB Vcb,
5566     IN PUDF_FILE_INFO FileInfo
5567     )
5568 {
5569     AdPrint(("UDFPretendFileDeleted__:\n"));
5570 
5571     NTSTATUS RC;
5572     PDIR_INDEX_HDR hDirNdx = UDFGetDirIndexByFileInfo(FileInfo);
5573     if(!hDirNdx) return STATUS_CANNOT_DELETE;
5574     PDIR_INDEX_ITEM DirNdx = UDFDirIndex(hDirNdx, FileInfo->Index);
5575     if(!DirNdx) return STATUS_CANNOT_DELETE;
5576 
5577 
5578     // we can't hide file that is not marked as deleted
5579     RC = UDFDoesOSAllowFilePretendDeleted__(FileInfo);
5580     if(!NT_SUCCESS(RC))
5581         return RC;
5582 
5583     AdPrint(("UDFPretendFileDeleted__: set UDF_FI_FLAG_FI_INTERNAL\n"));
5584 
5585     DirNdx->FI_Flags |= UDF_FI_FLAG_FI_INTERNAL;
5586     if(DirNdx->FName.Buffer) {
5587         MyFreePool__(DirNdx->FName.Buffer);
5588         DirNdx->FName.Buffer = NULL;
5589         DirNdx->FName.Length =
5590         DirNdx->FName.MaximumLength = 0;
5591     }
5592     return STATUS_SUCCESS;
5593 } // end UDFPretendFileDeleted__()
5594 #endif //UDF_READ_ONLY_BUILD
5595