ReactOS  0.4.14-dev-593-g1793dcc
udf_info.cpp
Go to the documentation of this file.
1 // 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.
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
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 
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 
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
241  IN PUNICODE_STRING UName,
242  IN OUT uint8** _CS0,
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
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 {
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));
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
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
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
428  IN PVCB Vcb,
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
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;
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;
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);
578 } // end UDFDOSName100()
579 
580 void
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;
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;
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);
695 } // end UDFDOSName200()
696 
697 
698 void
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;
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;
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);
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
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
972  IN PVCB Vcb,
973  IN PUDF_FILE_INFO DirInfo,
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;
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))) {
1000  UDFFreeFESpace(Vcb, DirInfo, &_FEExtInfo); // free
1001  MyFreePool__(_FEExtInfo.Mapping);
1002  return status;
1003  }
1005  if(!FileEntry) {
1006  UDFRemoveDloc(Vcb, FileInfo->Dloc);
1007  FileInfo->Dloc = NULL;
1008  UDFFreeFESpace(Vcb, DirInfo, &_FEExtInfo); // free
1009  MyFreePool__(_FEExtInfo.Mapping);
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
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
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)
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
1108  IN PVCB Vcb,
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);
1129  }
1130  // allocate memory for FI
1131  l = (sizeof(FILE_IDENT_DESC) + Nlen + ImpUseLen + 3) & ~((uint32)3);
1133  if(!FileId) {
1134  if(CS0) MyFreePool__(CS0);
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
1159  IN int64 Size
1160  )
1161 {
1162  uint16 Ident;
1163 // PDIR_INDEX_ITEM DirIndex;
1164 
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
1191  IN PVCB Vcb,
1193  IN int64* ASize
1194  )
1195 {
1196  uint16 Ident;
1197  PDIR_INDEX_ITEM DirIndex;
1198 
1200  if(ASize) {
1201  AdPrint(("UDFSetFileSizeInDirNdx: %I64x\n", *ASize));
1202  } else {
1203  AdPrint(("UDFSetFileSizeInDirNdx: sync\n"));
1204  }
1205 
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
1238  )
1239 {
1240  uint16 Ident;
1241 
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
1257  IN PVCB Vcb,
1259  )
1260 {
1261  PDIR_INDEX_ITEM DirIndex;
1262 
1264 
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
1278  IN PVCB Vcb,
1280  )
1281 {
1282  uint16 Ident;
1283 
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
1317  IN BOOLEAN Increase
1318  )
1319 {
1320  uint16 Ident;
1321 
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
1357  )
1358 {
1359  uint16 Ident;
1360  uint16 d;
1361 
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(
1389  uint16 LinkCount
1390  )
1391 {
1392  uint16 Ident;
1393  uint16 d;
1394 
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
1422  )
1423 {
1424  uint16 Ident;
1425 
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
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
1457  IN PVCB Vcb,
1459  )
1460 {
1461  uint16 Ident;
1462  int64 UID;
1463 
1465 
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
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
1511  )
1512 {
1514 
1515  return UDFGetFileUID_(FileInfo->Dloc->FileEntry);
1516 } // end UDFGetFileUID()
1517 
1518 #ifndef UDF_READ_ONLY_BUILD
1519 void
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) {
1535  } else {
1537  }
1538 
1539 } // end UDFChangeFileCounter()
1540 
1541 void
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
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
1606  IN PVCB Vcb,
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;
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);
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));
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  UDFWriteExtent(Vcb, &(Dloc->DataLoc), 0, (uint32)OldLen, FALSE, OldInIcb, &_WrittenBytes);
1723  MyFreePool__(OldInIcb);
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;
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
1767  IN PVCB Vcb,
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 
1787 
1788 #ifndef _CONSOLE
1789  // now we can't call this if there is no OS-specific File Desc. present
1790  if(FileInfo->Fcb)
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))
1837  }
1838  DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
1839  DirNdx->FileCharacteristics |= FILE_DELETED;
1840  FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED;
1841  hDirNdx->DelCount++;
1843  }
1844  UDFDecFileLinkCount(FileInfo); // decrease
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;
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) {
1873  return STATUS_CANNOT_DELETE;
1874  }
1875  // open SDir
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);
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
1917  if(!OS_SUCCESS(status)) {
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 |
1927  FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_IS_DEL_SDIR;
1928  UDFDecFileLinkCount(FileInfo->ParentFile);
1929  }
1930  if(Dloc->DirIndex) {
1932  }
1933  // flush file
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
1946  IN PVCB Vcb,
1947  IN PUDF_FILE_INFO DirInfo
1948  )
1949 {
1950  PDIR_INDEX_HDR hCurDirNdx;
1951  PDIR_INDEX_ITEM CurDirNdx;
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:
1980  if(FileInfo)
1982  return status;
1983  }
1984 
1986  AdPrint((" "));
1989 skip_del_stream:
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
2005  IN PVCB Vcb,
2007  IN BOOLEAN NotDeleted,
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;
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)))
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) {
2050  *_FileInfo = FileInfo;
2052  RtlCopyMemory(FileInfo, DirNdx->FileInfo, sizeof(UDF_FILE_INFO));
2053  // FileInfo->NextLinkedFile = DirNdx->FileInfo->NextLinkedFile; // is already done
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
2065 
2066  ASSERT(FileInfo->ParentFile == DirInfo);
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  }
2079  *_FileInfo = FileInfo;
2082  // init horizontal links
2083  FileInfo->NextLinkedFile =
2084  FileInfo->PrevLinkedFile = FileInfo;
2085  // read FileIdent
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();
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)
2118  FileInfo->Dloc->AllocLoc.Mapping = UDFExtentToMapping(&FEExt);
2119  if(!(FileInfo->Dloc->AllocLoc.Mapping))
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))
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)) {
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) {
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)) {
2170  if(!OS_SUCCESS(status))
2171  return status;
2172  }
2173 #endif //UDF_READ_ONLY_BUILD
2174  }
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
2188  IN PVCB Vcb,
2189  IN lb_addr* RootLoc,
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 
2203  RootLBA = UDFPartLbaToPhys(Vcb,RootLoc);
2204  if(RootLBA == LBA_OUT_OF_EXTENT)
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)
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))
2245  // init DirIndex
2246  if( (FileType = ((icbtag*)((FileInfo->Dloc->FileEntry)+1))->fileType) != UDF_FILE_TYPE_DIRECTORY &&
2247  (FileType != UDF_FILE_TYPE_STREAMDIR) ) {
2249  UDFReleaseDloc(Vcb, FileInfo->Dloc);
2250  return STATUS_SUCCESS;
2251  }
2252  // build index for directories
2253  if(!FileInfo->Dloc->DirIndex) {
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)) {
2261  if(!OS_SUCCESS(status))
2262  return status;
2263  }
2264 #endif //UDF_READ_ONLY_BUILD
2265  }
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
2277  IN PVCB Vcb,
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 
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 ||
2336  Dloc->AllocLoc.Modified ||
2337  Dloc->FELoc.Modified ||
2338  (DirNdx && (DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) );
2339  }
2340 #endif // UDF_DBG
2341 
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
2434  MyFreePool__(Dloc->FileEntry);
2435  Dloc->FileEntry = NULL;
2436  } else if(FileInfo->Index >= 2) {
2437  // error durring open operation
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
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
2472  MyFreePool__(Dloc->FileEntry);
2473  Dloc->FileEntry = NULL;
2474  } else if(FileInfo->Index >= 2) {
2475  // error durring open operation
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
2578  IN PVCB Vcb,
2579 // IN uint16 AllocMode, // short/long/ext/in-icb // always in-ICB
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;
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
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();
2634  if(!OS_SUCCESS(status))
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....
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();
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
2674  if(!OS_SUCCESS(status)) {
2675  BrutePoint();
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
2691  *_FileInfo = FileInfo;
2692  if(!FileInfo)
2694  ImpUseLen = (ImpUseLen + 3) & ~((uint16)3);
2695 
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
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)) ))
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)
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
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);
2832  }
2833  FileInfo->Dloc->DataLoc.Length = 0;
2834  FileInfo->Dloc->DataLoc.Offset = FileInfo->Dloc->FileEntryLen;
2835  FileInfo->ParentFile = DirInfo;
2836  // init FileEntry
2839  UDFIncFileLinkCount(FileInfo); // increase to 1
2840  UDFUpdateCreateTime(Vcb, FileInfo);
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;
2876  UDFFlushFE(Vcb, FileInfo, PartNum);
2877  if(undel)
2878  hDirNdx->DelCount--;
2879  UDFReleaseDloc(Vcb, FileInfo->Dloc);
2881 
2882  UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used
2883 
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
2926  IN PVCB Vcb,
2928  IN int64 Offset, // offset in extent
2929  IN SIZE_T Length,
2930  IN BOOLEAN Direct,
2932  )
2933 {
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
2945  IN PVCB Vcb,
2947  IN int64 Offset, // offset in extent
2948  IN SIZE_T Length,
2949  IN BOOLEAN Direct,
2951  )
2952 {
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
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) ||
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
2995  IN PVCB Vcb,
2997  )
2998 {
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 &&
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;
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
3177  IN PVCB Vcb,
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);
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:
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)) {
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))
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 {
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
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;
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
3385  IN PVCB Vcb,
3386  IN OUT PUDF_FILE_INFO DirInfo // source (opened)
3387  )
3388 {
3389  OSSTATUS status;
3390  LONG_AD FEicb;
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
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);
3440  // init structure
3441  UDFSetUpTag(Vcb, &(FileInfo.FileIdent->descTag), (uint16)(FileInfo.FileIdentLen),
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
3469  IN PVCB Vcb,
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));
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) {
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
3514  MEM_EXTMAP_TAG);
3515  if(!(NewMap)) {
3516  MyFreePool__(OldInIcb);
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 {
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;
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)) {
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
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... :(((
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] &&
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"));
3662  if(((icbtag*)(VatFileInfo->Dloc->FileEntry+1))->fileType != UDF_FILE_TYPE_VAT15) {
3664  goto err_vat_15;
3665  }
3667  if(!Buf) {
3668 err_vat_15_2:
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"));
3694  if(((icbtag*)(VatFileInfo->Dloc->FileEntry+1))->fileType != UDF_FILE_TYPE_VAT20) {
3696  goto err_vat_15;
3697  }
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"));
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
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
3865  IN PVCB Vcb,
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
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
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));
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;
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
4052  IN PVCB Vcb,
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;
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  }
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
4120  IN PVCB Vcb,
4122  IN ULONG FlushFlags
4123  )
4124 {
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;
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
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