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