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