[UDFS] Don't access OldInIcb after being freed
[reactos.git] / drivers / filesystems / udfs / udf_info / udf_info.cpp
1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3 // All rights reserved
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*
7 Module name:
8
9 udf_info.cpp
10
11 Abstract:
12
13 This file contains filesystem-specific routines
14
15 */
16
17 #include "udf.h"
18
19 #define UDF_BUG_CHECK_ID UDF_FILE_UDF_INFO
20
21 #ifdef _X86_
22 static const int8 valid_char_arr[] =
23 {1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
24 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
25 1,0,1,0, 0,0,0,0, 0,0,1,1, 1,0,0,1,
26 0,0,0,0, 0,0,0,0, 0,0,1,1, 1,1,1,1,
27 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // @ABCDE....
28 0,0,0,0, 0,0,0,0, 0,0,0,1, 1,1,0,0, // ....Z[/]^_
29 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // `abcde....
30 0,0,0,0, 0,0,0,0, 0,0,0,1, 1,1,0,1, // ....z{|}~
31
32 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
33 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
34 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
35 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
36 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
37 1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
38 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
39 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
40 #else // NO X86 optimization , use generic C/C++
41 static const char valid_char_arr[] = {"*/:?\"<>|\\"};
42 #endif // _X86_
43
44 #define DOS_CRC_MODULUS 41
45 #define hexChar crcChar
46 static const char crcChar[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ#_~-@";
47
48 /* Used to convert hex digits to ASCII for readability. */
49 //static const char hexChar[] = "0123456789ABCDEF";
50
51 static const uint16 CrcTable[256] = {
52 0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50a5U, 0x60c6U, 0x70e7U,
53 0x8108U, 0x9129U, 0xa14aU, 0xb16bU, 0xc18cU, 0xd1adU, 0xe1ceU, 0xf1efU,
54 0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52b5U, 0x4294U, 0x72f7U, 0x62d6U,
55 0x9339U, 0x8318U, 0xb37bU, 0xa35aU, 0xd3bdU, 0xc39cU, 0xf3ffU, 0xe3deU,
56 0x2462U, 0x3443U, 0x0420U, 0x1401U, 0x64e6U, 0x74c7U, 0x44a4U, 0x5485U,
57 0xa56aU, 0xb54bU, 0x8528U, 0x9509U, 0xe5eeU, 0xf5cfU, 0xc5acU, 0xd58dU,
58 0x3653U, 0x2672U, 0x1611U, 0x0630U, 0x76d7U, 0x66f6U, 0x5695U, 0x46b4U,
59 0xb75bU, 0xa77aU, 0x9719U, 0x8738U, 0xf7dfU, 0xe7feU, 0xd79dU, 0xc7bcU,
60 0x48c4U, 0x58e5U, 0x6886U, 0x78a7U, 0x0840U, 0x1861U, 0x2802U, 0x3823U,
61 0xc9ccU, 0xd9edU, 0xe98eU, 0xf9afU, 0x8948U, 0x9969U, 0xa90aU, 0xb92bU,
62 0x5af5U, 0x4ad4U, 0x7ab7U, 0x6a96U, 0x1a71U, 0x0a50U, 0x3a33U, 0x2a12U,
63 0xdbfdU, 0xcbdcU, 0xfbbfU, 0xeb9eU, 0x9b79U, 0x8b58U, 0xbb3bU, 0xab1aU,
64 0x6ca6U, 0x7c87U, 0x4ce4U, 0x5cc5U, 0x2c22U, 0x3c03U, 0x0c60U, 0x1c41U,
65 0xedaeU, 0xfd8fU, 0xcdecU, 0xddcdU, 0xad2aU, 0xbd0bU, 0x8d68U, 0x9d49U,
66 0x7e97U, 0x6eb6U, 0x5ed5U, 0x4ef4U, 0x3e13U, 0x2e32U, 0x1e51U, 0x0e70U,
67 0xff9fU, 0xefbeU, 0xdfddU, 0xcffcU, 0xbf1bU, 0xaf3aU, 0x9f59U, 0x8f78U,
68 0x9188U, 0x81a9U, 0xb1caU, 0xa1ebU, 0xd10cU, 0xc12dU, 0xf14eU, 0xe16fU,
69 0x1080U, 0x00a1U, 0x30c2U, 0x20e3U, 0x5004U, 0x4025U, 0x7046U, 0x6067U,
70 0x83b9U, 0x9398U, 0xa3fbU, 0xb3daU, 0xc33dU, 0xd31cU, 0xe37fU, 0xf35eU,
71 0x02b1U, 0x1290U, 0x22f3U, 0x32d2U, 0x4235U, 0x5214U, 0x6277U, 0x7256U,
72 0xb5eaU, 0xa5cbU, 0x95a8U, 0x8589U, 0xf56eU, 0xe54fU, 0xd52cU, 0xc50dU,
73 0x34e2U, 0x24c3U, 0x14a0U, 0x0481U, 0x7466U, 0x6447U, 0x5424U, 0x4405U,
74 0xa7dbU, 0xb7faU, 0x8799U, 0x97b8U, 0xe75fU, 0xf77eU, 0xc71dU, 0xd73cU,
75 0x26d3U, 0x36f2U, 0x0691U, 0x16b0U, 0x6657U, 0x7676U, 0x4615U, 0x5634U,
76 0xd94cU, 0xc96dU, 0xf90eU, 0xe92fU, 0x99c8U, 0x89e9U, 0xb98aU, 0xa9abU,
77 0x5844U, 0x4865U, 0x7806U, 0x6827U, 0x18c0U, 0x08e1U, 0x3882U, 0x28a3U,
78 0xcb7dU, 0xdb5cU, 0xeb3fU, 0xfb1eU, 0x8bf9U, 0x9bd8U, 0xabbbU, 0xbb9aU,
79 0x4a75U, 0x5a54U, 0x6a37U, 0x7a16U, 0x0af1U, 0x1ad0U, 0x2ab3U, 0x3a92U,
80 0xfd2eU, 0xed0fU, 0xdd6cU, 0xcd4dU, 0xbdaaU, 0xad8bU, 0x9de8U, 0x8dc9U,
81 0x7c26U, 0x6c07U, 0x5c64U, 0x4c45U, 0x3ca2U, 0x2c83U, 0x1ce0U, 0x0cc1U,
82 0xef1fU, 0xff3eU, 0xcf5dU, 0xdf7cU, 0xaf9bU, 0xbfbaU, 0x8fd9U, 0x9ff8U,
83 0x6e17U, 0x7e36U, 0x4e55U, 0x5e74U, 0x2e93U, 0x3eb2U, 0x0ed1U, 0x1ef0U
84 };
85
86 static const uint32 crc32_tab[] = {
87 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
88 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
89 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
90 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
91 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
92 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
93 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
94 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
95 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
96 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
97 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
98 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
99 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
100 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
101 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
102 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
103 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
104 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
105 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
106 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
107 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
108 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
109 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
110 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
111 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
112 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
113 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
114 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
115 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
116 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
117 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
118 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
119 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
120 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
121 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
122 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
123 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
124 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
125 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
126 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
127 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
128 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
129 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
130 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
131 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
132 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
133 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
134 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
135 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
136 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
137 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
138 0x2d02ef8dL
139 };
140
141 /*
142 This routine allocates new memory block, copies data there & free old one
143 */
144 /*uint32
145 UDFMemRealloc(
146 int8* OldBuff,
147 uint32 OldLength,
148 int8** NewBuff,
149 uint32 NewLength
150 )
151 {
152 int8* new_buff;
153
154 (*NewBuff) = OldBuff;
155 if(OldLength == NewLength) return OldLength;
156 new_buff = (int8*)MyAllocatePool__(NonPagedPool, NewLength);
157 if(!new_buff) return 0;
158 if(OldLength > NewLength) OldLength = NewLength;
159 RtlCopyMemory(new_buff, OldBuff, OldLength);
160 MyFreePool__(OldBuff);
161 (*NewBuff) = new_buff;
162 return OldLength;
163 } // end UDFMemRealloc()*/
164
165 /*
166 This routine converts compressed Unicode to standard
167 */
168 void
169 __fastcall
170 UDFDecompressUnicode(
171 IN OUT PUNICODE_STRING UName,
172 IN uint8* CS0,
173 IN SIZE_T Length,
174 OUT uint16* valueCRC
175 )
176 {
177 uint16 compID = CS0[0];
178 uint32 unicodeIndex = 0;
179 uint32 byteIndex = 1;
180 PWCHAR buff;
181 uint8* _CS0 = CS0+1;
182
183 if(!Length) goto return_empty_str;
184 // First check for valid compID.
185 switch(compID) {
186 case UDF_COMP_ID_8: {
187
188 buff = (PWCHAR)MyAllocatePoolTag__(UDF_FILENAME_MT, (Length)*sizeof(WCHAR), MEM_FNAME_TAG);
189 if(!buff) goto return_empty_str;
190 UName->Buffer = buff;
191
192 // Loop through all the bytes.
193 while (byteIndex < Length) {
194 (*buff) = (*_CS0);
195 _CS0++;
196 byteIndex++;
197 buff++;
198 }
199 unicodeIndex = byteIndex-1;
200 break;
201 }
202 case UDF_COMP_ID_16: {
203
204 buff = (PWCHAR)MyAllocatePoolTag__(UDF_FILENAME_MT, (Length-1)+sizeof(WCHAR), MEM_FNAME16_TAG);
205 if(!buff) goto return_empty_str;
206 UName->Buffer = buff;
207
208 // Loop through all the bytes.
209 while (byteIndex < Length) {
210 // Move the first byte to the high bits of the unicode char.
211 *buff = ((*_CS0) << 8) | (*(_CS0+1));
212 _CS0+=2;
213 byteIndex+=2;
214 unicodeIndex++;
215 buff++;
216 ASSERT(byteIndex <= Length);
217 }
218 break;
219 }
220 default: {
221 return_empty_str:
222 UName->Buffer = NULL;
223 UName->MaximumLength =
224 UName->Length = 0;
225 return;
226 }
227 }
228 UName->MaximumLength = (UName->Length = (((uint16)unicodeIndex)*sizeof(WCHAR))) + sizeof(WCHAR);
229 UName->Buffer[unicodeIndex] = 0;
230 if(valueCRC) {
231 *valueCRC = UDFCrc(CS0+1, Length-1);
232 }
233 } // end UDFDecompressUnicode()
234
235 /*
236 This routine converts standard Unicode to compressed
237 */
238 void
239 __fastcall
240 UDFCompressUnicode(
241 IN PUNICODE_STRING UName,
242 IN OUT uint8** _CS0,
243 IN OUT PSIZE_T Length
244 )
245 {
246 uint8* CS0;
247 uint8 compID;
248 uint16 unicodeIndex;
249 uint32 i, len;
250 PWCHAR Buff;
251
252 len = (UName->Length) / sizeof(WCHAR);
253 compID = (!len) ? 0 : UDF_COMP_ID_8;
254 // check for uncompressable characters
255 Buff = UName->Buffer;
256 for(i=0; i<len; i++, Buff++) {
257 if((*Buff) & 0xff00) {
258 compID = UDF_COMP_ID_16;
259 break;
260 }
261 }
262
263 CS0 = (uint8*)MyAllocatePool__(NonPagedPool, *Length = (((compID==UDF_COMP_ID_8) ? 1 : 2)*len + 1) );
264 if(!CS0) return;
265
266 CS0[0] = compID;
267 *_CS0 = CS0;
268 // init loop
269 CS0++;
270 unicodeIndex = 0;
271 Buff = UName->Buffer;
272 if(compID == UDF_COMP_ID_16) {
273 // Loop through all the bytes.
274 while (unicodeIndex < len) {
275 // Move the 2nd byte to the low bits of the compressed unicode char.
276 *CS0 = (uint8)((*Buff) >> 8);
277 CS0++;
278 *CS0 = (uint8)(*Buff);
279 CS0++;
280 Buff++;
281 unicodeIndex++;
282 }
283 } else {
284 // Loop through all the bytes.
285 while (unicodeIndex < len) {
286 *CS0 = (uint8)(*Buff);
287 CS0++;
288 Buff++;
289 unicodeIndex++;
290 }
291 }
292 } // end UDFCompressUnicode()
293
294 /*
295 OSSTATUS UDFFindFile__(IN PVCB Vcb,
296 IN BOOLEAN IgnoreCase,
297 IN PUNICODE_STRING Name,
298 IN PUDF_FILE_INFO DirInfo)
299 see 'Udf_info.h'
300 */
301
302 /*
303 This routine reads (Extended)FileEntry according to FileDesc
304 */
305 OSSTATUS
306 UDFReadFileEntry(
307 IN PVCB Vcb,
308 IN long_ad* Icb,
309 IN OUT PFILE_ENTRY FileEntry, // here we can also get ExtendedFileEntry
310 IN OUT uint16* Ident
311 )
312 {
313 OSSTATUS status;
314
315 if(!OS_SUCCESS(status = UDFReadTagged(Vcb, (int8*)FileEntry,
316 UDFPartLbaToPhys(Vcb,&(Icb->extLocation)),
317 Icb->extLocation.logicalBlockNum,
318 Ident))) return status;
319 if((FileEntry->descTag.tagIdent != TID_FILE_ENTRY) &&
320 (FileEntry->descTag.tagIdent != TID_EXTENDED_FILE_ENTRY)) {
321 UDFPrint((" Not a FileEntry (lbn=%x, tag=%x)\n", Icb->extLocation.logicalBlockNum, FileEntry->descTag.tagIdent));
322 return STATUS_FILE_CORRUPT_ERROR;
323 }
324 return STATUS_SUCCESS;
325 } // UDFReadFileEntry()
326
327 #if !defined (_X86_) || !defined (_MSC_VER)
328 /*
329 Decides if a Unicode character matches one of a list
330 of ASCII characters.
331 Used by DOS version of UDFIsIllegalChar for readability, since all of the
332 illegal characters above 0x0020 are in the ASCII subset of Unicode.
333 Works very similarly to the standard C function strchr().
334 */
335 BOOLEAN
336 UDFUnicodeInString(
337 IN uint8* string, // String to search through.
338 IN WCHAR ch // Unicode char to search for.
339 )
340 {
341 BOOLEAN found = FALSE;
342
343 while(*string != '\0' && !found) {
344 // These types should compare, since both are unsigned numbers.
345 if(*string == ch) {
346 found = TRUE;
347 }
348 string++;
349 }
350 return(found);
351 } // end UDFUnicodeInString()
352 #endif // _X86_
353
354 /*
355 Decides whether character passed is an illegal character for a
356 DOS file name.
357 */
358 #ifdef _MSC_VER
359 #pragma warning(push)
360 #pragma warning(disable:4035) // re-enable below
361 #endif
362
363 #ifdef _X86_
364 #ifdef _MSC_VER
365 __declspec (naked)
366 #endif
367 #endif // _X86_
368 BOOLEAN
369 __fastcall
370 UDFIsIllegalChar(
371 IN WCHAR chr // ECX
372 )
373 {
374 // Genuine illegal char's for DOS.
375 #if defined (_X86_) && defined (_MSC_VER)
376 _asm {
377 push ebx
378
379 xor eax,eax
380 // mov ax,chr
381 mov ax,cx
382 or ah,ah
383 jnz ERR_IIC
384
385 lea ebx,[valid_char_arr]
386 xlatb
387 jmp short ERR_IIC2
388 ERR_IIC:
389 mov al,1
390 ERR_IIC2:
391
392 pop ebx
393 ret
394 }
395
396 #else // NO X86 optimization , use generic C/C++
397 /* FIXME */
398 //return ((ch < 0x20) || UDFUnicodeInString((uint8*)&valid_char_arr, ch));
399 return ((chr < 0x20) || UDFUnicodeInString((uint8*)&valid_char_arr, chr));
400 #endif // _X86_
401 } // end UDFIsIllegalChar()
402
403 #ifdef _MSC_VER
404 #pragma warning(pop) // re-enable warning #4035
405 #endif
406
407 /*
408 Translate udfName to dosName using OSTA compliant.
409 dosName must be a unicode string with min length of 12.
410 */
411
412 /*void UDFDOSName__(
413 IN PVCB Vcb,
414 IN OUT PUNICODE_STRING DosName,
415 IN PUNICODE_STRING UdfName,
416 IN PUDF_FILE_INFO FileInfo
417 )
418 {
419 BOOLEAN KeepIntact;
420
421 KeepIntact = (FileInfo && (FileInfo->Index < 2));
422 UDFDOSName(Vcb, DosName, UdfName, KeepIntact);
423 }*/
424
425 void
426 __fastcall
427 UDFDOSName(
428 IN PVCB Vcb,
429 IN OUT PUNICODE_STRING DosName,
430 IN PUNICODE_STRING UdfName,
431 IN BOOLEAN KeepIntact
432 )
433 {
434 #ifndef _CONSOLE
435 if(Vcb->CompatFlags & UDF_VCB_IC_OS_NATIVE_DOS_NAME) {
436 UDFDOSNameOsNative(DosName, UdfName, KeepIntact);
437 return;
438 }
439 #endif //_CONSOLE
440
441 switch(Vcb->CurrentUDFRev) {
442 case 0x0100:
443 case 0x0101:
444 case 0x0102:
445 UDFDOSName100(DosName, UdfName, KeepIntact);
446 break;
447
448 case 0x0150:
449 // in general, we need bytes-from-media to
450 // create valid UDF 1.50 name.
451 // Curently it is impossible, thus, we'll use
452 // UDF 2.00 translation algorithm
453 case 0x0200:
454 UDFDOSName200(DosName, UdfName, KeepIntact, Vcb->CurrentUDFRev == 0x0150);
455 break;
456
457 case 0x0201:
458 default:
459 UDFDOSName201(DosName, UdfName, KeepIntact);
460 }
461 }
462
463 void
464 __fastcall
465 UDFDOSName100(
466 IN OUT PUNICODE_STRING DosName,
467 IN PUNICODE_STRING UdfName,
468 IN BOOLEAN KeepIntact
469 )
470 {
471 PWCHAR dosName = DosName->Buffer;
472 PWCHAR udfName = UdfName->Buffer;
473 uint32 udfLen = UdfName->Length / sizeof(WCHAR);
474
475 uint32 index, dosIndex = 0, extIndex = 0, lastPeriodIndex;
476 BOOLEAN needsCRC = FALSE, hasExt = FALSE, writingExt = FALSE, isParent = FALSE;
477 uint32 valueCRC;
478 WCHAR ext[DOS_EXT_LEN], current;
479
480 if(KeepIntact &&
481 (udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) {
482 isParent = TRUE;
483 if((udfLen == 2) && (udfName[1] != UNICODE_PERIOD))
484 isParent = FALSE;
485 }
486
487 for (index = 0 ; index < udfLen ; index++) {
488 current = udfName[index];
489 if (current == UNICODE_PERIOD && !isParent) {
490 if (dosIndex==0 || hasExt) {
491 // Ignore leading periods or any other than used for extension.
492 needsCRC = TRUE;
493 } else {
494 // First, find last character which is NOT a period or space.
495 lastPeriodIndex = udfLen - 1;
496 while(lastPeriodIndex >=0 &&
497 (udfName[lastPeriodIndex] == UNICODE_PERIOD ||
498 udfName[lastPeriodIndex] == UNICODE_SPACE))
499 lastPeriodIndex--;
500 // Now search for last remaining period.
501 while(lastPeriodIndex >= 0 &&
502 udfName[lastPeriodIndex] != UNICODE_PERIOD)
503 lastPeriodIndex--;
504 // See if the period we found was the last or not.
505 if (lastPeriodIndex != index)
506 needsCRC = TRUE; // If not, name needs translation.
507 // As long as the period was not trailing,
508 // the file name has an extension.
509 if (lastPeriodIndex >= 0) hasExt = TRUE;
510 }
511 } else {
512 if ((!hasExt && dosIndex == DOS_NAME_LEN) ||
513 extIndex == DOS_EXT_LEN) {
514 // File name or extension is too long for DOS.
515 needsCRC = TRUE;
516 } else {
517 if (current == UNICODE_SPACE) { // Ignore spaces.
518 needsCRC = TRUE;
519 } else {
520 // Look for illegal or unprintable characters.
521 if (UDFIsIllegalChar(current) /*|| !UnicodeIsPrint(current)*/) {
522 needsCRC = TRUE;
523 current = ILLEGAL_CHAR_MARK;
524 /* Skip Illegal characters(even spaces),
525 * but not periods.
526 */
527 while(index+1 < udfLen &&
528 (UDFIsIllegalChar(udfName[index+1]) /*||
529 !UnicodeIsPrint(udfName[index+1])*/) &&
530 udfName[index+1] != UNICODE_PERIOD)
531 index++;
532 }
533 // Add current char to either file name or ext.
534 if (writingExt) {
535 ext[extIndex] = current;
536 extIndex++;
537 } else {
538 dosName[dosIndex] = current;
539 dosIndex++;
540 }
541 }
542 }
543 }
544 // See if we are done with file name, either because we reached
545 // the end of the file name length, or the final period.
546 if (!writingExt && hasExt && (dosIndex == DOS_NAME_LEN ||
547 index == lastPeriodIndex)) {
548 // If so, and the name has an extension, start reading it.
549 writingExt = TRUE;
550 // Extension starts after last period.
551 index = lastPeriodIndex;
552 }
553 }
554 //
555 if (needsCRC) {
556 // Add CRC to end of file name or at position 4.
557 if (dosIndex >4) dosIndex = 4;
558 valueCRC = UDFUnicodeCksum(udfName, udfLen);
559 // set CRC prefix
560 dosName[dosIndex] = UNICODE_CRC_MARK;
561 // Convert 12-bit CRC to hex characters.
562 dosName[dosIndex+1] = hexChar[(valueCRC & 0x0f00) >> 8];
563 dosName[dosIndex+2] = hexChar[(valueCRC & 0x00f0) >> 4];
564 dosName[dosIndex+3] = hexChar[(valueCRC & 0x000f)];
565 dosIndex+=4;
566 }
567 // Add extension, if any.
568 if (extIndex != 0) {
569 dosName[dosIndex] = UNICODE_PERIOD;
570 dosIndex++;
571 for (index = 0; index < extIndex; index++) {
572 dosName[dosIndex] = ext[index];
573 dosIndex++;
574 }
575 }
576 DosName->Length = (uint16)dosIndex*sizeof(WCHAR);
577 RtlUpcaseUnicodeString(DosName, DosName, FALSE);
578 } // end UDFDOSName100()
579
580 void
581 __fastcall
582 UDFDOSName200(
583 IN OUT PUNICODE_STRING DosName,
584 IN PUNICODE_STRING UdfName,
585 IN BOOLEAN KeepIntact,
586 IN BOOLEAN Mode150
587 )
588 {
589 PWCHAR dosName = DosName->Buffer;
590 PWCHAR udfName = UdfName->Buffer;
591 uint32 udfLen = UdfName->Length / sizeof(WCHAR);
592
593 uint32 index, dosIndex = 0, extIndex = 0, lastPeriodIndex;
594 BOOLEAN needsCRC = FALSE, hasExt = FALSE, writingExt = FALSE, isParent = FALSE;
595 uint32 valueCRC;
596 WCHAR ext[DOS_EXT_LEN], current;
597
598 if(KeepIntact &&
599 (udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) {
600 isParent = TRUE;
601 if((udfLen == 2) && (udfName[1] != UNICODE_PERIOD))
602 isParent = FALSE;
603 }
604
605 for (index = 0 ; index < udfLen ; index++) {
606 current = udfName[index];
607 if (current == UNICODE_PERIOD && !isParent) {
608 if (dosIndex==0 || hasExt) {
609 // Ignore leading periods or any other than used for extension.
610 needsCRC = TRUE;
611 } else {
612 // First, find last character which is NOT a period or space.
613 lastPeriodIndex = udfLen - 1;
614 while(lastPeriodIndex >=0 &&
615 (udfName[lastPeriodIndex] == UNICODE_PERIOD ||
616 udfName[lastPeriodIndex] == UNICODE_SPACE))
617 lastPeriodIndex--;
618 // Now search for last remaining period.
619 while(lastPeriodIndex >= 0 &&
620 udfName[lastPeriodIndex] != UNICODE_PERIOD)
621 lastPeriodIndex--;
622 // See if the period we found was the last or not.
623 if (lastPeriodIndex != index)
624 needsCRC = TRUE; // If not, name needs translation.
625 // As long as the period was not trailing,
626 // the file name has an extension.
627 if (lastPeriodIndex >= 0) hasExt = TRUE;
628 }
629 } else {
630 if ((!hasExt && dosIndex == DOS_NAME_LEN) ||
631 extIndex == DOS_EXT_LEN) {
632 // File name or extension is too long for DOS.
633 needsCRC = TRUE;
634 } else {
635 if (current == UNICODE_SPACE) { // Ignore spaces.
636 needsCRC = TRUE;
637 } else {
638 // Look for illegal or unprintable characters.
639 if (UDFIsIllegalChar(current) /*|| !UnicodeIsPrint(current)*/) {
640 needsCRC = TRUE;
641 current = ILLEGAL_CHAR_MARK;
642 /* Skip Illegal characters(even spaces),
643 * but not periods.
644 */
645 while(index+1 < udfLen &&
646 (UDFIsIllegalChar(udfName[index+1]) /*||
647 !UnicodeIsPrint(udfName[index+1])*/) &&
648 udfName[index+1] != UNICODE_PERIOD)
649 index++;
650 }
651 // Add current char to either file name or ext.
652 if (writingExt) {
653 ext[extIndex] = current;
654 extIndex++;
655 } else {
656 dosName[dosIndex] = current;
657 dosIndex++;
658 }
659 }
660 }
661 }
662 // See if we are done with file name, either because we reached
663 // the end of the file name length, or the final period.
664 if (!writingExt && hasExt && (dosIndex == DOS_NAME_LEN ||
665 index == lastPeriodIndex)) {
666 // If so, and the name has an extension, start reading it.
667 writingExt = TRUE;
668 // Extension starts after last period.
669 index = lastPeriodIndex;
670 }
671 }
672 // Now handle CRC if needed.
673 if (needsCRC) {
674 // Add CRC to end of file name or at position 4.
675 if (dosIndex >4) dosIndex = 4;
676 valueCRC = Mode150 ? UDFUnicodeCksum150(udfName, udfLen) : UDFUnicodeCksum(udfName, udfLen);
677 // Convert 16-bit CRC to hex characters.
678 dosName[dosIndex] = hexChar[(valueCRC & 0xf000) >> 12];
679 dosName[dosIndex+1] = hexChar[(valueCRC & 0x0f00) >> 8];
680 dosName[dosIndex+2] = hexChar[(valueCRC & 0x00f0) >> 4];
681 dosName[dosIndex+3] = hexChar[(valueCRC & 0x000f)];
682 dosIndex+=4;
683 }
684 // Add extension, if any.
685 if (extIndex != 0) {
686 dosName[dosIndex] = UNICODE_PERIOD;
687 dosIndex++;
688 for (index = 0; index < extIndex; index++) {
689 dosName[dosIndex] = ext[index];
690 dosIndex++;
691 }
692 }
693 DosName->Length = (uint16)dosIndex*sizeof(WCHAR);
694 RtlUpcaseUnicodeString(DosName, DosName, FALSE);
695 } // end UDFDOSName200()
696
697
698 void
699 __fastcall
700 UDFDOSName201(
701 IN OUT PUNICODE_STRING DosName,
702 IN PUNICODE_STRING UdfName,
703 IN BOOLEAN KeepIntact
704 )
705 {
706 PWCHAR dosName = DosName->Buffer;
707 PWCHAR udfName = UdfName->Buffer;
708 uint16 udfLen = UdfName->Length / sizeof(WCHAR);
709
710 uint16 index, dosIndex = 0;
711 //uint16 extIndex = 0;
712 BOOLEAN needsCRC = FALSE, isParent = FALSE;
713 //BOOLEAN hasExt = FALSE, writingExt = FALSE;
714 uint16 valueCRC;
715 WCHAR ext[DOS_EXT_LEN];
716 WCHAR current;
717
718 if(KeepIntact &&
719 (udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) {
720 isParent = TRUE;
721 if((udfLen == 2) && (udfName[1] != UNICODE_PERIOD))
722 isParent = FALSE;
723 }
724
725 #define DOS_CRC_LEN 4
726 #define DOS_CRC_MODULUS 41
727
728 int16 crcIndex;
729 uint16 extLen;
730 uint16 nameLen;
731 uint16 charLen;
732 int16 overlayBytes;
733 int16 bytesLeft;
734
735 /* Start at the end of the UDF file name and scan for a period */
736 /* ('.'). This will be where the DOS extension starts (if */
737 /* any). */
738 index = udfLen;
739 while (index-- > 0) {
740 if (udfName[index] == '.')
741 break;
742 }
743 if ((index < 0) || isParent) {
744 /* There name was scanned to the beginning of the buffer */
745 /* and no extension was found. */
746 extLen = 0;
747 nameLen = udfLen;
748 } else {
749 /* A DOS extension was found, process it first. */
750 extLen = udfLen - index - 1;
751 nameLen = index;
752 dosIndex = 0;
753 bytesLeft = DOS_EXT_LEN;
754 while (++index < udfLen && bytesLeft > 0) {
755 /* Get the current character and convert it to upper */
756 /* case. */
757 current = udfName[index];
758 if (current == ' ') {
759 /* If a space is found, a CRC must be appended to */
760 /* the mangled file name. */
761 needsCRC = TRUE;
762 } else {
763 /* Determine if this is a valid file name char and */
764 /* calculate its corresponding BCS character byte */
765 /* length (zero if the char is not legal or */
766 /* undisplayable on this system). */
767
768 charLen = (UDFIsIllegalChar(current)
769 /*|| !UnicodeIsPrint(current)*/) ? 0 : 1;
770
771 /* If the char is larger than the available space */
772 /* in the buffer, pretend it is undisplayable. */
773 if (charLen > bytesLeft)
774 charLen = 0;
775 if (charLen == 0) {
776 /* Undisplayable or illegal characters are */
777 /* substituted with an underscore ("_"), and */
778 /* required a CRC code appended to the mangled */
779 /* file name. */
780 needsCRC = TRUE;
781 charLen = 1;
782 current = '_';
783 /* Skip over any following undiplayable or */
784 /* illegal chars. */
785 while (index +1 <udfLen &&
786 (UDFIsIllegalChar(udfName[index+1])
787 /*|| !UnicodeIsPrint(udfName[index+1])*/))
788 index++;
789 }
790 /* Assign the resulting char to the next index in */
791 /* the extension buffer and determine how many BCS */
792 /* bytes are left. */
793 ext[dosIndex++] = current;
794 bytesLeft -= charLen;
795 }
796 }
797 /* Save the number of Unicode characters in the extension */
798 extLen = dosIndex;
799 /* If the extension was too large, or it was zero length */
800 /* (i.e. the name ended in a period), a CRC code must be */
801 /* appended to the mangled name. */
802 if (index < udfLen || extLen == 0)
803 needsCRC = TRUE;
804 }
805 /* Now process the actual file name. */
806 index = 0;
807 dosIndex = 0;
808 crcIndex = 0;
809 overlayBytes = -1;
810 bytesLeft = DOS_NAME_LEN;
811 while (index < nameLen && bytesLeft > 0) {
812 /* Get the current character and convert it to upper case. */
813 current = udfName[index];
814 if (current ==' ' || (current == '.' && !isParent) ) {
815 /* Spaces and periods are just skipped, a CRC code */
816 /* must be added to the mangled file name. */
817 needsCRC = TRUE;
818 } else {
819 /* Determine if this is a valid file name char and */
820 /* calculate its corresponding BCS character byte */
821 /* length (zero if the char is not legal or */
822 /* undisplayable on this system). */
823
824 charLen = (UDFIsIllegalChar(current)
825 /*|| !UnicodeIsPrint(current)*/) ? 0 : 1;
826
827 /* If the char is larger than the available space in */
828 /* the buffer, pretend it is undisplayable. */
829 if (charLen > bytesLeft)
830 charLen = 0;
831
832 if (charLen == 0) {
833 /* Undisplayable or illegal characters are */
834 /* substituted with an underscore ("_"), and */
835 /* required a CRC code appended to the mangled */
836 /* file name. */
837 needsCRC = TRUE;
838 charLen = 1;
839 current = '_';
840 /* Skip over any following undisplayable or illegal */
841 /* chars. */
842 while (index +1 <nameLen &&
843 (UDFIsIllegalChar(udfName[index+1])
844 /*|| !UnicodeIsPrint(udfName[index+1])*/))
845 index++;
846 /* Terminate loop if at the end of the file name. */
847 if (index >= nameLen)
848 break;
849 }
850 /* Assign the resulting char to the next index in the */
851 /* file name buffer and determine how many BCS bytes */
852 /* are left. */
853 dosName[dosIndex++] = current;
854 bytesLeft -= charLen;
855 /* This figures out where the CRC code needs to start */
856 /* in the file name buffer. */
857 if (bytesLeft >= DOS_CRC_LEN) {
858 /* If there is enough space left, just tack it */
859 /* onto the end. */
860 crcIndex = dosIndex;
861 } else {
862 /* If there is not enough space left, the CRC */
863 /* must overlay a character already in the file */
864 /* name buffer. Once this condition has been */
865 /* met, the value will not change. */
866 if (overlayBytes < 0) {
867 /* Determine the index and save the length of */
868 /* the BCS character that is overlayed. It */
869 /* is possible that the CRC might overlay */
870 /* half of a two-byte BCS character depending */
871 /* upon how the character boundaries line up. */
872 overlayBytes = (bytesLeft + charLen > DOS_CRC_LEN)?1 :0;
873 crcIndex = dosIndex - 1;
874 }
875 }
876 }
877 /* Advance to the next character. */
878 index++;
879 }
880 /* If the scan did not reach the end of the file name, or the */
881 /* length of the file name is zero, a CRC code is needed. */
882 if (index < nameLen || index == 0)
883 needsCRC = TRUE;
884
885 /* If the name has illegal characters or and extension, it */
886 /* is not a DOS device name. */
887
888 /* if (needsCRC == FALSE && extLen == 0) { */
889 /* If this is the name of a DOS device, a CRC code should */
890 /* be appended to the file name.
891 if (IsDeviceName(udfName, udfLen))
892 needsCRC = TRUE;
893 }*/
894
895 /* Append the CRC code to the file name, if needed. */
896 if (needsCRC) {
897 /* Get the CRC value for the original Unicode string */
898 valueCRC = UDFUnicodeCksum(udfName, udfLen);
899
900 /* begin. */
901 dosIndex = crcIndex;
902 /* If the character being overlayed is a two-byte BCS */
903 /* character, replace the first byte with an underscore. */
904 if (overlayBytes > 0)
905 dosName[dosIndex++] = '_';
906 /* Append the encoded CRC value with delimiter. */
907 dosName[dosIndex++] = '#';
908 dosName[dosIndex++] =
909 crcChar[valueCRC / (DOS_CRC_MODULUS * DOS_CRC_MODULUS)];
910 valueCRC %= DOS_CRC_MODULUS * DOS_CRC_MODULUS;
911 dosName[dosIndex++] =
912 crcChar[valueCRC / DOS_CRC_MODULUS];
913 valueCRC %= DOS_CRC_MODULUS;
914 dosName[dosIndex++] = crcChar[valueCRC];
915 }
916 /* Append the extension, if any. */
917 if (extLen > 0) {
918 /* Tack on a period and each successive byte in the */
919 /* extension buffer. */
920 dosName[dosIndex++] = '.';
921 for (index = 0; index < extLen; index++)
922 dosName[dosIndex++] = ext[index];
923 }
924 /* Return the length of the resulting Unicode string. */
925 DosName->Length = (uint16)dosIndex*sizeof(WCHAR);
926 RtlUpcaseUnicodeString(DosName, DosName, FALSE);
927
928 } // end UDFDOSName201()
929
930 #ifndef UDF_READ_ONLY_BUILD
931 /*
932 This routine initializes Tag structure. It must be called after all
933 manual settings to generate valid CRC & Checksum
934 */
935 void
936 UDFSetUpTag(
937 IN PVCB Vcb,
938 IN tag* Tag,
939 IN uint16 DataLen, // total length of descriptor _including_ icbTag
940 IN uint32 TagLoc
941 )
942 {
943 uint32 i;
944 int8* tb;
945
946 AdPrint(("UDF: SetTag Loc=%x(%x), tagIdent=%x\n", TagLoc, Tag->tagLocation, Tag->tagIdent));
947
948 if(DataLen) DataLen -= sizeof(tag);
949 // int8* Data = ((int8*)Tag) + sizeof(tag);
950 // Ecma-167 states, that all implementations
951 // shall set this field to '3' even if
952 // disc contains descriptors recorded with
953 // value '2'
954 // But we should ignore this to make happy othe UDF implementations :(
955 Tag->descVersion = (Vcb->NSRDesc & VRS_NSR03_FOUND) ? 3 : 2;
956 Tag->tagLocation = TagLoc;
957 Tag->tagSerialNum = (uint16)(Vcb->SerialNumber + 1);
958 Tag->descCRCLength = DataLen;
959 Tag->descCRC = UDFCrc((uint8*)(Tag+1), DataLen);
960 Tag->tagChecksum = 0;
961 tb = ((int8*)Tag);
962 for (i=0; i<sizeof(tag); i++,tb++)
963 Tag->tagChecksum += (i!=4) ? (*tb) : 0;
964 } // end UDFSetUpTag()
965
966 /*
967 This routine builds FileEntry & associated AllocDescs for specified
968 extent.
969 */
970 OSSTATUS
971 UDFBuildFileEntry(
972 IN PVCB Vcb,
973 IN PUDF_FILE_INFO DirInfo,
974 IN PUDF_FILE_INFO FileInfo,
975 IN uint32 PartNum,
976 IN uint16 AllocMode, // short/long/ext/in-icb
977 IN uint32 ExtAttrSz,
978 IN BOOLEAN Extended
979 )
980 {
981 PFILE_ENTRY FileEntry;
982 OSSTATUS status;
983 // EntityID* eID;
984 uint32 l;
985 EXTENT_INFO _FEExtInfo;
986 uint16* lcp;
987
988 ASSERT(!PartNum);
989 ASSERT(!ExtAttrSz);
990 // calculate the length required
991 l = (Extended ? sizeof(EXTENDED_FILE_ENTRY) : sizeof(FILE_ENTRY)) + ExtAttrSz;
992 if(l > Vcb->LBlockSize) return STATUS_INVALID_PARAMETER;
993 // allocate block for FE
994 if(!OS_SUCCESS(status = UDFAllocateFESpace(Vcb, DirInfo, PartNum, &_FEExtInfo, l) ))
995 return status;
996 // remember FE location for future hard link creation
997 ASSERT(UDFFindDloc(Vcb, _FEExtInfo.Mapping[0].extLocation) == (-1));
998 if(!OS_SUCCESS(status = UDFStoreDloc(Vcb, FileInfo, _FEExtInfo.Mapping[0].extLocation))) {
999 ASSERT(status != STATUS_SHARING_PAUSED);
1000 UDFFreeFESpace(Vcb, DirInfo, &_FEExtInfo); // free
1001 MyFreePool__(_FEExtInfo.Mapping);
1002 return status;
1003 }
1004 FileEntry = (PFILE_ENTRY)MyAllocatePoolTag__(NonPagedPool, l, MEM_FE_TAG);
1005 if(!FileEntry) {
1006 UDFRemoveDloc(Vcb, FileInfo->Dloc);
1007 FileInfo->Dloc = NULL;
1008 UDFFreeFESpace(Vcb, DirInfo, &_FEExtInfo); // free
1009 MyFreePool__(_FEExtInfo.Mapping);
1010 return STATUS_INSUFFICIENT_RESOURCES;
1011 }
1012 FileInfo->Dloc->FELoc = _FEExtInfo;
1013
1014 RtlZeroMemory((int8*)FileEntry, l);
1015 // set up in-memory FE structure
1016 FileEntry->icbTag.flags = AllocMode;
1017 FileEntry->icbTag.fileType = UDF_FILE_TYPE_REGULAR;
1018 FileEntry->icbTag.numEntries = 1;
1019 // if(DirInfo && DirInfo->Dloc && DirInfo->Dloc
1020 FileEntry->icbTag.strategyType = 4;
1021 // FileEntry->icbTag.strategyParameter = 0;
1022 FileEntry->descTag.tagIdent = Extended ? TID_EXTENDED_FILE_ENTRY : TID_FILE_ENTRY;
1023 FileEntry->descTag.tagLocation = UDFPhysLbaToPart(Vcb, PartNum, _FEExtInfo.Mapping[0].extLocation);
1024 FileEntry->uid = Vcb->DefaultUID;
1025 FileEntry->gid = Vcb->DefaultGID;
1026
1027 if(Extended) {
1028 // eID = &(((PEXTENDED_FILE_ENTRY)FileEntry)->impIdent);
1029 lcp = &(((PEXTENDED_FILE_ENTRY)FileEntry)->fileLinkCount);
1030 ((PEXTENDED_FILE_ENTRY)FileEntry)->checkpoint = 1;
1031 } else {
1032 // eID = &(FileEntry->impIdent);
1033 lcp = &(FileEntry->fileLinkCount);
1034 ((PFILE_ENTRY)FileEntry)->checkpoint = 1;
1035 }
1036
1037 #if 0
1038 UDFSetEntityID_imp(eID, UDF_ID_DEVELOPER);
1039 #endif
1040
1041 /*RtlCopyMemory((int8*)&(eID->ident), UDF_ID_DEVELOPER, sizeof(UDF_ID_DEVELOPER) );
1042 iis = (impIdentSuffix*)&(eID->identSuffix);
1043 iis->OSClass = UDF_OS_CLASS_WINNT;
1044 iis->OSIdent = UDF_OS_ID_WINNT;*/
1045
1046 *lcp = 0xffff;
1047
1048 FileInfo->Dloc->FileEntry = (tag*)FileEntry;
1049 FileInfo->Dloc->FileEntryLen = l;
1050
1051 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1052
1053 return STATUS_SUCCESS;
1054 } // end UDFBuildFileEntry()
1055 #endif //UDF_READ_ONLY_BUILD
1056
1057 /*
1058 This routine builds ExtentInfo for specified (Ex)FileEntry & associated
1059 AllocDescs
1060 */
1061 OSSTATUS
1062 UDFLoadExtInfo(
1063 IN PVCB Vcb,
1064 IN PFILE_ENTRY fe,
1065 IN PLONG_AD fe_loc,
1066 IN OUT PEXTENT_INFO FExtInfo, // user data
1067 IN OUT PEXTENT_INFO AExtInfo // alloc descs
1068 )
1069 {
1070 EXTENT_AD TmpExt;
1071
1072 UDFPrint((" UDFLoadExtInfo:\n"));
1073 FExtInfo->Mapping = UDFReadMappingFromXEntry(Vcb, fe_loc->extLocation.partitionReferenceNum,
1074 (tag*)fe, &(FExtInfo->Offset), AExtInfo);
1075 if(!(FExtInfo->Mapping)) {
1076 if(!(FExtInfo->Offset))
1077 return STATUS_UNSUCCESSFUL;
1078 TmpExt.extLength = fe_loc->extLength;
1079 TmpExt.extLocation = UDFPartLbaToPhys(Vcb, &(fe_loc->extLocation));
1080 if(TmpExt.extLocation == LBA_OUT_OF_EXTENT)
1081 return STATUS_FILE_CORRUPT_ERROR;
1082 FExtInfo->Mapping = UDFExtentToMapping(&TmpExt);
1083 }
1084 if(fe->descTag.tagIdent == TID_FILE_ENTRY) {
1085 // UDFPrint(("Standard FileEntry\n"));
1086 FExtInfo->Length = fe->informationLength;
1087 } else /*if(fe->descTag.tagIdent == TID_EXTENDED_FILE_ENTRY) */ {
1088 FExtInfo->Length = ((PEXTENDED_FILE_ENTRY)fe)->informationLength;
1089 }
1090 UDFPrint((" FExtInfo->Length %x\n", FExtInfo->Length));
1091 ASSERT(FExtInfo->Length <= UDFGetExtentLength(FExtInfo->Mapping));
1092 FExtInfo->Modified = FALSE;
1093
1094 return STATUS_SUCCESS;
1095 } // end UDFLoadExtInfo()
1096
1097 /*
1098 This routine builds FileIdent for specified FileEntry.
1099 We shall call UDFSetUpTag after all other initializations
1100 This structure is a precise copy of on-disk FileIdent
1101 structure. All modifications of it (including memory block
1102 size) are reflected on Directory extent. This, allocation of
1103 too long block (without changes in ImpUseLen) will lead to
1104 unreadable Directory
1105 */
1106 OSSTATUS
1107 UDFBuildFileIdent(
1108 IN PVCB Vcb,
1109 IN PUNICODE_STRING fn,
1110 IN PLONG_AD FileEntryIcb, // virtual address of FileEntry
1111 IN uint32 ImpUseLen,
1112 OUT PFILE_IDENT_DESC* _FileId,
1113 OUT uint32* FileIdLen
1114 )
1115 {
1116 PFILE_IDENT_DESC FileId;
1117 uint8* CS0;
1118 SIZE_T Nlen;
1119 uint32 l;
1120 // prepare filename
1121 UDFCompressUnicode(fn, &CS0, &Nlen);
1122 if(!CS0) return STATUS_INSUFFICIENT_RESOURCES;
1123 if(Nlen < 2) {
1124 Nlen = 0;
1125 } else
1126 if(Nlen > UDF_NAME_LEN) {
1127 if(CS0) MyFreePool__(CS0);
1128 return STATUS_OBJECT_NAME_INVALID;
1129 }
1130 // allocate memory for FI
1131 l = (sizeof(FILE_IDENT_DESC) + Nlen + ImpUseLen + 3) & ~((uint32)3);
1132 FileId = (PFILE_IDENT_DESC)MyAllocatePoolTag__(NonPagedPool, l, MEM_FID_TAG);
1133 if(!FileId) {
1134 if(CS0) MyFreePool__(CS0);
1135 return STATUS_INSUFFICIENT_RESOURCES;
1136 }
1137 // fill FI structure
1138 RtlZeroMemory( (int8*)FileId, l);
1139 RtlCopyMemory( ((int8*)(FileId+1))+ImpUseLen, CS0, Nlen);
1140 FileId->descTag.tagIdent = TID_FILE_IDENT_DESC;
1141 FileId->fileVersionNum = 1;
1142 FileId->lengthOfImpUse = (uint16)ImpUseLen;
1143 FileId->lengthFileIdent = (uint8)Nlen;
1144 FileId->icb = *FileEntryIcb;
1145 *_FileId = FileId;
1146 *FileIdLen = l;
1147
1148 if(CS0) MyFreePool__(CS0);
1149 return STATUS_SUCCESS;
1150 } // end UDFBuildFileIdent()
1151
1152 #ifndef UDF_READ_ONLY_BUILD
1153 /*
1154 This routine sets informationLength field in (Ext)FileEntry
1155 */
1156 void
1157 UDFSetFileSize(
1158 IN PUDF_FILE_INFO FileInfo,
1159 IN int64 Size
1160 )
1161 {
1162 uint16 Ident;
1163 // PDIR_INDEX_ITEM DirIndex;
1164
1165 ValidateFileInfo(FileInfo);
1166 AdPrint(("UDFSetFileSize: %I64x, FI %x\n", Size, FileInfo));
1167
1168 //AdPrint((" Dloc %x\n", FileInfo->Dloc));
1169 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1170 //AdPrint((" FileEntry %x\n", FileInfo->Dloc->FileEntry));
1171 Ident = FileInfo->Dloc->FileEntry->tagIdent;
1172 //AdPrint((" Ident %x\n", Ident));
1173 if(Ident == TID_FILE_ENTRY) {
1174 PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1175 //AdPrint((" fe %x\n", fe));
1176 fe->informationLength = Size;
1177 } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1178 PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1179 //AdPrint((" ext-fe %x\n", fe));
1180 fe->informationLength = Size;
1181 }
1182 /* if(DirIndex = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index) ) {
1183 DirIndex->FileSize = Size;
1184 }*/
1185 //AdPrint(("UDFSetFileSize: ok\n"));
1186 return;
1187 } // end UDFSetFileSize()
1188
1189 void
1190 UDFSetFileSizeInDirNdx(
1191 IN PVCB Vcb,
1192 IN PUDF_FILE_INFO FileInfo,
1193 IN int64* ASize
1194 )
1195 {
1196 uint16 Ident;
1197 PDIR_INDEX_ITEM DirIndex;
1198
1199 ValidateFileInfo(FileInfo);
1200 if(ASize) {
1201 AdPrint(("UDFSetFileSizeInDirNdx: %I64x\n", *ASize));
1202 } else {
1203 AdPrint(("UDFSetFileSizeInDirNdx: sync\n"));
1204 }
1205
1206 DirIndex = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index);
1207 if(!DirIndex)
1208 return;
1209
1210 Ident = FileInfo->Dloc->FileEntry->tagIdent;
1211 if(Ident == TID_FILE_ENTRY) {
1212 PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1213 DirIndex->FileSize = fe->informationLength;
1214 if(ASize) {
1215 DirIndex->AllocationSize = *ASize;
1216 // } else {
1217 // DirIndex->AllocationSize = (fe->informationLength + Vcb->LBlockSize - 1) & ~(Vcb->LBlockSize - 1);
1218 }
1219 } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1220 PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1221 DirIndex->FileSize = fe->informationLength;
1222 if(ASize) {
1223 DirIndex->AllocationSize = *ASize;
1224 // } else {
1225 // DirIndex->AllocationSize = (fe->informationLength + Vcb->LBlockSize - 1) & ~(Vcb->LBlockSize - 1);
1226 }
1227 }
1228 return;
1229 } // end UDFSetFileSizeInDirNdx()
1230 #endif //UDF_READ_ONLY_BUILD
1231
1232 /*
1233 This routine gets informationLength field in (Ext)FileEntry
1234 */
1235 int64
1236 UDFGetFileSize(
1237 IN PUDF_FILE_INFO FileInfo
1238 )
1239 {
1240 uint16 Ident;
1241
1242 ValidateFileInfo(FileInfo);
1243
1244 Ident = FileInfo->Dloc->FileEntry->tagIdent;
1245 if(Ident == TID_FILE_ENTRY) {
1246 PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1247 return fe->informationLength;
1248 } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1249 PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1250 return fe->informationLength;
1251 }
1252 return (-1);
1253 } // end UDFGetFileSize()
1254
1255 int64
1256 UDFGetFileSizeFromDirNdx(
1257 IN PVCB Vcb,
1258 IN PUDF_FILE_INFO FileInfo
1259 )
1260 {
1261 PDIR_INDEX_ITEM DirIndex;
1262
1263 ValidateFileInfo(FileInfo);
1264
1265 DirIndex = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index);
1266 if(!DirIndex)
1267 return -1;
1268
1269 return DirIndex->FileSize;
1270 } // end UDFGetFileSizeFromDirNdx()
1271
1272 #ifndef UDF_READ_ONLY_BUILD
1273 /*
1274 This routine sets lengthAllocDesc field in (Ext)FileEntry
1275 */
1276 void
1277 UDFSetAllocDescLen(
1278 IN PVCB Vcb,
1279 IN PUDF_FILE_INFO FileInfo
1280 )
1281 {
1282 uint16 Ident;
1283
1284 ValidateFileInfo(FileInfo);
1285
1286 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1287 Ident = FileInfo->Dloc->FileEntry->tagIdent;
1288 if(Ident == TID_FILE_ENTRY) {
1289 PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1290 if(FileInfo->Dloc->AllocLoc.Length) {
1291 fe->lengthAllocDescs = min(FileInfo->Dloc->AllocLoc.Mapping[0].extLength -
1292 FileInfo->Dloc->AllocLoc.Offset,
1293 (uint32)(FileInfo->Dloc->AllocLoc.Length));
1294 } else
1295 if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
1296 fe->lengthAllocDescs = (uint32)(FileInfo->Dloc->DataLoc.Length);
1297 }
1298 } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1299 PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1300 if(FileInfo->Dloc->AllocLoc.Length) {
1301 fe->lengthAllocDescs = min(FileInfo->Dloc->AllocLoc.Mapping[0].extLength -
1302 FileInfo->Dloc->AllocLoc.Offset,
1303 (uint32)(FileInfo->Dloc->AllocLoc.Length));
1304 } else
1305 if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
1306 fe->lengthAllocDescs = (uint32)(FileInfo->Dloc->DataLoc.Length);
1307 }
1308 }
1309 } // end UDFSetAllocDescLen()
1310
1311 /*
1312 This routine changes fileLinkCount field in (Ext)FileEntry
1313 */
1314 void
1315 UDFChangeFileLinkCount(
1316 IN PUDF_FILE_INFO FileInfo,
1317 IN BOOLEAN Increase
1318 )
1319 {
1320 uint16 Ident;
1321
1322 ValidateFileInfo(FileInfo);
1323
1324 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1325 Ident = FileInfo->Dloc->FileEntry->tagIdent;
1326 if(Ident == TID_FILE_ENTRY) {
1327 PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1328 if(Increase) {
1329 fe->fileLinkCount++;
1330 } else {
1331 fe->fileLinkCount--;
1332 }
1333 if(fe->fileLinkCount & 0x8000)
1334 fe->fileLinkCount = 0xffff;
1335 return;
1336 } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1337 PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1338 if(Increase) {
1339 fe->fileLinkCount++;
1340 } else {
1341 fe->fileLinkCount--;
1342 }
1343 if(fe->fileLinkCount & 0x8000)
1344 fe->fileLinkCount = 0xffff;
1345 return;
1346 }
1347 return;
1348 } // end UDFChangeFileLinkCount()
1349 #endif //UDF_READ_ONLY_BUILD
1350
1351 /*
1352 This routine gets fileLinkCount field from (Ext)FileEntry
1353 */
1354 uint16
1355 UDFGetFileLinkCount(
1356 IN PUDF_FILE_INFO FileInfo
1357 )
1358 {
1359 uint16 Ident;
1360 uint16 d;
1361
1362 ValidateFileInfo(FileInfo);
1363
1364 if(!FileInfo->Dloc->FileEntry)
1365 return 1;
1366 Ident = FileInfo->Dloc->FileEntry->tagIdent;
1367 // UDF engine assumes that LinkCount is a counter
1368 // of FileIdents, referencing this FE.
1369 // UDF 2.0 states, that it should be counter of ALL
1370 // references (including SDir) - 1.
1371 // Thus we'll write to media UDF-required value, but return
1372 // cooked value to callers
1373 d = UDFHasAStreamDir(FileInfo) ? 0 : 1;
1374 if(Ident == TID_FILE_ENTRY) {
1375 return ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount + d;
1376 } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1377 return ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount + d;
1378 }
1379 return UDF_INVALID_LINK_COUNT;
1380 } // end UDFGetFileLinkCount()
1381
1382 #ifdef UDF_CHECK_UTIL
1383 /*
1384 This routine sets fileLinkCount field in (Ext)FileEntry
1385 */
1386 void
1387 UDFSetFileLinkCount(
1388 IN PUDF_FILE_INFO FileInfo,
1389 uint16 LinkCount
1390 )
1391 {
1392 uint16 Ident;
1393 uint16 d;
1394
1395 ValidateFileInfo(FileInfo);
1396
1397 if(!FileInfo->Dloc->FileEntry)
1398 return;
1399 Ident = FileInfo->Dloc->FileEntry->tagIdent;
1400 // UDF engine assumes that LinkCount is a counter
1401 // of FileIdents, referencing this FE.
1402 // UDF 2.0 states, that it should be counter of ALL
1403 // references (including SDir) - 1.
1404 // Thus we'll write to media UDF-required value, but return
1405 // cooked value to callers
1406 d = UDFHasAStreamDir(FileInfo) ? 0 : 1;
1407 if(Ident == TID_FILE_ENTRY) {
1408 ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount = LinkCount - d;
1409 } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1410 ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount = LinkCount - d;
1411 }
1412 return;
1413 } // end UDFGetFileLinkCount()
1414 #endif //UDF_CHECK_UTIL
1415
1416 /*
1417 This routine gets lengthExtendedAttr field in (Ext)FileEntry
1418 */
1419 uint32
1420 UDFGetFileEALength(
1421 IN PUDF_FILE_INFO FileInfo
1422 )
1423 {
1424 uint16 Ident;
1425
1426 ValidateFileInfo(FileInfo);
1427
1428 if(!FileInfo->Dloc->FileEntry)
1429 return 1;
1430 Ident = FileInfo->Dloc->FileEntry->tagIdent;
1431
1432 if(Ident == TID_FILE_ENTRY) {
1433 return ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->lengthExtendedAttr;
1434 } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1435 return ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->lengthExtendedAttr;
1436 }
1437 return 0;
1438 } // end UDFGetFileEALength()
1439
1440 #ifndef UDF_READ_ONLY_BUILD
1441 /*
1442 This routine sets UniqueID field in (Ext)FileEntry
1443 */
1444 int64
1445 UDFAssingNewFUID(
1446 IN PVCB Vcb
1447 )
1448 {
1449 Vcb->NextUniqueId++;
1450 if(!((uint32)(Vcb->NextUniqueId)))
1451 Vcb->NextUniqueId += 16;
1452 return Vcb->NextUniqueId;
1453 }
1454
1455 void
1456 UDFSetFileUID(
1457 IN PVCB Vcb,
1458 IN PUDF_FILE_INFO FileInfo
1459 )
1460 {
1461 uint16 Ident;
1462 int64 UID;
1463
1464 ValidateFileInfo(FileInfo);
1465
1466 UID = UDFAssingNewFUID(Vcb);
1467
1468 /* UID = FileInfo->Dloc->FELoc.Mapping[0].extLocation |
1469 ( FileInfo->ParentFile ? (((int64)(FileInfo->ParentFile->Dloc->FELoc.Mapping[0].extLocation)) << 32) : 0);*/
1470
1471 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1472 Ident = FileInfo->Dloc->FileEntry->tagIdent;
1473 if(Ident == TID_FILE_ENTRY) {
1474 PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1475 fe->uniqueID = UID;
1476 } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1477 PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1478 fe->uniqueID = UID;
1479 }
1480 if(FileInfo->FileIdent)
1481 ((FidADImpUse*)&(FileInfo->FileIdent->icb.impUse))->uniqueID = (uint32)UID;
1482 return;
1483 } // end UDFSetFileUID()
1484 #endif //UDF_READ_ONLY_BUILD
1485
1486 /*
1487 This routine gets UniqueID field in (Ext)FileEntry
1488 */
1489 __inline
1490 int64
1491 UDFGetFileUID_(
1492 IN tag* FileEntry
1493 )
1494 {
1495 uint16 Ident;
1496
1497 Ident = FileEntry->tagIdent;
1498 if(Ident == TID_FILE_ENTRY) {
1499 PFILE_ENTRY fe = (PFILE_ENTRY)(FileEntry);
1500 return fe->uniqueID;
1501 } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1502 PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileEntry);
1503 return fe->uniqueID;
1504 }
1505 return (-1);
1506 } // end UDFGetFileUID()
1507
1508 int64
1509 UDFGetFileUID(
1510 IN PUDF_FILE_INFO FileInfo
1511 )
1512 {
1513 ValidateFileInfo(FileInfo);
1514
1515 return UDFGetFileUID_(FileInfo->Dloc->FileEntry);
1516 } // end UDFGetFileUID()
1517
1518 #ifndef UDF_READ_ONLY_BUILD
1519 void
1520 UDFChangeFileCounter(
1521 IN PVCB Vcb,
1522 IN BOOLEAN FileCounter,
1523 IN BOOLEAN Increase
1524 )
1525 {
1526 uint32* counter;
1527
1528 counter = FileCounter ?
1529 &(Vcb->numFiles) :
1530 &(Vcb->numDirs);
1531 if(*counter == (ULONG)-1)
1532 return;
1533 if(Increase) {
1534 UDFInterlockedIncrement((int32*)counter);
1535 } else {
1536 UDFInterlockedDecrement((int32*)counter);
1537 }
1538
1539 } // end UDFChangeFileCounter()
1540
1541 void
1542 UDFSetEntityID_imp_(
1543 IN EntityID* eID,
1544 IN uint8* Str,
1545 IN uint32 Len
1546 )
1547 {
1548 impIdentSuffix* iis;
1549
1550 RtlCopyMemory( (int8*)&(eID->ident), Str, Len );
1551 iis = (impIdentSuffix*)&(eID->identSuffix);
1552 iis->OSClass = UDF_OS_CLASS_WINNT;
1553 iis->OSIdent = UDF_OS_ID_WINNT;
1554
1555 } // end UDFSetEntityID_imp_()
1556 #endif //UDF_READ_ONLY_BUILD
1557
1558 void
1559 UDFReadEntityID_Domain(
1560 PVCB Vcb,
1561 EntityID* eID
1562 )
1563 {
1564 domainIdentSuffix* dis;
1565 uint8 flags;
1566
1567 dis = (domainIdentSuffix*)&(eID->identSuffix);
1568
1569 UDFPrint(("UDF: Entity Id:\n"));
1570 UDFPrint(("flags: %x\n", eID->flags));
1571 UDFPrint(("ident[0]: %x\n", eID->ident[0]));
1572 UDFPrint(("ident[1]: %x\n", eID->ident[1]));
1573 UDFPrint(("ident[2]: %x\n", eID->ident[2]));
1574 UDFPrint(("ident[3]: %x\n", eID->ident[3]));
1575 UDFPrint(("UDF: Entity Id Domain:\n"));
1576 // Get current UDF revision
1577 Vcb->CurrentUDFRev = max(dis->currentRev, Vcb->CurrentUDFRev);
1578 UDFPrint(("Effective Revision: %x\n", Vcb->CurrentUDFRev));
1579 // Get Read-Only flags
1580 flags = dis->flags;
1581 UDFPrint(("Flags: %x\n", flags));
1582 if((flags & ENTITYID_FLAGS_SOFT_RO) &&
1583 (Vcb->CompatFlags & UDF_VCB_IC_SOFT_RO)) {
1584 Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY;
1585 Vcb->UserFSFlags |= UDF_USER_FS_FLAGS_SOFT_RO;
1586 UDFPrint((" Soft-RO\n"));
1587 }
1588 if((flags & ENTITYID_FLAGS_HARD_RO) &&
1589 (Vcb->CompatFlags & UDF_VCB_IC_HW_RO)) {
1590 Vcb->VCBFlags |= UDF_VCB_FLAGS_MEDIA_READ_ONLY;
1591 Vcb->UserFSFlags |= UDF_USER_FS_FLAGS_HW_RO;
1592 UDFPrint((" Hard-RO\n"));
1593 }
1594
1595 } // end UDFReadEntityID_Domain()
1596
1597 #ifndef UDF_READ_ONLY_BUILD
1598 /*
1599 This routine writes data to file & increases it if necessary.
1600 In case of increasing AllocDescs will be rebuilt & flushed to disc
1601 (via driver's cache, of cource). Free space map will be updated only
1602 durring global media flush.
1603 */
1604 OSSTATUS
1605 UDFWriteFile__(
1606 IN PVCB Vcb,
1607 IN PUDF_FILE_INFO FileInfo,
1608 IN int64 Offset,
1609 IN SIZE_T Length,
1610 IN BOOLEAN Direct,
1611 IN int8* Buffer,
1612 OUT PSIZE_T WrittenBytes
1613 )
1614 {
1615 int64 t, elen;
1616 OSSTATUS status;
1617 int8* OldInIcb = NULL;
1618 ValidateFileInfo(FileInfo);
1619 SIZE_T ReadBytes;
1620 SIZE_T _WrittenBytes;
1621 PUDF_DATALOC_INFO Dloc;
1622 // unwind staff
1623 BOOLEAN WasInIcb = FALSE;
1624 uint64 OldLen;
1625
1626 // ASSERT(FileInfo->RefCount >= 1);
1627
1628 Dloc = FileInfo->Dloc;
1629 ASSERT(Dloc->FELoc.Mapping[0].extLocation);
1630 uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, Dloc->FELoc.Mapping[0].extLocation);
1631 (*WrittenBytes) = 0;
1632
1633 AdPrint(("UDFWriteFile__ FE %x, FileInfo %x, ExtInfo %x, Mapping %x\n",
1634 Dloc->FELoc.Mapping[0].extLocation, FileInfo, &(Dloc->DataLoc), Dloc->DataLoc.Mapping));
1635
1636 t = Offset + Length;
1637 // UDFUpdateModifyTime(Vcb, FileInfo);
1638 if(t <= Dloc->DataLoc.Length) {
1639 // write Alloc-Rec area
1640 ExtPrint((" WAlloc-Rec: %I64x <= %I64x\n", t, Dloc->DataLoc.Length));
1641 status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), Offset, Length, Direct, Buffer, WrittenBytes);
1642 return status;
1643 }
1644 elen = UDFGetExtentLength(Dloc->DataLoc.Mapping);
1645 ExtPrint((" DataLoc Offs %x, Len %I64x\n",
1646 Dloc->DataLoc.Offset, Dloc->DataLoc.Length));
1647 if(t <= (elen - Dloc->DataLoc.Offset)) {
1648 // write Alloc-Not-Rec area
1649 ExtPrint((" WAlloc-Not-Rec: %I64x <= %I64x (%I64x - %I64x)\n",
1650 t, elen - Dloc->DataLoc.Offset - Dloc->DataLoc.Length,
1651 elen - Dloc->DataLoc.Offset,
1652 Dloc->DataLoc.Length));
1653 UDFSetFileSize(FileInfo, t);
1654 if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
1655 ExtPrint((" w2k-compat -> rebuild allocs\n"));
1656 Dloc->DataLoc.Modified = TRUE;
1657 } else
1658 if((ULONG)((elen+Vcb->LBlockSize-1) >> Vcb->LBlockSizeBits) != (ULONG)((t+Vcb->LBlockSize-1) >> Vcb->LBlockSizeBits)) {
1659 ExtPrint((" LBS boundary crossed -> rebuild allocs\n"));
1660 Dloc->DataLoc.Modified = TRUE;
1661 }
1662 Dloc->DataLoc.Length = t;
1663 return UDFWriteExtent(Vcb, &(Dloc->DataLoc), Offset, Length, Direct, Buffer, WrittenBytes);
1664 }
1665 // We should not get here if Direct=TRUE
1666 if(Direct) return STATUS_INVALID_PARAMETER;
1667 OldLen = Dloc->DataLoc.Length;
1668 if(Dloc->DataLoc.Offset && Dloc->DataLoc.Length) {
1669 // read in-icb data. it'll be replaced after resize
1670 ExtPrint((" read in-icb data\n"));
1671 OldInIcb = (int8*)MyAllocatePool__(NonPagedPool, (uint32)(Dloc->DataLoc.Length));
1672 if(!OldInIcb) return STATUS_INSUFFICIENT_RESOURCES;
1673 status = UDFReadExtent(Vcb, &(Dloc->DataLoc), 0, (uint32)OldLen, FALSE, OldInIcb, &ReadBytes);
1674 if(!OS_SUCCESS(status)) {
1675 MyFreePool__(OldInIcb);
1676 return status;
1677 }
1678 }
1679 // init Alloc mode
1680 ExtPrint((" init Alloc mode\n"));
1681 if((((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) {
1682 ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK;
1683 ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= Vcb->DefaultAllocMode;
1684 WasInIcb = TRUE;
1685 }
1686 // increase extent
1687 ExtPrint((" %s %s %s\n",
1688 UDFIsADirectory(FileInfo) ? "DIR" : "FILE",
1689 WasInIcb ? "In-Icb" : "",
1690 Vcb->LowFreeSpace ? "LowSpace" : ""));
1691 if(UDFIsADirectory(FileInfo) && !WasInIcb && !Vcb->LowFreeSpace) {
1692 FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_ALLOC_SEQUENTIAL;
1693 status = UDFResizeExtent(Vcb, PartNum, (t*2+Vcb->WriteBlockSize-1) & ~(SIZE_T)(Vcb->WriteBlockSize-1), FALSE, &(Dloc->DataLoc));
1694 if(OS_SUCCESS(status)) {
1695 AdPrint((" preallocated space for Dir\n"));
1696 FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_PREALLOCATED;
1697 //UDFSetFileSize(FileInfo, t);
1698 Dloc->DataLoc.Length = t;
1699 } else
1700 if(status == STATUS_DISK_FULL) {
1701 status = UDFResizeExtent(Vcb, PartNum, t, FALSE, &(Dloc->DataLoc));
1702 }
1703 } else {
1704 status = UDFResizeExtent(Vcb, PartNum, t, FALSE, &(Dloc->DataLoc));
1705 }
1706 ExtPrint((" DataLoc Offs %x, Len %I64x\n",
1707 Dloc->DataLoc.Offset, Dloc->DataLoc.Length));
1708 AdPrint(("UDFWriteFile__ (2) FileInfo %x, ExtInfo %x, Mapping %x\n", FileInfo, &(Dloc->DataLoc), Dloc->DataLoc.Mapping));
1709 if(!OS_SUCCESS(status)) {
1710 // rollback
1711 ExtPrint((" err -> rollback\n"));
1712 if(WasInIcb) {
1713 // restore Alloc mode
1714 ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK;
1715 ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= ICB_FLAG_AD_IN_ICB;
1716 if(Dloc->AllocLoc.Mapping) {
1717 MyFreePool__(Dloc->AllocLoc.Mapping);
1718 Dloc->AllocLoc.Mapping = NULL;
1719 }
1720 }
1721 if(OldInIcb) {
1722 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;
1748 UDFSetFileSize(FileInfo, t);
1749 Dloc->DataLoc.Modified = TRUE;
1750 #ifdef UDF_DBG
1751 if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
1752 ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping));
1753 } else {
1754 ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) ==
1755 ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)));
1756 }
1757 #endif // UDF_DBG
1758 return STATUS_SUCCESS;
1759 } // end UDFWriteFile__()
1760
1761 /*
1762 This routine marks file as deleted & decrements file link counter.
1763 It can optionaly free allocation space
1764 */
1765 OSSTATUS
1766 UDFUnlinkFile__(
1767 IN PVCB Vcb,
1768 IN PUDF_FILE_INFO FileInfo,
1769 IN BOOLEAN FreeSpace
1770 )
1771 {
1772 uint_di Index; // index of file to be deleted
1773 uint16 lc;
1774 PUDF_DATALOC_INFO Dloc;
1775 PUDF_FILE_INFO DirInfo;
1776 PUDF_FILE_INFO SDirInfo;
1777 PDIR_INDEX_HDR hDirNdx;
1778 PDIR_INDEX_HDR hCurDirNdx;
1779 PDIR_INDEX_ITEM DirNdx;
1780 OSSTATUS status;
1781 BOOLEAN IsSDir;
1782
1783 AdPrint(("UDFUnlinkFile__:\n"));
1784 if(!FileInfo) return STATUS_SUCCESS;
1785
1786 ValidateFileInfo(FileInfo);
1787
1788 #ifndef _CONSOLE
1789 // now we can't call this if there is no OS-specific File Desc. present
1790 if(FileInfo->Fcb)
1791 UDFRemoveFileId__(Vcb, FileInfo);
1792 #endif //_CONSOLE
1793 // check references
1794 Dloc = FileInfo->Dloc;
1795 if((FileInfo->OpenCount /*> (uint32)(UDFHasAStreamDir(FileInfo) ? 1 : 0)*/) ||
1796 (FileInfo->RefCount>1)) return STATUS_CANNOT_DELETE;
1797 if(Dloc->SDirInfo)
1798 return STATUS_CANNOT_DELETE;
1799 ASSERT(FileInfo->RefCount == 1);
1800 DirInfo = FileInfo->ParentFile;
1801 // root dir or self
1802 if(!DirInfo || ((FileInfo->Index < 2) && !UDFIsAStreamDir(FileInfo))) return STATUS_CANNOT_DELETE;
1803 hDirNdx = DirInfo->Dloc->DirIndex;
1804 Index = FileInfo->Index;
1805 // we can't delete modified file
1806 // it should be closed & reopened (or flushed) before deletion
1807 DirNdx = UDFDirIndex(hDirNdx,Index);
1808 #if defined UDF_DBG || defined PRINT_ALWAYS
1809 if(DirNdx && DirNdx->FName.Buffer) {
1810 AdPrint(("Unlink: %ws\n",DirNdx->FName.Buffer));
1811 }
1812 #endif // UDF_DBG
1813 if(FreeSpace &&
1814 ((Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) ||
1815 Dloc->DataLoc.Modified ||
1816 Dloc->AllocLoc.Modified ||
1817 Dloc->FELoc.Modified ||
1818 (DirNdx && (DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) )) {
1819 // BrutePoint();
1820 return STATUS_CANNOT_DELETE;
1821 }
1822 SDirInfo = Dloc->SDirInfo;
1823 /* if(FreeSpace && SDirInfo) {
1824 UDFPrint(("Unlink: SDirInfo should be NULL !!!\n"));
1825 BrutePoint();
1826 return STATUS_CANNOT_DELETE;
1827 }*/
1828 // stream directory can be deleted even being not empty
1829 // otherwise we should perform some checks
1830 if(!(IsSDir = UDFIsAStreamDir(FileInfo))) {
1831 // check if not empty direcory
1832 if((DirNdx->FileCharacteristics & FILE_DIRECTORY) &&
1833 (hCurDirNdx = Dloc->DirIndex) &&
1834 FreeSpace) {
1835 if(!UDFIsDirEmpty(hCurDirNdx))
1836 return STATUS_DIRECTORY_NOT_EMPTY;
1837 }
1838 DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
1839 DirNdx->FileCharacteristics |= FILE_DELETED;
1840 FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED;
1841 hDirNdx->DelCount++;
1842 UDFChangeFileCounter(Vcb, !UDFIsADirectory(FileInfo), FALSE);
1843 }
1844 UDFDecFileLinkCount(FileInfo); // decrease
1845 lc = UDFGetFileLinkCount(FileInfo);
1846 if(DirNdx && FreeSpace) {
1847 // FileIdent marked as 'deleted' should have an empty ICB
1848 // We shall do it only if object has parent Dir
1849 // (for ex. SDir has parent object, but has no parent Dir)
1850 DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
1851 DirNdx->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR;
1852 // Root Files (Root/SDir/Vat/etc.) has no FileIdent...
1853 if(FileInfo->FileIdent)
1854 RtlZeroMemory(&(FileInfo->FileIdent->icb), sizeof(long_ad));
1855 }
1856 // caller wishes to free allocation, but we can't do it due to
1857 // alive links. In this case we should just remove reference
1858 if(FreeSpace && lc) {
1859 ((icbtag*)(Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum = 0;
1860 ((icbtag*)(Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum = 0;
1861 Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1862 } else
1863 // if caller wishes to free file allocation &
1864 // there are no more references(links) to this file, lets do it >;->
1865 if(FreeSpace && !lc) {
1866 if(UDFHasAStreamDir(FileInfo) &&
1867 !UDFIsSDirDeleted(Dloc->SDirInfo) ) {
1868 // we have a Stream Dir associated...
1869 PUDF_FILE_INFO SFileInfo;
1870 // ... try to open it
1871 if(Dloc->SDirInfo) {
1872 UDFFlushFile__(Vcb, FileInfo);
1873 return STATUS_CANNOT_DELETE;
1874 }
1875 // open SDir
1876 status = UDFOpenStreamDir__(Vcb, FileInfo, &(Dloc->SDirInfo));
1877 if(!OS_SUCCESS(status)) {
1878 // abort Unlink on error
1879 SFileInfo = Dloc->SDirInfo;
1880 cleanup_SDir:
1881 UDFCleanUpFile__(Vcb, SFileInfo);
1882 if(SFileInfo) MyFreePool__(SFileInfo);
1883 UDFFlushFile__(Vcb, FileInfo);
1884 return status;
1885 }
1886 SDirInfo = Dloc->SDirInfo;
1887 // try to perform deltree for Streams
1888 status = UDFUnlinkAllFilesInDir(Vcb, SDirInfo);
1889 if(!OS_SUCCESS(status)) {
1890 // abort Unlink on error
1891 UDFCloseFile__(Vcb, SDirInfo);
1892 SFileInfo = SDirInfo;
1893 BrutePoint();
1894 goto cleanup_SDir;
1895 }
1896 // delete SDir
1897 UDFFlushFile__(Vcb, SDirInfo);
1898 AdPrint((" "));
1899 UDFUnlinkFile__(Vcb, SDirInfo, TRUE);
1900 // close SDir
1901 UDFCloseFile__(Vcb, SDirInfo);
1902 if(UDFCleanUpFile__(Vcb, SDirInfo)) {
1903 MyFreePool__(SDirInfo);
1904 #ifdef UDF_DBG
1905 } else {
1906 BrutePoint();
1907 #endif // UDF_DBG
1908 }
1909 // update FileInfo
1910 ASSERT(Dloc->FileEntry);
1911 RtlZeroMemory( &(((PEXTENDED_FILE_ENTRY)(Dloc->FileEntry))->streamDirectoryICB), sizeof(long_ad));
1912 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1913 } else
1914 if(IsSDir) {
1915 // do deltree for Streams
1916 status = UDFUnlinkAllFilesInDir(Vcb, FileInfo);
1917 if(!OS_SUCCESS(status)) {
1918 UDFFlushFile__(Vcb, FileInfo);
1919 return status;
1920 }
1921 // update parent FileInfo
1922 ASSERT(FileInfo->ParentFile->Dloc->FileEntry);
1923 RtlZeroMemory( &(((PEXTENDED_FILE_ENTRY)(FileInfo->ParentFile->Dloc->FileEntry))->streamDirectoryICB), sizeof(long_ad));
1924 FileInfo->ParentFile->Dloc->FE_Flags &= ~UDF_FE_FLAG_HAS_SDIR;
1925 FileInfo->ParentFile->Dloc->FE_Flags |= (UDF_FE_FLAG_FE_MODIFIED |
1926 UDF_FE_FLAG_HAS_DEL_SDIR);
1927 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_IS_DEL_SDIR;
1928 UDFDecFileLinkCount(FileInfo->ParentFile);
1929 }
1930 if(Dloc->DirIndex) {
1931 UDFFlushFESpace(Vcb, Dloc, FLUSH_FE_FOR_DEL);
1932 }
1933 // flush file
1934 UDFFlushFile__(Vcb, FileInfo);
1935 UDFUnlinkDloc(Vcb, Dloc);
1936 // free allocation
1937 UDFFreeFileAllocation(Vcb, DirInfo, FileInfo);
1938 ASSERT(!(FileInfo->Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED));
1939 FileInfo->Dloc->FE_Flags &= ~UDF_FE_FLAG_FE_MODIFIED;
1940 }
1941 return STATUS_SUCCESS;
1942 } // end UDFUnlinkFile__()
1943
1944 OSSTATUS
1945 UDFUnlinkAllFilesInDir(
1946 IN PVCB Vcb,
1947 IN PUDF_FILE_INFO DirInfo
1948 )
1949 {
1950 PDIR_INDEX_HDR hCurDirNdx;
1951 PDIR_INDEX_ITEM CurDirNdx;
1952 PUDF_FILE_INFO FileInfo;
1953 OSSTATUS status;
1954 uint_di i;
1955
1956 hCurDirNdx = DirInfo->Dloc->DirIndex;
1957 // check if we can delete all files
1958 for(i=2; (CurDirNdx = UDFDirIndex(hCurDirNdx,i)); i++) {
1959 // try to open Stream
1960 if(CurDirNdx->FileInfo)
1961 return STATUS_CANNOT_DELETE;
1962 }
1963 // start deletion
1964 for(i=2; (CurDirNdx = UDFDirIndex(hCurDirNdx,i)); i++) {
1965 // try to open Stream
1966 status = UDFOpenFile__(Vcb, FALSE, TRUE, NULL, DirInfo, &FileInfo, &i);
1967 if(status == STATUS_FILE_DELETED) {
1968 // we should not release on-disk allocation for
1969 // deleted streams twice
1970 if(CurDirNdx->FileInfo) {
1971 BrutePoint();
1972 goto err_del_stream;
1973 }
1974 goto skip_del_stream;
1975 } else
1976 if(!OS_SUCCESS(status)) {
1977 // Error :(((
1978 err_del_stream:
1979 UDFCleanUpFile__(Vcb, FileInfo);
1980 if(FileInfo)
1981 MyFreePool__(FileInfo);
1982 return status;
1983 }
1984
1985 UDFFlushFile__(Vcb, FileInfo);
1986 AdPrint((" "));
1987 UDFUnlinkFile__(Vcb, FileInfo, TRUE);
1988 UDFCloseFile__(Vcb, FileInfo);
1989 skip_del_stream:
1990 if(FileInfo && UDFCleanUpFile__(Vcb, FileInfo)) {
1991 MyFreePool__(FileInfo);
1992 }
1993 }
1994 return STATUS_SUCCESS;
1995 } // end UDFUnlinkAllFilesInDir()
1996 #endif //UDF_READ_ONLY_BUILD
1997
1998 /*
1999 This routine inits UDF_FILE_INFO structure for specified file
2000 If it returns status != STATUS_SUCCESS caller should call UDFCleanUpFile__
2001 for returned pointer *WITHOUT* using UDFCloseFile__
2002 */
2003 OSSTATUS
2004 UDFOpenFile__(
2005 IN PVCB Vcb,
2006 IN BOOLEAN IgnoreCase,
2007 IN BOOLEAN NotDeleted,
2008 IN PUNICODE_STRING fn,
2009 IN PUDF_FILE_INFO DirInfo,
2010 OUT PUDF_FILE_INFO* _FileInfo,// this is to be filled & doesn't contain
2011 // any pointers
2012 IN uint_di* IndexToOpen
2013 )
2014 {
2015 OSSTATUS status;
2016 uint_di i=0;
2017 EXTENT_AD FEExt;
2018 uint16 Ident;
2019 PDIR_INDEX_HDR hDirNdx = DirInfo->Dloc->DirIndex;
2020 PDIR_INDEX_ITEM DirNdx;
2021 PUDF_FILE_INFO FileInfo;
2022 PUDF_FILE_INFO ParFileInfo;
2023 SIZE_T ReadBytes;
2024 *_FileInfo = NULL;
2025 if(!hDirNdx) return STATUS_NOT_A_DIRECTORY;
2026
2027 // find specified file in directory index
2028 // if it is already known, skip this foolish code
2029 if(IndexToOpen) {
2030 i=*IndexToOpen;
2031 } else
2032 if(!OS_SUCCESS(status = UDFFindFile(Vcb, IgnoreCase, NotDeleted, fn, DirInfo, &i)))
2033 return status;
2034 // do this check for OpenByIndex
2035 // some routines may send invalid Index
2036 if(!(DirNdx = UDFDirIndex(hDirNdx,i)))
2037 return STATUS_OBJECT_NAME_NOT_FOUND;
2038 if((FileInfo = DirNdx->FileInfo)) {
2039 // file is already opened.
2040 if((DirNdx->FileCharacteristics & FILE_DELETED) && NotDeleted) {
2041 AdPrint((" FILE_DELETED on open\n"));
2042 return STATUS_FILE_DELETED;
2043 }
2044 if((FileInfo->ParentFile != DirInfo) &&
2045 (FileInfo->Index >= 2)) {
2046 ParFileInfo = UDFLocateParallelFI(DirInfo, i, FileInfo);
2047 BrutePoint();
2048 if(ParFileInfo->ParentFile != DirInfo) {
2049 FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_FINF_TAG);
2050 *_FileInfo = FileInfo;
2051 if(!FileInfo) return STATUS_INSUFFICIENT_RESOURCES;
2052 RtlCopyMemory(FileInfo, DirNdx->FileInfo, sizeof(UDF_FILE_INFO));
2053 // FileInfo->NextLinkedFile = DirNdx->FileInfo->NextLinkedFile; // is already done
2054 UDFInsertLinkedFile(FileInfo, DirNdx->FileInfo);
2055 DirNdx->FI_Flags |= UDF_FI_FLAG_LINKED;
2056 FileInfo->RefCount = 0;
2057 FileInfo->ParentFile = DirInfo;
2058 FileInfo->Fcb = NULL;
2059 } else {
2060 FileInfo = ParFileInfo;
2061 }
2062 }
2063 // Just increase some counters & exit
2064 UDFReferenceFile__(FileInfo);
2065
2066 ASSERT(FileInfo->ParentFile == DirInfo);
2067 ValidateFileInfo(FileInfo);
2068
2069 *_FileInfo = FileInfo;
2070 return STATUS_SUCCESS;
2071 } else
2072 if(IndexToOpen) {
2073 if((DirNdx->FileCharacteristics & FILE_DELETED) && NotDeleted) {
2074 AdPrint((" FILE_DELETED on open (2)\n"));
2075 return STATUS_FILE_DELETED;
2076 }
2077 }
2078 FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_FINF_TAG);
2079 *_FileInfo = FileInfo;
2080 if(!FileInfo) return STATUS_INSUFFICIENT_RESOURCES;
2081 RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO));
2082 // init horizontal links
2083 FileInfo->NextLinkedFile =
2084 FileInfo->PrevLinkedFile = FileInfo;
2085 // read FileIdent
2086 FileInfo->FileIdent = (PFILE_IDENT_DESC)MyAllocatePoolTag__(NonPagedPool, DirNdx->Length, MEM_FID_TAG);
2087 if(!(FileInfo->FileIdent)) return STATUS_INSUFFICIENT_RESOURCES;
2088 FileInfo->FileIdentLen = DirNdx->Length;
2089 if(!OS_SUCCESS(status = UDFReadExtent(Vcb, &(DirInfo->Dloc->DataLoc), DirNdx->Offset,
2090 DirNdx->Length, FALSE, (int8*)(FileInfo->FileIdent), &ReadBytes) ))
2091 return status;
2092 if(FileInfo->FileIdent->descTag.tagIdent != TID_FILE_IDENT_DESC) {
2093 BrutePoint();
2094 return STATUS_FILE_CORRUPT_ERROR;
2095 }
2096 // check for opened links
2097 if(!OS_SUCCESS(status = UDFStoreDloc(Vcb, FileInfo, UDFPartLbaToPhys(Vcb, &(FileInfo->FileIdent->icb.extLocation)))))
2098 return status;
2099 // init pointer to parent object
2100 FileInfo->Index = i;
2101 FileInfo->ParentFile = DirInfo;
2102 // init pointers to linked files (if any)
2103 if(FileInfo->Dloc->LinkedFileInfo != FileInfo)
2104 UDFInsertLinkedFile(FileInfo, FileInfo->Dloc->LinkedFileInfo);
2105 if(FileInfo->Dloc->FileEntry)
2106 goto init_tree_entry;
2107 // read (Ex)FileEntry
2108 FileInfo->Dloc->FileEntry = (tag*)MyAllocatePoolTag__(NonPagedPool, Vcb->LBlockSize, MEM_FE_TAG);
2109 if(!(FileInfo->Dloc->FileEntry)) return STATUS_INSUFFICIENT_RESOURCES;
2110 if(!OS_SUCCESS(status = UDFReadFileEntry(Vcb, &(FileInfo->FileIdent->icb), (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &Ident)))
2111 return status;
2112 // build mappings for Data & AllocDescs
2113 if(!FileInfo->Dloc->AllocLoc.Mapping) {
2114 FEExt.extLength = FileInfo->FileIdent->icb.extLength;
2115 FEExt.extLocation = UDFPartLbaToPhys(Vcb, &(FileInfo->FileIdent->icb.extLocation) );
2116 if(FEExt.extLocation == LBA_OUT_OF_EXTENT)
2117 return STATUS_FILE_CORRUPT_ERROR;
2118 FileInfo->Dloc->AllocLoc.Mapping = UDFExtentToMapping(&FEExt);
2119 if(!(FileInfo->Dloc->AllocLoc.Mapping))
2120 return STATUS_INSUFFICIENT_RESOURCES;
2121 }
2122 // read location info
2123 status = UDFLoadExtInfo(Vcb, (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &(FileInfo->FileIdent->icb),
2124 &(FileInfo->Dloc->DataLoc), &(FileInfo->Dloc->AllocLoc) );
2125 if(!OS_SUCCESS(status))
2126 return status;
2127 // init (Ex)FileEntry mapping
2128 FileInfo->Dloc->FELoc.Length = (FileInfo->Dloc->DataLoc.Offset) ? FileInfo->Dloc->DataLoc.Offset :
2129 FileInfo->Dloc->AllocLoc.Offset;
2130 // FileInfo->Dloc->FELoc.Offset = 0;
2131 FileInfo->Dloc->FELoc.Mapping = UDFExtentToMapping(&FEExt);
2132 FileInfo->Dloc->FileEntryLen = (uint32)(FileInfo->Dloc->FELoc.Length);
2133 // we get here immediately when opened link encountered
2134 init_tree_entry:
2135 // init back pointer from parent object
2136 ASSERT(!DirNdx->FileInfo);
2137 DirNdx->FileInfo = FileInfo;
2138 // init DirIndex
2139 if(UDFGetFileLinkCount(FileInfo) > 1) {
2140 DirNdx->FI_Flags |= UDF_FI_FLAG_LINKED;
2141 } else {
2142 DirNdx->FI_Flags &= ~UDF_FI_FLAG_LINKED;
2143 }
2144 // resize FE cache (0x800 instead of 0x40 is not a good idea)
2145 if(!MyReallocPool__((int8*)((FileInfo->Dloc->FileEntry)), Vcb->LBlockSize,
2146 (int8**)&((FileInfo->Dloc->FileEntry)), FileInfo->Dloc->FileEntryLen))
2147 return STATUS_INSUFFICIENT_RESOURCES;
2148 // check if this file has a SDir
2149 if((FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY) &&
2150 ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLength )
2151 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_HAS_SDIR;
2152 if(!(FileInfo->FileIdent->fileCharacteristics & FILE_DIRECTORY)) {
2153 UDFReferenceFile__(FileInfo);
2154 ASSERT(FileInfo->ParentFile == DirInfo);
2155 UDFReleaseDloc(Vcb, FileInfo->Dloc);
2156 return STATUS_SUCCESS;
2157 }
2158
2159 UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used
2160
2161 // build index for directories
2162 if(!FileInfo->Dloc->DirIndex) {
2163 status = UDFIndexDirectory(Vcb, FileInfo);
2164 if(!OS_SUCCESS(status))
2165 return status;
2166 #ifndef UDF_READ_ONLY_BUILD
2167 if((FileInfo->Dloc->DirIndex->DelCount > Vcb->PackDirThreshold) &&
2168 !(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)) {
2169 status = UDFPackDirectory__(Vcb, FileInfo);
2170 if(!OS_SUCCESS(status))
2171 return status;
2172 }
2173 #endif //UDF_READ_ONLY_BUILD
2174 }
2175 UDFReferenceFile__(FileInfo);
2176 UDFReleaseDloc(Vcb, FileInfo->Dloc);
2177 ASSERT(FileInfo->ParentFile == DirInfo);
2178
2179 return status;
2180 } // end UDFOpenFile__()
2181
2182
2183 /*
2184 This routine inits UDF_FILE_INFO structure for root directory
2185 */
2186 OSSTATUS
2187 UDFOpenRootFile__(
2188 IN PVCB Vcb,
2189 IN lb_addr* RootLoc,
2190 OUT PUDF_FILE_INFO FileInfo
2191 )
2192 {
2193 uint32 RootLBA;
2194 OSSTATUS status;
2195 // uint32 PartNum = RootLoc->partitionReferenceNum;
2196 uint32 LBS = Vcb->LBlockSize;
2197 uint16 Ident;
2198 LONG_AD FELoc;
2199 EXTENT_AD FEExt;
2200 uint8 FileType;
2201
2202 RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO));
2203 RootLBA = UDFPartLbaToPhys(Vcb,RootLoc);
2204 if(RootLBA == LBA_OUT_OF_EXTENT)
2205 return STATUS_FILE_CORRUPT_ERROR;
2206 FELoc.extLocation = *RootLoc;
2207 FELoc.extLength = LBS;
2208 // init horizontal links
2209 FileInfo->NextLinkedFile =
2210 FileInfo->PrevLinkedFile = FileInfo;
2211 // check for opened links
2212 if(!OS_SUCCESS(status = UDFStoreDloc(Vcb, FileInfo, RootLBA)))
2213 return status;
2214 if(FileInfo->Dloc->FileEntry)
2215 goto init_tree_entry;
2216 // read (Ex)FileEntry
2217 FileInfo->Dloc->FileEntry = (tag*)MyAllocatePoolTag__(NonPagedPool, LBS, MEM_FE_TAG);
2218 if(!(FileInfo->Dloc->FileEntry)) return STATUS_INSUFFICIENT_RESOURCES;
2219
2220 if(!OS_SUCCESS(status = UDFReadFileEntry(Vcb, &FELoc, (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &Ident)))
2221 return status;
2222 // build mappings for Data & AllocDescs
2223 FEExt.extLength = LBS;
2224 FEExt.extLocation = UDFPartLbaToPhys(Vcb, &(FELoc.extLocation) );
2225 if(FEExt.extLocation == LBA_OUT_OF_EXTENT)
2226 return STATUS_FILE_CORRUPT_ERROR;
2227 FileInfo->Dloc->FELoc.Mapping = UDFExtentToMapping(&FEExt);
2228 if(!(FileInfo->Dloc->FELoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES;
2229 // build mappings for AllocDescs
2230 if(!FileInfo->Dloc->AllocLoc.Mapping) {
2231 FileInfo->Dloc->AllocLoc.Mapping = UDFExtentToMapping(&FEExt);
2232 if(!(FileInfo->Dloc->AllocLoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES;
2233 }
2234 if(!OS_SUCCESS(status = UDFLoadExtInfo(Vcb, (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &FELoc,
2235 &(FileInfo->Dloc->DataLoc), &(FileInfo->Dloc->AllocLoc) ) ))
2236 return status;
2237 FileInfo->Dloc->FileEntryLen = (uint32)
2238 (FileInfo->Dloc->FELoc.Length = (FileInfo->Dloc->DataLoc.Offset) ? FileInfo->Dloc->DataLoc.Offset :
2239 FileInfo->Dloc->AllocLoc.Offset);
2240 init_tree_entry:
2241 // resize FE cache (0x800 instead of 0x40 is not a good idea)
2242 if(!MyReallocPool__((int8*)((FileInfo->Dloc->FileEntry)), LBS,
2243 (int8**)&((FileInfo->Dloc->FileEntry)), FileInfo->Dloc->FileEntryLen))
2244 return STATUS_INSUFFICIENT_RESOURCES;
2245 // init DirIndex
2246 if( (FileType = ((icbtag*)((FileInfo->Dloc->FileEntry)+1))->fileType) != UDF_FILE_TYPE_DIRECTORY &&
2247 (FileType != UDF_FILE_TYPE_STREAMDIR) ) {
2248 UDFReferenceFile__(FileInfo);
2249 UDFReleaseDloc(Vcb, FileInfo->Dloc);
2250 return STATUS_SUCCESS;
2251 }
2252 // build index for directories
2253 if(!FileInfo->Dloc->DirIndex) {
2254 status = UDFIndexDirectory(Vcb, FileInfo);
2255 if(!OS_SUCCESS(status))
2256 return status;
2257 #ifndef UDF_READ_ONLY_BUILD
2258 if((FileInfo->Dloc->DirIndex->DelCount > Vcb->PackDirThreshold) &&
2259 !(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)) {
2260 status = UDFPackDirectory__(Vcb, FileInfo);
2261 if(!OS_SUCCESS(status))
2262 return status;
2263 }
2264 #endif //UDF_READ_ONLY_BUILD
2265 }
2266 UDFReferenceFile__(FileInfo);
2267 UDFReleaseDloc(Vcb, FileInfo->Dloc);
2268
2269 return status;
2270 } // end UDFOpenRootFile__()
2271
2272 /*
2273 This routine frees all memory blocks referenced by given FileInfo
2274 */
2275 uint32
2276 UDFCleanUpFile__(
2277 IN PVCB Vcb,
2278 IN PUDF_FILE_INFO FileInfo
2279 )
2280 {
2281 PUDF_DATALOC_INFO Dloc;
2282 uint32 lc = 0;
2283 BOOLEAN IsASDir;
2284 BOOLEAN KeepDloc;
2285 PDIR_INDEX_ITEM DirNdx, DirNdx2;
2286 BOOLEAN Parallel = FALSE;
2287 BOOLEAN Linked = FALSE;
2288 #ifdef UDF_DBG
2289 BOOLEAN Modified = FALSE;
2290 PDIR_INDEX_HDR hDirNdx;
2291 uint_di Index;
2292 PUDF_FILE_INFO DirInfo;
2293 #endif // UDF_DBG
2294
2295 if(!FileInfo) return UDF_FREE_FILEINFO;
2296
2297 ValidateFileInfo(FileInfo);
2298
2299 if(FileInfo->OpenCount || FileInfo->RefCount) {
2300 UDFPrint(("UDF: not all references are closed\n"));
2301 UDFPrint((" Skipping cleanup\n"));
2302 UDFPrint(("UDF: OpenCount = %x, RefCount = %x, LinkRefCount = %x\n",
2303 FileInfo->OpenCount,FileInfo->RefCount,FileInfo->Dloc->LinkRefCount));
2304 return UDF_FREE_NOTHING;
2305 }
2306 if(FileInfo->Fcb) {
2307 UDFPrint(("Operating System still has references to this file\n"));
2308 UDFPrint((" Skipping cleanup\n"));
2309 // BrutePoint();
2310 return UDF_FREE_NOTHING;
2311 }
2312
2313 IsASDir = UDFIsAStreamDir(FileInfo);
2314
2315 if((Dloc = FileInfo->Dloc)) {
2316
2317 #ifdef UDF_DBG
2318 DirInfo = FileInfo->ParentFile;
2319 if(DirInfo) {
2320 hDirNdx = DirInfo->Dloc->DirIndex;
2321 Index = FileInfo->Index;
2322 // we can't delete modified file
2323 // it should be closed & reopened (or flushed) before deletion
2324 DirNdx = UDFDirIndex(hDirNdx,Index);
2325 UDFPrint(("Cleanup Mod: %s%s%s%s%s%s\n",
2326 (Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) ? "FE " : "",
2327 (Dloc->DataLoc.Modified) ? "DataLoc " : "",
2328 (Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) ? "Data-PreAlloc " : "",
2329 (Dloc->AllocLoc.Modified) ? "AllocLoc " : "",
2330 (Dloc->FELoc.Modified) ? "FELoc " : "",
2331 (DirNdx && (DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) ? "FI " : ""
2332 ));
2333 Modified = ((Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) ||
2334 Dloc->DataLoc.Modified ||
2335 (Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) ||
2336 Dloc->AllocLoc.Modified ||
2337 Dloc->FELoc.Modified ||
2338 (DirNdx && (DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) );
2339 }
2340 #endif // UDF_DBG
2341
2342 PUDF_FILE_INFO ParFileInfo = UDFLocateAnyParallelFI(FileInfo);
2343
2344 Parallel = (ParFileInfo != NULL);
2345 Linked = (FileInfo->NextLinkedFile != FileInfo);
2346
2347 // Parallel = (FileInfo->NextLinkedFile != FileInfo);
2348 ASSERT(FileInfo->NextLinkedFile);
2349 // ASSERT(!Parallel);
2350 KeepDloc = (Dloc->LinkRefCount ||
2351 Dloc->CommonFcb ||
2352 Linked ) ?
2353 TRUE : FALSE;
2354
2355 if(Dloc->DirIndex) {
2356 uint_di i;
2357 for(i=2; (DirNdx = UDFDirIndex(Dloc->DirIndex,i)); i++) {
2358 if(DirNdx->FileInfo) {
2359 if(!KeepDloc) {
2360 BrutePoint();
2361 UDFPrint(("UDF: Found not cleaned up reference.\n"));
2362 UDFPrint((" Skipping cleanup (1)\n"));
2363 // BrutePoint();
2364 return UDF_FREE_NOTHING;
2365 }
2366 // The file being cleaned up may have not closed Dirs
2367 // (linked Dir). In this case each of them may have
2368 // reference to FileInfo in DirIndex[1]
2369 // Here we'll check it and change for valid value if
2370 // necessary (Update Child Objects - I)
2371 if(DirNdx->FileInfo->Dloc) {
2372 // we can get here only when (Parallel == TRUE)
2373 DirNdx2 = UDFDirIndex(DirNdx->FileInfo->Dloc->DirIndex, 1);
2374 // It is enough to check DirNdx2->FileInfo only.
2375 // If one of Parallel FI's has reference (and equal)
2376 // to the FI being removed, it'll be removed from
2377 // the chain & nothing wrong will happen.
2378 if(DirNdx2 && (DirNdx2->FileInfo == FileInfo)) {
2379 if(FileInfo->PrevLinkedFile == FileInfo) {
2380 BrutePoint();
2381 DirNdx2->FileInfo = NULL;
2382 } else {
2383 DirNdx2->FileInfo = Parallel ?
2384 ParFileInfo : FileInfo->PrevLinkedFile;
2385 }
2386 ASSERT(!DirNdx2->FileInfo->RefCount);
2387 }
2388 }
2389 }
2390 }
2391 }
2392 if(Dloc->SDirInfo) {
2393 UDFPrint(("UDF: Found not cleaned up reference (SDir).\n"));
2394
2395 // (Update Child Objects - II)
2396 if(Dloc->SDirInfo->ParentFile == FileInfo) {
2397 BrutePoint();
2398 ASSERT(ParFileInfo);
2399 Dloc->SDirInfo->ParentFile = ParFileInfo;
2400 }
2401 // We should break Cleanup process if alive reference detected
2402 // and there is no possibility to store pointer in some other
2403 // place (in parallel object)
2404 if(!KeepDloc) {
2405 BrutePoint();
2406 UDFPrint((" Skipping cleanup\n"));
2407 return UDF_FREE_NOTHING;
2408 }
2409
2410 if(!UDFIsSDirDeleted(Dloc->SDirInfo) &&
2411 Dloc->SDirInfo->Dloc) {
2412 DirNdx2 = UDFDirIndex(Dloc->SDirInfo->Dloc->DirIndex, 1);
2413 if(DirNdx2 && (DirNdx2->FileInfo == FileInfo)) {
2414 DirNdx2->FileInfo =
2415 Parallel ? ParFileInfo : NULL;
2416 ASSERT(!DirNdx2->FileInfo->RefCount);
2417 }
2418 }
2419 }
2420
2421 if(!KeepDloc) {
2422
2423 #ifdef UDF_DBG
2424 ASSERT(!Modified);
2425 #endif
2426
2427 #ifndef UDF_TRACK_ONDISK_ALLOCATION
2428 if(Dloc->DataLoc.Mapping) MyFreePool__(Dloc->DataLoc.Mapping);
2429 if(Dloc->AllocLoc.Mapping) MyFreePool__(Dloc->AllocLoc.Mapping);
2430 if(Dloc->FELoc.Mapping) MyFreePool__(Dloc->FELoc.Mapping);
2431 if(Dloc->FileEntry) {
2432 // plain file
2433 lc = UDFGetFileLinkCount(FileInfo);
2434 MyFreePool__(Dloc->FileEntry);
2435 Dloc->FileEntry = NULL;
2436 } else if(FileInfo->Index >= 2) {
2437 // error durring open operation
2438 lc = UDF_INVALID_LINK_COUNT;
2439 }
2440 #endif //UDF_TRACK_ONDISK_ALLOCATION
2441 if(FileInfo->Dloc->DirIndex) {
2442 uint_di i;
2443 for(i=2; (DirNdx = UDFDirIndex(Dloc->DirIndex,i)); i++) {
2444 ASSERT(!DirNdx->FileInfo);
2445 if(DirNdx->FName.Buffer)
2446 MyFreePool__(DirNdx->FName.Buffer);
2447 }
2448 // The only place where we can free FE_Charge extent is here
2449 UDFFlushFESpace(Vcb, Dloc);
2450 UDFDirIndexFree(Dloc->DirIndex);
2451 Dloc->DirIndex = NULL;
2452 #ifdef UDF_TRACK_ONDISK_ALLOCATION
2453 UDFIndexDirectory(Vcb, FileInfo);
2454 if(FileInfo->Dloc->DirIndex) {
2455 for(i=2; DirNdx = UDFDirIndex(Dloc->DirIndex,i); i++) {
2456 ASSERT(!DirNdx->FileInfo);
2457 if(DirNdx->FName.Buffer)
2458 MyFreePool__(DirNdx->FName.Buffer);
2459 }
2460 UDFDirIndexFree(Dloc->DirIndex);
2461 Dloc->DirIndex = NULL;
2462 }
2463 #endif //UDF_TRACK_ONDISK_ALLOCATION
2464 }
2465
2466 #ifdef UDF_TRACK_ONDISK_ALLOCATION
2467 if(Dloc->AllocLoc.Mapping) MyFreePool__(Dloc->AllocLoc.Mapping);
2468 if(Dloc->FELoc.Mapping) MyFreePool__(Dloc->FELoc.Mapping);
2469 if(Dloc->FileEntry) {
2470 // plain file
2471 lc = UDFGetFileLinkCount(FileInfo);
2472 MyFreePool__(Dloc->FileEntry);
2473 Dloc->FileEntry = NULL;
2474 } else if(FileInfo->Index >= 2) {
2475 // error durring open operation
2476 lc = UDF_INVALID_LINK_COUNT;
2477 }
2478 if(Dloc->DataLoc.Mapping) {
2479 if(lc && (lc != UDF_INVALID_LINK_COUNT)) {
2480 UDFCheckSpaceAllocation(Vcb, 0, Dloc->DataLoc.Mapping, AS_USED); // check if used
2481 } else {
2482 UDFCheckSpaceAllocation(Vcb, 0, Dloc->DataLoc.Mapping, AS_FREE); // check if free
2483 }
2484 MyFreePool__(Dloc->DataLoc.Mapping);
2485 }
2486 #endif //UDF_TRACK_ONDISK_ALLOCATION
2487
2488 if(lc && (lc != UDF_INVALID_LINK_COUNT)) {
2489 UDFRemoveDloc(Vcb, Dloc);
2490 } else {
2491 UDFFreeDloc(Vcb, Dloc);
2492 }
2493 } else // KeepDloc cannot be FALSE if (Linked == TRUE)
2494 if(Linked) {
2495 // BrutePoint();
2496 // Update pointers in ParentObject (if any)
2497 if(FileInfo->ParentFile->Dloc->SDirInfo == FileInfo)
2498 FileInfo->ParentFile->Dloc->SDirInfo = FileInfo->PrevLinkedFile;
2499 DirNdx = UDFDirIndex(FileInfo->Dloc->DirIndex, 0);
2500 if(DirNdx && (DirNdx->FileInfo == FileInfo))
2501 DirNdx->FileInfo = FileInfo->PrevLinkedFile;
2502 DirNdx = UDFDirIndex(FileInfo->ParentFile->Dloc->DirIndex, FileInfo->Index);
2503 if(DirNdx && (DirNdx->FileInfo == FileInfo))
2504 DirNdx->FileInfo = ParFileInfo;
2505 // remove from linked chain
2506 FileInfo->NextLinkedFile->PrevLinkedFile = FileInfo->PrevLinkedFile;
2507 FileInfo->PrevLinkedFile->NextLinkedFile = FileInfo->NextLinkedFile;
2508 // update pointer in Dloc
2509 if(FileInfo->Dloc->LinkedFileInfo == FileInfo)
2510 FileInfo->Dloc->LinkedFileInfo = FileInfo->PrevLinkedFile;
2511 }
2512 FileInfo->Dloc = NULL;
2513 } else {
2514 KeepDloc = FALSE;
2515 }
2516
2517 // Cleanup pointers in ParentObject (if any)
2518 if(IsASDir) {
2519 if(FileInfo->ParentFile->Dloc->SDirInfo == FileInfo) {
2520 ASSERT(!Linked);
2521 FileInfo->ParentFile->Dloc->SDirInfo = NULL;
2522 FileInfo->ParentFile->Dloc->FE_Flags &= ~UDF_FE_FLAG_HAS_DEL_SDIR;
2523 }
2524 } else
2525 if(FileInfo->ParentFile) {
2526 ASSERT(FileInfo->ParentFile->Dloc);
2527 DirNdx = UDFDirIndex(FileInfo->ParentFile->Dloc->DirIndex, FileInfo->Index);
2528 ASSERT(DirNdx);
2529 #ifdef UDF_DBG
2530 PUDF_FILE_INFO OldFI;
2531 if(Parallel) {
2532 ASSERT(!DirNdx || !(OldFI = DirNdx->FileInfo) ||
2533 !(OldFI == FileInfo));
2534 } else {
2535 ASSERT(!DirNdx || !(OldFI = DirNdx->FileInfo) ||
2536 (OldFI == FileInfo));
2537 }
2538 #endif
2539 if( DirNdx && (DirNdx->FileInfo == FileInfo) ) {
2540 if(!Parallel)
2541 DirNdx->FileInfo = NULL;
2542 #ifdef UDF_DBG
2543 } else {
2544 // We can get here after incomplete Open
2545 if(!Parallel && DirNdx->FileInfo)
2546 BrutePoint();
2547 #endif
2548 }
2549 #ifdef UDF_DBG
2550 } else {
2551 // BrutePoint();
2552 #endif
2553 }
2554
2555 if(!Parallel && FileInfo->FileIdent)
2556 MyFreePool__(FileInfo->FileIdent);
2557 FileInfo->FileIdent = NULL;
2558 // Kill reference to parent object
2559 FileInfo->ParentFile = NULL;
2560 // Kill references to parallel object(s) since it has no reference to
2561 // this one now
2562 FileInfo->NextLinkedFile =
2563 FileInfo->PrevLinkedFile = FileInfo;
2564 if(FileInfo->ListPtr)
2565 FileInfo->ListPtr->FileInfo = NULL;;
2566 return KeepDloc ? UDF_FREE_FILEINFO : (UDF_FREE_FILEINFO | UDF_FREE_DLOC);
2567 } // end UDFCleanUpFile__()
2568
2569 #ifndef UDF_READ_ONLY_BUILD
2570 /*
2571 This routine creates FileIdent record in destination directory &
2572 allocates FileEntry with in-ICB zero-sized data
2573 If it returns status != STATUS_SUCCESS caller should call UDFCleanUpFile__
2574 for returned pointer *WITHOUT* using UDFCloseFile__
2575 */
2576 OSSTATUS
2577 UDFCreateFile__(
2578 IN PVCB Vcb,
2579 // IN uint16 AllocMode, // short/long/ext/in-icb // always in-ICB
2580 IN BOOLEAN IgnoreCase,
2581 IN PUNICODE_STRING _fn,
2582 IN uint32 ExtAttrSz,
2583 IN uint32 ImpUseLen,
2584 IN BOOLEAN Extended,
2585 IN BOOLEAN CreateNew,
2586 IN OUT PUDF_FILE_INFO DirInfo,
2587 OUT PUDF_FILE_INFO* _FileInfo
2588 )
2589 {
2590 uint32 l, d;
2591 uint_di i, j;
2592 OSSTATUS status;
2593 LONG_AD FEicb;
2594 UDF_DIR_SCAN_CONTEXT ScanContext;
2595 PDIR_INDEX_HDR hDirNdx = DirInfo->Dloc->DirIndex;
2596 PDIR_INDEX_ITEM DirNdx;
2597 uint32 LBS = Vcb->LBlockSize;
2598 PUDF_FILE_INFO FileInfo;
2599 *_FileInfo = NULL;
2600 BOOLEAN undel = FALSE;
2601 SIZE_T ReadBytes;
2602 // BOOLEAN PackDir = FALSE;
2603 BOOLEAN FEAllocated = FALSE;
2604
2605 ValidateFileInfo(DirInfo);
2606 *_FileInfo = NULL;
2607
2608 ASSERT(DirInfo->Dloc->FELoc.Mapping[0].extLocation);
2609 uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, DirInfo->Dloc->FELoc.Mapping[0].extLocation);
2610 if(!hDirNdx) return STATUS_NOT_A_DIRECTORY;
2611 i = 0;
2612
2613 _SEH2_TRY {
2614
2615 // check if exists
2616 status = UDFFindFile(Vcb, IgnoreCase, FALSE, _fn, DirInfo, &i);
2617 DirNdx = UDFDirIndex(hDirNdx,i);
2618 if(OS_SUCCESS(status)) {
2619 // file is a Cur(Parent)Dir
2620 if(i<2) try_return (status = STATUS_ACCESS_DENIED);
2621 // file deleted
2622 if(UDFIsDeleted(DirNdx)) {
2623 j=0;
2624 if(OS_SUCCESS(UDFFindFile(Vcb, IgnoreCase, TRUE, _fn, DirInfo, &j))) {
2625 i=j;
2626 DirNdx = UDFDirIndex(hDirNdx,i);
2627 goto CreateBothFound;
2628 }
2629 // we needn't allocating new FileIdent inside Dir stream
2630 // perform 'undel'
2631 if(DirNdx->FileInfo) {
2632 // BrutePoint();
2633 status = UDFPretendFileDeleted__(Vcb, DirNdx->FileInfo);
2634 if(!OS_SUCCESS(status))
2635 try_return (status = STATUS_FILE_DELETED);
2636 } else {
2637 undel = TRUE;
2638 }
2639 // BrutePoint();
2640 goto CreateUndel;
2641 }
2642 CreateBothFound:
2643 // file already exists
2644 if(CreateNew) try_return (status = STATUS_ACCESS_DENIED);
2645 // try to open it
2646 BrutePoint();
2647 status = UDFOpenFile__(Vcb, IgnoreCase, TRUE, _fn, DirInfo, _FileInfo,&i);
2648 // *_FileInfo = FileInfo; // OpenFile__ has already done it, so update it...
2649 DirNdx = UDFDirIndex(hDirNdx,i);
2650 DirNdx->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR;
2651 FileInfo = *_FileInfo;
2652 if(!OS_SUCCESS(status)) {
2653 // :(( can't open....
2654 if(FileInfo && UDFCleanUpFile__(Vcb, FileInfo)) {
2655 MyFreePool__(FileInfo);
2656 *_FileInfo = NULL;
2657 }
2658 BrutePoint();
2659 try_return (status);
2660 }
2661 // check if we can delete this file
2662 if(FileInfo->OpenCount || (FileInfo->RefCount > 1)) {
2663 BrutePoint();
2664 UDFCloseFile__(Vcb, FileInfo);
2665 try_return (status = STATUS_CANNOT_DELETE);
2666 }
2667 BrutePoint();
2668 // remove DIRECTORY flag
2669 DirNdx->FileCharacteristics &= ~FILE_DIRECTORY;
2670 FileInfo->FileIdent->fileCharacteristics &= ~FILE_DIRECTORY;
2671 DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
2672 // truncate file size to ZERO
2673 status = UDFResizeFile__(Vcb, FileInfo, 0);
2674 if(!OS_SUCCESS(status)) {
2675 BrutePoint();
2676 UDFCloseFile__(Vcb, FileInfo);
2677 }
2678 // set NORMAL flag
2679 FileInfo->FileIdent->fileCharacteristics = 0;
2680 DirNdx->FileCharacteristics = 0;
2681 // update DeletedFiles counter in Directory... (for PackDir)
2682 if(undel && OS_SUCCESS(status))
2683 hDirNdx->DelCount--;
2684 try_return (status);
2685 }
2686
2687 CreateUndel:
2688
2689 // allocate FileInfo
2690 FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_FE_TAG);
2691 *_FileInfo = FileInfo;
2692 if(!FileInfo)
2693 try_return (status = STATUS_INSUFFICIENT_RESOURCES);
2694 ImpUseLen = (ImpUseLen + 3) & ~((uint16)3);
2695
2696 RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO));
2697 // init horizontal links
2698 FileInfo->NextLinkedFile =
2699 FileInfo->PrevLinkedFile = FileInfo;
2700 // allocate space for FileEntry
2701 if(!OS_SUCCESS(status =
2702 UDFBuildFileEntry(Vcb, DirInfo, FileInfo, PartNum, ICB_FLAG_AD_IN_ICB, ExtAttrSz, Extended) )) {
2703 BrutePoint();
2704 try_return (status);
2705 }
2706 FEAllocated = TRUE;
2707 FEicb.extLength = LBS;
2708 ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
2709 FEicb.extLocation.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
2710 FEicb.extLocation.partitionReferenceNum = (uint16)PartNum;
2711 RtlZeroMemory(&(FEicb.impUse), sizeof(FEicb.impUse));
2712
2713 if(!undel) {
2714 // build FileIdent
2715 if(!OS_SUCCESS(status =
2716 UDFBuildFileIdent(Vcb, _fn, &FEicb, ImpUseLen,
2717 &(FileInfo->FileIdent), &(FileInfo->FileIdentLen)) ))
2718 try_return (status);
2719 } else {
2720 // read FileIdent
2721 FileInfo->FileIdent = (PFILE_IDENT_DESC)MyAllocatePoolTag__(NonPagedPool, DirNdx->Length, MEM_FID_TAG);
2722 if(!(FileInfo->FileIdent)) try_return (status = STATUS_INSUFFICIENT_RESOURCES);
2723 FileInfo->FileIdentLen = DirNdx->Length;
2724 if(!OS_SUCCESS(status = UDFReadExtent(Vcb, &(DirInfo->Dloc->DataLoc), DirNdx->Offset,
2725 DirNdx->Length, FALSE, (int8*)(FileInfo->FileIdent), &ReadBytes) ))
2726 try_return (status);
2727 FileInfo->FileIdent->fileCharacteristics = 0;
2728 FileInfo->FileIdent->icb = FEicb;
2729 ImpUseLen = FileInfo->FileIdent->lengthOfImpUse;
2730 DirNdx->FileCharacteristics = 0;
2731 }
2732 // init 'parentICBLocation' & so on in FE
2733 ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum =
2734 UDFPhysLbaToPart(Vcb, PartNum, DirInfo->Dloc->FELoc.Mapping[0].extLocation);
2735 ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum = (uint16)PartNum;
2736 // ((icbtag*)(FileInfo->Dloc->FileEntry+1))->strategyType = 4;
2737 // ((icbtag*)(FileInfo->Dloc->FileEntry+1))->numEntries = 1;
2738 // try to find suitable unused FileIdent in DirIndex
2739 l = FileInfo->FileIdentLen;
2740 if(undel) goto CrF__2;
2741 #ifndef UDF_LIMIT_DIR_SIZE
2742 if(Vcb->CDR_Mode) {
2743 #endif // UDF_LIMIT_DIR_SIZE
2744 // search for suitable unused entry
2745 if(UDFDirIndexInitScan(DirInfo, &ScanContext, 2)) {
2746 while((DirNdx = UDFDirIndexScan(&ScanContext, NULL))) {
2747 if((DirNdx->Length == l) && UDFIsDeleted(DirNdx) &&
2748 !DirNdx->FileInfo ) {
2749 // free unicode-buffer with old name
2750 if(DirNdx->FName.Buffer) {
2751 MyFreePool__(DirNdx->FName.Buffer);
2752 DirNdx->FName.Buffer = NULL;
2753 }
2754 i = ScanContext.i;
2755 goto CrF__1;
2756 }
2757 }
2758 }
2759 #ifndef UDF_LIMIT_DIR_SIZE
2760 } else {
2761 #endif // UDF_LIMIT_DIR_SIZE
2762 i = UDFDirIndexGetLastIndex(hDirNdx); // 'i' points beyond EO DirIndex
2763 #ifndef UDF_LIMIT_DIR_SIZE
2764 }
2765 #endif // UDF_LIMIT_DIR_SIZE
2766
2767 // append entry
2768 if(!OS_SUCCESS(status = UDFDirIndexGrow(&(DirInfo->Dloc->DirIndex), 1))) {
2769 try_return (status);
2770 }
2771
2772 // init offset of new FileIdent in directory Data extent
2773 hDirNdx = DirInfo->Dloc->DirIndex;
2774 if(i-1) {
2775 DirNdx = UDFDirIndex(hDirNdx,i-1);
2776 UDFDirIndex(hDirNdx,i)->Offset = DirNdx->Offset + DirNdx->Length;
2777 DirNdx = UDFDirIndex(hDirNdx,i);
2778 } else {
2779 DirNdx = UDFDirIndex(hDirNdx,i);
2780 DirNdx->Offset = 0;
2781 }
2782 // new terminator is recorded by UDFDirIndexGrow()
2783 if( ((d = ((LBS - (DirNdx->Offset + l + DirInfo->Dloc->DataLoc.Offset)) & (LBS-1) )) < sizeof(FILE_IDENT_DESC)) &&
2784 d ) {
2785 // insufficient space at the end of last sector for
2786 // next FileIdent's tag. fill it with ImpUse data
2787
2788 // generally, all data should be DWORD-aligned, but if it is not so
2789 // this opearation will help us to avoid glitches
2790 d = (d+3) & ~((uint32)3);
2791
2792 uint32 IUl, FIl;
2793 if(!MyReallocPool__((int8*)(FileInfo->FileIdent), l,
2794 (int8**)&(FileInfo->FileIdent), (l+d+3) & ~((uint32)(3)) ))
2795 try_return (status = STATUS_INSUFFICIENT_RESOURCES);
2796 l += d;
2797 IUl = FileInfo->FileIdent->lengthOfImpUse;
2798 FIl = FileInfo->FileIdent->lengthFileIdent;
2799 // move filename to higher addr
2800 RtlMoveMemory(((int8*)(FileInfo->FileIdent+1))+IUl+d,
2801 ((int8*)(FileInfo->FileIdent+1))+IUl, FIl);
2802 RtlZeroMemory(((int8*)(FileInfo->FileIdent+1))+IUl, d);
2803 FileInfo->FileIdent->lengthOfImpUse += (uint16)d;
2804 FileInfo->FileIdentLen = l;
2805 }
2806 DirNdx->Length = l;
2807 CrF__1:
2808 // clone unicode string
2809 // it **<<MUST>>** be allocated with internal memory manager
2810 DirNdx->FName.Buffer = (PWCHAR)MyAllocatePoolTag__(UDF_FILENAME_MT, (DirNdx->FName.MaximumLength = _fn->Length + sizeof(WCHAR)), MEM_FNAMECPY_TAG);
2811 DirNdx->FName.Length = _fn->Length;
2812 if(!DirNdx->FName.Buffer)
2813 try_return (status = STATUS_INSUFFICIENT_RESOURCES);
2814 RtlCopyMemory(DirNdx->FName.Buffer, _fn->Buffer, _fn->Length);
2815 DirNdx->FName.Buffer[_fn->Length/sizeof(WCHAR)] = 0;
2816 CrF__2:
2817 DirNdx->FI_Flags |= UDFBuildHashEntry(Vcb, &(DirNdx->FName), &(DirNdx->hashes), HASH_ALL);
2818 // we get here immediately when 'undel' occured
2819 FileInfo->Index = i;
2820 DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED;
2821 DirNdx->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR;
2822 ASSERT(!DirNdx->FileInfo);
2823 DirNdx->FileInfo = FileInfo;
2824 DirNdx->FileEntryLoc = FEicb.extLocation;
2825 // mark file as 'deleted' for now
2826 DirNdx->FileCharacteristics = FILE_DELETED;
2827 FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED;
2828 FileInfo->Dloc->DataLoc.Mapping = UDFExtentToMapping(&(FileInfo->Dloc->FELoc.Mapping[0]));
2829 if(!(FileInfo->Dloc->DataLoc.Mapping)) {
2830 UDFFlushFI(Vcb, FileInfo, PartNum);
2831 try_return (status = STATUS_INSUFFICIENT_RESOURCES);
2832 }
2833 FileInfo->Dloc->DataLoc.Length = 0;
2834 FileInfo->Dloc->DataLoc.Offset = FileInfo->Dloc->FileEntryLen;
2835 FileInfo->ParentFile = DirInfo;
2836 // init FileEntry
2837 UDFSetFileUID(Vcb, FileInfo);
2838 UDFSetFileSize(FileInfo, 0);
2839 UDFIncFileLinkCount(FileInfo); // increase to 1
2840 UDFUpdateCreateTime(Vcb, FileInfo);
2841 UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index),
2842 FileInfo->Dloc->FileEntry, Vcb->DefaultAttr);
2843 FileInfo->Dloc->DataLoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK;
2844 FileInfo->Dloc->DataLoc.Modified = TRUE;
2845 FileInfo->Dloc->FELoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK;
2846 // zero sector for FileEntry
2847 if(!Vcb->CDR_Mode) {
2848 status = UDFWriteData(Vcb, TRUE, ((int64)(FileInfo->Dloc->FELoc.Mapping[0].extLocation)) << Vcb->BlockSizeBits, LBS, FALSE, Vcb->ZBuffer, &ReadBytes);
2849 if(!OS_SUCCESS(status)) {
2850 UDFFlushFI(Vcb, FileInfo, PartNum);
2851 try_return (status);
2852 }
2853 }
2854 #if 0
2855 if((i >= 2) && (DirNdx->FName.Buffer[0] == L'.')) {
2856 BrutePoint();
2857 }
2858 #endif
2859
2860 #ifdef UDF_CHECK_DISK_ALLOCATION
2861 if( /*FileInfo->Fcb &&*/
2862 UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) {
2863
2864 if(!FileInfo->FileIdent ||
2865 !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED)) {
2866 AdPrint(("Flushing to Discarded block %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation));
2867 BrutePoint();
2868 }
2869 }
2870 #endif // UDF_CHECK_DISK_ALLOCATION
2871
2872 // make FileIdent valid
2873 FileInfo->FileIdent->fileCharacteristics = 0;
2874 DirNdx->FileCharacteristics = 0;
2875 UDFReferenceFile__(FileInfo);
2876 UDFFlushFE(Vcb, FileInfo, PartNum);
2877 if(undel)
2878 hDirNdx->DelCount--;
2879 UDFReleaseDloc(Vcb, FileInfo->Dloc);
2880 UDFIncFileCounter(Vcb);
2881
2882 UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used
2883