ReactOS 0.4.15-dev-5895-g2687c1b
udf_info.cpp
Go to the documentation of this file.
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.
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_
22static 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++
41static const char valid_char_arr[] = {"*/:?\"<>|\\"};
42#endif // _X86_
43
44#define DOS_CRC_MODULUS 41
45#define hexChar crcChar
46static const char crcChar[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ#_~-@";
47
48/* Used to convert hex digits to ASCII for readability. */
49//static const char hexChar[] = "0123456789ABCDEF";
50
51static 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
86static 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
145UDFMemRealloc(
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 */
168void
171 IN OUT PUNICODE_STRING UName,
172 IN uint8* CS0,
174 OUT uint16* valueCRC
175 )
176{
177 uint16 compID = CS0[0];
178 uint32 unicodeIndex = 0;
179 uint32 byteIndex = 1;
180 PWCHAR buff;
181 uint8* _CS0 = CS0+1;
182
183 if(!Length) goto return_empty_str;
184 // First check for valid compID.
185 switch(compID) {
186 case UDF_COMP_ID_8: {
187
189 if(!buff) goto return_empty_str;
190 UName->Buffer = buff;
191
192 // Loop through all the bytes.
193 while (byteIndex < Length) {
194 (*buff) = (*_CS0);
195 _CS0++;
196 byteIndex++;
197 buff++;
198 }
199 unicodeIndex = byteIndex-1;
200 break;
201 }
202 case UDF_COMP_ID_16: {
203
205 if(!buff) goto return_empty_str;
206 UName->Buffer = buff;
207
208 // Loop through all the bytes.
209 while (byteIndex < Length) {
210 // Move the first byte to the high bits of the unicode char.
211 *buff = ((*_CS0) << 8) | (*(_CS0+1));
212 _CS0+=2;
213 byteIndex+=2;
214 unicodeIndex++;
215 buff++;
216 ASSERT(byteIndex <= Length);
217 }
218 break;
219 }
220 default: {
221return_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 */
238void
241 IN PUNICODE_STRING UName,
242 IN OUT uint8** _CS0,
244 )
245{
246 uint8* CS0;
247 uint8 compID;
248 uint16 unicodeIndex;
249 uint32 i, len;
250 PWCHAR Buff;
251
252 len = (UName->Length) / sizeof(WCHAR);
253 compID = (!len) ? 0 : UDF_COMP_ID_8;
254 // check for uncompressable characters
255 Buff = UName->Buffer;
256 for(i=0; i<len; i++, Buff++) {
257 if((*Buff) & 0xff00) {
258 compID = UDF_COMP_ID_16;
259 break;
260 }
261 }
262
263 CS0 = (uint8*)MyAllocatePool__(NonPagedPool, *Length = (((compID==UDF_COMP_ID_8) ? 1 : 2)*len + 1) );
264 if(!CS0) return;
265
266 CS0[0] = compID;
267 *_CS0 = CS0;
268 // init loop
269 CS0++;
270 unicodeIndex = 0;
271 Buff = UName->Buffer;
272 if(compID == UDF_COMP_ID_16) {
273 // Loop through all the bytes.
274 while (unicodeIndex < len) {
275 // Move the 2nd byte to the low bits of the compressed unicode char.
276 *CS0 = (uint8)((*Buff) >> 8);
277 CS0++;
278 *CS0 = (uint8)(*Buff);
279 CS0++;
280 Buff++;
281 unicodeIndex++;
282 }
283 } else {
284 // Loop through all the bytes.
285 while (unicodeIndex < len) {
286 *CS0 = (uint8)(*Buff);
287 CS0++;
288 Buff++;
289 unicodeIndex++;
290 }
291 }
292} // end UDFCompressUnicode()
293
294/*
295OSSTATUS 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 */
307 IN PVCB Vcb,
308 IN long_ad* Icb,
309 IN OUT PFILE_ENTRY FileEntry, // here we can also get ExtendedFileEntry
310 IN OUT uint16* Ident
311 )
312{
314
315 if(!OS_SUCCESS(status = UDFReadTagged(Vcb, (int8*)FileEntry,
316 UDFPartLbaToPhys(Vcb,&(Icb->extLocation)),
317 Icb->extLocation.logicalBlockNum,
318 Ident))) return status;
319 if((FileEntry->descTag.tagIdent != TID_FILE_ENTRY) &&
320 (FileEntry->descTag.tagIdent != TID_EXTENDED_FILE_ENTRY)) {
321 UDFPrint((" Not a FileEntry (lbn=%x, tag=%x)\n", Icb->extLocation.logicalBlockNum, FileEntry->descTag.tagIdent));
323 }
324 return STATUS_SUCCESS;
325} // UDFReadFileEntry()
326
327#if !defined (_X86_) || !defined (_MSC_VER)
328/*
329 Decides if a Unicode character matches one of a list
330 of ASCII characters.
331 Used by DOS version of UDFIsIllegalChar for readability, since all of the
332 illegal characters above 0x0020 are in the ASCII subset of Unicode.
333 Works very similarly to the standard C function strchr().
334 */
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_
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
388ERR_IIC:
389 mov al,1
390ERR_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
425void
428 IN PVCB Vcb,
430 IN PUNICODE_STRING UdfName,
431 IN BOOLEAN KeepIntact
432 )
433{
434#ifndef _CONSOLE
435 if(Vcb->CompatFlags & UDF_VCB_IC_OS_NATIVE_DOS_NAME) {
436 UDFDOSNameOsNative(DosName, UdfName, KeepIntact);
437 return;
438 }
439#endif //_CONSOLE
440
441 switch(Vcb->CurrentUDFRev) {
442 case 0x0100:
443 case 0x0101:
444 case 0x0102:
445 UDFDOSName100(DosName, UdfName, KeepIntact);
446 break;
447
448 case 0x0150:
449 // in general, we need bytes-from-media to
450 // create valid UDF 1.50 name.
451 // Curently it is impossible, thus, we'll use
452 // UDF 2.00 translation algorithm
453 case 0x0200:
454 UDFDOSName200(DosName, UdfName, KeepIntact, Vcb->CurrentUDFRev == 0x0150);
455 break;
456
457 case 0x0201:
458 default:
459 UDFDOSName201(DosName, UdfName, KeepIntact);
460 }
461}
462
463void
467 IN PUNICODE_STRING UdfName,
468 IN BOOLEAN KeepIntact
469 )
470{
471 PWCHAR dosName = DosName->Buffer;
472 PWCHAR udfName = UdfName->Buffer;
473 uint32 udfLen = UdfName->Length / sizeof(WCHAR);
474
475 uint32 index, dosIndex = 0, extIndex = 0, lastPeriodIndex;
476 BOOLEAN needsCRC = FALSE, hasExt = FALSE, writingExt = FALSE, isParent = FALSE;
477 uint32 valueCRC;
479
480 if(KeepIntact &&
481 (udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) {
482 isParent = TRUE;
483 if((udfLen == 2) && (udfName[1] != UNICODE_PERIOD))
484 isParent = FALSE;
485 }
486
487 for (index = 0 ; index < udfLen ; index++) {
488 current = udfName[index];
489 if (current == UNICODE_PERIOD && !isParent) {
490 if (dosIndex==0 || hasExt) {
491 // Ignore leading periods or any other than used for extension.
492 needsCRC = TRUE;
493 } else {
494 // First, find last character which is NOT a period or space.
495 lastPeriodIndex = udfLen - 1;
496 while(lastPeriodIndex >=0 &&
497 (udfName[lastPeriodIndex] == UNICODE_PERIOD ||
498 udfName[lastPeriodIndex] == UNICODE_SPACE))
499 lastPeriodIndex--;
500 // Now search for last remaining period.
501 while(lastPeriodIndex >= 0 &&
502 udfName[lastPeriodIndex] != UNICODE_PERIOD)
503 lastPeriodIndex--;
504 // See if the period we found was the last or not.
505 if (lastPeriodIndex != index)
506 needsCRC = TRUE; // If not, name needs translation.
507 // As long as the period was not trailing,
508 // the file name has an extension.
509 if (lastPeriodIndex >= 0) hasExt = TRUE;
510 }
511 } else {
512 if ((!hasExt && dosIndex == DOS_NAME_LEN) ||
513 extIndex == DOS_EXT_LEN) {
514 // File name or extension is too long for DOS.
515 needsCRC = TRUE;
516 } else {
517 if (current == UNICODE_SPACE) { // Ignore spaces.
518 needsCRC = TRUE;
519 } else {
520 // Look for illegal or unprintable characters.
521 if (UDFIsIllegalChar(current) /*|| !UnicodeIsPrint(current)*/) {
522 needsCRC = TRUE;
524 /* Skip Illegal characters(even spaces),
525 * but not periods.
526 */
527 while(index+1 < udfLen &&
528 (UDFIsIllegalChar(udfName[index+1]) /*||
529 !UnicodeIsPrint(udfName[index+1])*/) &&
530 udfName[index+1] != UNICODE_PERIOD)
531 index++;
532 }
533 // Add current char to either file name or ext.
534 if (writingExt) {
535 ext[extIndex] = current;
536 extIndex++;
537 } else {
538 dosName[dosIndex] = current;
539 dosIndex++;
540 }
541 }
542 }
543 }
544 // See if we are done with file name, either because we reached
545 // the end of the file name length, or the final period.
546 if (!writingExt && hasExt && (dosIndex == DOS_NAME_LEN ||
547 index == lastPeriodIndex)) {
548 // If so, and the name has an extension, start reading it.
549 writingExt = TRUE;
550 // Extension starts after last period.
551 index = lastPeriodIndex;
552 }
553 }
554 //
555 if (needsCRC) {
556 // Add CRC to end of file name or at position 4.
557 if (dosIndex >4) dosIndex = 4;
558 valueCRC = UDFUnicodeCksum(udfName, udfLen);
559 // set CRC prefix
560 dosName[dosIndex] = UNICODE_CRC_MARK;
561 // Convert 12-bit CRC to hex characters.
562 dosName[dosIndex+1] = hexChar[(valueCRC & 0x0f00) >> 8];
563 dosName[dosIndex+2] = hexChar[(valueCRC & 0x00f0) >> 4];
564 dosName[dosIndex+3] = hexChar[(valueCRC & 0x000f)];
565 dosIndex+=4;
566 }
567 // Add extension, if any.
568 if (extIndex != 0) {
569 dosName[dosIndex] = UNICODE_PERIOD;
570 dosIndex++;
571 for (index = 0; index < extIndex; index++) {
572 dosName[dosIndex] = ext[index];
573 dosIndex++;
574 }
575 }
576 DosName->Length = (uint16)dosIndex*sizeof(WCHAR);
578} // end UDFDOSName100()
579
580void
584 IN PUNICODE_STRING UdfName,
585 IN BOOLEAN KeepIntact,
586 IN BOOLEAN Mode150
587 )
588{
589 PWCHAR dosName = DosName->Buffer;
590 PWCHAR udfName = UdfName->Buffer;
591 uint32 udfLen = UdfName->Length / sizeof(WCHAR);
592
593 uint32 index, dosIndex = 0, extIndex = 0, lastPeriodIndex;
594 BOOLEAN needsCRC = FALSE, hasExt = FALSE, writingExt = FALSE, isParent = FALSE;
595 uint32 valueCRC;
597
598 if(KeepIntact &&
599 (udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) {
600 isParent = TRUE;
601 if((udfLen == 2) && (udfName[1] != UNICODE_PERIOD))
602 isParent = FALSE;
603 }
604
605 for (index = 0 ; index < udfLen ; index++) {
606 current = udfName[index];
607 if (current == UNICODE_PERIOD && !isParent) {
608 if (dosIndex==0 || hasExt) {
609 // Ignore leading periods or any other than used for extension.
610 needsCRC = TRUE;
611 } else {
612 // First, find last character which is NOT a period or space.
613 lastPeriodIndex = udfLen - 1;
614 while(lastPeriodIndex >=0 &&
615 (udfName[lastPeriodIndex] == UNICODE_PERIOD ||
616 udfName[lastPeriodIndex] == UNICODE_SPACE))
617 lastPeriodIndex--;
618 // Now search for last remaining period.
619 while(lastPeriodIndex >= 0 &&
620 udfName[lastPeriodIndex] != UNICODE_PERIOD)
621 lastPeriodIndex--;
622 // See if the period we found was the last or not.
623 if (lastPeriodIndex != index)
624 needsCRC = TRUE; // If not, name needs translation.
625 // As long as the period was not trailing,
626 // the file name has an extension.
627 if (lastPeriodIndex >= 0) hasExt = TRUE;
628 }
629 } else {
630 if ((!hasExt && dosIndex == DOS_NAME_LEN) ||
631 extIndex == DOS_EXT_LEN) {
632 // File name or extension is too long for DOS.
633 needsCRC = TRUE;
634 } else {
635 if (current == UNICODE_SPACE) { // Ignore spaces.
636 needsCRC = TRUE;
637 } else {
638 // Look for illegal or unprintable characters.
639 if (UDFIsIllegalChar(current) /*|| !UnicodeIsPrint(current)*/) {
640 needsCRC = TRUE;
642 /* Skip Illegal characters(even spaces),
643 * but not periods.
644 */
645 while(index+1 < udfLen &&
646 (UDFIsIllegalChar(udfName[index+1]) /*||
647 !UnicodeIsPrint(udfName[index+1])*/) &&
648 udfName[index+1] != UNICODE_PERIOD)
649 index++;
650 }
651 // Add current char to either file name or ext.
652 if (writingExt) {
653 ext[extIndex] = current;
654 extIndex++;
655 } else {
656 dosName[dosIndex] = current;
657 dosIndex++;
658 }
659 }
660 }
661 }
662 // See if we are done with file name, either because we reached
663 // the end of the file name length, or the final period.
664 if (!writingExt && hasExt && (dosIndex == DOS_NAME_LEN ||
665 index == lastPeriodIndex)) {
666 // If so, and the name has an extension, start reading it.
667 writingExt = TRUE;
668 // Extension starts after last period.
669 index = lastPeriodIndex;
670 }
671 }
672 // Now handle CRC if needed.
673 if (needsCRC) {
674 // Add CRC to end of file name or at position 4.
675 if (dosIndex >4) dosIndex = 4;
676 valueCRC = Mode150 ? UDFUnicodeCksum150(udfName, udfLen) : UDFUnicodeCksum(udfName, udfLen);
677 // Convert 16-bit CRC to hex characters.
678 dosName[dosIndex] = hexChar[(valueCRC & 0xf000) >> 12];
679 dosName[dosIndex+1] = hexChar[(valueCRC & 0x0f00) >> 8];
680 dosName[dosIndex+2] = hexChar[(valueCRC & 0x00f0) >> 4];
681 dosName[dosIndex+3] = hexChar[(valueCRC & 0x000f)];
682 dosIndex+=4;
683 }
684 // Add extension, if any.
685 if (extIndex != 0) {
686 dosName[dosIndex] = UNICODE_PERIOD;
687 dosIndex++;
688 for (index = 0; index < extIndex; index++) {
689 dosName[dosIndex] = ext[index];
690 dosIndex++;
691 }
692 }
693 DosName->Length = (uint16)dosIndex*sizeof(WCHAR);
695} // end UDFDOSName200()
696
697
698void
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;
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++] =
910 valueCRC %= DOS_CRC_MODULUS * DOS_CRC_MODULUS;
911 dosName[dosIndex++] =
912 crcChar[valueCRC / DOS_CRC_MODULUS];
913 valueCRC %= DOS_CRC_MODULUS;
914 dosName[dosIndex++] = crcChar[valueCRC];
915 }
916 /* Append the extension, if any. */
917 if (extLen > 0) {
918 /* Tack on a period and each successive byte in the */
919 /* extension buffer. */
920 dosName[dosIndex++] = '.';
921 for (index = 0; index < extLen; index++)
922 dosName[dosIndex++] = ext[index];
923 }
924 /* Return the length of the resulting Unicode string. */
925 DosName->Length = (uint16)dosIndex*sizeof(WCHAR);
927
928} // end UDFDOSName201()
929
930#ifndef UDF_READ_ONLY_BUILD
931/*
932 This routine initializes Tag structure. It must be called after all
933 manual settings to generate valid CRC & Checksum
934 */
935void
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 */
972 IN PVCB Vcb,
973 IN PUDF_FILE_INFO DirInfo,
975 IN uint32 PartNum,
976 IN uint16 AllocMode, // short/long/ext/in-icb
977 IN uint32 ExtAttrSz,
978 IN BOOLEAN Extended
979 )
980{
981 PFILE_ENTRY FileEntry;
983// EntityID* eID;
984 uint32 l;
985 EXTENT_INFO _FEExtInfo;
986 uint16* lcp;
987
988 ASSERT(!PartNum);
989 ASSERT(!ExtAttrSz);
990 // calculate the length required
991 l = (Extended ? sizeof(EXTENDED_FILE_ENTRY) : sizeof(FILE_ENTRY)) + ExtAttrSz;
992 if(l > Vcb->LBlockSize) return STATUS_INVALID_PARAMETER;
993 // allocate block for FE
994 if(!OS_SUCCESS(status = UDFAllocateFESpace(Vcb, DirInfo, PartNum, &_FEExtInfo, l) ))
995 return status;
996 // remember FE location for future hard link creation
997 ASSERT(UDFFindDloc(Vcb, _FEExtInfo.Mapping[0].extLocation) == (-1));
998 if(!OS_SUCCESS(status = UDFStoreDloc(Vcb, FileInfo, _FEExtInfo.Mapping[0].extLocation))) {
1000 UDFFreeFESpace(Vcb, DirInfo, &_FEExtInfo); // free
1001 MyFreePool__(_FEExtInfo.Mapping);
1002 return status;
1003 }
1005 if(!FileEntry) {
1006 UDFRemoveDloc(Vcb, FileInfo->Dloc);
1007 FileInfo->Dloc = NULL;
1008 UDFFreeFESpace(Vcb, DirInfo, &_FEExtInfo); // free
1009 MyFreePool__(_FEExtInfo.Mapping);
1011 }
1012 FileInfo->Dloc->FELoc = _FEExtInfo;
1013
1014 RtlZeroMemory((int8*)FileEntry, l);
1015 // set up in-memory FE structure
1016 FileEntry->icbTag.flags = AllocMode;
1018 FileEntry->icbTag.numEntries = 1;
1019// if(DirInfo && DirInfo->Dloc && DirInfo->Dloc
1020 FileEntry->icbTag.strategyType = 4;
1021// FileEntry->icbTag.strategyParameter = 0;
1022 FileEntry->descTag.tagIdent = Extended ? TID_EXTENDED_FILE_ENTRY : TID_FILE_ENTRY;
1023 FileEntry->descTag.tagLocation = UDFPhysLbaToPart(Vcb, PartNum, _FEExtInfo.Mapping[0].extLocation);
1024 FileEntry->uid = Vcb->DefaultUID;
1025 FileEntry->gid = Vcb->DefaultGID;
1026
1027 if(Extended) {
1028// eID = &(((PEXTENDED_FILE_ENTRY)FileEntry)->impIdent);
1029 lcp = &(((PEXTENDED_FILE_ENTRY)FileEntry)->fileLinkCount);
1030 ((PEXTENDED_FILE_ENTRY)FileEntry)->checkpoint = 1;
1031 } else {
1032// eID = &(FileEntry->impIdent);
1033 lcp = &(FileEntry->fileLinkCount);
1034 ((PFILE_ENTRY)FileEntry)->checkpoint = 1;
1035 }
1036
1037#if 0
1039#endif
1040
1041 /*RtlCopyMemory((int8*)&(eID->ident), UDF_ID_DEVELOPER, sizeof(UDF_ID_DEVELOPER) );
1042 iis = (impIdentSuffix*)&(eID->identSuffix);
1043 iis->OSClass = UDF_OS_CLASS_WINNT;
1044 iis->OSIdent = UDF_OS_ID_WINNT;*/
1045
1046 *lcp = 0xffff;
1047
1048 FileInfo->Dloc->FileEntry = (tag*)FileEntry;
1049 FileInfo->Dloc->FileEntryLen = l;
1050
1051 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1052
1053 return STATUS_SUCCESS;
1054} // end UDFBuildFileEntry()
1055#endif //UDF_READ_ONLY_BUILD
1056
1057/*
1058 This routine builds ExtentInfo for specified (Ex)FileEntry & associated
1059 AllocDescs
1060 */
1063 IN PVCB Vcb,
1064 IN PFILE_ENTRY fe,
1065 IN PLONG_AD fe_loc,
1066 IN OUT PEXTENT_INFO FExtInfo, // user data
1067 IN OUT PEXTENT_INFO AExtInfo // alloc descs
1068 )
1069{
1070 EXTENT_AD TmpExt;
1071
1072 UDFPrint((" UDFLoadExtInfo:\n"));
1073 FExtInfo->Mapping = UDFReadMappingFromXEntry(Vcb, fe_loc->extLocation.partitionReferenceNum,
1074 (tag*)fe, &(FExtInfo->Offset), AExtInfo);
1075 if(!(FExtInfo->Mapping)) {
1076 if(!(FExtInfo->Offset))
1077 return STATUS_UNSUCCESSFUL;
1078 TmpExt.extLength = fe_loc->extLength;
1079 TmpExt.extLocation = UDFPartLbaToPhys(Vcb, &(fe_loc->extLocation));
1080 if(TmpExt.extLocation == LBA_OUT_OF_EXTENT)
1082 FExtInfo->Mapping = UDFExtentToMapping(&TmpExt);
1083 }
1084 if(fe->descTag.tagIdent == TID_FILE_ENTRY) {
1085// UDFPrint(("Standard FileEntry\n"));
1086 FExtInfo->Length = fe->informationLength;
1087 } else /*if(fe->descTag.tagIdent == TID_EXTENDED_FILE_ENTRY) */ {
1088 FExtInfo->Length = ((PEXTENDED_FILE_ENTRY)fe)->informationLength;
1089 }
1090 UDFPrint((" FExtInfo->Length %x\n", FExtInfo->Length));
1091 ASSERT(FExtInfo->Length <= UDFGetExtentLength(FExtInfo->Mapping));
1092 FExtInfo->Modified = FALSE;
1093
1094 return STATUS_SUCCESS;
1095} // end UDFLoadExtInfo()
1096
1097/*
1098 This routine builds FileIdent for specified FileEntry.
1099 We shall call UDFSetUpTag after all other initializations
1100 This structure is a precise copy of on-disk FileIdent
1101 structure. All modifications of it (including memory block
1102 size) are reflected on Directory extent. This, allocation of
1103 too long block (without changes in ImpUseLen) will lead to
1104 unreadable Directory
1105 */
1108 IN PVCB Vcb,
1110 IN PLONG_AD FileEntryIcb, // virtual address of FileEntry
1111 IN uint32 ImpUseLen,
1112 OUT PFILE_IDENT_DESC* _FileId,
1113 OUT uint32* FileIdLen
1114 )
1115{
1116 PFILE_IDENT_DESC FileId;
1117 uint8* CS0;
1118 SIZE_T Nlen;
1119 uint32 l;
1120 // prepare filename
1121 UDFCompressUnicode(fn, &CS0, &Nlen);
1122 if(!CS0) return STATUS_INSUFFICIENT_RESOURCES;
1123 if(Nlen < 2) {
1124 Nlen = 0;
1125 } else
1126 if(Nlen > UDF_NAME_LEN) {
1127 if(CS0) MyFreePool__(CS0);
1129 }
1130 // allocate memory for FI
1131 l = (sizeof(FILE_IDENT_DESC) + Nlen + ImpUseLen + 3) & ~((uint32)3);
1133 if(!FileId) {
1134 if(CS0) MyFreePool__(CS0);
1136 }
1137 // fill FI structure
1138 RtlZeroMemory( (int8*)FileId, l);
1139 RtlCopyMemory( ((int8*)(FileId+1))+ImpUseLen, CS0, Nlen);
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 */
1156void
1159 IN int64 Size
1160 )
1161{
1162 uint16 Ident;
1163// PDIR_INDEX_ITEM DirIndex;
1164
1166 AdPrint(("UDFSetFileSize: %I64x, FI %x\n", Size, FileInfo));
1167
1168 //AdPrint((" Dloc %x\n", FileInfo->Dloc));
1169 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1170 //AdPrint((" FileEntry %x\n", FileInfo->Dloc->FileEntry));
1171 Ident = FileInfo->Dloc->FileEntry->tagIdent;
1172 //AdPrint((" Ident %x\n", Ident));
1173 if(Ident == TID_FILE_ENTRY) {
1174 PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1175 //AdPrint((" fe %x\n", fe));
1176 fe->informationLength = Size;
1177 } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1178 PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1179 //AdPrint((" ext-fe %x\n", fe));
1180 fe->informationLength = Size;
1181 }
1182/* if(DirIndex = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index) ) {
1183 DirIndex->FileSize = Size;
1184 }*/
1185 //AdPrint(("UDFSetFileSize: ok\n"));
1186 return;
1187} // end UDFSetFileSize()
1188
1189void
1191 IN PVCB Vcb,
1193 IN int64* ASize
1194 )
1195{
1196 uint16 Ident;
1197 PDIR_INDEX_ITEM DirIndex;
1198
1200 if(ASize) {
1201 AdPrint(("UDFSetFileSizeInDirNdx: %I64x\n", *ASize));
1202 } else {
1203 AdPrint(("UDFSetFileSizeInDirNdx: sync\n"));
1204 }
1205
1207 if(!DirIndex)
1208 return;
1209
1210 Ident = FileInfo->Dloc->FileEntry->tagIdent;
1211 if(Ident == TID_FILE_ENTRY) {
1212 PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1213 DirIndex->FileSize = fe->informationLength;
1214 if(ASize) {
1215 DirIndex->AllocationSize = *ASize;
1216// } else {
1217// DirIndex->AllocationSize = (fe->informationLength + Vcb->LBlockSize - 1) & ~(Vcb->LBlockSize - 1);
1218 }
1219 } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1220 PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1221 DirIndex->FileSize = fe->informationLength;
1222 if(ASize) {
1223 DirIndex->AllocationSize = *ASize;
1224// } else {
1225// DirIndex->AllocationSize = (fe->informationLength + Vcb->LBlockSize - 1) & ~(Vcb->LBlockSize - 1);
1226 }
1227 }
1228 return;
1229} // end UDFSetFileSizeInDirNdx()
1230#endif //UDF_READ_ONLY_BUILD
1231
1232/*
1233 This routine gets informationLength field in (Ext)FileEntry
1234 */
1235int64
1238 )
1239{
1240 uint16 Ident;
1241
1243
1244 Ident = FileInfo->Dloc->FileEntry->tagIdent;
1245 if(Ident == TID_FILE_ENTRY) {
1246 PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1247 return fe->informationLength;
1248 } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1249 PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1250 return fe->informationLength;
1251 }
1252 return (-1);
1253} // end UDFGetFileSize()
1254
1255int64
1257 IN PVCB Vcb,
1259 )
1260{
1261 PDIR_INDEX_ITEM DirIndex;
1262
1264
1266 if(!DirIndex)
1267 return -1;
1268
1269 return DirIndex->FileSize;
1270} // end UDFGetFileSizeFromDirNdx()
1271
1272#ifndef UDF_READ_ONLY_BUILD
1273/*
1274 This routine sets lengthAllocDesc field in (Ext)FileEntry
1275 */
1276void
1278 IN PVCB Vcb,
1280 )
1281{
1282 uint16 Ident;
1283
1285
1286 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1287 Ident = FileInfo->Dloc->FileEntry->tagIdent;
1288 if(Ident == TID_FILE_ENTRY) {
1289 PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1290 if(FileInfo->Dloc->AllocLoc.Length) {
1291 fe->lengthAllocDescs = min(FileInfo->Dloc->AllocLoc.Mapping[0].extLength -
1292 FileInfo->Dloc->AllocLoc.Offset,
1293 (uint32)(FileInfo->Dloc->AllocLoc.Length));
1294 } else
1295 if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
1296 fe->lengthAllocDescs = (uint32)(FileInfo->Dloc->DataLoc.Length);
1297 }
1298 } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1299 PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1300 if(FileInfo->Dloc->AllocLoc.Length) {
1301 fe->lengthAllocDescs = min(FileInfo->Dloc->AllocLoc.Mapping[0].extLength -
1302 FileInfo->Dloc->AllocLoc.Offset,
1303 (uint32)(FileInfo->Dloc->AllocLoc.Length));
1304 } else
1305 if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
1306 fe->lengthAllocDescs = (uint32)(FileInfo->Dloc->DataLoc.Length);
1307 }
1308 }
1309} // end UDFSetAllocDescLen()
1310
1311/*
1312 This routine changes fileLinkCount field in (Ext)FileEntry
1313 */
1314void
1317 IN BOOLEAN Increase
1318 )
1319{
1320 uint16 Ident;
1321
1323
1324 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1325 Ident = FileInfo->Dloc->FileEntry->tagIdent;
1326 if(Ident == TID_FILE_ENTRY) {
1327 PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1328 if(Increase) {
1329 fe->fileLinkCount++;
1330 } else {
1331 fe->fileLinkCount--;
1332 }
1333 if(fe->fileLinkCount & 0x8000)
1334 fe->fileLinkCount = 0xffff;
1335 return;
1336 } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1337 PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1338 if(Increase) {
1339 fe->fileLinkCount++;
1340 } else {
1341 fe->fileLinkCount--;
1342 }
1343 if(fe->fileLinkCount & 0x8000)
1344 fe->fileLinkCount = 0xffff;
1345 return;
1346 }
1347 return;
1348} // end UDFChangeFileLinkCount()
1349#endif //UDF_READ_ONLY_BUILD
1350
1351/*
1352 This routine gets fileLinkCount field from (Ext)FileEntry
1353 */
1354uint16
1357 )
1358{
1359 uint16 Ident;
1360 uint16 d;
1361
1363
1364 if(!FileInfo->Dloc->FileEntry)
1365 return 1;
1366 Ident = FileInfo->Dloc->FileEntry->tagIdent;
1367 // UDF engine assumes that LinkCount is a counter
1368 // of FileIdents, referencing this FE.
1369 // UDF 2.0 states, that it should be counter of ALL
1370 // references (including SDir) - 1.
1371 // Thus we'll write to media UDF-required value, but return
1372 // cooked value to callers
1373 d = UDFHasAStreamDir(FileInfo) ? 0 : 1;
1374 if(Ident == TID_FILE_ENTRY) {
1375 return ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount + d;
1376 } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1377 return ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount + d;
1378 }
1380} // end UDFGetFileLinkCount()
1381
1382#ifdef UDF_CHECK_UTIL
1383/*
1384 This routine sets fileLinkCount field in (Ext)FileEntry
1385 */
1386void
1387UDFSetFileLinkCount(
1389 uint16 LinkCount
1390 )
1391{
1392 uint16 Ident;
1393 uint16 d;
1394
1396
1397 if(!FileInfo->Dloc->FileEntry)
1398 return;
1399 Ident = FileInfo->Dloc->FileEntry->tagIdent;
1400 // UDF engine assumes that LinkCount is a counter
1401 // of FileIdents, referencing this FE.
1402 // UDF 2.0 states, that it should be counter of ALL
1403 // references (including SDir) - 1.
1404 // Thus we'll write to media UDF-required value, but return
1405 // cooked value to callers
1406 d = UDFHasAStreamDir(FileInfo) ? 0 : 1;
1407 if(Ident == TID_FILE_ENTRY) {
1408 ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount = LinkCount - d;
1409 } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1410 ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount = LinkCount - d;
1411 }
1412 return;
1413} // end UDFGetFileLinkCount()
1414#endif //UDF_CHECK_UTIL
1415
1416/*
1417 This routine gets lengthExtendedAttr field in (Ext)FileEntry
1418 */
1419uint32
1422 )
1423{
1424 uint16 Ident;
1425
1427
1428 if(!FileInfo->Dloc->FileEntry)
1429 return 1;
1430 Ident = FileInfo->Dloc->FileEntry->tagIdent;
1431
1432 if(Ident == TID_FILE_ENTRY) {
1433 return ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->lengthExtendedAttr;
1434 } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1435 return ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->lengthExtendedAttr;
1436 }
1437 return 0;
1438} // end UDFGetFileEALength()
1439
1440#ifndef UDF_READ_ONLY_BUILD
1441/*
1442 This routine sets UniqueID field in (Ext)FileEntry
1443 */
1444int64
1446 IN PVCB Vcb
1447 )
1448{
1449 Vcb->NextUniqueId++;
1450 if(!((uint32)(Vcb->NextUniqueId)))
1451 Vcb->NextUniqueId += 16;
1452 return Vcb->NextUniqueId;
1453}
1454
1455void
1457 IN PVCB Vcb,
1459 )
1460{
1461 uint16 Ident;
1462 int64 UID;
1463
1465
1467
1468/* UID = FileInfo->Dloc->FELoc.Mapping[0].extLocation |
1469 ( FileInfo->ParentFile ? (((int64)(FileInfo->ParentFile->Dloc->FELoc.Mapping[0].extLocation)) << 32) : 0);*/
1470
1471 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1472 Ident = FileInfo->Dloc->FileEntry->tagIdent;
1473 if(Ident == TID_FILE_ENTRY) {
1474 PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry);
1475 fe->uniqueID = UID;
1476 } else if(Ident == TID_EXTENDED_FILE_ENTRY) {
1477 PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry);
1478 fe->uniqueID = UID;
1479 }
1480 if(FileInfo->FileIdent)
1481 ((FidADImpUse*)&(FileInfo->FileIdent->icb.impUse))->uniqueID = (uint32)UID;
1482 return;
1483} // end UDFSetFileUID()
1484#endif //UDF_READ_ONLY_BUILD
1485
1486/*
1487 This routine gets UniqueID field in (Ext)FileEntry
1488 */
1489__inline
1490int64
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) {
1503 return fe->uniqueID;
1504 }
1505 return (-1);
1506} // end UDFGetFileUID()
1507
1508int64
1511 )
1512{
1514
1515 return UDFGetFileUID_(FileInfo->Dloc->FileEntry);
1516} // end UDFGetFileUID()
1517
1518#ifndef UDF_READ_ONLY_BUILD
1519void
1521 IN PVCB Vcb,
1522 IN BOOLEAN FileCounter,
1523 IN BOOLEAN Increase
1524 )
1525{
1526 uint32* counter;
1527
1528 counter = FileCounter ?
1529 &(Vcb->numFiles) :
1530 &(Vcb->numDirs);
1531 if(*counter == (ULONG)-1)
1532 return;
1533 if(Increase) {
1535 } else {
1537 }
1538
1539} // end UDFChangeFileCounter()
1540
1541void
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);
1553 iis->OSIdent = UDF_OS_ID_WINNT;
1554
1555} // end UDFSetEntityID_imp_()
1556#endif //UDF_READ_ONLY_BUILD
1557
1558void
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));
1583 (Vcb->CompatFlags & UDF_VCB_IC_SOFT_RO)) {
1585 Vcb->UserFSFlags |= UDF_USER_FS_FLAGS_SOFT_RO;
1586 UDFPrint((" Soft-RO\n"));
1587 }
1589 (Vcb->CompatFlags & UDF_VCB_IC_HW_RO)) {
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 */
1606 IN PVCB Vcb,
1608 IN int64 Offset,
1610 IN BOOLEAN Direct,
1611 IN int8* Buffer,
1612 OUT PSIZE_T WrittenBytes
1613 )
1614{
1615 int64 t, elen;
1617 int8* OldInIcb = NULL;
1620 SIZE_T _WrittenBytes;
1621 PUDF_DATALOC_INFO Dloc;
1622 // unwind staff
1623 BOOLEAN WasInIcb = FALSE;
1624 uint64 OldLen;
1625
1626// ASSERT(FileInfo->RefCount >= 1);
1627
1628 Dloc = FileInfo->Dloc;
1629 ASSERT(Dloc->FELoc.Mapping[0].extLocation);
1631 (*WrittenBytes) = 0;
1632
1633 AdPrint(("UDFWriteFile__ FE %x, FileInfo %x, ExtInfo %x, Mapping %x\n",
1634 Dloc->FELoc.Mapping[0].extLocation, FileInfo, &(Dloc->DataLoc), Dloc->DataLoc.Mapping));
1635
1636 t = Offset + Length;
1637// UDFUpdateModifyTime(Vcb, FileInfo);
1638 if(t <= Dloc->DataLoc.Length) {
1639 // write Alloc-Rec area
1640 ExtPrint((" WAlloc-Rec: %I64x <= %I64x\n", t, Dloc->DataLoc.Length));
1641 status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), Offset, Length, Direct, Buffer, WrittenBytes);
1642 return status;
1643 }
1644 elen = UDFGetExtentLength(Dloc->DataLoc.Mapping);
1645 ExtPrint((" DataLoc Offs %x, Len %I64x\n",
1646 Dloc->DataLoc.Offset, Dloc->DataLoc.Length));
1647 if(t <= (elen - Dloc->DataLoc.Offset)) {
1648 // write Alloc-Not-Rec area
1649 ExtPrint((" WAlloc-Not-Rec: %I64x <= %I64x (%I64x - %I64x)\n",
1650 t, elen - Dloc->DataLoc.Offset - Dloc->DataLoc.Length,
1651 elen - Dloc->DataLoc.Offset,
1652 Dloc->DataLoc.Length));
1654 if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
1655 ExtPrint((" w2k-compat -> rebuild allocs\n"));
1656 Dloc->DataLoc.Modified = TRUE;
1657 } else
1658 if((ULONG)((elen+Vcb->LBlockSize-1) >> Vcb->LBlockSizeBits) != (ULONG)((t+Vcb->LBlockSize-1) >> Vcb->LBlockSizeBits)) {
1659 ExtPrint((" LBS boundary crossed -> rebuild allocs\n"));
1660 Dloc->DataLoc.Modified = TRUE;
1661 }
1662 Dloc->DataLoc.Length = t;
1663 return UDFWriteExtent(Vcb, &(Dloc->DataLoc), Offset, Length, Direct, Buffer, WrittenBytes);
1664 }
1665 // We should not get here if Direct=TRUE
1666 if(Direct) return STATUS_INVALID_PARAMETER;
1667 OldLen = Dloc->DataLoc.Length;
1668 if(Dloc->DataLoc.Offset && Dloc->DataLoc.Length) {
1669 // read in-icb data. it'll be replaced after resize
1670 ExtPrint((" read in-icb data\n"));
1671 OldInIcb = (int8*)MyAllocatePool__(NonPagedPool, (uint32)(Dloc->DataLoc.Length));
1672 if(!OldInIcb) return STATUS_INSUFFICIENT_RESOURCES;
1673 status = UDFReadExtent(Vcb, &(Dloc->DataLoc), 0, (uint32)OldLen, FALSE, OldInIcb, &ReadBytes);
1674 if(!OS_SUCCESS(status)) {
1675 MyFreePool__(OldInIcb);
1676 return status;
1677 }
1678 }
1679 // init Alloc mode
1680 ExtPrint((" init Alloc mode\n"));
1681 if((((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) {
1682 ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK;
1683 ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= Vcb->DefaultAllocMode;
1684 WasInIcb = TRUE;
1685 }
1686 // increase extent
1687 ExtPrint((" %s %s %s\n",
1688 UDFIsADirectory(FileInfo) ? "DIR" : "FILE",
1689 WasInIcb ? "In-Icb" : "",
1690 Vcb->LowFreeSpace ? "LowSpace" : ""));
1691 if(UDFIsADirectory(FileInfo) && !WasInIcb && !Vcb->LowFreeSpace) {
1692 FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_ALLOC_SEQUENTIAL;
1693 status = UDFResizeExtent(Vcb, PartNum, (t*2+Vcb->WriteBlockSize-1) & ~(SIZE_T)(Vcb->WriteBlockSize-1), FALSE, &(Dloc->DataLoc));
1694 if(OS_SUCCESS(status)) {
1695 AdPrint((" preallocated space for Dir\n"));
1696 FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_PREALLOCATED;
1697 //UDFSetFileSize(FileInfo, t);
1698 Dloc->DataLoc.Length = t;
1699 } else
1700 if(status == STATUS_DISK_FULL) {
1701 status = UDFResizeExtent(Vcb, PartNum, t, FALSE, &(Dloc->DataLoc));
1702 }
1703 } else {
1704 status = UDFResizeExtent(Vcb, PartNum, t, FALSE, &(Dloc->DataLoc));
1705 }
1706 ExtPrint((" DataLoc Offs %x, Len %I64x\n",
1707 Dloc->DataLoc.Offset, Dloc->DataLoc.Length));
1708 AdPrint(("UDFWriteFile__ (2) FileInfo %x, ExtInfo %x, Mapping %x\n", FileInfo, &(Dloc->DataLoc), Dloc->DataLoc.Mapping));
1709 if(!OS_SUCCESS(status)) {
1710 // rollback
1711 ExtPrint((" err -> rollback\n"));
1712 if(WasInIcb) {
1713 // restore Alloc mode
1714 ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK;
1715 ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= ICB_FLAG_AD_IN_ICB;
1716 if(Dloc->AllocLoc.Mapping) {
1718 Dloc->AllocLoc.Mapping = NULL;
1719 }
1720 }
1721 if(OldInIcb) {
1722 UDFWriteExtent(Vcb, &(Dloc->DataLoc), 0, (uint32)OldLen, FALSE, OldInIcb, &_WrittenBytes);
1723 MyFreePool__(OldInIcb);
1724 }
1725 if((int64)OldLen != Dloc->DataLoc.Length) {
1726 // restore file size
1727 AdPrint((" restore alloc\n"));
1728 FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_CUT_PREALLOCATED;
1729 UDFResizeExtent(Vcb, PartNum, OldLen, FALSE, &(Dloc->DataLoc));
1730 FileInfo->Dloc->DataLoc.Flags &= ~EXTENT_FLAG_CUT_PREALLOCATED;
1731 }
1732 return status;
1733 }
1734 if(OldInIcb) {
1735 // replace data from ICB (if any) & free buffer
1736 ExtPrint((" write old in-icd data\n"));
1737 status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), 0, (uint32)OldLen, FALSE, OldInIcb, &_WrittenBytes);
1738 MyFreePool__(OldInIcb);
1739 if(!OS_SUCCESS(status))
1740 return status;
1741 }
1742 // ufff...
1743 // & now we'll write out data to well prepared extent...
1744 // ... like all normal people do...
1745 ExtPrint((" write user data\n"));
1746 if(!OS_SUCCESS(status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), Offset, Length, FALSE, Buffer, WrittenBytes)))
1747 return status;
1749 Dloc->DataLoc.Modified = TRUE;
1750#ifdef UDF_DBG
1751 if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
1752 ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping));
1753 } else {
1754 ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) ==
1755 ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)));
1756 }
1757#endif // UDF_DBG
1758 return STATUS_SUCCESS;
1759} // end UDFWriteFile__()
1760
1761/*
1762 This routine marks file as deleted & decrements file link counter.
1763 It can optionaly free allocation space
1764 */
1767 IN PVCB Vcb,
1769 IN BOOLEAN FreeSpace
1770 )
1771{
1772 uint_di Index; // index of file to be deleted
1773 uint16 lc;
1774 PUDF_DATALOC_INFO Dloc;
1775 PUDF_FILE_INFO DirInfo;
1776 PUDF_FILE_INFO SDirInfo;
1777 PDIR_INDEX_HDR hDirNdx;
1778 PDIR_INDEX_HDR hCurDirNdx;
1779 PDIR_INDEX_ITEM DirNdx;
1781 BOOLEAN IsSDir;
1782
1783 AdPrint(("UDFUnlinkFile__:\n"));
1784 if(!FileInfo) return STATUS_SUCCESS;
1785
1787
1788#ifndef _CONSOLE
1789 // now we can't call this if there is no OS-specific File Desc. present
1790 if(FileInfo->Fcb)
1792#endif //_CONSOLE
1793 // check references
1794 Dloc = FileInfo->Dloc;
1795 if((FileInfo->OpenCount /*> (uint32)(UDFHasAStreamDir(FileInfo) ? 1 : 0)*/) ||
1796 (FileInfo->RefCount>1)) return STATUS_CANNOT_DELETE;
1797 if(Dloc->SDirInfo)
1798 return STATUS_CANNOT_DELETE;
1799 ASSERT(FileInfo->RefCount == 1);
1800 DirInfo = FileInfo->ParentFile;
1801 // root dir or self
1802 if(!DirInfo || ((FileInfo->Index < 2) && !UDFIsAStreamDir(FileInfo))) return STATUS_CANNOT_DELETE;
1803 hDirNdx = DirInfo->Dloc->DirIndex;
1804 Index = FileInfo->Index;
1805 // we can't delete modified file
1806 // it should be closed & reopened (or flushed) before deletion
1807 DirNdx = UDFDirIndex(hDirNdx,Index);
1808#if defined UDF_DBG || defined PRINT_ALWAYS
1809 if(DirNdx && DirNdx->FName.Buffer) {
1810 AdPrint(("Unlink: %ws\n",DirNdx->FName.Buffer));
1811 }
1812#endif // UDF_DBG
1813 if(FreeSpace &&
1814 ((Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) ||
1815 Dloc->DataLoc.Modified ||
1816 Dloc->AllocLoc.Modified ||
1817 Dloc->FELoc.Modified ||
1818 (DirNdx && (DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) )) {
1819// BrutePoint();
1820 return STATUS_CANNOT_DELETE;
1821 }
1822 SDirInfo = Dloc->SDirInfo;
1823/* if(FreeSpace && SDirInfo) {
1824 UDFPrint(("Unlink: SDirInfo should be NULL !!!\n"));
1825 BrutePoint();
1826 return STATUS_CANNOT_DELETE;
1827 }*/
1828 // stream directory can be deleted even being not empty
1829 // otherwise we should perform some checks
1830 if(!(IsSDir = UDFIsAStreamDir(FileInfo))) {
1831 // check if not empty direcory
1832 if((DirNdx->FileCharacteristics & FILE_DIRECTORY) &&
1833 (hCurDirNdx = Dloc->DirIndex) &&
1834 FreeSpace) {
1835 if(!UDFIsDirEmpty(hCurDirNdx))
1837 }
1840 FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED;
1841 hDirNdx->DelCount++;
1843 }
1844 UDFDecFileLinkCount(FileInfo); // decrease
1846 if(DirNdx && FreeSpace) {
1847 // FileIdent marked as 'deleted' should have an empty ICB
1848 // We shall do it only if object has parent Dir
1849 // (for ex. SDir has parent object, but has no parent Dir)
1851 DirNdx->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR;
1852 // Root Files (Root/SDir/Vat/etc.) has no FileIdent...
1853 if(FileInfo->FileIdent)
1854 RtlZeroMemory(&(FileInfo->FileIdent->icb), sizeof(long_ad));
1855 }
1856 // caller wishes to free allocation, but we can't do it due to
1857 // alive links. In this case we should just remove reference
1858 if(FreeSpace && lc) {
1859 ((icbtag*)(Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum = 0;
1860 ((icbtag*)(Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum = 0;
1862 } else
1863 // if caller wishes to free file allocation &
1864 // there are no more references(links) to this file, lets do it >;->
1865 if(FreeSpace && !lc) {
1867 !UDFIsSDirDeleted(Dloc->SDirInfo) ) {
1868 // we have a Stream Dir associated...
1869 PUDF_FILE_INFO SFileInfo;
1870 // ... try to open it
1871 if(Dloc->SDirInfo) {
1873 return STATUS_CANNOT_DELETE;
1874 }
1875 // open SDir
1877 if(!OS_SUCCESS(status)) {
1878 // abort Unlink on error
1879 SFileInfo = Dloc->SDirInfo;
1880cleanup_SDir:
1881 UDFCleanUpFile__(Vcb, SFileInfo);
1882 if(SFileInfo) MyFreePool__(SFileInfo);
1884 return status;
1885 }
1886 SDirInfo = Dloc->SDirInfo;
1887 // try to perform deltree for Streams
1888 status = UDFUnlinkAllFilesInDir(Vcb, SDirInfo);
1889 if(!OS_SUCCESS(status)) {
1890 // abort Unlink on error
1891 UDFCloseFile__(Vcb, SDirInfo);
1892 SFileInfo = SDirInfo;
1893 BrutePoint();
1894 goto cleanup_SDir;
1895 }
1896 // delete SDir
1897 UDFFlushFile__(Vcb, SDirInfo);
1898 AdPrint((" "));
1899 UDFUnlinkFile__(Vcb, SDirInfo, TRUE);
1900 // close SDir
1901 UDFCloseFile__(Vcb, SDirInfo);
1902 if(UDFCleanUpFile__(Vcb, SDirInfo)) {
1903 MyFreePool__(SDirInfo);
1904#ifdef UDF_DBG
1905 } else {
1906 BrutePoint();
1907#endif // UDF_DBG
1908 }
1909 // update FileInfo
1910 ASSERT(Dloc->FileEntry);
1911 RtlZeroMemory( &(((PEXTENDED_FILE_ENTRY)(Dloc->FileEntry))->streamDirectoryICB), sizeof(long_ad));
1912 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
1913 } else
1914 if(IsSDir) {
1915 // do deltree for Streams
1917 if(!OS_SUCCESS(status)) {
1919 return status;
1920 }
1921 // update parent FileInfo
1922 ASSERT(FileInfo->ParentFile->Dloc->FileEntry);
1923 RtlZeroMemory( &(((PEXTENDED_FILE_ENTRY)(FileInfo->ParentFile->Dloc->FileEntry))->streamDirectoryICB), sizeof(long_ad));
1924 FileInfo->ParentFile->Dloc->FE_Flags &= ~UDF_FE_FLAG_HAS_SDIR;
1925 FileInfo->ParentFile->Dloc->FE_Flags |= (UDF_FE_FLAG_FE_MODIFIED |
1927 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_IS_DEL_SDIR;
1928 UDFDecFileLinkCount(FileInfo->ParentFile);
1929 }
1930 if(Dloc->DirIndex) {
1932 }
1933 // flush file
1935 UDFUnlinkDloc(Vcb, Dloc);
1936 // free allocation
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
1946 IN PVCB Vcb,
1947 IN PUDF_FILE_INFO DirInfo
1948 )
1949{
1950 PDIR_INDEX_HDR hCurDirNdx;
1951 PDIR_INDEX_ITEM CurDirNdx;
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);
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 :(((
1978err_del_stream:
1980 if(FileInfo)
1982 return status;
1983 }
1984
1986 AdPrint((" "));
1989skip_del_stream:
1992 }
1993 }
1994 return STATUS_SUCCESS;
1995} // end UDFUnlinkAllFilesInDir()
1996#endif //UDF_READ_ONLY_BUILD
1997
1998/*
1999 This routine inits UDF_FILE_INFO structure for specified file
2000 If it returns status != STATUS_SUCCESS caller should call UDFCleanUpFile__
2001 for returned pointer *WITHOUT* using UDFCloseFile__
2002 */
2005 IN PVCB Vcb,
2007 IN BOOLEAN NotDeleted,
2009 IN PUDF_FILE_INFO DirInfo,
2010 OUT PUDF_FILE_INFO* _FileInfo,// this is to be filled & doesn't contain
2011 // any pointers
2012 IN uint_di* IndexToOpen
2013 )
2014{
2016 uint_di i=0;
2017 EXTENT_AD FEExt;
2018 uint16 Ident;
2019 PDIR_INDEX_HDR hDirNdx = DirInfo->Dloc->DirIndex;
2020 PDIR_INDEX_ITEM DirNdx;
2022 PUDF_FILE_INFO ParFileInfo;
2024 *_FileInfo = NULL;
2025 if(!hDirNdx) return STATUS_NOT_A_DIRECTORY;
2026
2027 // find specified file in directory index
2028 // if it is already known, skip this foolish code
2029 if(IndexToOpen) {
2030 i=*IndexToOpen;
2031 } else
2032 if(!OS_SUCCESS(status = UDFFindFile(Vcb, IgnoreCase, NotDeleted, fn, DirInfo, &i)))
2033 return status;
2034 // do this check for OpenByIndex
2035 // some routines may send invalid Index
2036 if(!(DirNdx = UDFDirIndex(hDirNdx,i)))
2038 if((FileInfo = DirNdx->FileInfo)) {
2039 // file is already opened.
2040 if((DirNdx->FileCharacteristics & FILE_DELETED) && NotDeleted) {
2041 AdPrint((" FILE_DELETED on open\n"));
2042 return STATUS_FILE_DELETED;
2043 }
2044 if((FileInfo->ParentFile != DirInfo) &&
2045 (FileInfo->Index >= 2)) {
2046 ParFileInfo = UDFLocateParallelFI(DirInfo, i, FileInfo);
2047 BrutePoint();
2048 if(ParFileInfo->ParentFile != DirInfo) {
2050 *_FileInfo = FileInfo;
2052 RtlCopyMemory(FileInfo, DirNdx->FileInfo, sizeof(UDF_FILE_INFO));
2053 // FileInfo->NextLinkedFile = DirNdx->FileInfo->NextLinkedFile; // is already done
2055 DirNdx->FI_Flags |= UDF_FI_FLAG_LINKED;
2056 FileInfo->RefCount = 0;
2057 FileInfo->ParentFile = DirInfo;
2058 FileInfo->Fcb = NULL;
2059 } else {
2060 FileInfo = ParFileInfo;
2061 }
2062 }
2063 // Just increase some counters & exit
2065
2066 ASSERT(FileInfo->ParentFile == DirInfo);
2068
2069 *_FileInfo = FileInfo;
2070 return STATUS_SUCCESS;
2071 } else
2072 if(IndexToOpen) {
2073 if((DirNdx->FileCharacteristics & FILE_DELETED) && NotDeleted) {
2074 AdPrint((" FILE_DELETED on open (2)\n"));
2075 return STATUS_FILE_DELETED;
2076 }
2077 }
2079 *_FileInfo = FileInfo;
2082 // init horizontal links
2083 FileInfo->NextLinkedFile =
2084 FileInfo->PrevLinkedFile = FileInfo;
2085 // read FileIdent
2087 if(!(FileInfo->FileIdent)) return STATUS_INSUFFICIENT_RESOURCES;
2088 FileInfo->FileIdentLen = DirNdx->Length;
2089 if(!OS_SUCCESS(status = UDFReadExtent(Vcb, &(DirInfo->Dloc->DataLoc), DirNdx->Offset,
2090 DirNdx->Length, FALSE, (int8*)(FileInfo->FileIdent), &ReadBytes) ))
2091 return status;
2092 if(FileInfo->FileIdent->descTag.tagIdent != TID_FILE_IDENT_DESC) {
2093 BrutePoint();
2095 }
2096 // check for opened links
2097 if(!OS_SUCCESS(status = UDFStoreDloc(Vcb, FileInfo, UDFPartLbaToPhys(Vcb, &(FileInfo->FileIdent->icb.extLocation)))))
2098 return status;
2099 // init pointer to parent object
2100 FileInfo->Index = i;
2101 FileInfo->ParentFile = DirInfo;
2102 // init pointers to linked files (if any)
2103 if(FileInfo->Dloc->LinkedFileInfo != FileInfo)
2104 UDFInsertLinkedFile(FileInfo, FileInfo->Dloc->LinkedFileInfo);
2105 if(FileInfo->Dloc->FileEntry)
2106 goto init_tree_entry;
2107 // read (Ex)FileEntry
2108 FileInfo->Dloc->FileEntry = (tag*)MyAllocatePoolTag__(NonPagedPool, Vcb->LBlockSize, MEM_FE_TAG);
2109 if(!(FileInfo->Dloc->FileEntry)) return STATUS_INSUFFICIENT_RESOURCES;
2110 if(!OS_SUCCESS(status = UDFReadFileEntry(Vcb, &(FileInfo->FileIdent->icb), (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &Ident)))
2111 return status;
2112 // build mappings for Data & AllocDescs
2113 if(!FileInfo->Dloc->AllocLoc.Mapping) {
2114 FEExt.extLength = FileInfo->FileIdent->icb.extLength;
2115 FEExt.extLocation = UDFPartLbaToPhys(Vcb, &(FileInfo->FileIdent->icb.extLocation) );
2116 if(FEExt.extLocation == LBA_OUT_OF_EXTENT)
2118 FileInfo->Dloc->AllocLoc.Mapping = UDFExtentToMapping(&FEExt);
2119 if(!(FileInfo->Dloc->AllocLoc.Mapping))
2121 }
2122 // read location info
2123 status = UDFLoadExtInfo(Vcb, (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &(FileInfo->FileIdent->icb),
2124 &(FileInfo->Dloc->DataLoc), &(FileInfo->Dloc->AllocLoc) );
2125 if(!OS_SUCCESS(status))
2126 return status;
2127 // init (Ex)FileEntry mapping
2128 FileInfo->Dloc->FELoc.Length = (FileInfo->Dloc->DataLoc.Offset) ? FileInfo->Dloc->DataLoc.Offset :
2129 FileInfo->Dloc->AllocLoc.Offset;
2130// FileInfo->Dloc->FELoc.Offset = 0;
2131 FileInfo->Dloc->FELoc.Mapping = UDFExtentToMapping(&FEExt);
2132 FileInfo->Dloc->FileEntryLen = (uint32)(FileInfo->Dloc->FELoc.Length);
2133 // we get here immediately when opened link encountered
2134init_tree_entry:
2135 // init back pointer from parent object
2136 ASSERT(!DirNdx->FileInfo);
2137 DirNdx->FileInfo = FileInfo;
2138 // init DirIndex
2139 if(UDFGetFileLinkCount(FileInfo) > 1) {
2140 DirNdx->FI_Flags |= UDF_FI_FLAG_LINKED;
2141 } else {
2142 DirNdx->FI_Flags &= ~UDF_FI_FLAG_LINKED;
2143 }
2144 // resize FE cache (0x800 instead of 0x40 is not a good idea)
2145 if(!MyReallocPool__((int8*)((FileInfo->Dloc->FileEntry)), Vcb->LBlockSize,
2146 (int8**)&((FileInfo->Dloc->FileEntry)), FileInfo->Dloc->FileEntryLen))
2148 // check if this file has a SDir
2149 if((FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY) &&
2150 ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLength )
2151 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_HAS_SDIR;
2152 if(!(FileInfo->FileIdent->fileCharacteristics & FILE_DIRECTORY)) {
2154 ASSERT(FileInfo->ParentFile == DirInfo);
2155 UDFReleaseDloc(Vcb, FileInfo->Dloc);
2156 return STATUS_SUCCESS;
2157 }
2158
2159 UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used
2160
2161 // build index for directories
2162 if(!FileInfo->Dloc->DirIndex) {
2164 if(!OS_SUCCESS(status))
2165 return status;
2166#ifndef UDF_READ_ONLY_BUILD
2167 if((FileInfo->Dloc->DirIndex->DelCount > Vcb->PackDirThreshold) &&
2168 !(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)) {
2170 if(!OS_SUCCESS(status))
2171 return status;
2172 }
2173#endif //UDF_READ_ONLY_BUILD
2174 }
2176 UDFReleaseDloc(Vcb, FileInfo->Dloc);
2177 ASSERT(FileInfo->ParentFile == DirInfo);
2178
2179 return status;
2180} // end UDFOpenFile__()
2181
2182
2183/*
2184 This routine inits UDF_FILE_INFO structure for root directory
2185 */
2188 IN PVCB Vcb,
2189 IN lb_addr* RootLoc,
2191 )
2192{
2193 uint32 RootLBA;
2195// uint32 PartNum = RootLoc->partitionReferenceNum;
2196 uint32 LBS = Vcb->LBlockSize;
2197 uint16 Ident;
2198 LONG_AD FELoc;
2199 EXTENT_AD FEExt;
2201
2203 RootLBA = UDFPartLbaToPhys(Vcb,RootLoc);
2204 if(RootLBA == LBA_OUT_OF_EXTENT)
2206 FELoc.extLocation = *RootLoc;
2207 FELoc.extLength = LBS;
2208 // init horizontal links
2209 FileInfo->NextLinkedFile =
2210 FileInfo->PrevLinkedFile = FileInfo;
2211 // check for opened links
2212 if(!OS_SUCCESS(status = UDFStoreDloc(Vcb, FileInfo, RootLBA)))
2213 return status;
2214 if(FileInfo->Dloc->FileEntry)
2215 goto init_tree_entry;
2216 // read (Ex)FileEntry
2217 FileInfo->Dloc->FileEntry = (tag*)MyAllocatePoolTag__(NonPagedPool, LBS, MEM_FE_TAG);
2218 if(!(FileInfo->Dloc->FileEntry)) return STATUS_INSUFFICIENT_RESOURCES;
2219
2220 if(!OS_SUCCESS(status = UDFReadFileEntry(Vcb, &FELoc, (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &Ident)))
2221 return status;
2222 // build mappings for Data & AllocDescs
2223 FEExt.extLength = LBS;
2224 FEExt.extLocation = UDFPartLbaToPhys(Vcb, &(FELoc.extLocation) );
2225 if(FEExt.extLocation == LBA_OUT_OF_EXTENT)
2227 FileInfo->Dloc->FELoc.Mapping = UDFExtentToMapping(&FEExt);
2228 if(!(FileInfo->Dloc->FELoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES;
2229 // build mappings for AllocDescs
2230 if(!FileInfo->Dloc->AllocLoc.Mapping) {
2231 FileInfo->Dloc->AllocLoc.Mapping = UDFExtentToMapping(&FEExt);
2232 if(!(FileInfo->Dloc->AllocLoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES;
2233 }
2234 if(!OS_SUCCESS(status = UDFLoadExtInfo(Vcb, (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &FELoc,
2235 &(FileInfo->Dloc->DataLoc), &(FileInfo->Dloc->AllocLoc) ) ))
2236 return status;
2237 FileInfo->Dloc->FileEntryLen = (uint32)
2238 (FileInfo->Dloc->FELoc.Length = (FileInfo->Dloc->DataLoc.Offset) ? FileInfo->Dloc->DataLoc.Offset :
2239 FileInfo->Dloc->AllocLoc.Offset);
2240init_tree_entry:
2241 // resize FE cache (0x800 instead of 0x40 is not a good idea)
2242 if(!MyReallocPool__((int8*)((FileInfo->Dloc->FileEntry)), LBS,
2243 (int8**)&((FileInfo->Dloc->FileEntry)), FileInfo->Dloc->FileEntryLen))
2245 // init DirIndex
2246 if( (FileType = ((icbtag*)((FileInfo->Dloc->FileEntry)+1))->fileType) != UDF_FILE_TYPE_DIRECTORY &&
2249 UDFReleaseDloc(Vcb, FileInfo->Dloc);
2250 return STATUS_SUCCESS;
2251 }
2252 // build index for directories
2253 if(!FileInfo->Dloc->DirIndex) {
2255 if(!OS_SUCCESS(status))
2256 return status;
2257#ifndef UDF_READ_ONLY_BUILD
2258 if((FileInfo->Dloc->DirIndex->DelCount > Vcb->PackDirThreshold) &&
2259 !(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)) {
2261 if(!OS_SUCCESS(status))
2262 return status;
2263 }
2264#endif //UDF_READ_ONLY_BUILD
2265 }
2267 UDFReleaseDloc(Vcb, FileInfo->Dloc);
2268
2269 return status;
2270} // end UDFOpenRootFile__()
2271
2272/*
2273 This routine frees all memory blocks referenced by given FileInfo
2274 */
2275uint32
2277 IN PVCB Vcb,
2279 )
2280{
2281 PUDF_DATALOC_INFO Dloc;
2282 uint32 lc = 0;
2283 BOOLEAN IsASDir;
2284 BOOLEAN KeepDloc;
2285 PDIR_INDEX_ITEM DirNdx, DirNdx2;
2286 BOOLEAN Parallel = FALSE;
2288#ifdef UDF_DBG
2289 BOOLEAN Modified = FALSE;
2290 PDIR_INDEX_HDR hDirNdx;
2291 uint_di Index;
2292 PUDF_FILE_INFO DirInfo;
2293#endif // UDF_DBG
2294
2295 if(!FileInfo) return UDF_FREE_FILEINFO;
2296
2298
2299 if(FileInfo->OpenCount || FileInfo->RefCount) {
2300 UDFPrint(("UDF: not all references are closed\n"));
2301 UDFPrint((" Skipping cleanup\n"));
2302 UDFPrint(("UDF: OpenCount = %x, RefCount = %x, LinkRefCount = %x\n",
2303 FileInfo->OpenCount,FileInfo->RefCount,FileInfo->Dloc->LinkRefCount));
2304 return UDF_FREE_NOTHING;
2305 }
2306 if(FileInfo->Fcb) {
2307 UDFPrint(("Operating System still has references to this file\n"));
2308 UDFPrint((" Skipping cleanup\n"));
2309// BrutePoint();
2310 return UDF_FREE_NOTHING;
2311 }
2312
2313 IsASDir = UDFIsAStreamDir(FileInfo);
2314
2315 if((Dloc = FileInfo->Dloc)) {
2316
2317#ifdef UDF_DBG
2318 DirInfo = FileInfo->ParentFile;
2319 if(DirInfo) {
2320 hDirNdx = DirInfo->Dloc->DirIndex;
2321 Index = FileInfo->Index;
2322 // we can't delete modified file
2323 // it should be closed & reopened (or flushed) before deletion
2324 DirNdx = UDFDirIndex(hDirNdx,Index);
2325 UDFPrint(("Cleanup Mod: %s%s%s%s%s%s\n",
2326 (Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) ? "FE " : "",
2327 (Dloc->DataLoc.Modified) ? "DataLoc " : "",
2328 (Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) ? "Data-PreAlloc " : "",
2329 (Dloc->AllocLoc.Modified) ? "AllocLoc " : "",
2330 (Dloc->FELoc.Modified) ? "FELoc " : "",
2331 (DirNdx && (DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) ? "FI " : ""
2332 ));
2333 Modified = ((Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) ||
2334 Dloc->DataLoc.Modified ||
2336 Dloc->AllocLoc.Modified ||
2337 Dloc->FELoc.Modified ||
2338 (DirNdx && (DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) );
2339 }
2340#endif // UDF_DBG
2341
2343
2344 Parallel = (ParFileInfo != NULL);
2345 Linked = (FileInfo->NextLinkedFile != FileInfo);
2346
2347// Parallel = (FileInfo->NextLinkedFile != FileInfo);
2348 ASSERT(FileInfo->NextLinkedFile);
2349// ASSERT(!Parallel);
2350 KeepDloc = (Dloc->LinkRefCount ||
2351 Dloc->CommonFcb ||
2352 Linked ) ?
2353 TRUE : FALSE;
2354
2355 if(Dloc->DirIndex) {
2356 uint_di i;
2357 for(i=2; (DirNdx = UDFDirIndex(Dloc->DirIndex,i)); i++) {
2358 if(DirNdx->FileInfo) {
2359 if(!KeepDloc) {
2360 BrutePoint();
2361 UDFPrint(("UDF: Found not cleaned up reference.\n"));
2362 UDFPrint((" Skipping cleanup (1)\n"));
2363// BrutePoint();
2364 return UDF_FREE_NOTHING;
2365 }
2366 // The file being cleaned up may have not closed Dirs
2367 // (linked Dir). In this case each of them may have
2368 // reference to FileInfo in DirIndex[1]
2369 // Here we'll check it and change for valid value if
2370 // necessary (Update Child Objects - I)
2371 if(DirNdx->FileInfo->Dloc) {
2372 // we can get here only when (Parallel == TRUE)
2373 DirNdx2 = UDFDirIndex(DirNdx->FileInfo->Dloc->DirIndex, 1);
2374 // It is enough to check DirNdx2->FileInfo only.
2375 // If one of Parallel FI's has reference (and equal)
2376 // to the FI being removed, it'll be removed from
2377 // the chain & nothing wrong will happen.
2378 if(DirNdx2 && (DirNdx2->FileInfo == FileInfo)) {
2379 if(FileInfo->PrevLinkedFile == FileInfo) {
2380 BrutePoint();
2381 DirNdx2->FileInfo = NULL;
2382 } else {
2383 DirNdx2->FileInfo = Parallel ?
2384 ParFileInfo : FileInfo->PrevLinkedFile;
2385 }
2386 ASSERT(!DirNdx2->FileInfo->RefCount);
2387 }
2388 }
2389 }
2390 }
2391 }
2392 if(Dloc->SDirInfo) {
2393 UDFPrint(("UDF: Found not cleaned up reference (SDir).\n"));
2394
2395 // (Update Child Objects - II)
2396 if(Dloc->SDirInfo->ParentFile == FileInfo) {
2397 BrutePoint();
2398 ASSERT(ParFileInfo);
2399 Dloc->SDirInfo->ParentFile = ParFileInfo;
2400 }
2401 // We should break Cleanup process if alive reference detected
2402 // and there is no possibility to store pointer in some other
2403 // place (in parallel object)
2404 if(!KeepDloc) {
2405 BrutePoint();
2406 UDFPrint((" Skipping cleanup\n"));
2407 return UDF_FREE_NOTHING;
2408 }
2409
2410 if(!UDFIsSDirDeleted(Dloc->SDirInfo) &&
2411 Dloc->SDirInfo->Dloc) {
2412 DirNdx2 = UDFDirIndex(Dloc->SDirInfo->Dloc->DirIndex, 1);
2413 if(DirNdx2 && (DirNdx2->FileInfo == FileInfo)) {
2414 DirNdx2->FileInfo =
2415 Parallel ? ParFileInfo : NULL;
2416 ASSERT(!DirNdx2->FileInfo->RefCount);
2417 }
2418 }
2419 }
2420
2421 if(!KeepDloc) {
2422
2423#ifdef UDF_DBG
2424 ASSERT(!Modified);
2425#endif
2426
2427#ifndef UDF_TRACK_ONDISK_ALLOCATION
2428 if(Dloc->DataLoc.Mapping) MyFreePool__(Dloc->DataLoc.Mapping);
2429 if(Dloc->AllocLoc.Mapping) MyFreePool__(Dloc->AllocLoc.Mapping);
2430 if(Dloc->FELoc.Mapping) MyFreePool__(Dloc->FELoc.Mapping);
2431 if(Dloc->FileEntry) {
2432 // plain file
2434 MyFreePool__(Dloc->FileEntry);
2435 Dloc->FileEntry = NULL;
2436 } else if(FileInfo->Index >= 2) {
2437 // error durring open operation
2439 }
2440#endif //UDF_TRACK_ONDISK_ALLOCATION
2441 if(FileInfo->Dloc->DirIndex) {
2442 uint_di i;
2443 for(i=2; (DirNdx = UDFDirIndex(Dloc->DirIndex,i)); i++) {
2444 ASSERT(!DirNdx->FileInfo);
2445 if(DirNdx->FName.Buffer)
2446 MyFreePool__(DirNdx->FName.Buffer);
2447 }
2448 // The only place where we can free FE_Charge extent is here
2449 UDFFlushFESpace(Vcb, Dloc);
2451 Dloc->DirIndex = NULL;
2452#ifdef UDF_TRACK_ONDISK_ALLOCATION
2454 if(FileInfo->Dloc->DirIndex) {
2455 for(i=2; DirNdx = UDFDirIndex(Dloc->DirIndex,i); i++) {
2456 ASSERT(!DirNdx->FileInfo);
2457 if(DirNdx->FName.Buffer)
2458 MyFreePool__(DirNdx->FName.Buffer);
2459 }
2461 Dloc->DirIndex = NULL;
2462 }
2463#endif //UDF_TRACK_ONDISK_ALLOCATION
2464 }
2465
2466#ifdef UDF_TRACK_ONDISK_ALLOCATION
2467 if(Dloc->AllocLoc.Mapping) MyFreePool__(Dloc->AllocLoc.Mapping);
2468 if(Dloc->FELoc.Mapping) MyFreePool__(Dloc->FELoc.Mapping);
2469 if(Dloc->FileEntry) {
2470 // plain file
2472 MyFreePool__(Dloc->FileEntry);
2473 Dloc->FileEntry = NULL;
2474 } else if(FileInfo->Index >= 2) {
2475 // error durring open operation
2477 }
2478 if(Dloc->DataLoc.Mapping) {
2479 if(lc && (lc != UDF_INVALID_LINK_COUNT)) {
2480 UDFCheckSpaceAllocation(Vcb, 0, Dloc->DataLoc.Mapping, AS_USED); // check if used
2481 } else {
2482 UDFCheckSpaceAllocation(Vcb, 0, Dloc->DataLoc.Mapping, AS_FREE); // check if free
2483 }
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 */
2578 IN PVCB Vcb,
2579// IN uint16 AllocMode, // short/long/ext/in-icb // always in-ICB
2581 IN PUNICODE_STRING _fn,
2582 IN uint32 ExtAttrSz,
2583 IN uint32 ImpUseLen,
2584 IN BOOLEAN Extended,
2585 IN BOOLEAN CreateNew,
2586 IN OUT PUDF_FILE_INFO DirInfo,
2587 OUT PUDF_FILE_INFO* _FileInfo
2588 )
2589{
2590 uint32 l, d;
2591 uint_di i, j;
2593 LONG_AD FEicb;
2594 UDF_DIR_SCAN_CONTEXT ScanContext;
2595 PDIR_INDEX_HDR hDirNdx = DirInfo->Dloc->DirIndex;
2596 PDIR_INDEX_ITEM DirNdx;
2597 uint32 LBS = Vcb->LBlockSize;
2599 *_FileInfo = NULL;
2600 BOOLEAN undel = FALSE;
2602// BOOLEAN PackDir = FALSE;
2603 BOOLEAN FEAllocated = FALSE;
2604
2605 ValidateFileInfo(DirInfo);
2606 *_FileInfo = NULL;
2607
2608 ASSERT(DirInfo->Dloc->FELoc.Mapping[0].extLocation);
2609 uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, DirInfo->Dloc->FELoc.Mapping[0].extLocation);
2610 if(!hDirNdx) return STATUS_NOT_A_DIRECTORY;
2611 i = 0;
2612
2613 _SEH2_TRY {
2614
2615 // check if exists
2616 status = UDFFindFile(Vcb, IgnoreCase, FALSE, _fn, DirInfo, &i);
2617 DirNdx = UDFDirIndex(hDirNdx,i);
2618 if(OS_SUCCESS(status)) {
2619 // file is a Cur(Parent)Dir
2621 // file deleted
2622 if(UDFIsDeleted(DirNdx)) {
2623 j=0;
2624 if(OS_SUCCESS(UDFFindFile(Vcb, IgnoreCase, TRUE, _fn, DirInfo, &j))) {
2625 i=j;
2626 DirNdx = UDFDirIndex(hDirNdx,i);
2627 goto CreateBothFound;
2628 }
2629 // we needn't allocating new FileIdent inside Dir stream
2630 // perform 'undel'
2631 if(DirNdx->FileInfo) {
2632 // BrutePoint();
2634 if(!OS_SUCCESS(status))
2636 } else {
2637 undel = TRUE;
2638 }
2639 // BrutePoint();
2640 goto CreateUndel;
2641 }
2642CreateBothFound:
2643 // file already exists
2644 if(CreateNew) try_return (status = STATUS_ACCESS_DENIED);
2645 // try to open it
2646 BrutePoint();
2647 status = UDFOpenFile__(Vcb, IgnoreCase, TRUE, _fn, DirInfo, _FileInfo,&i);
2648 // *_FileInfo = FileInfo; // OpenFile__ has already done it, so update it...
2649 DirNdx = UDFDirIndex(hDirNdx,i);
2650 DirNdx->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR;
2651 FileInfo = *_FileInfo;
2652 if(!OS_SUCCESS(status)) {
2653 // :(( can't open....
2656 *_FileInfo = NULL;
2657 }
2658 BrutePoint();
2660 }
2661 // check if we can delete this file
2662 if(FileInfo->OpenCount || (FileInfo->RefCount > 1)) {
2663 BrutePoint();
2666 }
2667 BrutePoint();
2668 // remove DIRECTORY flag
2669 DirNdx->FileCharacteristics &= ~FILE_DIRECTORY;
2670 FileInfo->FileIdent->fileCharacteristics &= ~FILE_DIRECTORY;
2672 // truncate file size to ZERO
2674 if(!OS_SUCCESS(status)) {
2675 BrutePoint();
2677 }
2678 // set NORMAL flag
2679 FileInfo->FileIdent->fileCharacteristics = 0;
2680 DirNdx->FileCharacteristics = 0;
2681 // update DeletedFiles counter in Directory... (for PackDir)
2682 if(undel && OS_SUCCESS(status))
2683 hDirNdx->DelCount--;
2685 }
2686
2687CreateUndel:
2688
2689 // allocate FileInfo
2691 *_FileInfo = FileInfo;
2692 if(!FileInfo)
2694 ImpUseLen = (ImpUseLen + 3) & ~((uint16)3);
2695
2697 // init horizontal links
2698 FileInfo->NextLinkedFile =
2699 FileInfo->PrevLinkedFile = FileInfo;
2700 // allocate space for FileEntry
2701 if(!OS_SUCCESS(status =
2702 UDFBuildFileEntry(Vcb, DirInfo, FileInfo, PartNum, ICB_FLAG_AD_IN_ICB, ExtAttrSz, Extended) )) {
2703 BrutePoint();
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)) ))
2719 } else {
2720 // read FileIdent
2723 FileInfo->FileIdentLen = DirNdx->Length;
2724 if(!OS_SUCCESS(status = UDFReadExtent(Vcb, &(DirInfo->Dloc->DataLoc), DirNdx->Offset,
2725 DirNdx->Length, FALSE, (int8*)(FileInfo->FileIdent), &ReadBytes) ))
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))) {
2770 }
2771
2772 // init offset of new FileIdent in directory Data extent
2773 hDirNdx = DirInfo->Dloc->DirIndex;
2774 if(i-1) {
2775 DirNdx = UDFDirIndex(hDirNdx,i-1);
2776 UDFDirIndex(hDirNdx,i)->Offset = DirNdx->Offset + DirNdx->Length;
2777 DirNdx = UDFDirIndex(hDirNdx,i);
2778 } else {
2779 DirNdx = UDFDirIndex(hDirNdx,i);
2780 DirNdx->Offset = 0;
2781 }
2782 // new terminator is recorded by UDFDirIndexGrow()
2783 if( ((d = ((LBS - (DirNdx->Offset + l + DirInfo->Dloc->DataLoc.Offset)) & (LBS-1) )) < sizeof(FILE_IDENT_DESC)) &&
2784 d ) {
2785 // insufficient space at the end of last sector for
2786 // next FileIdent's tag. fill it with ImpUse data
2787
2788 // generally, all data should be DWORD-aligned, but if it is not so
2789 // this opearation will help us to avoid glitches
2790 d = (d+3) & ~((uint32)3);
2791
2792 uint32 IUl, FIl;
2793 if(!MyReallocPool__((int8*)(FileInfo->FileIdent), l,
2794 (int8**)&(FileInfo->FileIdent), (l+d+3) & ~((uint32)(3)) ))
2796 l += d;
2797 IUl = FileInfo->FileIdent->lengthOfImpUse;
2798 FIl = FileInfo->FileIdent->lengthFileIdent;
2799 // move filename to higher addr
2800 RtlMoveMemory(((int8*)(FileInfo->FileIdent+1))+IUl+d,
2801 ((int8*)(FileInfo->FileIdent+1))+IUl, FIl);
2802 RtlZeroMemory(((int8*)(FileInfo->FileIdent+1))+IUl, d);
2803 FileInfo->FileIdent->lengthOfImpUse += (uint16)d;
2804 FileInfo->FileIdentLen = l;
2805 }
2806 DirNdx->Length = l;
2807CrF__1:
2808 // clone unicode string
2809 // it **<<MUST>>** be allocated with internal memory manager
2810 DirNdx->FName.Buffer = (PWCHAR)MyAllocatePoolTag__(UDF_FILENAME_MT, (DirNdx->FName.MaximumLength = _fn->Length + sizeof(WCHAR)), MEM_FNAMECPY_TAG);
2811 DirNdx->FName.Length = _fn->Length;
2812 if(!DirNdx->FName.Buffer)
2814 RtlCopyMemory(DirNdx->FName.Buffer, _fn->Buffer, _fn->Length);
2815 DirNdx->FName.Buffer[_fn->Length/sizeof(WCHAR)] = 0;
2816CrF__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;
2821 DirNdx->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR;
2822 ASSERT(!DirNdx->FileInfo);
2823 DirNdx->FileInfo = FileInfo;
2824 DirNdx->FileEntryLoc = FEicb.extLocation;
2825 // mark file as 'deleted' for now
2827 FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED;
2828 FileInfo->Dloc->DataLoc.Mapping = UDFExtentToMapping(&(FileInfo->Dloc->FELoc.Mapping[0]));
2829 if(!(FileInfo->Dloc->DataLoc.Mapping)) {
2830 UDFFlushFI(Vcb, FileInfo, PartNum);
2832 }
2833 FileInfo->Dloc->DataLoc.Length = 0;
2834 FileInfo->Dloc->DataLoc.Offset = FileInfo->Dloc->FileEntryLen;
2835 FileInfo->ParentFile = DirInfo;
2836 // init FileEntry
2839 UDFIncFileLinkCount(FileInfo); // increase to 1
2840 UDFUpdateCreateTime(Vcb, FileInfo);
2842 FileInfo->Dloc->FileEntry, Vcb->DefaultAttr);
2843 FileInfo->Dloc->DataLoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK;
2844 FileInfo->Dloc->DataLoc.Modified = TRUE;
2845 FileInfo->Dloc->FELoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK;
2846 // zero sector for FileEntry
2847 if(!Vcb->CDR_Mode) {
2848 status = UDFWriteData(Vcb, TRUE, ((int64)(FileInfo->Dloc->FELoc.Mapping[0].extLocation)) << Vcb->BlockSizeBits, LBS, FALSE, Vcb->ZBuffer, &ReadBytes);
2849 if(!OS_SUCCESS(status)) {
2850 UDFFlushFI(Vcb, FileInfo, PartNum);
2852 }
2853 }
2854#if 0
2855 if((i >= 2) && (DirNdx->FName.Buffer[0] == L'.')) {
2856 BrutePoint();
2857 }
2858#endif
2859
2860#ifdef UDF_CHECK_DISK_ALLOCATION
2861 if( /*FileInfo->Fcb &&*/
2862 UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) {
2863
2864 if(!FileInfo->FileIdent ||
2865 !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED)) {
2866 AdPrint(("Flushing to Discarded block %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation));
2867 BrutePoint();
2868 }
2869 }
2870#endif // UDF_CHECK_DISK_ALLOCATION
2871
2872 // make FileIdent valid
2873 FileInfo->FileIdent->fileCharacteristics = 0;
2874 DirNdx->FileCharacteristics = 0;
2876 UDFFlushFE(Vcb, FileInfo, PartNum);
2877 if(undel)
2878 hDirNdx->DelCount--;
2879 UDFReleaseDloc(Vcb, FileInfo->Dloc);
2881
2882 UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used
2883
2885
2886try_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
2903OSSTATUS
2904UDFReadFile__(
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
2926 IN PVCB Vcb,
2928 IN int64 Offset, // offset in extent
2930 IN BOOLEAN Direct,
2932 )
2933{
2935
2936 return UDFZeroExtent__(Vcb, &(FileInfo->Dloc->DataLoc), Offset, Length, Direct, ReadBytes);
2937} // end UDFZeroFile__()*/
2938
2939/*
2940 This routine makes sparse area in file described by FileInfo
2941 */
2942__inline
2945 IN PVCB Vcb,
2947 IN int64 Offset, // offset in extent
2949 IN BOOLEAN Direct,
2951 )
2952{
2954
2955 return UDFSparseExtent__(Vcb, &(FileInfo->Dloc->DataLoc), Offset, Length, Direct, ReadBytes);
2956} // end UDFSparseFile__()*/
2957
2958/*
2959 This routine fills tails of the last sector in extent with ZEROs
2960 */
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;
2973 // Length should not be zero
2974 int64 Offset = ExtInfo->Length + ExtInfo->Offset;
2975 // data is sector-size-aligned, we needn't any padding
2976 if(Offset && !((uint32)Offset & (Vcb->LBlockSize-1) )) return STATUS_SUCCESS;
2977 // get Lba of the last sector
2978 Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, &sect_offs, &to_write, &flags, NULL);
2979 // EOF check. If we have valid ExtInfo this will not happen, but who knows..
2980 if((Lba == (uint32)-1) ||
2982 return STATUS_END_OF_FILE;
2983 // write tail
2984 status = UDFWriteData(Vcb, TRUE, (((int64)Lba) << Vcb->BlockSizeBits) + sect_offs, to_write, FALSE, Vcb->ZBuffer, &WrittenBytes);
2985 return status;
2986} // UDFPadLastSector()
2987#endif //UDF_READ_ONLY_BUILD
2988
2989/*
2990 This routine updates AllocDesc sequence, FileIdent & FileEntry
2991 for given file
2992 */
2995 IN PVCB Vcb,
2997 )
2998{
3000
3001 if(!FileInfo) return STATUS_SUCCESS;
3002 if(FileInfo->Index<2 && (FileInfo->ParentFile) && !UDFIsAStreamDir(FileInfo)) {
3003 UDFPrint(("Closing Current or Parent Directory... :-\\\n"));
3004 if(FileInfo->RefCount) {
3005 UDFInterlockedDecrement((PLONG)&(FileInfo->RefCount));
3006 ASSERT(FileInfo->Dloc);
3007 if(FileInfo->Dloc)
3008 UDFInterlockedDecrement((PLONG)&(FileInfo->Dloc->LinkRefCount));
3009#ifdef UDF_DBG
3010 } else {
3011 BrutePoint();
3012 UDFPrint(("ERROR: Closing unreferenced file!\n"));
3013#endif // UDF_DBG
3014 }
3015 if(FileInfo->ParentFile->OpenCount) {
3016 UDFInterlockedDecrement((PLONG)&(FileInfo->ParentFile->OpenCount));
3017#ifdef UDF_DBG
3018 } else {
3019 BrutePoint();
3020 UDFPrint(("ERROR: Closing unopened file!\n"));
3021#endif // UDF_DBG
3022 }
3023 return STATUS_SUCCESS;
3024 }
3025 PUDF_FILE_INFO DirInfo = FileInfo->ParentFile;
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) {
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);
3075 UDFPrint((" Not DELETED SDir\n"));
3076 BrutePoint();
3077 }
3078 ASSERT(!FileInfo->Dloc->FELoc.Modified);
3079 } else
3080 if(!FileInfo->FileIdent ||
3081 !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED)) {
3082 if(!FileInfo->FileIdent) {
3083 AdPrint((" No FileIdent\n"));
3084 }
3085 if(FileInfo->FileIdent &&
3086 !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED))
3087 AdPrint((" Not DELETED\n"));
3088 ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3089 AdPrint(("Flushing to Discarded block %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation));
3090 BrutePoint();
3091 } else {
3092 UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_FREE); // check if free
3093 UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->FELoc.Mapping, AS_FREE); // check if free
3094 }
3095 } else {
3096 if(!FileInfo->Dloc->FELoc.Mapping[0].extLocation ||
3097 UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) {
3098 UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_FREE); // check if free
3099 } else {
3100 UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used
3101 }
3102 }
3103#endif // UDF_CHECK_DISK_ALLOCATION
3104 // check if we should update parentICBLocation
3105 if( !((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum &&
3106 !((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum &&
3107 DirInfo &&
3108 !Vcb->CDR_Mode &&
3109 Vcb->Modified &&
3111 ASSERT(DirInfo->Dloc->FELoc.Mapping[0].extLocation);
3112 ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum =
3113 UDFPhysLbaToPart(Vcb, PartNum, DirInfo->Dloc->FELoc.Mapping[0].extLocation);
3114 ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum = (uint16)PartNum;
3115 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
3116 }
3117
3118 // we needn't flushing FE & Allocs untill all links are closed...
3119 if(!FileInfo->Dloc->LinkRefCount) {
3120
3121 // flush FE and pre-allocation charge for directories
3122 if(FileInfo->Dloc &&
3123 FileInfo->Dloc->DirIndex) {
3124
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));
3130 if(OS_SUCCESS(status)) {
3131 AdPrint(("Dir pre-alloc truncated (Close)\n"));
3132 FileInfo->Dloc->DataLoc.Modified = TRUE;
3133 }
3134 }
3135 }
3136
3137 if(!OS_SUCCESS(status = UDFFlushFE(Vcb, FileInfo, PartNum))) {
3138 UDFPrint(("Error flushing FE\n"));
3139//flush_recovery:
3140 BrutePoint();
3141 if(FileInfo->Index >= 2) {
3142 PDIR_INDEX_ITEM DirNdx;
3144 if(DirNdx) {
3145 UDFPrint(("Recovery: mark as deleted & flush FI\n"));
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 */
3177 IN PVCB Vcb,
3179 IN OUT BOOLEAN* Replace, // replace if destination file exists
3180 IN PUNICODE_STRING fn, // destination
3181 IN OUT PUDF_FILE_INFO DirInfo1,
3182 IN OUT PUDF_FILE_INFO DirInfo2,
3183 IN OUT PUDF_FILE_INFO FileInfo // source (opened)
3184 )
3185{
3186 PUDF_FILE_INFO FileInfo2;
3188 PDIR_INDEX_ITEM DirNdx1;
3189 PDIR_INDEX_ITEM DirNdx2;
3190 uint_di i,j;
3191 BOOLEAN Recovery = FALSE;
3192 BOOLEAN SameFE = FALSE;
3193 uint32 NTAttr = 0;
3194
3195 // validate FileInfo
3196 ValidateFileInfo(DirInfo1);
3197 ValidateFileInfo(DirInfo2);
3199
3200 i = j = 0;
3201 if(DirInfo1 == DirInfo2) {
3202 if(OS_SUCCESS(status = UDFFindFile(Vcb, IgnoreCase, TRUE, fn, DirInfo2, &j)) &&
3203 (j==FileInfo->Index) ) {
3204 // case-only rename
3205 uint8* CS0;
3206 SIZE_T Nlen, /* l, FIXME ReactOS */ IUl;
3207
3208 // prepare filename
3209 UDFCompressUnicode(fn, &CS0, &Nlen);
3210 if(!CS0) return STATUS_INSUFFICIENT_RESOURCES;
3211/* if(Nlen > UDF_NAME_LEN) {
3212 if(CS0) MyFreePool__(CS0);
3213 return STATUS_OBJECT_NAME_INVALID;
3214 }*/
3215 // allocate memory for FI
3216 DirNdx2 = UDFDirIndex(DirInfo2->Dloc->DirIndex,j);
3217 IUl = DirNdx2->FileInfo->FileIdent->lengthOfImpUse;
3218#if 0
3219 l = (sizeof(FILE_IDENT_DESC) + Nlen + IUl + 3) & ~((uint32)3);
3220#endif
3221
3222 RtlCopyMemory( ((uint8*)(DirNdx2->FileInfo->FileIdent+1))+IUl, CS0, Nlen);
3223 RtlCopyMemory(DirNdx2->FName.Buffer, fn->Buffer, fn->Length);
3224
3225 if(CS0) MyFreePool__(CS0);
3226
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
3243RenameRetry:
3245 0, (FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY),
3246 TRUE, DirInfo2, &FileInfo2))) {
3247 UDFCleanUpFile__(Vcb, FileInfo2);
3248 if(FileInfo2) MyFreePool__(FileInfo2);
3250 // try to recover >;->
3251 if((*Replace) && !Recovery) {
3252 Recovery = TRUE;
3253 status = UDFOpenFile__(Vcb, IgnoreCase, TRUE, fn, DirInfo2, &FileInfo2, NULL);
3254 if(OS_SUCCESS(status)) {
3256 if(!OS_SUCCESS(status)) {
3257 UDFCloseFile__(Vcb, FileInfo2);
3258 goto cleanup_and_abort_rename;
3259 }
3260 status = UDFUnlinkFile__(Vcb, FileInfo2, TRUE);
3261// UDFPretendFileDeleted__(Vcb, FileInfo2);
3262 UDFCloseFile__(Vcb, FileInfo2);
3263 if(UDFCleanUpFile__(Vcb, FileInfo2)) {
3264 MyFreePool__(FileInfo2);
3265 FileInfo2 = NULL;
3266 if(SameFE)
3267 return status;
3268 } else {
3269 // we get here if the FileInfo has associated
3270 // system-specific Fcb
3271 // Such fact means that not all system references
3272 // has already gone (except Linked file case)
3273/* if(SameFE)
3274 return status;*/
3275// UDFRemoveOSReferences__(FileInfo2);
3276 if(!OS_SUCCESS(status) ||
3277 (UDFGetFileLinkCount(FileInfo2) < 1))
3279 }
3280 if(OS_SUCCESS(status)) goto RenameRetry;
3281 }
3282cleanup_and_abort_rename:
3283 if(FileInfo2 && UDFCleanUpFile__(Vcb, FileInfo2)) {
3284 MyFreePool__(FileInfo2);
3285 FileInfo2 = NULL;
3286 }
3287 } else {
3289 }
3290 }
3291 return status;
3292 }
3293 // update pointers
3294 DirNdx1 = UDFDirIndex(DirInfo1->Dloc->DirIndex, i = FileInfo->Index);
3295 DirNdx2 = UDFDirIndex(DirInfo2->Dloc->DirIndex, j = FileInfo2->Index);
3296
3297 // copy file attributes to newly created FileIdent
3298 NTAttr = UDFAttributesToNT(DirNdx1, FileInfo->Dloc->FileEntry);
3299 FileInfo2->FileIdent->fileVersionNum = FileInfo->FileIdent->fileVersionNum;
3300 // unlink source FileIdent
3302 // kill newly created entry
3303 UDFFlushFile__(Vcb, FileInfo2);
3304 UDFUnlinkFile__(Vcb, FileInfo2, TRUE);
3305 UDFCloseFile__(Vcb, FileInfo2);
3306 UDFCleanUpFile__(Vcb, FileInfo2);
3307 MyFreePool__(FileInfo2);
3308 return status;
3309 }
3310
3311 // PHASE 1
3312 // drop all unnecessary info from FileInfo & flush FI
3313
3314 DirNdx1->FileInfo = NULL;
3315 ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3316 UDFFlushFI(Vcb, FileInfo, UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation));
3317 UDFInterlockedExchangeAdd((PLONG)&(DirInfo1->OpenCount),
3318 -((LONG)(FileInfo->RefCount)));
3319 // PHASE 2
3320 // copy all necessary info from FileInfo to FileInfo2
3321
3322 FileInfo2->FileIdent->icb = FileInfo->FileIdent->icb;
3323 FileInfo2->FileIdent->fileCharacteristics = FileInfo->FileIdent->fileCharacteristics;
3324 FileInfo2->FileIdent->fileVersionNum = FileInfo->FileIdent->fileVersionNum;
3325 MyFreePool__(FileInfo->FileIdent);
3326 FileInfo->FileIdent = NULL;
3327
3328 // PHASE 3
3329 // copy all necessary info from FileInfo2 to FileInfo
3330
3331 DirNdx2->FileInfo = FileInfo;
3332 DirNdx2->FileCharacteristics = DirNdx1->FileCharacteristics & ~FILE_DELETED;
3333 DirNdx2->FileEntryLoc = DirNdx1->FileEntryLoc;
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 */
3385 IN PVCB Vcb,
3386 IN OUT PUDF_FILE_INFO DirInfo // source (opened)
3387 )
3388{
3390 LONG_AD FEicb;
3392 UDF_DATALOC_INFO Dloc;
3393 UNICODE_STRING PName;
3394 uint32 PartNum;
3395 SIZE_T WrittenBytes;
3396 PDIR_INDEX_ITEM CurDirNdx;
3397 uint32 lba;
3398
3399 // validate DirInfo
3400 ValidateFileInfo(DirInfo);
3401 if(DirInfo->ParentFile && UDFIsAStreamDir(DirInfo->ParentFile))
3402 return STATUS_ACCESS_DENIED;
3403 // file should be empty
3404 if(UDFGetFileSize(DirInfo)) {
3405 if( DirInfo->FileIdent &&
3406 (DirInfo->FileIdent->fileCharacteristics & FILE_DIRECTORY)) return STATUS_FILE_IS_A_DIRECTORY;
3408 }
3409 if(DirInfo->Dloc->DirIndex) return STATUS_FILE_IS_A_DIRECTORY;
3410 // create empty DirIndex
3411 if(DirInfo->FileIdent) DirInfo->FileIdent->fileCharacteristics |= FILE_DIRECTORY;
3412 if((CurDirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(DirInfo),DirInfo->Index)))
3413 CurDirNdx->FileCharacteristics |= FILE_DIRECTORY;
3414 ((icbtag*)(DirInfo->Dloc->FileEntry+1))->fileType = UDF_FILE_TYPE_DIRECTORY;
3415 // init temporary FileInfo
3417 FileInfo.Dloc = &Dloc;
3418 FileInfo.Dloc->FileEntry = DirInfo->ParentFile->Dloc->FileEntry;
3419 FileInfo.Dloc->FileEntryLen = DirInfo->ParentFile->Dloc->FileEntryLen;
3420 FileInfo.Dloc->DataLoc = DirInfo->Dloc->DataLoc;
3421 FileInfo.Dloc->FELoc = DirInfo->Dloc->FELoc;
3422 FileInfo.ParentFile = DirInfo;
3423 // prepare FileIdent for 'parent Dir'
3424 lba = DirInfo->Dloc->FELoc.Mapping[0].extLocation;
3425 ASSERT(lba);
3426 PartNum = UDFGetPartNumByPhysLba(Vcb, lba);
3427 FEicb.extLength = Vcb->LBlockSize;
3429 FEicb.extLocation.partitionReferenceNum = (uint16)PartNum;
3430 RtlZeroMemory(&(FEicb.impUse), sizeof(FEicb.impUse));
3431 PName.Buffer = (PWCH)L"";
3432 PName.Length = (PName.MaximumLength = sizeof(L"")) - sizeof(WCHAR);
3433 if(!OS_SUCCESS(status =
3434 UDFBuildFileIdent(Vcb, &PName, &FEicb, 0,
3435 &(FileInfo.FileIdent), &(FileInfo.FileIdentLen)) ))
3436 return status;
3437 FileInfo.FileIdent->fileCharacteristics |= (FILE_PARENT | FILE_DIRECTORY);
3440 // init structure
3441 UDFSetUpTag(Vcb, &(FileInfo.FileIdent->descTag), (uint16)(FileInfo.FileIdentLen),
3443 FileInfo.Dloc->DataLoc.Flags |= EXTENT_FLAG_VERIFY; // for metadata
3444 // flush
3445 status = UDFWriteFile__(Vcb, DirInfo, 0, FileInfo.FileIdentLen, FALSE, (int8*)(FileInfo.FileIdent), &WrittenBytes);
3446// status = UDFFlushFI(Vcb, &FileInfo, PartNum);
3447
3448#ifdef UDF_DBG
3449 if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
3450 ASSERT(UDFGetFileSize(DirInfo) <= UDFGetExtentLength(DirInfo->Dloc->DataLoc.Mapping));
3451 } else {
3452 ASSERT(((UDFGetFileSize(DirInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) ==
3453 ((UDFGetExtentLength(DirInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)));
3454 }
3455#endif // UDF_DBG
3456
3457 MyFreePool__(FileInfo.FileIdent);
3458 if(!OS_SUCCESS(status)) return status;
3459 if(CurDirNdx) CurDirNdx->FileCharacteristics =
3460 DirInfo->FileIdent->fileCharacteristics;
3461 return UDFIndexDirectory(Vcb, DirInfo);
3462} // end UDFRecordDirectory__()
3463
3464/*
3465 This routine changes file size (on disc)
3466 */
3469 IN PVCB Vcb,
3472 )
3473{
3474 SIZE_T WrittenBytes;
3476 uint32 PartNum;
3477 int8* OldInIcb = NULL;
3478 PEXTENT_MAP NewMap;
3479
3480 UDFPrint(("UDFResizeFile__: FI %x, -> %I64x\n", FileInfo, NewLength));
3482// ASSERT(FileInfo->RefCount >= 1);
3483
3484 if((NewLength >> Vcb->LBlockSizeBits) > Vcb->TotalAllocUnits) {
3485 UDFPrint(("STATUS_DISK_FULL\n"));
3486 return STATUS_DISK_FULL;
3487 }
3488 if (NewLength == FileInfo->Dloc->DataLoc.Length) return STATUS_SUCCESS;
3489 if(FileInfo->ParentFile && (FileInfo->Index >= 2)) {
3490 UDFDirIndex(FileInfo->ParentFile->Dloc->DirIndex,FileInfo->Index)->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR;
3491 }
3492 if(NewLength > FileInfo->Dloc->DataLoc.Length) {
3493 // grow file
3494 return UDFWriteFile__(Vcb, FileInfo, NewLength, 0, FALSE, NULL, &WrittenBytes);
3495 }
3496 // truncate file
3497 if(NewLength <= (Vcb->LBlockSize - FileInfo->Dloc->FileEntryLen)) {
3498 // check if we are already in IN_ICB mode
3499 if((((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) != ICB_FLAG_AD_IN_ICB) {
3500 // read data from old location
3501 if(NewLength) {
3503 if(!OldInIcb) return STATUS_INSUFFICIENT_RESOURCES;
3504 status = UDFReadExtent(Vcb, &(FileInfo->Dloc->DataLoc), 0, (uint32)NewLength, FALSE, OldInIcb, &WrittenBytes);
3505 if(!OS_SUCCESS(status)) {
3506 MyFreePool__(OldInIcb);
3507 return status;
3508 }
3509 } else {
3510 OldInIcb = NULL;
3511 }
3512 // allocate storage for new mapping
3515 if(!(NewMap)) {
3516 MyFreePool__(OldInIcb);
3518 }
3519 // free old location...
3520 if(FileInfo->Dloc->DataLoc.Mapping[0].extLocation !=
3521 FileInfo->Dloc->FELoc.Mapping[0].extLocation) {
3522 ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3523mark_data_map_0:
3524 UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, FileInfo->Dloc->DataLoc.Mapping, AS_DISCARDED); // free
3525 } else {
3526 if((FileInfo->Dloc->DataLoc.Mapping[0].extLength & UDF_EXTENT_LENGTH_MASK)
3527 > Vcb->LBlockSize) {
3528 BrutePoint();
3529 FileInfo->Dloc->DataLoc.Mapping[0].extLength -= Vcb->LBlockSize;
3530 FileInfo->Dloc->DataLoc.Mapping[0].extLocation += (1 << Vcb->LB2B_Bits);
3531 goto mark_data_map_0;
3532 }
3533 UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->DataLoc.Mapping[1]), AS_DISCARDED); // free
3534 }
3535 if(FileInfo->Dloc->AllocLoc.Mapping) {
3536 if((FileInfo->Dloc->AllocLoc.Mapping[0].extLength & UDF_EXTENT_LENGTH_MASK)
3537 > Vcb->LBlockSize) {
3538 FileInfo->Dloc->AllocLoc.Mapping[0].extLength -= Vcb->LBlockSize;
3539 FileInfo->Dloc->AllocLoc.Mapping[0].extLocation += (1 << Vcb->LB2B_Bits);
3540 UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, FileInfo->Dloc->AllocLoc.Mapping, AS_DISCARDED); // free
3541 } else {
3542 UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->AllocLoc.Mapping[1]), AS_DISCARDED); // free
3543 }
3544 MyFreePool__(FileInfo->Dloc->AllocLoc.Mapping);
3545 }
3546 MyFreePool__(FileInfo->Dloc->DataLoc.Mapping);
3547 FileInfo->Dloc->AllocLoc.Mapping = NULL;
3548 FileInfo->Dloc->AllocLoc.Length = 0;
3549 FileInfo->Dloc->AllocLoc.Offset = 0;
3550 FileInfo->Dloc->AllocLoc.Modified = TRUE;
3551 // switch to IN_ICB mode
3552 ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK;
3553 ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags |= ICB_FLAG_AD_IN_ICB;
3554 // init new data location descriptors
3555 FileInfo->Dloc->DataLoc.Mapping = NewMap;
3556 RtlZeroMemory((int8*)(FileInfo->Dloc->DataLoc.Mapping), 2*sizeof(EXTENT_MAP));
3557 FileInfo->Dloc->DataLoc.Mapping[0] = FileInfo->Dloc->FELoc.Mapping[0];
3558 FileInfo->Dloc->DataLoc.Length = NewLength;
3559 FileInfo->Dloc->DataLoc.Offset = FileInfo->Dloc->FileEntryLen;
3560 // write data to new location
3561 if(OldInIcb) {
3562 status = UDFWriteExtent(Vcb, &(FileInfo->Dloc->DataLoc), 0, (uint32)NewLength, FALSE, OldInIcb, &WrittenBytes);
3563 } else {
3565 }
3566 FileInfo->Dloc->DataLoc.Modified = TRUE;
3567 if(OldInIcb) MyFreePool__(OldInIcb);
3568 } else {
3569 // just modify Length field
3570 FileInfo->Dloc->DataLoc.Length = NewLength;
3572 }
3573 } else {
3574 // resize extent
3575 ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3576 PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation);
3577 status = UDFResizeExtent(Vcb, PartNum, NewLength, FALSE, &(FileInfo->Dloc->DataLoc));
3578 FileInfo->Dloc->DataLoc.Modified = TRUE;
3579 FileInfo->Dloc->AllocLoc.Modified = TRUE;
3580 }
3581 if(OS_SUCCESS(status)) {
3583 }
3584
3585#ifdef UDF_DBG
3586 if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
3587 ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping));
3588 } else {
3589 ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) ==
3590 ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)));
3591 }
3592#endif // UDF_DBG
3593
3594 return status;
3595} // end UDFResizeFile__()
3596#endif //UDF_READ_ONLY_BUILD
3597
3598/*
3599 This routine loads VAT.
3600 */
3603 IN PVCB Vcb,
3604 IN uint32 PartNdx
3605 )
3606{
3607 lb_addr VatFELoc;
3609 PUDF_FILE_INFO VatFileInfo;
3610 uint32 len, i=0, j, to_read;
3611 uint32 Offset, hdrOffset;
3613 uint32 root;
3614 uint16 PartNum;
3615// uint32 VatFirstLba = 0;
3616 int8* VatOldData;
3617 uint32 VatLba[6] = { Vcb->LastLBA,
3618 Vcb->LastLBA - 2,
3619 Vcb->LastLBA - 3,
3620 Vcb->LastLBA - 5,
3621 Vcb->LastLBA - 7,
3622 0 };
3623
3624 if(Vcb->Vat) return STATUS_SUCCESS;
3625 if(!Vcb->CDR_Mode) return STATUS_SUCCESS;
3626 // disable VAT for now. We'll reenable it if VAT is successfuly loaded
3627 Vcb->CDR_Mode = FALSE;
3628 PartNum = Vcb->Partitions[PartNdx].PartitionNum;
3629 root = Vcb->Partitions[PartNdx].PartitionRoot;
3630 if(Vcb->LBlockSize != Vcb->BlockSize) {
3631 // don't know how to operate... :(((
3633 }
3634 if((Vcb->LastTrackNum > 1) &&
3635 (Vcb->LastLBA == Vcb->TrackMap[Vcb->LastTrackNum-1].LastLba)) {
3636 UDFPrint(("Hardware Read-only volume\n"));
3638 }
3639
3641 if(!VatFileInfo) return STATUS_INSUFFICIENT_RESOURCES;
3642 // load VAT FE (we know its location)
3643 VatFELoc.partitionReferenceNum = PartNum;
3644retry_load_vat:
3645 VatFELoc.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, VatLba[i]);
3646 if(!OS_SUCCESS(status = UDFOpenRootFile__(Vcb, &VatFELoc, VatFileInfo))) {
3647 UDFCleanUpFile__(Vcb, VatFileInfo);
3648 // try another location
3649 i++;
3650 if( VatLba[i] &&
3652 (status != STATUS_CRC_ERROR)) goto retry_load_vat;
3653 MyFreePool__(VatFileInfo);
3654 Vcb->VatFileInfo = NULL;
3655 return status;
3656 }
3657 len = (uint32)UDFGetFileSize(VatFileInfo);
3658 if(Vcb->Partitions[PartNdx].PartitionType == UDF_VIRTUAL_MAP15) {
3659 // load Vat 1.50 header
3660 UDFPrint(("Load VAT 1.50\n"));
3662 if(((icbtag*)(VatFileInfo->Dloc->FileEntry+1))->fileType != UDF_FILE_TYPE_VAT15) {
3664 goto err_vat_15;
3665 }
3667 if(!Buf) {
3668err_vat_15_2:
3670err_vat_15:
3671 UDFCloseFile__(Vcb, VatFileInfo);
3672 UDFCleanUpFile__(Vcb, VatFileInfo);
3673 MyFreePool__(VatFileInfo);
3674 Vcb->VatFileInfo = NULL;
3675 return status;
3676 }
3677 Offset = 0;
3678 to_read =
3679 hdrOffset = len - sizeof(VirtualAllocationTable15);
3680 MyFreePool__(Buf);
3681
3682 Vcb->minUDFReadRev =
3683 Vcb->minUDFWriteRev =
3684 Vcb->maxUDFWriteRev = 0x0150;
3685
3686 Vcb->numFiles =
3687 Vcb->numDirs = -1;
3688
3689 } else
3690 if(Vcb->Partitions[PartNdx].PartitionType == UDF_VIRTUAL_MAP20) {
3691 // load Vat 2.00 header
3692 UDFPrint(("Load VAT 2.00\n"));
3694 if(((icbtag*)(VatFileInfo->Dloc->FileEntry+1))->fileType != UDF_FILE_TYPE_VAT20) {
3696 goto err_vat_15;
3697 }
3699 if(!Buf) goto err_vat_15_2;
3700 Offset = Buf->lengthHeader;
3701 to_read = len - Offset;
3702 hdrOffset = 0;
3703 MyFreePool__(Buf);
3704
3705 Vcb->minUDFReadRev = Buf->minReadRevision;
3706 Vcb->minUDFWriteRev = Buf->minWriteRevision;
3707 Vcb->maxUDFWriteRev = Buf->maxWriteRevision;
3708
3709 Vcb->numFiles = Buf->numFIDSFiles;
3710 Vcb->numDirs = Buf->numFIDSDirectories;
3711
3712 } else {
3713 // unknown (or wrong) VAT format
3714 UDFPrint(("unknown (or wrong) VAT format\n"));
3716 goto err_vat_15;
3717 }
3718 // read VAT & remember old version
3719 Vcb->Vat = (uint32*)DbgAllocatePool(NonPagedPool, (Vcb->LastPossibleLBA+1)*sizeof(uint32) );
3720 if(!Vcb->Vat) {
3721 goto err_vat_15_2;
3722 }
3723 // store base version of VAT in memory
3724 VatOldData = (int8*)DbgAllocatePool(PagedPool, len);
3725 if(!VatOldData) {
3726 DbgFreePool(Vcb->Vat);
3727 Vcb->Vat = NULL;
3728 goto err_vat_15_2;
3729 }
3730 status = UDFReadFile__(Vcb, VatFileInfo, 0, len, FALSE, VatOldData, &ReadBytes);
3731 if(!OS_SUCCESS(status)) {
3732 UDFCloseFile__(Vcb, VatFileInfo);
3733 UDFCleanUpFile__(Vcb, VatFileInfo);
3734 MyFreePool__(VatFileInfo);
3735 DbgFreePool(Vcb->Vat);
3736 DbgFreePool(VatOldData);
3737 Vcb->Vat = NULL;
3738 Vcb->VatFileInfo = NULL;
3739 } else {
3740 // initialize VAT
3741 // !!! NOTE !!!
3742 // Both VAT copies - in-memory & on-disc
3743 // contain _relative_ addresses
3744 len = Vcb->NWA - root;
3745 for(i=0; i<=len; i++) {
3746 Vcb->Vat[i] = i;
3747 }
3748 RtlCopyMemory(Vcb->Vat, VatOldData+Offset, to_read);
3749 Vcb->InitVatCount =
3750 Vcb->VatCount = to_read/sizeof(uint32);
3751 Vcb->VatPartNdx = PartNdx;
3752 Vcb->CDR_Mode = TRUE;
3753 len = Vcb->VatCount;
3754 RtlFillMemory(&(Vcb->Vat[Vcb->NWA-root]), (Vcb->LastPossibleLBA-Vcb->NWA+1)*sizeof(uint32), 0xff);
3755 // sync VAT and FSBM
3756 for(i=0; i<len; i++) {
3757 if(Vcb->Vat[i] == UDF_VAT_FREE_ENTRY) {
3758 UDFSetFreeBit(Vcb->FSBM_Bitmap, root+i);
3759 }
3760 }
3761 len = Vcb->LastPossibleLBA;
3762 // "pre-format" reserved area
3763 for(i=Vcb->NWA; i<len;) {
3764 for(j=0; (j<PACKETSIZE_UDF) && (i<len); j++, i++)
3765 UDFSetFreeBit(Vcb->FSBM_Bitmap, i);
3766 for(j=0; (j<7) && (i<len); j++, i++)
3767 UDFSetUsedBit(Vcb->FSBM_Bitmap, i);
3768 }
3769 DbgFreePool(VatOldData);
3770 }
3771 return status;
3772} // end UDFLoadVAT()
3773
3774/*
3775 Reads Extended Attributes
3776 Caller should use UDFGetFileEALength to allocate Buffer of sufficient
3777 size
3778 *//*
3779OSSTATUS
3780UDFReadFileEA(
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
3805UDFIsDeleted(
3806 IN PDIR_INDEX DirNdx
3807 )
3808{
3809 return (DirNdx->FileCharacteristics & FILE_DELETED);
3810} */
3811
3812/*BOOLEAN
3813UDFIsADirectory(
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
3828UDFGetFileAllocationSize(
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 */
3843BOOLEAN
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 */
3865 IN PVCB Vcb,
3867 IN uint32 PartNum
3868 )
3869{
3870 int8* NewAllocDescs;
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
3890retry_flush_FE:
3891 UDFPrint((" FlushFE: %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation));
3892#ifndef UDF_READ_ONLY_BUILD
3894 if(FileInfo->Dloc->DataLoc.Modified ||
3895 FileInfo->Dloc->AllocLoc.Modified) {
3896 ASSERT(PartNum != (uint32)(-1));
3897 // prepare new AllocDescs for flushing...
3898 if(!OS_SUCCESS(status = UDFBuildAllocDescs(Vcb, PartNum, FileInfo, &NewAllocDescs))) {
3899 UDFPrint((" FlushFE: UDFBuildAllocDescs() faliled (%x)\n", status));
3900 if(NewAllocDescs)
3901 MyFreePool__(NewAllocDescs);
3902 return status;
3903 }
3904#ifdef UDF_DBG
3905 if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
3906 ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping));
3907 } else {
3908 ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) ==
3909 ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)));
3910 }
3911 AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK;
3912#endif // UDF_DBG
3913 // initiate update of lengthAllocDescs
3914 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
3915 if(NewAllocDescs) {
3916 ASSERT(AllocMode != ICB_FLAG_AD_IN_ICB);
3917 status = UDFPadLastSector(Vcb, &(FileInfo->Dloc->AllocLoc));
3918 // ... and flush it
3919 status = UDFWriteExtent(Vcb, &(FileInfo->Dloc->AllocLoc), 0, (uint32)(FileInfo->Dloc->AllocLoc.Length), FALSE, NewAllocDescs, &WrittenBytes);
3920 MyFreePool__(NewAllocDescs);
3921 if(!OS_SUCCESS(status)) {
3922 UDFPrint((" FlushFE: UDFWriteExtent() faliled (%x)\n", status));
3923 return status;
3924 }
3925#ifdef UDF_DBG
3926 } else {
3927 ASSERT(AllocMode == ICB_FLAG_AD_IN_ICB);
3928#endif // UDF_DBG
3929 }
3930 FileInfo->Dloc->DataLoc.Modified = FALSE;
3931 FileInfo->Dloc->AllocLoc.Modified = FALSE;
3932 } else {
3933#if defined(UDF_DBG) && !defined(UDF_CHECK_UTIL)
3934 if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) {
3935 ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping));
3936 } else {
3937 ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) ==
3938 ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)));
3939 }
3940#endif // UDF_DBG
3941 }
3942/* if(FileInfo->Fcb &&
3943 ((FileInfo->Dloc->FELoc.Mapping[0].extLocation > Vcb->LastLBA) ||
3944 UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) ) {
3945 BrutePoint();
3946 }*/
3947/* if(FileInfo->Dloc->FELoc.Mapping[0].extLocation) {
3948 ASSERT( FileInfo->Dloc->FileEntry->tagLocation ==
3949 (FileInfo->Dloc->FELoc.Mapping[0].extLocation - 0x580));
3950 }*/
3951 if((FileInfo->Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) ||
3952 FileInfo->Dloc->FELoc.Modified) {
3953 ASSERT(PartNum != (uint32)(-1));
3954 ASSERT(!PartNum);
3955 if(PartNum == (uint32)(-1) || PartNum == (uint32)(-2)) {
3956 UDFPrint((" bad PartNum: %d\n", PartNum));
3957 }
3958 // update lengthAllocDescs in FE
3960/* ASSERT( FileInfo->Dloc->FileEntry->tagLocation ==
3961 (FileInfo->Dloc->FELoc.Mapping[0].extLocation - 0x580));*/
3962 // flush FileEntry
3963
3964 // if FE is located in remapped block, place it to reliable space
3965 lba = FileInfo->Dloc->FELoc.Mapping[0].extLocation;
3966 if(Vcb->BSBM_Bitmap) {
3967 if(UDFGetBadBit((uint32*)(Vcb->BSBM_Bitmap), lba)) {
3968 AdPrint((" bad block under FE @%x\n", lba));
3969 goto relocate_FE;
3970 }
3971 }
3972
3973 AdPrint((" setup tag: @%x\n", lba));
3974 ASSERT( lba );
3975 UDFSetUpTag(Vcb, FileInfo->Dloc->FileEntry, (uint16)(FileInfo->Dloc->FileEntryLen),
3976 UDFPhysLbaToPart(Vcb, PartNum, lba));
3977 status = UDFWriteExtent(Vcb, &(FileInfo->Dloc->FELoc), 0,
3978 (uint32)(FileInfo->Dloc->FELoc.Length), FALSE,
3979 (int8*)(FileInfo->Dloc->FileEntry), &WrittenBytes);
3980 if(!OS_SUCCESS(status)) {
3981 UDFPrint((" FlushFE: UDFWriteExtent(2) faliled (%x)\n", status));
3983relocate_FE:
3984 UDFPrint((" try to relocate\n"));
3985
3986 EXTENT_INFO _FEExtInfo;
3987 // calculate the length required
3988
3989 // allocate block for FE
3990 if(OS_SUCCESS(UDFAllocateFESpace(Vcb, FileInfo->ParentFile, PartNum, &_FEExtInfo, (uint32)(FileInfo->Dloc->FELoc.Length)) )) {
3991 UDFPrint((" relocate %x -> %x\n",
3992 lba,
3993 _FEExtInfo.Mapping[0].extLocation));
3994
3995 UDFMarkSpaceAsXXX(Vcb, 0, FileInfo->Dloc->FELoc.Mapping, AS_BAD);
3996
3997 UDFRelocateDloc(Vcb, FileInfo->Dloc, _FEExtInfo.Mapping[0].extLocation);
3998 MyFreePool__(FileInfo->Dloc->FELoc.Mapping);
3999 FileInfo->Dloc->FELoc.Mapping = _FEExtInfo.Mapping;
4000
4001 FileInfo->Dloc->FELoc.Modified = TRUE;
4002 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED;
4003
4004 AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK;
4005 if(AllocMode == ICB_FLAG_AD_IN_ICB) {
4006 UDFPrint((" IN-ICB data lost\n"));
4007 FileInfo->Dloc->DataLoc.Mapping[0].extLocation = _FEExtInfo.Mapping[0].extLocation;
4008 FileInfo->Dloc->DataLoc.Modified = TRUE;
4009 } else {
4010 FileInfo->Dloc->AllocLoc.Mapping[0].extLocation = _FEExtInfo.Mapping[0].extLocation;
4011 FileInfo->Dloc->AllocLoc.Modified = TRUE;
4012 }
4013
4014 if(FileInfo->Index >= 2) {
4015 PDIR_INDEX_ITEM DirNdx;
4017 if(DirNdx) {
4018 UDFPrint((" update reference in FI\n"));
4020 FileInfo->FileIdent->icb.extLocation.logicalBlockNum =
4021 UDFPhysLbaToPart(Vcb, PartNum, _FEExtInfo.Mapping[0].extLocation);
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
4052 IN PVCB Vcb,
4054 IN uint32 PartNum
4055 )
4056{
4057 PUDF_FILE_INFO DirInfo = FileInfo->ParentFile;
4058 PDIR_INDEX_ITEM DirNdx;
4060 SIZE_T WrittenBytes;
4061 // use WrittenBytes variable to store LBA of FI to be recorded
4062 #define lba WrittenBytes
4063
4064// ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation);
4065 // some files has no FI
4066 if(!DirInfo || UDFIsAStreamDir(FileInfo))
4067 return STATUS_SUCCESS;
4068 DirNdx = UDFDirIndex(DirInfo->Dloc->DirIndex, FileInfo->Index);
4069// ASSERT(FileInfo->FileIdent->lengthFileIdent < 0x80);
4070#ifdef UDF_DBG
4071 if(DirNdx->FileCharacteristics & FILE_DELETED) {
4072 ASSERT(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED);
4073 }
4074#endif // UDF_DBG
4075 UDFPrint((" FlushFI: offs %x\n", (ULONG)(DirNdx->Offset)));
4076#ifndef UDF_READ_ONLY_BUILD
4077 if((DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) {
4078 // flush FileIdent
4079 ASSERT(PartNum != (uint32)(-1));
4080 FileInfo->FileIdent->fileCharacteristics = DirNdx->FileCharacteristics;
4082 DirNdx->Offset, NULL, NULL, NULL, NULL);
4083 AdPrint((" FI lba %x\n", lba));
4084 // check if requested Offset is allocated
4085 if(lba == (uint32)LBA_OUT_OF_EXTENT) {
4086 // write 1 byte
4087 if(!OS_SUCCESS(status = UDFWriteFile__(Vcb, DirInfo, DirNdx->Offset, 1, FALSE, (int8*)(FileInfo->FileIdent), &WrittenBytes) )) {
4088 BrutePoint();
4089 return status;
4090 }
4092 DirNdx->Offset, NULL, NULL, NULL, NULL);
4093 AdPrint((" allocated FI lba %x\n", lba));
4094 // check if requested Offset is allocated
4095 if(lba == (uint32)LBA_OUT_OF_EXTENT) {
4096 BrutePoint();
4097 return STATUS_UNSUCCESSFUL;
4098 }
4099 }
4100 // init structure
4101 UDFSetUpTag(Vcb, &(FileInfo->FileIdent->descTag), (uint16)(FileInfo->FileIdentLen),
4102 UDFPhysLbaToPart(Vcb, PartNum, lba));
4103 // record data
4104 if(!OS_SUCCESS(status = UDFWriteFile__(Vcb, DirInfo, DirNdx->Offset, FileInfo->FileIdentLen, FALSE, (int8*)(FileInfo->FileIdent), &WrittenBytes) )) {
4105 BrutePoint();
4106 return status;
4107 }
4108 DirNdx->FI_Flags &= ~UDF_FI_FLAG_FI_MODIFIED;
4109 }
4110#endif //UDF_READ_ONLY_BUILD
4111 return STATUS_SUCCESS;
4112} // end UDFFlushFI()
4113
4114/*
4115 This routine updates AllocDesc sequence, FileIdent & FileEntry
4116 for given file
4117 */
4120 IN PVCB Vcb,
4122 IN ULONG FlushFlags
4123 )
4124{
4126
4127 if(!FileInfo) return STATUS_SUCCESS;
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
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)) {
4170full_flush:
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));
4176 if(OS_SUCCESS(status)) {
4177 AdPrint(("Dir pre-alloc truncated (Flush)\n"));
4178 FileInfo->Dloc->DataLoc.Modified = TRUE;
4179 }
4180