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 SIZE_T 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 PSIZE_T 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     SIZE_T Nlen;
1119     uint32 l;
1120     // prepare filename
1121     UDFCompressUnicode(fn, &CS0, &Nlen);
1122     if(!CS0) return STATUS_INSUFFICIENT_RESOURCES;
1123     if(Nlen < 2) {
1124         Nlen = 0;
1125     } else
1126     if(Nlen > UDF_NAME_LEN) {
1127         if(CS0) MyFreePool__(CS0);
1128         return STATUS_OBJECT_NAME_INVALID;
1129     }
1130     // allocate memory for FI
1131     l = (sizeof(FILE_IDENT_DESC) + Nlen + ImpUseLen + 3) & ~((uint32)3);
1132     FileId = (PFILE_IDENT_DESC)MyAllocatePoolTag__(NonPagedPool, l, MEM_FID_TAG);
1133     if(!FileId) {
1134         if(CS0) MyFreePool__(CS0);
1135         return STATUS_INSUFFICIENT_RESOURCES;
1136     }
1137     // fill FI structure
1138     RtlZeroMemory( (int8*)FileId, l);
1139     RtlCopyMemory( ((int8*)(FileId+1))+ImpUseLen, CS0, Nlen);
1140     FileId->descTag.tagIdent = TID_FILE_IDENT_DESC;
1141     FileId->fileVersionNum = 1;
1142     FileId->lengthOfImpUse = (uint16)ImpUseLen;
1143     FileId->lengthFileIdent = (uint8)Nlen;
1144     FileId->icb = *FileEntryIcb;
1145     *_FileId = FileId;
1146     *FileIdLen = l;
1147 
1148     if(CS0) MyFreePool__(CS0);
1149     return STATUS_SUCCESS;
1150 } // end UDFBuildFileIdent()
1151 
1152 #ifndef UDF_READ_ONLY_BUILD
1153 /*
1154     This routine sets informationLength field in (Ext)FileEntry
1155  */
1156 void
1157 UDFSetFileSize(
1158     IN PUDF_FILE_INFO FileInfo,
1159     IN int64 Size
1160     )
1161 {
1162     uint16 Ident;
1163 //    PDIR_INDEX_ITEM DirIndex;
1164 
1165     ValidateFileInfo(FileInfo);
1166     AdPrint(("UDFSetFileSize: %I64x, FI %x\n", Size, FileInfo));
1167 
1168     //AdPrint(("  Dloc %x\n", FileInfo->Dloc));
1169     FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1170     //AdPrint(("  FileEntry %x\n", FileInfo->Dloc->FileEntry));
1171     Ident = FileInfo->Dloc->FileEntry->tagIdent;
1172     //AdPrint(("  Ident %x\n", Ident));
1173     if(Ident == TID_FILE_ENTRY) {
1174         PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1175         //AdPrint(("  fe %x\n", fe));
1176         fe->informationLength = Size;
1177     } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1178         PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1179         //AdPrint(("  ext-fe %x\n", fe));
1180         fe->informationLength = Size;
1181     }
1182 /*    if(DirIndex = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index) ) {
1183         DirIndex->FileSize = Size;
1184     }*/
1185     //AdPrint(("UDFSetFileSize: ok\n"));
1186     return;
1187 } // end UDFSetFileSize()
1188 
1189 void
1190 UDFSetFileSizeInDirNdx(
1191     IN PVCB Vcb,
1192     IN PUDF_FILE_INFO FileInfo,
1193     IN int64* ASize
1194     )
1195 {
1196     uint16 Ident;
1197     PDIR_INDEX_ITEM DirIndex;
1198 
1199     ValidateFileInfo(FileInfo);
1200     if(ASize) {
1201         AdPrint(("UDFSetFileSizeInDirNdx: %I64x\n", *ASize));
1202     } else {
1203         AdPrint(("UDFSetFileSizeInDirNdx: sync\n"));
1204     }
1205 
1206     DirIndex = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index);
1207     if(!DirIndex)
1208        return;
1209 
1210     Ident = FileInfo->Dloc->FileEntry->tagIdent;
1211     if(Ident == TID_FILE_ENTRY) {
1212         PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1213         DirIndex->FileSize = fe->informationLength;
1214         if(ASize) {
1215             DirIndex->AllocationSize = *ASize;
1216 //        } else {
1217 //            DirIndex->AllocationSize = (fe->informationLength + Vcb->LBlockSize - 1) & ~(Vcb->LBlockSize - 1);
1218         }
1219     } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1220         PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1221         DirIndex->FileSize = fe->informationLength;
1222         if(ASize) {
1223             DirIndex->AllocationSize = *ASize;
1224 //        } else {
1225 //            DirIndex->AllocationSize = (fe->informationLength + Vcb->LBlockSize - 1) & ~(Vcb->LBlockSize - 1);
1226         }
1227     }
1228     return;
1229 } // end UDFSetFileSizeInDirNdx()
1230 #endif //UDF_READ_ONLY_BUILD
1231 
1232 /*
1233     This routine gets informationLength field in (Ext)FileEntry
1234  */
1235 int64
1236 UDFGetFileSize(
1237     IN PUDF_FILE_INFO FileInfo
1238     )
1239 {
1240     uint16 Ident;
1241 
1242     ValidateFileInfo(FileInfo);
1243 
1244     Ident = FileInfo->Dloc->FileEntry->tagIdent;
1245     if(Ident == TID_FILE_ENTRY) {
1246         PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1247         return fe->informationLength;
1248     } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1249         PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1250         return fe->informationLength;
1251     }
1252     return (-1);
1253 } // end UDFGetFileSize()
1254 
1255 int64
1256 UDFGetFileSizeFromDirNdx(
1257     IN PVCB Vcb,
1258     IN PUDF_FILE_INFO FileInfo
1259     )
1260 {
1261     PDIR_INDEX_ITEM DirIndex;
1262 
1263     ValidateFileInfo(FileInfo);
1264 
1265     DirIndex = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index);
1266     if(!DirIndex)
1267        return -1;
1268 
1269     return DirIndex->FileSize;
1270 } // end UDFGetFileSizeFromDirNdx()
1271 
1272 #ifndef UDF_READ_ONLY_BUILD
1273 /*
1274     This routine sets lengthAllocDesc field in (Ext)FileEntry
1275  */
1276 void
1277 UDFSetAllocDescLen(
1278     IN PVCB Vcb,
1279     IN PUDF_FILE_INFO FileInfo
1280     )
1281 {
1282     uint16 Ident;
1283 
1284     ValidateFileInfo(FileInfo);
1285 
1286     FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1287     Ident = FileInfo->Dloc->FileEntry->tagIdent;
1288     if(Ident == TID_FILE_ENTRY) {
1289         PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1290         if(FileInfo->Dloc->AllocLoc.Length) {
1291             fe->lengthAllocDescs = min(FileInfo->Dloc->AllocLoc.Mapping[0].extLength -
1292                                        FileInfo->Dloc->AllocLoc.Offset,
1293                                        (uint32)(FileInfo->Dloc->AllocLoc.Length));
1294         } else
1295         if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
1296             fe->lengthAllocDescs = (uint32)(FileInfo->Dloc->DataLoc.Length);
1297         }
1298     } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1299         PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1300         if(FileInfo->Dloc->AllocLoc.Length) {
1301             fe->lengthAllocDescs = min(FileInfo->Dloc->AllocLoc.Mapping[0].extLength -
1302                                        FileInfo->Dloc->AllocLoc.Offset,
1303                                        (uint32)(FileInfo->Dloc->AllocLoc.Length));
1304         } else
1305         if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
1306             fe->lengthAllocDescs = (uint32)(FileInfo->Dloc->DataLoc.Length);
1307         }
1308     }
1309 } // end UDFSetAllocDescLen()
1310 
1311 /*
1312     This routine changes fileLinkCount field in (Ext)FileEntry
1313  */
1314 void
1315 UDFChangeFileLinkCount(
1316     IN PUDF_FILE_INFO FileInfo,
1317     IN BOOLEAN Increase
1318     )
1319 {
1320     uint16 Ident;
1321 
1322     ValidateFileInfo(FileInfo);
1323 
1324     FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1325     Ident = FileInfo->Dloc->FileEntry->tagIdent;
1326     if(Ident == TID_FILE_ENTRY) {
1327         PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1328         if(Increase) {
1329             fe->fileLinkCount++;
1330         } else {
1331             fe->fileLinkCount--;
1332         }
1333         if(fe->fileLinkCount & 0x8000)
1334             fe->fileLinkCount = 0xffff;
1335         return;
1336     } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1337         PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1338         if(Increase) {
1339             fe->fileLinkCount++;
1340         } else {
1341             fe->fileLinkCount--;
1342         }
1343         if(fe->fileLinkCount & 0x8000)
1344             fe->fileLinkCount = 0xffff;
1345         return;
1346     }
1347     return;
1348 } // end UDFChangeFileLinkCount()
1349 #endif //UDF_READ_ONLY_BUILD
1350 
1351 /*
1352     This routine gets fileLinkCount field from (Ext)FileEntry
1353  */
1354 uint16
1355 UDFGetFileLinkCount(
1356     IN PUDF_FILE_INFO FileInfo
1357     )
1358 {
1359     uint16 Ident;
1360     uint16 d;
1361 
1362     ValidateFileInfo(FileInfo);
1363 
1364     if(!FileInfo->Dloc->FileEntry)
1365         return 1;
1366     Ident = FileInfo->Dloc->FileEntry->tagIdent;
1367     // UDF engine assumes that LinkCount is a counter
1368     // of FileIdents, referencing this FE.
1369     // UDF 2.0 states, that it should be counter of ALL
1370     // references (including SDir) - 1.
1371     // Thus we'll write to media UDF-required value, but return
1372     // cooked value to callers
1373     d = UDFHasAStreamDir(FileInfo) ? 0 : 1;
1374     if(Ident == TID_FILE_ENTRY) {
1375         return ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount + d;
1376     } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1377         return ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount + d;
1378     }
1379     return UDF_INVALID_LINK_COUNT;
1380 } // end UDFGetFileLinkCount()
1381 
1382 #ifdef UDF_CHECK_UTIL
1383 /*
1384     This routine sets fileLinkCount field in (Ext)FileEntry
1385  */
1386 void
1387 UDFSetFileLinkCount(
1388     IN PUDF_FILE_INFO FileInfo,
1389     uint16 LinkCount
1390     )
1391 {
1392     uint16 Ident;
1393     uint16 d;
1394 
1395     ValidateFileInfo(FileInfo);
1396 
1397     if(!FileInfo->Dloc->FileEntry)
1398         return;
1399     Ident = FileInfo->Dloc->FileEntry->tagIdent;
1400     // UDF engine assumes that LinkCount is a counter
1401     // of FileIdents, referencing this FE.
1402     // UDF 2.0 states, that it should be counter of ALL
1403     // references (including SDir) - 1.
1404     // Thus we'll write to media UDF-required value, but return
1405     // cooked value to callers
1406     d = UDFHasAStreamDir(FileInfo) ? 0 : 1;
1407     if(Ident == TID_FILE_ENTRY) {
1408         ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount = LinkCount - d;
1409     } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1410         ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount = LinkCount - d;
1411     }
1412     return;
1413 } // end UDFGetFileLinkCount()
1414 #endif //UDF_CHECK_UTIL
1415 
1416 /*
1417     This routine gets lengthExtendedAttr field in (Ext)FileEntry
1418  */
1419 uint32
1420 UDFGetFileEALength(
1421     IN PUDF_FILE_INFO FileInfo
1422     )
1423 {
1424     uint16 Ident;
1425 
1426     ValidateFileInfo(FileInfo);
1427 
1428     if(!FileInfo->Dloc->FileEntry)
1429         return 1;
1430     Ident = FileInfo->Dloc->FileEntry->tagIdent;
1431 
1432     if(Ident == TID_FILE_ENTRY) {
1433         return ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->lengthExtendedAttr;
1434     } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1435         return ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->lengthExtendedAttr;
1436     }
1437     return 0;
1438 } // end UDFGetFileEALength()
1439 
1440 #ifndef UDF_READ_ONLY_BUILD
1441 /*
1442     This routine sets UniqueID field in (Ext)FileEntry
1443  */
1444 int64
1445 UDFAssingNewFUID(
1446     IN PVCB Vcb
1447     )
1448 {
1449     Vcb->NextUniqueId++;
1450     if(!((uint32)(Vcb->NextUniqueId)))
1451         Vcb->NextUniqueId += 16;
1452     return Vcb->NextUniqueId;
1453 }
1454 
1455 void
1456 UDFSetFileUID(
1457     IN PVCB Vcb,
1458     IN PUDF_FILE_INFO FileInfo
1459     )
1460 {
1461     uint16 Ident;
1462     int64 UID;
1463 
1464     ValidateFileInfo(FileInfo);
1465 
1466     UID = UDFAssingNewFUID(Vcb);
1467 
1468 /*    UID = FileInfo->Dloc->FELoc.Mapping[0].extLocation |
1469           ( FileInfo->ParentFile ? (((int64)(FileInfo->ParentFile->Dloc->FELoc.Mapping[0].extLocation)) << 32) : 0);*/
1470 
1471     FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1472     Ident = FileInfo->Dloc->FileEntry->tagIdent;
1473     if(Ident == TID_FILE_ENTRY) {
1474         PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1475         fe->uniqueID = UID;
1476     } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1477         PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1478         fe->uniqueID = UID;
1479     }
1480     if(FileInfo->FileIdent)
1481         ((FidADImpUse*)&(FileInfo->FileIdent->icb.impUse))->uniqueID = (uint32)UID;
1482     return;
1483 } // end UDFSetFileUID()
1484 #endif //UDF_READ_ONLY_BUILD
1485 
1486 /*
1487     This routine gets UniqueID field in (Ext)FileEntry
1488  */
1489 __inline
1490 int64
1491 UDFGetFileUID_(
1492     IN tag* FileEntry
1493     )
1494 {
1495     uint16 Ident;
1496 
1497     Ident = FileEntry->tagIdent;
1498     if(Ident == TID_FILE_ENTRY) {
1499         PFILE_ENTRY fe = (PFILE_ENTRY)(FileEntry);
1500         return fe->uniqueID;
1501     } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1502         PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileEntry);
1503         return fe->uniqueID;
1504     }
1505     return (-1);
1506 } // end UDFGetFileUID()
1507 
1508 int64
1509 UDFGetFileUID(
1510     IN PUDF_FILE_INFO FileInfo
1511     )
1512 {
1513     ValidateFileInfo(FileInfo);
1514 
1515     return UDFGetFileUID_(FileInfo->Dloc->FileEntry);
1516 } // end UDFGetFileUID()
1517 
1518 #ifndef UDF_READ_ONLY_BUILD
1519 void
1520 UDFChangeFileCounter(
1521     IN PVCB Vcb,
1522     IN BOOLEAN FileCounter,
1523     IN BOOLEAN Increase
1524     )
1525 {
1526     uint32* counter;
1527 
1528     counter = FileCounter ?
1529         &(Vcb->numFiles) :
1530         &(Vcb->numDirs);
1531     if(*counter == (ULONG)-1)
1532         return;
1533     if(Increase) {
1534         UDFInterlockedIncrement((int32*)counter);
1535     } else {
1536         UDFInterlockedDecrement((int32*)counter);
1537     }
1538 
1539 } // end UDFChangeFileCounter()
1540 
1541 void
1542 UDFSetEntityID_imp_(
1543     IN EntityID* eID,
1544     IN uint8* Str,
1545     IN uint32 Len
1546     )
1547 {
1548     impIdentSuffix* iis;
1549 
1550     RtlCopyMemory( (int8*)&(eID->ident), Str, Len );
1551     iis = (impIdentSuffix*)&(eID->identSuffix);
1552     iis->OSClass = UDF_OS_CLASS_WINNT;
1553     iis->OSIdent = UDF_OS_ID_WINNT;
1554 
1555 } // end UDFSetEntityID_imp_()
1556 #endif //UDF_READ_ONLY_BUILD
1557 
1558 void
1559 UDFReadEntityID_Domain(
1560     PVCB Vcb,
1561     EntityID* eID
1562     )
1563 {
1564     domainIdentSuffix* dis;
1565     uint8 flags;
1566 
1567     dis = (domainIdentSuffix*)&(eID->identSuffix);
1568 
1569     UDFPrint(("UDF: Entity Id:\n"));
1570     UDFPrint(("flags: %x\n", eID->flags));
1571     UDFPrint(("ident[0]: %x\n", eID->ident[0]));
1572     UDFPrint(("ident[1]: %x\n", eID->ident[1]));
1573     UDFPrint(("ident[2]: %x\n", eID->ident[2]));
1574     UDFPrint(("ident[3]: %x\n", eID->ident[3]));
1575     UDFPrint(("UDF: Entity Id Domain:\n"));
1576     // Get current UDF revision
1577     Vcb->CurrentUDFRev = max(dis->currentRev, Vcb->CurrentUDFRev);
1578     UDFPrint(("Effective Revision: %x\n", Vcb->CurrentUDFRev));
1579     // Get Read-Only flags
1580     flags = dis->flags;
1581     UDFPrint(("Flags: %x\n", flags));
1582     if((flags & ENTITYID_FLAGS_SOFT_RO) &&
1583         (Vcb->CompatFlags & UDF_VCB_IC_SOFT_RO)) {
1584         Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY;
1585         Vcb->UserFSFlags |= UDF_USER_FS_FLAGS_SOFT_RO;
1586         UDFPrint(("       Soft-RO\n"));
1587     }
1588     if((flags & ENTITYID_FLAGS_HARD_RO) &&
1589        (Vcb->CompatFlags & UDF_VCB_IC_HW_RO)) {
1590         Vcb->VCBFlags |= UDF_VCB_FLAGS_MEDIA_READ_ONLY;
1591         Vcb->UserFSFlags |= UDF_USER_FS_FLAGS_HW_RO;
1592         UDFPrint(("       Hard-RO\n"));
1593     }
1594 
1595 } // end UDFReadEntityID_Domain()
1596 
1597 #ifndef UDF_READ_ONLY_BUILD
1598 /*
1599     This routine writes data to file & increases it if necessary.
1600     In case of increasing AllocDescs will be rebuilt & flushed to disc
1601     (via driver's cache, of cource). Free space map will be updated only
1602     durring global media flush.
1603  */
1604 OSSTATUS
1605 UDFWriteFile__(
1606     IN PVCB Vcb,
1607     IN PUDF_FILE_INFO FileInfo,
1608     IN int64 Offset,
1609     IN SIZE_T Length,
1610     IN BOOLEAN Direct,
1611     IN int8* Buffer,
1612     OUT PSIZE_T WrittenBytes
1613     )
1614 {
1615     int64 t, elen;
1616     OSSTATUS status;
1617     int8* OldInIcb = NULL;
1618     ValidateFileInfo(FileInfo);
1619     SIZE_T ReadBytes;
1620     SIZE_T _WrittenBytes;
1621     PUDF_DATALOC_INFO Dloc;
1622     // unwind staff
1623     BOOLEAN WasInIcb = FALSE;
1624     uint64 OldLen;
1625 
1626 //    ASSERT(FileInfo->RefCount >= 1);
1627 
1628     Dloc = FileInfo->Dloc;
1629     ASSERT(Dloc->FELoc.Mapping[0].extLocation);
1630     uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, Dloc->FELoc.Mapping[0].extLocation);
1631     (*WrittenBytes) = 0;
1632 
1633     AdPrint(("UDFWriteFile__ FE %x, FileInfo %x, ExtInfo %x, Mapping %x\n",
1634         Dloc->FELoc.Mapping[0].extLocation, FileInfo, &(Dloc->DataLoc), Dloc->DataLoc.Mapping));
1635 
1636     t = Offset + Length;
1637 //    UDFUpdateModifyTime(Vcb, FileInfo);
1638     if(t <= Dloc->DataLoc.Length) {
1639         // write Alloc-Rec area
1640         ExtPrint(("  WAlloc-Rec: %I64x <= %I64x\n", t, Dloc->DataLoc.Length));
1641         status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), Offset, Length, Direct, Buffer, WrittenBytes);
1642         return status;
1643     }
1644     elen = UDFGetExtentLength(Dloc->DataLoc.Mapping);
1645     ExtPrint(("  DataLoc Offs %x, Len %I64x\n",
1646         Dloc->DataLoc.Offset, Dloc->DataLoc.Length));
1647     if(t <= (elen - Dloc->DataLoc.Offset)) {
1648         // write Alloc-Not-Rec area
1649         ExtPrint(("  WAlloc-Not-Rec: %I64x <= %I64x (%I64x - %I64x)\n",
1650             t, elen - Dloc->DataLoc.Offset - Dloc->DataLoc.Length,
1651             elen - Dloc->DataLoc.Offset,
1652             Dloc->DataLoc.Length));
1653         UDFSetFileSize(FileInfo, t);
1654         if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
1655             ExtPrint(("  w2k-compat -> rebuild allocs\n"));
1656             Dloc->DataLoc.Modified = TRUE;
1657         } else
1658         if((ULONG)((elen+Vcb->LBlockSize-1) >> Vcb->LBlockSizeBits) != (ULONG)((t+Vcb->LBlockSize-1) >> Vcb->LBlockSizeBits)) {
1659             ExtPrint(("  LBS boundary crossed -> rebuild allocs\n"));
1660             Dloc->DataLoc.Modified = TRUE;
1661         }
1662         Dloc->DataLoc.Length = t;
1663         return UDFWriteExtent(Vcb, &(Dloc->DataLoc), Offset, Length, Direct, Buffer, WrittenBytes);
1664     }
1665     // We should not get here if Direct=TRUE
1666     if(Direct) return STATUS_INVALID_PARAMETER;
1667     OldLen = Dloc->DataLoc.Length;
1668     if(Dloc->DataLoc.Offset && Dloc->DataLoc.Length) {
1669         // read in-icb data. it'll be replaced after resize
1670         ExtPrint(("  read in-icb data\n"));
1671         OldInIcb = (int8*)MyAllocatePool__(NonPagedPool, (uint32)(Dloc->DataLoc.Length));
1672         if(!OldInIcb) return STATUS_INSUFFICIENT_RESOURCES;
1673         status = UDFReadExtent(Vcb, &(Dloc->DataLoc), 0, (uint32)OldLen, FALSE, OldInIcb, &ReadBytes);
1674         if(!OS_SUCCESS(status)) {
1675             MyFreePool__(OldInIcb);
1676             return status;
1677         }
1678     }
1679     // init Alloc mode
1680     ExtPrint(("  init Alloc mode\n"));
1681     if((((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) {
1682         ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK;
1683         ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= Vcb->DefaultAllocMode;
1684         WasInIcb = TRUE;
1685     }
1686     // increase extent
1687     ExtPrint(("  %s %s %s\n",
1688         UDFIsADirectory(FileInfo) ? "DIR" : "FILE",
1689         WasInIcb ? "In-Icb" : "",
1690         Vcb->LowFreeSpace ? "LowSpace" : ""));
1691     if(UDFIsADirectory(FileInfo) && !WasInIcb && !Vcb->LowFreeSpace) {
1692         FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_ALLOC_SEQUENTIAL;
1693         status = UDFResizeExtent(Vcb, PartNum, (t*2+Vcb->WriteBlockSize-1) & ~(SIZE_T)(Vcb->WriteBlockSize-1), FALSE, &(Dloc->DataLoc));
1694         if(OS_SUCCESS(status)) {
1695             AdPrint(("  preallocated space for Dir\n"));
1696             FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_PREALLOCATED;
1697             //UDFSetFileSize(FileInfo, t);
1698             Dloc->DataLoc.Length = t;
1699         } else
1700         if(status == STATUS_DISK_FULL) {
1701             status = UDFResizeExtent(Vcb, PartNum, t, FALSE, &(Dloc->DataLoc));
1702         }
1703     } else {
1704         status = UDFResizeExtent(Vcb, PartNum, t, FALSE, &(Dloc->DataLoc));
1705     }
1706     ExtPrint(("  DataLoc Offs %x, Len %I64x\n",
1707         Dloc->DataLoc.Offset, Dloc->DataLoc.Length));
1708     AdPrint(("UDFWriteFile__ (2) FileInfo %x, ExtInfo %x, Mapping %x\n", FileInfo, &(Dloc->DataLoc), Dloc->DataLoc.Mapping));
1709     if(!OS_SUCCESS(status)) {
1710         // rollback
1711         ExtPrint(("  err -> rollback\n"));
1712         if(WasInIcb) {
1713             // restore Alloc mode
1714             ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK;
1715             ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= ICB_FLAG_AD_IN_ICB;
1716             if(Dloc->AllocLoc.Mapping) {
1717                 MyFreePool__(Dloc->AllocLoc.Mapping);
1718                 Dloc->AllocLoc.Mapping = NULL;
1719             }
1720         }
1721         if(OldInIcb) {
1722             MyFreePool__(OldInIcb);
1723             UDFWriteExtent(Vcb, &(Dloc->DataLoc), 0, (uint32)OldLen, FALSE, OldInIcb, &_WrittenBytes);
1724         }
1725         if((int64)OldLen != Dloc->DataLoc.Length) {
1726             // restore file size
1727             AdPrint(("  restore alloc\n"));
1728             FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_CUT_PREALLOCATED;
1729             UDFResizeExtent(Vcb, PartNum, OldLen, FALSE, &(Dloc->DataLoc));
1730             FileInfo->Dloc->DataLoc.Flags &= ~EXTENT_FLAG_CUT_PREALLOCATED;
1731         }
1732         return status;
1733     }
1734     if(OldInIcb) {
1735         // replace data from ICB (if any) & free buffer
1736         ExtPrint(("  write old in-icd data\n"));
1737         status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), 0, (uint32)OldLen, FALSE, OldInIcb, &_WrittenBytes);
1738         MyFreePool__(OldInIcb);
1739         if(!OS_SUCCESS(status))
1740             return status;
1741     }
1742     // ufff...
1743     // & now we'll write out data to well prepared extent...
1744     // ... like all normal people do...
1745     ExtPrint(("  write user data\n"));
1746     if(!OS_SUCCESS(status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), Offset, Length, FALSE, Buffer, WrittenBytes)))
1747         return status;
1748     UDFSetFileSize(FileInfo, t);
1749     Dloc->DataLoc.Modified = TRUE;
1750 #ifdef UDF_DBG
1751     if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
1752         ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping));
1753     } else {
1754         ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) ==
1755                ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)));
1756     }
1757 #endif // UDF_DBG
1758     return STATUS_SUCCESS;
1759 } // end UDFWriteFile__()
1760 
1761 /*
1762     This routine marks file as deleted & decrements file link counter.
1763     It can optionaly free allocation space
1764  */
1765 OSSTATUS
1766 UDFUnlinkFile__(
1767     IN PVCB Vcb,
1768     IN PUDF_FILE_INFO FileInfo,
1769     IN BOOLEAN FreeSpace
1770     )
1771 {
1772     uint_di Index;   // index of file to be deleted
1773     uint16 lc;
1774     PUDF_DATALOC_INFO Dloc;
1775     PUDF_FILE_INFO DirInfo;
1776     PUDF_FILE_INFO SDirInfo;
1777     PDIR_INDEX_HDR hDirNdx;
1778     PDIR_INDEX_HDR hCurDirNdx;
1779     PDIR_INDEX_ITEM DirNdx;
1780     OSSTATUS status;
1781     BOOLEAN IsSDir;
1782 
1783     AdPrint(("UDFUnlinkFile__:\n"));
1784     if(!FileInfo) return STATUS_SUCCESS;
1785 
1786     ValidateFileInfo(FileInfo);
1787 
1788 #ifndef _CONSOLE
1789     // now we can't call this if there is no OS-specific File Desc. present
1790     if(FileInfo->Fcb)
1791         UDFRemoveFileId__(Vcb, FileInfo);
1792 #endif //_CONSOLE
1793     // check references
1794     Dloc = FileInfo->Dloc;
1795     if((FileInfo->OpenCount /*> (uint32)(UDFHasAStreamDir(FileInfo) ? 1 : 0)*/) ||
1796        (FileInfo->RefCount>1)) return STATUS_CANNOT_DELETE;
1797     if(Dloc->SDirInfo)
1798         return STATUS_CANNOT_DELETE;
1799     ASSERT(FileInfo->RefCount == 1);
1800     DirInfo = FileInfo->ParentFile;
1801     // root dir or self
1802     if(!DirInfo || ((FileInfo->Index < 2) && !UDFIsAStreamDir(FileInfo))) return STATUS_CANNOT_DELETE;
1803     hDirNdx = DirInfo->Dloc->DirIndex;
1804     Index = FileInfo->Index;
1805     // we can't delete modified file
1806     // it should be closed & reopened (or flushed) before deletion
1807     DirNdx = UDFDirIndex(hDirNdx,Index);
1808 #if defined UDF_DBG || defined PRINT_ALWAYS
1809     if(DirNdx && DirNdx->FName.Buffer) {
1810         AdPrint(("Unlink: %ws\n",DirNdx->FName.Buffer));
1811     }
1812 #endif // UDF_DBG
1813     if(FreeSpace &&
1814        ((Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) ||
1815          Dloc->DataLoc.Modified ||
1816          Dloc->AllocLoc.Modified ||
1817          Dloc->FELoc.Modified ||
1818         (DirNdx && (DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) )) {
1819 //        BrutePoint();
1820         return STATUS_CANNOT_DELETE;
1821     }
1822     SDirInfo = Dloc->SDirInfo;
1823 /*    if(FreeSpace && SDirInfo) {
1824         UDFPrint(("Unlink: SDirInfo should be NULL !!!\n"));
1825         BrutePoint();
1826         return STATUS_CANNOT_DELETE;
1827     }*/
1828     // stream directory can be deleted even being not empty
1829     // otherwise we should perform some checks
1830     if(!(IsSDir = UDFIsAStreamDir(FileInfo))) {
1831         // check if not empty direcory
1832         if((DirNdx->FileCharacteristics & FILE_DIRECTORY) &&
1833            (hCurDirNdx = Dloc->DirIndex) &&
1834             FreeSpace) {
1835             if(!UDFIsDirEmpty(hCurDirNdx))
1836                 return STATUS_DIRECTORY_NOT_EMPTY;
1837         }
1838         DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
1839         DirNdx->FileCharacteristics |= FILE_DELETED;
1840         FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED;
1841         hDirNdx->DelCount++;
1842         UDFChangeFileCounter(Vcb, !UDFIsADirectory(FileInfo), FALSE);
1843     }
1844     UDFDecFileLinkCount(FileInfo); // decrease
1845     lc = UDFGetFileLinkCount(FileInfo);
1846     if(DirNdx && FreeSpace) {
1847         // FileIdent marked as 'deleted' should have an empty ICB
1848         // We shall do it only if object has parent Dir
1849         // (for ex. SDir has parent object, but has no parent Dir)
1850         DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
1851         DirNdx->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR;
1852         // Root Files (Root/SDir/Vat/etc.) has no FileIdent...
1853         if(FileInfo->FileIdent)
1854             RtlZeroMemory(&(FileInfo->FileIdent->icb), sizeof(long_ad));
1855     }
1856     // caller wishes to free allocation, but we can't do it due to
1857     // alive links. In this case we should just remove reference
1858     if(FreeSpace && lc) {
1859         ((icbtag*)(Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum = 0;
1860         ((icbtag*)(Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum = 0;
1861         Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1862     } else
1863     // if caller wishes to free file allocation &
1864     // there are no more references(links) to this file, lets do it >;->
1865     if(FreeSpace && !lc) {
1866         if(UDFHasAStreamDir(FileInfo) &&
1867            !UDFIsSDirDeleted(Dloc->SDirInfo) ) {
1868             // we have a Stream Dir associated...
1869             PUDF_FILE_INFO SFileInfo;
1870             // ... try to open it
1871             if(Dloc->SDirInfo) {
1872                 UDFFlushFile__(Vcb, FileInfo);
1873                 return STATUS_CANNOT_DELETE;
1874             }
1875             // open SDir
1876             status = UDFOpenStreamDir__(Vcb, FileInfo, &(Dloc->SDirInfo));
1877             if(!OS_SUCCESS(status)) {
1878                 // abort Unlink on error
1879                 SFileInfo = Dloc->SDirInfo;
1880 cleanup_SDir:
1881                 UDFCleanUpFile__(Vcb, SFileInfo);
1882                 if(SFileInfo) MyFreePool__(SFileInfo);
1883                 UDFFlushFile__(Vcb, FileInfo);
1884                 return status;
1885             }
1886             SDirInfo = Dloc->SDirInfo;
1887             // try to perform deltree for Streams
1888             status = UDFUnlinkAllFilesInDir(Vcb, SDirInfo);
1889             if(!OS_SUCCESS(status)) {
1890                 // abort Unlink on error
1891                 UDFCloseFile__(Vcb, SDirInfo);
1892                 SFileInfo = SDirInfo;
1893                 BrutePoint();
1894                 goto cleanup_SDir;
1895             }
1896             // delete SDir
1897             UDFFlushFile__(Vcb, SDirInfo);
1898             AdPrint(("  "));
1899             UDFUnlinkFile__(Vcb, SDirInfo, TRUE);
1900             // close SDir
1901             UDFCloseFile__(Vcb, SDirInfo);
1902             if(UDFCleanUpFile__(Vcb, SDirInfo)) {
1903                 MyFreePool__(SDirInfo);
1904 #ifdef UDF_DBG
1905             } else {
1906                 BrutePoint();
1907 #endif // UDF_DBG
1908             }
1909             // update FileInfo
1910             ASSERT(Dloc->FileEntry);
1911             RtlZeroMemory( &(((PEXTENDED_FILE_ENTRY)(Dloc->FileEntry))->streamDirectoryICB), sizeof(long_ad));
1912             FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1913         } else
1914         if(IsSDir) {
1915             // do deltree for Streams
1916             status = UDFUnlinkAllFilesInDir(Vcb, FileInfo);
1917             if(!OS_SUCCESS(status)) {
1918                 UDFFlushFile__(Vcb, FileInfo);
1919                 return status;
1920             }
1921             // update parent FileInfo
1922             ASSERT(FileInfo->ParentFile->Dloc->FileEntry);
1923             RtlZeroMemory( &(((PEXTENDED_FILE_ENTRY)(FileInfo->ParentFile->Dloc->FileEntry))->streamDirectoryICB), sizeof(long_ad));
1924             FileInfo->ParentFile->Dloc->FE_Flags &= ~UDF_FE_FLAG_HAS_SDIR;
1925             FileInfo->ParentFile->Dloc->FE_Flags |= (UDF_FE_FLAG_FE_MODIFIED |
1926                                                      UDF_FE_FLAG_HAS_DEL_SDIR);
1927             FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_IS_DEL_SDIR;
1928             UDFDecFileLinkCount(FileInfo->ParentFile);
1929         }
1930         if(Dloc->DirIndex) {
1931             UDFFlushFESpace(Vcb, Dloc, FLUSH_FE_FOR_DEL);
1932         }
1933         // flush file
1934         UDFFlushFile__(Vcb, FileInfo);
1935         UDFUnlinkDloc(Vcb, Dloc);
1936         // free allocation
1937         UDFFreeFileAllocation(Vcb, DirInfo, FileInfo);
1938         ASSERT(!(FileInfo->Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED));
1939         FileInfo->Dloc->FE_Flags &= ~UDF_FE_FLAG_FE_MODIFIED;
1940     }
1941     return STATUS_SUCCESS;
1942 } // end UDFUnlinkFile__()
1943 
1944 OSSTATUS
1945 UDFUnlinkAllFilesInDir(
1946     IN PVCB Vcb,
1947     IN PUDF_FILE_INFO DirInfo
1948     )
1949 {
1950     PDIR_INDEX_HDR hCurDirNdx;
1951     PDIR_INDEX_ITEM CurDirNdx;
1952     PUDF_FILE_INFO FileInfo;
1953     OSSTATUS status;
1954     uint_di i;
1955 
1956     hCurDirNdx = DirInfo->Dloc->DirIndex;
1957     // check if we can delete all files
1958     for(i=2; (CurDirNdx = UDFDirIndex(hCurDirNdx,i)); i++) {
1959         // try to open Stream
1960         if(CurDirNdx->FileInfo)
1961             return STATUS_CANNOT_DELETE;
1962     }
1963     // start deletion
1964     for(i=2; (CurDirNdx = UDFDirIndex(hCurDirNdx,i)); i++) {
1965         // try to open Stream
1966         status = UDFOpenFile__(Vcb, FALSE, TRUE, NULL, DirInfo, &FileInfo, &i);
1967         if(status == STATUS_FILE_DELETED) {
1968             // we should not release on-disk allocation for
1969             // deleted streams twice
1970             if(CurDirNdx->FileInfo) {
1971                 BrutePoint();
1972                 goto err_del_stream;
1973             }
1974             goto skip_del_stream;
1975         } else
1976         if(!OS_SUCCESS(status)) {
1977             // Error :(((
1978 err_del_stream:
1979             UDFCleanUpFile__(Vcb, FileInfo);
1980             if(FileInfo)
1981                 MyFreePool__(FileInfo);
1982             return status;
1983         }
1984 
1985         UDFFlushFile__(Vcb, FileInfo);
1986         AdPrint(("    "));
1987         UDFUnlinkFile__(Vcb, FileInfo, TRUE);
1988         UDFCloseFile__(Vcb, FileInfo);
1989 skip_del_stream:
1990         if(FileInfo && UDFCleanUpFile__(Vcb, FileInfo)) {
1991             MyFreePool__(FileInfo);
1992         }
1993     }
1994     return STATUS_SUCCESS;
1995 } // end UDFUnlinkAllFilesInDir()
1996 #endif //UDF_READ_ONLY_BUILD
1997 
1998 /*
1999     This routine inits UDF_FILE_INFO structure for specified file
2000     If it returns status != STATUS_SUCCESS caller should call UDFCleanUpFile__
2001     for returned pointer *WITHOUT* using UDFCloseFile__
2002  */
2003 OSSTATUS
2004 UDFOpenFile__(
2005     IN PVCB Vcb,
2006     IN BOOLEAN IgnoreCase,
2007     IN BOOLEAN NotDeleted,
2008     IN PUNICODE_STRING fn,
2009     IN PUDF_FILE_INFO DirInfo,
2010     OUT PUDF_FILE_INFO* _FileInfo,// this is to be filled & doesn't contain
2011                                 // any pointers
2012     IN uint_di* IndexToOpen
2013     )
2014 {
2015     OSSTATUS status;
2016     uint_di i=0;
2017     EXTENT_AD FEExt;
2018     uint16 Ident;
2019     PDIR_INDEX_HDR hDirNdx = DirInfo->Dloc->DirIndex;
2020     PDIR_INDEX_ITEM DirNdx;
2021     PUDF_FILE_INFO FileInfo;
2022     PUDF_FILE_INFO ParFileInfo;
2023     SIZE_T ReadBytes;
2024     *_FileInfo = NULL;
2025     if(!hDirNdx) return STATUS_NOT_A_DIRECTORY;
2026 
2027     // find specified file in directory index
2028     // if it is already known, skip this foolish code
2029     if(IndexToOpen) {
2030         i=*IndexToOpen;
2031     } else
2032         if(!OS_SUCCESS(status = UDFFindFile(Vcb, IgnoreCase, NotDeleted, fn, DirInfo, &i)))
2033             return status;
2034     // do this check for OpenByIndex
2035     // some routines may send invalid Index
2036     if(!(DirNdx = UDFDirIndex(hDirNdx,i)))
2037         return STATUS_OBJECT_NAME_NOT_FOUND;
2038     if((FileInfo = DirNdx->FileInfo)) {
2039         // file is already opened.
2040         if((DirNdx->FileCharacteristics & FILE_DELETED) && NotDeleted) {
2041             AdPrint(("  FILE_DELETED on open\n"));
2042             return STATUS_FILE_DELETED;
2043         }
2044         if((FileInfo->ParentFile != DirInfo) &&
2045            (FileInfo->Index >= 2)) {
2046             ParFileInfo = UDFLocateParallelFI(DirInfo, i, FileInfo);
2047             BrutePoint();
2048             if(ParFileInfo->ParentFile != DirInfo) {
2049                 FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_FINF_TAG);
2050                 *_FileInfo = FileInfo;
2051                 if(!FileInfo) return STATUS_INSUFFICIENT_RESOURCES;
2052                 RtlCopyMemory(FileInfo, DirNdx->FileInfo, sizeof(UDF_FILE_INFO));
2053     //          FileInfo->NextLinkedFile = DirNdx->FileInfo->NextLinkedFile; // is already done
2054                 UDFInsertLinkedFile(FileInfo, DirNdx->FileInfo);
2055                 DirNdx->FI_Flags |= UDF_FI_FLAG_LINKED;
2056                 FileInfo->RefCount = 0;
2057                 FileInfo->ParentFile = DirInfo;
2058                 FileInfo->Fcb = NULL;
2059             } else {
2060                 FileInfo = ParFileInfo;
2061             }
2062         }
2063         // Just increase some counters & exit
2064         UDFReferenceFile__(FileInfo);
2065 
2066         ASSERT(FileInfo->ParentFile == DirInfo);
2067         ValidateFileInfo(FileInfo);
2068 
2069         *_FileInfo = FileInfo;
2070         return STATUS_SUCCESS;
2071     } else
2072     if(IndexToOpen) {
2073         if((DirNdx->FileCharacteristics & FILE_DELETED) && NotDeleted) {
2074             AdPrint(("  FILE_DELETED on open (2)\n"));
2075             return STATUS_FILE_DELETED;
2076         }
2077     }
2078     FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_FINF_TAG);
2079     *_FileInfo = FileInfo;
2080     if(!FileInfo) return STATUS_INSUFFICIENT_RESOURCES;
2081     RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO));
2082     // init horizontal links
2083     FileInfo->NextLinkedFile =
2084     FileInfo->PrevLinkedFile = FileInfo;
2085     // read FileIdent
2086     FileInfo->FileIdent = (PFILE_IDENT_DESC)MyAllocatePoolTag__(NonPagedPool, DirNdx->Length, MEM_FID_TAG);
2087     if(!(FileInfo->FileIdent)) return STATUS_INSUFFICIENT_RESOURCES;
2088     FileInfo->FileIdentLen = DirNdx->Length;
2089     if(!OS_SUCCESS(status = UDFReadExtent(Vcb, &(DirInfo->Dloc->DataLoc), DirNdx->Offset,
2090                              DirNdx->Length, FALSE, (int8*)(FileInfo->FileIdent), &ReadBytes) ))
2091         return status;
2092     if(FileInfo->FileIdent->descTag.tagIdent != TID_FILE_IDENT_DESC) {
2093         BrutePoint();
2094         return STATUS_FILE_CORRUPT_ERROR;
2095     }
2096     // check for opened links
2097     if(!OS_SUCCESS(status = UDFStoreDloc(Vcb, FileInfo, UDFPartLbaToPhys(Vcb, &(FileInfo->FileIdent->icb.extLocation)))))
2098         return status;
2099     // init pointer to parent object
2100     FileInfo->Index = i;
2101     FileInfo->ParentFile = DirInfo;
2102     // init pointers to linked files (if any)
2103     if(FileInfo->Dloc->LinkedFileInfo != FileInfo)
2104         UDFInsertLinkedFile(FileInfo, FileInfo->Dloc->LinkedFileInfo);
2105     if(FileInfo->Dloc->FileEntry)
2106         goto init_tree_entry;
2107     // read (Ex)FileEntry
2108     FileInfo->Dloc->FileEntry = (tag*)MyAllocatePoolTag__(NonPagedPool, Vcb->LBlockSize, MEM_FE_TAG);
2109     if(!(FileInfo->Dloc->FileEntry)) return STATUS_INSUFFICIENT_RESOURCES;
2110     if(!OS_SUCCESS(status = UDFReadFileEntry(Vcb, &(FileInfo->FileIdent->icb), (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &Ident)))
2111         return status;
2112     // build mappings for Data & AllocDescs
2113     if(!FileInfo->Dloc->AllocLoc.Mapping) {
2114         FEExt.extLength = FileInfo->FileIdent->icb.extLength;
2115         FEExt.extLocation = UDFPartLbaToPhys(Vcb, &(FileInfo->FileIdent->icb.extLocation) );
2116         if(FEExt.extLocation == LBA_OUT_OF_EXTENT)
2117             return STATUS_FILE_CORRUPT_ERROR;
2118         FileInfo->Dloc->AllocLoc.Mapping = UDFExtentToMapping(&FEExt);
2119         if(!(FileInfo->Dloc->AllocLoc.Mapping))
2120             return STATUS_INSUFFICIENT_RESOURCES;
2121     }
2122     // read location info
2123     status = UDFLoadExtInfo(Vcb, (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &(FileInfo->FileIdent->icb),
2124                            &(FileInfo->Dloc->DataLoc), &(FileInfo->Dloc->AllocLoc) );
2125     if(!OS_SUCCESS(status))
2126         return status;
2127     // init (Ex)FileEntry mapping
2128     FileInfo->Dloc->FELoc.Length = (FileInfo->Dloc->DataLoc.Offset) ? FileInfo->Dloc->DataLoc.Offset :
2129                                                           FileInfo->Dloc->AllocLoc.Offset;
2130 //    FileInfo->Dloc->FELoc.Offset = 0;
2131     FileInfo->Dloc->FELoc.Mapping = UDFExtentToMapping(&FEExt);
2132     FileInfo->Dloc->FileEntryLen = (uint32)(FileInfo->Dloc->FELoc.Length);
2133     // we get here immediately when opened link encountered
2134 init_tree_entry:
2135     // init back pointer from parent object
2136     ASSERT(!DirNdx->FileInfo);
2137     DirNdx->FileInfo = FileInfo;
2138     // init DirIndex
2139     if(UDFGetFileLinkCount(FileInfo) > 1) {
2140         DirNdx->FI_Flags |= UDF_FI_FLAG_LINKED;
2141     } else {
2142         DirNdx->FI_Flags &= ~UDF_FI_FLAG_LINKED;
2143     }
2144     // resize FE cache (0x800 instead of 0x40 is not a good idea)
2145     if(!MyReallocPool__((int8*)((FileInfo->Dloc->FileEntry)), Vcb->LBlockSize,
2146                      (int8**)&((FileInfo->Dloc->FileEntry)), FileInfo->Dloc->FileEntryLen))
2147         return STATUS_INSUFFICIENT_RESOURCES;
2148     // check if this file has a SDir
2149     if((FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY) &&
2150        ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLength )
2151         FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_HAS_SDIR;
2152     if(!(FileInfo->FileIdent->fileCharacteristics & FILE_DIRECTORY)) {
2153         UDFReferenceFile__(FileInfo);
2154         ASSERT(FileInfo->ParentFile == DirInfo);
2155         UDFReleaseDloc(Vcb, FileInfo->Dloc);
2156         return STATUS_SUCCESS;
2157     }
2158 
2159     UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used
2160 
2161     // build index for directories
2162     if(!FileInfo->Dloc->DirIndex) {
2163         status = UDFIndexDirectory(Vcb, FileInfo);
2164         if(!OS_SUCCESS(status))
2165             return status;
2166 #ifndef UDF_READ_ONLY_BUILD
2167         if((FileInfo->Dloc->DirIndex->DelCount > Vcb->PackDirThreshold) &&
2168            !(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)) {
2169             status = UDFPackDirectory__(Vcb, FileInfo);
2170             if(!OS_SUCCESS(status))
2171                 return status;
2172         }
2173 #endif //UDF_READ_ONLY_BUILD
2174     }
2175     UDFReferenceFile__(FileInfo);
2176     UDFReleaseDloc(Vcb, FileInfo->Dloc);
2177     ASSERT(FileInfo->ParentFile == DirInfo);
2178 
2179     return status;
2180 } // end UDFOpenFile__()
2181 
2182 
2183 /*
2184     This routine inits UDF_FILE_INFO structure for root directory
2185  */
2186 OSSTATUS
2187 UDFOpenRootFile__(
2188     IN PVCB Vcb,
2189     IN lb_addr* RootLoc,
2190     OUT PUDF_FILE_INFO FileInfo
2191     )
2192 {
2193     uint32 RootLBA;
2194     OSSTATUS status;
2195 //    uint32 PartNum = RootLoc->partitionReferenceNum;
2196     uint32 LBS = Vcb->LBlockSize;
2197     uint16 Ident;
2198     LONG_AD FELoc;
2199     EXTENT_AD FEExt;
2200     uint8 FileType;
2201 
2202     RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO));
2203     RootLBA = UDFPartLbaToPhys(Vcb,RootLoc);
2204     if(RootLBA == LBA_OUT_OF_EXTENT)
2205         return STATUS_FILE_CORRUPT_ERROR;
2206     FELoc.extLocation = *RootLoc;
2207     FELoc.extLength = LBS;
2208     // init horizontal links
2209     FileInfo->NextLinkedFile =
2210     FileInfo->PrevLinkedFile = FileInfo;
2211     // check for opened links
2212     if(!OS_SUCCESS(status = UDFStoreDloc(Vcb, FileInfo, RootLBA)))
2213         return status;
2214     if(FileInfo->Dloc->FileEntry)
2215         goto init_tree_entry;
2216     // read (Ex)FileEntry
2217     FileInfo->Dloc->FileEntry = (tag*)MyAllocatePoolTag__(NonPagedPool, LBS, MEM_FE_TAG);
2218     if(!(FileInfo->Dloc->FileEntry)) return STATUS_INSUFFICIENT_RESOURCES;
2219 
2220     if(!OS_SUCCESS(status = UDFReadFileEntry(Vcb, &FELoc, (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &Ident)))
2221         return status;
2222     // build mappings for Data & AllocDescs
2223     FEExt.extLength = LBS;
2224     FEExt.extLocation = UDFPartLbaToPhys(Vcb, &(FELoc.extLocation) );
2225     if(FEExt.extLocation == LBA_OUT_OF_EXTENT)
2226         return STATUS_FILE_CORRUPT_ERROR;
2227     FileInfo->Dloc->FELoc.Mapping = UDFExtentToMapping(&FEExt);
2228     if(!(FileInfo->Dloc->FELoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES;
2229     // build mappings for AllocDescs
2230     if(!FileInfo->Dloc->AllocLoc.Mapping) {
2231         FileInfo->Dloc->AllocLoc.Mapping = UDFExtentToMapping(&FEExt);
2232         if(!(FileInfo->Dloc->AllocLoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES;
2233     }
2234     if(!OS_SUCCESS(status = UDFLoadExtInfo(Vcb, (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &FELoc,
2235                        &(FileInfo->Dloc->DataLoc), &(FileInfo->Dloc->AllocLoc) ) ))
2236         return status;
2237     FileInfo->Dloc->FileEntryLen = (uint32)
2238     (FileInfo->Dloc->FELoc.Length = (FileInfo->Dloc->DataLoc.Offset) ? FileInfo->Dloc->DataLoc.Offset :
2239                                                           FileInfo->Dloc->AllocLoc.Offset);
2240 init_tree_entry:
2241     // resize FE cache (0x800 instead of 0x40 is not a good idea)
2242     if(!MyReallocPool__((int8*)((FileInfo->Dloc->FileEntry)), LBS,
2243                      (int8**)&((FileInfo->Dloc->FileEntry)), FileInfo->Dloc->FileEntryLen))
2244         return STATUS_INSUFFICIENT_RESOURCES;
2245     // init DirIndex
2246     if( (FileType = ((icbtag*)((FileInfo->Dloc->FileEntry)+1))->fileType) != UDF_FILE_TYPE_DIRECTORY &&
2247         (FileType != UDF_FILE_TYPE_STREAMDIR) ) {
2248         UDFReferenceFile__(FileInfo);
2249         UDFReleaseDloc(Vcb, FileInfo->Dloc);
2250         return STATUS_SUCCESS;
2251     }
2252     // build index for directories
2253     if(!FileInfo->Dloc->DirIndex) {
2254         status = UDFIndexDirectory(Vcb, FileInfo);
2255         if(!OS_SUCCESS(status))
2256             return status;
2257 #ifndef UDF_READ_ONLY_BUILD
2258         if((FileInfo->Dloc->DirIndex->DelCount > Vcb->PackDirThreshold) &&
2259            !(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)) {
2260             status = UDFPackDirectory__(Vcb, FileInfo);
2261             if(!OS_SUCCESS(status))
2262                 return status;
2263         }
2264 #endif //UDF_READ_ONLY_BUILD
2265     }
2266     UDFReferenceFile__(FileInfo);
2267     UDFReleaseDloc(Vcb, FileInfo->Dloc);
2268 
2269     return status;
2270 } // end UDFOpenRootFile__()
2271 
2272 /*
2273     This routine frees all memory blocks referenced by given FileInfo
2274  */
2275 uint32
2276 UDFCleanUpFile__(
2277     IN PVCB Vcb,
2278     IN PUDF_FILE_INFO FileInfo
2279     )
2280 {
2281     PUDF_DATALOC_INFO Dloc;
2282     uint32 lc = 0;
2283     BOOLEAN IsASDir;
2284     BOOLEAN KeepDloc;
2285     PDIR_INDEX_ITEM DirNdx, DirNdx2;
2286     BOOLEAN Parallel = FALSE;
2287     BOOLEAN Linked = FALSE;
2288 #ifdef UDF_DBG
2289     BOOLEAN Modified = FALSE;
2290     PDIR_INDEX_HDR hDirNdx;
2291     uint_di Index;
2292     PUDF_FILE_INFO DirInfo;
2293 #endif // UDF_DBG
2294 
2295     if(!FileInfo) return UDF_FREE_FILEINFO;
2296 
2297     ValidateFileInfo(FileInfo);
2298 
2299     if(FileInfo->OpenCount || FileInfo->RefCount) {
2300         UDFPrint(("UDF: not all references are closed\n"));
2301         UDFPrint(("     Skipping cleanup\n"));
2302         UDFPrint(("UDF: OpenCount = %x, RefCount = %x, LinkRefCount = %x\n",
2303                               FileInfo->OpenCount,FileInfo->RefCount,FileInfo->Dloc->LinkRefCount));
2304         return UDF_FREE_NOTHING;
2305     }
2306     if(FileInfo->Fcb) {
2307         UDFPrint(("Operating System still has references to this file\n"));
2308         UDFPrint(("     Skipping cleanup\n"));
2309 //        BrutePoint();
2310         return UDF_FREE_NOTHING;
2311     }
2312 
2313     IsASDir = UDFIsAStreamDir(FileInfo);
2314 
2315     if((Dloc = FileInfo->Dloc)) {
2316 
2317 #ifdef UDF_DBG
2318         DirInfo = FileInfo->ParentFile;
2319         if(DirInfo) {
2320             hDirNdx = DirInfo->Dloc->DirIndex;
2321             Index = FileInfo->Index;
2322             // we can't delete modified file
2323             // it should be closed & reopened (or flushed) before deletion
2324             DirNdx = UDFDirIndex(hDirNdx,Index);
2325             UDFPrint(("Cleanup Mod: %s%s%s%s%s%s\n",
2326                                  (Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) ? "FE "       : "",
2327                                  (Dloc->DataLoc.Modified)                   ? "DataLoc "  : "",
2328                                  (Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) ? "Data-PreAlloc " : "",
2329                                  (Dloc->AllocLoc.Modified)                  ? "AllocLoc " : "",
2330                                  (Dloc->FELoc.Modified)                     ? "FELoc "    : "",
2331                                  (DirNdx && (DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) ? "FI " : ""
2332                                  ));
2333             Modified = ((Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) ||
2334                          Dloc->DataLoc.Modified ||
2335                         (Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) ||
2336                          Dloc->AllocLoc.Modified ||
2337                          Dloc->FELoc.Modified ||
2338                         (DirNdx && (DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) );
2339         }
2340 #endif // UDF_DBG
2341 
2342         PUDF_FILE_INFO ParFileInfo = UDFLocateAnyParallelFI(FileInfo);
2343 
2344         Parallel = (ParFileInfo != NULL);
2345         Linked = (FileInfo->NextLinkedFile != FileInfo);
2346 
2347 //        Parallel = (FileInfo->NextLinkedFile != FileInfo);
2348         ASSERT(FileInfo->NextLinkedFile);
2349 //        ASSERT(!Parallel);
2350         KeepDloc = (Dloc->LinkRefCount ||
2351                     Dloc->CommonFcb ||
2352                     Linked ) ?
2353                     TRUE : FALSE;
2354 
2355         if(Dloc->DirIndex) {
2356             uint_di i;
2357             for(i=2; (DirNdx = UDFDirIndex(Dloc->DirIndex,i)); i++) {
2358                 if(DirNdx->FileInfo) {
2359                     if(!KeepDloc) {
2360                         BrutePoint();
2361                         UDFPrint(("UDF: Found not cleaned up reference.\n"));
2362                         UDFPrint(("     Skipping cleanup (1)\n"));
2363 //                        BrutePoint();
2364                         return UDF_FREE_NOTHING;
2365                     }
2366                     // The file being cleaned up may have not closed Dirs
2367                     // (linked Dir). In this case each of them may have
2368                     // reference to FileInfo in DirIndex[1]
2369                     // Here we'll check it and change for valid value if
2370                     // necessary (Update Child Objects - I)
2371                     if(DirNdx->FileInfo->Dloc) {
2372                         // we can get here only when (Parallel == TRUE)
2373                         DirNdx2 = UDFDirIndex(DirNdx->FileInfo->Dloc->DirIndex, 1);
2374                         // It is enough to check DirNdx2->FileInfo only.
2375                         // If one of Parallel FI's has reference (and equal)
2376                         // to the FI being removed, it'll be removed from
2377                         // the chain & nothing wrong will happen.
2378                         if(DirNdx2 && (DirNdx2->FileInfo == FileInfo)) {
2379                             if(FileInfo->PrevLinkedFile == FileInfo) {
2380                                 BrutePoint();
2381                                 DirNdx2->FileInfo = NULL;
2382                             } else {
2383                                 DirNdx2->FileInfo = Parallel ?
2384                                     ParFileInfo : FileInfo->PrevLinkedFile;
2385                             }
2386                             ASSERT(!DirNdx2->FileInfo->RefCount);
2387                         }
2388                     }
2389                 }
2390             }
2391         }
2392         if(Dloc->SDirInfo) {
2393             UDFPrint(("UDF: Found not cleaned up reference (SDir).\n"));
2394 
2395             // (Update Child Objects - II)
2396             if(Dloc->SDirInfo->ParentFile == FileInfo) {
2397                 BrutePoint();
2398                 ASSERT(ParFileInfo);
2399                 Dloc->SDirInfo->ParentFile = ParFileInfo;
2400             }
2401             // We should break Cleanup process if alive reference detected
2402             // and there is no possibility to store pointer in some other
2403             // place (in parallel object)
2404             if(!KeepDloc) {
2405                 BrutePoint();
2406                 UDFPrint(("     Skipping cleanup\n"));
2407                 return UDF_FREE_NOTHING;
2408             }
2409 
2410             if(!UDFIsSDirDeleted(Dloc->SDirInfo) &&
2411                Dloc->SDirInfo->Dloc) {
2412                 DirNdx2 = UDFDirIndex(Dloc->SDirInfo->Dloc->DirIndex, 1);
2413                 if(DirNdx2 && (DirNdx2->FileInfo == FileInfo)) {
2414                     DirNdx2->FileInfo =
2415                         Parallel ? ParFileInfo : NULL;
2416                     ASSERT(!DirNdx2->FileInfo->RefCount);
2417                 }
2418             }
2419         }
2420 
2421         if(!KeepDloc) {
2422 
2423 #ifdef UDF_DBG
2424             ASSERT(!Modified);
2425 #endif
2426 
2427 #ifndef UDF_TRACK_ONDISK_ALLOCATION
2428             if(Dloc->DataLoc.Mapping)  MyFreePool__(Dloc->DataLoc.Mapping);
2429             if(Dloc->AllocLoc.Mapping) MyFreePool__(Dloc->AllocLoc.Mapping);
2430             if(Dloc->FELoc.Mapping)    MyFreePool__(Dloc->FELoc.Mapping);
2431             if(Dloc->FileEntry) {
2432                 // plain file
2433                 lc = UDFGetFileLinkCount(FileInfo);
2434                 MyFreePool__(Dloc->FileEntry);
2435                 Dloc->FileEntry = NULL;
2436             } else if(FileInfo->Index >= 2) {
2437                 // error durring open operation
2438                 lc = UDF_INVALID_LINK_COUNT;
2439             }
2440 #endif //UDF_TRACK_ONDISK_ALLOCATION
2441             if(FileInfo->Dloc->DirIndex) {
2442                 uint_di i;
2443                 for(i=2; (DirNdx = UDFDirIndex(Dloc->DirIndex,i)); i++) {
2444                     ASSERT(!DirNdx->FileInfo);
2445                     if(DirNdx->FName.Buffer)
2446                         MyFreePool__(DirNdx->FName.Buffer);
2447                 }
2448                 // The only place where we can free FE_Charge extent is here
2449                 UDFFlushFESpace(Vcb, Dloc);
2450                 UDFDirIndexFree(Dloc->DirIndex);
2451                 Dloc->DirIndex = NULL;
2452 #ifdef UDF_TRACK_ONDISK_ALLOCATION
2453                 UDFIndexDirectory(Vcb, FileInfo);
2454                 if(FileInfo->Dloc->DirIndex) {
2455                     for(i=2; DirNdx = UDFDirIndex(Dloc->DirIndex,i); i++) {
2456                         ASSERT(!DirNdx->FileInfo);
2457                         if(DirNdx->FName.Buffer)
2458                             MyFreePool__(DirNdx->FName.Buffer);
2459                     }
2460                     UDFDirIndexFree(Dloc->DirIndex);
2461                     Dloc->DirIndex = NULL;
2462                 }
2463 #endif //UDF_TRACK_ONDISK_ALLOCATION
2464             }
2465 
2466 #ifdef UDF_TRACK_ONDISK_ALLOCATION
2467             if(Dloc->AllocLoc.Mapping) MyFreePool__(Dloc->AllocLoc.Mapping);
2468             if(Dloc->FELoc.Mapping)    MyFreePool__(Dloc->FELoc.Mapping);
2469             if(Dloc->FileEntry) {
2470                 // plain file
2471                 lc = UDFGetFileLinkCount(FileInfo);
2472                 MyFreePool__(Dloc->FileEntry);
2473                 Dloc->FileEntry = NULL;
2474             } else if(FileInfo->Index >= 2) {
2475                 // error durring open operation
2476                 lc = UDF_INVALID_LINK_COUNT;
2477             }
2478             if(Dloc->DataLoc.Mapping) {
2479                 if(lc && (lc != UDF_INVALID_LINK_COUNT)) {
2480                     UDFCheckSpaceAllocation(Vcb, 0, Dloc->DataLoc.Mapping, AS_USED); // check if used
2481                 } else {
2482                     UDFCheckSpaceAllocation(Vcb, 0, Dloc->DataLoc.Mapping, AS_FREE); // check if free
2483                 }
2484                 MyFreePool__(Dloc->DataLoc.Mapping);
2485             }
2486 #endif //UDF_TRACK_ONDISK_ALLOCATION
2487 
2488             if(lc && (lc != UDF_INVALID_LINK_COUNT)) {
2489                 UDFRemoveDloc(Vcb, Dloc);
2490             } else {
2491                 UDFFreeDloc(Vcb, Dloc);
2492             }
2493         } else // KeepDloc cannot be FALSE if (Linked == TRUE)
2494         if(Linked) {
2495 //            BrutePoint();
2496             // Update pointers in ParentObject (if any)
2497             if(FileInfo->ParentFile->Dloc->SDirInfo == FileInfo)
2498                 FileInfo->ParentFile->Dloc->SDirInfo = FileInfo->PrevLinkedFile;
2499             DirNdx = UDFDirIndex(FileInfo->Dloc->DirIndex, 0);
2500             if(DirNdx && (DirNdx->FileInfo == FileInfo))
2501                 DirNdx->FileInfo = FileInfo->PrevLinkedFile;
2502             DirNdx = UDFDirIndex(FileInfo->ParentFile->Dloc->DirIndex, FileInfo->Index);
2503             if(DirNdx && (DirNdx->FileInfo == FileInfo))
2504                 DirNdx->FileInfo = ParFileInfo;
2505             // remove from linked chain
2506             FileInfo->NextLinkedFile->PrevLinkedFile = FileInfo->PrevLinkedFile;
2507             FileInfo->PrevLinkedFile->NextLinkedFile = FileInfo->NextLinkedFile;
2508             // update pointer in Dloc
2509             if(FileInfo->Dloc->LinkedFileInfo == FileInfo)
2510                 FileInfo->Dloc->LinkedFileInfo = FileInfo->PrevLinkedFile;
2511         }
2512         FileInfo->Dloc = NULL;
2513     } else {
2514         KeepDloc = FALSE;
2515     }
2516 
2517     // Cleanup pointers in ParentObject (if any)
2518     if(IsASDir) {
2519         if(FileInfo->ParentFile->Dloc->SDirInfo == FileInfo) {
2520             ASSERT(!Linked);
2521             FileInfo->ParentFile->Dloc->SDirInfo = NULL;
2522             FileInfo->ParentFile->Dloc->FE_Flags &= ~UDF_FE_FLAG_HAS_DEL_SDIR;
2523         }
2524     } else
2525     if(FileInfo->ParentFile) {
2526         ASSERT(FileInfo->ParentFile->Dloc);
2527         DirNdx = UDFDirIndex(FileInfo->ParentFile->Dloc->DirIndex, FileInfo->Index);
2528         ASSERT(DirNdx);
2529 #ifdef UDF_DBG
2530         PUDF_FILE_INFO OldFI;
2531         if(Parallel) {
2532             ASSERT(!DirNdx || !(OldFI = DirNdx->FileInfo) ||
2533                     !(OldFI == FileInfo));
2534         } else {
2535             ASSERT(!DirNdx || !(OldFI = DirNdx->FileInfo) ||
2536                      (OldFI == FileInfo));
2537         }
2538 #endif
2539         if( DirNdx && (DirNdx->FileInfo == FileInfo) ) {
2540             if(!Parallel)
2541                 DirNdx->FileInfo = NULL;
2542 #ifdef UDF_DBG
2543         } else {
2544             // We can get here after incomplete Open
2545             if(!Parallel && DirNdx->FileInfo)
2546                 BrutePoint();
2547 #endif
2548         }
2549 #ifdef UDF_DBG
2550     } else {
2551 //        BrutePoint();
2552 #endif
2553     }
2554 
2555     if(!Parallel && FileInfo->FileIdent)
2556         MyFreePool__(FileInfo->FileIdent);
2557     FileInfo->FileIdent = NULL;
2558     // Kill reference to parent object
2559     FileInfo->ParentFile = NULL;
2560     // Kill references to parallel object(s) since it has no reference to
2561     // this one now
2562     FileInfo->NextLinkedFile =
2563     FileInfo->PrevLinkedFile = FileInfo;
2564     if(FileInfo->ListPtr)
2565         FileInfo->ListPtr->FileInfo = NULL;;
2566     return KeepDloc ? UDF_FREE_FILEINFO : (UDF_FREE_FILEINFO | UDF_FREE_DLOC);
2567 } // end UDFCleanUpFile__()
2568 
2569 #ifndef UDF_READ_ONLY_BUILD
2570 /*
2571     This routine creates FileIdent record in destination directory &
2572     allocates FileEntry with in-ICB zero-sized data
2573     If it returns status != STATUS_SUCCESS caller should call UDFCleanUpFile__
2574     for returned pointer *WITHOUT* using UDFCloseFile__
2575  */
2576 OSSTATUS
2577 UDFCreateFile__(
2578     IN PVCB Vcb,
2579 //    IN uint16 AllocMode, // short/long/ext/in-icb  // always in-ICB
2580     IN BOOLEAN IgnoreCase,
2581     IN PUNICODE_STRING _fn,
2582     IN uint32 ExtAttrSz,
2583     IN uint32 ImpUseLen,
2584     IN BOOLEAN Extended,
2585     IN BOOLEAN CreateNew,
2586  IN OUT PUDF_FILE_INFO DirInfo,
2587     OUT PUDF_FILE_INFO* _FileInfo
2588     )
2589 {
2590     uint32 l, d;
2591     uint_di i, j;
2592     OSSTATUS status;
2593     LONG_AD FEicb;
2594     UDF_DIR_SCAN_CONTEXT ScanContext;
2595     PDIR_INDEX_HDR hDirNdx = DirInfo->Dloc->DirIndex;
2596     PDIR_INDEX_ITEM DirNdx;
2597     uint32 LBS = Vcb->LBlockSize;
2598     PUDF_FILE_INFO FileInfo;
2599     *_FileInfo = NULL;
2600     BOOLEAN undel = FALSE;
2601     SIZE_T ReadBytes;
2602 //    BOOLEAN PackDir = FALSE;
2603     BOOLEAN FEAllocated = FALSE;
2604 
2605     ValidateFileInfo(DirInfo);
2606     *_FileInfo = NULL;
2607 
2608     ASSERT(DirInfo->Dloc->FELoc.Mapping[0].extLocation);
2609     uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, DirInfo->Dloc->FELoc.Mapping[0].extLocation);
2610     if(!hDirNdx) return STATUS_NOT_A_DIRECTORY;
2611     i = 0;
2612 
2613     _SEH2_TRY {
2614 
2615         // check if exists
2616         status = UDFFindFile(Vcb, IgnoreCase, FALSE, _fn, DirInfo, &i);
2617         DirNdx = UDFDirIndex(hDirNdx,i);
2618         if(OS_SUCCESS(status)) {
2619             // file is a Cur(Parent)Dir
2620             if(i<2) try_return (status = STATUS_ACCESS_DENIED);
2621             // file deleted
2622             if(UDFIsDeleted(DirNdx)) {
2623                 j=0;
2624                 if(OS_SUCCESS(UDFFindFile(Vcb, IgnoreCase, TRUE, _fn, DirInfo, &j))) {
2625                    i=j;
2626                    DirNdx = UDFDirIndex(hDirNdx,i);
2627                    goto CreateBothFound;
2628                 }
2629                 // we needn't allocating new FileIdent inside Dir stream
2630                 // perform 'undel'
2631                 if(DirNdx->FileInfo) {
2632     //                BrutePoint();
2633                     status = UDFPretendFileDeleted__(Vcb, DirNdx->FileInfo);
2634                     if(!OS_SUCCESS(status))
2635                         try_return (status = STATUS_FILE_DELETED);
2636                 } else {
2637                     undel = TRUE;
2638                 }
2639     //            BrutePoint();
2640                 goto CreateUndel;
2641             }
2642 CreateBothFound:
2643             // file already exists
2644             if(CreateNew) try_return (status = STATUS_ACCESS_DENIED);
2645             // try to open it
2646             BrutePoint();
2647             status = UDFOpenFile__(Vcb, IgnoreCase, TRUE, _fn, DirInfo, _FileInfo,&i);
2648     //        *_FileInfo = FileInfo; // OpenFile__ has already done it, so update it...
2649             DirNdx = UDFDirIndex(hDirNdx,i);
2650             DirNdx->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR;
2651             FileInfo = *_FileInfo;
2652             if(!OS_SUCCESS(status)) {
2653                 // :(( can't open....
2654                 if(FileInfo && UDFCleanUpFile__(Vcb, FileInfo)) {
2655                     MyFreePool__(FileInfo);
2656                     *_FileInfo = NULL;
2657                 }
2658                 BrutePoint();
2659                 try_return (status);
2660             }
2661             // check if we can delete this file
2662             if(FileInfo->OpenCount || (FileInfo->RefCount > 1)) {
2663                 BrutePoint();
2664                 UDFCloseFile__(Vcb, FileInfo);
2665                 try_return (status = STATUS_CANNOT_DELETE);
2666             }
2667             BrutePoint();
2668             // remove DIRECTORY flag
2669             DirNdx->FileCharacteristics &= ~FILE_DIRECTORY;
2670             FileInfo->FileIdent->fileCharacteristics &= ~FILE_DIRECTORY;
2671             DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
2672             // truncate file size to ZERO
2673             status = UDFResizeFile__(Vcb, FileInfo, 0);
2674             if(!OS_SUCCESS(status)) {
2675                 BrutePoint();
2676                 UDFCloseFile__(Vcb, FileInfo);
2677             }
2678             // set NORMAL flag
2679             FileInfo->FileIdent->fileCharacteristics = 0;
2680             DirNdx->FileCharacteristics = 0;
2681             // update DeletedFiles counter in Directory... (for PackDir)
2682             if(undel && OS_SUCCESS(status))
2683                 hDirNdx->DelCount--;
2684             try_return (status);
2685         }
2686 
2687 CreateUndel:
2688 
2689         // allocate FileInfo
2690         FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_FE_TAG);
2691         *_FileInfo = FileInfo;
2692         if(!FileInfo)
2693             try_return (status = STATUS_INSUFFICIENT_RESOURCES);
2694         ImpUseLen = (ImpUseLen + 3) & ~((uint16)3);
2695 
2696         RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO));
2697         // init horizontal links
2698         FileInfo->NextLinkedFile =
2699         FileInfo->PrevLinkedFile = FileInfo;
2700         // allocate space for FileEntry
2701         if(!OS_SUCCESS(status =
2702             UDFBuildFileEntry(Vcb, DirInfo, FileInfo, PartNum, ICB_FLAG_AD_IN_ICB, ExtAttrSz, Extended) )) {
2703             BrutePoint();
2704             try_return (status);
2705         }
2706         FEAllocated = TRUE;
2707         FEicb.extLength = LBS;
2708         ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
2709         FEicb.extLocation.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
2710         FEicb.extLocation.partitionReferenceNum = (uint16)PartNum;
2711         RtlZeroMemory(&(FEicb.impUse), sizeof(FEicb.impUse));
2712 
2713         if(!undel) {
2714             // build FileIdent
2715             if(!OS_SUCCESS(status =
2716                 UDFBuildFileIdent(Vcb, _fn, &FEicb, ImpUseLen,
2717                         &(FileInfo->FileIdent), &(FileInfo->FileIdentLen)) ))
2718                 try_return (status);
2719         } else {
2720             // read FileIdent
2721             FileInfo->FileIdent = (PFILE_IDENT_DESC)MyAllocatePoolTag__(NonPagedPool, DirNdx->Length, MEM_FID_TAG);
2722             if(!(FileInfo->FileIdent)) try_return (status = STATUS_INSUFFICIENT_RESOURCES);
2723             FileInfo->FileIdentLen = DirNdx->Length;
2724             if(!OS_SUCCESS(status = UDFReadExtent(Vcb, &(DirInfo->Dloc->DataLoc), DirNdx->Offset,
2725                                      DirNdx->Length, FALSE, (int8*)(FileInfo->FileIdent), &ReadBytes) ))
2726                 try_return (status);
2727             FileInfo->FileIdent->fileCharacteristics = 0;
2728             FileInfo->FileIdent->icb = FEicb;
2729             ImpUseLen = FileInfo->FileIdent->lengthOfImpUse;
2730             DirNdx->FileCharacteristics = 0;
2731         }
2732         // init 'parentICBLocation' & so on in FE
2733         ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum =
2734              UDFPhysLbaToPart(Vcb, PartNum, DirInfo->Dloc->FELoc.Mapping[0].extLocation);
2735         ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum = (uint16)PartNum;
2736     //    ((icbtag*)(FileInfo->Dloc->FileEntry+1))->strategyType = 4;
2737     //    ((icbtag*)(FileInfo->Dloc->FileEntry+1))->numEntries = 1;
2738         // try to find suitable unused FileIdent in DirIndex
2739         l = FileInfo->FileIdentLen;
2740         if(undel) goto CrF__2;
2741 #ifndef UDF_LIMIT_DIR_SIZE
2742         if(Vcb->CDR_Mode) {
2743 #endif // UDF_LIMIT_DIR_SIZE
2744             // search for suitable unused entry
2745             if(UDFDirIndexInitScan(DirInfo, &ScanContext, 2)) {
2746                 while((DirNdx = UDFDirIndexScan(&ScanContext, NULL))) {
2747                     if((DirNdx->Length == l) && UDFIsDeleted(DirNdx) &&
2748                        !DirNdx->FileInfo ) {
2749                         // free unicode-buffer with old name
2750                         if(DirNdx->FName.Buffer) {
2751                             MyFreePool__(DirNdx->FName.Buffer);
2752                             DirNdx->FName.Buffer = NULL;
2753                         }
2754                         i = ScanContext.i;
2755                         goto CrF__1;
2756                     }
2757                 }
2758             }
2759 #ifndef UDF_LIMIT_DIR_SIZE
2760         } else {
2761 #endif // UDF_LIMIT_DIR_SIZE
2762             i = UDFDirIndexGetLastIndex(hDirNdx); // 'i' points beyond EO DirIndex
2763 #ifndef UDF_LIMIT_DIR_SIZE
2764         }
2765 #endif // UDF_LIMIT_DIR_SIZE
2766 
2767         // append entry
2768         if(!OS_SUCCESS(status = UDFDirIndexGrow(&(DirInfo->Dloc->DirIndex), 1))) {
2769             try_return (status);
2770         }
2771 
2772         // init offset of new FileIdent in directory Data extent
2773         hDirNdx = DirInfo->Dloc->DirIndex;
2774         if(i-1) {
2775             DirNdx = UDFDirIndex(hDirNdx,i-1);
2776             UDFDirIndex(hDirNdx,i)->Offset = DirNdx->Offset + DirNdx->Length;
2777             DirNdx = UDFDirIndex(hDirNdx,i);
2778         } else {
2779             DirNdx = UDFDirIndex(hDirNdx,i);
2780             DirNdx->Offset = 0;
2781         }
2782         // new terminator is recorded by UDFDirIndexGrow()
2783         if( ((d = ((LBS - (DirNdx->Offset + l + DirInfo->Dloc->DataLoc.Offset)) & (LBS-1) )) < sizeof(FILE_IDENT_DESC)) &&
2784               d ) {
2785             // insufficient space at the end of last sector for
2786             // next FileIdent's tag. fill it with ImpUse data
2787 
2788             // generally, all data should be DWORD-aligned, but if it is not so
2789             // this opearation will help us to avoid glitches
2790             d = (d+3) & ~((uint32)3);
2791 
2792             uint32 IUl, FIl;
2793             if(!MyReallocPool__((int8*)(FileInfo->FileIdent), l,
2794                          (int8**)&(FileInfo->FileIdent), (l+d+3) & ~((uint32)(3)) ))
2795                 try_return (status = STATUS_INSUFFICIENT_RESOURCES);
2796             l += d;
2797             IUl = FileInfo->FileIdent->lengthOfImpUse;
2798             FIl = FileInfo->FileIdent->lengthFileIdent;
2799             // move filename to higher addr
2800             RtlMoveMemory(((int8*)(FileInfo->FileIdent+1))+IUl+d,
2801                           ((int8*)(FileInfo->FileIdent+1))+IUl, FIl);
2802             RtlZeroMemory(((int8*)(FileInfo->FileIdent+1))+IUl, d);
2803             FileInfo->FileIdent->lengthOfImpUse += (uint16)d;
2804             FileInfo->FileIdentLen = l;
2805         }
2806         DirNdx->Length = l;
2807 CrF__1:
2808         // clone unicode string
2809         // it  **<<MUST>>**  be allocated with internal memory manager
2810         DirNdx->FName.Buffer = (PWCHAR)MyAllocatePoolTag__(UDF_FILENAME_MT, (DirNdx->FName.MaximumLength = _fn->Length + sizeof(WCHAR)), MEM_FNAMECPY_TAG);
2811         DirNdx->FName.Length = _fn->Length;
2812         if(!DirNdx->FName.Buffer)
2813             try_return (status = STATUS_INSUFFICIENT_RESOURCES);
2814         RtlCopyMemory(DirNdx->FName.Buffer, _fn->Buffer, _fn->Length);
2815         DirNdx->FName.Buffer[_fn->Length/sizeof(WCHAR)] = 0;
2816 CrF__2:
2817         DirNdx->FI_Flags |= UDFBuildHashEntry(Vcb, &(DirNdx->FName), &(DirNdx->hashes), HASH_ALL);
2818         // we get here immediately when 'undel' occured
2819         FileInfo->Index = i;
2820         DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
2821         DirNdx->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR;
2822         ASSERT(!DirNdx->FileInfo);
2823         DirNdx->FileInfo = FileInfo;
2824         DirNdx->FileEntryLoc = FEicb.extLocation;
2825         // mark file as 'deleted' for now
2826         DirNdx->FileCharacteristics = FILE_DELETED;
2827         FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED;
2828         FileInfo->Dloc->DataLoc.Mapping = UDFExtentToMapping(&(FileInfo->Dloc->FELoc.Mapping[0]));
2829         if(!(FileInfo->Dloc->DataLoc.Mapping)) {
2830             UDFFlushFI(Vcb, FileInfo, PartNum);
2831             try_return (status = STATUS_INSUFFICIENT_RESOURCES);
2832         }
2833         FileInfo->Dloc->DataLoc.Length = 0;
2834         FileInfo->Dloc->DataLoc.Offset = FileInfo->Dloc->FileEntryLen;
2835         FileInfo->ParentFile = DirInfo;
2836         // init FileEntry
2837         UDFSetFileUID(Vcb, FileInfo);
2838         UDFSetFileSize(FileInfo, 0);
2839         UDFIncFileLinkCount(FileInfo); // increase to 1
2840         UDFUpdateCreateTime(Vcb, FileInfo);
2841         UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index),
2842                              FileInfo->Dloc->FileEntry, Vcb->DefaultAttr);
2843         FileInfo->Dloc->DataLoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK;
2844         FileInfo->Dloc->DataLoc.Modified = TRUE;
2845         FileInfo->Dloc->FELoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK;
2846         // zero sector for FileEntry
2847         if(!Vcb->CDR_Mode) {
2848             status = UDFWriteData(Vcb, TRUE, ((int64)(FileInfo->Dloc->FELoc.Mapping[0].extLocation)) << Vcb->BlockSizeBits, LBS, FALSE, Vcb->ZBuffer, &ReadBytes);
2849             if(!OS_SUCCESS(status)) {
2850                 UDFFlushFI(Vcb, FileInfo, PartNum);
2851                 try_return (status);
2852             }
2853         }
2854 #if 0
2855         if((i >= 2) && (DirNdx->FName.Buffer[0] == L'.')) {
2856             BrutePoint();
2857         }
2858 #endif
2859 
2860 #ifdef UDF_CHECK_DISK_ALLOCATION
2861         if(  /*FileInfo->Fcb &&*/
2862              UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) {
2863 
2864             if(!FileInfo->FileIdent ||
2865                !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED)) {
2866                 AdPrint(("Flushing to Discarded block %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation));
2867                 BrutePoint();
2868             }
2869         }
2870 #endif // UDF_CHECK_DISK_ALLOCATION
2871 
2872         // make FileIdent valid
2873         FileInfo->FileIdent->fileCharacteristics = 0;
2874         DirNdx->FileCharacteristics = 0;
2875         UDFReferenceFile__(FileInfo);
2876         UDFFlushFE(Vcb, FileInfo, PartNum);
2877         if(undel)
2878             hDirNdx->DelCount--;
2879         UDFReleaseDloc(Vcb, FileInfo->Dloc);
2880         UDFIncFileCounter(Vcb);
2881 
2882         UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used
2883 
2884         try_return (status = STATUS_SUCCESS);
2885 
2886 try_exit:   NOTHING;
2887 
2888     } _SEH2_FINALLY {
2889         if(!OS_SUCCESS(status)) {
2890             if(FEAllocated)
2891                 UDFFreeFESpace(Vcb, DirInfo, &(FileInfo->Dloc->FELoc));
2892         }
2893     } _SEH2_END
2894     return status;
2895 
2896 } // end UDFCreateFile__()
2897 #endif //UDF_READ_ONLY_BUILD
2898 
2899 /*
2900     This routine reads data from file described by FileInfo
2901  */
2902 /*__inline
2903 OSSTATUS
2904 UDFReadFile__(
2905     IN PVCB Vcb,
2906     IN PUDF_FILE_INFO FileInfo,
2907     IN int64 Offset,   // offset in extent
2908     IN SIZE_T Length,
2909     IN BOOLEAN Direct,
2910     OUT int8* Buffer,
2911     OUT PSIZE_T ReadBytes
2912     )
2913 {
2914     ValidateFileInfo(FileInfo);
2915 
2916     return UDFReadExtent(Vcb, &(FileInfo->Dloc->DataLoc), Offset, Length, Direct, Buffer, ReadBytes);
2917 } // end UDFReadFile__()*/
2918 
2919 #ifndef UDF_READ_ONLY_BUILD
2920 /*
2921     This routine zeros data in file described by FileInfo
2922  */
2923 __inline
2924 OSSTATUS
2925 UDFZeroFile__(
2926     IN PVCB Vcb,
2927     IN PUDF_FILE_INFO FileInfo,
2928     IN int64 Offset,   // offset in extent
2929     IN SIZE_T Length,
2930     IN BOOLEAN Direct,
2931     OUT PSIZE_T ReadBytes
2932     )
2933 {
2934     ValidateFileInfo(FileInfo);
2935 
2936     return UDFZeroExtent__(Vcb, &(FileInfo->Dloc->DataLoc), Offset, Length, Direct, ReadBytes);
2937 } // end UDFZeroFile__()*/
2938 
2939 /*
2940     This routine makes sparse area in file described by FileInfo
2941  */
2942 __inline
2943 OSSTATUS
2944 UDFSparseFile__(
2945     IN PVCB Vcb,
2946     IN PUDF_FILE_INFO FileInfo,
2947     IN int64 Offset,   // offset in extent
2948     IN SIZE_T Length,
2949     IN BOOLEAN Direct,
2950     OUT PSIZE_T ReadBytes
2951     )
2952 {
2953     ValidateFileInfo(FileInfo);
2954 
2955     return UDFSparseExtent__(Vcb, &(FileInfo->Dloc->DataLoc), Offset, Length, Direct, ReadBytes);
2956 } // end UDFSparseFile__()*/
2957 
2958 /*
2959     This routine fills tails of the last sector in extent with ZEROs
2960  */
2961 OSSTATUS
2962 UDFPadLastSector(
2963     IN PVCB Vcb,
2964     IN PEXTENT_INFO ExtInfo
2965     )
2966 {
2967     if(!ExtInfo || !(ExtInfo->Mapping) || !(ExtInfo->Length)) return STATUS_INVALID_PARAMETER;
2968 
2969     PEXTENT_MAP Extent = ExtInfo->Mapping;   // Extent array
2970     SIZE_T to_write, WrittenBytes;
2971     uint32 Lba, sect_offs, flags;
2972     OSSTATUS status;
2973     // Length should not be zero
2974     int64 Offset = ExtInfo->Length + ExtInfo->Offset;
2975     // data is sector-size-aligned, we needn't any padding
2976     if(Offset && !((uint32)Offset & (Vcb->LBlockSize-1) )) return STATUS_SUCCESS;
2977     // get Lba of the last sector
2978     Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
2979     // EOF check. If we have valid ExtInfo this will not happen, but who knows..
2980     if((Lba == (uint32)-1) ||
2981        (flags == EXTENT_NOT_RECORDED_NOT_ALLOCATED))
2982         return STATUS_END_OF_FILE;
2983     // write tail
2984     status = UDFWriteData(Vcb, TRUE, (((int64)Lba) << Vcb->BlockSizeBits) + sect_offs, to_write, FALSE, Vcb->ZBuffer, &WrittenBytes);
2985     return status;
2986 } // UDFPadLastSector()
2987 #endif //UDF_READ_ONLY_BUILD
2988 
2989 /*
2990     This routine updates AllocDesc sequence, FileIdent & FileEntry
2991     for given file
2992  */
2993 OSSTATUS
2994 UDFCloseFile__(
2995     IN PVCB Vcb,
2996     IN PUDF_FILE_INFO FileInfo
2997     )
2998 {
2999     ValidateFileInfo(FileInfo);
3000 
3001     if(!FileInfo) return STATUS_SUCCESS;
3002     if(FileInfo->Index<2 && (FileInfo->ParentFile) && !UDFIsAStreamDir(FileInfo)) {
3003         UDFPrint(("Closing Current or Parent Directory... :-\\\n"));
3004         if(FileInfo->RefCount) {
3005             UDFInterlockedDecrement((PLONG)&(FileInfo->RefCount));
3006             ASSERT(FileInfo->Dloc);
3007             if(FileInfo->Dloc)
3008                 UDFInterlockedDecrement((PLONG)&(FileInfo->Dloc->LinkRefCount));
3009 #ifdef UDF_DBG
3010         } else {
3011             BrutePoint();
3012             UDFPrint(("ERROR: Closing unreferenced file!\n"));
3013 #endif // UDF_DBG
3014         }
3015         if(FileInfo->ParentFile->OpenCount) {
3016             UDFInterlockedDecrement((PLONG)&(FileInfo->ParentFile->OpenCount));
3017 #ifdef UDF_DBG
3018         } else {
3019             BrutePoint();
3020             UDFPrint(("ERROR: Closing unopened file!\n"));
3021 #endif // UDF_DBG
3022         }
3023         return STATUS_SUCCESS;
3024     }
3025     PUDF_FILE_INFO DirInfo = FileInfo->ParentFile;
3026     OSSTATUS status;
3027     uint32 PartNum;
3028     if(FileInfo->RefCount) {
3029         UDFInterlockedDecrement((PLONG)&(FileInfo->RefCount));
3030         ASSERT(FileInfo->Dloc);
3031         if(FileInfo->Dloc)
3032             UDFInterlockedDecrement((PLONG)&(FileInfo->Dloc->LinkRefCount));
3033 #ifdef UDF_DBG
3034     } else {
3035         BrutePoint();
3036         UDFPrint(("ERROR: Closing unreferenced file!\n"));
3037 #endif // UDF_DBG
3038     }
3039     if(DirInfo) {
3040         // validate DirInfo
3041         ValidateFileInfo(DirInfo);
3042 
3043         if(DirInfo->OpenCount) {
3044             UDFInterlockedDecrement((PLONG)&(DirInfo->OpenCount));
3045 #ifdef UDF_DBG
3046         } else {
3047             BrutePoint();
3048             UDFPrint(("ERROR: Closing unopened file!\n"));
3049 #endif // UDF_DBG
3050         }
3051     }
3052     // If the file has gone (unlinked) we should return STATUS_SUCCESS here.
3053     if(!FileInfo->Dloc) return STATUS_SUCCESS;
3054 
3055     if(FileInfo->RefCount ||
3056        FileInfo->OpenCount ||
3057        !(FileInfo->Dloc->FELoc.Mapping)) return STATUS_SUCCESS;
3058 //    ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3059     PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3060     if(PartNum == (uint32)-1) {
3061         UDFPrint(("  Is DELETED ?\n"));
3062         if(DirInfo) {
3063             PartNum = UDFGetPartNumByPhysLba(Vcb, DirInfo->Dloc->FELoc.Mapping[0].extLocation);
3064         } else {
3065             BrutePoint();
3066         }
3067     }
3068 #ifdef UDF_CHECK_DISK_ALLOCATION
3069     if(  FileInfo->Fcb &&
3070          UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) {
3071 
3072         //ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3073         if(UDFIsAStreamDir(FileInfo)) {
3074             if(!UDFIsSDirDeleted(FileInfo)) {
3075                 UDFPrint(("  Not DELETED SDir\n"));
3076                 BrutePoint();
3077             }
3078             ASSERT(!FileInfo->Dloc->FELoc.Modified);
3079         } else
3080         if(!FileInfo->FileIdent ||
3081            !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED)) {
3082             if(!FileInfo->FileIdent) {
3083                 AdPrint(("  No FileIdent\n"));
3084             }
3085             if(FileInfo->FileIdent &&
3086                !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED))
3087                 AdPrint(("  Not DELETED\n"));
3088             ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3089             AdPrint(("Flushing to Discarded block %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation));
3090             BrutePoint();
3091         } else {
3092             UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_FREE); // check if free
3093             UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->FELoc.Mapping, AS_FREE); // check if free
3094         }
3095     } else {
3096         if(!FileInfo->Dloc->FELoc.Mapping[0].extLocation ||
3097             UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) {
3098             UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_FREE); // check if free
3099         } else {
3100             UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used
3101         }
3102     }
3103 #endif // UDF_CHECK_DISK_ALLOCATION
3104     // check if we should update parentICBLocation
3105     if( !((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum &&
3106         !((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum &&
3107         DirInfo &&
3108         !Vcb->CDR_Mode &&
3109         Vcb->Modified &&
3110         UDFGetFileLinkCount(FileInfo) ) {
3111         ASSERT(DirInfo->Dloc->FELoc.Mapping[0].extLocation);
3112         ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum =
3113              UDFPhysLbaToPart(Vcb, PartNum, DirInfo->Dloc->FELoc.Mapping[0].extLocation);
3114         ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum = (uint16)PartNum;
3115         FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
3116     }
3117 
3118     // we needn't flushing FE & Allocs untill all links are closed...
3119     if(!FileInfo->Dloc->LinkRefCount) {
3120 
3121         // flush FE and pre-allocation charge for directories
3122         if(FileInfo->Dloc &&
3123            FileInfo->Dloc->DirIndex) {
3124 
3125             UDFFlushFESpace(Vcb, FileInfo->Dloc);
3126             if(FileInfo->Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) {
3127                 FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_CUT_PREALLOCATED;
3128                 status = UDFResizeExtent(Vcb, PartNum, UDFGetFileSize(FileInfo), FALSE, &(FileInfo->Dloc->DataLoc));
3129                 FileInfo->Dloc->DataLoc.Flags &= ~(EXTENT_FLAG_PREALLOCATED | EXTENT_FLAG_CUT_PREALLOCATED);
3130                 if(OS_SUCCESS(status)) {
3131                     AdPrint(("Dir pre-alloc truncated (Close)\n"));
3132                     FileInfo->Dloc->DataLoc.Modified = TRUE;
3133                 }
3134             }
3135         }
3136 
3137         if(!OS_SUCCESS(status = UDFFlushFE(Vcb, FileInfo, PartNum))) {
3138             UDFPrint(("Error flushing FE\n"));
3139 //flush_recovery:
3140             BrutePoint();
3141             if(FileInfo->Index >= 2) {
3142                 PDIR_INDEX_ITEM DirNdx;
3143                 DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index);
3144                 if(DirNdx) {
3145                     UDFPrint(("Recovery: mark as deleted & flush FI\n"));
3146                     DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
3147                     DirNdx->FileCharacteristics |= FILE_DELETED;
3148                     FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED;
3149                     UDFFlushFI(Vcb, FileInfo, PartNum);
3150                 }
3151             }
3152             return status;
3153         }
3154     }
3155     // ... but FI must be updated (if any)
3156     if(!OS_SUCCESS(status = UDFFlushFI(Vcb, FileInfo, PartNum))) {
3157         UDFPrint(("Error flushing FI\n"));
3158         return status;
3159     }
3160 #ifdef UDF_DBG
3161 //    ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3162     if((FileInfo->Dloc->FileEntry->descVersion != 2) &&
3163        (FileInfo->Dloc->FileEntry->descVersion != 3)) {
3164         ASSERT(UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation));
3165     }
3166 #endif // UDF_DBG
3167     return STATUS_SUCCESS;
3168 } // end UDFCloseFile__()
3169 
3170 
3171 #ifndef UDF_READ_ONLY_BUILD
3172 /*
3173     This routine moves file from DirInfo1 to DirInfo2 & renames it to fn
3174  */
3175 OSSTATUS
3176 UDFRenameMoveFile__(
3177     IN PVCB Vcb,
3178     IN BOOLEAN IgnoreCase,
3179  IN OUT BOOLEAN* Replace,        // replace if destination file exists
3180     IN PUNICODE_STRING fn,       // destination
3181  IN OUT PUDF_FILE_INFO DirInfo1,
3182  IN OUT PUDF_FILE_INFO DirInfo2,
3183  IN OUT PUDF_FILE_INFO FileInfo  // source (opened)
3184     )
3185 {
3186     PUDF_FILE_INFO FileInfo2;
3187     OSSTATUS status;
3188     PDIR_INDEX_ITEM DirNdx1;
3189     PDIR_INDEX_ITEM DirNdx2;
3190     uint_di i,j;
3191     BOOLEAN Recovery = FALSE;
3192     BOOLEAN SameFE = FALSE;
3193     uint32 NTAttr = 0;
3194 
3195     // validate FileInfo
3196     ValidateFileInfo(DirInfo1);
3197     ValidateFileInfo(DirInfo2);
3198     ValidateFileInfo(FileInfo);
3199 
3200     i = j = 0;
3201     if(DirInfo1 == DirInfo2) {
3202         if(OS_SUCCESS(status = UDFFindFile(Vcb, IgnoreCase, TRUE, fn, DirInfo2, &j)) &&
3203            (j==FileInfo->Index) ) {
3204             // case-only rename
3205             uint8* CS0;
3206             SIZE_T Nlen, /* l, FIXME ReactOS */ IUl;
3207 
3208             // prepare filename
3209             UDFCompressUnicode(fn, &CS0, &Nlen);
3210             if(!CS0) return STATUS_INSUFFICIENT_RESOURCES;
3211 /*            if(Nlen > UDF_NAME_LEN) {
3212                 if(CS0) MyFreePool__(CS0);
3213                 return STATUS_OBJECT_NAME_INVALID;
3214             }*/
3215             // allocate memory for FI
3216             DirNdx2 = UDFDirIndex(DirInfo2->Dloc->DirIndex,j);
3217             IUl = DirNdx2->FileInfo->FileIdent->lengthOfImpUse;
3218 #if 0
3219             l = (sizeof(FILE_IDENT_DESC) + Nlen + IUl + 3) & ~((uint32)3);
3220 #endif
3221 
3222             RtlCopyMemory( ((uint8*)(DirNdx2->FileInfo->FileIdent+1))+IUl, CS0, Nlen);
3223             RtlCopyMemory(DirNdx2->FName.Buffer, fn->Buffer, fn->Length);
3224 
3225             if(CS0) MyFreePool__(CS0);
3226 
3227             DirNdx2->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
3228             UDFBuildHashEntry(Vcb, &(DirNdx2->FName), &(DirNdx2->hashes), HASH_ALL);
3229             return STATUS_SUCCESS;
3230 /*        } else
3231         if(!OS_SUCCESS(status) && (fn->Length == UDFDirIndex(DirInfo2->Dloc->DirIndex, j=FileInfo->Index)->FName.Length)) {
3232             // target file doesn't exist, but name lengthes are equal
3233             RtlCopyMemory((DirNdx1 = UDFDirIndex(DirInfo1->Dloc->DirIndex,j))->FName.Buffer, fn->Buffer, fn->Length);
3234             DirNdx1->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
3235             UDFBuildHashEntry(Vcb, &(DirNdx1->FName), &(DirNdx1->hashes), HASH_ALL);
3236             return STATUS_SUCCESS;*/
3237         }
3238     }
3239 
3240     // PHASE 0
3241     // try to create new FileIdent & FileEntry in Dir2
3242 
3243 RenameRetry:
3244     if(!OS_SUCCESS(status = UDFCreateFile__(Vcb, IgnoreCase, fn, UDFGetFileEALength(FileInfo),
3245                     0, (FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY),
3246                     TRUE, DirInfo2, &FileInfo2))) {
3247         UDFCleanUpFile__(Vcb, FileInfo2);
3248         if(FileInfo2) MyFreePool__(FileInfo2);
3249         if(status == STATUS_ACCESS_DENIED) {
3250             // try to recover >;->
3251             if((*Replace) && !Recovery) {
3252                 Recovery = TRUE;
3253                 status = UDFOpenFile__(Vcb, IgnoreCase, TRUE, fn, DirInfo2, &FileInfo2, NULL);
3254                 if(OS_SUCCESS(status)) {
3255                     status = UDFDoesOSAllowFileToBeTargetForRename__(FileInfo2);
3256                     if(!OS_SUCCESS(status)) {
3257                         UDFCloseFile__(Vcb, FileInfo2);
3258                         goto cleanup_and_abort_rename;
3259                     }
3260                     status = UDFUnlinkFile__(Vcb, FileInfo2, TRUE);
3261 //                    UDFPretendFileDeleted__(Vcb, FileInfo2);
3262                     UDFCloseFile__(Vcb, FileInfo2);
3263                     if(UDFCleanUpFile__(Vcb, FileInfo2)) {
3264                         MyFreePool__(FileInfo2);
3265                         FileInfo2 = NULL;
3266                         if(SameFE)
3267                             return status;
3268                     } else {
3269                         // we get here if the FileInfo has associated
3270                         // system-specific Fcb
3271                         // Such fact means that not all system references
3272                         // has already gone (except Linked file case)
3273 /*                        if(SameFE)
3274                             return status;*/
3275 //                        UDFRemoveOSReferences__(FileInfo2);
3276                         if(!OS_SUCCESS(status) ||
3277                            (UDFGetFileLinkCount(FileInfo2) < 1))
3278                             status = STATUS_ACCESS_DENIED;
3279                     }
3280                     if(OS_SUCCESS(status)) goto RenameRetry;
3281                 }
3282 cleanup_and_abort_rename:
3283                 if(FileInfo2 && UDFCleanUpFile__(Vcb, FileInfo2)) {
3284                     MyFreePool__(FileInfo2);
3285                     FileInfo2 = NULL;
3286                 }
3287             } else {
3288                 status = STATUS_OBJECT_NAME_COLLISION;
3289             }
3290         }
3291         return status;
3292     }
3293     // update pointers
3294     DirNdx1 = UDFDirIndex(DirInfo1->Dloc->DirIndex, i = FileInfo->Index);
3295     DirNdx2 = UDFDirIndex(DirInfo2->Dloc->DirIndex, j = FileInfo2->Index);
3296 
3297     // copy file attributes to newly created FileIdent
3298     NTAttr = UDFAttributesToNT(DirNdx1, FileInfo->Dloc->FileEntry);
3299     FileInfo2->FileIdent->fileVersionNum = FileInfo->FileIdent->fileVersionNum;
3300     // unlink source FileIdent
3301     if(!OS_SUCCESS(status = UDFUnlinkFile__(Vcb, FileInfo, FALSE))) {
3302         // kill newly created entry
3303         UDFFlushFile__(Vcb, FileInfo2);
3304         UDFUnlinkFile__(Vcb, FileInfo2, TRUE);
3305         UDFCloseFile__(Vcb, FileInfo2);
3306         UDFCleanUpFile__(Vcb, FileInfo2);
3307         MyFreePool__(FileInfo2);
3308         return status;
3309     }
3310 
3311     // PHASE 1
3312     // drop all unnecessary info from FileInfo & flush FI
3313 
3314     DirNdx1->FileInfo = NULL;
3315     ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3316     UDFFlushFI(Vcb, FileInfo, UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation));
3317     UDFInterlockedExchangeAdd((PLONG)&(DirInfo1->OpenCount),
3318                             -((LONG)(FileInfo->RefCount)));
3319     // PHASE 2
3320     // copy all necessary info from FileInfo to FileInfo2
3321 
3322     FileInfo2->FileIdent->icb = FileInfo->FileIdent->icb;
3323     FileInfo2->FileIdent->fileCharacteristics = FileInfo->FileIdent->fileCharacteristics;
3324     FileInfo2->FileIdent->fileVersionNum = FileInfo->FileIdent->fileVersionNum;
3325     MyFreePool__(FileInfo->FileIdent);
3326     FileInfo->FileIdent = NULL;
3327 
3328     // PHASE 3
3329     // copy all necessary info from FileInfo2 to FileInfo
3330 
3331     DirNdx2->FileInfo = FileInfo;
3332     DirNdx2->FileCharacteristics = DirNdx1->FileCharacteristics & ~FILE_DELETED;
3333     DirNdx2->FileEntryLoc = DirNdx1->FileEntryLoc;
3334     DirNdx2->FI_Flags = (DirNdx1->FI_Flags & ~UDF_FI_FLAG_SYS_ATTR) | UDF_FI_FLAG_FI_MODIFIED;
3335     UDFInterlockedExchangeAdd((PLONG)&(DirInfo2->OpenCount),
3336                             FileInfo->RefCount - FileInfo2->RefCount);
3337 
3338     UDFAttributesToUDF(DirNdx2, FileInfo2->Dloc->FileEntry, NTAttr);
3339 
3340     FileInfo->Index = j;
3341     FileInfo->FileIdent = FileInfo2->FileIdent;
3342     FileInfo->FileIdentLen = FileInfo2->FileIdentLen;
3343     FileInfo->ParentFile = DirInfo2;
3344     FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
3345 
3346     ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation =
3347         ((icbtag*)(FileInfo2->Dloc->FileEntry+1))->parentICBLocation;
3348 
3349     UDFIncFileLinkCount(FileInfo); // increase to 1
3350 
3351 //    UDFUpdateModifyTime(Vcb, FileInfo);
3352 
3353     // PHASE 4
3354     // drop all unnecessary info from FileInfo2
3355 
3356     UDFFreeFESpace(Vcb, DirInfo2, &(FileInfo2->Dloc->FELoc));
3357     UDFUnlinkDloc(Vcb, FileInfo2->Dloc);
3358     UDFDecFileLinkCount(FileInfo2);
3359 
3360     FileInfo2->Dloc->FE_Flags &= ~UDF_FE_FLAG_FE_MODIFIED;
3361 /*    MyFreePool__(FileInfo2->Dloc->FileEntry);
3362     FileInfo2->Dloc->FileEntry = NULL;*/
3363     FileInfo2->ParentFile = NULL;
3364     FileInfo2->FileIdent = NULL;
3365     FileInfo2->RefCount = 0;
3366     FileInfo2->Dloc->LinkRefCount = 0;
3367     ASSERT(FileInfo2->Dloc->DataLoc.Mapping);
3368     FileInfo2->Dloc->DataLoc.Mapping[0].extLocation = 0;
3369     FileInfo2->Dloc->DataLoc.Mapping[0].extLength = 0;
3370 
3371     UDFCleanUpFile__(Vcb, FileInfo2);
3372     MyFreePool__(FileInfo2);
3373 
3374     // return 'delete target' status
3375     (*Replace) = Recovery;
3376 
3377     return STATUS_SUCCESS;
3378 } // end UDFRenameMoveFile__()
3379 
3380 /*
3381     This routine transforms zero-sized file to directory
3382  */
3383 OSSTATUS
3384 UDFRecordDirectory__(
3385     IN PVCB Vcb,
3386  IN OUT PUDF_FILE_INFO DirInfo   // source (opened)
3387     )
3388 {
3389     OSSTATUS status;
3390     LONG_AD FEicb;
3391     UDF_FILE_INFO FileInfo;
3392     UDF_DATALOC_INFO Dloc;
3393     UNICODE_STRING PName;
3394     uint32 PartNum;
3395     SIZE_T WrittenBytes;
3396     PDIR_INDEX_ITEM CurDirNdx;
3397     uint32 lba;
3398 
3399     // validate DirInfo
3400     ValidateFileInfo(DirInfo);
3401     if(DirInfo->ParentFile && UDFIsAStreamDir(DirInfo->ParentFile))
3402         return STATUS_ACCESS_DENIED;
3403     // file should be empty
3404     if(UDFGetFileSize(DirInfo)) {
3405         if( DirInfo->FileIdent &&
3406            (DirInfo->FileIdent->fileCharacteristics & FILE_DIRECTORY)) return STATUS_FILE_IS_A_DIRECTORY;
3407         return STATUS_NOT_A_DIRECTORY;
3408     }
3409     if(DirInfo->Dloc->DirIndex) return STATUS_FILE_IS_A_DIRECTORY;
3410     // create empty DirIndex
3411     if(DirInfo->FileIdent) DirInfo->FileIdent->fileCharacteristics |= FILE_DIRECTORY;
3412     if((CurDirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(DirInfo),DirInfo->Index)))
3413         CurDirNdx->FileCharacteristics |= FILE_DIRECTORY;
3414     ((icbtag*)(DirInfo->Dloc->FileEntry+1))->fileType = UDF_FILE_TYPE_DIRECTORY;
3415     // init temporary FileInfo
3416     RtlZeroMemory(&FileInfo, sizeof(UDF_FILE_INFO));
3417     FileInfo.Dloc = &Dloc;
3418     FileInfo.Dloc->FileEntry = DirInfo->ParentFile->Dloc->FileEntry;
3419     FileInfo.Dloc->FileEntryLen = DirInfo->ParentFile->Dloc->FileEntryLen;
3420     FileInfo.Dloc->DataLoc = DirInfo->Dloc->DataLoc;
3421     FileInfo.Dloc->FELoc = DirInfo->Dloc->FELoc;
3422     FileInfo.ParentFile = DirInfo;
3423     // prepare FileIdent for 'parent Dir'
3424     lba = DirInfo->Dloc->FELoc.Mapping[0].extLocation;
3425     ASSERT(lba);
3426     PartNum = UDFGetPartNumByPhysLba(Vcb, lba);
3427     FEicb.extLength = Vcb->LBlockSize;
3428     FEicb.extLocation.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, lba);
3429     FEicb.extLocation.partitionReferenceNum = (uint16)PartNum;
3430     RtlZeroMemory(&(FEicb.impUse), sizeof(FEicb.impUse));
3431     PName.Buffer = (PWCH)L"";
3432     PName.Length = (PName.MaximumLength = sizeof(L"")) - sizeof(WCHAR);
3433     if(!OS_SUCCESS(status =
3434         UDFBuildFileIdent(Vcb, &PName, &FEicb, 0,
3435                 &(FileInfo.FileIdent), &(FileInfo.FileIdentLen)) ))
3436         return status;
3437     FileInfo.FileIdent->fileCharacteristics |= (FILE_PARENT | FILE_DIRECTORY);
3438     UDFDecFileCounter(Vcb);
3439     UDFIncDirCounter(Vcb);
3440     // init structure
3441     UDFSetUpTag(Vcb, &(FileInfo.FileIdent->descTag), (uint16)(FileInfo.FileIdentLen),
3442               FEicb.extLocation.logicalBlockNum);
3443     FileInfo.Dloc->DataLoc.Flags |= EXTENT_FLAG_VERIFY; // for metadata
3444     // flush
3445     status = UDFWriteFile__(Vcb, DirInfo, 0, FileInfo.FileIdentLen, FALSE, (int8*)(FileInfo.FileIdent), &WrittenBytes);
3446 //    status = UDFFlushFI(Vcb, &FileInfo, PartNum);
3447 
3448 #ifdef UDF_DBG
3449     if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
3450         ASSERT(UDFGetFileSize(DirInfo) <= UDFGetExtentLength(DirInfo->Dloc->DataLoc.Mapping));
3451     } else {
3452         ASSERT(((UDFGetFileSize(DirInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) ==
3453                ((UDFGetExtentLength(DirInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)));
3454     }
3455 #endif // UDF_DBG
3456 
3457     MyFreePool__(FileInfo.FileIdent);
3458     if(!OS_SUCCESS(status)) return status;
3459     if(CurDirNdx) CurDirNdx->FileCharacteristics =
3460         DirInfo->FileIdent->fileCharacteristics;
3461     return UDFIndexDirectory(Vcb, DirInfo);
3462 } // end UDFRecordDirectory__()
3463 
3464 /*
3465     This routine changes file size (on disc)
3466  */
3467 OSSTATUS
3468 UDFResizeFile__(
3469     IN PVCB Vcb,
3470  IN OUT PUDF_FILE_INFO FileInfo,
3471     IN int64 NewLength
3472     )
3473 {
3474     SIZE_T WrittenBytes;
3475     OSSTATUS status;
3476     uint32 PartNum;
3477     int8* OldInIcb = NULL;
3478     PEXTENT_MAP NewMap;
3479 
3480     UDFPrint(("UDFResizeFile__: FI %x, -> %I64x\n", FileInfo, NewLength));
3481     ValidateFileInfo(FileInfo);
3482 //    ASSERT(FileInfo->RefCount >= 1);
3483 
3484     if((NewLength >> Vcb->LBlockSizeBits) > Vcb->TotalAllocUnits) {
3485         UDFPrint(("STATUS_DISK_FULL\n"));
3486         return STATUS_DISK_FULL;
3487     }
3488     if (NewLength == FileInfo->Dloc->DataLoc.Length) return STATUS_SUCCESS;
3489     if(FileInfo->ParentFile && (FileInfo->Index >= 2)) {
3490         UDFDirIndex(FileInfo->ParentFile->Dloc->DirIndex,FileInfo->Index)->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR;
3491     }
3492     if(NewLength > FileInfo->Dloc->DataLoc.Length) {
3493         // grow file
3494         return UDFWriteFile__(Vcb, FileInfo, NewLength, 0, FALSE, NULL, &WrittenBytes);
3495     }
3496     // truncate file
3497     if(NewLength <= (Vcb->LBlockSize - FileInfo->Dloc->FileEntryLen)) {
3498         // check if we are already in IN_ICB mode
3499         if((((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) != ICB_FLAG_AD_IN_ICB) {
3500             // read data from old location
3501             if(NewLength) {
3502                 OldInIcb = (int8*)MyAllocatePool__(NonPagedPool, (uint32)NewLength);
3503                 if(!OldInIcb) return STATUS_INSUFFICIENT_RESOURCES;
3504                 status = UDFReadExtent(Vcb, &(FileInfo->Dloc->DataLoc), 0, (uint32)NewLength, FALSE, OldInIcb, &WrittenBytes);
3505                 if(!OS_SUCCESS(status)) {
3506                     MyFreePool__(OldInIcb);
3507                     return status;
3508                 }
3509             } else {
3510                 OldInIcb = NULL;
3511             }
3512             // allocate storage for new mapping
3513             NewMap = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , 2*sizeof(EXTENT_MAP),
3514                                                                MEM_EXTMAP_TAG);
3515             if(!(NewMap)) {
3516                 MyFreePool__(OldInIcb);
3517                 return STATUS_INSUFFICIENT_RESOURCES;
3518             }
3519             // free old location...
3520             if(FileInfo->Dloc->DataLoc.Mapping[0].extLocation !=
3521                FileInfo->Dloc->FELoc.Mapping[0].extLocation) {
3522                ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3523 mark_data_map_0:
3524                 UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, FileInfo->Dloc->DataLoc.Mapping, AS_DISCARDED); // free
3525             } else {
3526                 if((FileInfo->Dloc->DataLoc.Mapping[0].extLength & UDF_EXTENT_LENGTH_MASK)
3527                        > Vcb->LBlockSize) {
3528                     BrutePoint();
3529                     FileInfo->Dloc->DataLoc.Mapping[0].extLength -= Vcb->LBlockSize;
3530                     FileInfo->Dloc->DataLoc.Mapping[0].extLocation += (1 << Vcb->LB2B_Bits);
3531                     goto mark_data_map_0;
3532                 }
3533                 UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->DataLoc.Mapping[1]), AS_DISCARDED); // free
3534             }
3535             if(FileInfo->Dloc->AllocLoc.Mapping) {
3536                 if((FileInfo->Dloc->AllocLoc.Mapping[0].extLength & UDF_EXTENT_LENGTH_MASK)
3537                        > Vcb->LBlockSize) {
3538                     FileInfo->Dloc->AllocLoc.Mapping[0].extLength -= Vcb->LBlockSize;
3539                     FileInfo->Dloc->AllocLoc.Mapping[0].extLocation += (1 << Vcb->LB2B_Bits);
3540                     UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, FileInfo->Dloc->AllocLoc.Mapping, AS_DISCARDED); // free
3541                 } else {
3542                     UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->AllocLoc.Mapping[1]), AS_DISCARDED); // free
3543                 }
3544                 MyFreePool__(FileInfo->Dloc->AllocLoc.Mapping);
3545             }
3546             MyFreePool__(FileInfo->Dloc->DataLoc.Mapping);
3547             FileInfo->Dloc->AllocLoc.Mapping = NULL;
3548             FileInfo->Dloc->AllocLoc.Length = 0;
3549             FileInfo->Dloc->AllocLoc.Offset = 0;
3550             FileInfo->Dloc->AllocLoc.Modified = TRUE;
3551             // switch to IN_ICB mode
3552             ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK;
3553             ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags |= ICB_FLAG_AD_IN_ICB;
3554             // init new data location descriptors
3555             FileInfo->Dloc->DataLoc.Mapping = NewMap;
3556             RtlZeroMemory((int8*)(FileInfo->Dloc->DataLoc.Mapping), 2*sizeof(EXTENT_MAP));
3557             FileInfo->Dloc->DataLoc.Mapping[0] = FileInfo->Dloc->FELoc.Mapping[0];
3558             FileInfo->Dloc->DataLoc.Length = NewLength;
3559             FileInfo->Dloc->DataLoc.Offset = FileInfo->Dloc->FileEntryLen;
3560             // write data to new location
3561             if(OldInIcb) {
3562                 status = UDFWriteExtent(Vcb, &(FileInfo->Dloc->DataLoc), 0, (uint32)NewLength, FALSE, OldInIcb, &WrittenBytes);
3563             } else {
3564                 status = STATUS_SUCCESS;
3565             }
3566             FileInfo->Dloc->DataLoc.Modified = TRUE;
3567             if(OldInIcb) MyFreePool__(OldInIcb);
3568         } else {
3569             // just modify Length field
3570             FileInfo->Dloc->DataLoc.Length = NewLength;
3571             status = STATUS_SUCCESS;
3572         }
3573     } else {
3574         // resize extent
3575         ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3576         PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3577         status = UDFResizeExtent(Vcb, PartNum, NewLength, FALSE, &(FileInfo->Dloc->DataLoc));
3578         FileInfo->Dloc->DataLoc.Modified = TRUE;
3579         FileInfo->Dloc->AllocLoc.Modified = TRUE;
3580     }
3581     if(OS_SUCCESS(status)) {
3582         UDFSetFileSize(FileInfo, NewLength);
3583     }
3584 
3585 #ifdef UDF_DBG
3586     if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
3587         ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping));
3588     } else {
3589         ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) ==
3590                ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)));
3591     }
3592 #endif // UDF_DBG
3593 
3594     return status;
3595 } // end UDFResizeFile__()
3596 #endif //UDF_READ_ONLY_BUILD
3597 
3598 /*
3599     This routine loads VAT.
3600  */
3601 OSSTATUS
3602 UDFLoadVAT(
3603     IN PVCB Vcb,
3604     IN uint32 PartNdx
3605     )
3606 {
3607     lb_addr VatFELoc;
3608     OSSTATUS status;
3609     PUDF_FILE_INFO VatFileInfo;
3610     uint32 len, i=0, j, to_read;
3611     uint32 Offset, hdrOffset;
3612     SIZE_T ReadBytes;
3613     uint32 root;
3614     uint16 PartNum;
3615 //    uint32 VatFirstLba = 0;
3616     int8* VatOldData;
3617     uint32 VatLba[6] = { Vcb->LastLBA,
3618                         Vcb->LastLBA - 2,
3619                         Vcb->LastLBA - 3,
3620                         Vcb->LastLBA - 5,
3621                         Vcb->LastLBA - 7,
3622                         0 };
3623 
3624     if(Vcb->Vat) return STATUS_SUCCESS;
3625     if(!Vcb->CDR_Mode) return STATUS_SUCCESS;
3626     // disable VAT for now. We'll reenable it if VAT is successfuly loaded
3627     Vcb->CDR_Mode = FALSE;
3628     PartNum = Vcb->Partitions[PartNdx].PartitionNum;
3629     root = Vcb->Partitions[PartNdx].PartitionRoot;
3630     if(Vcb->LBlockSize != Vcb->BlockSize) {
3631         // don't know how to operate... :(((
3632         return STATUS_UNRECOGNIZED_VOLUME;
3633     }
3634     if((Vcb->LastTrackNum > 1) &&
3635        (Vcb->LastLBA == Vcb->TrackMap[Vcb->LastTrackNum-1].LastLba)) {
3636         UDFPrint(("Hardware Read-only volume\n"));
3637         Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY;
3638     }
3639 
3640     VatFileInfo = Vcb->VatFileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT, sizeof(UDF_FILE_INFO), MEM_VATFINF_TAG);
3641     if(!VatFileInfo) return STATUS_INSUFFICIENT_RESOURCES;
3642     // load VAT FE (we know its location)
3643     VatFELoc.partitionReferenceNum = PartNum;
3644 retry_load_vat:
3645     VatFELoc.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, VatLba[i]);
3646     if(!OS_SUCCESS(status = UDFOpenRootFile__(Vcb, &VatFELoc, VatFileInfo))) {
3647         UDFCleanUpFile__(Vcb, VatFileInfo);
3648         // try another location
3649         i++;
3650         if( VatLba[i] &&
3651            (status != STATUS_FILE_CORRUPT_ERROR) &&
3652            (status != STATUS_CRC_ERROR)) goto retry_load_vat;
3653         MyFreePool__(VatFileInfo);
3654         Vcb->VatFileInfo = NULL;
3655         return status;
3656     }
3657     len = (uint32)UDFGetFileSize(VatFileInfo);
3658     if(Vcb->Partitions[PartNdx].PartitionType == UDF_VIRTUAL_MAP15) {
3659         // load Vat 1.50 header
3660         UDFPrint(("Load VAT 1.50\n"));
3661         VirtualAllocationTable15* Buf;
3662         if(((icbtag*)(VatFileInfo->Dloc->FileEntry+1))->fileType != UDF_FILE_TYPE_VAT15) {
3663             status = STATUS_FILE_CORRUPT_ERROR;
3664             goto err_vat_15;
3665         }
3666         Buf = (VirtualAllocationTable15*)MyAllocatePool__(NonPagedPool, sizeof(VirtualAllocationTable15));
3667         if(!Buf) {
3668 err_vat_15_2:
3669             status = STATUS_INSUFFICIENT_RESOURCES;
3670 err_vat_15:
3671             UDFCloseFile__(Vcb, VatFileInfo);
3672             UDFCleanUpFile__(Vcb, VatFileInfo);
3673             MyFreePool__(VatFileInfo);
3674             Vcb->VatFileInfo = NULL;
3675             return status;
3676         }
3677         Offset = 0;
3678         to_read =
3679         hdrOffset = len - sizeof(VirtualAllocationTable15);
3680         MyFreePool__(Buf);
3681 
3682         Vcb->minUDFReadRev  =
3683         Vcb->minUDFWriteRev =
3684         Vcb->maxUDFWriteRev = 0x0150;
3685 
3686         Vcb->numFiles =
3687         Vcb->numDirs  = -1;
3688 
3689     } else
3690     if(Vcb->Partitions[PartNdx].PartitionType == UDF_VIRTUAL_MAP20) {
3691         // load Vat 2.00 header
3692         UDFPrint(("Load VAT 2.00\n"));
3693         VirtualAllocationTable20* Buf;
3694         if(((icbtag*)(VatFileInfo->Dloc->FileEntry+1))->fileType != UDF_FILE_TYPE_VAT20) {
3695             status = STATUS_FILE_CORRUPT_ERROR;
3696             goto err_vat_15;
3697         }
3698         Buf = (VirtualAllocationTable20*)MyAllocatePool__(NonPagedPool, sizeof(VirtualAllocationTable20));
3699         if(!Buf) goto err_vat_15_2;
3700         Offset = Buf->lengthHeader;
3701         to_read = len - Offset;
3702         hdrOffset = 0;
3703         MyFreePool__(Buf);
3704 
3705         Vcb->minUDFReadRev  = Buf->minReadRevision;
3706         Vcb->minUDFWriteRev = Buf->minWriteRevision;
3707         Vcb->maxUDFWriteRev = Buf->maxWriteRevision;
3708 
3709         Vcb->numFiles = Buf->numFIDSFiles;
3710         Vcb->numDirs  = Buf->numFIDSDirectories;
3711 
3712     } else {
3713         // unknown (or wrong) VAT format
3714         UDFPrint(("unknown (or wrong) VAT format\n"));
3715         status = STATUS_FILE_CORRUPT_ERROR;
3716         goto err_vat_15;
3717     }
3718     // read VAT & remember old version
3719     Vcb->Vat = (uint32*)DbgAllocatePool(NonPagedPool, (Vcb->LastPossibleLBA+1)*sizeof(uint32) );
3720     if(!Vcb->Vat) {
3721         goto err_vat_15_2;
3722     }
3723     // store base version of VAT in memory
3724     VatOldData = (int8*)DbgAllocatePool(PagedPool, len);
3725     if(!VatOldData) {
3726         DbgFreePool(Vcb->Vat);
3727         Vcb->Vat = NULL;
3728         goto err_vat_15_2;
3729     }
3730     status = UDFReadFile__(Vcb, VatFileInfo, 0, len, FALSE, VatOldData, &ReadBytes);
3731     if(!OS_SUCCESS(status)) {
3732         UDFCloseFile__(Vcb, VatFileInfo);
3733         UDFCleanUpFile__(Vcb, VatFileInfo);
3734         MyFreePool__(VatFileInfo);
3735         DbgFreePool(Vcb->Vat);
3736         DbgFreePool(VatOldData);
3737         Vcb->Vat = NULL;
3738         Vcb->VatFileInfo = NULL;
3739     } else {
3740         // initialize VAT
3741         // !!! NOTE !!!
3742         // Both VAT copies - in-memory & on-disc
3743         // contain _relative_ addresses
3744         len = Vcb->NWA - root;
3745         for(i=0; i<=len; i++) {
3746             Vcb->Vat[i] = i;
3747         }
3748         RtlCopyMemory(Vcb->Vat, VatOldData+Offset, to_read);
3749         Vcb->InitVatCount =
3750         Vcb->VatCount = to_read/sizeof(uint32);
3751         Vcb->VatPartNdx = PartNdx;
3752         Vcb->CDR_Mode = TRUE;
3753         len = Vcb->VatCount;
3754         RtlFillMemory(&(Vcb->Vat[Vcb->NWA-root]), (Vcb->LastPossibleLBA-Vcb->NWA+1)*sizeof(uint32), 0xff);
3755         // sync VAT and FSBM
3756         for(i=0; i<len; i++) {
3757             if(Vcb->Vat[i] == UDF_VAT_FREE_ENTRY) {
3758                 UDFSetFreeBit(Vcb->FSBM_Bitmap, root+i);
3759             }
3760         }
3761         len = Vcb->LastPossibleLBA;
3762         // "pre-format" reserved area
3763         for(i=Vcb->NWA; i<len;) {
3764             for(j=0; (j<PACKETSIZE_UDF) && (i<len); j++, i++)
3765                 UDFSetFreeBit(Vcb->FSBM_Bitmap, i);
3766             for(j=0; (j<7) && (i<len); j++, i++)
3767                 UDFSetUsedBit(Vcb->FSBM_Bitmap, i);
3768         }
3769         DbgFreePool(VatOldData);
3770     }
3771     return status;
3772 } // end UDFLoadVAT()
3773 
3774 /*
3775     Reads Extended Attributes
3776     Caller should use UDFGetFileEALength to allocate Buffer of sufficient
3777     size
3778  *//*
3779 OSSTATUS
3780 UDFReadFileEA(
3781     IN PVCB Vcb,
3782     IN PDIR_INDEX FileDirNdx,
3783     OUT int8* Buffer
3784     )
3785 {
3786     PFILE_ENTRY FileEntry;
3787     OSSTATUS status;
3788 
3789     if(FileDirNdx->FileInfo) {
3790         FileEntry = (PFILE_ENTRY)(FileDirNdx->FileInfo->Dloc->FileEntry);
3791     } else {
3792         FileEntry = (PFILE_ENTRY)MyAllocatePool__(NonPagedPool, Vcb->BlockSize);
3793         if(!FileEntry) return;
3794         if(!OS_SUCCESS(status = UDFReadFileEntry(Vcb, &(FileDirNdx->FileEntry), FileEntry, &Ident))) {
3795             MyFreePool__(FileEntry);
3796             return status;
3797         }
3798     }
3799 }*/
3800 /*
3801     This dumb routine checks if the file has been found is deleted
3802     It is introduced to make main modules FS-type independent
3803  */
3804 /*BOOLEAN
3805 UDFIsDeleted(
3806     IN PDIR_INDEX DirNdx
3807     )
3808 {
3809     return (DirNdx->FileCharacteristics & FILE_DELETED);
3810 } */
3811 
3812 /*BOOLEAN
3813 UDFIsADirectory(
3814     IN PUDF_FILE_INFO FileInfo
3815     )
3816 {
3817     ValidateFileInfo(FileInfo);
3818 
3819     if(!FileInfo) return FALSE;
3820     if(FileInfo->Dloc->DirIndex) return TRUE;
3821     if(!(FileInfo->FileIdent)) return FALSE;
3822     return (FileInfo->FileIdent->fileCharacteristics & FILE_DIRECTORY);
3823 } */
3824 /*
3825     This routine calculates actual allocation size
3826  */
3827 /*int64
3828 UDFGetFileAllocationSize(
3829     IN PVCB Vcb,
3830     IN PUDF_FILE_INFO FileInfo
3831     )
3832 {
3833     ValidateFileInfo(FileInfo);
3834 
3835     return UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping);// +
3836 //           UDFGetExtentLength(FileInfo->Dloc->FELoc.Mapping) +
3837 //           UDFGetExtentLength(FileInfo->Dloc->AllocLoc.Mapping) - Vcb->BlockSize;
3838 }*/
3839 
3840 /*
3841     This routine checks if the directory is empty
3842  */
3843 BOOLEAN
3844 UDFIsDirEmpty(
3845     IN PDIR_INDEX_HDR hCurDirNdx
3846     )
3847 {
3848     uint32 fc;
3849     uint_di i;
3850     PDIR_INDEX_ITEM CurDirNdx;
3851     // not empty
3852     for(i=2; (CurDirNdx = UDFDirIndex(hCurDirNdx,i)); i++) {
3853         fc = CurDirNdx->FileCharacteristics;
3854         if(!(fc & (FILE_PARENT | FILE_DELETED)) &&
3855            CurDirNdx->Length)
3856             return FALSE;
3857     }
3858     return TRUE;
3859 } // end UDFIsDirEmpty()
3860 
3861 /*
3862  */
3863 OSSTATUS
3864 UDFFlushFE(
3865     IN PVCB Vcb,
3866     IN PUDF_FILE_INFO FileInfo,
3867     IN uint32 PartNum
3868     )
3869 {
3870     int8* NewAllocDescs;
3871     OSSTATUS status;
3872     SIZE_T WrittenBytes;
3873     uint16 AllocMode;
3874     uint32 lba;
3875 
3876     AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK;
3877 #ifdef UDF_DBG
3878 /*    if(UDFIsADirectory(FileInfo) && (UDFGetFileSize(FileInfo) < 0x28) &&
3879        !UDFIsDeleted(UDFDirIndex(DirInfo->Dloc->DirIndex, FileInfo->Index)) ) {
3880         BrutePoint();
3881     }*/
3882 //    ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3883     if(FileInfo->Dloc->FELoc.Offset) {
3884         BrutePoint();
3885     }
3886     if(FileInfo->Dloc->AllocLoc.Mapping) {
3887         ASSERT(AllocMode != ICB_FLAG_AD_IN_ICB);
3888     }
3889 #endif // UDF_DBG
3890 retry_flush_FE:
3891     UDFPrint(("  FlushFE: %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation));
3892 #ifndef UDF_READ_ONLY_BUILD
3893     UDFReTagDirectory(Vcb, FileInfo);
3894     if(FileInfo->Dloc->DataLoc.Modified ||
3895        FileInfo->Dloc->AllocLoc.Modified) {
3896         ASSERT(PartNum != (uint32)(-1));
3897         // prepare new AllocDescs for flushing...
3898         if(!OS_SUCCESS(status = UDFBuildAllocDescs(Vcb, PartNum, FileInfo, &NewAllocDescs))) {
3899             UDFPrint(("  FlushFE: UDFBuildAllocDescs() faliled (%x)\n", status));
3900             if(NewAllocDescs)
3901                 MyFreePool__(NewAllocDescs);
3902             return status;
3903         }
3904 #ifdef UDF_DBG
3905         if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
3906             ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping));
3907         } else {
3908             ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) ==
3909                    ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)));
3910         }
3911         AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK;
3912 #endif // UDF_DBG
3913         // initiate update of lengthAllocDescs
3914         FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
3915         if(NewAllocDescs) {
3916             ASSERT(AllocMode != ICB_FLAG_AD_IN_ICB);
3917             status = UDFPadLastSector(Vcb, &(FileInfo->Dloc->AllocLoc));
3918             // ... and flush it
3919             status = UDFWriteExtent(Vcb, &(FileInfo->Dloc->AllocLoc), 0, (uint32)(FileInfo->Dloc->AllocLoc.Length), FALSE, NewAllocDescs, &WrittenBytes);
3920             MyFreePool__(NewAllocDescs);
3921             if(!OS_SUCCESS(status)) {
3922                 UDFPrint(("  FlushFE: UDFWriteExtent() faliled (%x)\n", status));
3923                 return status;
3924             }
3925 #ifdef UDF_DBG
3926         } else {
3927             ASSERT(AllocMode == ICB_FLAG_AD_IN_ICB);
3928 #endif // UDF_DBG
3929         }
3930         FileInfo->Dloc->DataLoc.Modified = FALSE;
3931         FileInfo->Dloc->AllocLoc.Modified = FALSE;
3932     } else {
3933 #if defined(UDF_DBG) && !defined(UDF_CHECK_UTIL)
3934         if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
3935             ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping));
3936         } else {
3937             ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) ==
3938                    ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)));
3939         }
3940 #endif // UDF_DBG
3941     }
3942 /*    if(FileInfo->Fcb &&
3943        ((FileInfo->Dloc->FELoc.Mapping[0].extLocation > Vcb->LastLBA) ||
3944         UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) ) {
3945         BrutePoint();
3946     }*/
3947 /*    if(FileInfo->Dloc->FELoc.Mapping[0].extLocation) {
3948         ASSERT( FileInfo->Dloc->FileEntry->tagLocation ==
3949                (FileInfo->Dloc->FELoc.Mapping[0].extLocation - 0x580));
3950     }*/
3951     if((FileInfo->Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) ||
3952         FileInfo->Dloc->FELoc.Modified) {
3953         ASSERT(PartNum != (uint32)(-1));
3954         ASSERT(!PartNum);
3955         if(PartNum == (uint32)(-1) || PartNum == (uint32)(-2)) {
3956             UDFPrint(("  bad PartNum: %d\n", PartNum));
3957         }
3958         // update lengthAllocDescs in FE
3959         UDFSetAllocDescLen(Vcb, FileInfo);
3960 /*        ASSERT( FileInfo->Dloc->FileEntry->tagLocation ==
3961                (FileInfo->Dloc->FELoc.Mapping[0].extLocation - 0x580));*/
3962         // flush FileEntry
3963 
3964         // if FE is located in remapped block, place it to reliable space
3965         lba = FileInfo->Dloc->FELoc.Mapping[0].extLocation;
3966         if(Vcb->BSBM_Bitmap) {
3967             if(UDFGetBadBit((uint32*)(Vcb->BSBM_Bitmap), lba)) {
3968                 AdPrint(("  bad block under FE @%x\n", lba));
3969                 goto relocate_FE;
3970             }
3971         }
3972 
3973         AdPrint(("  setup tag: @%x\n", lba));
3974         ASSERT( lba );
3975         UDFSetUpTag(Vcb, FileInfo->Dloc->FileEntry, (uint16)(FileInfo->Dloc->FileEntryLen),
3976                   UDFPhysLbaToPart(Vcb, PartNum, lba));
3977         status = UDFWriteExtent(Vcb, &(FileInfo->Dloc->FELoc), 0,
3978                   (uint32)(FileInfo->Dloc->FELoc.Length), FALSE,
3979                   (int8*)(FileInfo->Dloc->FileEntry), &WrittenBytes);
3980         if(!OS_SUCCESS(status)) {
3981             UDFPrint(("  FlushFE: UDFWriteExtent(2) faliled (%x)\n", status));
3982             if(status == STATUS_DEVICE_DATA_ERROR) {
3983 relocate_FE:
3984                 UDFPrint(("  try to relocate\n"));
3985 
3986                 EXTENT_INFO _FEExtInfo;
3987                 // calculate the length required
3988 
3989                 // allocate block for FE
3990                 if(OS_SUCCESS(UDFAllocateFESpace(Vcb, FileInfo->ParentFile, PartNum, &_FEExtInfo, (uint32)(FileInfo->Dloc->FELoc.Length)) )) {
3991                     UDFPrint(("  relocate %x -> %x\n",
3992                         lba,
3993                         _FEExtInfo.Mapping[0].extLocation));
3994 
3995                     UDFMarkSpaceAsXXX(Vcb, 0, FileInfo->Dloc->FELoc.Mapping, AS_BAD);
3996 
3997                     UDFRelocateDloc(Vcb, FileInfo->Dloc, _FEExtInfo.Mapping[0].extLocation);
3998                     MyFreePool__(FileInfo->Dloc->FELoc.Mapping);
3999                     FileInfo->Dloc->FELoc.Mapping = _FEExtInfo.Mapping;
4000 
4001                     FileInfo->Dloc->FELoc.Modified = TRUE;
4002                     FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
4003 
4004                     AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK;
4005                     if(AllocMode == ICB_FLAG_AD_IN_ICB) {
4006                         UDFPrint(("  IN-ICB data lost\n"));
4007                         FileInfo->Dloc->DataLoc.Mapping[0].extLocation = _FEExtInfo.Mapping[0].extLocation;
4008                         FileInfo->Dloc->DataLoc.Modified = TRUE;
4009                     } else {
4010                         FileInfo->Dloc->AllocLoc.Mapping[0].extLocation = _FEExtInfo.Mapping[0].extLocation;
4011                         FileInfo->Dloc->AllocLoc.Modified = TRUE;
4012                     }
4013 
4014                     if(FileInfo->Index >= 2) {
4015                         PDIR_INDEX_ITEM DirNdx;
4016                         DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index);
4017                         if(DirNdx) {
4018                             UDFPrint(("  update reference in FI\n"));
4019                             DirNdx->FileEntryLoc.logicalBlockNum =
4020                                 FileInfo->FileIdent->icb.extLocation.logicalBlockNum =
4021                                 UDFPhysLbaToPart(Vcb, PartNum, _FEExtInfo.Mapping[0].extLocation);
4022                             DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
4023                         }
4024                     }
4025                     // this will update
4026                     UDFPrint(("  retry flush...\n"));
4027                     goto retry_flush_FE;
4028                 }
4029             }
4030             BrutePoint();
4031             return status;
4032         }
4033         FileInfo->Dloc->FE_Flags &= ~UDF_FE_FLAG_FE_MODIFIED;
4034         FileInfo->Dloc->FELoc.Modified = FALSE;
4035     } else {
4036         ASSERT((FileInfo->Dloc->FileEntry->descVersion == 2) ||
4037                (FileInfo->Dloc->FileEntry->descVersion == 3));
4038     }
4039 #endif //UDF_READ_ONLY_BUILD
4040 #ifdef UDF_DBG
4041     if(FileInfo->Dloc->AllocLoc.Mapping) {
4042         ASSERT(AllocMode != ICB_FLAG_AD_IN_ICB);
4043     } else {
4044         ASSERT(AllocMode == ICB_FLAG_AD_IN_ICB);
4045     }
4046 #endif // UDF_DBG
4047     return STATUS_SUCCESS;
4048 } // end UDFFlushFE()
4049 
4050 OSSTATUS
4051 UDFFlushFI(
4052     IN PVCB Vcb,
4053     IN PUDF_FILE_INFO FileInfo,
4054     IN uint32 PartNum
4055     )
4056 {
4057     PUDF_FILE_INFO DirInfo = FileInfo->ParentFile;
4058     PDIR_INDEX_ITEM DirNdx;
4059     OSSTATUS status;
4060     SIZE_T WrittenBytes;
4061     // use WrittenBytes variable to store LBA of FI to be recorded
4062     #define lba   WrittenBytes
4063 
4064 //    ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
4065     // some files has no FI
4066     if(!DirInfo || UDFIsAStreamDir(FileInfo))
4067         return STATUS_SUCCESS;
4068     DirNdx = UDFDirIndex(DirInfo->Dloc->DirIndex, FileInfo->Index);
4069 //    ASSERT(FileInfo->FileIdent->lengthFileIdent < 0x80);
4070 #ifdef UDF_DBG
4071     if(DirNdx->FileCharacteristics & FILE_DELETED) {
4072         ASSERT(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED);
4073     }
4074 #endif // UDF_DBG
4075     UDFPrint(("  FlushFI: offs %x\n", (ULONG)(DirNdx->Offset)));
4076 #ifndef UDF_READ_ONLY_BUILD
4077     if((DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) {
4078         // flush FileIdent
4079         ASSERT(PartNum != (uint32)(-1));
4080         FileInfo->FileIdent->fileCharacteristics = DirNdx->FileCharacteristics;
4081         lba = UDFExtentOffsetToLba(Vcb, DirInfo->Dloc->DataLoc.Mapping,
4082                                         DirNdx->Offset, NULL, NULL, NULL, NULL);
4083         AdPrint(("  FI lba %x\n", lba));
4084         // check if requested Offset is allocated
4085         if(lba == (uint32)LBA_OUT_OF_EXTENT) {
4086             // write 1 byte
4087             if(!OS_SUCCESS(status = UDFWriteFile__(Vcb, DirInfo, DirNdx->Offset, 1, FALSE, (int8*)(FileInfo->FileIdent), &WrittenBytes) )) {
4088                 BrutePoint();
4089                 return status;
4090             }
4091             lba = UDFExtentOffsetToLba(Vcb, DirInfo->Dloc->DataLoc.Mapping,
4092                                             DirNdx->Offset, NULL, NULL, NULL, NULL);
4093             AdPrint(("  allocated FI lba %x\n", lba));
4094             // check if requested Offset is allocated
4095             if(lba == (uint32)LBA_OUT_OF_EXTENT) {
4096                 BrutePoint();
4097                 return STATUS_UNSUCCESSFUL;
4098             }
4099         }
4100         // init structure
4101         UDFSetUpTag(Vcb, &(FileInfo->FileIdent->descTag), (uint16)(FileInfo->FileIdentLen),
4102                   UDFPhysLbaToPart(Vcb, PartNum, lba));
4103         // record data
4104         if(!OS_SUCCESS(status = UDFWriteFile__(Vcb, DirInfo, DirNdx->Offset, FileInfo->FileIdentLen, FALSE, (int8*)(FileInfo->FileIdent), &WrittenBytes) )) {
4105             BrutePoint();
4106             return status;
4107         }
4108         DirNdx->FI_Flags &= ~UDF_FI_FLAG_FI_MODIFIED;
4109     }
4110 #endif //UDF_READ_ONLY_BUILD
4111     return STATUS_SUCCESS;
4112 } // end UDFFlushFI()
4113 
4114 /*
4115     This routine updates AllocDesc sequence, FileIdent & FileEntry
4116     for given file
4117  */
4118 OSSTATUS
4119 UDFFlushFile__(
4120     IN PVCB Vcb,
4121     IN PUDF_FILE_INFO FileInfo,
4122     IN ULONG FlushFlags
4123     )
4124 {
4125     ValidateFileInfo(FileInfo);
4126 
4127     if(!FileInfo) return STATUS_SUCCESS;
4128     OSSTATUS status;
4129     uint32 PartNum;
4130 
4131     ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
4132     PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
4133     if(PartNum == (uint32)-1) {
4134         UDFPrint(("  Is DELETED ?\n"));
4135         if(FileInfo->ParentFile) {
4136             PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->ParentFile->Dloc->FELoc.Mapping[0].extLocation);
4137         } else {
4138             BrutePoint();
4139         }
4140     }
4141 #ifdef UDF_CHECK_DISK_ALLOCATION
4142     if( FileInfo->Fcb &&
4143         UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) {
4144 
4145         if(UDFIsAStreamDir(FileInfo)) {
4146             if(!UDFIsSDirDeleted(FileInfo)) {
4147                 UDFPrint(("  Not DELETED SDir\n"));
4148                 BrutePoint();
4149             }
4150             ASSERT(!FileInfo->Dloc->FELoc.Modified);
4151         } else
4152         if(!FileInfo->FileIdent ||
4153            !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED)) {
4154             if(!FileInfo->FileIdent)
4155                 AdPrint(("  No FileIdent\n"));
4156             if(FileInfo->FileIdent &&
4157                !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED))
4158                 AdPrint(("  Not DELETED\n"));
4159             AdPrint(("Flushing to Discarded block %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation));
4160             BrutePoint();
4161         }
4162     }
4163 #endif // UDF_CHECK_DISK_ALLOCATION
4164 
4165     // flush FE and pre-allocation charge for directories
4166     if(FileInfo->Dloc &&
4167        FileInfo->Dloc->DirIndex) {
4168         // if Lite Flush is used, keep preallocations
4169         if(!(FlushFlags & UDF_FLUSH_FLAGS_LITE)) {
4170 full_flush:
4171             UDFFlushFESpace(Vcb, FileInfo->Dloc);
4172             if(FileInfo->Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) {
4173                 FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_CUT_PREALLOCATED;
4174                 status = UDFResizeExtent(Vcb, PartNum, UDFGetFileSize(FileInfo), FALSE, &(FileInfo->Dloc->DataLoc));
4175                 FileInfo->Dloc->DataLoc.Flags &= ~(EXTENT_FLAG_PREALLOCATED | EXTENT_FLAG_CUT_PREALLOCATED);
4176                 if(OS_SUCCESS(status)) {
4177                     AdPrint(("Dir pre-alloc truncated (Flush)\n"));
4178                     FileInfo->Dloc->DataLoc.Modified = TRUE;
4179                 }
4180             }
4181         }
4182     }
4183     // flush FE
4184     if(!OS_SUCCESS(status = UDFFlushFE(Vcb, FileInfo, PartNum))) {
4185         UDFPrint(("Error flushing FE\n"));
4186         BrutePoint();
4187         if(FlushFlags & UDF_FLUSH_FLAGS_LITE) {
4188             UDFPrint(("  flush pre-alloc\n"));
4189             FlushFlags &= ~UDF_FLUSH_FLAGS_LITE;
4190             goto full_flush;
4191         }
4192         if(FileInfo->Index >= 2) {
4193             PDIR_INDEX_ITEM DirNdx;
4194             DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index);
4195             if(DirNdx) {
4196                 UDFPrint(("Recovery: mark as deleted & flush FI\n"));
4197                 DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
4198                 DirNdx->FileCharacteristics |= FILE_DELETED;
4199                 FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED;
4200                 UDFFlushFI(Vcb, FileInfo, PartNum);
4201             }
4202         }
4203         return status;
4204     }
4205     if(!OS_SUCCESS(status = UDFFlushFI(Vcb, FileInfo, PartNum)))
4206         return status;
4207 
4208     ASSERT((FileInfo->Dloc->FileEntry->descVersion == 2) ||
4209            (FileInfo->Dloc->FileEntry->descVersion == 3));
4210 
4211     return STATUS_SUCCESS;
4212 } // end UDFFlushFile__()
4213 
4214 /*
4215     This routine compares 2 FileInfo structures
4216  */
4217 BOOLEAN
4218 UDFCompareFileInfo(
4219     IN PUDF_FILE_INFO f1,
4220     IN PUDF_FILE_INFO f2
4221     )
4222 {
4223     uint_di i;
4224     PDIR_INDEX_HDR hDirIndex1;
4225     PDIR_INDEX_HDR hDirIndex2;
4226     PDIR_INDEX_ITEM DirIndex1;
4227     PDIR_INDEX_ITEM DirIndex2;
4228 
4229     if(!f1 || !f2) return FALSE;
4230     if(f1->Dloc->FileEntryLen != f2->Dloc->FileEntryLen) return FALSE;
4231 //    if(f1->FileIdentLen != f2->FileIdentLen) return FALSE;
4232 /*    if(f1->Dloc->DirIndex && !f2->Dloc->DirIndex) return FALSE;
4233     if(f2->Dloc->DirIndex && !f1->Dloc->DirIndex) return FALSE;
4234     if((f1->Dloc->DirIndex) &&
4235        (f1->Dloc->DirIndex->LastFrameCount != f2->Dloc->DirIndex->LastFrameCount)) return FALSE;*/
4236     if(f1->Index != f2->Index) return FALSE;
4237     if(!(f1->Dloc->DataLoc.Mapping)) return FALSE;
4238     if(!(f2->Dloc->DataLoc.Mapping)) return FALSE;
4239     if(f1->Dloc->DataLoc.Mapping[0].extLocation != f2->Dloc->DataLoc.Mapping[0].extLocation) return FALSE;
4240     if(f1->Dloc->DataLoc.Mapping[0].extLength != f2->Dloc->DataLoc.Mapping[0].extLength) return FALSE;
4241 //    if(f1-> != f2->) return FALSE;
4242 //    if(f1-> != f2->) return FALSE;
4243 //    if(f1-> != f2->) return FALSE;
4244     if(!(f1->Dloc->FileEntry)) return FALSE;
4245     if(!(f2->Dloc->FileEntry)) return FALSE;
4246     if(RtlCompareMemory(f1->Dloc->FileEntry, f2->Dloc->FileEntry, f2->Dloc->FileEntryLen) != f2->Dloc->FileEntryLen)
4247         return FALSE;
4248     if(!(hDirIndex1 = f1->Dloc->DirIndex)) return FALSE;
4249     if(!(hDirIndex2 = f2->Dloc->DirIndex)) return FALSE;
4250 
4251     for(i=2; (DirIndex1 = UDFDirIndex(hDirIndex1,i)) &&
4252              (DirIndex2 = UDFDirIndex(hDirIndex2,i)); i++) {
4253         if( DirIndex1->FName.Buffer &&
4254            !DirIndex2->FName.Buffer)
4255             return FALSE;
4256         if( DirIndex2->FName.Buffer &&
4257            !DirIndex1->FName.Buffer)
4258             return FALSE;
4259         if(!DirIndex2->FName.Buffer &&
4260            !DirIndex1->FName.Buffer)
4261             continue;
4262         if(RtlCompareUnicodeString(&(DirIndex1->FName),
4263                                    &(DirIndex2->FName),FALSE)) {
4264             return FALSE;
4265         }
4266 //        if(DirIndex1[i].FileEntry != DirIndex2[i].FileEntry)
4267 //            return FALSE;
4268         if(RtlCompareMemory(&(DirIndex1->FileEntryLoc),
4269                             &(DirIndex2->FileEntryLoc), sizeof(lb_addr)) != sizeof(lb_addr))
4270             return FALSE;
4271     }
4272 
4273     return TRUE;
4274 } // end UDFCompareFileInfo()
4275 
4276 /*
4277     This routine computes 32-bit hash based on CRC-32 from SSH
4278  */
4279 
4280 #ifdef _MSC_VER
4281 #pragma warning(push)
4282 #pragma warning(disable:4035)               // re-enable below
4283 #endif
4284 
4285 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
4286 __declspec (naked)
4287 #endif // _X86_
4288 uint32
4289 __fastcall
4290 crc32(
4291     IN uint8* s,  // ECX
4292     IN uint32 len // EDX
4293     )
4294 {
4295 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
4296 //    uint32 _Size = len;
4297 
4298     __asm {
4299         push  ebx
4300         push  ecx
4301         push  edx
4302         push  esi
4303 
4304         xor   eax,eax
4305         mov   esi,ecx  // ESI <- s
4306         mov   ecx,edx  // ECX <- len
4307 
4308         jecxz EO_CRC
4309 
4310         lea   ebx,[crc32_tab]
4311         xor   edx,edx
4312 
4313 CRC_loop:
4314 
4315         mov   dl,al
4316         xor   dl,[esi]
4317         shr   eax,8
4318         xor   eax,[dword ptr ebx+edx*4]
4319         inc   esi
4320         loop  CRC_loop
4321 
4322 EO_CRC:
4323 
4324         pop   esi
4325         pop   edx
4326         pop   ecx
4327         pop   ebx
4328 
4329         ret
4330     }
4331 #else  // NO X86 optimization , use generic C/C++
4332     uint32 i;
4333     uint32 crc32val = 0;
4334 
4335     for(i=0; i<len; i++, s++) {
4336         crc32val =
4337             crc32_tab[(crc32val ^ (*s)) & 0xff] ^ (crc32val >> 8);
4338     }
4339     return crc32val;
4340 #endif // _X86_
4341 } // end crc32()
4342 
4343 /*
4344     Calculate a 16-bit CRC checksum for unicode strings
4345     using ITU-T V.41 polynomial.
4346 
4347     The OSTA-UDF(tm) 1.50 standard states that using CRCs is mandatory.
4348     The polynomial used is: x^16 + x^12 + x^15 + 1
4349 */
4350 
4351 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
4352 __declspec (naked)
4353 #endif // _X86_
4354 uint16
4355 __fastcall
4356 UDFUnicodeCksum(
4357     PWCHAR s, // ECX
4358     uint32 n  // EDX
4359     )
4360 {
4361 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
4362 //    uint32 _Size = n;
4363 
4364     __asm {
4365         push  ebx
4366         push  ecx
4367         push  edx
4368         push  esi
4369 
4370         xor   eax,eax
4371         mov   esi,ecx
4372         mov   ecx,edx
4373 
4374         jecxz EO_uCRC
4375 
4376         lea   ebx,[CrcTable]
4377         xor   edx,edx
4378 
4379 uCRC_loop:
4380 
4381         mov   dl,ah            // dl = (Crc >> 8)
4382         xor   dl,[esi+1]       // dl = ((Crc >> 8) ^ (*s >> 8)) & 0xff
4383         mov   ah,al
4384         mov   al,dh            // ax = (Crc << 8)
4385         xor   ax,[word ptr ebx+edx*2]  // ax = ...........
4386 
4387         mov   dl,ah
4388         xor   dl,[esi]
4389         mov   ah,al
4390         mov   al,dh
4391         xor   ax,[word ptr ebx+edx*2]
4392 
4393         inc   esi
4394         inc   esi
4395         loop  uCRC_loop
4396 
4397 EO_uCRC:
4398 
4399         pop   esi
4400         pop   edx
4401         pop   ecx
4402         pop   ebx
4403 
4404         ret
4405     }
4406 #else  // NO X86 optimization , use generic C/C++
4407     uint16 Crc = 0;
4408     while (n--) {
4409         Crc = CrcTable[(Crc >> 8 ^ (*s >> 8)) & 0xff] ^ (Crc << 8);
4410         Crc = CrcTable[(Crc >> 8 ^ (*s++ & 0xff)) & 0xff] ^ (Crc << 8);
4411     }
4412     return Crc;
4413 
4414 #endif // _X86_
4415 } // end UDFUnicodeCksum()
4416 
4417 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
4418 __declspec (naked)
4419 #endif // _X86_
4420 uint16
4421 __fastcall
4422 UDFUnicodeCksum150(
4423     PWCHAR s, // ECX
4424     uint32 n  // EDX
4425     )
4426 {
4427 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
4428 //    uint32 _Size = n;
4429 
4430     __asm {
4431         push  ebx
4432         push  ecx
4433         push  edx
4434         push  esi
4435         push  edi
4436 
4437         xor   eax,eax
4438         mov   esi,ecx
4439         mov   ecx,edx
4440         xor   edi,edi
4441 
4442         jecxz EO_uCRC
4443 
4444         //lea   ebx,[CrcTable]
4445         xor   edx,edx
4446         xor   ebx,ebx
4447 
4448 uCRC_loop:
4449 
4450         mov   dl,ah            // dl = (Crc >> 8)
4451         or    edi,edx          // if(*s & 0xff00) Use16 = TRUE;
4452         xor   dl,[esi+1]       // dl = ((Crc >> 8) ^ (*s >> 8)) & 0xff
4453         mov   ah,al
4454         mov   al,0             // ax = (Crc << 8)
4455         xor   ax,[word ptr CrcTable+edx*2]  // ax = ...........
4456 
4457         mov   dl,ah
4458         xor   dl,[esi]
4459         mov   ah,al
4460         mov   al,0
4461         xor   ax,[word ptr CrcTable+edx*2]
4462 
4463         or    edi,edi          // if(!Use16) {
4464         jnz   use16_1
4465 
4466         rol   eax,16
4467 
4468         mov   bl,ah            // dl = (Crc >> 8)
4469         xor   bl,[esi]         // dl = ((Crc >> 8) ^ (*s >> 8)) & 0xff
4470         mov   ah,al
4471         mov   al,0             // ax = (Crc << 8)
4472         xor   ax,[word ptr CrcTable+ebx*2]  // ax = ...........
4473 
4474         rol   eax,16
4475 use16_1:
4476         inc   esi
4477         inc   esi
4478         loop  uCRC_loop
4479 
4480 EO_uCRC:
4481 
4482         or    edi,edi          // if(!Use16) {
4483         jnz   use16_2
4484 
4485         rol   eax,16           // }
4486 use16_2:
4487         and   eax,0xffff
4488 
4489         pop   edi
4490         pop   esi
4491         pop   edx
4492         pop   ecx
4493         pop   ebx
4494 
4495         ret
4496     }
4497 #else  // NO X86 optimization , use generic C/C++
4498     uint16 Crc = 0;
4499     uint16 Crc2 = 0;
4500     BOOLEAN Use16 = FALSE;
4501     while (n--) {
4502         if(!Use16) {
4503             if((*s) & 0xff00) {
4504                 Use16 = TRUE;
4505             } else {
4506                 Crc2 = CrcTable[(Crc2 >> 8 ^ (*s >> 8)) & 0xff] ^ (Crc2 << 8);
4507             }
4508         }
4509         Crc = CrcTable[(Crc >> 8 ^ (*s >> 8)) & 0xff] ^ (Crc << 8);
4510         Crc = CrcTable[(Crc >> 8 ^ (*s++ & 0xff)) & 0xff] ^ (Crc << 8);
4511     }
4512     return Use16 ? Crc : Crc2;
4513 #endif // _X86_
4514 } // end UDFUnicodeCksum150()
4515 
4516 /*
4517     Calculate a 16-bit CRC checksum using ITU-T V.41 polynomial.
4518 
4519     The OSTA-UDF(tm) 1.50 standard states that using CRCs is mandatory.
4520     The polynomial used is: x^16 + x^12 + x^15 + 1
4521 */
4522 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
4523 __declspec (naked)
4524 #endif // _X86_
4525 uint16
4526 __fastcall
4527 UDFCrc(
4528     IN uint8* Data, // ECX
4529     IN SIZE_T Size  // EDX
4530     )
4531 {
4532 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__)
4533 //    uint32 _Size = Size;
4534 
4535     __asm {
4536         push  ebx
4537         push  ecx
4538         push  edx
4539         push  esi
4540 
4541         mov   esi,ecx
4542         mov   ecx,edx
4543         xor   eax,eax
4544 
4545         jecxz EO_CRC
4546 
4547         lea   ebx,[CrcTable]
4548         xor   edx,edx
4549 
4550 CRC_loop:
4551 
4552         mov   dl,ah
4553         xor   dl,[esi]
4554         mov   ah,al
4555         mov   al,dh
4556         xor   ax,[word ptr ebx+edx*2]
4557         inc   esi
4558         loop  CRC_loop
4559 
4560 EO_CRC:
4561 
4562         pop   esi
4563         pop   edx
4564         pop   ecx
4565         pop   ebx
4566 
4567         ret
4568     }
4569 #else  // NO X86 optimization , use generic C/C++
4570     uint16 Crc = 0;
4571     while (Size--)
4572         Crc = CrcTable[(Crc >> 8 ^ *Data++) & 0xff] ^ (Crc << 8);
4573     return Crc;
4574 #endif // _X86_
4575 
4576 } // end UDFCrc()
4577 
4578 #ifdef _MSC_VER
4579 #pragma warning(pop)    // re-enable warning #4035
4580 #endif
4581 
4582 /*
4583     Read the first block of a tagged descriptor & check it.
4584 */
4585 OSSTATUS
4586 UDFReadTagged(
4587     PVCB Vcb,
4588     int8* Buf,
4589     uint32 Block,
4590     uint32 Location,
4591     uint16 *Ident
4592     )
4593 {
4594     OSSTATUS RC;
4595     tag* PTag = (tag*)Buf;
4596 //    icbtag* Icb = (icbtag*)(Buf+1);
4597     uint8 checksum;
4598     unsigned int i;
4599     SIZE_T ReadBytes;
4600     int8* tb;
4601 
4602     // Read the block
4603     if(Block == 0xFFFFFFFF)
4604         return NULL;
4605 
4606     _SEH2_TRY {
4607         RC = UDFReadSectors(Vcb, FALSE, Block, 1, FALSE, Buf, &ReadBytes);
4608         if(!OS_SUCCESS(RC)) {
4609             UDFPrint(("UDF: Block=%x, Location=%x: read failed\n", Block, Location));
4610             try_return(RC);
4611         }
4612 
4613         *Ident = PTag->tagIdent;
4614 
4615         if(Location != PTag->tagLocation) {
4616             UDFPrint(("UDF: location mismatch block %x, tag %x != %x\n",
4617                 Block, PTag->tagLocation, Location));
4618             try_return(RC = STATUS_FILE_CORRUPT_ERROR);
4619         }
4620 
4621         /* Verify the tag checksum */
4622         checksum = 0;
4623         tb = Buf;
4624         for (i=0; i<sizeof(tag); i++, tb++)
4625             checksum += (uint8)((i!=4) ? (*tb) : 0);
4626 
4627         if(checksum != PTag->tagChecksum) {
4628             UDFPrint(("UDF: tag checksum failed block %x\n", Block));
4629             try_return(RC = STATUS_CRC_ERROR);
4630         }
4631 
4632         // Verify the tag version
4633         if((PTag->descVersion != 2) &&
4634            (PTag->descVersion != 3)) {
4635             UDFPrint(("UDF: Tag version 0x%04x != 0x0002 || 0x0003 block %x\n",
4636                 (PTag->descVersion), Block));
4637             try_return(RC = STATUS_FILE_CORRUPT_ERROR);
4638         }
4639 
4640         // Verify the descriptor CRC
4641         if(((PTag->descCRCLength) + sizeof(tag) > Vcb->BlockSize) ||
4642            ((PTag->descCRC) == UDFCrc((uint8*)Buf + sizeof(tag), PTag->descCRCLength)) ||
4643            !(PTag->descCRC) ) {
4644     /*        UDFPrint(("Tag ID: %x, ver %x\t", PTag->tagIdent, PTag->descVersion ));
4645             if((i == TID_FILE_ENTRY) ||
4646                (i == TID_EXTENDED_FILE_ENTRY)) {
4647                 UDFPrint(("StrategType: %x, ", Icb->strategyType ));
4648                 UDFPrint(("FileType: %x\t", Icb->fileType ));
4649             }
4650             UDFPrint(("\n"));*/
4651             try_return(RC = STATUS_SUCCESS);
4652         }
4653         UDFPrint(("UDF: Crc failure block %x: crc = %x, crclen = %x\n",
4654             Block, PTag->descCRC, PTag->descCRCLength));
4655         RC = STATUS_CRC_ERROR;
4656 
4657 try_exit:    NOTHING;
4658 
4659     } _SEH2_FINALLY {
4660         ;
4661     } _SEH2_END
4662 
4663     return RC;
4664 } // end UDFReadTagged()
4665 
4666 #ifndef UDF_READ_ONLY_BUILD
4667 /*
4668     This routine creates hard link for the file from DirInfo1
4669     to DirInfo2 & names it as fn
4670  */
4671 OSSTATUS
4672 UDFHardLinkFile__(
4673     IN PVCB Vcb,
4674     IN BOOLEAN IgnoreCase,
4675  IN OUT BOOLEAN* Replace,        // replace if destination file exists
4676     IN PUNICODE_STRING fn,       // destination
4677  IN OUT PUDF_FILE_INFO DirInfo1,
4678  IN OUT PUDF_FILE_INFO DirInfo2,
4679  IN OUT PUDF_FILE_INFO FileInfo  // source (opened)
4680     )
4681 {
4682     PUDF_FILE_INFO FileInfo2;
4683     OSSTATUS status;
4684     PDIR_INDEX_ITEM DirNdx1;
4685     PDIR_INDEX_ITEM DirNdx2;
4686     uint_di i;
4687     BOOLEAN Recovery = FALSE;
4688     BOOLEAN SameFE = FALSE;
4689     uint32 NTAttr = 0;
4690 
4691     // validate FileInfo
4692     ValidateFileInfo(DirInfo1);
4693     ValidateFileInfo(DirInfo2);
4694     ValidateFileInfo(FileInfo);
4695 
4696     if(UDFGetFileLinkCount(FileInfo) >= UDF_MAX_LINK_COUNT) {
4697         // too many links to file...
4698         return STATUS_TOO_MANY_LINKS;
4699     }
4700 
4701     i = 0;
4702     if(DirInfo1 == DirInfo2) {
4703         if(OS_SUCCESS(status = UDFFindFile(Vcb, IgnoreCase, TRUE, fn, DirInfo2, &i)) &&
4704            (i==FileInfo->Index) ) {
4705             // case-only difference
4706             return STATUS_OBJECT_NAME_COLLISION;
4707         }
4708     }
4709 
4710     // PHASE 0
4711     // try to create new FileIdent & FileEntry in Dir2
4712 
4713 HLinkRetry:
4714     if(!OS_SUCCESS(status = UDFCreateFile__(Vcb, IgnoreCase, fn, UDFGetFileEALength(FileInfo),
4715                     0, (FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY),
4716                     TRUE, DirInfo2, &FileInfo2))) {
4717         if(UDFCleanUpFile__(Vcb, FileInfo2) && FileInfo2)
4718             MyFreePool__(FileInfo2);
4719         if(status == STATUS_ACCESS_DENIED) {
4720             // try to recover >;->
4721             if((*Replace) && !Recovery) {
4722                 Recovery = TRUE;
4723                 status = UDFOpenFile__(Vcb, IgnoreCase, TRUE, fn, DirInfo2, &FileInfo2, NULL);
4724                 if(OS_SUCCESS(status)) {
4725                     status = UDFDoesOSAllowFileToBeTargetForHLink__(FileInfo2);
4726                     if(!OS_SUCCESS(status)) {
4727                         UDFCloseFile__(Vcb, FileInfo2);
4728                         goto cleanup_and_abort_hlink;
4729                     }
4730                     if((FileInfo->Dloc == FileInfo2->Dloc)  &&
4731                        (FileInfo != FileInfo2)) {
4732                         SameFE = TRUE;
4733                         // 'status' is already STATUS_SUCCESS here
4734                     } else {
4735                         status = UDFUnlinkFile__(Vcb, FileInfo2, TRUE);
4736                     }
4737                     UDFCloseFile__(Vcb, FileInfo2);
4738                     if(UDFCleanUpFile__(Vcb, FileInfo2)) {
4739                         MyFreePool__(FileInfo2);
4740                         FileInfo2 = NULL;
4741                         if(SameFE)
4742                             return STATUS_SUCCESS;
4743                     } else {
4744                         // we get here if the FileInfo has associated
4745                         // system-specific Fcb
4746                         // Such fact means that not all system references
4747                         // has already gone (except Linked file case)
4748                         if(SameFE)
4749                             return STATUS_SUCCESS;
4750                         if(!OS_SUCCESS(status) ||
4751                            (UDFGetFileLinkCount(FileInfo) < 1))
4752                             status = STATUS_ACCESS_DENIED;
4753                     }
4754                     if(OS_SUCCESS(status)) goto HLinkRetry;
4755                 }
4756 cleanup_and_abort_hlink:
4757                 if(FileInfo2 && UDFCleanUpFile__(Vcb, FileInfo2)) {
4758                     MyFreePool__(FileInfo2);
4759                     FileInfo2 = NULL;
4760                 }
4761             } else {
4762                 status = STATUS_OBJECT_NAME_COLLISION;
4763             }
4764         }
4765         return status;
4766     }
4767     // update pointers
4768     DirNdx1 = UDFDirIndex(DirInfo1->Dloc->DirIndex, FileInfo->Index);
4769     DirNdx2 = UDFDirIndex(DirInfo2->Dloc->DirIndex, FileInfo2->Index);
4770 
4771     // copy file attributes to newly created FileIdent
4772     NTAttr = UDFAttributesToNT(DirNdx1, FileInfo->Dloc->FileEntry);
4773     FileInfo2->FileIdent->fileVersionNum = FileInfo->FileIdent->fileVersionNum;
4774 
4775     // PHASE 1
4776     // copy all necessary info from FileInfo to FileInfo2
4777 
4778     FileInfo2->FileIdent->icb = FileInfo->FileIdent->icb;
4779     FileInfo2->FileIdent->fileCharacteristics = FileInfo->FileIdent->fileCharacteristics;
4780     FileInfo2->FileIdent->fileVersionNum = FileInfo->FileIdent->fileVersionNum;
4781 
4782     DirNdx2->FileCharacteristics = DirNdx1->FileCharacteristics & ~FILE_DELETED;
4783     DirNdx2->FileEntryLoc = DirNdx1->FileEntryLoc;
4784     DirNdx2->FI_Flags = (DirNdx1->FI_Flags & ~UDF_FI_FLAG_SYS_ATTR) | UDF_FI_FLAG_FI_MODIFIED | UDF_FI_FLAG_LINKED;
4785 
4786     UDFAttributesToUDF(DirNdx2, FileInfo2->Dloc->FileEntry, NTAttr);
4787 
4788     // PHASE 2
4789     // update FileInfo
4790 
4791     FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
4792     DirNdx1->FI_Flags = DirNdx2->FI_Flags;
4793     UDFIncFileLinkCount(FileInfo); // increase to 1
4794 //    UDFUpdateModifyTime(Vcb, FileInfo);
4795     FileInfo->Dloc->LinkRefCount += FileInfo2->Dloc->LinkRefCount;
4796     if(FileInfo2->FileIdent)
4797         ((FidADImpUse*)&(FileInfo2->FileIdent->icb.impUse))->uniqueID = (uint32)UDFAssingNewFUID(Vcb);
4798 
4799     // PHASE 3
4800     // drop all unnecessary info from FileInfo2
4801 
4802     UDFFreeFESpace(Vcb, DirInfo2, &(FileInfo2->Dloc->FELoc));
4803     UDFRemoveDloc(Vcb, FileInfo2->Dloc);
4804 
4805     // PHASE 4
4806     // perform in-memory linkage (update driver's tree structures) and flush
4807 
4808     FileInfo2->Dloc = FileInfo->Dloc;
4809     UDFInsertLinkedFile(FileInfo2, FileInfo);
4810 
4811     UDFCloseFile__(Vcb, FileInfo2);
4812     if(UDFCleanUpFile__(Vcb, FileInfo2)) {
4813         MyFreePool__(FileInfo2);
4814     }
4815     // return 'delete target' status
4816     (*Replace) = Recovery;
4817 
4818     return STATUS_SUCCESS;
4819 } // end UDFHardLinkFile__()
4820 
4821 /*
4822     This routine allocates FileEntry with in-ICB zero-sized data
4823     If it returns status != STATUS_SUCCESS caller should call UDFCleanUpFile__
4824     for returned pointer *WITHOUT* using UDFCloseFile__
4825  */
4826 OSSTATUS
4827 UDFCreateRootFile__(
4828     IN PVCB Vcb,
4829 //    IN uint16 AllocMode, // short/long/ext/in-icb  // always in-ICB
4830     IN uint32 PartNum,
4831     IN uint32 ExtAttrSz,
4832     IN uint32 ImpUseLen,
4833     IN BOOLEAN Extended,
4834     OUT PUDF_FILE_INFO* _FileInfo
4835     )
4836 {
4837     OSSTATUS status;
4838     LONG_AD FEicb;
4839     PUDF_FILE_INFO FileInfo;
4840     *_FileInfo = NULL;
4841     SIZE_T ReadBytes;
4842 
4843     FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_FINF_TAG);
4844     *_FileInfo = FileInfo;
4845     if(!FileInfo)
4846         return STATUS_INSUFFICIENT_RESOURCES;
4847     ImpUseLen = (ImpUseLen + 3) & ~((uint16)3);
4848 
4849     RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO));
4850     // init horizontal links
4851     FileInfo->NextLinkedFile =
4852     FileInfo->PrevLinkedFile = FileInfo;
4853     // allocate space for FileEntry
4854     if(!OS_SUCCESS(status =
4855         UDFBuildFileEntry(Vcb, NULL, FileInfo, PartNum, ICB_FLAG_AD_IN_ICB, ExtAttrSz, Extended) ))
4856         return status;
4857     FEicb.extLength = Vcb->LBlockSize;
4858     FEicb.extLocation.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
4859     FEicb.extLocation.partitionReferenceNum = (uint16)PartNum;
4860     RtlZeroMemory(&(FEicb.impUse), sizeof(FEicb.impUse));
4861 
4862     FileInfo->Dloc->DataLoc.Mapping = UDFExtentToMapping(&(FileInfo->Dloc->FELoc.Mapping[0]));
4863     if(!(FileInfo->Dloc->DataLoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES;
4864     FileInfo->Dloc->DataLoc.Length = 0;
4865     FileInfo->Dloc->DataLoc.Offset = FileInfo->Dloc->FileEntryLen;
4866     // init FileEntry
4867     UDFSetFileUID(Vcb, FileInfo);
4868     UDFSetFileSize(FileInfo, 0);
4869     UDFIncFileLinkCount(FileInfo); // increase to 1
4870     UDFUpdateCreateTime(Vcb, FileInfo);
4871     // zero sector for FileEntry
4872     FileInfo->Dloc->DataLoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK;
4873     FileInfo->Dloc->FELoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK;
4874     status = UDFWriteData(Vcb, TRUE, ((int64)(FileInfo->Dloc->FELoc.Mapping[0].extLocation)) << Vcb->BlockSizeBits, Vcb->LBlockSize, FALSE, Vcb->ZBuffer, &ReadBytes);
4875     if(!OS_SUCCESS(status))
4876         return status;
4877 
4878     UDFReferenceFile__(FileInfo);
4879     UDFReleaseDloc(Vcb, FileInfo->Dloc);
4880     return STATUS_SUCCESS;
4881 } // end UDFCreateRootFile__()
4882 
4883 /*
4884     This routine tries to create StreamDirectory associated with given file
4885     Caller should use UDFCleanUpFile__ if returned status != STATUS_SUCCESS
4886  */
4887 OSSTATUS
4888 UDFCreateStreamDir__(
4889     IN PVCB Vcb,
4890     IN PUDF_FILE_INFO FileInfo,    // file containing stream-dir
4891     OUT PUDF_FILE_INFO* _SDirInfo  // this is to be filled & doesn't contain
4892                                    // any pointers
4893     )
4894 {
4895     OSSTATUS status;
4896     PUDF_FILE_INFO SDirInfo;
4897     uint16 Ident;
4898 
4899     *_SDirInfo = NULL;
4900     ValidateFileInfo(FileInfo);
4901     // check currently recorded UDF revision
4902     if(!UDFStreamsSupported(Vcb))
4903         return STATUS_INVALID_PARAMETER;
4904     // check if we are allowed to associate Stream Dir with this file
4905     if((FileInfo->ParentFile && UDFIsAStreamDir(FileInfo->ParentFile)) ||
4906         UDFHasAStreamDir(FileInfo))
4907         return STATUS_FILE_DELETED;
4908     // check if we have Deleted SDir
4909     if(FileInfo->Dloc->SDirInfo &&
4910        UDFIsSDirDeleted(FileInfo->Dloc->SDirInfo))
4911         return STATUS_ACCESS_DENIED;
4912     // check if this file has ExtendedFileEntry
4913     if((Ident = FileInfo->Dloc->FileEntry->tagIdent) != TID_EXTENDED_FILE_ENTRY) {
4914         if(!OS_SUCCESS(status = UDFConvertFEToExtended(Vcb, FileInfo)))
4915             return status;
4916     }
4917 
4918     uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
4919     // create stream directory file
4920     if(!OS_SUCCESS(status = UDFCreateRootFile__(Vcb, PartNum, 0,0,FALSE, &SDirInfo)))
4921         return status;
4922     // link objects
4923     SDirInfo->ParentFile = FileInfo;
4924     // record directory structure
4925     SDirInfo->Dloc->FE_Flags |= (UDF_FE_FLAG_FE_MODIFIED | UDF_FE_FLAG_IS_SDIR);
4926 
4927     FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_HAS_SDIR;
4928     UDFIncFileLinkCount(FileInfo);
4929     FileInfo->Dloc->FE_Flags &= ~UDF_FE_FLAG_HAS_SDIR;
4930 
4931     status = UDFRecordDirectory__(Vcb, SDirInfo);
4932     UDFDecDirCounter(Vcb);
4933 
4934     UDFInterlockedIncrement((PLONG)&(FileInfo->OpenCount));
4935     if(!OS_SUCCESS(status)) {
4936         UDFUnlinkFile__(Vcb, SDirInfo, TRUE);
4937         UDFCloseFile__(Vcb, SDirInfo);
4938         UDFCleanUpFile__(Vcb, SDirInfo);
4939         MyFreePool__(SDirInfo);
4940         ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLength = 0;
4941         ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation.partitionReferenceNum = 0;
4942         ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation.logicalBlockNum = 0;
4943         return status;
4944     }
4945     *_SDirInfo = SDirInfo;
4946     // do some init
4947     ((PEXTENDED_FILE_ENTRY)(SDirInfo->Dloc->FileEntry))->icbTag.fileType = UDF_FILE_TYPE_STREAMDIR;
4948     ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLength = Vcb->LBlockSize;
4949     ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation.partitionReferenceNum = (uint16)PartNum;
4950     ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation.logicalBlockNum =
4951         UDFPhysLbaToPart(Vcb, PartNum, SDirInfo->Dloc->FELoc.Mapping[0].extLocation);
4952     ((PEXTENDED_FILE_ENTRY)(SDirInfo->Dloc->FileEntry))->uniqueID =
4953         ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->uniqueID;
4954     FileInfo->Dloc->FE_Flags |= (UDF_FE_FLAG_FE_MODIFIED | UDF_FE_FLAG_HAS_SDIR);
4955     // open & finalize linkage
4956     FileInfo->Dloc->SDirInfo = SDirInfo;
4957     return STATUS_SUCCESS;
4958 } // end UDFCreateStreamDir__()
4959 #endif //UDF_READ_ONLY_BUILD
4960 
4961 /*
4962     This routine opens Stream Directory associated with file specified
4963  */
4964 OSSTATUS
4965 UDFOpenStreamDir__(
4966     IN PVCB Vcb,
4967     IN PUDF_FILE_INFO FileInfo,    // file containing stream-dir
4968     OUT PUDF_FILE_INFO* _SDirInfo  // this is to be filled & doesn't contain
4969                                    // any pointers
4970     )
4971 {
4972     OSSTATUS status;
4973     PUDF_FILE_INFO SDirInfo;
4974     PUDF_FILE_INFO ParSDirInfo;
4975     uint16 Ident;
4976 
4977     *_SDirInfo = NULL;
4978     ValidateFileInfo(FileInfo);
4979     // check if this file has ExtendedFileEntry
4980     if((Ident = FileInfo->Dloc->FileEntry->tagIdent) != TID_EXTENDED_FILE_ENTRY) {
4981         return STATUS_NOT_FOUND;
4982     }
4983     if((SDirInfo = FileInfo->Dloc->SDirInfo)) {
4984         // it is already opened. Good...
4985 
4986         // check if we have Deleted SDir
4987         if(FileInfo->Dloc->SDirInfo &&
4988            UDFIsSDirDeleted(FileInfo->Dloc->SDirInfo))
4989             return STATUS_FILE_DELETED;
4990         // All right. Look for parallel SDir (if any)
4991         if(SDirInfo->ParentFile != FileInfo) {
4992             ParSDirInfo = UDFLocateParallelFI(FileInfo, 0, SDirInfo);
4993             BrutePoint();
4994             if(ParSDirInfo->ParentFile != FileInfo) {
4995                 SDirInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_SDFINF_TAG);
4996                 *_SDirInfo = SDirInfo;
4997                 if(!SDirInfo) return STATUS_INSUFFICIENT_RESOURCES;
4998                 RtlCopyMemory(SDirInfo, FileInfo->Dloc->SDirInfo, sizeof(UDF_FILE_INFO));
4999     //          SDirInfo->NextLinkedFile = FileInfo->Dloc->SDirInfo->NextLinkedFile; // is already done
5000                 UDFInsertLinkedFile(SDirInfo, FileInfo->Dloc->SDirInfo);
5001                 SDirInfo->RefCount = 0;
5002                 SDirInfo->ParentFile = FileInfo;
5003                 SDirInfo->Fcb = NULL;
5004             } else {
5005                 SDirInfo = ParSDirInfo;
5006             }
5007         }
5008         UDFReferenceFile__(SDirInfo);
5009         *_SDirInfo = SDirInfo;
5010         return STATUS_SUCCESS;
5011     }
5012     // normal open
5013     if(!((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLength)
5014         return STATUS_NOT_FOUND;
5015     SDirInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_SDFINF_TAG);
5016     if(!SDirInfo) return STATUS_INSUFFICIENT_RESOURCES;
5017     *_SDirInfo = SDirInfo;
5018     status = UDFOpenRootFile__(Vcb, &(((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation) ,SDirInfo);
5019     if(!OS_SUCCESS(status)) return status;
5020     // open & finalize linkage
5021     FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_HAS_SDIR;
5022     SDirInfo->Dloc->FE_Flags |= UDF_FE_FLAG_IS_SDIR;
5023     FileInfo->Dloc->SDirInfo = SDirInfo;
5024     SDirInfo->ParentFile = FileInfo;
5025 
5026     UDFInterlockedIncrement((PLONG)&(FileInfo->OpenCount));
5027 
5028     return STATUS_SUCCESS;
5029 } // end UDFOpenStreamDir__()
5030 
5031 #ifndef UDF_READ_ONLY_BUILD
5032 /*
5033     This routine records VAT & VAT Icb at the end of session
5034  */
5035 OSSTATUS
5036 UDFRecordVAT(
5037     IN PVCB Vcb
5038     )
5039 {
5040     uint32 Offset;
5041     uint32 to_read;
5042     uint32 hdrOffset, hdrOffsetNew;
5043     uint32 hdrLen;
5044     OSSTATUS status;
5045     SIZE_T ReadBytes;
5046     uint32 len;
5047     uint16 PartNdx = (uint16)Vcb->VatPartNdx;
5048     uint16 PartNum = UDFGetPartNumByPartNdx(Vcb, PartNdx);
5049     uint32 root = UDFPartStart(Vcb, PartNum);
5050     PUDF_FILE_INFO VatFileInfo = Vcb->VatFileInfo;
5051     uint32 i;
5052     PEXTENT_MAP Mapping;
5053     uint32 off, BS, NWA;
5054     int8* Old;
5055     int8* New;
5056     uint32* Vat;
5057     uint8 AllocMode;
5058     uint32 VatLen;
5059     uint32 PacketOffset;
5060     uint32 BSh = Vcb->BlockSizeBits;
5061     uint32 MaxPacket = Vcb->WriteBlockSize >> BSh;
5062     uint32 OldLen;
5063     EntityID* eID;
5064 
5065     if(!(Vat = Vcb->Vat) || !VatFileInfo) return STATUS_INVALID_PARAMETER;
5066     // Disable VAT-based translation
5067     Vcb->Vat = NULL;
5068     // sync VAT and FSBM
5069     len = min(UDFPartLen(Vcb, PartNum), Vcb->FSBM_BitCount - root);
5070     len = min(Vcb->VatCount, len);
5071     for(i=0; i<len; i++) {
5072         if(UDFGetFreeBit(Vcb->FSBM_Bitmap, root+i))
5073             Vat[i] = UDF_VAT_FREE_ENTRY;
5074     }
5075     // Ok, now we shall construct new VAT image...
5076     // !!! NOTE !!!
5077     // Both VAT copies - in-memory & on-disc
5078     // contain _relative_ addresses
5079     OldLen = len = (uint32)UDFGetFileSize(Vcb->VatFileInfo);
5080     VatLen = (Vcb->LastLBA - root + 1) * sizeof(uint32);
5081     Old = (int8*)DbgAllocatePool(PagedPool, OldLen);
5082     if(!Old) {
5083         DbgFreePool(Vat);
5084         return STATUS_INSUFFICIENT_RESOURCES;
5085     }
5086     // read old one
5087     status = UDFReadFile__(Vcb, VatFileInfo, 0, OldLen, FALSE, Old, &ReadBytes);
5088     if(!OS_SUCCESS(status)) {
5089         DbgFreePool(Vat);
5090         DbgFreePool(Old);
5091         return status;
5092     }
5093     // prepare some pointers
5094     // and fill headers
5095     if(Vcb->Partitions[PartNdx].PartitionType == UDF_VIRTUAL_MAP15) {
5096         Offset = 0;
5097         to_read =
5098         hdrOffset = len - sizeof(VirtualAllocationTable15);
5099         hdrLen = sizeof(VirtualAllocationTable15);
5100         hdrOffsetNew = VatLen;
5101         New = (int8*)DbgAllocatePool(PagedPool, VatLen + hdrLen);
5102         if(!New) {
5103             DbgFreePool(Vat);
5104             return STATUS_INSUFFICIENT_RESOURCES;
5105         }
5106         RtlCopyMemory(New+hdrOffsetNew, Old+hdrOffset, hdrLen);
5107         ((VirtualAllocationTable15*)(New + hdrOffset))->previousVATICB =
5108             VatFileInfo->Dloc->FELoc.Mapping[0].extLocation - root;
5109         eID = &(((VirtualAllocationTable15*)(New + hdrOffset))->ident);
5110 
5111         UDFSetEntityID_imp(eID, UDF_ID_ALLOC);
5112 
5113 /*        RtlCopyMemory((int8*)&(eID->ident), UDF_ID_ALLOC, sizeof(UDF_ID_ALLOC) );
5114         iis = (impIdentSuffix*)&(eID->identSuffix);
5115         iis->OSClass = UDF_OS_CLASS_WINNT;
5116         iis->OSIdent = UDF_OS_ID_WINNT;*/
5117     } else {
5118         VirtualAllocationTable20* Buf;
5119 
5120         Offset = ((VirtualAllocationTable20*)Old)->lengthHeader;
5121         to_read = len - Offset;
5122         hdrOffset = 0;
5123         hdrLen = sizeof(VirtualAllocationTable20);
5124         hdrOffsetNew = 0;
5125         New = (int8*)DbgAllocatePool(PagedPool, VatLen + hdrLen);
5126         if(!New) {
5127             DbgFreePool(Vat);
5128             return STATUS_INSUFFICIENT_RESOURCES;
5129         }
5130         RtlCopyMemory(New+hdrOffsetNew, Old+hdrOffset, hdrLen);
5131         ((VirtualAllocationTable20*)New)->previousVatICBLoc =
5132             VatFileInfo->Dloc->FELoc.Mapping[0].extLocation - root;
5133 
5134         Buf = (VirtualAllocationTable20*)New;
5135 
5136         Buf->minReadRevision  = Vcb->minUDFReadRev;
5137         Buf->minWriteRevision = Vcb->minUDFWriteRev;
5138         Buf->maxWriteRevision = Vcb->maxUDFWriteRev;
5139 
5140         Buf->numFIDSFiles       = Vcb->numFiles;
5141         Buf->numFIDSDirectories = Vcb->numDirs;
5142     }
5143 
5144     RtlCopyMemory(New+Offset, Vat, VatLen);
5145     //
5146     if(VatFileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY) {
5147         eID = &(((PEXTENDED_FILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->impIdent);
5148     } else {
5149         eID = &(((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->impIdent);
5150     }
5151 
5152 #if 0
5153     UDFSetEntityID_imp(eID, UDF_ID_DEVELOPER);
5154 #endif
5155 
5156 /*    RtlCopyMemory((int8*)&(eID->ident), UDF_ID_DEVELOPER, sizeof(UDF_ID_DEVELOPER) );
5157     iis = (impIdentSuffix*)&(eID->identSuffix);
5158     iis->OSClass = UDF_OS_CLASS_WINNT;
5159     iis->OSIdent = UDF_OS_ID_WINNT;*/
5160 
5161     VatFileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
5162     // drop VAT
5163     DbgFreePool(Vat);
5164     len = VatLen;
5165     // the operation of resize can modifiy WriteCount in WCache due to movement
5166     // of the data from FE. That's why we should remember PacketOffset now
5167     if(to_read < VatLen) {
5168         status = UDFResizeFile__(Vcb, VatFileInfo, len = hdrLen + VatLen);
5169         if(!OS_SUCCESS(status)) {
5170             return status;
5171         }
5172         UDFMarkSpaceAsXXX(Vcb, VatFileInfo->Dloc, VatFileInfo->Dloc->DataLoc.Mapping, AS_DISCARDED); //free
5173     }
5174     PacketOffset = WCacheGetWriteBlockCount__(&(Vcb->FastCache));
5175     if( ((((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) ) {
5176         // now we'll place FE & built-in data to the last sector of
5177         // the last packet will be recorded
5178         if(!PacketOffset) {
5179             // add padding
5180             UDFWriteData(Vcb, TRUE, ((uint64)Vcb->NWA) << Vcb->BlockSizeBits, 1, FALSE, Old, &ReadBytes);
5181             PacketOffset++;
5182         } else {
5183             Vcb->Vat = (uint32*)(New+Offset);
5184             WCacheSyncReloc__(&(Vcb->FastCache), Vcb);
5185             Vcb->Vat = NULL;
5186         }
5187         VatFileInfo->Dloc->FELoc.Mapping[0].extLocation =
5188         VatFileInfo->Dloc->DataLoc.Mapping[0].extLocation =
5189             Vcb->NWA+PacketOffset;
5190         VatFileInfo->Dloc->FELoc.Modified = TRUE;
5191         // setup descTag
5192         ((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->descTag.tagLocation =
5193             UDFPhysLbaToPart(Vcb, PartNum, VatFileInfo->Dloc->DataLoc.Mapping[0].extLocation);
5194         // record data
5195         if(OS_SUCCESS(status = UDFWriteFile__(Vcb, VatFileInfo, 0, VatLen + hdrLen, FALSE, New, &ReadBytes))) {
5196             status = UDFFlushFile__(Vcb, VatFileInfo);
5197         }
5198         return status;
5199     }
5200     // We can't fit the whole VAT in FE tail
5201     // Now lets 'unpack' VAT's mapping to make updating easier
5202     status = UDFUnPackMapping(Vcb, &(VatFileInfo->Dloc->DataLoc));
5203     if(!OS_SUCCESS(status)) return status;
5204     // update VAT with locations of not flushed blocks
5205     if(PacketOffset) {
5206         Vcb->Vat = (uint32*)(New+Offset);
5207         WCacheSyncReloc__(&(Vcb->FastCache), Vcb);
5208         Vcb->Vat = NULL;
5209     }
5210 
5211     Mapping = VatFileInfo->Dloc->DataLoc.Mapping;
5212     off=0;
5213     BS = Vcb->BlockSize;
5214     NWA = Vcb->NWA;
5215     VatLen += hdrLen;
5216     // record modified parts of VAT & update mapping
5217     for(i=0; Mapping[i].extLength; i++) {
5218         to_read = (VatLen>=BS) ? BS : VatLen;
5219         if((OldLen < off) || (RtlCompareMemory(Old+off, New+off, to_read) != to_read)) {
5220             // relocate frag
5221             Mapping[i].extLocation = NWA+PacketOffset;
5222             Mapping[i].extLength &= UDF_EXTENT_LENGTH_MASK;
5223             PacketOffset++;
5224             if(PacketOffset >= MaxPacket) {
5225                 NWA += (MaxPacket + 7);
5226                 PacketOffset = 0;
5227             }
5228             status = UDFWriteFile__(Vcb, VatFileInfo, off, to_read, FALSE, New+off, &ReadBytes);
5229             if(!OS_SUCCESS(status)) {
5230                 return status;
5231             }
5232         }
5233         VatLen-=BS;
5234         off+=BS;
5235     }
5236     // pack mapping
5237     UDFPackMapping(Vcb, &(VatFileInfo->Dloc->DataLoc));
5238     len = UDFGetMappingLength(VatFileInfo->Dloc->DataLoc.Mapping)/sizeof(EXTENT_MAP) - 1;
5239     // obtain AllocMode
5240     AllocMode = ((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK;
5241     switch(AllocMode) {
5242     case ICB_FLAG_AD_SHORT: {
5243         AllocMode = sizeof(SHORT_AD);
5244         break;
5245     }
5246     case ICB_FLAG_AD_LONG: {
5247         AllocMode = sizeof(LONG_AD);
5248         break;
5249     }
5250     case ICB_FLAG_AD_EXTENDED: {
5251 //            break;
5252     }
5253     default: {
5254         return STATUS_INVALID_PARAMETER;
5255     }
5256     }
5257     // calculate actual AllocSequence length (in blocks)
5258     len = (len*AllocMode+BS-1+VatFileInfo->Dloc->AllocLoc.Offset) /
5259 //          (((BS - sizeof(ALLOC_EXT_DESC))/sizeof(SHORT_AD))*sizeof(SHORT_AD));
5260         ((BS - sizeof(ALLOC_EXT_DESC) + AllocMode - 1) & ~(AllocMode-1));
5261     // Re-init AllocLoc
5262     if(VatFileInfo->Dloc->AllocLoc.Mapping) MyFreePool__(VatFileInfo->Dloc->AllocLoc.Mapping);
5263     VatFileInfo->Dloc->AllocLoc.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , (len+1)*sizeof(EXTENT_MAP),
5264                                                        MEM_EXTMAP_TAG);
5265     if(!(VatFileInfo->Dloc->AllocLoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES;
5266 
5267     VatFileInfo->Dloc->AllocLoc.Offset = (uint32)(VatFileInfo->Dloc->FELoc.Length);
5268     VatFileInfo->Dloc->AllocLoc.Length = 0;
5269     Mapping = VatFileInfo->Dloc->AllocLoc.Mapping;
5270     Mapping[0].extLength = BS-VatFileInfo->Dloc->AllocLoc.Offset;
5271 //  Mapping[0].extLocation = ???;
5272     for(i=1; i<len; i++) {
5273         // relocate frag
5274         Mapping[i].extLocation = NWA+PacketOffset;
5275         Mapping[i].extLength = BS;
5276         PacketOffset++;
5277         if(PacketOffset >= MaxPacket) {
5278             NWA += (MaxPacket + 7);
5279             PacketOffset = 0;
5280         }
5281     }
5282     // Terminator
5283     Mapping[i].extLocation =
5284     Mapping[i].extLength = 0;
5285 
5286     if( !PacketOffset &&
5287         (VatFileInfo->Dloc->AllocLoc.Length <= (Vcb->BlockSize - (uint32)(VatFileInfo->Dloc->AllocLoc.Offset)) ) ) {
5288         // add padding
5289         UDFWriteData(Vcb, TRUE, ((uint64)NWA) << Vcb->BlockSizeBits, 1, FALSE, Old, &ReadBytes);
5290         PacketOffset++;
5291     }
5292     // now we'll place FE & built-in data to the last sector of
5293     // the last packet will be recorded
5294     VatFileInfo->Dloc->FELoc.Mapping[0].extLocation =
5295     VatFileInfo->Dloc->AllocLoc.Mapping[0].extLocation =
5296         NWA+PacketOffset;
5297     VatFileInfo->Dloc->FELoc.Modified = TRUE;
5298     // setup descTag
5299     ((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->descTag.tagLocation =
5300         UDFPhysLbaToPart(Vcb, PartNum, VatFileInfo->Dloc->FELoc.Mapping[0].extLocation);
5301     VatFileInfo->Dloc->DataLoc.Modified = TRUE;
5302 
5303     status = UDFFlushFile__(Vcb, VatFileInfo);
5304     if(!OS_SUCCESS(status))
5305         return status;
5306     WCacheFlushAll__(&(Vcb->FastCache), Vcb);
5307     return STATUS_SUCCESS;
5308 } // end UDFRecordVAT()
5309 #endif //UDF_READ_ONLY_BUILD
5310 
5311 /*
5312     This routine updates VAT according to RequestedLbaTable (RelocTab) &
5313     actual physical address where this data will be stored
5314  */
5315 OSSTATUS
5316 UDFUpdateVAT(
5317     IN void* _Vcb,
5318     IN uint32 Lba,
5319     IN uint32* RelocTab,  // can be NULL
5320     IN uint32 BCount
5321     )
5322 {
5323 #ifndef UDF_READ_ONLY_BUILD
5324     PVCB Vcb = (PVCB)_Vcb;
5325     uint16 PartNdx = (uint16)(Vcb->VatPartNdx);
5326     uint16 PartNum = (uint16)(Lba ? UDFGetPartNumByPhysLba(Vcb, Lba) : UDFGetPartNumByPartNdx(Vcb, PartNdx));
5327     if(PartNum != UDFGetPartNumByPartNdx(Vcb, PartNdx)) {
5328         UDFPrint(("UDFUpdateVAT: Write to Write-Protected partition\n"));
5329         return STATUS_MEDIA_WRITE_PROTECTED;
5330     }
5331     // !!! NOTE !!!
5332     // Both VAT copies - in-memory & on-disc
5333     // contain _relative_ addresses
5334     uint32 root = Vcb->Partitions[PartNdx].PartitionRoot;
5335     uint32 NWA = Vcb->NWA-root;
5336     uint32 i;
5337     uint32 CurLba;
5338 
5339     if(!Vcb->Vat) return STATUS_SUCCESS;
5340 
5341     for(i=0; i<BCount; i++, NWA++) {
5342         if((CurLba = (RelocTab ? RelocTab[i] : (Lba+i)) - root) >= Vcb->VatCount)
5343             Vcb->VatCount = CurLba+1;
5344         Vcb->Vat[CurLba] = NWA;
5345     }
5346     return STATUS_SUCCESS;
5347 #else //UDF_READ_ONLY_BUILD
5348     return STATUS_MEDIA_WRITE_PROTECTED;
5349 #endif //UDF_READ_ONLY_BUILD
5350 } // end UDFUpdateVAT()
5351 
5352 #ifndef UDF_READ_ONLY_BUILD
5353 /*
5354     This routine rebuilds file's FE in order to move data from
5355     ICB to separate Block.
5356  */
5357 OSSTATUS
5358 UDFConvertFEToNonInICB(
5359     IN PVCB Vcb,
5360     IN PUDF_FILE_INFO FileInfo,
5361     IN uint8 NewAllocMode
5362     )
5363 {
5364     OSSTATUS status;
5365     int8* OldInIcb = NULL;
5366     uint32 OldLen;
5367     ValidateFileInfo(FileInfo);
5368     SIZE_T ReadBytes;
5369     SIZE_T _WrittenBytes;
5370     PUDF_DATALOC_INFO Dloc;
5371 
5372 //    ASSERT(FileInfo->RefCount >= 1);
5373 
5374     Dloc = FileInfo->Dloc;
5375     ASSERT(Dloc->FELoc.Mapping[0].extLocation);
5376     uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, Dloc->FELoc.Mapping[0].extLocation);
5377 
5378     if(NewAllocMode == ICB_FLAG_AD_DEFAULT_ALLOC_MODE) {
5379         NewAllocMode = (uint8)(Vcb->DefaultAllocMode);
5380     }
5381     // we do not support recording of extended AD now
5382     if(NewAllocMode != ICB_FLAG_AD_SHORT &&
5383        NewAllocMode != ICB_FLAG_AD_LONG)
5384         return STATUS_INVALID_PARAMETER;
5385     if(!Dloc->DataLoc.Offset || !Dloc->DataLoc.Length)
5386         return STATUS_SUCCESS;
5387     ASSERT(!Dloc->AllocLoc.Mapping);
5388     // read in-icb data. it'll be replaced after resize
5389     OldInIcb = (int8*)MyAllocatePool__(NonPagedPool, (uint32)(Dloc->DataLoc.Length));
5390     if(!OldInIcb)
5391         return STATUS_INSUFFICIENT_RESOURCES;
5392     OldLen = (uint32)(Dloc->DataLoc.Length);
5393     status = UDFReadExtent(Vcb, &(Dloc->DataLoc), 0, OldLen, FALSE, OldInIcb, &ReadBytes);
5394     if(!OS_SUCCESS(status)) {
5395         MyFreePool__(OldInIcb);
5396         return status;
5397     }
5398 /*    if(!Dloc->AllocLoc.Mapping) {
5399         Dloc->AllocLoc.Mapping = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, sizeof(EXTENT_MAP)*2);
5400         if(!Dloc->AllocLoc.Mapping) {
5401             MyFreePool__(OldInIcb);
5402             return STATUS_INSUFFICIENT_RESOURCES;
5403         }
5404     }
5405     // init Alloc mode
5406     if((((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) {
5407         ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK;
5408         ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= Vcb->DefaultAllocMode;
5409     } else {
5410         BrutePoint();
5411     }
5412     RtlZeroMemory(Dloc->AllocLoc.Mapping, sizeof(EXTENT_MAP)*2);
5413 //    Dloc->AllocLoc.Mapping[0].extLocation = 0;
5414     Dloc->AllocLoc.Mapping[0].extLength   = Vcb->LBlockSize | EXTENT_NOT_RECORDED_NOT_ALLOCATED;
5415 //    Dloc->AllocLoc.Mapping[1].extLocation = 0;
5416 //    Dloc->AllocLoc.Mapping[1].extLength = 0;
5417 */
5418 
5419     // grow extent in order to force space allocation
5420     status = UDFResizeExtent(Vcb, PartNum, Vcb->LBlockSize, FALSE, &Dloc->DataLoc);
5421     if(!OS_SUCCESS(status)) {
5422         MyFreePool__(OldInIcb);
5423         return status;
5424     }
5425 
5426     // set Alloc mode
5427     if((((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) {
5428         ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK;
5429         ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= NewAllocMode;
5430     } else {
5431         BrutePoint();
5432     }
5433 
5434     // revert to initial extent size. This will not cause NonInICB->InICB transform
5435     status = UDFResizeExtent(Vcb, PartNum, OldLen, FALSE, &Dloc->DataLoc);
5436     if(!OS_SUCCESS(status)) {
5437         MyFreePool__(OldInIcb);
5438         return status;
5439     }
5440 
5441     // replace data from ICB (if any) & free buffer
5442     status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), 0, OldLen, FALSE, OldInIcb, &_WrittenBytes);
5443     MyFreePool__(OldInIcb);
5444     if(!OS_SUCCESS(status)) {
5445         return status;
5446     }
5447     // inform UdfInfo, that AllocDesc's must be rebuilt on flush/close
5448     Dloc->AllocLoc.Modified = TRUE;
5449     Dloc->DataLoc.Modified = TRUE;
5450     return STATUS_SUCCESS;
5451 } // end UDFConvertFEToNonInICB()
5452 
5453 /*
5454     This routine converts file's FE to extended form.
5455     It is needed for stream creation.
5456  */
5457 OSSTATUS
5458 UDFConvertFEToExtended(
5459     IN PVCB Vcb,
5460     IN PUDF_FILE_INFO FileInfo
5461     )
5462 {
5463     PEXTENDED_FILE_ENTRY ExFileEntry;
5464     PFILE_ENTRY FileEntry;
5465     uint32 Length, NewLength, l;
5466     OSSTATUS status;
5467     SIZE_T ReadBytes;
5468 
5469     if(!FileInfo) return STATUS_INVALID_PARAMETER;
5470     ValidateFileInfo(FileInfo);
5471     if(FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY) return STATUS_SUCCESS;
5472     if(FileInfo->Dloc->FileEntry->tagIdent != TID_FILE_ENTRY) return STATUS_INVALID_PARAMETER;
5473 
5474 /*    if(!OS_SUCCESS(status = UDFFlushFile__(Vcb, FileInfo)))
5475         return status;*/
5476 
5477     Length = FileInfo->Dloc->FileEntryLen;
5478     NewLength = Length - sizeof(FILE_ENTRY) + sizeof(EXTENDED_FILE_ENTRY);
5479     ExFileEntry = (PEXTENDED_FILE_ENTRY)MyAllocatePoolTag__(NonPagedPool, NewLength, MEM_XFE_TAG);
5480     if(!ExFileEntry) return STATUS_INSUFFICIENT_RESOURCES;
5481     FileEntry = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
5482     RtlZeroMemory(ExFileEntry, NewLength);
5483 
5484     ExFileEntry->descTag.tagIdent = TID_EXTENDED_FILE_ENTRY;
5485     ExFileEntry->icbTag = FileEntry->icbTag;
5486     ExFileEntry->uid = FileEntry->uid;
5487     ExFileEntry->gid = FileEntry->gid;
5488     ExFileEntry->permissions = FileEntry->permissions;
5489     ExFileEntry->fileLinkCount = FileEntry->fileLinkCount;
5490     ExFileEntry->recordFormat = FileEntry->recordFormat;
5491     ExFileEntry->recordDisplayAttr = FileEntry->recordDisplayAttr;
5492     ExFileEntry->recordLength = FileEntry->recordLength;
5493     ExFileEntry->informationLength = FileEntry->informationLength;
5494     ExFileEntry->logicalBlocksRecorded = FileEntry->logicalBlocksRecorded;
5495     ExFileEntry->accessTime = FileEntry->accessTime;
5496     ExFileEntry->modificationTime = FileEntry->modificationTime;
5497     ExFileEntry->attrTime = FileEntry->attrTime;
5498     ExFileEntry->checkpoint = FileEntry->checkpoint;
5499     ExFileEntry->extendedAttrICB = FileEntry->extendedAttrICB;
5500     ExFileEntry->impIdent = FileEntry->impIdent;
5501     ExFileEntry->uniqueID = FileEntry->uniqueID;
5502     ExFileEntry->lengthExtendedAttr = FileEntry->lengthExtendedAttr;
5503     ExFileEntry->lengthAllocDescs = FileEntry->lengthAllocDescs;
5504     RtlCopyMemory(ExFileEntry+1, FileEntry+1, FileEntry->lengthExtendedAttr);
5505     RtlCopyMemory((int8*)(ExFileEntry+1)+FileEntry->lengthExtendedAttr, (int8*)(ExFileEntry+1)+FileEntry->lengthExtendedAttr, FileEntry->lengthAllocDescs);
5506 
5507     if((((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) {
5508 
5509         if((l = (uint32)(FileInfo->Dloc->DataLoc.Length))) {
5510 
5511             int8* tmp_buff = (int8*)MyAllocatePool__(NonPagedPool, l);
5512             if(!tmp_buff) {
5513                 MyFreePool__(ExFileEntry);
5514                 return STATUS_INSUFFICIENT_RESOURCES;
5515             }
5516             if(!OS_SUCCESS(status = UDFReadFile__(Vcb, FileInfo, 0, l, FALSE, tmp_buff, &ReadBytes)) ||
5517                !OS_SUCCESS(status = UDFResizeFile__(Vcb, FileInfo, 0)) ) {
5518                 MyFreePool__(ExFileEntry);
5519                 MyFreePool__(tmp_buff);
5520                 return status;
5521             }
5522             FileInfo->Dloc->FELoc.Length =
5523             FileInfo->Dloc->DataLoc.Offset = NewLength;
5524             FileInfo->Dloc->FELoc.Modified =
5525             FileInfo->Dloc->DataLoc.Modified = TRUE;
5526             MyFreePool__(FileInfo->Dloc->FileEntry);
5527             FileInfo->Dloc->FileEntry = (tag*)ExFileEntry;
5528             if(!OS_SUCCESS(status = UDFResizeFile__(Vcb, FileInfo, l)) ||
5529                !OS_SUCCESS(status = UDFWriteFile__(Vcb, FileInfo, 0, l, FALSE, tmp_buff, &ReadBytes)) ) {
5530                 MyFreePool__(ExFileEntry);
5531                 MyFreePool__(tmp_buff);
5532                 return status;
5533             }
5534             MyFreePool__(tmp_buff);
5535         } else {
5536             FileInfo->Dloc->FELoc.Length =
5537             FileInfo->Dloc->DataLoc.Offset = NewLength;
5538             FileInfo->Dloc->FELoc.Modified =
5539             FileInfo->Dloc->DataLoc.Modified = TRUE;
5540             MyFreePool__(FileInfo->Dloc->FileEntry);
5541             FileInfo->Dloc->FileEntry = (tag*)ExFileEntry;
5542         }
5543     } else {
5544         FileInfo->Dloc->FELoc.Length =
5545         FileInfo->Dloc->AllocLoc.Offset = NewLength;
5546         FileInfo->Dloc->FELoc.Modified =
5547         FileInfo->Dloc->AllocLoc.Modified = TRUE;
5548         MyFreePool__(FileInfo->Dloc->FileEntry);
5549         FileInfo->Dloc->FileEntry = (tag*)ExFileEntry;
5550     }
5551     FileInfo->Dloc->FileEntryLen = NewLength;
5552     FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
5553     if(Vcb->minUDFReadRev < 0x0200)
5554         Vcb->minUDFReadRev = 0x0200;
5555     return STATUS_SUCCESS;
5556 } // end UDFConvertFEToExtended()
5557 
5558 /*
5559     This routine makes file almost unavailable for external callers.
5560     The only way to access Hidden with this routine file is OpenByIndex.
5561     It is usefull calling this routine to pretend file to be deleted,
5562     for ex. when we have UDFCleanUp__() or smth. like this in progress,
5563     but we want to create file with the same name.
5564  */
5565 OSSTATUS
5566 UDFPretendFileDeleted__(
5567     IN PVCB Vcb,
5568     IN PUDF_FILE_INFO FileInfo
5569     )
5570 {
5571     AdPrint(("UDFPretendFileDeleted__:\n"));
5572 
5573     NTSTATUS RC;
5574     PDIR_INDEX_HDR hDirNdx = UDFGetDirIndexByFileInfo(FileInfo);
5575     if(!hDirNdx) return STATUS_CANNOT_DELETE;
5576     PDIR_INDEX_ITEM DirNdx = UDFDirIndex(hDirNdx, FileInfo->Index);
5577     if(!DirNdx) return STATUS_CANNOT_DELETE;
5578 
5579 
5580     // we can't hide file that is not marked as deleted
5581     RC = UDFDoesOSAllowFilePretendDeleted__(FileInfo);
5582     if(!NT_SUCCESS(RC))
5583         return RC;
5584 
5585     AdPrint(("UDFPretendFileDeleted__: set UDF_FI_FLAG_FI_INTERNAL\n"));
5586 
5587     DirNdx->FI_Flags |= UDF_FI_FLAG_FI_INTERNAL;
5588     if(DirNdx->FName.Buffer) {
5589         MyFreePool__(DirNdx->FName.Buffer);
5590         DirNdx->FName.Buffer = NULL;
5591         DirNdx->FName.Length =
5592         DirNdx->FName.MaximumLength = 0;
5593     }
5594     return STATUS_SUCCESS;
5595 } // end UDFPretendFileDeleted__()
5596 #endif //UDF_READ_ONLY_BUILD
5597