1 //////////////////////////////////////////////////////////////////// 2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine 3 // All rights reserved 4 // This file was released under the GPLv2 on June 2015. 5 //////////////////////////////////////////////////////////////////// 6 /* 7 Module name: 8 9 udf_info.cpp 10 11 Abstract: 12 13 This file contains filesystem-specific routines 14 15 */ 16 17 #include "udf.h" 18 19 #define UDF_BUG_CHECK_ID UDF_FILE_UDF_INFO 20 21 #ifdef _X86_ 22 static const int8 valid_char_arr[] = 23 {1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, 24 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, 25 1,0,1,0, 0,0,0,0, 0,0,1,1, 1,0,0,1, 26 0,0,0,0, 0,0,0,0, 0,0,1,1, 1,1,1,1, 27 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // @ABCDE.... 28 0,0,0,0, 0,0,0,0, 0,0,0,1, 1,1,0,0, // ....Z[/]^_ 29 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // `abcde.... 30 0,0,0,0, 0,0,0,0, 0,0,0,1, 1,1,0,1, // ....z{|}~ 31 32 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 33 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 34 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 35 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 36 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 37 1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 38 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 39 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}; 40 #else // NO X86 optimization , use generic C/C++ 41 static const char valid_char_arr[] = {"*/:?\"<>|\\"}; 42 #endif // _X86_ 43 44 #define DOS_CRC_MODULUS 41 45 #define hexChar crcChar 46 static const char crcChar[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ#_~-@"; 47 48 /* Used to convert hex digits to ASCII for readability. */ 49 //static const char hexChar[] = "0123456789ABCDEF"; 50 51 static const uint16 CrcTable[256] = { 52 0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50a5U, 0x60c6U, 0x70e7U, 53 0x8108U, 0x9129U, 0xa14aU, 0xb16bU, 0xc18cU, 0xd1adU, 0xe1ceU, 0xf1efU, 54 0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52b5U, 0x4294U, 0x72f7U, 0x62d6U, 55 0x9339U, 0x8318U, 0xb37bU, 0xa35aU, 0xd3bdU, 0xc39cU, 0xf3ffU, 0xe3deU, 56 0x2462U, 0x3443U, 0x0420U, 0x1401U, 0x64e6U, 0x74c7U, 0x44a4U, 0x5485U, 57 0xa56aU, 0xb54bU, 0x8528U, 0x9509U, 0xe5eeU, 0xf5cfU, 0xc5acU, 0xd58dU, 58 0x3653U, 0x2672U, 0x1611U, 0x0630U, 0x76d7U, 0x66f6U, 0x5695U, 0x46b4U, 59 0xb75bU, 0xa77aU, 0x9719U, 0x8738U, 0xf7dfU, 0xe7feU, 0xd79dU, 0xc7bcU, 60 0x48c4U, 0x58e5U, 0x6886U, 0x78a7U, 0x0840U, 0x1861U, 0x2802U, 0x3823U, 61 0xc9ccU, 0xd9edU, 0xe98eU, 0xf9afU, 0x8948U, 0x9969U, 0xa90aU, 0xb92bU, 62 0x5af5U, 0x4ad4U, 0x7ab7U, 0x6a96U, 0x1a71U, 0x0a50U, 0x3a33U, 0x2a12U, 63 0xdbfdU, 0xcbdcU, 0xfbbfU, 0xeb9eU, 0x9b79U, 0x8b58U, 0xbb3bU, 0xab1aU, 64 0x6ca6U, 0x7c87U, 0x4ce4U, 0x5cc5U, 0x2c22U, 0x3c03U, 0x0c60U, 0x1c41U, 65 0xedaeU, 0xfd8fU, 0xcdecU, 0xddcdU, 0xad2aU, 0xbd0bU, 0x8d68U, 0x9d49U, 66 0x7e97U, 0x6eb6U, 0x5ed5U, 0x4ef4U, 0x3e13U, 0x2e32U, 0x1e51U, 0x0e70U, 67 0xff9fU, 0xefbeU, 0xdfddU, 0xcffcU, 0xbf1bU, 0xaf3aU, 0x9f59U, 0x8f78U, 68 0x9188U, 0x81a9U, 0xb1caU, 0xa1ebU, 0xd10cU, 0xc12dU, 0xf14eU, 0xe16fU, 69 0x1080U, 0x00a1U, 0x30c2U, 0x20e3U, 0x5004U, 0x4025U, 0x7046U, 0x6067U, 70 0x83b9U, 0x9398U, 0xa3fbU, 0xb3daU, 0xc33dU, 0xd31cU, 0xe37fU, 0xf35eU, 71 0x02b1U, 0x1290U, 0x22f3U, 0x32d2U, 0x4235U, 0x5214U, 0x6277U, 0x7256U, 72 0xb5eaU, 0xa5cbU, 0x95a8U, 0x8589U, 0xf56eU, 0xe54fU, 0xd52cU, 0xc50dU, 73 0x34e2U, 0x24c3U, 0x14a0U, 0x0481U, 0x7466U, 0x6447U, 0x5424U, 0x4405U, 74 0xa7dbU, 0xb7faU, 0x8799U, 0x97b8U, 0xe75fU, 0xf77eU, 0xc71dU, 0xd73cU, 75 0x26d3U, 0x36f2U, 0x0691U, 0x16b0U, 0x6657U, 0x7676U, 0x4615U, 0x5634U, 76 0xd94cU, 0xc96dU, 0xf90eU, 0xe92fU, 0x99c8U, 0x89e9U, 0xb98aU, 0xa9abU, 77 0x5844U, 0x4865U, 0x7806U, 0x6827U, 0x18c0U, 0x08e1U, 0x3882U, 0x28a3U, 78 0xcb7dU, 0xdb5cU, 0xeb3fU, 0xfb1eU, 0x8bf9U, 0x9bd8U, 0xabbbU, 0xbb9aU, 79 0x4a75U, 0x5a54U, 0x6a37U, 0x7a16U, 0x0af1U, 0x1ad0U, 0x2ab3U, 0x3a92U, 80 0xfd2eU, 0xed0fU, 0xdd6cU, 0xcd4dU, 0xbdaaU, 0xad8bU, 0x9de8U, 0x8dc9U, 81 0x7c26U, 0x6c07U, 0x5c64U, 0x4c45U, 0x3ca2U, 0x2c83U, 0x1ce0U, 0x0cc1U, 82 0xef1fU, 0xff3eU, 0xcf5dU, 0xdf7cU, 0xaf9bU, 0xbfbaU, 0x8fd9U, 0x9ff8U, 83 0x6e17U, 0x7e36U, 0x4e55U, 0x5e74U, 0x2e93U, 0x3eb2U, 0x0ed1U, 0x1ef0U 84 }; 85 86 static const uint32 crc32_tab[] = { 87 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 88 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 89 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 90 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 91 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 92 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 93 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 94 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 95 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 96 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 97 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 98 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 99 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 100 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 101 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 102 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, 103 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 104 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 105 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 106 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 107 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 108 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 109 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 110 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 111 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 112 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 113 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 114 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 115 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, 116 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 117 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 118 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 119 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 120 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 121 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 122 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 123 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 124 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 125 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 126 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, 127 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 128 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 129 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 130 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 131 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 132 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 133 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 134 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 135 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 136 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 137 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 138 0x2d02ef8dL 139 }; 140 141 /* 142 This routine allocates new memory block, copies data there & free old one 143 */ 144 /*uint32 145 UDFMemRealloc( 146 int8* OldBuff, 147 uint32 OldLength, 148 int8** NewBuff, 149 uint32 NewLength 150 ) 151 { 152 int8* new_buff; 153 154 (*NewBuff) = OldBuff; 155 if(OldLength == NewLength) return OldLength; 156 new_buff = (int8*)MyAllocatePool__(NonPagedPool, NewLength); 157 if(!new_buff) return 0; 158 if(OldLength > NewLength) OldLength = NewLength; 159 RtlCopyMemory(new_buff, OldBuff, OldLength); 160 MyFreePool__(OldBuff); 161 (*NewBuff) = new_buff; 162 return OldLength; 163 } // end UDFMemRealloc()*/ 164 165 /* 166 This routine converts compressed Unicode to standard 167 */ 168 void 169 __fastcall 170 UDFDecompressUnicode( 171 IN OUT PUNICODE_STRING UName, 172 IN uint8* CS0, 173 IN SIZE_T Length, 174 OUT uint16* valueCRC 175 ) 176 { 177 uint16 compID = CS0[0]; 178 uint32 unicodeIndex = 0; 179 uint32 byteIndex = 1; 180 PWCHAR buff; 181 uint8* _CS0 = CS0+1; 182 183 if(!Length) goto return_empty_str; 184 // First check for valid compID. 185 switch(compID) { 186 case UDF_COMP_ID_8: { 187 188 buff = (PWCHAR)MyAllocatePoolTag__(UDF_FILENAME_MT, (Length)*sizeof(WCHAR), MEM_FNAME_TAG); 189 if(!buff) goto return_empty_str; 190 UName->Buffer = buff; 191 192 // Loop through all the bytes. 193 while (byteIndex < Length) { 194 (*buff) = (*_CS0); 195 _CS0++; 196 byteIndex++; 197 buff++; 198 } 199 unicodeIndex = byteIndex-1; 200 break; 201 } 202 case UDF_COMP_ID_16: { 203 204 buff = (PWCHAR)MyAllocatePoolTag__(UDF_FILENAME_MT, (Length-1)+sizeof(WCHAR), MEM_FNAME16_TAG); 205 if(!buff) goto return_empty_str; 206 UName->Buffer = buff; 207 208 // Loop through all the bytes. 209 while (byteIndex < Length) { 210 // Move the first byte to the high bits of the unicode char. 211 *buff = ((*_CS0) << 8) | (*(_CS0+1)); 212 _CS0+=2; 213 byteIndex+=2; 214 unicodeIndex++; 215 buff++; 216 ASSERT(byteIndex <= Length); 217 } 218 break; 219 } 220 default: { 221 return_empty_str: 222 UName->Buffer = NULL; 223 UName->MaximumLength = 224 UName->Length = 0; 225 return; 226 } 227 } 228 UName->MaximumLength = (UName->Length = (((uint16)unicodeIndex)*sizeof(WCHAR))) + sizeof(WCHAR); 229 UName->Buffer[unicodeIndex] = 0; 230 if(valueCRC) { 231 *valueCRC = UDFCrc(CS0+1, Length-1); 232 } 233 } // end UDFDecompressUnicode() 234 235 /* 236 This routine converts standard Unicode to compressed 237 */ 238 void 239 __fastcall 240 UDFCompressUnicode( 241 IN PUNICODE_STRING UName, 242 IN OUT uint8** _CS0, 243 IN OUT PSIZE_T Length 244 ) 245 { 246 uint8* CS0; 247 uint8 compID; 248 uint16 unicodeIndex; 249 uint32 i, len; 250 PWCHAR Buff; 251 252 len = (UName->Length) / sizeof(WCHAR); 253 compID = (!len) ? 0 : UDF_COMP_ID_8; 254 // check for uncompressable characters 255 Buff = UName->Buffer; 256 for(i=0; i<len; i++, Buff++) { 257 if((*Buff) & 0xff00) { 258 compID = UDF_COMP_ID_16; 259 break; 260 } 261 } 262 263 CS0 = (uint8*)MyAllocatePool__(NonPagedPool, *Length = (((compID==UDF_COMP_ID_8) ? 1 : 2)*len + 1) ); 264 if(!CS0) return; 265 266 CS0[0] = compID; 267 *_CS0 = CS0; 268 // init loop 269 CS0++; 270 unicodeIndex = 0; 271 Buff = UName->Buffer; 272 if(compID == UDF_COMP_ID_16) { 273 // Loop through all the bytes. 274 while (unicodeIndex < len) { 275 // Move the 2nd byte to the low bits of the compressed unicode char. 276 *CS0 = (uint8)((*Buff) >> 8); 277 CS0++; 278 *CS0 = (uint8)(*Buff); 279 CS0++; 280 Buff++; 281 unicodeIndex++; 282 } 283 } else { 284 // Loop through all the bytes. 285 while (unicodeIndex < len) { 286 *CS0 = (uint8)(*Buff); 287 CS0++; 288 Buff++; 289 unicodeIndex++; 290 } 291 } 292 } // end UDFCompressUnicode() 293 294 /* 295 OSSTATUS UDFFindFile__(IN PVCB Vcb, 296 IN BOOLEAN IgnoreCase, 297 IN PUNICODE_STRING Name, 298 IN PUDF_FILE_INFO DirInfo) 299 see 'Udf_info.h' 300 */ 301 302 /* 303 This routine reads (Extended)FileEntry according to FileDesc 304 */ 305 OSSTATUS 306 UDFReadFileEntry( 307 IN PVCB Vcb, 308 IN long_ad* Icb, 309 IN OUT PFILE_ENTRY FileEntry, // here we can also get ExtendedFileEntry 310 IN OUT uint16* Ident 311 ) 312 { 313 OSSTATUS status; 314 315 if(!OS_SUCCESS(status = UDFReadTagged(Vcb, (int8*)FileEntry, 316 UDFPartLbaToPhys(Vcb,&(Icb->extLocation)), 317 Icb->extLocation.logicalBlockNum, 318 Ident))) return status; 319 if((FileEntry->descTag.tagIdent != TID_FILE_ENTRY) && 320 (FileEntry->descTag.tagIdent != TID_EXTENDED_FILE_ENTRY)) { 321 UDFPrint((" Not a FileEntry (lbn=%x, tag=%x)\n", Icb->extLocation.logicalBlockNum, FileEntry->descTag.tagIdent)); 322 return STATUS_FILE_CORRUPT_ERROR; 323 } 324 return STATUS_SUCCESS; 325 } // UDFReadFileEntry() 326 327 #if !defined (_X86_) || !defined (_MSC_VER) 328 /* 329 Decides if a Unicode character matches one of a list 330 of ASCII characters. 331 Used by DOS version of UDFIsIllegalChar for readability, since all of the 332 illegal characters above 0x0020 are in the ASCII subset of Unicode. 333 Works very similarly to the standard C function strchr(). 334 */ 335 BOOLEAN 336 UDFUnicodeInString( 337 IN uint8* string, // String to search through. 338 IN WCHAR ch // Unicode char to search for. 339 ) 340 { 341 BOOLEAN found = FALSE; 342 343 while(*string != '\0' && !found) { 344 // These types should compare, since both are unsigned numbers. 345 if(*string == ch) { 346 found = TRUE; 347 } 348 string++; 349 } 350 return(found); 351 } // end UDFUnicodeInString() 352 #endif // _X86_ 353 354 /* 355 Decides whether character passed is an illegal character for a 356 DOS file name. 357 */ 358 #ifdef _MSC_VER 359 #pragma warning(push) 360 #pragma warning(disable:4035) // re-enable below 361 #endif 362 363 #ifdef _X86_ 364 #ifdef _MSC_VER 365 __declspec (naked) 366 #endif 367 #endif // _X86_ 368 BOOLEAN 369 __fastcall 370 UDFIsIllegalChar( 371 IN WCHAR chr // ECX 372 ) 373 { 374 // Genuine illegal char's for DOS. 375 #if defined (_X86_) && defined (_MSC_VER) 376 _asm { 377 push ebx 378 379 xor eax,eax 380 // mov ax,chr 381 mov ax,cx 382 or ah,ah 383 jnz ERR_IIC 384 385 lea ebx,[valid_char_arr] 386 xlatb 387 jmp short ERR_IIC2 388 ERR_IIC: 389 mov al,1 390 ERR_IIC2: 391 392 pop ebx 393 ret 394 } 395 396 #else // NO X86 optimization , use generic C/C++ 397 /* FIXME */ 398 //return ((ch < 0x20) || UDFUnicodeInString((uint8*)&valid_char_arr, ch)); 399 return ((chr < 0x20) || UDFUnicodeInString((uint8*)&valid_char_arr, chr)); 400 #endif // _X86_ 401 } // end UDFIsIllegalChar() 402 403 #ifdef _MSC_VER 404 #pragma warning(pop) // re-enable warning #4035 405 #endif 406 407 /* 408 Translate udfName to dosName using OSTA compliant. 409 dosName must be a unicode string with min length of 12. 410 */ 411 412 /*void UDFDOSName__( 413 IN PVCB Vcb, 414 IN OUT PUNICODE_STRING DosName, 415 IN PUNICODE_STRING UdfName, 416 IN PUDF_FILE_INFO FileInfo 417 ) 418 { 419 BOOLEAN KeepIntact; 420 421 KeepIntact = (FileInfo && (FileInfo->Index < 2)); 422 UDFDOSName(Vcb, DosName, UdfName, KeepIntact); 423 }*/ 424 425 void 426 __fastcall 427 UDFDOSName( 428 IN PVCB Vcb, 429 IN OUT PUNICODE_STRING DosName, 430 IN PUNICODE_STRING UdfName, 431 IN BOOLEAN KeepIntact 432 ) 433 { 434 #ifndef _CONSOLE 435 if(Vcb->CompatFlags & UDF_VCB_IC_OS_NATIVE_DOS_NAME) { 436 UDFDOSNameOsNative(DosName, UdfName, KeepIntact); 437 return; 438 } 439 #endif //_CONSOLE 440 441 switch(Vcb->CurrentUDFRev) { 442 case 0x0100: 443 case 0x0101: 444 case 0x0102: 445 UDFDOSName100(DosName, UdfName, KeepIntact); 446 break; 447 448 case 0x0150: 449 // in general, we need bytes-from-media to 450 // create valid UDF 1.50 name. 451 // Curently it is impossible, thus, we'll use 452 // UDF 2.00 translation algorithm 453 case 0x0200: 454 UDFDOSName200(DosName, UdfName, KeepIntact, Vcb->CurrentUDFRev == 0x0150); 455 break; 456 457 case 0x0201: 458 default: 459 UDFDOSName201(DosName, UdfName, KeepIntact); 460 } 461 } 462 463 void 464 __fastcall 465 UDFDOSName100( 466 IN OUT PUNICODE_STRING DosName, 467 IN PUNICODE_STRING UdfName, 468 IN BOOLEAN KeepIntact 469 ) 470 { 471 PWCHAR dosName = DosName->Buffer; 472 PWCHAR udfName = UdfName->Buffer; 473 uint32 udfLen = UdfName->Length / sizeof(WCHAR); 474 475 uint32 index, dosIndex = 0, extIndex = 0, lastPeriodIndex; 476 BOOLEAN needsCRC = FALSE, hasExt = FALSE, writingExt = FALSE, isParent = FALSE; 477 uint32 valueCRC; 478 WCHAR ext[DOS_EXT_LEN], current; 479 480 if(KeepIntact && 481 (udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) { 482 isParent = TRUE; 483 if((udfLen == 2) && (udfName[1] != UNICODE_PERIOD)) 484 isParent = FALSE; 485 } 486 487 for (index = 0 ; index < udfLen ; index++) { 488 current = udfName[index]; 489 if (current == UNICODE_PERIOD && !isParent) { 490 if (dosIndex==0 || hasExt) { 491 // Ignore leading periods or any other than used for extension. 492 needsCRC = TRUE; 493 } else { 494 // First, find last character which is NOT a period or space. 495 lastPeriodIndex = udfLen - 1; 496 while(lastPeriodIndex >=0 && 497 (udfName[lastPeriodIndex] == UNICODE_PERIOD || 498 udfName[lastPeriodIndex] == UNICODE_SPACE)) 499 lastPeriodIndex--; 500 // Now search for last remaining period. 501 while(lastPeriodIndex >= 0 && 502 udfName[lastPeriodIndex] != UNICODE_PERIOD) 503 lastPeriodIndex--; 504 // See if the period we found was the last or not. 505 if (lastPeriodIndex != index) 506 needsCRC = TRUE; // If not, name needs translation. 507 // As long as the period was not trailing, 508 // the file name has an extension. 509 if (lastPeriodIndex >= 0) hasExt = TRUE; 510 } 511 } else { 512 if ((!hasExt && dosIndex == DOS_NAME_LEN) || 513 extIndex == DOS_EXT_LEN) { 514 // File name or extension is too long for DOS. 515 needsCRC = TRUE; 516 } else { 517 if (current == UNICODE_SPACE) { // Ignore spaces. 518 needsCRC = TRUE; 519 } else { 520 // Look for illegal or unprintable characters. 521 if (UDFIsIllegalChar(current) /*|| !UnicodeIsPrint(current)*/) { 522 needsCRC = TRUE; 523 current = ILLEGAL_CHAR_MARK; 524 /* Skip Illegal characters(even spaces), 525 * but not periods. 526 */ 527 while(index+1 < udfLen && 528 (UDFIsIllegalChar(udfName[index+1]) /*|| 529 !UnicodeIsPrint(udfName[index+1])*/) && 530 udfName[index+1] != UNICODE_PERIOD) 531 index++; 532 } 533 // Add current char to either file name or ext. 534 if (writingExt) { 535 ext[extIndex] = current; 536 extIndex++; 537 } else { 538 dosName[dosIndex] = current; 539 dosIndex++; 540 } 541 } 542 } 543 } 544 // See if we are done with file name, either because we reached 545 // the end of the file name length, or the final period. 546 if (!writingExt && hasExt && (dosIndex == DOS_NAME_LEN || 547 index == lastPeriodIndex)) { 548 // If so, and the name has an extension, start reading it. 549 writingExt = TRUE; 550 // Extension starts after last period. 551 index = lastPeriodIndex; 552 } 553 } 554 // 555 if (needsCRC) { 556 // Add CRC to end of file name or at position 4. 557 if (dosIndex >4) dosIndex = 4; 558 valueCRC = UDFUnicodeCksum(udfName, udfLen); 559 // set CRC prefix 560 dosName[dosIndex] = UNICODE_CRC_MARK; 561 // Convert 12-bit CRC to hex characters. 562 dosName[dosIndex+1] = hexChar[(valueCRC & 0x0f00) >> 8]; 563 dosName[dosIndex+2] = hexChar[(valueCRC & 0x00f0) >> 4]; 564 dosName[dosIndex+3] = hexChar[(valueCRC & 0x000f)]; 565 dosIndex+=4; 566 } 567 // Add extension, if any. 568 if (extIndex != 0) { 569 dosName[dosIndex] = UNICODE_PERIOD; 570 dosIndex++; 571 for (index = 0; index < extIndex; index++) { 572 dosName[dosIndex] = ext[index]; 573 dosIndex++; 574 } 575 } 576 DosName->Length = (uint16)dosIndex*sizeof(WCHAR); 577 RtlUpcaseUnicodeString(DosName, DosName, FALSE); 578 } // end UDFDOSName100() 579 580 void 581 __fastcall 582 UDFDOSName200( 583 IN OUT PUNICODE_STRING DosName, 584 IN PUNICODE_STRING UdfName, 585 IN BOOLEAN KeepIntact, 586 IN BOOLEAN Mode150 587 ) 588 { 589 PWCHAR dosName = DosName->Buffer; 590 PWCHAR udfName = UdfName->Buffer; 591 uint32 udfLen = UdfName->Length / sizeof(WCHAR); 592 593 uint32 index, dosIndex = 0, extIndex = 0, lastPeriodIndex; 594 BOOLEAN needsCRC = FALSE, hasExt = FALSE, writingExt = FALSE, isParent = FALSE; 595 uint32 valueCRC; 596 WCHAR ext[DOS_EXT_LEN], current; 597 598 if(KeepIntact && 599 (udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) { 600 isParent = TRUE; 601 if((udfLen == 2) && (udfName[1] != UNICODE_PERIOD)) 602 isParent = FALSE; 603 } 604 605 for (index = 0 ; index < udfLen ; index++) { 606 current = udfName[index]; 607 if (current == UNICODE_PERIOD && !isParent) { 608 if (dosIndex==0 || hasExt) { 609 // Ignore leading periods or any other than used for extension. 610 needsCRC = TRUE; 611 } else { 612 // First, find last character which is NOT a period or space. 613 lastPeriodIndex = udfLen - 1; 614 while(lastPeriodIndex >=0 && 615 (udfName[lastPeriodIndex] == UNICODE_PERIOD || 616 udfName[lastPeriodIndex] == UNICODE_SPACE)) 617 lastPeriodIndex--; 618 // Now search for last remaining period. 619 while(lastPeriodIndex >= 0 && 620 udfName[lastPeriodIndex] != UNICODE_PERIOD) 621 lastPeriodIndex--; 622 // See if the period we found was the last or not. 623 if (lastPeriodIndex != index) 624 needsCRC = TRUE; // If not, name needs translation. 625 // As long as the period was not trailing, 626 // the file name has an extension. 627 if (lastPeriodIndex >= 0) hasExt = TRUE; 628 } 629 } else { 630 if ((!hasExt && dosIndex == DOS_NAME_LEN) || 631 extIndex == DOS_EXT_LEN) { 632 // File name or extension is too long for DOS. 633 needsCRC = TRUE; 634 } else { 635 if (current == UNICODE_SPACE) { // Ignore spaces. 636 needsCRC = TRUE; 637 } else { 638 // Look for illegal or unprintable characters. 639 if (UDFIsIllegalChar(current) /*|| !UnicodeIsPrint(current)*/) { 640 needsCRC = TRUE; 641 current = ILLEGAL_CHAR_MARK; 642 /* Skip Illegal characters(even spaces), 643 * but not periods. 644 */ 645 while(index+1 < udfLen && 646 (UDFIsIllegalChar(udfName[index+1]) /*|| 647 !UnicodeIsPrint(udfName[index+1])*/) && 648 udfName[index+1] != UNICODE_PERIOD) 649 index++; 650 } 651 // Add current char to either file name or ext. 652 if (writingExt) { 653 ext[extIndex] = current; 654 extIndex++; 655 } else { 656 dosName[dosIndex] = current; 657 dosIndex++; 658 } 659 } 660 } 661 } 662 // See if we are done with file name, either because we reached 663 // the end of the file name length, or the final period. 664 if (!writingExt && hasExt && (dosIndex == DOS_NAME_LEN || 665 index == lastPeriodIndex)) { 666 // If so, and the name has an extension, start reading it. 667 writingExt = TRUE; 668 // Extension starts after last period. 669 index = lastPeriodIndex; 670 } 671 } 672 // Now handle CRC if needed. 673 if (needsCRC) { 674 // Add CRC to end of file name or at position 4. 675 if (dosIndex >4) dosIndex = 4; 676 valueCRC = Mode150 ? UDFUnicodeCksum150(udfName, udfLen) : UDFUnicodeCksum(udfName, udfLen); 677 // Convert 16-bit CRC to hex characters. 678 dosName[dosIndex] = hexChar[(valueCRC & 0xf000) >> 12]; 679 dosName[dosIndex+1] = hexChar[(valueCRC & 0x0f00) >> 8]; 680 dosName[dosIndex+2] = hexChar[(valueCRC & 0x00f0) >> 4]; 681 dosName[dosIndex+3] = hexChar[(valueCRC & 0x000f)]; 682 dosIndex+=4; 683 } 684 // Add extension, if any. 685 if (extIndex != 0) { 686 dosName[dosIndex] = UNICODE_PERIOD; 687 dosIndex++; 688 for (index = 0; index < extIndex; index++) { 689 dosName[dosIndex] = ext[index]; 690 dosIndex++; 691 } 692 } 693 DosName->Length = (uint16)dosIndex*sizeof(WCHAR); 694 RtlUpcaseUnicodeString(DosName, DosName, FALSE); 695 } // end UDFDOSName200() 696 697 698 void 699 __fastcall 700 UDFDOSName201( 701 IN OUT PUNICODE_STRING DosName, 702 IN PUNICODE_STRING UdfName, 703 IN BOOLEAN KeepIntact 704 ) 705 { 706 PWCHAR dosName = DosName->Buffer; 707 PWCHAR udfName = UdfName->Buffer; 708 uint16 udfLen = UdfName->Length / sizeof(WCHAR); 709 710 uint16 index, dosIndex = 0; 711 //uint16 extIndex = 0; 712 BOOLEAN needsCRC = FALSE, isParent = FALSE; 713 //BOOLEAN hasExt = FALSE, writingExt = FALSE; 714 uint16 valueCRC; 715 WCHAR ext[DOS_EXT_LEN]; 716 WCHAR current; 717 718 if(KeepIntact && 719 (udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) { 720 isParent = TRUE; 721 if((udfLen == 2) && (udfName[1] != UNICODE_PERIOD)) 722 isParent = FALSE; 723 } 724 725 #define DOS_CRC_LEN 4 726 #define DOS_CRC_MODULUS 41 727 728 int16 crcIndex; 729 uint16 extLen; 730 uint16 nameLen; 731 uint16 charLen; 732 int16 overlayBytes; 733 int16 bytesLeft; 734 735 /* Start at the end of the UDF file name and scan for a period */ 736 /* ('.'). This will be where the DOS extension starts (if */ 737 /* any). */ 738 index = udfLen; 739 while (index-- > 0) { 740 if (udfName[index] == '.') 741 break; 742 } 743 if ((index < 0) || isParent) { 744 /* There name was scanned to the beginning of the buffer */ 745 /* and no extension was found. */ 746 extLen = 0; 747 nameLen = udfLen; 748 } else { 749 /* A DOS extension was found, process it first. */ 750 extLen = udfLen - index - 1; 751 nameLen = index; 752 dosIndex = 0; 753 bytesLeft = DOS_EXT_LEN; 754 while (++index < udfLen && bytesLeft > 0) { 755 /* Get the current character and convert it to upper */ 756 /* case. */ 757 current = udfName[index]; 758 if (current == ' ') { 759 /* If a space is found, a CRC must be appended to */ 760 /* the mangled file name. */ 761 needsCRC = TRUE; 762 } else { 763 /* Determine if this is a valid file name char and */ 764 /* calculate its corresponding BCS character byte */ 765 /* length (zero if the char is not legal or */ 766 /* undisplayable on this system). */ 767 768 charLen = (UDFIsIllegalChar(current) 769 /*|| !UnicodeIsPrint(current)*/) ? 0 : 1; 770 771 /* If the char is larger than the available space */ 772 /* in the buffer, pretend it is undisplayable. */ 773 if (charLen > bytesLeft) 774 charLen = 0; 775 if (charLen == 0) { 776 /* Undisplayable or illegal characters are */ 777 /* substituted with an underscore ("_"), and */ 778 /* required a CRC code appended to the mangled */ 779 /* file name. */ 780 needsCRC = TRUE; 781 charLen = 1; 782 current = '_'; 783 /* Skip over any following undiplayable or */ 784 /* illegal chars. */ 785 while (index +1 <udfLen && 786 (UDFIsIllegalChar(udfName[index+1]) 787 /*|| !UnicodeIsPrint(udfName[index+1])*/)) 788 index++; 789 } 790 /* Assign the resulting char to the next index in */ 791 /* the extension buffer and determine how many BCS */ 792 /* bytes are left. */ 793 ext[dosIndex++] = current; 794 bytesLeft -= charLen; 795 } 796 } 797 /* Save the number of Unicode characters in the extension */ 798 extLen = dosIndex; 799 /* If the extension was too large, or it was zero length */ 800 /* (i.e. the name ended in a period), a CRC code must be */ 801 /* appended to the mangled name. */ 802 if (index < udfLen || extLen == 0) 803 needsCRC = TRUE; 804 } 805 /* Now process the actual file name. */ 806 index = 0; 807 dosIndex = 0; 808 crcIndex = 0; 809 overlayBytes = -1; 810 bytesLeft = DOS_NAME_LEN; 811 while (index < nameLen && bytesLeft > 0) { 812 /* Get the current character and convert it to upper case. */ 813 current = udfName[index]; 814 if (current ==' ' || (current == '.' && !isParent) ) { 815 /* Spaces and periods are just skipped, a CRC code */ 816 /* must be added to the mangled file name. */ 817 needsCRC = TRUE; 818 } else { 819 /* Determine if this is a valid file name char and */ 820 /* calculate its corresponding BCS character byte */ 821 /* length (zero if the char is not legal or */ 822 /* undisplayable on this system). */ 823 824 charLen = (UDFIsIllegalChar(current) 825 /*|| !UnicodeIsPrint(current)*/) ? 0 : 1; 826 827 /* If the char is larger than the available space in */ 828 /* the buffer, pretend it is undisplayable. */ 829 if (charLen > bytesLeft) 830 charLen = 0; 831 832 if (charLen == 0) { 833 /* Undisplayable or illegal characters are */ 834 /* substituted with an underscore ("_"), and */ 835 /* required a CRC code appended to the mangled */ 836 /* file name. */ 837 needsCRC = TRUE; 838 charLen = 1; 839 current = '_'; 840 /* Skip over any following undisplayable or illegal */ 841 /* chars. */ 842 while (index +1 <nameLen && 843 (UDFIsIllegalChar(udfName[index+1]) 844 /*|| !UnicodeIsPrint(udfName[index+1])*/)) 845 index++; 846 /* Terminate loop if at the end of the file name. */ 847 if (index >= nameLen) 848 break; 849 } 850 /* Assign the resulting char to the next index in the */ 851 /* file name buffer and determine how many BCS bytes */ 852 /* are left. */ 853 dosName[dosIndex++] = current; 854 bytesLeft -= charLen; 855 /* This figures out where the CRC code needs to start */ 856 /* in the file name buffer. */ 857 if (bytesLeft >= DOS_CRC_LEN) { 858 /* If there is enough space left, just tack it */ 859 /* onto the end. */ 860 crcIndex = dosIndex; 861 } else { 862 /* If there is not enough space left, the CRC */ 863 /* must overlay a character already in the file */ 864 /* name buffer. Once this condition has been */ 865 /* met, the value will not change. */ 866 if (overlayBytes < 0) { 867 /* Determine the index and save the length of */ 868 /* the BCS character that is overlayed. It */ 869 /* is possible that the CRC might overlay */ 870 /* half of a two-byte BCS character depending */ 871 /* upon how the character boundaries line up. */ 872 overlayBytes = (bytesLeft + charLen > DOS_CRC_LEN)?1 :0; 873 crcIndex = dosIndex - 1; 874 } 875 } 876 } 877 /* Advance to the next character. */ 878 index++; 879 } 880 /* If the scan did not reach the end of the file name, or the */ 881 /* length of the file name is zero, a CRC code is needed. */ 882 if (index < nameLen || index == 0) 883 needsCRC = TRUE; 884 885 /* If the name has illegal characters or and extension, it */ 886 /* is not a DOS device name. */ 887 888 /* if (needsCRC == FALSE && extLen == 0) { */ 889 /* If this is the name of a DOS device, a CRC code should */ 890 /* be appended to the file name. 891 if (IsDeviceName(udfName, udfLen)) 892 needsCRC = TRUE; 893 }*/ 894 895 /* Append the CRC code to the file name, if needed. */ 896 if (needsCRC) { 897 /* Get the CRC value for the original Unicode string */ 898 valueCRC = UDFUnicodeCksum(udfName, udfLen); 899 900 /* begin. */ 901 dosIndex = crcIndex; 902 /* If the character being overlayed is a two-byte BCS */ 903 /* character, replace the first byte with an underscore. */ 904 if (overlayBytes > 0) 905 dosName[dosIndex++] = '_'; 906 /* Append the encoded CRC value with delimiter. */ 907 dosName[dosIndex++] = '#'; 908 dosName[dosIndex++] = 909 crcChar[valueCRC / (DOS_CRC_MODULUS * DOS_CRC_MODULUS)]; 910 valueCRC %= DOS_CRC_MODULUS * DOS_CRC_MODULUS; 911 dosName[dosIndex++] = 912 crcChar[valueCRC / DOS_CRC_MODULUS]; 913 valueCRC %= DOS_CRC_MODULUS; 914 dosName[dosIndex++] = crcChar[valueCRC]; 915 } 916 /* Append the extension, if any. */ 917 if (extLen > 0) { 918 /* Tack on a period and each successive byte in the */ 919 /* extension buffer. */ 920 dosName[dosIndex++] = '.'; 921 for (index = 0; index < extLen; index++) 922 dosName[dosIndex++] = ext[index]; 923 } 924 /* Return the length of the resulting Unicode string. */ 925 DosName->Length = (uint16)dosIndex*sizeof(WCHAR); 926 RtlUpcaseUnicodeString(DosName, DosName, FALSE); 927 928 } // end UDFDOSName201() 929 930 #ifndef UDF_READ_ONLY_BUILD 931 /* 932 This routine initializes Tag structure. It must be called after all 933 manual settings to generate valid CRC & Checksum 934 */ 935 void 936 UDFSetUpTag( 937 IN PVCB Vcb, 938 IN tag* Tag, 939 IN uint16 DataLen, // total length of descriptor _including_ icbTag 940 IN uint32 TagLoc 941 ) 942 { 943 uint32 i; 944 int8* tb; 945 946 AdPrint(("UDF: SetTag Loc=%x(%x), tagIdent=%x\n", TagLoc, Tag->tagLocation, Tag->tagIdent)); 947 948 if(DataLen) DataLen -= sizeof(tag); 949 // int8* Data = ((int8*)Tag) + sizeof(tag); 950 // Ecma-167 states, that all implementations 951 // shall set this field to '3' even if 952 // disc contains descriptors recorded with 953 // value '2' 954 // But we should ignore this to make happy othe UDF implementations :( 955 Tag->descVersion = (Vcb->NSRDesc & VRS_NSR03_FOUND) ? 3 : 2; 956 Tag->tagLocation = TagLoc; 957 Tag->tagSerialNum = (uint16)(Vcb->SerialNumber + 1); 958 Tag->descCRCLength = DataLen; 959 Tag->descCRC = UDFCrc((uint8*)(Tag+1), DataLen); 960 Tag->tagChecksum = 0; 961 tb = ((int8*)Tag); 962 for (i=0; i<sizeof(tag); i++,tb++) 963 Tag->tagChecksum += (i!=4) ? (*tb) : 0; 964 } // end UDFSetUpTag() 965 966 /* 967 This routine builds FileEntry & associated AllocDescs for specified 968 extent. 969 */ 970 OSSTATUS 971 UDFBuildFileEntry( 972 IN PVCB Vcb, 973 IN PUDF_FILE_INFO DirInfo, 974 IN PUDF_FILE_INFO FileInfo, 975 IN uint32 PartNum, 976 IN uint16 AllocMode, // short/long/ext/in-icb 977 IN uint32 ExtAttrSz, 978 IN BOOLEAN Extended 979 ) 980 { 981 PFILE_ENTRY FileEntry; 982 OSSTATUS status; 983 // EntityID* eID; 984 uint32 l; 985 EXTENT_INFO _FEExtInfo; 986 uint16* lcp; 987 988 ASSERT(!PartNum); 989 ASSERT(!ExtAttrSz); 990 // calculate the length required 991 l = (Extended ? sizeof(EXTENDED_FILE_ENTRY) : sizeof(FILE_ENTRY)) + ExtAttrSz; 992 if(l > Vcb->LBlockSize) return STATUS_INVALID_PARAMETER; 993 // allocate block for FE 994 if(!OS_SUCCESS(status = UDFAllocateFESpace(Vcb, DirInfo, PartNum, &_FEExtInfo, l) )) 995 return status; 996 // remember FE location for future hard link creation 997 ASSERT(UDFFindDloc(Vcb, _FEExtInfo.Mapping[0].extLocation) == (-1)); 998 if(!OS_SUCCESS(status = UDFStoreDloc(Vcb, FileInfo, _FEExtInfo.Mapping[0].extLocation))) { 999 ASSERT(status != STATUS_SHARING_PAUSED); 1000 UDFFreeFESpace(Vcb, DirInfo, &_FEExtInfo); // free 1001 MyFreePool__(_FEExtInfo.Mapping); 1002 return status; 1003 } 1004 FileEntry = (PFILE_ENTRY)MyAllocatePoolTag__(NonPagedPool, l, MEM_FE_TAG); 1005 if(!FileEntry) { 1006 UDFRemoveDloc(Vcb, FileInfo->Dloc); 1007 FileInfo->Dloc = NULL; 1008 UDFFreeFESpace(Vcb, DirInfo, &_FEExtInfo); // free 1009 MyFreePool__(_FEExtInfo.Mapping); 1010 return STATUS_INSUFFICIENT_RESOURCES; 1011 } 1012 FileInfo->Dloc->FELoc = _FEExtInfo; 1013 1014 RtlZeroMemory((int8*)FileEntry, l); 1015 // set up in-memory FE structure 1016 FileEntry->icbTag.flags = AllocMode; 1017 FileEntry->icbTag.fileType = UDF_FILE_TYPE_REGULAR; 1018 FileEntry->icbTag.numEntries = 1; 1019 // if(DirInfo && DirInfo->Dloc && DirInfo->Dloc 1020 FileEntry->icbTag.strategyType = 4; 1021 // FileEntry->icbTag.strategyParameter = 0; 1022 FileEntry->descTag.tagIdent = Extended ? TID_EXTENDED_FILE_ENTRY : TID_FILE_ENTRY; 1023 FileEntry->descTag.tagLocation = UDFPhysLbaToPart(Vcb, PartNum, _FEExtInfo.Mapping[0].extLocation); 1024 FileEntry->uid = Vcb->DefaultUID; 1025 FileEntry->gid = Vcb->DefaultGID; 1026 1027 if(Extended) { 1028 // eID = &(((PEXTENDED_FILE_ENTRY)FileEntry)->impIdent); 1029 lcp = &(((PEXTENDED_FILE_ENTRY)FileEntry)->fileLinkCount); 1030 ((PEXTENDED_FILE_ENTRY)FileEntry)->checkpoint = 1; 1031 } else { 1032 // eID = &(FileEntry->impIdent); 1033 lcp = &(FileEntry->fileLinkCount); 1034 ((PFILE_ENTRY)FileEntry)->checkpoint = 1; 1035 } 1036 1037 #if 0 1038 UDFSetEntityID_imp(eID, UDF_ID_DEVELOPER); 1039 #endif 1040 1041 /*RtlCopyMemory((int8*)&(eID->ident), UDF_ID_DEVELOPER, sizeof(UDF_ID_DEVELOPER) ); 1042 iis = (impIdentSuffix*)&(eID->identSuffix); 1043 iis->OSClass = UDF_OS_CLASS_WINNT; 1044 iis->OSIdent = UDF_OS_ID_WINNT;*/ 1045 1046 *lcp = 0xffff; 1047 1048 FileInfo->Dloc->FileEntry = (tag*)FileEntry; 1049 FileInfo->Dloc->FileEntryLen = l; 1050 1051 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; 1052 1053 return STATUS_SUCCESS; 1054 } // end UDFBuildFileEntry() 1055 #endif //UDF_READ_ONLY_BUILD 1056 1057 /* 1058 This routine builds ExtentInfo for specified (Ex)FileEntry & associated 1059 AllocDescs 1060 */ 1061 OSSTATUS 1062 UDFLoadExtInfo( 1063 IN PVCB Vcb, 1064 IN PFILE_ENTRY fe, 1065 IN PLONG_AD fe_loc, 1066 IN OUT PEXTENT_INFO FExtInfo, // user data 1067 IN OUT PEXTENT_INFO AExtInfo // alloc descs 1068 ) 1069 { 1070 EXTENT_AD TmpExt; 1071 1072 UDFPrint((" UDFLoadExtInfo:\n")); 1073 FExtInfo->Mapping = UDFReadMappingFromXEntry(Vcb, fe_loc->extLocation.partitionReferenceNum, 1074 (tag*)fe, &(FExtInfo->Offset), AExtInfo); 1075 if(!(FExtInfo->Mapping)) { 1076 if(!(FExtInfo->Offset)) 1077 return STATUS_UNSUCCESSFUL; 1078 TmpExt.extLength = fe_loc->extLength; 1079 TmpExt.extLocation = UDFPartLbaToPhys(Vcb, &(fe_loc->extLocation)); 1080 if(TmpExt.extLocation == LBA_OUT_OF_EXTENT) 1081 return STATUS_FILE_CORRUPT_ERROR; 1082 FExtInfo->Mapping = UDFExtentToMapping(&TmpExt); 1083 } 1084 if(fe->descTag.tagIdent == TID_FILE_ENTRY) { 1085 // UDFPrint(("Standard FileEntry\n")); 1086 FExtInfo->Length = fe->informationLength; 1087 } else /*if(fe->descTag.tagIdent == TID_EXTENDED_FILE_ENTRY) */ { 1088 FExtInfo->Length = ((PEXTENDED_FILE_ENTRY)fe)->informationLength; 1089 } 1090 UDFPrint((" FExtInfo->Length %x\n", FExtInfo->Length)); 1091 ASSERT(FExtInfo->Length <= UDFGetExtentLength(FExtInfo->Mapping)); 1092 FExtInfo->Modified = FALSE; 1093 1094 return STATUS_SUCCESS; 1095 } // end UDFLoadExtInfo() 1096 1097 /* 1098 This routine builds FileIdent for specified FileEntry. 1099 We shall call UDFSetUpTag after all other initializations 1100 This structure is a precise copy of on-disk FileIdent 1101 structure. All modifications of it (including memory block 1102 size) are reflected on Directory extent. This, allocation of 1103 too long block (without changes in ImpUseLen) will lead to 1104 unreadable Directory 1105 */ 1106 OSSTATUS 1107 UDFBuildFileIdent( 1108 IN PVCB Vcb, 1109 IN PUNICODE_STRING fn, 1110 IN PLONG_AD FileEntryIcb, // virtual address of FileEntry 1111 IN uint32 ImpUseLen, 1112 OUT PFILE_IDENT_DESC* _FileId, 1113 OUT uint32* FileIdLen 1114 ) 1115 { 1116 PFILE_IDENT_DESC FileId; 1117 uint8* CS0; 1118 SIZE_T Nlen; 1119 uint32 l; 1120 // prepare filename 1121 UDFCompressUnicode(fn, &CS0, &Nlen); 1122 if(!CS0) return STATUS_INSUFFICIENT_RESOURCES; 1123 if(Nlen < 2) { 1124 Nlen = 0; 1125 } else 1126 if(Nlen > UDF_NAME_LEN) { 1127 if(CS0) MyFreePool__(CS0); 1128 return STATUS_OBJECT_NAME_INVALID; 1129 } 1130 // allocate memory for FI 1131 l = (sizeof(FILE_IDENT_DESC) + Nlen + ImpUseLen + 3) & ~((uint32)3); 1132 FileId = (PFILE_IDENT_DESC)MyAllocatePoolTag__(NonPagedPool, l, MEM_FID_TAG); 1133 if(!FileId) { 1134 if(CS0) MyFreePool__(CS0); 1135 return STATUS_INSUFFICIENT_RESOURCES; 1136 } 1137 // fill FI structure 1138 RtlZeroMemory( (int8*)FileId, l); 1139 RtlCopyMemory( ((int8*)(FileId+1))+ImpUseLen, CS0, Nlen); 1140 FileId->descTag.tagIdent = TID_FILE_IDENT_DESC; 1141 FileId->fileVersionNum = 1; 1142 FileId->lengthOfImpUse = (uint16)ImpUseLen; 1143 FileId->lengthFileIdent = (uint8)Nlen; 1144 FileId->icb = *FileEntryIcb; 1145 *_FileId = FileId; 1146 *FileIdLen = l; 1147 1148 if(CS0) MyFreePool__(CS0); 1149 return STATUS_SUCCESS; 1150 } // end UDFBuildFileIdent() 1151 1152 #ifndef UDF_READ_ONLY_BUILD 1153 /* 1154 This routine sets informationLength field in (Ext)FileEntry 1155 */ 1156 void 1157 UDFSetFileSize( 1158 IN PUDF_FILE_INFO FileInfo, 1159 IN int64 Size 1160 ) 1161 { 1162 uint16 Ident; 1163 // PDIR_INDEX_ITEM DirIndex; 1164 1165 ValidateFileInfo(FileInfo); 1166 AdPrint(("UDFSetFileSize: %I64x, FI %x\n", Size, FileInfo)); 1167 1168 //AdPrint((" Dloc %x\n", FileInfo->Dloc)); 1169 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; 1170 //AdPrint((" FileEntry %x\n", FileInfo->Dloc->FileEntry)); 1171 Ident = FileInfo->Dloc->FileEntry->tagIdent; 1172 //AdPrint((" Ident %x\n", Ident)); 1173 if(Ident == TID_FILE_ENTRY) { 1174 PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry); 1175 //AdPrint((" fe %x\n", fe)); 1176 fe->informationLength = Size; 1177 } else if(Ident == TID_EXTENDED_FILE_ENTRY) { 1178 PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry); 1179 //AdPrint((" ext-fe %x\n", fe)); 1180 fe->informationLength = Size; 1181 } 1182 /* if(DirIndex = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index) ) { 1183 DirIndex->FileSize = Size; 1184 }*/ 1185 //AdPrint(("UDFSetFileSize: ok\n")); 1186 return; 1187 } // end UDFSetFileSize() 1188 1189 void 1190 UDFSetFileSizeInDirNdx( 1191 IN PVCB Vcb, 1192 IN PUDF_FILE_INFO FileInfo, 1193 IN int64* ASize 1194 ) 1195 { 1196 uint16 Ident; 1197 PDIR_INDEX_ITEM DirIndex; 1198 1199 ValidateFileInfo(FileInfo); 1200 if(ASize) { 1201 AdPrint(("UDFSetFileSizeInDirNdx: %I64x\n", *ASize)); 1202 } else { 1203 AdPrint(("UDFSetFileSizeInDirNdx: sync\n")); 1204 } 1205 1206 DirIndex = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index); 1207 if(!DirIndex) 1208 return; 1209 1210 Ident = FileInfo->Dloc->FileEntry->tagIdent; 1211 if(Ident == TID_FILE_ENTRY) { 1212 PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry); 1213 DirIndex->FileSize = fe->informationLength; 1214 if(ASize) { 1215 DirIndex->AllocationSize = *ASize; 1216 // } else { 1217 // DirIndex->AllocationSize = (fe->informationLength + Vcb->LBlockSize - 1) & ~(Vcb->LBlockSize - 1); 1218 } 1219 } else if(Ident == TID_EXTENDED_FILE_ENTRY) { 1220 PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry); 1221 DirIndex->FileSize = fe->informationLength; 1222 if(ASize) { 1223 DirIndex->AllocationSize = *ASize; 1224 // } else { 1225 // DirIndex->AllocationSize = (fe->informationLength + Vcb->LBlockSize - 1) & ~(Vcb->LBlockSize - 1); 1226 } 1227 } 1228 return; 1229 } // end UDFSetFileSizeInDirNdx() 1230 #endif //UDF_READ_ONLY_BUILD 1231 1232 /* 1233 This routine gets informationLength field in (Ext)FileEntry 1234 */ 1235 int64 1236 UDFGetFileSize( 1237 IN PUDF_FILE_INFO FileInfo 1238 ) 1239 { 1240 uint16 Ident; 1241 1242 ValidateFileInfo(FileInfo); 1243 1244 Ident = FileInfo->Dloc->FileEntry->tagIdent; 1245 if(Ident == TID_FILE_ENTRY) { 1246 PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry); 1247 return fe->informationLength; 1248 } else if(Ident == TID_EXTENDED_FILE_ENTRY) { 1249 PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry); 1250 return fe->informationLength; 1251 } 1252 return (-1); 1253 } // end UDFGetFileSize() 1254 1255 int64 1256 UDFGetFileSizeFromDirNdx( 1257 IN PVCB Vcb, 1258 IN PUDF_FILE_INFO FileInfo 1259 ) 1260 { 1261 PDIR_INDEX_ITEM DirIndex; 1262 1263 ValidateFileInfo(FileInfo); 1264 1265 DirIndex = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index); 1266 if(!DirIndex) 1267 return -1; 1268 1269 return DirIndex->FileSize; 1270 } // end UDFGetFileSizeFromDirNdx() 1271 1272 #ifndef UDF_READ_ONLY_BUILD 1273 /* 1274 This routine sets lengthAllocDesc field in (Ext)FileEntry 1275 */ 1276 void 1277 UDFSetAllocDescLen( 1278 IN PVCB Vcb, 1279 IN PUDF_FILE_INFO FileInfo 1280 ) 1281 { 1282 uint16 Ident; 1283 1284 ValidateFileInfo(FileInfo); 1285 1286 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; 1287 Ident = FileInfo->Dloc->FileEntry->tagIdent; 1288 if(Ident == TID_FILE_ENTRY) { 1289 PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry); 1290 if(FileInfo->Dloc->AllocLoc.Length) { 1291 fe->lengthAllocDescs = min(FileInfo->Dloc->AllocLoc.Mapping[0].extLength - 1292 FileInfo->Dloc->AllocLoc.Offset, 1293 (uint32)(FileInfo->Dloc->AllocLoc.Length)); 1294 } else 1295 if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { 1296 fe->lengthAllocDescs = (uint32)(FileInfo->Dloc->DataLoc.Length); 1297 } 1298 } else if(Ident == TID_EXTENDED_FILE_ENTRY) { 1299 PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry); 1300 if(FileInfo->Dloc->AllocLoc.Length) { 1301 fe->lengthAllocDescs = min(FileInfo->Dloc->AllocLoc.Mapping[0].extLength - 1302 FileInfo->Dloc->AllocLoc.Offset, 1303 (uint32)(FileInfo->Dloc->AllocLoc.Length)); 1304 } else 1305 if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { 1306 fe->lengthAllocDescs = (uint32)(FileInfo->Dloc->DataLoc.Length); 1307 } 1308 } 1309 } // end UDFSetAllocDescLen() 1310 1311 /* 1312 This routine changes fileLinkCount field in (Ext)FileEntry 1313 */ 1314 void 1315 UDFChangeFileLinkCount( 1316 IN PUDF_FILE_INFO FileInfo, 1317 IN BOOLEAN Increase 1318 ) 1319 { 1320 uint16 Ident; 1321 1322 ValidateFileInfo(FileInfo); 1323 1324 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; 1325 Ident = FileInfo->Dloc->FileEntry->tagIdent; 1326 if(Ident == TID_FILE_ENTRY) { 1327 PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry); 1328 if(Increase) { 1329 fe->fileLinkCount++; 1330 } else { 1331 fe->fileLinkCount--; 1332 } 1333 if(fe->fileLinkCount & 0x8000) 1334 fe->fileLinkCount = 0xffff; 1335 return; 1336 } else if(Ident == TID_EXTENDED_FILE_ENTRY) { 1337 PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry); 1338 if(Increase) { 1339 fe->fileLinkCount++; 1340 } else { 1341 fe->fileLinkCount--; 1342 } 1343 if(fe->fileLinkCount & 0x8000) 1344 fe->fileLinkCount = 0xffff; 1345 return; 1346 } 1347 return; 1348 } // end UDFChangeFileLinkCount() 1349 #endif //UDF_READ_ONLY_BUILD 1350 1351 /* 1352 This routine gets fileLinkCount field from (Ext)FileEntry 1353 */ 1354 uint16 1355 UDFGetFileLinkCount( 1356 IN PUDF_FILE_INFO FileInfo 1357 ) 1358 { 1359 uint16 Ident; 1360 uint16 d; 1361 1362 ValidateFileInfo(FileInfo); 1363 1364 if(!FileInfo->Dloc->FileEntry) 1365 return 1; 1366 Ident = FileInfo->Dloc->FileEntry->tagIdent; 1367 // UDF engine assumes that LinkCount is a counter 1368 // of FileIdents, referencing this FE. 1369 // UDF 2.0 states, that it should be counter of ALL 1370 // references (including SDir) - 1. 1371 // Thus we'll write to media UDF-required value, but return 1372 // cooked value to callers 1373 d = UDFHasAStreamDir(FileInfo) ? 0 : 1; 1374 if(Ident == TID_FILE_ENTRY) { 1375 return ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount + d; 1376 } else if(Ident == TID_EXTENDED_FILE_ENTRY) { 1377 return ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount + d; 1378 } 1379 return UDF_INVALID_LINK_COUNT; 1380 } // end UDFGetFileLinkCount() 1381 1382 #ifdef UDF_CHECK_UTIL 1383 /* 1384 This routine sets fileLinkCount field in (Ext)FileEntry 1385 */ 1386 void 1387 UDFSetFileLinkCount( 1388 IN PUDF_FILE_INFO FileInfo, 1389 uint16 LinkCount 1390 ) 1391 { 1392 uint16 Ident; 1393 uint16 d; 1394 1395 ValidateFileInfo(FileInfo); 1396 1397 if(!FileInfo->Dloc->FileEntry) 1398 return; 1399 Ident = FileInfo->Dloc->FileEntry->tagIdent; 1400 // UDF engine assumes that LinkCount is a counter 1401 // of FileIdents, referencing this FE. 1402 // UDF 2.0 states, that it should be counter of ALL 1403 // references (including SDir) - 1. 1404 // Thus we'll write to media UDF-required value, but return 1405 // cooked value to callers 1406 d = UDFHasAStreamDir(FileInfo) ? 0 : 1; 1407 if(Ident == TID_FILE_ENTRY) { 1408 ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount = LinkCount - d; 1409 } else if(Ident == TID_EXTENDED_FILE_ENTRY) { 1410 ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->fileLinkCount = LinkCount - d; 1411 } 1412 return; 1413 } // end UDFGetFileLinkCount() 1414 #endif //UDF_CHECK_UTIL 1415 1416 /* 1417 This routine gets lengthExtendedAttr field in (Ext)FileEntry 1418 */ 1419 uint32 1420 UDFGetFileEALength( 1421 IN PUDF_FILE_INFO FileInfo 1422 ) 1423 { 1424 uint16 Ident; 1425 1426 ValidateFileInfo(FileInfo); 1427 1428 if(!FileInfo->Dloc->FileEntry) 1429 return 1; 1430 Ident = FileInfo->Dloc->FileEntry->tagIdent; 1431 1432 if(Ident == TID_FILE_ENTRY) { 1433 return ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->lengthExtendedAttr; 1434 } else if(Ident == TID_EXTENDED_FILE_ENTRY) { 1435 return ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->lengthExtendedAttr; 1436 } 1437 return 0; 1438 } // end UDFGetFileEALength() 1439 1440 #ifndef UDF_READ_ONLY_BUILD 1441 /* 1442 This routine sets UniqueID field in (Ext)FileEntry 1443 */ 1444 int64 1445 UDFAssingNewFUID( 1446 IN PVCB Vcb 1447 ) 1448 { 1449 Vcb->NextUniqueId++; 1450 if(!((uint32)(Vcb->NextUniqueId))) 1451 Vcb->NextUniqueId += 16; 1452 return Vcb->NextUniqueId; 1453 } 1454 1455 void 1456 UDFSetFileUID( 1457 IN PVCB Vcb, 1458 IN PUDF_FILE_INFO FileInfo 1459 ) 1460 { 1461 uint16 Ident; 1462 int64 UID; 1463 1464 ValidateFileInfo(FileInfo); 1465 1466 UID = UDFAssingNewFUID(Vcb); 1467 1468 /* UID = FileInfo->Dloc->FELoc.Mapping[0].extLocation | 1469 ( FileInfo->ParentFile ? (((int64)(FileInfo->ParentFile->Dloc->FELoc.Mapping[0].extLocation)) << 32) : 0);*/ 1470 1471 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; 1472 Ident = FileInfo->Dloc->FileEntry->tagIdent; 1473 if(Ident == TID_FILE_ENTRY) { 1474 PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry); 1475 fe->uniqueID = UID; 1476 } else if(Ident == TID_EXTENDED_FILE_ENTRY) { 1477 PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry); 1478 fe->uniqueID = UID; 1479 } 1480 if(FileInfo->FileIdent) 1481 ((FidADImpUse*)&(FileInfo->FileIdent->icb.impUse))->uniqueID = (uint32)UID; 1482 return; 1483 } // end UDFSetFileUID() 1484 #endif //UDF_READ_ONLY_BUILD 1485 1486 /* 1487 This routine gets UniqueID field in (Ext)FileEntry 1488 */ 1489 __inline 1490 int64 1491 UDFGetFileUID_( 1492 IN tag* FileEntry 1493 ) 1494 { 1495 uint16 Ident; 1496 1497 Ident = FileEntry->tagIdent; 1498 if(Ident == TID_FILE_ENTRY) { 1499 PFILE_ENTRY fe = (PFILE_ENTRY)(FileEntry); 1500 return fe->uniqueID; 1501 } else if(Ident == TID_EXTENDED_FILE_ENTRY) { 1502 PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileEntry); 1503 return fe->uniqueID; 1504 } 1505 return (-1); 1506 } // end UDFGetFileUID() 1507 1508 int64 1509 UDFGetFileUID( 1510 IN PUDF_FILE_INFO FileInfo 1511 ) 1512 { 1513 ValidateFileInfo(FileInfo); 1514 1515 return UDFGetFileUID_(FileInfo->Dloc->FileEntry); 1516 } // end UDFGetFileUID() 1517 1518 #ifndef UDF_READ_ONLY_BUILD 1519 void 1520 UDFChangeFileCounter( 1521 IN PVCB Vcb, 1522 IN BOOLEAN FileCounter, 1523 IN BOOLEAN Increase 1524 ) 1525 { 1526 uint32* counter; 1527 1528 counter = FileCounter ? 1529 &(Vcb->numFiles) : 1530 &(Vcb->numDirs); 1531 if(*counter == (ULONG)-1) 1532 return; 1533 if(Increase) { 1534 UDFInterlockedIncrement((int32*)counter); 1535 } else { 1536 UDFInterlockedDecrement((int32*)counter); 1537 } 1538 1539 } // end UDFChangeFileCounter() 1540 1541 void 1542 UDFSetEntityID_imp_( 1543 IN EntityID* eID, 1544 IN uint8* Str, 1545 IN uint32 Len 1546 ) 1547 { 1548 impIdentSuffix* iis; 1549 1550 RtlCopyMemory( (int8*)&(eID->ident), Str, Len ); 1551 iis = (impIdentSuffix*)&(eID->identSuffix); 1552 iis->OSClass = UDF_OS_CLASS_WINNT; 1553 iis->OSIdent = UDF_OS_ID_WINNT; 1554 1555 } // end UDFSetEntityID_imp_() 1556 #endif //UDF_READ_ONLY_BUILD 1557 1558 void 1559 UDFReadEntityID_Domain( 1560 PVCB Vcb, 1561 EntityID* eID 1562 ) 1563 { 1564 domainIdentSuffix* dis; 1565 uint8 flags; 1566 1567 dis = (domainIdentSuffix*)&(eID->identSuffix); 1568 1569 UDFPrint(("UDF: Entity Id:\n")); 1570 UDFPrint(("flags: %x\n", eID->flags)); 1571 UDFPrint(("ident[0]: %x\n", eID->ident[0])); 1572 UDFPrint(("ident[1]: %x\n", eID->ident[1])); 1573 UDFPrint(("ident[2]: %x\n", eID->ident[2])); 1574 UDFPrint(("ident[3]: %x\n", eID->ident[3])); 1575 UDFPrint(("UDF: Entity Id Domain:\n")); 1576 // Get current UDF revision 1577 Vcb->CurrentUDFRev = max(dis->currentRev, Vcb->CurrentUDFRev); 1578 UDFPrint(("Effective Revision: %x\n", Vcb->CurrentUDFRev)); 1579 // Get Read-Only flags 1580 flags = dis->flags; 1581 UDFPrint(("Flags: %x\n", flags)); 1582 if((flags & ENTITYID_FLAGS_SOFT_RO) && 1583 (Vcb->CompatFlags & UDF_VCB_IC_SOFT_RO)) { 1584 Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; 1585 Vcb->UserFSFlags |= UDF_USER_FS_FLAGS_SOFT_RO; 1586 UDFPrint((" Soft-RO\n")); 1587 } 1588 if((flags & ENTITYID_FLAGS_HARD_RO) && 1589 (Vcb->CompatFlags & UDF_VCB_IC_HW_RO)) { 1590 Vcb->VCBFlags |= UDF_VCB_FLAGS_MEDIA_READ_ONLY; 1591 Vcb->UserFSFlags |= UDF_USER_FS_FLAGS_HW_RO; 1592 UDFPrint((" Hard-RO\n")); 1593 } 1594 1595 } // end UDFReadEntityID_Domain() 1596 1597 #ifndef UDF_READ_ONLY_BUILD 1598 /* 1599 This routine writes data to file & increases it if necessary. 1600 In case of increasing AllocDescs will be rebuilt & flushed to disc 1601 (via driver's cache, of cource). Free space map will be updated only 1602 durring global media flush. 1603 */ 1604 OSSTATUS 1605 UDFWriteFile__( 1606 IN PVCB Vcb, 1607 IN PUDF_FILE_INFO FileInfo, 1608 IN int64 Offset, 1609 IN SIZE_T Length, 1610 IN BOOLEAN Direct, 1611 IN int8* Buffer, 1612 OUT PSIZE_T WrittenBytes 1613 ) 1614 { 1615 int64 t, elen; 1616 OSSTATUS status; 1617 int8* OldInIcb = NULL; 1618 ValidateFileInfo(FileInfo); 1619 SIZE_T ReadBytes; 1620 SIZE_T _WrittenBytes; 1621 PUDF_DATALOC_INFO Dloc; 1622 // unwind staff 1623 BOOLEAN WasInIcb = FALSE; 1624 uint64 OldLen; 1625 1626 // ASSERT(FileInfo->RefCount >= 1); 1627 1628 Dloc = FileInfo->Dloc; 1629 ASSERT(Dloc->FELoc.Mapping[0].extLocation); 1630 uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, Dloc->FELoc.Mapping[0].extLocation); 1631 (*WrittenBytes) = 0; 1632 1633 AdPrint(("UDFWriteFile__ FE %x, FileInfo %x, ExtInfo %x, Mapping %x\n", 1634 Dloc->FELoc.Mapping[0].extLocation, FileInfo, &(Dloc->DataLoc), Dloc->DataLoc.Mapping)); 1635 1636 t = Offset + Length; 1637 // UDFUpdateModifyTime(Vcb, FileInfo); 1638 if(t <= Dloc->DataLoc.Length) { 1639 // write Alloc-Rec area 1640 ExtPrint((" WAlloc-Rec: %I64x <= %I64x\n", t, Dloc->DataLoc.Length)); 1641 status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), Offset, Length, Direct, Buffer, WrittenBytes); 1642 return status; 1643 } 1644 elen = UDFGetExtentLength(Dloc->DataLoc.Mapping); 1645 ExtPrint((" DataLoc Offs %x, Len %I64x\n", 1646 Dloc->DataLoc.Offset, Dloc->DataLoc.Length)); 1647 if(t <= (elen - Dloc->DataLoc.Offset)) { 1648 // write Alloc-Not-Rec area 1649 ExtPrint((" WAlloc-Not-Rec: %I64x <= %I64x (%I64x - %I64x)\n", 1650 t, elen - Dloc->DataLoc.Offset - Dloc->DataLoc.Length, 1651 elen - Dloc->DataLoc.Offset, 1652 Dloc->DataLoc.Length)); 1653 UDFSetFileSize(FileInfo, t); 1654 if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { 1655 ExtPrint((" w2k-compat -> rebuild allocs\n")); 1656 Dloc->DataLoc.Modified = TRUE; 1657 } else 1658 if((ULONG)((elen+Vcb->LBlockSize-1) >> Vcb->LBlockSizeBits) != (ULONG)((t+Vcb->LBlockSize-1) >> Vcb->LBlockSizeBits)) { 1659 ExtPrint((" LBS boundary crossed -> rebuild allocs\n")); 1660 Dloc->DataLoc.Modified = TRUE; 1661 } 1662 Dloc->DataLoc.Length = t; 1663 return UDFWriteExtent(Vcb, &(Dloc->DataLoc), Offset, Length, Direct, Buffer, WrittenBytes); 1664 } 1665 // We should not get here if Direct=TRUE 1666 if(Direct) return STATUS_INVALID_PARAMETER; 1667 OldLen = Dloc->DataLoc.Length; 1668 if(Dloc->DataLoc.Offset && Dloc->DataLoc.Length) { 1669 // read in-icb data. it'll be replaced after resize 1670 ExtPrint((" read in-icb data\n")); 1671 OldInIcb = (int8*)MyAllocatePool__(NonPagedPool, (uint32)(Dloc->DataLoc.Length)); 1672 if(!OldInIcb) return STATUS_INSUFFICIENT_RESOURCES; 1673 status = UDFReadExtent(Vcb, &(Dloc->DataLoc), 0, (uint32)OldLen, FALSE, OldInIcb, &ReadBytes); 1674 if(!OS_SUCCESS(status)) { 1675 MyFreePool__(OldInIcb); 1676 return status; 1677 } 1678 } 1679 // init Alloc mode 1680 ExtPrint((" init Alloc mode\n")); 1681 if((((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) { 1682 ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK; 1683 ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= Vcb->DefaultAllocMode; 1684 WasInIcb = TRUE; 1685 } 1686 // increase extent 1687 ExtPrint((" %s %s %s\n", 1688 UDFIsADirectory(FileInfo) ? "DIR" : "FILE", 1689 WasInIcb ? "In-Icb" : "", 1690 Vcb->LowFreeSpace ? "LowSpace" : "")); 1691 if(UDFIsADirectory(FileInfo) && !WasInIcb && !Vcb->LowFreeSpace) { 1692 FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_ALLOC_SEQUENTIAL; 1693 status = UDFResizeExtent(Vcb, PartNum, (t*2+Vcb->WriteBlockSize-1) & ~(SIZE_T)(Vcb->WriteBlockSize-1), FALSE, &(Dloc->DataLoc)); 1694 if(OS_SUCCESS(status)) { 1695 AdPrint((" preallocated space for Dir\n")); 1696 FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_PREALLOCATED; 1697 //UDFSetFileSize(FileInfo, t); 1698 Dloc->DataLoc.Length = t; 1699 } else 1700 if(status == STATUS_DISK_FULL) { 1701 status = UDFResizeExtent(Vcb, PartNum, t, FALSE, &(Dloc->DataLoc)); 1702 } 1703 } else { 1704 status = UDFResizeExtent(Vcb, PartNum, t, FALSE, &(Dloc->DataLoc)); 1705 } 1706 ExtPrint((" DataLoc Offs %x, Len %I64x\n", 1707 Dloc->DataLoc.Offset, Dloc->DataLoc.Length)); 1708 AdPrint(("UDFWriteFile__ (2) FileInfo %x, ExtInfo %x, Mapping %x\n", FileInfo, &(Dloc->DataLoc), Dloc->DataLoc.Mapping)); 1709 if(!OS_SUCCESS(status)) { 1710 // rollback 1711 ExtPrint((" err -> rollback\n")); 1712 if(WasInIcb) { 1713 // restore Alloc mode 1714 ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK; 1715 ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= ICB_FLAG_AD_IN_ICB; 1716 if(Dloc->AllocLoc.Mapping) { 1717 MyFreePool__(Dloc->AllocLoc.Mapping); 1718 Dloc->AllocLoc.Mapping = NULL; 1719 } 1720 } 1721 if(OldInIcb) { 1722 MyFreePool__(OldInIcb); 1723 UDFWriteExtent(Vcb, &(Dloc->DataLoc), 0, (uint32)OldLen, FALSE, OldInIcb, &_WrittenBytes); 1724 } 1725 if((int64)OldLen != Dloc->DataLoc.Length) { 1726 // restore file size 1727 AdPrint((" restore alloc\n")); 1728 FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_CUT_PREALLOCATED; 1729 UDFResizeExtent(Vcb, PartNum, OldLen, FALSE, &(Dloc->DataLoc)); 1730 FileInfo->Dloc->DataLoc.Flags &= ~EXTENT_FLAG_CUT_PREALLOCATED; 1731 } 1732 return status; 1733 } 1734 if(OldInIcb) { 1735 // replace data from ICB (if any) & free buffer 1736 ExtPrint((" write old in-icd data\n")); 1737 status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), 0, (uint32)OldLen, FALSE, OldInIcb, &_WrittenBytes); 1738 MyFreePool__(OldInIcb); 1739 if(!OS_SUCCESS(status)) 1740 return status; 1741 } 1742 // ufff... 1743 // & now we'll write out data to well prepared extent... 1744 // ... like all normal people do... 1745 ExtPrint((" write user data\n")); 1746 if(!OS_SUCCESS(status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), Offset, Length, FALSE, Buffer, WrittenBytes))) 1747 return status; 1748 UDFSetFileSize(FileInfo, t); 1749 Dloc->DataLoc.Modified = TRUE; 1750 #ifdef UDF_DBG 1751 if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { 1752 ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)); 1753 } else { 1754 ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) == 1755 ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1))); 1756 } 1757 #endif // UDF_DBG 1758 return STATUS_SUCCESS; 1759 } // end UDFWriteFile__() 1760 1761 /* 1762 This routine marks file as deleted & decrements file link counter. 1763 It can optionaly free allocation space 1764 */ 1765 OSSTATUS 1766 UDFUnlinkFile__( 1767 IN PVCB Vcb, 1768 IN PUDF_FILE_INFO FileInfo, 1769 IN BOOLEAN FreeSpace 1770 ) 1771 { 1772 uint_di Index; // index of file to be deleted 1773 uint16 lc; 1774 PUDF_DATALOC_INFO Dloc; 1775 PUDF_FILE_INFO DirInfo; 1776 PUDF_FILE_INFO SDirInfo; 1777 PDIR_INDEX_HDR hDirNdx; 1778 PDIR_INDEX_HDR hCurDirNdx; 1779 PDIR_INDEX_ITEM DirNdx; 1780 OSSTATUS status; 1781 BOOLEAN IsSDir; 1782 1783 AdPrint(("UDFUnlinkFile__:\n")); 1784 if(!FileInfo) return STATUS_SUCCESS; 1785 1786 ValidateFileInfo(FileInfo); 1787 1788 #ifndef _CONSOLE 1789 // now we can't call this if there is no OS-specific File Desc. present 1790 if(FileInfo->Fcb) 1791 UDFRemoveFileId__(Vcb, FileInfo); 1792 #endif //_CONSOLE 1793 // check references 1794 Dloc = FileInfo->Dloc; 1795 if((FileInfo->OpenCount /*> (uint32)(UDFHasAStreamDir(FileInfo) ? 1 : 0)*/) || 1796 (FileInfo->RefCount>1)) return STATUS_CANNOT_DELETE; 1797 if(Dloc->SDirInfo) 1798 return STATUS_CANNOT_DELETE; 1799 ASSERT(FileInfo->RefCount == 1); 1800 DirInfo = FileInfo->ParentFile; 1801 // root dir or self 1802 if(!DirInfo || ((FileInfo->Index < 2) && !UDFIsAStreamDir(FileInfo))) return STATUS_CANNOT_DELETE; 1803 hDirNdx = DirInfo->Dloc->DirIndex; 1804 Index = FileInfo->Index; 1805 // we can't delete modified file 1806 // it should be closed & reopened (or flushed) before deletion 1807 DirNdx = UDFDirIndex(hDirNdx,Index); 1808 #if defined UDF_DBG || defined PRINT_ALWAYS 1809 if(DirNdx && DirNdx->FName.Buffer) { 1810 AdPrint(("Unlink: %ws\n",DirNdx->FName.Buffer)); 1811 } 1812 #endif // UDF_DBG 1813 if(FreeSpace && 1814 ((Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) || 1815 Dloc->DataLoc.Modified || 1816 Dloc->AllocLoc.Modified || 1817 Dloc->FELoc.Modified || 1818 (DirNdx && (DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) )) { 1819 // BrutePoint(); 1820 return STATUS_CANNOT_DELETE; 1821 } 1822 SDirInfo = Dloc->SDirInfo; 1823 /* if(FreeSpace && SDirInfo) { 1824 UDFPrint(("Unlink: SDirInfo should be NULL !!!\n")); 1825 BrutePoint(); 1826 return STATUS_CANNOT_DELETE; 1827 }*/ 1828 // stream directory can be deleted even being not empty 1829 // otherwise we should perform some checks 1830 if(!(IsSDir = UDFIsAStreamDir(FileInfo))) { 1831 // check if not empty direcory 1832 if((DirNdx->FileCharacteristics & FILE_DIRECTORY) && 1833 (hCurDirNdx = Dloc->DirIndex) && 1834 FreeSpace) { 1835 if(!UDFIsDirEmpty(hCurDirNdx)) 1836 return STATUS_DIRECTORY_NOT_EMPTY; 1837 } 1838 DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; 1839 DirNdx->FileCharacteristics |= FILE_DELETED; 1840 FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED; 1841 hDirNdx->DelCount++; 1842 UDFChangeFileCounter(Vcb, !UDFIsADirectory(FileInfo), FALSE); 1843 } 1844 UDFDecFileLinkCount(FileInfo); // decrease 1845 lc = UDFGetFileLinkCount(FileInfo); 1846 if(DirNdx && FreeSpace) { 1847 // FileIdent marked as 'deleted' should have an empty ICB 1848 // We shall do it only if object has parent Dir 1849 // (for ex. SDir has parent object, but has no parent Dir) 1850 DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; 1851 DirNdx->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR; 1852 // Root Files (Root/SDir/Vat/etc.) has no FileIdent... 1853 if(FileInfo->FileIdent) 1854 RtlZeroMemory(&(FileInfo->FileIdent->icb), sizeof(long_ad)); 1855 } 1856 // caller wishes to free allocation, but we can't do it due to 1857 // alive links. In this case we should just remove reference 1858 if(FreeSpace && lc) { 1859 ((icbtag*)(Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum = 0; 1860 ((icbtag*)(Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum = 0; 1861 Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; 1862 } else 1863 // if caller wishes to free file allocation & 1864 // there are no more references(links) to this file, lets do it >;-> 1865 if(FreeSpace && !lc) { 1866 if(UDFHasAStreamDir(FileInfo) && 1867 !UDFIsSDirDeleted(Dloc->SDirInfo) ) { 1868 // we have a Stream Dir associated... 1869 PUDF_FILE_INFO SFileInfo; 1870 // ... try to open it 1871 if(Dloc->SDirInfo) { 1872 UDFFlushFile__(Vcb, FileInfo); 1873 return STATUS_CANNOT_DELETE; 1874 } 1875 // open SDir 1876 status = UDFOpenStreamDir__(Vcb, FileInfo, &(Dloc->SDirInfo)); 1877 if(!OS_SUCCESS(status)) { 1878 // abort Unlink on error 1879 SFileInfo = Dloc->SDirInfo; 1880 cleanup_SDir: 1881 UDFCleanUpFile__(Vcb, SFileInfo); 1882 if(SFileInfo) MyFreePool__(SFileInfo); 1883 UDFFlushFile__(Vcb, FileInfo); 1884 return status; 1885 } 1886 SDirInfo = Dloc->SDirInfo; 1887 // try to perform deltree for Streams 1888 status = UDFUnlinkAllFilesInDir(Vcb, SDirInfo); 1889 if(!OS_SUCCESS(status)) { 1890 // abort Unlink on error 1891 UDFCloseFile__(Vcb, SDirInfo); 1892 SFileInfo = SDirInfo; 1893 BrutePoint(); 1894 goto cleanup_SDir; 1895 } 1896 // delete SDir 1897 UDFFlushFile__(Vcb, SDirInfo); 1898 AdPrint((" ")); 1899 UDFUnlinkFile__(Vcb, SDirInfo, TRUE); 1900 // close SDir 1901 UDFCloseFile__(Vcb, SDirInfo); 1902 if(UDFCleanUpFile__(Vcb, SDirInfo)) { 1903 MyFreePool__(SDirInfo); 1904 #ifdef UDF_DBG 1905 } else { 1906 BrutePoint(); 1907 #endif // UDF_DBG 1908 } 1909 // update FileInfo 1910 ASSERT(Dloc->FileEntry); 1911 RtlZeroMemory( &(((PEXTENDED_FILE_ENTRY)(Dloc->FileEntry))->streamDirectoryICB), sizeof(long_ad)); 1912 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; 1913 } else 1914 if(IsSDir) { 1915 // do deltree for Streams 1916 status = UDFUnlinkAllFilesInDir(Vcb, FileInfo); 1917 if(!OS_SUCCESS(status)) { 1918 UDFFlushFile__(Vcb, FileInfo); 1919 return status; 1920 } 1921 // update parent FileInfo 1922 ASSERT(FileInfo->ParentFile->Dloc->FileEntry); 1923 RtlZeroMemory( &(((PEXTENDED_FILE_ENTRY)(FileInfo->ParentFile->Dloc->FileEntry))->streamDirectoryICB), sizeof(long_ad)); 1924 FileInfo->ParentFile->Dloc->FE_Flags &= ~UDF_FE_FLAG_HAS_SDIR; 1925 FileInfo->ParentFile->Dloc->FE_Flags |= (UDF_FE_FLAG_FE_MODIFIED | 1926 UDF_FE_FLAG_HAS_DEL_SDIR); 1927 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_IS_DEL_SDIR; 1928 UDFDecFileLinkCount(FileInfo->ParentFile); 1929 } 1930 if(Dloc->DirIndex) { 1931 UDFFlushFESpace(Vcb, Dloc, FLUSH_FE_FOR_DEL); 1932 } 1933 // flush file 1934 UDFFlushFile__(Vcb, FileInfo); 1935 UDFUnlinkDloc(Vcb, Dloc); 1936 // free allocation 1937 UDFFreeFileAllocation(Vcb, DirInfo, FileInfo); 1938 ASSERT(!(FileInfo->Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED)); 1939 FileInfo->Dloc->FE_Flags &= ~UDF_FE_FLAG_FE_MODIFIED; 1940 } 1941 return STATUS_SUCCESS; 1942 } // end UDFUnlinkFile__() 1943 1944 OSSTATUS 1945 UDFUnlinkAllFilesInDir( 1946 IN PVCB Vcb, 1947 IN PUDF_FILE_INFO DirInfo 1948 ) 1949 { 1950 PDIR_INDEX_HDR hCurDirNdx; 1951 PDIR_INDEX_ITEM CurDirNdx; 1952 PUDF_FILE_INFO FileInfo; 1953 OSSTATUS status; 1954 uint_di i; 1955 1956 hCurDirNdx = DirInfo->Dloc->DirIndex; 1957 // check if we can delete all files 1958 for(i=2; (CurDirNdx = UDFDirIndex(hCurDirNdx,i)); i++) { 1959 // try to open Stream 1960 if(CurDirNdx->FileInfo) 1961 return STATUS_CANNOT_DELETE; 1962 } 1963 // start deletion 1964 for(i=2; (CurDirNdx = UDFDirIndex(hCurDirNdx,i)); i++) { 1965 // try to open Stream 1966 status = UDFOpenFile__(Vcb, FALSE, TRUE, NULL, DirInfo, &FileInfo, &i); 1967 if(status == STATUS_FILE_DELETED) { 1968 // we should not release on-disk allocation for 1969 // deleted streams twice 1970 if(CurDirNdx->FileInfo) { 1971 BrutePoint(); 1972 goto err_del_stream; 1973 } 1974 goto skip_del_stream; 1975 } else 1976 if(!OS_SUCCESS(status)) { 1977 // Error :((( 1978 err_del_stream: 1979 UDFCleanUpFile__(Vcb, FileInfo); 1980 if(FileInfo) 1981 MyFreePool__(FileInfo); 1982 return status; 1983 } 1984 1985 UDFFlushFile__(Vcb, FileInfo); 1986 AdPrint((" ")); 1987 UDFUnlinkFile__(Vcb, FileInfo, TRUE); 1988 UDFCloseFile__(Vcb, FileInfo); 1989 skip_del_stream: 1990 if(FileInfo && UDFCleanUpFile__(Vcb, FileInfo)) { 1991 MyFreePool__(FileInfo); 1992 } 1993 } 1994 return STATUS_SUCCESS; 1995 } // end UDFUnlinkAllFilesInDir() 1996 #endif //UDF_READ_ONLY_BUILD 1997 1998 /* 1999 This routine inits UDF_FILE_INFO structure for specified file 2000 If it returns status != STATUS_SUCCESS caller should call UDFCleanUpFile__ 2001 for returned pointer *WITHOUT* using UDFCloseFile__ 2002 */ 2003 OSSTATUS 2004 UDFOpenFile__( 2005 IN PVCB Vcb, 2006 IN BOOLEAN IgnoreCase, 2007 IN BOOLEAN NotDeleted, 2008 IN PUNICODE_STRING fn, 2009 IN PUDF_FILE_INFO DirInfo, 2010 OUT PUDF_FILE_INFO* _FileInfo,// this is to be filled & doesn't contain 2011 // any pointers 2012 IN uint_di* IndexToOpen 2013 ) 2014 { 2015 OSSTATUS status; 2016 uint_di i=0; 2017 EXTENT_AD FEExt; 2018 uint16 Ident; 2019 PDIR_INDEX_HDR hDirNdx = DirInfo->Dloc->DirIndex; 2020 PDIR_INDEX_ITEM DirNdx; 2021 PUDF_FILE_INFO FileInfo; 2022 PUDF_FILE_INFO ParFileInfo; 2023 SIZE_T ReadBytes; 2024 *_FileInfo = NULL; 2025 if(!hDirNdx) return STATUS_NOT_A_DIRECTORY; 2026 2027 // find specified file in directory index 2028 // if it is already known, skip this foolish code 2029 if(IndexToOpen) { 2030 i=*IndexToOpen; 2031 } else 2032 if(!OS_SUCCESS(status = UDFFindFile(Vcb, IgnoreCase, NotDeleted, fn, DirInfo, &i))) 2033 return status; 2034 // do this check for OpenByIndex 2035 // some routines may send invalid Index 2036 if(!(DirNdx = UDFDirIndex(hDirNdx,i))) 2037 return STATUS_OBJECT_NAME_NOT_FOUND; 2038 if((FileInfo = DirNdx->FileInfo)) { 2039 // file is already opened. 2040 if((DirNdx->FileCharacteristics & FILE_DELETED) && NotDeleted) { 2041 AdPrint((" FILE_DELETED on open\n")); 2042 return STATUS_FILE_DELETED; 2043 } 2044 if((FileInfo->ParentFile != DirInfo) && 2045 (FileInfo->Index >= 2)) { 2046 ParFileInfo = UDFLocateParallelFI(DirInfo, i, FileInfo); 2047 BrutePoint(); 2048 if(ParFileInfo->ParentFile != DirInfo) { 2049 FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_FINF_TAG); 2050 *_FileInfo = FileInfo; 2051 if(!FileInfo) return STATUS_INSUFFICIENT_RESOURCES; 2052 RtlCopyMemory(FileInfo, DirNdx->FileInfo, sizeof(UDF_FILE_INFO)); 2053 // FileInfo->NextLinkedFile = DirNdx->FileInfo->NextLinkedFile; // is already done 2054 UDFInsertLinkedFile(FileInfo, DirNdx->FileInfo); 2055 DirNdx->FI_Flags |= UDF_FI_FLAG_LINKED; 2056 FileInfo->RefCount = 0; 2057 FileInfo->ParentFile = DirInfo; 2058 FileInfo->Fcb = NULL; 2059 } else { 2060 FileInfo = ParFileInfo; 2061 } 2062 } 2063 // Just increase some counters & exit 2064 UDFReferenceFile__(FileInfo); 2065 2066 ASSERT(FileInfo->ParentFile == DirInfo); 2067 ValidateFileInfo(FileInfo); 2068 2069 *_FileInfo = FileInfo; 2070 return STATUS_SUCCESS; 2071 } else 2072 if(IndexToOpen) { 2073 if((DirNdx->FileCharacteristics & FILE_DELETED) && NotDeleted) { 2074 AdPrint((" FILE_DELETED on open (2)\n")); 2075 return STATUS_FILE_DELETED; 2076 } 2077 } 2078 FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_FINF_TAG); 2079 *_FileInfo = FileInfo; 2080 if(!FileInfo) return STATUS_INSUFFICIENT_RESOURCES; 2081 RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO)); 2082 // init horizontal links 2083 FileInfo->NextLinkedFile = 2084 FileInfo->PrevLinkedFile = FileInfo; 2085 // read FileIdent 2086 FileInfo->FileIdent = (PFILE_IDENT_DESC)MyAllocatePoolTag__(NonPagedPool, DirNdx->Length, MEM_FID_TAG); 2087 if(!(FileInfo->FileIdent)) return STATUS_INSUFFICIENT_RESOURCES; 2088 FileInfo->FileIdentLen = DirNdx->Length; 2089 if(!OS_SUCCESS(status = UDFReadExtent(Vcb, &(DirInfo->Dloc->DataLoc), DirNdx->Offset, 2090 DirNdx->Length, FALSE, (int8*)(FileInfo->FileIdent), &ReadBytes) )) 2091 return status; 2092 if(FileInfo->FileIdent->descTag.tagIdent != TID_FILE_IDENT_DESC) { 2093 BrutePoint(); 2094 return STATUS_FILE_CORRUPT_ERROR; 2095 } 2096 // check for opened links 2097 if(!OS_SUCCESS(status = UDFStoreDloc(Vcb, FileInfo, UDFPartLbaToPhys(Vcb, &(FileInfo->FileIdent->icb.extLocation))))) 2098 return status; 2099 // init pointer to parent object 2100 FileInfo->Index = i; 2101 FileInfo->ParentFile = DirInfo; 2102 // init pointers to linked files (if any) 2103 if(FileInfo->Dloc->LinkedFileInfo != FileInfo) 2104 UDFInsertLinkedFile(FileInfo, FileInfo->Dloc->LinkedFileInfo); 2105 if(FileInfo->Dloc->FileEntry) 2106 goto init_tree_entry; 2107 // read (Ex)FileEntry 2108 FileInfo->Dloc->FileEntry = (tag*)MyAllocatePoolTag__(NonPagedPool, Vcb->LBlockSize, MEM_FE_TAG); 2109 if(!(FileInfo->Dloc->FileEntry)) return STATUS_INSUFFICIENT_RESOURCES; 2110 if(!OS_SUCCESS(status = UDFReadFileEntry(Vcb, &(FileInfo->FileIdent->icb), (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &Ident))) 2111 return status; 2112 // build mappings for Data & AllocDescs 2113 if(!FileInfo->Dloc->AllocLoc.Mapping) { 2114 FEExt.extLength = FileInfo->FileIdent->icb.extLength; 2115 FEExt.extLocation = UDFPartLbaToPhys(Vcb, &(FileInfo->FileIdent->icb.extLocation) ); 2116 if(FEExt.extLocation == LBA_OUT_OF_EXTENT) 2117 return STATUS_FILE_CORRUPT_ERROR; 2118 FileInfo->Dloc->AllocLoc.Mapping = UDFExtentToMapping(&FEExt); 2119 if(!(FileInfo->Dloc->AllocLoc.Mapping)) 2120 return STATUS_INSUFFICIENT_RESOURCES; 2121 } 2122 // read location info 2123 status = UDFLoadExtInfo(Vcb, (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &(FileInfo->FileIdent->icb), 2124 &(FileInfo->Dloc->DataLoc), &(FileInfo->Dloc->AllocLoc) ); 2125 if(!OS_SUCCESS(status)) 2126 return status; 2127 // init (Ex)FileEntry mapping 2128 FileInfo->Dloc->FELoc.Length = (FileInfo->Dloc->DataLoc.Offset) ? FileInfo->Dloc->DataLoc.Offset : 2129 FileInfo->Dloc->AllocLoc.Offset; 2130 // FileInfo->Dloc->FELoc.Offset = 0; 2131 FileInfo->Dloc->FELoc.Mapping = UDFExtentToMapping(&FEExt); 2132 FileInfo->Dloc->FileEntryLen = (uint32)(FileInfo->Dloc->FELoc.Length); 2133 // we get here immediately when opened link encountered 2134 init_tree_entry: 2135 // init back pointer from parent object 2136 ASSERT(!DirNdx->FileInfo); 2137 DirNdx->FileInfo = FileInfo; 2138 // init DirIndex 2139 if(UDFGetFileLinkCount(FileInfo) > 1) { 2140 DirNdx->FI_Flags |= UDF_FI_FLAG_LINKED; 2141 } else { 2142 DirNdx->FI_Flags &= ~UDF_FI_FLAG_LINKED; 2143 } 2144 // resize FE cache (0x800 instead of 0x40 is not a good idea) 2145 if(!MyReallocPool__((int8*)((FileInfo->Dloc->FileEntry)), Vcb->LBlockSize, 2146 (int8**)&((FileInfo->Dloc->FileEntry)), FileInfo->Dloc->FileEntryLen)) 2147 return STATUS_INSUFFICIENT_RESOURCES; 2148 // check if this file has a SDir 2149 if((FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY) && 2150 ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLength ) 2151 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_HAS_SDIR; 2152 if(!(FileInfo->FileIdent->fileCharacteristics & FILE_DIRECTORY)) { 2153 UDFReferenceFile__(FileInfo); 2154 ASSERT(FileInfo->ParentFile == DirInfo); 2155 UDFReleaseDloc(Vcb, FileInfo->Dloc); 2156 return STATUS_SUCCESS; 2157 } 2158 2159 UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used 2160 2161 // build index for directories 2162 if(!FileInfo->Dloc->DirIndex) { 2163 status = UDFIndexDirectory(Vcb, FileInfo); 2164 if(!OS_SUCCESS(status)) 2165 return status; 2166 #ifndef UDF_READ_ONLY_BUILD 2167 if((FileInfo->Dloc->DirIndex->DelCount > Vcb->PackDirThreshold) && 2168 !(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)) { 2169 status = UDFPackDirectory__(Vcb, FileInfo); 2170 if(!OS_SUCCESS(status)) 2171 return status; 2172 } 2173 #endif //UDF_READ_ONLY_BUILD 2174 } 2175 UDFReferenceFile__(FileInfo); 2176 UDFReleaseDloc(Vcb, FileInfo->Dloc); 2177 ASSERT(FileInfo->ParentFile == DirInfo); 2178 2179 return status; 2180 } // end UDFOpenFile__() 2181 2182 2183 /* 2184 This routine inits UDF_FILE_INFO structure for root directory 2185 */ 2186 OSSTATUS 2187 UDFOpenRootFile__( 2188 IN PVCB Vcb, 2189 IN lb_addr* RootLoc, 2190 OUT PUDF_FILE_INFO FileInfo 2191 ) 2192 { 2193 uint32 RootLBA; 2194 OSSTATUS status; 2195 // uint32 PartNum = RootLoc->partitionReferenceNum; 2196 uint32 LBS = Vcb->LBlockSize; 2197 uint16 Ident; 2198 LONG_AD FELoc; 2199 EXTENT_AD FEExt; 2200 uint8 FileType; 2201 2202 RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO)); 2203 RootLBA = UDFPartLbaToPhys(Vcb,RootLoc); 2204 if(RootLBA == LBA_OUT_OF_EXTENT) 2205 return STATUS_FILE_CORRUPT_ERROR; 2206 FELoc.extLocation = *RootLoc; 2207 FELoc.extLength = LBS; 2208 // init horizontal links 2209 FileInfo->NextLinkedFile = 2210 FileInfo->PrevLinkedFile = FileInfo; 2211 // check for opened links 2212 if(!OS_SUCCESS(status = UDFStoreDloc(Vcb, FileInfo, RootLBA))) 2213 return status; 2214 if(FileInfo->Dloc->FileEntry) 2215 goto init_tree_entry; 2216 // read (Ex)FileEntry 2217 FileInfo->Dloc->FileEntry = (tag*)MyAllocatePoolTag__(NonPagedPool, LBS, MEM_FE_TAG); 2218 if(!(FileInfo->Dloc->FileEntry)) return STATUS_INSUFFICIENT_RESOURCES; 2219 2220 if(!OS_SUCCESS(status = UDFReadFileEntry(Vcb, &FELoc, (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &Ident))) 2221 return status; 2222 // build mappings for Data & AllocDescs 2223 FEExt.extLength = LBS; 2224 FEExt.extLocation = UDFPartLbaToPhys(Vcb, &(FELoc.extLocation) ); 2225 if(FEExt.extLocation == LBA_OUT_OF_EXTENT) 2226 return STATUS_FILE_CORRUPT_ERROR; 2227 FileInfo->Dloc->FELoc.Mapping = UDFExtentToMapping(&FEExt); 2228 if(!(FileInfo->Dloc->FELoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES; 2229 // build mappings for AllocDescs 2230 if(!FileInfo->Dloc->AllocLoc.Mapping) { 2231 FileInfo->Dloc->AllocLoc.Mapping = UDFExtentToMapping(&FEExt); 2232 if(!(FileInfo->Dloc->AllocLoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES; 2233 } 2234 if(!OS_SUCCESS(status = UDFLoadExtInfo(Vcb, (PFILE_ENTRY)(FileInfo->Dloc->FileEntry), &FELoc, 2235 &(FileInfo->Dloc->DataLoc), &(FileInfo->Dloc->AllocLoc) ) )) 2236 return status; 2237 FileInfo->Dloc->FileEntryLen = (uint32) 2238 (FileInfo->Dloc->FELoc.Length = (FileInfo->Dloc->DataLoc.Offset) ? FileInfo->Dloc->DataLoc.Offset : 2239 FileInfo->Dloc->AllocLoc.Offset); 2240 init_tree_entry: 2241 // resize FE cache (0x800 instead of 0x40 is not a good idea) 2242 if(!MyReallocPool__((int8*)((FileInfo->Dloc->FileEntry)), LBS, 2243 (int8**)&((FileInfo->Dloc->FileEntry)), FileInfo->Dloc->FileEntryLen)) 2244 return STATUS_INSUFFICIENT_RESOURCES; 2245 // init DirIndex 2246 if( (FileType = ((icbtag*)((FileInfo->Dloc->FileEntry)+1))->fileType) != UDF_FILE_TYPE_DIRECTORY && 2247 (FileType != UDF_FILE_TYPE_STREAMDIR) ) { 2248 UDFReferenceFile__(FileInfo); 2249 UDFReleaseDloc(Vcb, FileInfo->Dloc); 2250 return STATUS_SUCCESS; 2251 } 2252 // build index for directories 2253 if(!FileInfo->Dloc->DirIndex) { 2254 status = UDFIndexDirectory(Vcb, FileInfo); 2255 if(!OS_SUCCESS(status)) 2256 return status; 2257 #ifndef UDF_READ_ONLY_BUILD 2258 if((FileInfo->Dloc->DirIndex->DelCount > Vcb->PackDirThreshold) && 2259 !(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_READ_ONLY)) { 2260 status = UDFPackDirectory__(Vcb, FileInfo); 2261 if(!OS_SUCCESS(status)) 2262 return status; 2263 } 2264 #endif //UDF_READ_ONLY_BUILD 2265 } 2266 UDFReferenceFile__(FileInfo); 2267 UDFReleaseDloc(Vcb, FileInfo->Dloc); 2268 2269 return status; 2270 } // end UDFOpenRootFile__() 2271 2272 /* 2273 This routine frees all memory blocks referenced by given FileInfo 2274 */ 2275 uint32 2276 UDFCleanUpFile__( 2277 IN PVCB Vcb, 2278 IN PUDF_FILE_INFO FileInfo 2279 ) 2280 { 2281 PUDF_DATALOC_INFO Dloc; 2282 uint32 lc = 0; 2283 BOOLEAN IsASDir; 2284 BOOLEAN KeepDloc; 2285 PDIR_INDEX_ITEM DirNdx, DirNdx2; 2286 BOOLEAN Parallel = FALSE; 2287 BOOLEAN Linked = FALSE; 2288 #ifdef UDF_DBG 2289 BOOLEAN Modified = FALSE; 2290 PDIR_INDEX_HDR hDirNdx; 2291 uint_di Index; 2292 PUDF_FILE_INFO DirInfo; 2293 #endif // UDF_DBG 2294 2295 if(!FileInfo) return UDF_FREE_FILEINFO; 2296 2297 ValidateFileInfo(FileInfo); 2298 2299 if(FileInfo->OpenCount || FileInfo->RefCount) { 2300 UDFPrint(("UDF: not all references are closed\n")); 2301 UDFPrint((" Skipping cleanup\n")); 2302 UDFPrint(("UDF: OpenCount = %x, RefCount = %x, LinkRefCount = %x\n", 2303 FileInfo->OpenCount,FileInfo->RefCount,FileInfo->Dloc->LinkRefCount)); 2304 return UDF_FREE_NOTHING; 2305 } 2306 if(FileInfo->Fcb) { 2307 UDFPrint(("Operating System still has references to this file\n")); 2308 UDFPrint((" Skipping cleanup\n")); 2309 // BrutePoint(); 2310 return UDF_FREE_NOTHING; 2311 } 2312 2313 IsASDir = UDFIsAStreamDir(FileInfo); 2314 2315 if((Dloc = FileInfo->Dloc)) { 2316 2317 #ifdef UDF_DBG 2318 DirInfo = FileInfo->ParentFile; 2319 if(DirInfo) { 2320 hDirNdx = DirInfo->Dloc->DirIndex; 2321 Index = FileInfo->Index; 2322 // we can't delete modified file 2323 // it should be closed & reopened (or flushed) before deletion 2324 DirNdx = UDFDirIndex(hDirNdx,Index); 2325 UDFPrint(("Cleanup Mod: %s%s%s%s%s%s\n", 2326 (Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) ? "FE " : "", 2327 (Dloc->DataLoc.Modified) ? "DataLoc " : "", 2328 (Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) ? "Data-PreAlloc " : "", 2329 (Dloc->AllocLoc.Modified) ? "AllocLoc " : "", 2330 (Dloc->FELoc.Modified) ? "FELoc " : "", 2331 (DirNdx && (DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) ? "FI " : "" 2332 )); 2333 Modified = ((Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) || 2334 Dloc->DataLoc.Modified || 2335 (Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) || 2336 Dloc->AllocLoc.Modified || 2337 Dloc->FELoc.Modified || 2338 (DirNdx && (DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) ); 2339 } 2340 #endif // UDF_DBG 2341 2342 PUDF_FILE_INFO ParFileInfo = UDFLocateAnyParallelFI(FileInfo); 2343 2344 Parallel = (ParFileInfo != NULL); 2345 Linked = (FileInfo->NextLinkedFile != FileInfo); 2346 2347 // Parallel = (FileInfo->NextLinkedFile != FileInfo); 2348 ASSERT(FileInfo->NextLinkedFile); 2349 // ASSERT(!Parallel); 2350 KeepDloc = (Dloc->LinkRefCount || 2351 Dloc->CommonFcb || 2352 Linked ) ? 2353 TRUE : FALSE; 2354 2355 if(Dloc->DirIndex) { 2356 uint_di i; 2357 for(i=2; (DirNdx = UDFDirIndex(Dloc->DirIndex,i)); i++) { 2358 if(DirNdx->FileInfo) { 2359 if(!KeepDloc) { 2360 BrutePoint(); 2361 UDFPrint(("UDF: Found not cleaned up reference.\n")); 2362 UDFPrint((" Skipping cleanup (1)\n")); 2363 // BrutePoint(); 2364 return UDF_FREE_NOTHING; 2365 } 2366 // The file being cleaned up may have not closed Dirs 2367 // (linked Dir). In this case each of them may have 2368 // reference to FileInfo in DirIndex[1] 2369 // Here we'll check it and change for valid value if 2370 // necessary (Update Child Objects - I) 2371 if(DirNdx->FileInfo->Dloc) { 2372 // we can get here only when (Parallel == TRUE) 2373 DirNdx2 = UDFDirIndex(DirNdx->FileInfo->Dloc->DirIndex, 1); 2374 // It is enough to check DirNdx2->FileInfo only. 2375 // If one of Parallel FI's has reference (and equal) 2376 // to the FI being removed, it'll be removed from 2377 // the chain & nothing wrong will happen. 2378 if(DirNdx2 && (DirNdx2->FileInfo == FileInfo)) { 2379 if(FileInfo->PrevLinkedFile == FileInfo) { 2380 BrutePoint(); 2381 DirNdx2->FileInfo = NULL; 2382 } else { 2383 DirNdx2->FileInfo = Parallel ? 2384 ParFileInfo : FileInfo->PrevLinkedFile; 2385 } 2386 ASSERT(!DirNdx2->FileInfo->RefCount); 2387 } 2388 } 2389 } 2390 } 2391 } 2392 if(Dloc->SDirInfo) { 2393 UDFPrint(("UDF: Found not cleaned up reference (SDir).\n")); 2394 2395 // (Update Child Objects - II) 2396 if(Dloc->SDirInfo->ParentFile == FileInfo) { 2397 BrutePoint(); 2398 ASSERT(ParFileInfo); 2399 Dloc->SDirInfo->ParentFile = ParFileInfo; 2400 } 2401 // We should break Cleanup process if alive reference detected 2402 // and there is no possibility to store pointer in some other 2403 // place (in parallel object) 2404 if(!KeepDloc) { 2405 BrutePoint(); 2406 UDFPrint((" Skipping cleanup\n")); 2407 return UDF_FREE_NOTHING; 2408 } 2409 2410 if(!UDFIsSDirDeleted(Dloc->SDirInfo) && 2411 Dloc->SDirInfo->Dloc) { 2412 DirNdx2 = UDFDirIndex(Dloc->SDirInfo->Dloc->DirIndex, 1); 2413 if(DirNdx2 && (DirNdx2->FileInfo == FileInfo)) { 2414 DirNdx2->FileInfo = 2415 Parallel ? ParFileInfo : NULL; 2416 ASSERT(!DirNdx2->FileInfo->RefCount); 2417 } 2418 } 2419 } 2420 2421 if(!KeepDloc) { 2422 2423 #ifdef UDF_DBG 2424 ASSERT(!Modified); 2425 #endif 2426 2427 #ifndef UDF_TRACK_ONDISK_ALLOCATION 2428 if(Dloc->DataLoc.Mapping) MyFreePool__(Dloc->DataLoc.Mapping); 2429 if(Dloc->AllocLoc.Mapping) MyFreePool__(Dloc->AllocLoc.Mapping); 2430 if(Dloc->FELoc.Mapping) MyFreePool__(Dloc->FELoc.Mapping); 2431 if(Dloc->FileEntry) { 2432 // plain file 2433 lc = UDFGetFileLinkCount(FileInfo); 2434 MyFreePool__(Dloc->FileEntry); 2435 Dloc->FileEntry = NULL; 2436 } else if(FileInfo->Index >= 2) { 2437 // error durring open operation 2438 lc = UDF_INVALID_LINK_COUNT; 2439 } 2440 #endif //UDF_TRACK_ONDISK_ALLOCATION 2441 if(FileInfo->Dloc->DirIndex) { 2442 uint_di i; 2443 for(i=2; (DirNdx = UDFDirIndex(Dloc->DirIndex,i)); i++) { 2444 ASSERT(!DirNdx->FileInfo); 2445 if(DirNdx->FName.Buffer) 2446 MyFreePool__(DirNdx->FName.Buffer); 2447 } 2448 // The only place where we can free FE_Charge extent is here 2449 UDFFlushFESpace(Vcb, Dloc); 2450 UDFDirIndexFree(Dloc->DirIndex); 2451 Dloc->DirIndex = NULL; 2452 #ifdef UDF_TRACK_ONDISK_ALLOCATION 2453 UDFIndexDirectory(Vcb, FileInfo); 2454 if(FileInfo->Dloc->DirIndex) { 2455 for(i=2; DirNdx = UDFDirIndex(Dloc->DirIndex,i); i++) { 2456 ASSERT(!DirNdx->FileInfo); 2457 if(DirNdx->FName.Buffer) 2458 MyFreePool__(DirNdx->FName.Buffer); 2459 } 2460 UDFDirIndexFree(Dloc->DirIndex); 2461 Dloc->DirIndex = NULL; 2462 } 2463 #endif //UDF_TRACK_ONDISK_ALLOCATION 2464 } 2465 2466 #ifdef UDF_TRACK_ONDISK_ALLOCATION 2467 if(Dloc->AllocLoc.Mapping) MyFreePool__(Dloc->AllocLoc.Mapping); 2468 if(Dloc->FELoc.Mapping) MyFreePool__(Dloc->FELoc.Mapping); 2469 if(Dloc->FileEntry) { 2470 // plain file 2471 lc = UDFGetFileLinkCount(FileInfo); 2472 MyFreePool__(Dloc->FileEntry); 2473 Dloc->FileEntry = NULL; 2474 } else if(FileInfo->Index >= 2) { 2475 // error durring open operation 2476 lc = UDF_INVALID_LINK_COUNT; 2477 } 2478 if(Dloc->DataLoc.Mapping) { 2479 if(lc && (lc != UDF_INVALID_LINK_COUNT)) { 2480 UDFCheckSpaceAllocation(Vcb, 0, Dloc->DataLoc.Mapping, AS_USED); // check if used 2481 } else { 2482 UDFCheckSpaceAllocation(Vcb, 0, Dloc->DataLoc.Mapping, AS_FREE); // check if free 2483 } 2484 MyFreePool__(Dloc->DataLoc.Mapping); 2485 } 2486 #endif //UDF_TRACK_ONDISK_ALLOCATION 2487 2488 if(lc && (lc != UDF_INVALID_LINK_COUNT)) { 2489 UDFRemoveDloc(Vcb, Dloc); 2490 } else { 2491 UDFFreeDloc(Vcb, Dloc); 2492 } 2493 } else // KeepDloc cannot be FALSE if (Linked == TRUE) 2494 if(Linked) { 2495 // BrutePoint(); 2496 // Update pointers in ParentObject (if any) 2497 if(FileInfo->ParentFile->Dloc->SDirInfo == FileInfo) 2498 FileInfo->ParentFile->Dloc->SDirInfo = FileInfo->PrevLinkedFile; 2499 DirNdx = UDFDirIndex(FileInfo->Dloc->DirIndex, 0); 2500 if(DirNdx && (DirNdx->FileInfo == FileInfo)) 2501 DirNdx->FileInfo = FileInfo->PrevLinkedFile; 2502 DirNdx = UDFDirIndex(FileInfo->ParentFile->Dloc->DirIndex, FileInfo->Index); 2503 if(DirNdx && (DirNdx->FileInfo == FileInfo)) 2504 DirNdx->FileInfo = ParFileInfo; 2505 // remove from linked chain 2506 FileInfo->NextLinkedFile->PrevLinkedFile = FileInfo->PrevLinkedFile; 2507 FileInfo->PrevLinkedFile->NextLinkedFile = FileInfo->NextLinkedFile; 2508 // update pointer in Dloc 2509 if(FileInfo->Dloc->LinkedFileInfo == FileInfo) 2510 FileInfo->Dloc->LinkedFileInfo = FileInfo->PrevLinkedFile; 2511 } 2512 FileInfo->Dloc = NULL; 2513 } else { 2514 KeepDloc = FALSE; 2515 } 2516 2517 // Cleanup pointers in ParentObject (if any) 2518 if(IsASDir) { 2519 if(FileInfo->ParentFile->Dloc->SDirInfo == FileInfo) { 2520 ASSERT(!Linked); 2521 FileInfo->ParentFile->Dloc->SDirInfo = NULL; 2522 FileInfo->ParentFile->Dloc->FE_Flags &= ~UDF_FE_FLAG_HAS_DEL_SDIR; 2523 } 2524 } else 2525 if(FileInfo->ParentFile) { 2526 ASSERT(FileInfo->ParentFile->Dloc); 2527 DirNdx = UDFDirIndex(FileInfo->ParentFile->Dloc->DirIndex, FileInfo->Index); 2528 ASSERT(DirNdx); 2529 #ifdef UDF_DBG 2530 PUDF_FILE_INFO OldFI; 2531 if(Parallel) { 2532 ASSERT(!DirNdx || !(OldFI = DirNdx->FileInfo) || 2533 !(OldFI == FileInfo)); 2534 } else { 2535 ASSERT(!DirNdx || !(OldFI = DirNdx->FileInfo) || 2536 (OldFI == FileInfo)); 2537 } 2538 #endif 2539 if( DirNdx && (DirNdx->FileInfo == FileInfo) ) { 2540 if(!Parallel) 2541 DirNdx->FileInfo = NULL; 2542 #ifdef UDF_DBG 2543 } else { 2544 // We can get here after incomplete Open 2545 if(!Parallel && DirNdx->FileInfo) 2546 BrutePoint(); 2547 #endif 2548 } 2549 #ifdef UDF_DBG 2550 } else { 2551 // BrutePoint(); 2552 #endif 2553 } 2554 2555 if(!Parallel && FileInfo->FileIdent) 2556 MyFreePool__(FileInfo->FileIdent); 2557 FileInfo->FileIdent = NULL; 2558 // Kill reference to parent object 2559 FileInfo->ParentFile = NULL; 2560 // Kill references to parallel object(s) since it has no reference to 2561 // this one now 2562 FileInfo->NextLinkedFile = 2563 FileInfo->PrevLinkedFile = FileInfo; 2564 if(FileInfo->ListPtr) 2565 FileInfo->ListPtr->FileInfo = NULL;; 2566 return KeepDloc ? UDF_FREE_FILEINFO : (UDF_FREE_FILEINFO | UDF_FREE_DLOC); 2567 } // end UDFCleanUpFile__() 2568 2569 #ifndef UDF_READ_ONLY_BUILD 2570 /* 2571 This routine creates FileIdent record in destination directory & 2572 allocates FileEntry with in-ICB zero-sized data 2573 If it returns status != STATUS_SUCCESS caller should call UDFCleanUpFile__ 2574 for returned pointer *WITHOUT* using UDFCloseFile__ 2575 */ 2576 OSSTATUS 2577 UDFCreateFile__( 2578 IN PVCB Vcb, 2579 // IN uint16 AllocMode, // short/long/ext/in-icb // always in-ICB 2580 IN BOOLEAN IgnoreCase, 2581 IN PUNICODE_STRING _fn, 2582 IN uint32 ExtAttrSz, 2583 IN uint32 ImpUseLen, 2584 IN BOOLEAN Extended, 2585 IN BOOLEAN CreateNew, 2586 IN OUT PUDF_FILE_INFO DirInfo, 2587 OUT PUDF_FILE_INFO* _FileInfo 2588 ) 2589 { 2590 uint32 l, d; 2591 uint_di i, j; 2592 OSSTATUS status; 2593 LONG_AD FEicb; 2594 UDF_DIR_SCAN_CONTEXT ScanContext; 2595 PDIR_INDEX_HDR hDirNdx = DirInfo->Dloc->DirIndex; 2596 PDIR_INDEX_ITEM DirNdx; 2597 uint32 LBS = Vcb->LBlockSize; 2598 PUDF_FILE_INFO FileInfo; 2599 *_FileInfo = NULL; 2600 BOOLEAN undel = FALSE; 2601 SIZE_T ReadBytes; 2602 // BOOLEAN PackDir = FALSE; 2603 BOOLEAN FEAllocated = FALSE; 2604 2605 ValidateFileInfo(DirInfo); 2606 *_FileInfo = NULL; 2607 2608 ASSERT(DirInfo->Dloc->FELoc.Mapping[0].extLocation); 2609 uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, DirInfo->Dloc->FELoc.Mapping[0].extLocation); 2610 if(!hDirNdx) return STATUS_NOT_A_DIRECTORY; 2611 i = 0; 2612 2613 _SEH2_TRY { 2614 2615 // check if exists 2616 status = UDFFindFile(Vcb, IgnoreCase, FALSE, _fn, DirInfo, &i); 2617 DirNdx = UDFDirIndex(hDirNdx,i); 2618 if(OS_SUCCESS(status)) { 2619 // file is a Cur(Parent)Dir 2620 if(i<2) try_return (status = STATUS_ACCESS_DENIED); 2621 // file deleted 2622 if(UDFIsDeleted(DirNdx)) { 2623 j=0; 2624 if(OS_SUCCESS(UDFFindFile(Vcb, IgnoreCase, TRUE, _fn, DirInfo, &j))) { 2625 i=j; 2626 DirNdx = UDFDirIndex(hDirNdx,i); 2627 goto CreateBothFound; 2628 } 2629 // we needn't allocating new FileIdent inside Dir stream 2630 // perform 'undel' 2631 if(DirNdx->FileInfo) { 2632 // BrutePoint(); 2633 status = UDFPretendFileDeleted__(Vcb, DirNdx->FileInfo); 2634 if(!OS_SUCCESS(status)) 2635 try_return (status = STATUS_FILE_DELETED); 2636 } else { 2637 undel = TRUE; 2638 } 2639 // BrutePoint(); 2640 goto CreateUndel; 2641 } 2642 CreateBothFound: 2643 // file already exists 2644 if(CreateNew) try_return (status = STATUS_ACCESS_DENIED); 2645 // try to open it 2646 BrutePoint(); 2647 status = UDFOpenFile__(Vcb, IgnoreCase, TRUE, _fn, DirInfo, _FileInfo,&i); 2648 // *_FileInfo = FileInfo; // OpenFile__ has already done it, so update it... 2649 DirNdx = UDFDirIndex(hDirNdx,i); 2650 DirNdx->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR; 2651 FileInfo = *_FileInfo; 2652 if(!OS_SUCCESS(status)) { 2653 // :(( can't open.... 2654 if(FileInfo && UDFCleanUpFile__(Vcb, FileInfo)) { 2655 MyFreePool__(FileInfo); 2656 *_FileInfo = NULL; 2657 } 2658 BrutePoint(); 2659 try_return (status); 2660 } 2661 // check if we can delete this file 2662 if(FileInfo->OpenCount || (FileInfo->RefCount > 1)) { 2663 BrutePoint(); 2664 UDFCloseFile__(Vcb, FileInfo); 2665 try_return (status = STATUS_CANNOT_DELETE); 2666 } 2667 BrutePoint(); 2668 // remove DIRECTORY flag 2669 DirNdx->FileCharacteristics &= ~FILE_DIRECTORY; 2670 FileInfo->FileIdent->fileCharacteristics &= ~FILE_DIRECTORY; 2671 DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; 2672 // truncate file size to ZERO 2673 status = UDFResizeFile__(Vcb, FileInfo, 0); 2674 if(!OS_SUCCESS(status)) { 2675 BrutePoint(); 2676 UDFCloseFile__(Vcb, FileInfo); 2677 } 2678 // set NORMAL flag 2679 FileInfo->FileIdent->fileCharacteristics = 0; 2680 DirNdx->FileCharacteristics = 0; 2681 // update DeletedFiles counter in Directory... (for PackDir) 2682 if(undel && OS_SUCCESS(status)) 2683 hDirNdx->DelCount--; 2684 try_return (status); 2685 } 2686 2687 CreateUndel: 2688 2689 // allocate FileInfo 2690 FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_FE_TAG); 2691 *_FileInfo = FileInfo; 2692 if(!FileInfo) 2693 try_return (status = STATUS_INSUFFICIENT_RESOURCES); 2694 ImpUseLen = (ImpUseLen + 3) & ~((uint16)3); 2695 2696 RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO)); 2697 // init horizontal links 2698 FileInfo->NextLinkedFile = 2699 FileInfo->PrevLinkedFile = FileInfo; 2700 // allocate space for FileEntry 2701 if(!OS_SUCCESS(status = 2702 UDFBuildFileEntry(Vcb, DirInfo, FileInfo, PartNum, ICB_FLAG_AD_IN_ICB, ExtAttrSz, Extended) )) { 2703 BrutePoint(); 2704 try_return (status); 2705 } 2706 FEAllocated = TRUE; 2707 FEicb.extLength = LBS; 2708 ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); 2709 FEicb.extLocation.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, FileInfo->Dloc->FELoc.Mapping[0].extLocation); 2710 FEicb.extLocation.partitionReferenceNum = (uint16)PartNum; 2711 RtlZeroMemory(&(FEicb.impUse), sizeof(FEicb.impUse)); 2712 2713 if(!undel) { 2714 // build FileIdent 2715 if(!OS_SUCCESS(status = 2716 UDFBuildFileIdent(Vcb, _fn, &FEicb, ImpUseLen, 2717 &(FileInfo->FileIdent), &(FileInfo->FileIdentLen)) )) 2718 try_return (status); 2719 } else { 2720 // read FileIdent 2721 FileInfo->FileIdent = (PFILE_IDENT_DESC)MyAllocatePoolTag__(NonPagedPool, DirNdx->Length, MEM_FID_TAG); 2722 if(!(FileInfo->FileIdent)) try_return (status = STATUS_INSUFFICIENT_RESOURCES); 2723 FileInfo->FileIdentLen = DirNdx->Length; 2724 if(!OS_SUCCESS(status = UDFReadExtent(Vcb, &(DirInfo->Dloc->DataLoc), DirNdx->Offset, 2725 DirNdx->Length, FALSE, (int8*)(FileInfo->FileIdent), &ReadBytes) )) 2726 try_return (status); 2727 FileInfo->FileIdent->fileCharacteristics = 0; 2728 FileInfo->FileIdent->icb = FEicb; 2729 ImpUseLen = FileInfo->FileIdent->lengthOfImpUse; 2730 DirNdx->FileCharacteristics = 0; 2731 } 2732 // init 'parentICBLocation' & so on in FE 2733 ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum = 2734 UDFPhysLbaToPart(Vcb, PartNum, DirInfo->Dloc->FELoc.Mapping[0].extLocation); 2735 ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum = (uint16)PartNum; 2736 // ((icbtag*)(FileInfo->Dloc->FileEntry+1))->strategyType = 4; 2737 // ((icbtag*)(FileInfo->Dloc->FileEntry+1))->numEntries = 1; 2738 // try to find suitable unused FileIdent in DirIndex 2739 l = FileInfo->FileIdentLen; 2740 if(undel) goto CrF__2; 2741 #ifndef UDF_LIMIT_DIR_SIZE 2742 if(Vcb->CDR_Mode) { 2743 #endif // UDF_LIMIT_DIR_SIZE 2744 // search for suitable unused entry 2745 if(UDFDirIndexInitScan(DirInfo, &ScanContext, 2)) { 2746 while((DirNdx = UDFDirIndexScan(&ScanContext, NULL))) { 2747 if((DirNdx->Length == l) && UDFIsDeleted(DirNdx) && 2748 !DirNdx->FileInfo ) { 2749 // free unicode-buffer with old name 2750 if(DirNdx->FName.Buffer) { 2751 MyFreePool__(DirNdx->FName.Buffer); 2752 DirNdx->FName.Buffer = NULL; 2753 } 2754 i = ScanContext.i; 2755 goto CrF__1; 2756 } 2757 } 2758 } 2759 #ifndef UDF_LIMIT_DIR_SIZE 2760 } else { 2761 #endif // UDF_LIMIT_DIR_SIZE 2762 i = UDFDirIndexGetLastIndex(hDirNdx); // 'i' points beyond EO DirIndex 2763 #ifndef UDF_LIMIT_DIR_SIZE 2764 } 2765 #endif // UDF_LIMIT_DIR_SIZE 2766 2767 // append entry 2768 if(!OS_SUCCESS(status = UDFDirIndexGrow(&(DirInfo->Dloc->DirIndex), 1))) { 2769 try_return (status); 2770 } 2771 2772 // init offset of new FileIdent in directory Data extent 2773 hDirNdx = DirInfo->Dloc->DirIndex; 2774 if(i-1) { 2775 DirNdx = UDFDirIndex(hDirNdx,i-1); 2776 UDFDirIndex(hDirNdx,i)->Offset = DirNdx->Offset + DirNdx->Length; 2777 DirNdx = UDFDirIndex(hDirNdx,i); 2778 } else { 2779 DirNdx = UDFDirIndex(hDirNdx,i); 2780 DirNdx->Offset = 0; 2781 } 2782 // new terminator is recorded by UDFDirIndexGrow() 2783 if( ((d = ((LBS - (DirNdx->Offset + l + DirInfo->Dloc->DataLoc.Offset)) & (LBS-1) )) < sizeof(FILE_IDENT_DESC)) && 2784 d ) { 2785 // insufficient space at the end of last sector for 2786 // next FileIdent's tag. fill it with ImpUse data 2787 2788 // generally, all data should be DWORD-aligned, but if it is not so 2789 // this opearation will help us to avoid glitches 2790 d = (d+3) & ~((uint32)3); 2791 2792 uint32 IUl, FIl; 2793 if(!MyReallocPool__((int8*)(FileInfo->FileIdent), l, 2794 (int8**)&(FileInfo->FileIdent), (l+d+3) & ~((uint32)(3)) )) 2795 try_return (status = STATUS_INSUFFICIENT_RESOURCES); 2796 l += d; 2797 IUl = FileInfo->FileIdent->lengthOfImpUse; 2798 FIl = FileInfo->FileIdent->lengthFileIdent; 2799 // move filename to higher addr 2800 RtlMoveMemory(((int8*)(FileInfo->FileIdent+1))+IUl+d, 2801 ((int8*)(FileInfo->FileIdent+1))+IUl, FIl); 2802 RtlZeroMemory(((int8*)(FileInfo->FileIdent+1))+IUl, d); 2803 FileInfo->FileIdent->lengthOfImpUse += (uint16)d; 2804 FileInfo->FileIdentLen = l; 2805 } 2806 DirNdx->Length = l; 2807 CrF__1: 2808 // clone unicode string 2809 // it **<<MUST>>** be allocated with internal memory manager 2810 DirNdx->FName.Buffer = (PWCHAR)MyAllocatePoolTag__(UDF_FILENAME_MT, (DirNdx->FName.MaximumLength = _fn->Length + sizeof(WCHAR)), MEM_FNAMECPY_TAG); 2811 DirNdx->FName.Length = _fn->Length; 2812 if(!DirNdx->FName.Buffer) 2813 try_return (status = STATUS_INSUFFICIENT_RESOURCES); 2814 RtlCopyMemory(DirNdx->FName.Buffer, _fn->Buffer, _fn->Length); 2815 DirNdx->FName.Buffer[_fn->Length/sizeof(WCHAR)] = 0; 2816 CrF__2: 2817 DirNdx->FI_Flags |= UDFBuildHashEntry(Vcb, &(DirNdx->FName), &(DirNdx->hashes), HASH_ALL); 2818 // we get here immediately when 'undel' occured 2819 FileInfo->Index = i; 2820 DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; 2821 DirNdx->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR; 2822 ASSERT(!DirNdx->FileInfo); 2823 DirNdx->FileInfo = FileInfo; 2824 DirNdx->FileEntryLoc = FEicb.extLocation; 2825 // mark file as 'deleted' for now 2826 DirNdx->FileCharacteristics = FILE_DELETED; 2827 FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED; 2828 FileInfo->Dloc->DataLoc.Mapping = UDFExtentToMapping(&(FileInfo->Dloc->FELoc.Mapping[0])); 2829 if(!(FileInfo->Dloc->DataLoc.Mapping)) { 2830 UDFFlushFI(Vcb, FileInfo, PartNum); 2831 try_return (status = STATUS_INSUFFICIENT_RESOURCES); 2832 } 2833 FileInfo->Dloc->DataLoc.Length = 0; 2834 FileInfo->Dloc->DataLoc.Offset = FileInfo->Dloc->FileEntryLen; 2835 FileInfo->ParentFile = DirInfo; 2836 // init FileEntry 2837 UDFSetFileUID(Vcb, FileInfo); 2838 UDFSetFileSize(FileInfo, 0); 2839 UDFIncFileLinkCount(FileInfo); // increase to 1 2840 UDFUpdateCreateTime(Vcb, FileInfo); 2841 UDFAttributesToUDF(UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index), 2842 FileInfo->Dloc->FileEntry, Vcb->DefaultAttr); 2843 FileInfo->Dloc->DataLoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK; 2844 FileInfo->Dloc->DataLoc.Modified = TRUE; 2845 FileInfo->Dloc->FELoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK; 2846 // zero sector for FileEntry 2847 if(!Vcb->CDR_Mode) { 2848 status = UDFWriteData(Vcb, TRUE, ((int64)(FileInfo->Dloc->FELoc.Mapping[0].extLocation)) << Vcb->BlockSizeBits, LBS, FALSE, Vcb->ZBuffer, &ReadBytes); 2849 if(!OS_SUCCESS(status)) { 2850 UDFFlushFI(Vcb, FileInfo, PartNum); 2851 try_return (status); 2852 } 2853 } 2854 #if 0 2855 if((i >= 2) && (DirNdx->FName.Buffer[0] == L'.')) { 2856 BrutePoint(); 2857 } 2858 #endif 2859 2860 #ifdef UDF_CHECK_DISK_ALLOCATION 2861 if( /*FileInfo->Fcb &&*/ 2862 UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) { 2863 2864 if(!FileInfo->FileIdent || 2865 !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED)) { 2866 AdPrint(("Flushing to Discarded block %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation)); 2867 BrutePoint(); 2868 } 2869 } 2870 #endif // UDF_CHECK_DISK_ALLOCATION 2871 2872 // make FileIdent valid 2873 FileInfo->FileIdent->fileCharacteristics = 0; 2874 DirNdx->FileCharacteristics = 0; 2875 UDFReferenceFile__(FileInfo); 2876 UDFFlushFE(Vcb, FileInfo, PartNum); 2877 if(undel) 2878 hDirNdx->DelCount--; 2879 UDFReleaseDloc(Vcb, FileInfo->Dloc); 2880 UDFIncFileCounter(Vcb); 2881 2882 UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used 2883 2884 try_return (status = STATUS_SUCCESS); 2885 2886 try_exit: NOTHING; 2887 2888 } _SEH2_FINALLY { 2889 if(!OS_SUCCESS(status)) { 2890 if(FEAllocated) 2891 UDFFreeFESpace(Vcb, DirInfo, &(FileInfo->Dloc->FELoc)); 2892 } 2893 } _SEH2_END 2894 return status; 2895 2896 } // end UDFCreateFile__() 2897 #endif //UDF_READ_ONLY_BUILD 2898 2899 /* 2900 This routine reads data from file described by FileInfo 2901 */ 2902 /*__inline 2903 OSSTATUS 2904 UDFReadFile__( 2905 IN PVCB Vcb, 2906 IN PUDF_FILE_INFO FileInfo, 2907 IN int64 Offset, // offset in extent 2908 IN SIZE_T Length, 2909 IN BOOLEAN Direct, 2910 OUT int8* Buffer, 2911 OUT PSIZE_T ReadBytes 2912 ) 2913 { 2914 ValidateFileInfo(FileInfo); 2915 2916 return UDFReadExtent(Vcb, &(FileInfo->Dloc->DataLoc), Offset, Length, Direct, Buffer, ReadBytes); 2917 } // end UDFReadFile__()*/ 2918 2919 #ifndef UDF_READ_ONLY_BUILD 2920 /* 2921 This routine zeros data in file described by FileInfo 2922 */ 2923 __inline 2924 OSSTATUS 2925 UDFZeroFile__( 2926 IN PVCB Vcb, 2927 IN PUDF_FILE_INFO FileInfo, 2928 IN int64 Offset, // offset in extent 2929 IN SIZE_T Length, 2930 IN BOOLEAN Direct, 2931 OUT PSIZE_T ReadBytes 2932 ) 2933 { 2934 ValidateFileInfo(FileInfo); 2935 2936 return UDFZeroExtent__(Vcb, &(FileInfo->Dloc->DataLoc), Offset, Length, Direct, ReadBytes); 2937 } // end UDFZeroFile__()*/ 2938 2939 /* 2940 This routine makes sparse area in file described by FileInfo 2941 */ 2942 __inline 2943 OSSTATUS 2944 UDFSparseFile__( 2945 IN PVCB Vcb, 2946 IN PUDF_FILE_INFO FileInfo, 2947 IN int64 Offset, // offset in extent 2948 IN SIZE_T Length, 2949 IN BOOLEAN Direct, 2950 OUT PSIZE_T ReadBytes 2951 ) 2952 { 2953 ValidateFileInfo(FileInfo); 2954 2955 return UDFSparseExtent__(Vcb, &(FileInfo->Dloc->DataLoc), Offset, Length, Direct, ReadBytes); 2956 } // end UDFSparseFile__()*/ 2957 2958 /* 2959 This routine fills tails of the last sector in extent with ZEROs 2960 */ 2961 OSSTATUS 2962 UDFPadLastSector( 2963 IN PVCB Vcb, 2964 IN PEXTENT_INFO ExtInfo 2965 ) 2966 { 2967 if(!ExtInfo || !(ExtInfo->Mapping) || !(ExtInfo->Length)) return STATUS_INVALID_PARAMETER; 2968 2969 PEXTENT_MAP Extent = ExtInfo->Mapping; // Extent array 2970 SIZE_T to_write, WrittenBytes; 2971 uint32 Lba, sect_offs, flags; 2972 OSSTATUS status; 2973 // Length should not be zero 2974 int64 Offset = ExtInfo->Length + ExtInfo->Offset; 2975 // data is sector-size-aligned, we needn't any padding 2976 if(Offset && !((uint32)Offset & (Vcb->LBlockSize-1) )) return STATUS_SUCCESS; 2977 // get Lba of the last sector 2978 Lba = UDFExtentOffsetToLba(Vcb, Extent, Offset, §_offs, &to_write, &flags, NULL); 2979 // EOF check. If we have valid ExtInfo this will not happen, but who knows.. 2980 if((Lba == (uint32)-1) || 2981 (flags == EXTENT_NOT_RECORDED_NOT_ALLOCATED)) 2982 return STATUS_END_OF_FILE; 2983 // write tail 2984 status = UDFWriteData(Vcb, TRUE, (((int64)Lba) << Vcb->BlockSizeBits) + sect_offs, to_write, FALSE, Vcb->ZBuffer, &WrittenBytes); 2985 return status; 2986 } // UDFPadLastSector() 2987 #endif //UDF_READ_ONLY_BUILD 2988 2989 /* 2990 This routine updates AllocDesc sequence, FileIdent & FileEntry 2991 for given file 2992 */ 2993 OSSTATUS 2994 UDFCloseFile__( 2995 IN PVCB Vcb, 2996 IN PUDF_FILE_INFO FileInfo 2997 ) 2998 { 2999 ValidateFileInfo(FileInfo); 3000 3001 if(!FileInfo) return STATUS_SUCCESS; 3002 if(FileInfo->Index<2 && (FileInfo->ParentFile) && !UDFIsAStreamDir(FileInfo)) { 3003 UDFPrint(("Closing Current or Parent Directory... :-\\\n")); 3004 if(FileInfo->RefCount) { 3005 UDFInterlockedDecrement((PLONG)&(FileInfo->RefCount)); 3006 ASSERT(FileInfo->Dloc); 3007 if(FileInfo->Dloc) 3008 UDFInterlockedDecrement((PLONG)&(FileInfo->Dloc->LinkRefCount)); 3009 #ifdef UDF_DBG 3010 } else { 3011 BrutePoint(); 3012 UDFPrint(("ERROR: Closing unreferenced file!\n")); 3013 #endif // UDF_DBG 3014 } 3015 if(FileInfo->ParentFile->OpenCount) { 3016 UDFInterlockedDecrement((PLONG)&(FileInfo->ParentFile->OpenCount)); 3017 #ifdef UDF_DBG 3018 } else { 3019 BrutePoint(); 3020 UDFPrint(("ERROR: Closing unopened file!\n")); 3021 #endif // UDF_DBG 3022 } 3023 return STATUS_SUCCESS; 3024 } 3025 PUDF_FILE_INFO DirInfo = FileInfo->ParentFile; 3026 OSSTATUS status; 3027 uint32 PartNum; 3028 if(FileInfo->RefCount) { 3029 UDFInterlockedDecrement((PLONG)&(FileInfo->RefCount)); 3030 ASSERT(FileInfo->Dloc); 3031 if(FileInfo->Dloc) 3032 UDFInterlockedDecrement((PLONG)&(FileInfo->Dloc->LinkRefCount)); 3033 #ifdef UDF_DBG 3034 } else { 3035 BrutePoint(); 3036 UDFPrint(("ERROR: Closing unreferenced file!\n")); 3037 #endif // UDF_DBG 3038 } 3039 if(DirInfo) { 3040 // validate DirInfo 3041 ValidateFileInfo(DirInfo); 3042 3043 if(DirInfo->OpenCount) { 3044 UDFInterlockedDecrement((PLONG)&(DirInfo->OpenCount)); 3045 #ifdef UDF_DBG 3046 } else { 3047 BrutePoint(); 3048 UDFPrint(("ERROR: Closing unopened file!\n")); 3049 #endif // UDF_DBG 3050 } 3051 } 3052 // If the file has gone (unlinked) we should return STATUS_SUCCESS here. 3053 if(!FileInfo->Dloc) return STATUS_SUCCESS; 3054 3055 if(FileInfo->RefCount || 3056 FileInfo->OpenCount || 3057 !(FileInfo->Dloc->FELoc.Mapping)) return STATUS_SUCCESS; 3058 // ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); 3059 PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation); 3060 if(PartNum == (uint32)-1) { 3061 UDFPrint((" Is DELETED ?\n")); 3062 if(DirInfo) { 3063 PartNum = UDFGetPartNumByPhysLba(Vcb, DirInfo->Dloc->FELoc.Mapping[0].extLocation); 3064 } else { 3065 BrutePoint(); 3066 } 3067 } 3068 #ifdef UDF_CHECK_DISK_ALLOCATION 3069 if( FileInfo->Fcb && 3070 UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) { 3071 3072 //ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); 3073 if(UDFIsAStreamDir(FileInfo)) { 3074 if(!UDFIsSDirDeleted(FileInfo)) { 3075 UDFPrint((" Not DELETED SDir\n")); 3076 BrutePoint(); 3077 } 3078 ASSERT(!FileInfo->Dloc->FELoc.Modified); 3079 } else 3080 if(!FileInfo->FileIdent || 3081 !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED)) { 3082 if(!FileInfo->FileIdent) { 3083 AdPrint((" No FileIdent\n")); 3084 } 3085 if(FileInfo->FileIdent && 3086 !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED)) 3087 AdPrint((" Not DELETED\n")); 3088 ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); 3089 AdPrint(("Flushing to Discarded block %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation)); 3090 BrutePoint(); 3091 } else { 3092 UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_FREE); // check if free 3093 UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->FELoc.Mapping, AS_FREE); // check if free 3094 } 3095 } else { 3096 if(!FileInfo->Dloc->FELoc.Mapping[0].extLocation || 3097 UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) { 3098 UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_FREE); // check if free 3099 } else { 3100 UDFCheckSpaceAllocation(Vcb, 0, FileInfo->Dloc->DataLoc.Mapping, AS_USED); // check if used 3101 } 3102 } 3103 #endif // UDF_CHECK_DISK_ALLOCATION 3104 // check if we should update parentICBLocation 3105 if( !((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum && 3106 !((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum && 3107 DirInfo && 3108 !Vcb->CDR_Mode && 3109 Vcb->Modified && 3110 UDFGetFileLinkCount(FileInfo) ) { 3111 ASSERT(DirInfo->Dloc->FELoc.Mapping[0].extLocation); 3112 ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.logicalBlockNum = 3113 UDFPhysLbaToPart(Vcb, PartNum, DirInfo->Dloc->FELoc.Mapping[0].extLocation); 3114 ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation.partitionReferenceNum = (uint16)PartNum; 3115 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; 3116 } 3117 3118 // we needn't flushing FE & Allocs untill all links are closed... 3119 if(!FileInfo->Dloc->LinkRefCount) { 3120 3121 // flush FE and pre-allocation charge for directories 3122 if(FileInfo->Dloc && 3123 FileInfo->Dloc->DirIndex) { 3124 3125 UDFFlushFESpace(Vcb, FileInfo->Dloc); 3126 if(FileInfo->Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) { 3127 FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_CUT_PREALLOCATED; 3128 status = UDFResizeExtent(Vcb, PartNum, UDFGetFileSize(FileInfo), FALSE, &(FileInfo->Dloc->DataLoc)); 3129 FileInfo->Dloc->DataLoc.Flags &= ~(EXTENT_FLAG_PREALLOCATED | EXTENT_FLAG_CUT_PREALLOCATED); 3130 if(OS_SUCCESS(status)) { 3131 AdPrint(("Dir pre-alloc truncated (Close)\n")); 3132 FileInfo->Dloc->DataLoc.Modified = TRUE; 3133 } 3134 } 3135 } 3136 3137 if(!OS_SUCCESS(status = UDFFlushFE(Vcb, FileInfo, PartNum))) { 3138 UDFPrint(("Error flushing FE\n")); 3139 //flush_recovery: 3140 BrutePoint(); 3141 if(FileInfo->Index >= 2) { 3142 PDIR_INDEX_ITEM DirNdx; 3143 DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index); 3144 if(DirNdx) { 3145 UDFPrint(("Recovery: mark as deleted & flush FI\n")); 3146 DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; 3147 DirNdx->FileCharacteristics |= FILE_DELETED; 3148 FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED; 3149 UDFFlushFI(Vcb, FileInfo, PartNum); 3150 } 3151 } 3152 return status; 3153 } 3154 } 3155 // ... but FI must be updated (if any) 3156 if(!OS_SUCCESS(status = UDFFlushFI(Vcb, FileInfo, PartNum))) { 3157 UDFPrint(("Error flushing FI\n")); 3158 return status; 3159 } 3160 #ifdef UDF_DBG 3161 // ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); 3162 if((FileInfo->Dloc->FileEntry->descVersion != 2) && 3163 (FileInfo->Dloc->FileEntry->descVersion != 3)) { 3164 ASSERT(UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)); 3165 } 3166 #endif // UDF_DBG 3167 return STATUS_SUCCESS; 3168 } // end UDFCloseFile__() 3169 3170 3171 #ifndef UDF_READ_ONLY_BUILD 3172 /* 3173 This routine moves file from DirInfo1 to DirInfo2 & renames it to fn 3174 */ 3175 OSSTATUS 3176 UDFRenameMoveFile__( 3177 IN PVCB Vcb, 3178 IN BOOLEAN IgnoreCase, 3179 IN OUT BOOLEAN* Replace, // replace if destination file exists 3180 IN PUNICODE_STRING fn, // destination 3181 IN OUT PUDF_FILE_INFO DirInfo1, 3182 IN OUT PUDF_FILE_INFO DirInfo2, 3183 IN OUT PUDF_FILE_INFO FileInfo // source (opened) 3184 ) 3185 { 3186 PUDF_FILE_INFO FileInfo2; 3187 OSSTATUS status; 3188 PDIR_INDEX_ITEM DirNdx1; 3189 PDIR_INDEX_ITEM DirNdx2; 3190 uint_di i,j; 3191 BOOLEAN Recovery = FALSE; 3192 BOOLEAN SameFE = FALSE; 3193 uint32 NTAttr = 0; 3194 3195 // validate FileInfo 3196 ValidateFileInfo(DirInfo1); 3197 ValidateFileInfo(DirInfo2); 3198 ValidateFileInfo(FileInfo); 3199 3200 i = j = 0; 3201 if(DirInfo1 == DirInfo2) { 3202 if(OS_SUCCESS(status = UDFFindFile(Vcb, IgnoreCase, TRUE, fn, DirInfo2, &j)) && 3203 (j==FileInfo->Index) ) { 3204 // case-only rename 3205 uint8* CS0; 3206 SIZE_T Nlen, /* l, FIXME ReactOS */ IUl; 3207 3208 // prepare filename 3209 UDFCompressUnicode(fn, &CS0, &Nlen); 3210 if(!CS0) return STATUS_INSUFFICIENT_RESOURCES; 3211 /* if(Nlen > UDF_NAME_LEN) { 3212 if(CS0) MyFreePool__(CS0); 3213 return STATUS_OBJECT_NAME_INVALID; 3214 }*/ 3215 // allocate memory for FI 3216 DirNdx2 = UDFDirIndex(DirInfo2->Dloc->DirIndex,j); 3217 IUl = DirNdx2->FileInfo->FileIdent->lengthOfImpUse; 3218 #if 0 3219 l = (sizeof(FILE_IDENT_DESC) + Nlen + IUl + 3) & ~((uint32)3); 3220 #endif 3221 3222 RtlCopyMemory( ((uint8*)(DirNdx2->FileInfo->FileIdent+1))+IUl, CS0, Nlen); 3223 RtlCopyMemory(DirNdx2->FName.Buffer, fn->Buffer, fn->Length); 3224 3225 if(CS0) MyFreePool__(CS0); 3226 3227 DirNdx2->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; 3228 UDFBuildHashEntry(Vcb, &(DirNdx2->FName), &(DirNdx2->hashes), HASH_ALL); 3229 return STATUS_SUCCESS; 3230 /* } else 3231 if(!OS_SUCCESS(status) && (fn->Length == UDFDirIndex(DirInfo2->Dloc->DirIndex, j=FileInfo->Index)->FName.Length)) { 3232 // target file doesn't exist, but name lengthes are equal 3233 RtlCopyMemory((DirNdx1 = UDFDirIndex(DirInfo1->Dloc->DirIndex,j))->FName.Buffer, fn->Buffer, fn->Length); 3234 DirNdx1->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; 3235 UDFBuildHashEntry(Vcb, &(DirNdx1->FName), &(DirNdx1->hashes), HASH_ALL); 3236 return STATUS_SUCCESS;*/ 3237 } 3238 } 3239 3240 // PHASE 0 3241 // try to create new FileIdent & FileEntry in Dir2 3242 3243 RenameRetry: 3244 if(!OS_SUCCESS(status = UDFCreateFile__(Vcb, IgnoreCase, fn, UDFGetFileEALength(FileInfo), 3245 0, (FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY), 3246 TRUE, DirInfo2, &FileInfo2))) { 3247 UDFCleanUpFile__(Vcb, FileInfo2); 3248 if(FileInfo2) MyFreePool__(FileInfo2); 3249 if(status == STATUS_ACCESS_DENIED) { 3250 // try to recover >;-> 3251 if((*Replace) && !Recovery) { 3252 Recovery = TRUE; 3253 status = UDFOpenFile__(Vcb, IgnoreCase, TRUE, fn, DirInfo2, &FileInfo2, NULL); 3254 if(OS_SUCCESS(status)) { 3255 status = UDFDoesOSAllowFileToBeTargetForRename__(FileInfo2); 3256 if(!OS_SUCCESS(status)) { 3257 UDFCloseFile__(Vcb, FileInfo2); 3258 goto cleanup_and_abort_rename; 3259 } 3260 status = UDFUnlinkFile__(Vcb, FileInfo2, TRUE); 3261 // UDFPretendFileDeleted__(Vcb, FileInfo2); 3262 UDFCloseFile__(Vcb, FileInfo2); 3263 if(UDFCleanUpFile__(Vcb, FileInfo2)) { 3264 MyFreePool__(FileInfo2); 3265 FileInfo2 = NULL; 3266 if(SameFE) 3267 return status; 3268 } else { 3269 // we get here if the FileInfo has associated 3270 // system-specific Fcb 3271 // Such fact means that not all system references 3272 // has already gone (except Linked file case) 3273 /* if(SameFE) 3274 return status;*/ 3275 // UDFRemoveOSReferences__(FileInfo2); 3276 if(!OS_SUCCESS(status) || 3277 (UDFGetFileLinkCount(FileInfo2) < 1)) 3278 status = STATUS_ACCESS_DENIED; 3279 } 3280 if(OS_SUCCESS(status)) goto RenameRetry; 3281 } 3282 cleanup_and_abort_rename: 3283 if(FileInfo2 && UDFCleanUpFile__(Vcb, FileInfo2)) { 3284 MyFreePool__(FileInfo2); 3285 FileInfo2 = NULL; 3286 } 3287 } else { 3288 status = STATUS_OBJECT_NAME_COLLISION; 3289 } 3290 } 3291 return status; 3292 } 3293 // update pointers 3294 DirNdx1 = UDFDirIndex(DirInfo1->Dloc->DirIndex, i = FileInfo->Index); 3295 DirNdx2 = UDFDirIndex(DirInfo2->Dloc->DirIndex, j = FileInfo2->Index); 3296 3297 // copy file attributes to newly created FileIdent 3298 NTAttr = UDFAttributesToNT(DirNdx1, FileInfo->Dloc->FileEntry); 3299 FileInfo2->FileIdent->fileVersionNum = FileInfo->FileIdent->fileVersionNum; 3300 // unlink source FileIdent 3301 if(!OS_SUCCESS(status = UDFUnlinkFile__(Vcb, FileInfo, FALSE))) { 3302 // kill newly created entry 3303 UDFFlushFile__(Vcb, FileInfo2); 3304 UDFUnlinkFile__(Vcb, FileInfo2, TRUE); 3305 UDFCloseFile__(Vcb, FileInfo2); 3306 UDFCleanUpFile__(Vcb, FileInfo2); 3307 MyFreePool__(FileInfo2); 3308 return status; 3309 } 3310 3311 // PHASE 1 3312 // drop all unnecessary info from FileInfo & flush FI 3313 3314 DirNdx1->FileInfo = NULL; 3315 ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); 3316 UDFFlushFI(Vcb, FileInfo, UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation)); 3317 UDFInterlockedExchangeAdd((PLONG)&(DirInfo1->OpenCount), 3318 -((LONG)(FileInfo->RefCount))); 3319 // PHASE 2 3320 // copy all necessary info from FileInfo to FileInfo2 3321 3322 FileInfo2->FileIdent->icb = FileInfo->FileIdent->icb; 3323 FileInfo2->FileIdent->fileCharacteristics = FileInfo->FileIdent->fileCharacteristics; 3324 FileInfo2->FileIdent->fileVersionNum = FileInfo->FileIdent->fileVersionNum; 3325 MyFreePool__(FileInfo->FileIdent); 3326 FileInfo->FileIdent = NULL; 3327 3328 // PHASE 3 3329 // copy all necessary info from FileInfo2 to FileInfo 3330 3331 DirNdx2->FileInfo = FileInfo; 3332 DirNdx2->FileCharacteristics = DirNdx1->FileCharacteristics & ~FILE_DELETED; 3333 DirNdx2->FileEntryLoc = DirNdx1->FileEntryLoc; 3334 DirNdx2->FI_Flags = (DirNdx1->FI_Flags & ~UDF_FI_FLAG_SYS_ATTR) | UDF_FI_FLAG_FI_MODIFIED; 3335 UDFInterlockedExchangeAdd((PLONG)&(DirInfo2->OpenCount), 3336 FileInfo->RefCount - FileInfo2->RefCount); 3337 3338 UDFAttributesToUDF(DirNdx2, FileInfo2->Dloc->FileEntry, NTAttr); 3339 3340 FileInfo->Index = j; 3341 FileInfo->FileIdent = FileInfo2->FileIdent; 3342 FileInfo->FileIdentLen = FileInfo2->FileIdentLen; 3343 FileInfo->ParentFile = DirInfo2; 3344 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; 3345 3346 ((icbtag*)(FileInfo->Dloc->FileEntry+1))->parentICBLocation = 3347 ((icbtag*)(FileInfo2->Dloc->FileEntry+1))->parentICBLocation; 3348 3349 UDFIncFileLinkCount(FileInfo); // increase to 1 3350 3351 // UDFUpdateModifyTime(Vcb, FileInfo); 3352 3353 // PHASE 4 3354 // drop all unnecessary info from FileInfo2 3355 3356 UDFFreeFESpace(Vcb, DirInfo2, &(FileInfo2->Dloc->FELoc)); 3357 UDFUnlinkDloc(Vcb, FileInfo2->Dloc); 3358 UDFDecFileLinkCount(FileInfo2); 3359 3360 FileInfo2->Dloc->FE_Flags &= ~UDF_FE_FLAG_FE_MODIFIED; 3361 /* MyFreePool__(FileInfo2->Dloc->FileEntry); 3362 FileInfo2->Dloc->FileEntry = NULL;*/ 3363 FileInfo2->ParentFile = NULL; 3364 FileInfo2->FileIdent = NULL; 3365 FileInfo2->RefCount = 0; 3366 FileInfo2->Dloc->LinkRefCount = 0; 3367 ASSERT(FileInfo2->Dloc->DataLoc.Mapping); 3368 FileInfo2->Dloc->DataLoc.Mapping[0].extLocation = 0; 3369 FileInfo2->Dloc->DataLoc.Mapping[0].extLength = 0; 3370 3371 UDFCleanUpFile__(Vcb, FileInfo2); 3372 MyFreePool__(FileInfo2); 3373 3374 // return 'delete target' status 3375 (*Replace) = Recovery; 3376 3377 return STATUS_SUCCESS; 3378 } // end UDFRenameMoveFile__() 3379 3380 /* 3381 This routine transforms zero-sized file to directory 3382 */ 3383 OSSTATUS 3384 UDFRecordDirectory__( 3385 IN PVCB Vcb, 3386 IN OUT PUDF_FILE_INFO DirInfo // source (opened) 3387 ) 3388 { 3389 OSSTATUS status; 3390 LONG_AD FEicb; 3391 UDF_FILE_INFO FileInfo; 3392 UDF_DATALOC_INFO Dloc; 3393 UNICODE_STRING PName; 3394 uint32 PartNum; 3395 SIZE_T WrittenBytes; 3396 PDIR_INDEX_ITEM CurDirNdx; 3397 uint32 lba; 3398 3399 // validate DirInfo 3400 ValidateFileInfo(DirInfo); 3401 if(DirInfo->ParentFile && UDFIsAStreamDir(DirInfo->ParentFile)) 3402 return STATUS_ACCESS_DENIED; 3403 // file should be empty 3404 if(UDFGetFileSize(DirInfo)) { 3405 if( DirInfo->FileIdent && 3406 (DirInfo->FileIdent->fileCharacteristics & FILE_DIRECTORY)) return STATUS_FILE_IS_A_DIRECTORY; 3407 return STATUS_NOT_A_DIRECTORY; 3408 } 3409 if(DirInfo->Dloc->DirIndex) return STATUS_FILE_IS_A_DIRECTORY; 3410 // create empty DirIndex 3411 if(DirInfo->FileIdent) DirInfo->FileIdent->fileCharacteristics |= FILE_DIRECTORY; 3412 if((CurDirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(DirInfo),DirInfo->Index))) 3413 CurDirNdx->FileCharacteristics |= FILE_DIRECTORY; 3414 ((icbtag*)(DirInfo->Dloc->FileEntry+1))->fileType = UDF_FILE_TYPE_DIRECTORY; 3415 // init temporary FileInfo 3416 RtlZeroMemory(&FileInfo, sizeof(UDF_FILE_INFO)); 3417 FileInfo.Dloc = &Dloc; 3418 FileInfo.Dloc->FileEntry = DirInfo->ParentFile->Dloc->FileEntry; 3419 FileInfo.Dloc->FileEntryLen = DirInfo->ParentFile->Dloc->FileEntryLen; 3420 FileInfo.Dloc->DataLoc = DirInfo->Dloc->DataLoc; 3421 FileInfo.Dloc->FELoc = DirInfo->Dloc->FELoc; 3422 FileInfo.ParentFile = DirInfo; 3423 // prepare FileIdent for 'parent Dir' 3424 lba = DirInfo->Dloc->FELoc.Mapping[0].extLocation; 3425 ASSERT(lba); 3426 PartNum = UDFGetPartNumByPhysLba(Vcb, lba); 3427 FEicb.extLength = Vcb->LBlockSize; 3428 FEicb.extLocation.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, lba); 3429 FEicb.extLocation.partitionReferenceNum = (uint16)PartNum; 3430 RtlZeroMemory(&(FEicb.impUse), sizeof(FEicb.impUse)); 3431 PName.Buffer = (PWCH)L""; 3432 PName.Length = (PName.MaximumLength = sizeof(L"")) - sizeof(WCHAR); 3433 if(!OS_SUCCESS(status = 3434 UDFBuildFileIdent(Vcb, &PName, &FEicb, 0, 3435 &(FileInfo.FileIdent), &(FileInfo.FileIdentLen)) )) 3436 return status; 3437 FileInfo.FileIdent->fileCharacteristics |= (FILE_PARENT | FILE_DIRECTORY); 3438 UDFDecFileCounter(Vcb); 3439 UDFIncDirCounter(Vcb); 3440 // init structure 3441 UDFSetUpTag(Vcb, &(FileInfo.FileIdent->descTag), (uint16)(FileInfo.FileIdentLen), 3442 FEicb.extLocation.logicalBlockNum); 3443 FileInfo.Dloc->DataLoc.Flags |= EXTENT_FLAG_VERIFY; // for metadata 3444 // flush 3445 status = UDFWriteFile__(Vcb, DirInfo, 0, FileInfo.FileIdentLen, FALSE, (int8*)(FileInfo.FileIdent), &WrittenBytes); 3446 // status = UDFFlushFI(Vcb, &FileInfo, PartNum); 3447 3448 #ifdef UDF_DBG 3449 if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { 3450 ASSERT(UDFGetFileSize(DirInfo) <= UDFGetExtentLength(DirInfo->Dloc->DataLoc.Mapping)); 3451 } else { 3452 ASSERT(((UDFGetFileSize(DirInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) == 3453 ((UDFGetExtentLength(DirInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1))); 3454 } 3455 #endif // UDF_DBG 3456 3457 MyFreePool__(FileInfo.FileIdent); 3458 if(!OS_SUCCESS(status)) return status; 3459 if(CurDirNdx) CurDirNdx->FileCharacteristics = 3460 DirInfo->FileIdent->fileCharacteristics; 3461 return UDFIndexDirectory(Vcb, DirInfo); 3462 } // end UDFRecordDirectory__() 3463 3464 /* 3465 This routine changes file size (on disc) 3466 */ 3467 OSSTATUS 3468 UDFResizeFile__( 3469 IN PVCB Vcb, 3470 IN OUT PUDF_FILE_INFO FileInfo, 3471 IN int64 NewLength 3472 ) 3473 { 3474 SIZE_T WrittenBytes; 3475 OSSTATUS status; 3476 uint32 PartNum; 3477 int8* OldInIcb = NULL; 3478 PEXTENT_MAP NewMap; 3479 3480 UDFPrint(("UDFResizeFile__: FI %x, -> %I64x\n", FileInfo, NewLength)); 3481 ValidateFileInfo(FileInfo); 3482 // ASSERT(FileInfo->RefCount >= 1); 3483 3484 if((NewLength >> Vcb->LBlockSizeBits) > Vcb->TotalAllocUnits) { 3485 UDFPrint(("STATUS_DISK_FULL\n")); 3486 return STATUS_DISK_FULL; 3487 } 3488 if (NewLength == FileInfo->Dloc->DataLoc.Length) return STATUS_SUCCESS; 3489 if(FileInfo->ParentFile && (FileInfo->Index >= 2)) { 3490 UDFDirIndex(FileInfo->ParentFile->Dloc->DirIndex,FileInfo->Index)->FI_Flags &= ~UDF_FI_FLAG_SYS_ATTR; 3491 } 3492 if(NewLength > FileInfo->Dloc->DataLoc.Length) { 3493 // grow file 3494 return UDFWriteFile__(Vcb, FileInfo, NewLength, 0, FALSE, NULL, &WrittenBytes); 3495 } 3496 // truncate file 3497 if(NewLength <= (Vcb->LBlockSize - FileInfo->Dloc->FileEntryLen)) { 3498 // check if we are already in IN_ICB mode 3499 if((((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) != ICB_FLAG_AD_IN_ICB) { 3500 // read data from old location 3501 if(NewLength) { 3502 OldInIcb = (int8*)MyAllocatePool__(NonPagedPool, (uint32)NewLength); 3503 if(!OldInIcb) return STATUS_INSUFFICIENT_RESOURCES; 3504 status = UDFReadExtent(Vcb, &(FileInfo->Dloc->DataLoc), 0, (uint32)NewLength, FALSE, OldInIcb, &WrittenBytes); 3505 if(!OS_SUCCESS(status)) { 3506 MyFreePool__(OldInIcb); 3507 return status; 3508 } 3509 } else { 3510 OldInIcb = NULL; 3511 } 3512 // allocate storage for new mapping 3513 NewMap = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , 2*sizeof(EXTENT_MAP), 3514 MEM_EXTMAP_TAG); 3515 if(!(NewMap)) { 3516 MyFreePool__(OldInIcb); 3517 return STATUS_INSUFFICIENT_RESOURCES; 3518 } 3519 // free old location... 3520 if(FileInfo->Dloc->DataLoc.Mapping[0].extLocation != 3521 FileInfo->Dloc->FELoc.Mapping[0].extLocation) { 3522 ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); 3523 mark_data_map_0: 3524 UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, FileInfo->Dloc->DataLoc.Mapping, AS_DISCARDED); // free 3525 } else { 3526 if((FileInfo->Dloc->DataLoc.Mapping[0].extLength & UDF_EXTENT_LENGTH_MASK) 3527 > Vcb->LBlockSize) { 3528 BrutePoint(); 3529 FileInfo->Dloc->DataLoc.Mapping[0].extLength -= Vcb->LBlockSize; 3530 FileInfo->Dloc->DataLoc.Mapping[0].extLocation += (1 << Vcb->LB2B_Bits); 3531 goto mark_data_map_0; 3532 } 3533 UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->DataLoc.Mapping[1]), AS_DISCARDED); // free 3534 } 3535 if(FileInfo->Dloc->AllocLoc.Mapping) { 3536 if((FileInfo->Dloc->AllocLoc.Mapping[0].extLength & UDF_EXTENT_LENGTH_MASK) 3537 > Vcb->LBlockSize) { 3538 FileInfo->Dloc->AllocLoc.Mapping[0].extLength -= Vcb->LBlockSize; 3539 FileInfo->Dloc->AllocLoc.Mapping[0].extLocation += (1 << Vcb->LB2B_Bits); 3540 UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, FileInfo->Dloc->AllocLoc.Mapping, AS_DISCARDED); // free 3541 } else { 3542 UDFMarkSpaceAsXXX(Vcb, FileInfo->Dloc, &(FileInfo->Dloc->AllocLoc.Mapping[1]), AS_DISCARDED); // free 3543 } 3544 MyFreePool__(FileInfo->Dloc->AllocLoc.Mapping); 3545 } 3546 MyFreePool__(FileInfo->Dloc->DataLoc.Mapping); 3547 FileInfo->Dloc->AllocLoc.Mapping = NULL; 3548 FileInfo->Dloc->AllocLoc.Length = 0; 3549 FileInfo->Dloc->AllocLoc.Offset = 0; 3550 FileInfo->Dloc->AllocLoc.Modified = TRUE; 3551 // switch to IN_ICB mode 3552 ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK; 3553 ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags |= ICB_FLAG_AD_IN_ICB; 3554 // init new data location descriptors 3555 FileInfo->Dloc->DataLoc.Mapping = NewMap; 3556 RtlZeroMemory((int8*)(FileInfo->Dloc->DataLoc.Mapping), 2*sizeof(EXTENT_MAP)); 3557 FileInfo->Dloc->DataLoc.Mapping[0] = FileInfo->Dloc->FELoc.Mapping[0]; 3558 FileInfo->Dloc->DataLoc.Length = NewLength; 3559 FileInfo->Dloc->DataLoc.Offset = FileInfo->Dloc->FileEntryLen; 3560 // write data to new location 3561 if(OldInIcb) { 3562 status = UDFWriteExtent(Vcb, &(FileInfo->Dloc->DataLoc), 0, (uint32)NewLength, FALSE, OldInIcb, &WrittenBytes); 3563 } else { 3564 status = STATUS_SUCCESS; 3565 } 3566 FileInfo->Dloc->DataLoc.Modified = TRUE; 3567 if(OldInIcb) MyFreePool__(OldInIcb); 3568 } else { 3569 // just modify Length field 3570 FileInfo->Dloc->DataLoc.Length = NewLength; 3571 status = STATUS_SUCCESS; 3572 } 3573 } else { 3574 // resize extent 3575 ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); 3576 PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation); 3577 status = UDFResizeExtent(Vcb, PartNum, NewLength, FALSE, &(FileInfo->Dloc->DataLoc)); 3578 FileInfo->Dloc->DataLoc.Modified = TRUE; 3579 FileInfo->Dloc->AllocLoc.Modified = TRUE; 3580 } 3581 if(OS_SUCCESS(status)) { 3582 UDFSetFileSize(FileInfo, NewLength); 3583 } 3584 3585 #ifdef UDF_DBG 3586 if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { 3587 ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)); 3588 } else { 3589 ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) == 3590 ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1))); 3591 } 3592 #endif // UDF_DBG 3593 3594 return status; 3595 } // end UDFResizeFile__() 3596 #endif //UDF_READ_ONLY_BUILD 3597 3598 /* 3599 This routine loads VAT. 3600 */ 3601 OSSTATUS 3602 UDFLoadVAT( 3603 IN PVCB Vcb, 3604 IN uint32 PartNdx 3605 ) 3606 { 3607 lb_addr VatFELoc; 3608 OSSTATUS status; 3609 PUDF_FILE_INFO VatFileInfo; 3610 uint32 len, i=0, j, to_read; 3611 uint32 Offset, hdrOffset; 3612 SIZE_T ReadBytes; 3613 uint32 root; 3614 uint16 PartNum; 3615 // uint32 VatFirstLba = 0; 3616 int8* VatOldData; 3617 uint32 VatLba[6] = { Vcb->LastLBA, 3618 Vcb->LastLBA - 2, 3619 Vcb->LastLBA - 3, 3620 Vcb->LastLBA - 5, 3621 Vcb->LastLBA - 7, 3622 0 }; 3623 3624 if(Vcb->Vat) return STATUS_SUCCESS; 3625 if(!Vcb->CDR_Mode) return STATUS_SUCCESS; 3626 // disable VAT for now. We'll reenable it if VAT is successfuly loaded 3627 Vcb->CDR_Mode = FALSE; 3628 PartNum = Vcb->Partitions[PartNdx].PartitionNum; 3629 root = Vcb->Partitions[PartNdx].PartitionRoot; 3630 if(Vcb->LBlockSize != Vcb->BlockSize) { 3631 // don't know how to operate... :((( 3632 return STATUS_UNRECOGNIZED_VOLUME; 3633 } 3634 if((Vcb->LastTrackNum > 1) && 3635 (Vcb->LastLBA == Vcb->TrackMap[Vcb->LastTrackNum-1].LastLba)) { 3636 UDFPrint(("Hardware Read-only volume\n")); 3637 Vcb->VCBFlags |= UDF_VCB_FLAGS_VOLUME_READ_ONLY; 3638 } 3639 3640 VatFileInfo = Vcb->VatFileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT, sizeof(UDF_FILE_INFO), MEM_VATFINF_TAG); 3641 if(!VatFileInfo) return STATUS_INSUFFICIENT_RESOURCES; 3642 // load VAT FE (we know its location) 3643 VatFELoc.partitionReferenceNum = PartNum; 3644 retry_load_vat: 3645 VatFELoc.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, VatLba[i]); 3646 if(!OS_SUCCESS(status = UDFOpenRootFile__(Vcb, &VatFELoc, VatFileInfo))) { 3647 UDFCleanUpFile__(Vcb, VatFileInfo); 3648 // try another location 3649 i++; 3650 if( VatLba[i] && 3651 (status != STATUS_FILE_CORRUPT_ERROR) && 3652 (status != STATUS_CRC_ERROR)) goto retry_load_vat; 3653 MyFreePool__(VatFileInfo); 3654 Vcb->VatFileInfo = NULL; 3655 return status; 3656 } 3657 len = (uint32)UDFGetFileSize(VatFileInfo); 3658 if(Vcb->Partitions[PartNdx].PartitionType == UDF_VIRTUAL_MAP15) { 3659 // load Vat 1.50 header 3660 UDFPrint(("Load VAT 1.50\n")); 3661 VirtualAllocationTable15* Buf; 3662 if(((icbtag*)(VatFileInfo->Dloc->FileEntry+1))->fileType != UDF_FILE_TYPE_VAT15) { 3663 status = STATUS_FILE_CORRUPT_ERROR; 3664 goto err_vat_15; 3665 } 3666 Buf = (VirtualAllocationTable15*)MyAllocatePool__(NonPagedPool, sizeof(VirtualAllocationTable15)); 3667 if(!Buf) { 3668 err_vat_15_2: 3669 status = STATUS_INSUFFICIENT_RESOURCES; 3670 err_vat_15: 3671 UDFCloseFile__(Vcb, VatFileInfo); 3672 UDFCleanUpFile__(Vcb, VatFileInfo); 3673 MyFreePool__(VatFileInfo); 3674 Vcb->VatFileInfo = NULL; 3675 return status; 3676 } 3677 Offset = 0; 3678 to_read = 3679 hdrOffset = len - sizeof(VirtualAllocationTable15); 3680 MyFreePool__(Buf); 3681 3682 Vcb->minUDFReadRev = 3683 Vcb->minUDFWriteRev = 3684 Vcb->maxUDFWriteRev = 0x0150; 3685 3686 Vcb->numFiles = 3687 Vcb->numDirs = -1; 3688 3689 } else 3690 if(Vcb->Partitions[PartNdx].PartitionType == UDF_VIRTUAL_MAP20) { 3691 // load Vat 2.00 header 3692 UDFPrint(("Load VAT 2.00\n")); 3693 VirtualAllocationTable20* Buf; 3694 if(((icbtag*)(VatFileInfo->Dloc->FileEntry+1))->fileType != UDF_FILE_TYPE_VAT20) { 3695 status = STATUS_FILE_CORRUPT_ERROR; 3696 goto err_vat_15; 3697 } 3698 Buf = (VirtualAllocationTable20*)MyAllocatePool__(NonPagedPool, sizeof(VirtualAllocationTable20)); 3699 if(!Buf) goto err_vat_15_2; 3700 Offset = Buf->lengthHeader; 3701 to_read = len - Offset; 3702 hdrOffset = 0; 3703 MyFreePool__(Buf); 3704 3705 Vcb->minUDFReadRev = Buf->minReadRevision; 3706 Vcb->minUDFWriteRev = Buf->minWriteRevision; 3707 Vcb->maxUDFWriteRev = Buf->maxWriteRevision; 3708 3709 Vcb->numFiles = Buf->numFIDSFiles; 3710 Vcb->numDirs = Buf->numFIDSDirectories; 3711 3712 } else { 3713 // unknown (or wrong) VAT format 3714 UDFPrint(("unknown (or wrong) VAT format\n")); 3715 status = STATUS_FILE_CORRUPT_ERROR; 3716 goto err_vat_15; 3717 } 3718 // read VAT & remember old version 3719 Vcb->Vat = (uint32*)DbgAllocatePool(NonPagedPool, (Vcb->LastPossibleLBA+1)*sizeof(uint32) ); 3720 if(!Vcb->Vat) { 3721 goto err_vat_15_2; 3722 } 3723 // store base version of VAT in memory 3724 VatOldData = (int8*)DbgAllocatePool(PagedPool, len); 3725 if(!VatOldData) { 3726 DbgFreePool(Vcb->Vat); 3727 Vcb->Vat = NULL; 3728 goto err_vat_15_2; 3729 } 3730 status = UDFReadFile__(Vcb, VatFileInfo, 0, len, FALSE, VatOldData, &ReadBytes); 3731 if(!OS_SUCCESS(status)) { 3732 UDFCloseFile__(Vcb, VatFileInfo); 3733 UDFCleanUpFile__(Vcb, VatFileInfo); 3734 MyFreePool__(VatFileInfo); 3735 DbgFreePool(Vcb->Vat); 3736 DbgFreePool(VatOldData); 3737 Vcb->Vat = NULL; 3738 Vcb->VatFileInfo = NULL; 3739 } else { 3740 // initialize VAT 3741 // !!! NOTE !!! 3742 // Both VAT copies - in-memory & on-disc 3743 // contain _relative_ addresses 3744 len = Vcb->NWA - root; 3745 for(i=0; i<=len; i++) { 3746 Vcb->Vat[i] = i; 3747 } 3748 RtlCopyMemory(Vcb->Vat, VatOldData+Offset, to_read); 3749 Vcb->InitVatCount = 3750 Vcb->VatCount = to_read/sizeof(uint32); 3751 Vcb->VatPartNdx = PartNdx; 3752 Vcb->CDR_Mode = TRUE; 3753 len = Vcb->VatCount; 3754 RtlFillMemory(&(Vcb->Vat[Vcb->NWA-root]), (Vcb->LastPossibleLBA-Vcb->NWA+1)*sizeof(uint32), 0xff); 3755 // sync VAT and FSBM 3756 for(i=0; i<len; i++) { 3757 if(Vcb->Vat[i] == UDF_VAT_FREE_ENTRY) { 3758 UDFSetFreeBit(Vcb->FSBM_Bitmap, root+i); 3759 } 3760 } 3761 len = Vcb->LastPossibleLBA; 3762 // "pre-format" reserved area 3763 for(i=Vcb->NWA; i<len;) { 3764 for(j=0; (j<PACKETSIZE_UDF) && (i<len); j++, i++) 3765 UDFSetFreeBit(Vcb->FSBM_Bitmap, i); 3766 for(j=0; (j<7) && (i<len); j++, i++) 3767 UDFSetUsedBit(Vcb->FSBM_Bitmap, i); 3768 } 3769 DbgFreePool(VatOldData); 3770 } 3771 return status; 3772 } // end UDFLoadVAT() 3773 3774 /* 3775 Reads Extended Attributes 3776 Caller should use UDFGetFileEALength to allocate Buffer of sufficient 3777 size 3778 *//* 3779 OSSTATUS 3780 UDFReadFileEA( 3781 IN PVCB Vcb, 3782 IN PDIR_INDEX FileDirNdx, 3783 OUT int8* Buffer 3784 ) 3785 { 3786 PFILE_ENTRY FileEntry; 3787 OSSTATUS status; 3788 3789 if(FileDirNdx->FileInfo) { 3790 FileEntry = (PFILE_ENTRY)(FileDirNdx->FileInfo->Dloc->FileEntry); 3791 } else { 3792 FileEntry = (PFILE_ENTRY)MyAllocatePool__(NonPagedPool, Vcb->BlockSize); 3793 if(!FileEntry) return; 3794 if(!OS_SUCCESS(status = UDFReadFileEntry(Vcb, &(FileDirNdx->FileEntry), FileEntry, &Ident))) { 3795 MyFreePool__(FileEntry); 3796 return status; 3797 } 3798 } 3799 }*/ 3800 /* 3801 This dumb routine checks if the file has been found is deleted 3802 It is introduced to make main modules FS-type independent 3803 */ 3804 /*BOOLEAN 3805 UDFIsDeleted( 3806 IN PDIR_INDEX DirNdx 3807 ) 3808 { 3809 return (DirNdx->FileCharacteristics & FILE_DELETED); 3810 } */ 3811 3812 /*BOOLEAN 3813 UDFIsADirectory( 3814 IN PUDF_FILE_INFO FileInfo 3815 ) 3816 { 3817 ValidateFileInfo(FileInfo); 3818 3819 if(!FileInfo) return FALSE; 3820 if(FileInfo->Dloc->DirIndex) return TRUE; 3821 if(!(FileInfo->FileIdent)) return FALSE; 3822 return (FileInfo->FileIdent->fileCharacteristics & FILE_DIRECTORY); 3823 } */ 3824 /* 3825 This routine calculates actual allocation size 3826 */ 3827 /*int64 3828 UDFGetFileAllocationSize( 3829 IN PVCB Vcb, 3830 IN PUDF_FILE_INFO FileInfo 3831 ) 3832 { 3833 ValidateFileInfo(FileInfo); 3834 3835 return UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping);// + 3836 // UDFGetExtentLength(FileInfo->Dloc->FELoc.Mapping) + 3837 // UDFGetExtentLength(FileInfo->Dloc->AllocLoc.Mapping) - Vcb->BlockSize; 3838 }*/ 3839 3840 /* 3841 This routine checks if the directory is empty 3842 */ 3843 BOOLEAN 3844 UDFIsDirEmpty( 3845 IN PDIR_INDEX_HDR hCurDirNdx 3846 ) 3847 { 3848 uint32 fc; 3849 uint_di i; 3850 PDIR_INDEX_ITEM CurDirNdx; 3851 // not empty 3852 for(i=2; (CurDirNdx = UDFDirIndex(hCurDirNdx,i)); i++) { 3853 fc = CurDirNdx->FileCharacteristics; 3854 if(!(fc & (FILE_PARENT | FILE_DELETED)) && 3855 CurDirNdx->Length) 3856 return FALSE; 3857 } 3858 return TRUE; 3859 } // end UDFIsDirEmpty() 3860 3861 /* 3862 */ 3863 OSSTATUS 3864 UDFFlushFE( 3865 IN PVCB Vcb, 3866 IN PUDF_FILE_INFO FileInfo, 3867 IN uint32 PartNum 3868 ) 3869 { 3870 int8* NewAllocDescs; 3871 OSSTATUS status; 3872 SIZE_T WrittenBytes; 3873 uint16 AllocMode; 3874 uint32 lba; 3875 3876 AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK; 3877 #ifdef UDF_DBG 3878 /* if(UDFIsADirectory(FileInfo) && (UDFGetFileSize(FileInfo) < 0x28) && 3879 !UDFIsDeleted(UDFDirIndex(DirInfo->Dloc->DirIndex, FileInfo->Index)) ) { 3880 BrutePoint(); 3881 }*/ 3882 // ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); 3883 if(FileInfo->Dloc->FELoc.Offset) { 3884 BrutePoint(); 3885 } 3886 if(FileInfo->Dloc->AllocLoc.Mapping) { 3887 ASSERT(AllocMode != ICB_FLAG_AD_IN_ICB); 3888 } 3889 #endif // UDF_DBG 3890 retry_flush_FE: 3891 UDFPrint((" FlushFE: %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation)); 3892 #ifndef UDF_READ_ONLY_BUILD 3893 UDFReTagDirectory(Vcb, FileInfo); 3894 if(FileInfo->Dloc->DataLoc.Modified || 3895 FileInfo->Dloc->AllocLoc.Modified) { 3896 ASSERT(PartNum != (uint32)(-1)); 3897 // prepare new AllocDescs for flushing... 3898 if(!OS_SUCCESS(status = UDFBuildAllocDescs(Vcb, PartNum, FileInfo, &NewAllocDescs))) { 3899 UDFPrint((" FlushFE: UDFBuildAllocDescs() faliled (%x)\n", status)); 3900 if(NewAllocDescs) 3901 MyFreePool__(NewAllocDescs); 3902 return status; 3903 } 3904 #ifdef UDF_DBG 3905 if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { 3906 ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)); 3907 } else { 3908 ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) == 3909 ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1))); 3910 } 3911 AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK; 3912 #endif // UDF_DBG 3913 // initiate update of lengthAllocDescs 3914 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; 3915 if(NewAllocDescs) { 3916 ASSERT(AllocMode != ICB_FLAG_AD_IN_ICB); 3917 status = UDFPadLastSector(Vcb, &(FileInfo->Dloc->AllocLoc)); 3918 // ... and flush it 3919 status = UDFWriteExtent(Vcb, &(FileInfo->Dloc->AllocLoc), 0, (uint32)(FileInfo->Dloc->AllocLoc.Length), FALSE, NewAllocDescs, &WrittenBytes); 3920 MyFreePool__(NewAllocDescs); 3921 if(!OS_SUCCESS(status)) { 3922 UDFPrint((" FlushFE: UDFWriteExtent() faliled (%x)\n", status)); 3923 return status; 3924 } 3925 #ifdef UDF_DBG 3926 } else { 3927 ASSERT(AllocMode == ICB_FLAG_AD_IN_ICB); 3928 #endif // UDF_DBG 3929 } 3930 FileInfo->Dloc->DataLoc.Modified = FALSE; 3931 FileInfo->Dloc->AllocLoc.Modified = FALSE; 3932 } else { 3933 #if defined(UDF_DBG) && !defined(UDF_CHECK_UTIL) 3934 if(Vcb->CompatFlags & UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS) { 3935 ASSERT(UDFGetFileSize(FileInfo) <= UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)); 3936 } else { 3937 ASSERT(((UDFGetFileSize(FileInfo)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1)) == 3938 ((UDFGetExtentLength(FileInfo->Dloc->DataLoc.Mapping)+Vcb->LBlockSize-1) & (Vcb->LBlockSize-1))); 3939 } 3940 #endif // UDF_DBG 3941 } 3942 /* if(FileInfo->Fcb && 3943 ((FileInfo->Dloc->FELoc.Mapping[0].extLocation > Vcb->LastLBA) || 3944 UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) ) { 3945 BrutePoint(); 3946 }*/ 3947 /* if(FileInfo->Dloc->FELoc.Mapping[0].extLocation) { 3948 ASSERT( FileInfo->Dloc->FileEntry->tagLocation == 3949 (FileInfo->Dloc->FELoc.Mapping[0].extLocation - 0x580)); 3950 }*/ 3951 if((FileInfo->Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) || 3952 FileInfo->Dloc->FELoc.Modified) { 3953 ASSERT(PartNum != (uint32)(-1)); 3954 ASSERT(!PartNum); 3955 if(PartNum == (uint32)(-1) || PartNum == (uint32)(-2)) { 3956 UDFPrint((" bad PartNum: %d\n", PartNum)); 3957 } 3958 // update lengthAllocDescs in FE 3959 UDFSetAllocDescLen(Vcb, FileInfo); 3960 /* ASSERT( FileInfo->Dloc->FileEntry->tagLocation == 3961 (FileInfo->Dloc->FELoc.Mapping[0].extLocation - 0x580));*/ 3962 // flush FileEntry 3963 3964 // if FE is located in remapped block, place it to reliable space 3965 lba = FileInfo->Dloc->FELoc.Mapping[0].extLocation; 3966 if(Vcb->BSBM_Bitmap) { 3967 if(UDFGetBadBit((uint32*)(Vcb->BSBM_Bitmap), lba)) { 3968 AdPrint((" bad block under FE @%x\n", lba)); 3969 goto relocate_FE; 3970 } 3971 } 3972 3973 AdPrint((" setup tag: @%x\n", lba)); 3974 ASSERT( lba ); 3975 UDFSetUpTag(Vcb, FileInfo->Dloc->FileEntry, (uint16)(FileInfo->Dloc->FileEntryLen), 3976 UDFPhysLbaToPart(Vcb, PartNum, lba)); 3977 status = UDFWriteExtent(Vcb, &(FileInfo->Dloc->FELoc), 0, 3978 (uint32)(FileInfo->Dloc->FELoc.Length), FALSE, 3979 (int8*)(FileInfo->Dloc->FileEntry), &WrittenBytes); 3980 if(!OS_SUCCESS(status)) { 3981 UDFPrint((" FlushFE: UDFWriteExtent(2) faliled (%x)\n", status)); 3982 if(status == STATUS_DEVICE_DATA_ERROR) { 3983 relocate_FE: 3984 UDFPrint((" try to relocate\n")); 3985 3986 EXTENT_INFO _FEExtInfo; 3987 // calculate the length required 3988 3989 // allocate block for FE 3990 if(OS_SUCCESS(UDFAllocateFESpace(Vcb, FileInfo->ParentFile, PartNum, &_FEExtInfo, (uint32)(FileInfo->Dloc->FELoc.Length)) )) { 3991 UDFPrint((" relocate %x -> %x\n", 3992 lba, 3993 _FEExtInfo.Mapping[0].extLocation)); 3994 3995 UDFMarkSpaceAsXXX(Vcb, 0, FileInfo->Dloc->FELoc.Mapping, AS_BAD); 3996 3997 UDFRelocateDloc(Vcb, FileInfo->Dloc, _FEExtInfo.Mapping[0].extLocation); 3998 MyFreePool__(FileInfo->Dloc->FELoc.Mapping); 3999 FileInfo->Dloc->FELoc.Mapping = _FEExtInfo.Mapping; 4000 4001 FileInfo->Dloc->FELoc.Modified = TRUE; 4002 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; 4003 4004 AllocMode = ((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK; 4005 if(AllocMode == ICB_FLAG_AD_IN_ICB) { 4006 UDFPrint((" IN-ICB data lost\n")); 4007 FileInfo->Dloc->DataLoc.Mapping[0].extLocation = _FEExtInfo.Mapping[0].extLocation; 4008 FileInfo->Dloc->DataLoc.Modified = TRUE; 4009 } else { 4010 FileInfo->Dloc->AllocLoc.Mapping[0].extLocation = _FEExtInfo.Mapping[0].extLocation; 4011 FileInfo->Dloc->AllocLoc.Modified = TRUE; 4012 } 4013 4014 if(FileInfo->Index >= 2) { 4015 PDIR_INDEX_ITEM DirNdx; 4016 DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index); 4017 if(DirNdx) { 4018 UDFPrint((" update reference in FI\n")); 4019 DirNdx->FileEntryLoc.logicalBlockNum = 4020 FileInfo->FileIdent->icb.extLocation.logicalBlockNum = 4021 UDFPhysLbaToPart(Vcb, PartNum, _FEExtInfo.Mapping[0].extLocation); 4022 DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; 4023 } 4024 } 4025 // this will update 4026 UDFPrint((" retry flush...\n")); 4027 goto retry_flush_FE; 4028 } 4029 } 4030 BrutePoint(); 4031 return status; 4032 } 4033 FileInfo->Dloc->FE_Flags &= ~UDF_FE_FLAG_FE_MODIFIED; 4034 FileInfo->Dloc->FELoc.Modified = FALSE; 4035 } else { 4036 ASSERT((FileInfo->Dloc->FileEntry->descVersion == 2) || 4037 (FileInfo->Dloc->FileEntry->descVersion == 3)); 4038 } 4039 #endif //UDF_READ_ONLY_BUILD 4040 #ifdef UDF_DBG 4041 if(FileInfo->Dloc->AllocLoc.Mapping) { 4042 ASSERT(AllocMode != ICB_FLAG_AD_IN_ICB); 4043 } else { 4044 ASSERT(AllocMode == ICB_FLAG_AD_IN_ICB); 4045 } 4046 #endif // UDF_DBG 4047 return STATUS_SUCCESS; 4048 } // end UDFFlushFE() 4049 4050 OSSTATUS 4051 UDFFlushFI( 4052 IN PVCB Vcb, 4053 IN PUDF_FILE_INFO FileInfo, 4054 IN uint32 PartNum 4055 ) 4056 { 4057 PUDF_FILE_INFO DirInfo = FileInfo->ParentFile; 4058 PDIR_INDEX_ITEM DirNdx; 4059 OSSTATUS status; 4060 SIZE_T WrittenBytes; 4061 // use WrittenBytes variable to store LBA of FI to be recorded 4062 #define lba WrittenBytes 4063 4064 // ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); 4065 // some files has no FI 4066 if(!DirInfo || UDFIsAStreamDir(FileInfo)) 4067 return STATUS_SUCCESS; 4068 DirNdx = UDFDirIndex(DirInfo->Dloc->DirIndex, FileInfo->Index); 4069 // ASSERT(FileInfo->FileIdent->lengthFileIdent < 0x80); 4070 #ifdef UDF_DBG 4071 if(DirNdx->FileCharacteristics & FILE_DELETED) { 4072 ASSERT(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED); 4073 } 4074 #endif // UDF_DBG 4075 UDFPrint((" FlushFI: offs %x\n", (ULONG)(DirNdx->Offset))); 4076 #ifndef UDF_READ_ONLY_BUILD 4077 if((DirNdx->FI_Flags & UDF_FI_FLAG_FI_MODIFIED)) { 4078 // flush FileIdent 4079 ASSERT(PartNum != (uint32)(-1)); 4080 FileInfo->FileIdent->fileCharacteristics = DirNdx->FileCharacteristics; 4081 lba = UDFExtentOffsetToLba(Vcb, DirInfo->Dloc->DataLoc.Mapping, 4082 DirNdx->Offset, NULL, NULL, NULL, NULL); 4083 AdPrint((" FI lba %x\n", lba)); 4084 // check if requested Offset is allocated 4085 if(lba == (uint32)LBA_OUT_OF_EXTENT) { 4086 // write 1 byte 4087 if(!OS_SUCCESS(status = UDFWriteFile__(Vcb, DirInfo, DirNdx->Offset, 1, FALSE, (int8*)(FileInfo->FileIdent), &WrittenBytes) )) { 4088 BrutePoint(); 4089 return status; 4090 } 4091 lba = UDFExtentOffsetToLba(Vcb, DirInfo->Dloc->DataLoc.Mapping, 4092 DirNdx->Offset, NULL, NULL, NULL, NULL); 4093 AdPrint((" allocated FI lba %x\n", lba)); 4094 // check if requested Offset is allocated 4095 if(lba == (uint32)LBA_OUT_OF_EXTENT) { 4096 BrutePoint(); 4097 return STATUS_UNSUCCESSFUL; 4098 } 4099 } 4100 // init structure 4101 UDFSetUpTag(Vcb, &(FileInfo->FileIdent->descTag), (uint16)(FileInfo->FileIdentLen), 4102 UDFPhysLbaToPart(Vcb, PartNum, lba)); 4103 // record data 4104 if(!OS_SUCCESS(status = UDFWriteFile__(Vcb, DirInfo, DirNdx->Offset, FileInfo->FileIdentLen, FALSE, (int8*)(FileInfo->FileIdent), &WrittenBytes) )) { 4105 BrutePoint(); 4106 return status; 4107 } 4108 DirNdx->FI_Flags &= ~UDF_FI_FLAG_FI_MODIFIED; 4109 } 4110 #endif //UDF_READ_ONLY_BUILD 4111 return STATUS_SUCCESS; 4112 } // end UDFFlushFI() 4113 4114 /* 4115 This routine updates AllocDesc sequence, FileIdent & FileEntry 4116 for given file 4117 */ 4118 OSSTATUS 4119 UDFFlushFile__( 4120 IN PVCB Vcb, 4121 IN PUDF_FILE_INFO FileInfo, 4122 IN ULONG FlushFlags 4123 ) 4124 { 4125 ValidateFileInfo(FileInfo); 4126 4127 if(!FileInfo) return STATUS_SUCCESS; 4128 OSSTATUS status; 4129 uint32 PartNum; 4130 4131 ASSERT(FileInfo->Dloc->FELoc.Mapping[0].extLocation); 4132 PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation); 4133 if(PartNum == (uint32)-1) { 4134 UDFPrint((" Is DELETED ?\n")); 4135 if(FileInfo->ParentFile) { 4136 PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->ParentFile->Dloc->FELoc.Mapping[0].extLocation); 4137 } else { 4138 BrutePoint(); 4139 } 4140 } 4141 #ifdef UDF_CHECK_DISK_ALLOCATION 4142 if( FileInfo->Fcb && 4143 UDFGetFreeBit(((uint32*)(Vcb->FSBM_Bitmap)), FileInfo->Dloc->FELoc.Mapping[0].extLocation)) { 4144 4145 if(UDFIsAStreamDir(FileInfo)) { 4146 if(!UDFIsSDirDeleted(FileInfo)) { 4147 UDFPrint((" Not DELETED SDir\n")); 4148 BrutePoint(); 4149 } 4150 ASSERT(!FileInfo->Dloc->FELoc.Modified); 4151 } else 4152 if(!FileInfo->FileIdent || 4153 !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED)) { 4154 if(!FileInfo->FileIdent) 4155 AdPrint((" No FileIdent\n")); 4156 if(FileInfo->FileIdent && 4157 !(FileInfo->FileIdent->fileCharacteristics & FILE_DELETED)) 4158 AdPrint((" Not DELETED\n")); 4159 AdPrint(("Flushing to Discarded block %x\n", FileInfo->Dloc->FELoc.Mapping[0].extLocation)); 4160 BrutePoint(); 4161 } 4162 } 4163 #endif // UDF_CHECK_DISK_ALLOCATION 4164 4165 // flush FE and pre-allocation charge for directories 4166 if(FileInfo->Dloc && 4167 FileInfo->Dloc->DirIndex) { 4168 // if Lite Flush is used, keep preallocations 4169 if(!(FlushFlags & UDF_FLUSH_FLAGS_LITE)) { 4170 full_flush: 4171 UDFFlushFESpace(Vcb, FileInfo->Dloc); 4172 if(FileInfo->Dloc->DataLoc.Flags & EXTENT_FLAG_PREALLOCATED) { 4173 FileInfo->Dloc->DataLoc.Flags |= EXTENT_FLAG_CUT_PREALLOCATED; 4174 status = UDFResizeExtent(Vcb, PartNum, UDFGetFileSize(FileInfo), FALSE, &(FileInfo->Dloc->DataLoc)); 4175 FileInfo->Dloc->DataLoc.Flags &= ~(EXTENT_FLAG_PREALLOCATED | EXTENT_FLAG_CUT_PREALLOCATED); 4176 if(OS_SUCCESS(status)) { 4177 AdPrint(("Dir pre-alloc truncated (Flush)\n")); 4178 FileInfo->Dloc->DataLoc.Modified = TRUE; 4179 } 4180 } 4181 } 4182 } 4183 // flush FE 4184 if(!OS_SUCCESS(status = UDFFlushFE(Vcb, FileInfo, PartNum))) { 4185 UDFPrint(("Error flushing FE\n")); 4186 BrutePoint(); 4187 if(FlushFlags & UDF_FLUSH_FLAGS_LITE) { 4188 UDFPrint((" flush pre-alloc\n")); 4189 FlushFlags &= ~UDF_FLUSH_FLAGS_LITE; 4190 goto full_flush; 4191 } 4192 if(FileInfo->Index >= 2) { 4193 PDIR_INDEX_ITEM DirNdx; 4194 DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index); 4195 if(DirNdx) { 4196 UDFPrint(("Recovery: mark as deleted & flush FI\n")); 4197 DirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; 4198 DirNdx->FileCharacteristics |= FILE_DELETED; 4199 FileInfo->FileIdent->fileCharacteristics |= FILE_DELETED; 4200 UDFFlushFI(Vcb, FileInfo, PartNum); 4201 } 4202 } 4203 return status; 4204 } 4205 if(!OS_SUCCESS(status = UDFFlushFI(Vcb, FileInfo, PartNum))) 4206 return status; 4207 4208 ASSERT((FileInfo->Dloc->FileEntry->descVersion == 2) || 4209 (FileInfo->Dloc->FileEntry->descVersion == 3)); 4210 4211 return STATUS_SUCCESS; 4212 } // end UDFFlushFile__() 4213 4214 /* 4215 This routine compares 2 FileInfo structures 4216 */ 4217 BOOLEAN 4218 UDFCompareFileInfo( 4219 IN PUDF_FILE_INFO f1, 4220 IN PUDF_FILE_INFO f2 4221 ) 4222 { 4223 uint_di i; 4224 PDIR_INDEX_HDR hDirIndex1; 4225 PDIR_INDEX_HDR hDirIndex2; 4226 PDIR_INDEX_ITEM DirIndex1; 4227 PDIR_INDEX_ITEM DirIndex2; 4228 4229 if(!f1 || !f2) return FALSE; 4230 if(f1->Dloc->FileEntryLen != f2->Dloc->FileEntryLen) return FALSE; 4231 // if(f1->FileIdentLen != f2->FileIdentLen) return FALSE; 4232 /* if(f1->Dloc->DirIndex && !f2->Dloc->DirIndex) return FALSE; 4233 if(f2->Dloc->DirIndex && !f1->Dloc->DirIndex) return FALSE; 4234 if((f1->Dloc->DirIndex) && 4235 (f1->Dloc->DirIndex->LastFrameCount != f2->Dloc->DirIndex->LastFrameCount)) return FALSE;*/ 4236 if(f1->Index != f2->Index) return FALSE; 4237 if(!(f1->Dloc->DataLoc.Mapping)) return FALSE; 4238 if(!(f2->Dloc->DataLoc.Mapping)) return FALSE; 4239 if(f1->Dloc->DataLoc.Mapping[0].extLocation != f2->Dloc->DataLoc.Mapping[0].extLocation) return FALSE; 4240 if(f1->Dloc->DataLoc.Mapping[0].extLength != f2->Dloc->DataLoc.Mapping[0].extLength) return FALSE; 4241 // if(f1-> != f2->) return FALSE; 4242 // if(f1-> != f2->) return FALSE; 4243 // if(f1-> != f2->) return FALSE; 4244 if(!(f1->Dloc->FileEntry)) return FALSE; 4245 if(!(f2->Dloc->FileEntry)) return FALSE; 4246 if(RtlCompareMemory(f1->Dloc->FileEntry, f2->Dloc->FileEntry, f2->Dloc->FileEntryLen) != f2->Dloc->FileEntryLen) 4247 return FALSE; 4248 if(!(hDirIndex1 = f1->Dloc->DirIndex)) return FALSE; 4249 if(!(hDirIndex2 = f2->Dloc->DirIndex)) return FALSE; 4250 4251 for(i=2; (DirIndex1 = UDFDirIndex(hDirIndex1,i)) && 4252 (DirIndex2 = UDFDirIndex(hDirIndex2,i)); i++) { 4253 if( DirIndex1->FName.Buffer && 4254 !DirIndex2->FName.Buffer) 4255 return FALSE; 4256 if( DirIndex2->FName.Buffer && 4257 !DirIndex1->FName.Buffer) 4258 return FALSE; 4259 if(!DirIndex2->FName.Buffer && 4260 !DirIndex1->FName.Buffer) 4261 continue; 4262 if(RtlCompareUnicodeString(&(DirIndex1->FName), 4263 &(DirIndex2->FName),FALSE)) { 4264 return FALSE; 4265 } 4266 // if(DirIndex1[i].FileEntry != DirIndex2[i].FileEntry) 4267 // return FALSE; 4268 if(RtlCompareMemory(&(DirIndex1->FileEntryLoc), 4269 &(DirIndex2->FileEntryLoc), sizeof(lb_addr)) != sizeof(lb_addr)) 4270 return FALSE; 4271 } 4272 4273 return TRUE; 4274 } // end UDFCompareFileInfo() 4275 4276 /* 4277 This routine computes 32-bit hash based on CRC-32 from SSH 4278 */ 4279 4280 #ifdef _MSC_VER 4281 #pragma warning(push) 4282 #pragma warning(disable:4035) // re-enable below 4283 #endif 4284 4285 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__) 4286 __declspec (naked) 4287 #endif // _X86_ 4288 uint32 4289 __fastcall 4290 crc32( 4291 IN uint8* s, // ECX 4292 IN uint32 len // EDX 4293 ) 4294 { 4295 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__) 4296 // uint32 _Size = len; 4297 4298 __asm { 4299 push ebx 4300 push ecx 4301 push edx 4302 push esi 4303 4304 xor eax,eax 4305 mov esi,ecx // ESI <- s 4306 mov ecx,edx // ECX <- len 4307 4308 jecxz EO_CRC 4309 4310 lea ebx,[crc32_tab] 4311 xor edx,edx 4312 4313 CRC_loop: 4314 4315 mov dl,al 4316 xor dl,[esi] 4317 shr eax,8 4318 xor eax,[dword ptr ebx+edx*4] 4319 inc esi 4320 loop CRC_loop 4321 4322 EO_CRC: 4323 4324 pop esi 4325 pop edx 4326 pop ecx 4327 pop ebx 4328 4329 ret 4330 } 4331 #else // NO X86 optimization , use generic C/C++ 4332 uint32 i; 4333 uint32 crc32val = 0; 4334 4335 for(i=0; i<len; i++, s++) { 4336 crc32val = 4337 crc32_tab[(crc32val ^ (*s)) & 0xff] ^ (crc32val >> 8); 4338 } 4339 return crc32val; 4340 #endif // _X86_ 4341 } // end crc32() 4342 4343 /* 4344 Calculate a 16-bit CRC checksum for unicode strings 4345 using ITU-T V.41 polynomial. 4346 4347 The OSTA-UDF(tm) 1.50 standard states that using CRCs is mandatory. 4348 The polynomial used is: x^16 + x^12 + x^15 + 1 4349 */ 4350 4351 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__) 4352 __declspec (naked) 4353 #endif // _X86_ 4354 uint16 4355 __fastcall 4356 UDFUnicodeCksum( 4357 PWCHAR s, // ECX 4358 uint32 n // EDX 4359 ) 4360 { 4361 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__) 4362 // uint32 _Size = n; 4363 4364 __asm { 4365 push ebx 4366 push ecx 4367 push edx 4368 push esi 4369 4370 xor eax,eax 4371 mov esi,ecx 4372 mov ecx,edx 4373 4374 jecxz EO_uCRC 4375 4376 lea ebx,[CrcTable] 4377 xor edx,edx 4378 4379 uCRC_loop: 4380 4381 mov dl,ah // dl = (Crc >> 8) 4382 xor dl,[esi+1] // dl = ((Crc >> 8) ^ (*s >> 8)) & 0xff 4383 mov ah,al 4384 mov al,dh // ax = (Crc << 8) 4385 xor ax,[word ptr ebx+edx*2] // ax = ........... 4386 4387 mov dl,ah 4388 xor dl,[esi] 4389 mov ah,al 4390 mov al,dh 4391 xor ax,[word ptr ebx+edx*2] 4392 4393 inc esi 4394 inc esi 4395 loop uCRC_loop 4396 4397 EO_uCRC: 4398 4399 pop esi 4400 pop edx 4401 pop ecx 4402 pop ebx 4403 4404 ret 4405 } 4406 #else // NO X86 optimization , use generic C/C++ 4407 uint16 Crc = 0; 4408 while (n--) { 4409 Crc = CrcTable[(Crc >> 8 ^ (*s >> 8)) & 0xff] ^ (Crc << 8); 4410 Crc = CrcTable[(Crc >> 8 ^ (*s++ & 0xff)) & 0xff] ^ (Crc << 8); 4411 } 4412 return Crc; 4413 4414 #endif // _X86_ 4415 } // end UDFUnicodeCksum() 4416 4417 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__) 4418 __declspec (naked) 4419 #endif // _X86_ 4420 uint16 4421 __fastcall 4422 UDFUnicodeCksum150( 4423 PWCHAR s, // ECX 4424 uint32 n // EDX 4425 ) 4426 { 4427 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__) 4428 // uint32 _Size = n; 4429 4430 __asm { 4431 push ebx 4432 push ecx 4433 push edx 4434 push esi 4435 push edi 4436 4437 xor eax,eax 4438 mov esi,ecx 4439 mov ecx,edx 4440 xor edi,edi 4441 4442 jecxz EO_uCRC 4443 4444 //lea ebx,[CrcTable] 4445 xor edx,edx 4446 xor ebx,ebx 4447 4448 uCRC_loop: 4449 4450 mov dl,ah // dl = (Crc >> 8) 4451 or edi,edx // if(*s & 0xff00) Use16 = TRUE; 4452 xor dl,[esi+1] // dl = ((Crc >> 8) ^ (*s >> 8)) & 0xff 4453 mov ah,al 4454 mov al,0 // ax = (Crc << 8) 4455 xor ax,[word ptr CrcTable+edx*2] // ax = ........... 4456 4457 mov dl,ah 4458 xor dl,[esi] 4459 mov ah,al 4460 mov al,0 4461 xor ax,[word ptr CrcTable+edx*2] 4462 4463 or edi,edi // if(!Use16) { 4464 jnz use16_1 4465 4466 rol eax,16 4467 4468 mov bl,ah // dl = (Crc >> 8) 4469 xor bl,[esi] // dl = ((Crc >> 8) ^ (*s >> 8)) & 0xff 4470 mov ah,al 4471 mov al,0 // ax = (Crc << 8) 4472 xor ax,[word ptr CrcTable+ebx*2] // ax = ........... 4473 4474 rol eax,16 4475 use16_1: 4476 inc esi 4477 inc esi 4478 loop uCRC_loop 4479 4480 EO_uCRC: 4481 4482 or edi,edi // if(!Use16) { 4483 jnz use16_2 4484 4485 rol eax,16 // } 4486 use16_2: 4487 and eax,0xffff 4488 4489 pop edi 4490 pop esi 4491 pop edx 4492 pop ecx 4493 pop ebx 4494 4495 ret 4496 } 4497 #else // NO X86 optimization , use generic C/C++ 4498 uint16 Crc = 0; 4499 uint16 Crc2 = 0; 4500 BOOLEAN Use16 = FALSE; 4501 while (n--) { 4502 if(!Use16) { 4503 if((*s) & 0xff00) { 4504 Use16 = TRUE; 4505 } else { 4506 Crc2 = CrcTable[(Crc2 >> 8 ^ (*s >> 8)) & 0xff] ^ (Crc2 << 8); 4507 } 4508 } 4509 Crc = CrcTable[(Crc >> 8 ^ (*s >> 8)) & 0xff] ^ (Crc << 8); 4510 Crc = CrcTable[(Crc >> 8 ^ (*s++ & 0xff)) & 0xff] ^ (Crc << 8); 4511 } 4512 return Use16 ? Crc : Crc2; 4513 #endif // _X86_ 4514 } // end UDFUnicodeCksum150() 4515 4516 /* 4517 Calculate a 16-bit CRC checksum using ITU-T V.41 polynomial. 4518 4519 The OSTA-UDF(tm) 1.50 standard states that using CRCs is mandatory. 4520 The polynomial used is: x^16 + x^12 + x^15 + 1 4521 */ 4522 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__) 4523 __declspec (naked) 4524 #endif // _X86_ 4525 uint16 4526 __fastcall 4527 UDFCrc( 4528 IN uint8* Data, // ECX 4529 IN SIZE_T Size // EDX 4530 ) 4531 { 4532 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__) 4533 // uint32 _Size = Size; 4534 4535 __asm { 4536 push ebx 4537 push ecx 4538 push edx 4539 push esi 4540 4541 mov esi,ecx 4542 mov ecx,edx 4543 xor eax,eax 4544 4545 jecxz EO_CRC 4546 4547 lea ebx,[CrcTable] 4548 xor edx,edx 4549 4550 CRC_loop: 4551 4552 mov dl,ah 4553 xor dl,[esi] 4554 mov ah,al 4555 mov al,dh 4556 xor ax,[word ptr ebx+edx*2] 4557 inc esi 4558 loop CRC_loop 4559 4560 EO_CRC: 4561 4562 pop esi 4563 pop edx 4564 pop ecx 4565 pop ebx 4566 4567 ret 4568 } 4569 #else // NO X86 optimization , use generic C/C++ 4570 uint16 Crc = 0; 4571 while (Size--) 4572 Crc = CrcTable[(Crc >> 8 ^ *Data++) & 0xff] ^ (Crc << 8); 4573 return Crc; 4574 #endif // _X86_ 4575 4576 } // end UDFCrc() 4577 4578 #ifdef _MSC_VER 4579 #pragma warning(pop) // re-enable warning #4035 4580 #endif 4581 4582 /* 4583 Read the first block of a tagged descriptor & check it. 4584 */ 4585 OSSTATUS 4586 UDFReadTagged( 4587 PVCB Vcb, 4588 int8* Buf, 4589 uint32 Block, 4590 uint32 Location, 4591 uint16 *Ident 4592 ) 4593 { 4594 OSSTATUS RC; 4595 tag* PTag = (tag*)Buf; 4596 // icbtag* Icb = (icbtag*)(Buf+1); 4597 uint8 checksum; 4598 unsigned int i; 4599 SIZE_T ReadBytes; 4600 int8* tb; 4601 4602 // Read the block 4603 if(Block == 0xFFFFFFFF) 4604 return NULL; 4605 4606 _SEH2_TRY { 4607 RC = UDFReadSectors(Vcb, FALSE, Block, 1, FALSE, Buf, &ReadBytes); 4608 if(!OS_SUCCESS(RC)) { 4609 UDFPrint(("UDF: Block=%x, Location=%x: read failed\n", Block, Location)); 4610 try_return(RC); 4611 } 4612 4613 *Ident = PTag->tagIdent; 4614 4615 if(Location != PTag->tagLocation) { 4616 UDFPrint(("UDF: location mismatch block %x, tag %x != %x\n", 4617 Block, PTag->tagLocation, Location)); 4618 try_return(RC = STATUS_FILE_CORRUPT_ERROR); 4619 } 4620 4621 /* Verify the tag checksum */ 4622 checksum = 0; 4623 tb = Buf; 4624 for (i=0; i<sizeof(tag); i++, tb++) 4625 checksum += (uint8)((i!=4) ? (*tb) : 0); 4626 4627 if(checksum != PTag->tagChecksum) { 4628 UDFPrint(("UDF: tag checksum failed block %x\n", Block)); 4629 try_return(RC = STATUS_CRC_ERROR); 4630 } 4631 4632 // Verify the tag version 4633 if((PTag->descVersion != 2) && 4634 (PTag->descVersion != 3)) { 4635 UDFPrint(("UDF: Tag version 0x%04x != 0x0002 || 0x0003 block %x\n", 4636 (PTag->descVersion), Block)); 4637 try_return(RC = STATUS_FILE_CORRUPT_ERROR); 4638 } 4639 4640 // Verify the descriptor CRC 4641 if(((PTag->descCRCLength) + sizeof(tag) > Vcb->BlockSize) || 4642 ((PTag->descCRC) == UDFCrc((uint8*)Buf + sizeof(tag), PTag->descCRCLength)) || 4643 !(PTag->descCRC) ) { 4644 /* UDFPrint(("Tag ID: %x, ver %x\t", PTag->tagIdent, PTag->descVersion )); 4645 if((i == TID_FILE_ENTRY) || 4646 (i == TID_EXTENDED_FILE_ENTRY)) { 4647 UDFPrint(("StrategType: %x, ", Icb->strategyType )); 4648 UDFPrint(("FileType: %x\t", Icb->fileType )); 4649 } 4650 UDFPrint(("\n"));*/ 4651 try_return(RC = STATUS_SUCCESS); 4652 } 4653 UDFPrint(("UDF: Crc failure block %x: crc = %x, crclen = %x\n", 4654 Block, PTag->descCRC, PTag->descCRCLength)); 4655 RC = STATUS_CRC_ERROR; 4656 4657 try_exit: NOTHING; 4658 4659 } _SEH2_FINALLY { 4660 ; 4661 } _SEH2_END 4662 4663 return RC; 4664 } // end UDFReadTagged() 4665 4666 #ifndef UDF_READ_ONLY_BUILD 4667 /* 4668 This routine creates hard link for the file from DirInfo1 4669 to DirInfo2 & names it as fn 4670 */ 4671 OSSTATUS 4672 UDFHardLinkFile__( 4673 IN PVCB Vcb, 4674 IN BOOLEAN IgnoreCase, 4675 IN OUT BOOLEAN* Replace, // replace if destination file exists 4676 IN PUNICODE_STRING fn, // destination 4677 IN OUT PUDF_FILE_INFO DirInfo1, 4678 IN OUT PUDF_FILE_INFO DirInfo2, 4679 IN OUT PUDF_FILE_INFO FileInfo // source (opened) 4680 ) 4681 { 4682 PUDF_FILE_INFO FileInfo2; 4683 OSSTATUS status; 4684 PDIR_INDEX_ITEM DirNdx1; 4685 PDIR_INDEX_ITEM DirNdx2; 4686 uint_di i; 4687 BOOLEAN Recovery = FALSE; 4688 BOOLEAN SameFE = FALSE; 4689 uint32 NTAttr = 0; 4690 4691 // validate FileInfo 4692 ValidateFileInfo(DirInfo1); 4693 ValidateFileInfo(DirInfo2); 4694 ValidateFileInfo(FileInfo); 4695 4696 if(UDFGetFileLinkCount(FileInfo) >= UDF_MAX_LINK_COUNT) { 4697 // too many links to file... 4698 return STATUS_TOO_MANY_LINKS; 4699 } 4700 4701 i = 0; 4702 if(DirInfo1 == DirInfo2) { 4703 if(OS_SUCCESS(status = UDFFindFile(Vcb, IgnoreCase, TRUE, fn, DirInfo2, &i)) && 4704 (i==FileInfo->Index) ) { 4705 // case-only difference 4706 return STATUS_OBJECT_NAME_COLLISION; 4707 } 4708 } 4709 4710 // PHASE 0 4711 // try to create new FileIdent & FileEntry in Dir2 4712 4713 HLinkRetry: 4714 if(!OS_SUCCESS(status = UDFCreateFile__(Vcb, IgnoreCase, fn, UDFGetFileEALength(FileInfo), 4715 0, (FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY), 4716 TRUE, DirInfo2, &FileInfo2))) { 4717 if(UDFCleanUpFile__(Vcb, FileInfo2) && FileInfo2) 4718 MyFreePool__(FileInfo2); 4719 if(status == STATUS_ACCESS_DENIED) { 4720 // try to recover >;-> 4721 if((*Replace) && !Recovery) { 4722 Recovery = TRUE; 4723 status = UDFOpenFile__(Vcb, IgnoreCase, TRUE, fn, DirInfo2, &FileInfo2, NULL); 4724 if(OS_SUCCESS(status)) { 4725 status = UDFDoesOSAllowFileToBeTargetForHLink__(FileInfo2); 4726 if(!OS_SUCCESS(status)) { 4727 UDFCloseFile__(Vcb, FileInfo2); 4728 goto cleanup_and_abort_hlink; 4729 } 4730 if((FileInfo->Dloc == FileInfo2->Dloc) && 4731 (FileInfo != FileInfo2)) { 4732 SameFE = TRUE; 4733 // 'status' is already STATUS_SUCCESS here 4734 } else { 4735 status = UDFUnlinkFile__(Vcb, FileInfo2, TRUE); 4736 } 4737 UDFCloseFile__(Vcb, FileInfo2); 4738 if(UDFCleanUpFile__(Vcb, FileInfo2)) { 4739 MyFreePool__(FileInfo2); 4740 FileInfo2 = NULL; 4741 if(SameFE) 4742 return STATUS_SUCCESS; 4743 } else { 4744 // we get here if the FileInfo has associated 4745 // system-specific Fcb 4746 // Such fact means that not all system references 4747 // has already gone (except Linked file case) 4748 if(SameFE) 4749 return STATUS_SUCCESS; 4750 if(!OS_SUCCESS(status) || 4751 (UDFGetFileLinkCount(FileInfo) < 1)) 4752 status = STATUS_ACCESS_DENIED; 4753 } 4754 if(OS_SUCCESS(status)) goto HLinkRetry; 4755 } 4756 cleanup_and_abort_hlink: 4757 if(FileInfo2 && UDFCleanUpFile__(Vcb, FileInfo2)) { 4758 MyFreePool__(FileInfo2); 4759 FileInfo2 = NULL; 4760 } 4761 } else { 4762 status = STATUS_OBJECT_NAME_COLLISION; 4763 } 4764 } 4765 return status; 4766 } 4767 // update pointers 4768 DirNdx1 = UDFDirIndex(DirInfo1->Dloc->DirIndex, FileInfo->Index); 4769 DirNdx2 = UDFDirIndex(DirInfo2->Dloc->DirIndex, FileInfo2->Index); 4770 4771 // copy file attributes to newly created FileIdent 4772 NTAttr = UDFAttributesToNT(DirNdx1, FileInfo->Dloc->FileEntry); 4773 FileInfo2->FileIdent->fileVersionNum = FileInfo->FileIdent->fileVersionNum; 4774 4775 // PHASE 1 4776 // copy all necessary info from FileInfo to FileInfo2 4777 4778 FileInfo2->FileIdent->icb = FileInfo->FileIdent->icb; 4779 FileInfo2->FileIdent->fileCharacteristics = FileInfo->FileIdent->fileCharacteristics; 4780 FileInfo2->FileIdent->fileVersionNum = FileInfo->FileIdent->fileVersionNum; 4781 4782 DirNdx2->FileCharacteristics = DirNdx1->FileCharacteristics & ~FILE_DELETED; 4783 DirNdx2->FileEntryLoc = DirNdx1->FileEntryLoc; 4784 DirNdx2->FI_Flags = (DirNdx1->FI_Flags & ~UDF_FI_FLAG_SYS_ATTR) | UDF_FI_FLAG_FI_MODIFIED | UDF_FI_FLAG_LINKED; 4785 4786 UDFAttributesToUDF(DirNdx2, FileInfo2->Dloc->FileEntry, NTAttr); 4787 4788 // PHASE 2 4789 // update FileInfo 4790 4791 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; 4792 DirNdx1->FI_Flags = DirNdx2->FI_Flags; 4793 UDFIncFileLinkCount(FileInfo); // increase to 1 4794 // UDFUpdateModifyTime(Vcb, FileInfo); 4795 FileInfo->Dloc->LinkRefCount += FileInfo2->Dloc->LinkRefCount; 4796 if(FileInfo2->FileIdent) 4797 ((FidADImpUse*)&(FileInfo2->FileIdent->icb.impUse))->uniqueID = (uint32)UDFAssingNewFUID(Vcb); 4798 4799 // PHASE 3 4800 // drop all unnecessary info from FileInfo2 4801 4802 UDFFreeFESpace(Vcb, DirInfo2, &(FileInfo2->Dloc->FELoc)); 4803 UDFRemoveDloc(Vcb, FileInfo2->Dloc); 4804 4805 // PHASE 4 4806 // perform in-memory linkage (update driver's tree structures) and flush 4807 4808 FileInfo2->Dloc = FileInfo->Dloc; 4809 UDFInsertLinkedFile(FileInfo2, FileInfo); 4810 4811 UDFCloseFile__(Vcb, FileInfo2); 4812 if(UDFCleanUpFile__(Vcb, FileInfo2)) { 4813 MyFreePool__(FileInfo2); 4814 } 4815 // return 'delete target' status 4816 (*Replace) = Recovery; 4817 4818 return STATUS_SUCCESS; 4819 } // end UDFHardLinkFile__() 4820 4821 /* 4822 This routine allocates FileEntry with in-ICB zero-sized data 4823 If it returns status != STATUS_SUCCESS caller should call UDFCleanUpFile__ 4824 for returned pointer *WITHOUT* using UDFCloseFile__ 4825 */ 4826 OSSTATUS 4827 UDFCreateRootFile__( 4828 IN PVCB Vcb, 4829 // IN uint16 AllocMode, // short/long/ext/in-icb // always in-ICB 4830 IN uint32 PartNum, 4831 IN uint32 ExtAttrSz, 4832 IN uint32 ImpUseLen, 4833 IN BOOLEAN Extended, 4834 OUT PUDF_FILE_INFO* _FileInfo 4835 ) 4836 { 4837 OSSTATUS status; 4838 LONG_AD FEicb; 4839 PUDF_FILE_INFO FileInfo; 4840 *_FileInfo = NULL; 4841 SIZE_T ReadBytes; 4842 4843 FileInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_FINF_TAG); 4844 *_FileInfo = FileInfo; 4845 if(!FileInfo) 4846 return STATUS_INSUFFICIENT_RESOURCES; 4847 ImpUseLen = (ImpUseLen + 3) & ~((uint16)3); 4848 4849 RtlZeroMemory(FileInfo, sizeof(UDF_FILE_INFO)); 4850 // init horizontal links 4851 FileInfo->NextLinkedFile = 4852 FileInfo->PrevLinkedFile = FileInfo; 4853 // allocate space for FileEntry 4854 if(!OS_SUCCESS(status = 4855 UDFBuildFileEntry(Vcb, NULL, FileInfo, PartNum, ICB_FLAG_AD_IN_ICB, ExtAttrSz, Extended) )) 4856 return status; 4857 FEicb.extLength = Vcb->LBlockSize; 4858 FEicb.extLocation.logicalBlockNum = UDFPhysLbaToPart(Vcb, PartNum, FileInfo->Dloc->FELoc.Mapping[0].extLocation); 4859 FEicb.extLocation.partitionReferenceNum = (uint16)PartNum; 4860 RtlZeroMemory(&(FEicb.impUse), sizeof(FEicb.impUse)); 4861 4862 FileInfo->Dloc->DataLoc.Mapping = UDFExtentToMapping(&(FileInfo->Dloc->FELoc.Mapping[0])); 4863 if(!(FileInfo->Dloc->DataLoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES; 4864 FileInfo->Dloc->DataLoc.Length = 0; 4865 FileInfo->Dloc->DataLoc.Offset = FileInfo->Dloc->FileEntryLen; 4866 // init FileEntry 4867 UDFSetFileUID(Vcb, FileInfo); 4868 UDFSetFileSize(FileInfo, 0); 4869 UDFIncFileLinkCount(FileInfo); // increase to 1 4870 UDFUpdateCreateTime(Vcb, FileInfo); 4871 // zero sector for FileEntry 4872 FileInfo->Dloc->DataLoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK; 4873 FileInfo->Dloc->FELoc.Mapping[0].extLength &= UDF_EXTENT_LENGTH_MASK; 4874 status = UDFWriteData(Vcb, TRUE, ((int64)(FileInfo->Dloc->FELoc.Mapping[0].extLocation)) << Vcb->BlockSizeBits, Vcb->LBlockSize, FALSE, Vcb->ZBuffer, &ReadBytes); 4875 if(!OS_SUCCESS(status)) 4876 return status; 4877 4878 UDFReferenceFile__(FileInfo); 4879 UDFReleaseDloc(Vcb, FileInfo->Dloc); 4880 return STATUS_SUCCESS; 4881 } // end UDFCreateRootFile__() 4882 4883 /* 4884 This routine tries to create StreamDirectory associated with given file 4885 Caller should use UDFCleanUpFile__ if returned status != STATUS_SUCCESS 4886 */ 4887 OSSTATUS 4888 UDFCreateStreamDir__( 4889 IN PVCB Vcb, 4890 IN PUDF_FILE_INFO FileInfo, // file containing stream-dir 4891 OUT PUDF_FILE_INFO* _SDirInfo // this is to be filled & doesn't contain 4892 // any pointers 4893 ) 4894 { 4895 OSSTATUS status; 4896 PUDF_FILE_INFO SDirInfo; 4897 uint16 Ident; 4898 4899 *_SDirInfo = NULL; 4900 ValidateFileInfo(FileInfo); 4901 // check currently recorded UDF revision 4902 if(!UDFStreamsSupported(Vcb)) 4903 return STATUS_INVALID_PARAMETER; 4904 // check if we are allowed to associate Stream Dir with this file 4905 if((FileInfo->ParentFile && UDFIsAStreamDir(FileInfo->ParentFile)) || 4906 UDFHasAStreamDir(FileInfo)) 4907 return STATUS_FILE_DELETED; 4908 // check if we have Deleted SDir 4909 if(FileInfo->Dloc->SDirInfo && 4910 UDFIsSDirDeleted(FileInfo->Dloc->SDirInfo)) 4911 return STATUS_ACCESS_DENIED; 4912 // check if this file has ExtendedFileEntry 4913 if((Ident = FileInfo->Dloc->FileEntry->tagIdent) != TID_EXTENDED_FILE_ENTRY) { 4914 if(!OS_SUCCESS(status = UDFConvertFEToExtended(Vcb, FileInfo))) 4915 return status; 4916 } 4917 4918 uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, FileInfo->Dloc->FELoc.Mapping[0].extLocation); 4919 // create stream directory file 4920 if(!OS_SUCCESS(status = UDFCreateRootFile__(Vcb, PartNum, 0,0,FALSE, &SDirInfo))) 4921 return status; 4922 // link objects 4923 SDirInfo->ParentFile = FileInfo; 4924 // record directory structure 4925 SDirInfo->Dloc->FE_Flags |= (UDF_FE_FLAG_FE_MODIFIED | UDF_FE_FLAG_IS_SDIR); 4926 4927 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_HAS_SDIR; 4928 UDFIncFileLinkCount(FileInfo); 4929 FileInfo->Dloc->FE_Flags &= ~UDF_FE_FLAG_HAS_SDIR; 4930 4931 status = UDFRecordDirectory__(Vcb, SDirInfo); 4932 UDFDecDirCounter(Vcb); 4933 4934 UDFInterlockedIncrement((PLONG)&(FileInfo->OpenCount)); 4935 if(!OS_SUCCESS(status)) { 4936 UDFUnlinkFile__(Vcb, SDirInfo, TRUE); 4937 UDFCloseFile__(Vcb, SDirInfo); 4938 UDFCleanUpFile__(Vcb, SDirInfo); 4939 MyFreePool__(SDirInfo); 4940 ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLength = 0; 4941 ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation.partitionReferenceNum = 0; 4942 ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation.logicalBlockNum = 0; 4943 return status; 4944 } 4945 *_SDirInfo = SDirInfo; 4946 // do some init 4947 ((PEXTENDED_FILE_ENTRY)(SDirInfo->Dloc->FileEntry))->icbTag.fileType = UDF_FILE_TYPE_STREAMDIR; 4948 ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLength = Vcb->LBlockSize; 4949 ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation.partitionReferenceNum = (uint16)PartNum; 4950 ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation.logicalBlockNum = 4951 UDFPhysLbaToPart(Vcb, PartNum, SDirInfo->Dloc->FELoc.Mapping[0].extLocation); 4952 ((PEXTENDED_FILE_ENTRY)(SDirInfo->Dloc->FileEntry))->uniqueID = 4953 ((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->uniqueID; 4954 FileInfo->Dloc->FE_Flags |= (UDF_FE_FLAG_FE_MODIFIED | UDF_FE_FLAG_HAS_SDIR); 4955 // open & finalize linkage 4956 FileInfo->Dloc->SDirInfo = SDirInfo; 4957 return STATUS_SUCCESS; 4958 } // end UDFCreateStreamDir__() 4959 #endif //UDF_READ_ONLY_BUILD 4960 4961 /* 4962 This routine opens Stream Directory associated with file specified 4963 */ 4964 OSSTATUS 4965 UDFOpenStreamDir__( 4966 IN PVCB Vcb, 4967 IN PUDF_FILE_INFO FileInfo, // file containing stream-dir 4968 OUT PUDF_FILE_INFO* _SDirInfo // this is to be filled & doesn't contain 4969 // any pointers 4970 ) 4971 { 4972 OSSTATUS status; 4973 PUDF_FILE_INFO SDirInfo; 4974 PUDF_FILE_INFO ParSDirInfo; 4975 uint16 Ident; 4976 4977 *_SDirInfo = NULL; 4978 ValidateFileInfo(FileInfo); 4979 // check if this file has ExtendedFileEntry 4980 if((Ident = FileInfo->Dloc->FileEntry->tagIdent) != TID_EXTENDED_FILE_ENTRY) { 4981 return STATUS_NOT_FOUND; 4982 } 4983 if((SDirInfo = FileInfo->Dloc->SDirInfo)) { 4984 // it is already opened. Good... 4985 4986 // check if we have Deleted SDir 4987 if(FileInfo->Dloc->SDirInfo && 4988 UDFIsSDirDeleted(FileInfo->Dloc->SDirInfo)) 4989 return STATUS_FILE_DELETED; 4990 // All right. Look for parallel SDir (if any) 4991 if(SDirInfo->ParentFile != FileInfo) { 4992 ParSDirInfo = UDFLocateParallelFI(FileInfo, 0, SDirInfo); 4993 BrutePoint(); 4994 if(ParSDirInfo->ParentFile != FileInfo) { 4995 SDirInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_SDFINF_TAG); 4996 *_SDirInfo = SDirInfo; 4997 if(!SDirInfo) return STATUS_INSUFFICIENT_RESOURCES; 4998 RtlCopyMemory(SDirInfo, FileInfo->Dloc->SDirInfo, sizeof(UDF_FILE_INFO)); 4999 // SDirInfo->NextLinkedFile = FileInfo->Dloc->SDirInfo->NextLinkedFile; // is already done 5000 UDFInsertLinkedFile(SDirInfo, FileInfo->Dloc->SDirInfo); 5001 SDirInfo->RefCount = 0; 5002 SDirInfo->ParentFile = FileInfo; 5003 SDirInfo->Fcb = NULL; 5004 } else { 5005 SDirInfo = ParSDirInfo; 5006 } 5007 } 5008 UDFReferenceFile__(SDirInfo); 5009 *_SDirInfo = SDirInfo; 5010 return STATUS_SUCCESS; 5011 } 5012 // normal open 5013 if(!((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLength) 5014 return STATUS_NOT_FOUND; 5015 SDirInfo = (PUDF_FILE_INFO)MyAllocatePoolTag__(UDF_FILE_INFO_MT,sizeof(UDF_FILE_INFO), MEM_SDFINF_TAG); 5016 if(!SDirInfo) return STATUS_INSUFFICIENT_RESOURCES; 5017 *_SDirInfo = SDirInfo; 5018 status = UDFOpenRootFile__(Vcb, &(((PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry))->streamDirectoryICB.extLocation) ,SDirInfo); 5019 if(!OS_SUCCESS(status)) return status; 5020 // open & finalize linkage 5021 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_HAS_SDIR; 5022 SDirInfo->Dloc->FE_Flags |= UDF_FE_FLAG_IS_SDIR; 5023 FileInfo->Dloc->SDirInfo = SDirInfo; 5024 SDirInfo->ParentFile = FileInfo; 5025 5026 UDFInterlockedIncrement((PLONG)&(FileInfo->OpenCount)); 5027 5028 return STATUS_SUCCESS; 5029 } // end UDFOpenStreamDir__() 5030 5031 #ifndef UDF_READ_ONLY_BUILD 5032 /* 5033 This routine records VAT & VAT Icb at the end of session 5034 */ 5035 OSSTATUS 5036 UDFRecordVAT( 5037 IN PVCB Vcb 5038 ) 5039 { 5040 uint32 Offset; 5041 uint32 to_read; 5042 uint32 hdrOffset, hdrOffsetNew; 5043 uint32 hdrLen; 5044 OSSTATUS status; 5045 SIZE_T ReadBytes; 5046 uint32 len; 5047 uint16 PartNdx = (uint16)Vcb->VatPartNdx; 5048 uint16 PartNum = UDFGetPartNumByPartNdx(Vcb, PartNdx); 5049 uint32 root = UDFPartStart(Vcb, PartNum); 5050 PUDF_FILE_INFO VatFileInfo = Vcb->VatFileInfo; 5051 uint32 i; 5052 PEXTENT_MAP Mapping; 5053 uint32 off, BS, NWA; 5054 int8* Old; 5055 int8* New; 5056 uint32* Vat; 5057 uint8 AllocMode; 5058 uint32 VatLen; 5059 uint32 PacketOffset; 5060 uint32 BSh = Vcb->BlockSizeBits; 5061 uint32 MaxPacket = Vcb->WriteBlockSize >> BSh; 5062 uint32 OldLen; 5063 EntityID* eID; 5064 5065 if(!(Vat = Vcb->Vat) || !VatFileInfo) return STATUS_INVALID_PARAMETER; 5066 // Disable VAT-based translation 5067 Vcb->Vat = NULL; 5068 // sync VAT and FSBM 5069 len = min(UDFPartLen(Vcb, PartNum), Vcb->FSBM_BitCount - root); 5070 len = min(Vcb->VatCount, len); 5071 for(i=0; i<len; i++) { 5072 if(UDFGetFreeBit(Vcb->FSBM_Bitmap, root+i)) 5073 Vat[i] = UDF_VAT_FREE_ENTRY; 5074 } 5075 // Ok, now we shall construct new VAT image... 5076 // !!! NOTE !!! 5077 // Both VAT copies - in-memory & on-disc 5078 // contain _relative_ addresses 5079 OldLen = len = (uint32)UDFGetFileSize(Vcb->VatFileInfo); 5080 VatLen = (Vcb->LastLBA - root + 1) * sizeof(uint32); 5081 Old = (int8*)DbgAllocatePool(PagedPool, OldLen); 5082 if(!Old) { 5083 DbgFreePool(Vat); 5084 return STATUS_INSUFFICIENT_RESOURCES; 5085 } 5086 // read old one 5087 status = UDFReadFile__(Vcb, VatFileInfo, 0, OldLen, FALSE, Old, &ReadBytes); 5088 if(!OS_SUCCESS(status)) { 5089 DbgFreePool(Vat); 5090 DbgFreePool(Old); 5091 return status; 5092 } 5093 // prepare some pointers 5094 // and fill headers 5095 if(Vcb->Partitions[PartNdx].PartitionType == UDF_VIRTUAL_MAP15) { 5096 Offset = 0; 5097 to_read = 5098 hdrOffset = len - sizeof(VirtualAllocationTable15); 5099 hdrLen = sizeof(VirtualAllocationTable15); 5100 hdrOffsetNew = VatLen; 5101 New = (int8*)DbgAllocatePool(PagedPool, VatLen + hdrLen); 5102 if(!New) { 5103 DbgFreePool(Vat); 5104 return STATUS_INSUFFICIENT_RESOURCES; 5105 } 5106 RtlCopyMemory(New+hdrOffsetNew, Old+hdrOffset, hdrLen); 5107 ((VirtualAllocationTable15*)(New + hdrOffset))->previousVATICB = 5108 VatFileInfo->Dloc->FELoc.Mapping[0].extLocation - root; 5109 eID = &(((VirtualAllocationTable15*)(New + hdrOffset))->ident); 5110 5111 UDFSetEntityID_imp(eID, UDF_ID_ALLOC); 5112 5113 /* RtlCopyMemory((int8*)&(eID->ident), UDF_ID_ALLOC, sizeof(UDF_ID_ALLOC) ); 5114 iis = (impIdentSuffix*)&(eID->identSuffix); 5115 iis->OSClass = UDF_OS_CLASS_WINNT; 5116 iis->OSIdent = UDF_OS_ID_WINNT;*/ 5117 } else { 5118 VirtualAllocationTable20* Buf; 5119 5120 Offset = ((VirtualAllocationTable20*)Old)->lengthHeader; 5121 to_read = len - Offset; 5122 hdrOffset = 0; 5123 hdrLen = sizeof(VirtualAllocationTable20); 5124 hdrOffsetNew = 0; 5125 New = (int8*)DbgAllocatePool(PagedPool, VatLen + hdrLen); 5126 if(!New) { 5127 DbgFreePool(Vat); 5128 return STATUS_INSUFFICIENT_RESOURCES; 5129 } 5130 RtlCopyMemory(New+hdrOffsetNew, Old+hdrOffset, hdrLen); 5131 ((VirtualAllocationTable20*)New)->previousVatICBLoc = 5132 VatFileInfo->Dloc->FELoc.Mapping[0].extLocation - root; 5133 5134 Buf = (VirtualAllocationTable20*)New; 5135 5136 Buf->minReadRevision = Vcb->minUDFReadRev; 5137 Buf->minWriteRevision = Vcb->minUDFWriteRev; 5138 Buf->maxWriteRevision = Vcb->maxUDFWriteRev; 5139 5140 Buf->numFIDSFiles = Vcb->numFiles; 5141 Buf->numFIDSDirectories = Vcb->numDirs; 5142 } 5143 5144 RtlCopyMemory(New+Offset, Vat, VatLen); 5145 // 5146 if(VatFileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY) { 5147 eID = &(((PEXTENDED_FILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->impIdent); 5148 } else { 5149 eID = &(((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->impIdent); 5150 } 5151 5152 #if 0 5153 UDFSetEntityID_imp(eID, UDF_ID_DEVELOPER); 5154 #endif 5155 5156 /* RtlCopyMemory((int8*)&(eID->ident), UDF_ID_DEVELOPER, sizeof(UDF_ID_DEVELOPER) ); 5157 iis = (impIdentSuffix*)&(eID->identSuffix); 5158 iis->OSClass = UDF_OS_CLASS_WINNT; 5159 iis->OSIdent = UDF_OS_ID_WINNT;*/ 5160 5161 VatFileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; 5162 // drop VAT 5163 DbgFreePool(Vat); 5164 len = VatLen; 5165 // the operation of resize can modifiy WriteCount in WCache due to movement 5166 // of the data from FE. That's why we should remember PacketOffset now 5167 if(to_read < VatLen) { 5168 status = UDFResizeFile__(Vcb, VatFileInfo, len = hdrLen + VatLen); 5169 if(!OS_SUCCESS(status)) { 5170 return status; 5171 } 5172 UDFMarkSpaceAsXXX(Vcb, VatFileInfo->Dloc, VatFileInfo->Dloc->DataLoc.Mapping, AS_DISCARDED); //free 5173 } 5174 PacketOffset = WCacheGetWriteBlockCount__(&(Vcb->FastCache)); 5175 if( ((((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) ) { 5176 // now we'll place FE & built-in data to the last sector of 5177 // the last packet will be recorded 5178 if(!PacketOffset) { 5179 // add padding 5180 UDFWriteData(Vcb, TRUE, ((uint64)Vcb->NWA) << Vcb->BlockSizeBits, 1, FALSE, Old, &ReadBytes); 5181 PacketOffset++; 5182 } else { 5183 Vcb->Vat = (uint32*)(New+Offset); 5184 WCacheSyncReloc__(&(Vcb->FastCache), Vcb); 5185 Vcb->Vat = NULL; 5186 } 5187 VatFileInfo->Dloc->FELoc.Mapping[0].extLocation = 5188 VatFileInfo->Dloc->DataLoc.Mapping[0].extLocation = 5189 Vcb->NWA+PacketOffset; 5190 VatFileInfo->Dloc->FELoc.Modified = TRUE; 5191 // setup descTag 5192 ((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->descTag.tagLocation = 5193 UDFPhysLbaToPart(Vcb, PartNum, VatFileInfo->Dloc->DataLoc.Mapping[0].extLocation); 5194 // record data 5195 if(OS_SUCCESS(status = UDFWriteFile__(Vcb, VatFileInfo, 0, VatLen + hdrLen, FALSE, New, &ReadBytes))) { 5196 status = UDFFlushFile__(Vcb, VatFileInfo); 5197 } 5198 return status; 5199 } 5200 // We can't fit the whole VAT in FE tail 5201 // Now lets 'unpack' VAT's mapping to make updating easier 5202 status = UDFUnPackMapping(Vcb, &(VatFileInfo->Dloc->DataLoc)); 5203 if(!OS_SUCCESS(status)) return status; 5204 // update VAT with locations of not flushed blocks 5205 if(PacketOffset) { 5206 Vcb->Vat = (uint32*)(New+Offset); 5207 WCacheSyncReloc__(&(Vcb->FastCache), Vcb); 5208 Vcb->Vat = NULL; 5209 } 5210 5211 Mapping = VatFileInfo->Dloc->DataLoc.Mapping; 5212 off=0; 5213 BS = Vcb->BlockSize; 5214 NWA = Vcb->NWA; 5215 VatLen += hdrLen; 5216 // record modified parts of VAT & update mapping 5217 for(i=0; Mapping[i].extLength; i++) { 5218 to_read = (VatLen>=BS) ? BS : VatLen; 5219 if((OldLen < off) || (RtlCompareMemory(Old+off, New+off, to_read) != to_read)) { 5220 // relocate frag 5221 Mapping[i].extLocation = NWA+PacketOffset; 5222 Mapping[i].extLength &= UDF_EXTENT_LENGTH_MASK; 5223 PacketOffset++; 5224 if(PacketOffset >= MaxPacket) { 5225 NWA += (MaxPacket + 7); 5226 PacketOffset = 0; 5227 } 5228 status = UDFWriteFile__(Vcb, VatFileInfo, off, to_read, FALSE, New+off, &ReadBytes); 5229 if(!OS_SUCCESS(status)) { 5230 return status; 5231 } 5232 } 5233 VatLen-=BS; 5234 off+=BS; 5235 } 5236 // pack mapping 5237 UDFPackMapping(Vcb, &(VatFileInfo->Dloc->DataLoc)); 5238 len = UDFGetMappingLength(VatFileInfo->Dloc->DataLoc.Mapping)/sizeof(EXTENT_MAP) - 1; 5239 // obtain AllocMode 5240 AllocMode = ((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK; 5241 switch(AllocMode) { 5242 case ICB_FLAG_AD_SHORT: { 5243 AllocMode = sizeof(SHORT_AD); 5244 break; 5245 } 5246 case ICB_FLAG_AD_LONG: { 5247 AllocMode = sizeof(LONG_AD); 5248 break; 5249 } 5250 case ICB_FLAG_AD_EXTENDED: { 5251 // break; 5252 } 5253 default: { 5254 return STATUS_INVALID_PARAMETER; 5255 } 5256 } 5257 // calculate actual AllocSequence length (in blocks) 5258 len = (len*AllocMode+BS-1+VatFileInfo->Dloc->AllocLoc.Offset) / 5259 // (((BS - sizeof(ALLOC_EXT_DESC))/sizeof(SHORT_AD))*sizeof(SHORT_AD)); 5260 ((BS - sizeof(ALLOC_EXT_DESC) + AllocMode - 1) & ~(AllocMode-1)); 5261 // Re-init AllocLoc 5262 if(VatFileInfo->Dloc->AllocLoc.Mapping) MyFreePool__(VatFileInfo->Dloc->AllocLoc.Mapping); 5263 VatFileInfo->Dloc->AllocLoc.Mapping = (PEXTENT_MAP)MyAllocatePoolTag__(NonPagedPool , (len+1)*sizeof(EXTENT_MAP), 5264 MEM_EXTMAP_TAG); 5265 if(!(VatFileInfo->Dloc->AllocLoc.Mapping)) return STATUS_INSUFFICIENT_RESOURCES; 5266 5267 VatFileInfo->Dloc->AllocLoc.Offset = (uint32)(VatFileInfo->Dloc->FELoc.Length); 5268 VatFileInfo->Dloc->AllocLoc.Length = 0; 5269 Mapping = VatFileInfo->Dloc->AllocLoc.Mapping; 5270 Mapping[0].extLength = BS-VatFileInfo->Dloc->AllocLoc.Offset; 5271 // Mapping[0].extLocation = ???; 5272 for(i=1; i<len; i++) { 5273 // relocate frag 5274 Mapping[i].extLocation = NWA+PacketOffset; 5275 Mapping[i].extLength = BS; 5276 PacketOffset++; 5277 if(PacketOffset >= MaxPacket) { 5278 NWA += (MaxPacket + 7); 5279 PacketOffset = 0; 5280 } 5281 } 5282 // Terminator 5283 Mapping[i].extLocation = 5284 Mapping[i].extLength = 0; 5285 5286 if( !PacketOffset && 5287 (VatFileInfo->Dloc->AllocLoc.Length <= (Vcb->BlockSize - (uint32)(VatFileInfo->Dloc->AllocLoc.Offset)) ) ) { 5288 // add padding 5289 UDFWriteData(Vcb, TRUE, ((uint64)NWA) << Vcb->BlockSizeBits, 1, FALSE, Old, &ReadBytes); 5290 PacketOffset++; 5291 } 5292 // now we'll place FE & built-in data to the last sector of 5293 // the last packet will be recorded 5294 VatFileInfo->Dloc->FELoc.Mapping[0].extLocation = 5295 VatFileInfo->Dloc->AllocLoc.Mapping[0].extLocation = 5296 NWA+PacketOffset; 5297 VatFileInfo->Dloc->FELoc.Modified = TRUE; 5298 // setup descTag 5299 ((PFILE_ENTRY)(VatFileInfo->Dloc->FileEntry))->descTag.tagLocation = 5300 UDFPhysLbaToPart(Vcb, PartNum, VatFileInfo->Dloc->FELoc.Mapping[0].extLocation); 5301 VatFileInfo->Dloc->DataLoc.Modified = TRUE; 5302 5303 status = UDFFlushFile__(Vcb, VatFileInfo); 5304 if(!OS_SUCCESS(status)) 5305 return status; 5306 WCacheFlushAll__(&(Vcb->FastCache), Vcb); 5307 return STATUS_SUCCESS; 5308 } // end UDFRecordVAT() 5309 #endif //UDF_READ_ONLY_BUILD 5310 5311 /* 5312 This routine updates VAT according to RequestedLbaTable (RelocTab) & 5313 actual physical address where this data will be stored 5314 */ 5315 OSSTATUS 5316 UDFUpdateVAT( 5317 IN void* _Vcb, 5318 IN uint32 Lba, 5319 IN uint32* RelocTab, // can be NULL 5320 IN uint32 BCount 5321 ) 5322 { 5323 #ifndef UDF_READ_ONLY_BUILD 5324 PVCB Vcb = (PVCB)_Vcb; 5325 uint16 PartNdx = (uint16)(Vcb->VatPartNdx); 5326 uint16 PartNum = (uint16)(Lba ? UDFGetPartNumByPhysLba(Vcb, Lba) : UDFGetPartNumByPartNdx(Vcb, PartNdx)); 5327 if(PartNum != UDFGetPartNumByPartNdx(Vcb, PartNdx)) { 5328 UDFPrint(("UDFUpdateVAT: Write to Write-Protected partition\n")); 5329 return STATUS_MEDIA_WRITE_PROTECTED; 5330 } 5331 // !!! NOTE !!! 5332 // Both VAT copies - in-memory & on-disc 5333 // contain _relative_ addresses 5334 uint32 root = Vcb->Partitions[PartNdx].PartitionRoot; 5335 uint32 NWA = Vcb->NWA-root; 5336 uint32 i; 5337 uint32 CurLba; 5338 5339 if(!Vcb->Vat) return STATUS_SUCCESS; 5340 5341 for(i=0; i<BCount; i++, NWA++) { 5342 if((CurLba = (RelocTab ? RelocTab[i] : (Lba+i)) - root) >= Vcb->VatCount) 5343 Vcb->VatCount = CurLba+1; 5344 Vcb->Vat[CurLba] = NWA; 5345 } 5346 return STATUS_SUCCESS; 5347 #else //UDF_READ_ONLY_BUILD 5348 return STATUS_MEDIA_WRITE_PROTECTED; 5349 #endif //UDF_READ_ONLY_BUILD 5350 } // end UDFUpdateVAT() 5351 5352 #ifndef UDF_READ_ONLY_BUILD 5353 /* 5354 This routine rebuilds file's FE in order to move data from 5355 ICB to separate Block. 5356 */ 5357 OSSTATUS 5358 UDFConvertFEToNonInICB( 5359 IN PVCB Vcb, 5360 IN PUDF_FILE_INFO FileInfo, 5361 IN uint8 NewAllocMode 5362 ) 5363 { 5364 OSSTATUS status; 5365 int8* OldInIcb = NULL; 5366 uint32 OldLen; 5367 ValidateFileInfo(FileInfo); 5368 SIZE_T ReadBytes; 5369 SIZE_T _WrittenBytes; 5370 PUDF_DATALOC_INFO Dloc; 5371 5372 // ASSERT(FileInfo->RefCount >= 1); 5373 5374 Dloc = FileInfo->Dloc; 5375 ASSERT(Dloc->FELoc.Mapping[0].extLocation); 5376 uint32 PartNum = UDFGetPartNumByPhysLba(Vcb, Dloc->FELoc.Mapping[0].extLocation); 5377 5378 if(NewAllocMode == ICB_FLAG_AD_DEFAULT_ALLOC_MODE) { 5379 NewAllocMode = (uint8)(Vcb->DefaultAllocMode); 5380 } 5381 // we do not support recording of extended AD now 5382 if(NewAllocMode != ICB_FLAG_AD_SHORT && 5383 NewAllocMode != ICB_FLAG_AD_LONG) 5384 return STATUS_INVALID_PARAMETER; 5385 if(!Dloc->DataLoc.Offset || !Dloc->DataLoc.Length) 5386 return STATUS_SUCCESS; 5387 ASSERT(!Dloc->AllocLoc.Mapping); 5388 // read in-icb data. it'll be replaced after resize 5389 OldInIcb = (int8*)MyAllocatePool__(NonPagedPool, (uint32)(Dloc->DataLoc.Length)); 5390 if(!OldInIcb) 5391 return STATUS_INSUFFICIENT_RESOURCES; 5392 OldLen = (uint32)(Dloc->DataLoc.Length); 5393 status = UDFReadExtent(Vcb, &(Dloc->DataLoc), 0, OldLen, FALSE, OldInIcb, &ReadBytes); 5394 if(!OS_SUCCESS(status)) { 5395 MyFreePool__(OldInIcb); 5396 return status; 5397 } 5398 /* if(!Dloc->AllocLoc.Mapping) { 5399 Dloc->AllocLoc.Mapping = (PEXTENT_MAP)MyAllocatePool__(NonPagedPool, sizeof(EXTENT_MAP)*2); 5400 if(!Dloc->AllocLoc.Mapping) { 5401 MyFreePool__(OldInIcb); 5402 return STATUS_INSUFFICIENT_RESOURCES; 5403 } 5404 } 5405 // init Alloc mode 5406 if((((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) { 5407 ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK; 5408 ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= Vcb->DefaultAllocMode; 5409 } else { 5410 BrutePoint(); 5411 } 5412 RtlZeroMemory(Dloc->AllocLoc.Mapping, sizeof(EXTENT_MAP)*2); 5413 // Dloc->AllocLoc.Mapping[0].extLocation = 0; 5414 Dloc->AllocLoc.Mapping[0].extLength = Vcb->LBlockSize | EXTENT_NOT_RECORDED_NOT_ALLOCATED; 5415 // Dloc->AllocLoc.Mapping[1].extLocation = 0; 5416 // Dloc->AllocLoc.Mapping[1].extLength = 0; 5417 */ 5418 5419 // grow extent in order to force space allocation 5420 status = UDFResizeExtent(Vcb, PartNum, Vcb->LBlockSize, FALSE, &Dloc->DataLoc); 5421 if(!OS_SUCCESS(status)) { 5422 MyFreePool__(OldInIcb); 5423 return status; 5424 } 5425 5426 // set Alloc mode 5427 if((((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) { 5428 ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags &= ~ICB_FLAG_ALLOC_MASK; 5429 ((PFILE_ENTRY)(Dloc->FileEntry))->icbTag.flags |= NewAllocMode; 5430 } else { 5431 BrutePoint(); 5432 } 5433 5434 // revert to initial extent size. This will not cause NonInICB->InICB transform 5435 status = UDFResizeExtent(Vcb, PartNum, OldLen, FALSE, &Dloc->DataLoc); 5436 if(!OS_SUCCESS(status)) { 5437 MyFreePool__(OldInIcb); 5438 return status; 5439 } 5440 5441 // replace data from ICB (if any) & free buffer 5442 status = UDFWriteExtent(Vcb, &(Dloc->DataLoc), 0, OldLen, FALSE, OldInIcb, &_WrittenBytes); 5443 MyFreePool__(OldInIcb); 5444 if(!OS_SUCCESS(status)) { 5445 return status; 5446 } 5447 // inform UdfInfo, that AllocDesc's must be rebuilt on flush/close 5448 Dloc->AllocLoc.Modified = TRUE; 5449 Dloc->DataLoc.Modified = TRUE; 5450 return STATUS_SUCCESS; 5451 } // end UDFConvertFEToNonInICB() 5452 5453 /* 5454 This routine converts file's FE to extended form. 5455 It is needed for stream creation. 5456 */ 5457 OSSTATUS 5458 UDFConvertFEToExtended( 5459 IN PVCB Vcb, 5460 IN PUDF_FILE_INFO FileInfo 5461 ) 5462 { 5463 PEXTENDED_FILE_ENTRY ExFileEntry; 5464 PFILE_ENTRY FileEntry; 5465 uint32 Length, NewLength, l; 5466 OSSTATUS status; 5467 SIZE_T ReadBytes; 5468 5469 if(!FileInfo) return STATUS_INVALID_PARAMETER; 5470 ValidateFileInfo(FileInfo); 5471 if(FileInfo->Dloc->FileEntry->tagIdent == TID_EXTENDED_FILE_ENTRY) return STATUS_SUCCESS; 5472 if(FileInfo->Dloc->FileEntry->tagIdent != TID_FILE_ENTRY) return STATUS_INVALID_PARAMETER; 5473 5474 /* if(!OS_SUCCESS(status = UDFFlushFile__(Vcb, FileInfo))) 5475 return status;*/ 5476 5477 Length = FileInfo->Dloc->FileEntryLen; 5478 NewLength = Length - sizeof(FILE_ENTRY) + sizeof(EXTENDED_FILE_ENTRY); 5479 ExFileEntry = (PEXTENDED_FILE_ENTRY)MyAllocatePoolTag__(NonPagedPool, NewLength, MEM_XFE_TAG); 5480 if(!ExFileEntry) return STATUS_INSUFFICIENT_RESOURCES; 5481 FileEntry = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry); 5482 RtlZeroMemory(ExFileEntry, NewLength); 5483 5484 ExFileEntry->descTag.tagIdent = TID_EXTENDED_FILE_ENTRY; 5485 ExFileEntry->icbTag = FileEntry->icbTag; 5486 ExFileEntry->uid = FileEntry->uid; 5487 ExFileEntry->gid = FileEntry->gid; 5488 ExFileEntry->permissions = FileEntry->permissions; 5489 ExFileEntry->fileLinkCount = FileEntry->fileLinkCount; 5490 ExFileEntry->recordFormat = FileEntry->recordFormat; 5491 ExFileEntry->recordDisplayAttr = FileEntry->recordDisplayAttr; 5492 ExFileEntry->recordLength = FileEntry->recordLength; 5493 ExFileEntry->informationLength = FileEntry->informationLength; 5494 ExFileEntry->logicalBlocksRecorded = FileEntry->logicalBlocksRecorded; 5495 ExFileEntry->accessTime = FileEntry->accessTime; 5496 ExFileEntry->modificationTime = FileEntry->modificationTime; 5497 ExFileEntry->attrTime = FileEntry->attrTime; 5498 ExFileEntry->checkpoint = FileEntry->checkpoint; 5499 ExFileEntry->extendedAttrICB = FileEntry->extendedAttrICB; 5500 ExFileEntry->impIdent = FileEntry->impIdent; 5501 ExFileEntry->uniqueID = FileEntry->uniqueID; 5502 ExFileEntry->lengthExtendedAttr = FileEntry->lengthExtendedAttr; 5503 ExFileEntry->lengthAllocDescs = FileEntry->lengthAllocDescs; 5504 RtlCopyMemory(ExFileEntry+1, FileEntry+1, FileEntry->lengthExtendedAttr); 5505 RtlCopyMemory((int8*)(ExFileEntry+1)+FileEntry->lengthExtendedAttr, (int8*)(ExFileEntry+1)+FileEntry->lengthExtendedAttr, FileEntry->lengthAllocDescs); 5506 5507 if((((PFILE_ENTRY)(FileInfo->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK) == ICB_FLAG_AD_IN_ICB) { 5508 5509 if((l = (uint32)(FileInfo->Dloc->DataLoc.Length))) { 5510 5511 int8* tmp_buff = (int8*)MyAllocatePool__(NonPagedPool, l); 5512 if(!tmp_buff) { 5513 MyFreePool__(ExFileEntry); 5514 return STATUS_INSUFFICIENT_RESOURCES; 5515 } 5516 if(!OS_SUCCESS(status = UDFReadFile__(Vcb, FileInfo, 0, l, FALSE, tmp_buff, &ReadBytes)) || 5517 !OS_SUCCESS(status = UDFResizeFile__(Vcb, FileInfo, 0)) ) { 5518 MyFreePool__(ExFileEntry); 5519 MyFreePool__(tmp_buff); 5520 return status; 5521 } 5522 FileInfo->Dloc->FELoc.Length = 5523 FileInfo->Dloc->DataLoc.Offset = NewLength; 5524 FileInfo->Dloc->FELoc.Modified = 5525 FileInfo->Dloc->DataLoc.Modified = TRUE; 5526 MyFreePool__(FileInfo->Dloc->FileEntry); 5527 FileInfo->Dloc->FileEntry = (tag*)ExFileEntry; 5528 if(!OS_SUCCESS(status = UDFResizeFile__(Vcb, FileInfo, l)) || 5529 !OS_SUCCESS(status = UDFWriteFile__(Vcb, FileInfo, 0, l, FALSE, tmp_buff, &ReadBytes)) ) { 5530 MyFreePool__(ExFileEntry); 5531 MyFreePool__(tmp_buff); 5532 return status; 5533 } 5534 MyFreePool__(tmp_buff); 5535 } else { 5536 FileInfo->Dloc->FELoc.Length = 5537 FileInfo->Dloc->DataLoc.Offset = NewLength; 5538 FileInfo->Dloc->FELoc.Modified = 5539 FileInfo->Dloc->DataLoc.Modified = TRUE; 5540 MyFreePool__(FileInfo->Dloc->FileEntry); 5541 FileInfo->Dloc->FileEntry = (tag*)ExFileEntry; 5542 } 5543 } else { 5544 FileInfo->Dloc->FELoc.Length = 5545 FileInfo->Dloc->AllocLoc.Offset = NewLength; 5546 FileInfo->Dloc->FELoc.Modified = 5547 FileInfo->Dloc->AllocLoc.Modified = TRUE; 5548 MyFreePool__(FileInfo->Dloc->FileEntry); 5549 FileInfo->Dloc->FileEntry = (tag*)ExFileEntry; 5550 } 5551 FileInfo->Dloc->FileEntryLen = NewLength; 5552 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; 5553 if(Vcb->minUDFReadRev < 0x0200) 5554 Vcb->minUDFReadRev = 0x0200; 5555 return STATUS_SUCCESS; 5556 } // end UDFConvertFEToExtended() 5557 5558 /* 5559 This routine makes file almost unavailable for external callers. 5560 The only way to access Hidden with this routine file is OpenByIndex. 5561 It is usefull calling this routine to pretend file to be deleted, 5562 for ex. when we have UDFCleanUp__() or smth. like this in progress, 5563 but we want to create file with the same name. 5564 */ 5565 OSSTATUS 5566 UDFPretendFileDeleted__( 5567 IN PVCB Vcb, 5568 IN PUDF_FILE_INFO FileInfo 5569 ) 5570 { 5571 AdPrint(("UDFPretendFileDeleted__:\n")); 5572 5573 NTSTATUS RC; 5574 PDIR_INDEX_HDR hDirNdx = UDFGetDirIndexByFileInfo(FileInfo); 5575 if(!hDirNdx) return STATUS_CANNOT_DELETE; 5576 PDIR_INDEX_ITEM DirNdx = UDFDirIndex(hDirNdx, FileInfo->Index); 5577 if(!DirNdx) return STATUS_CANNOT_DELETE; 5578 5579 5580 // we can't hide file that is not marked as deleted 5581 RC = UDFDoesOSAllowFilePretendDeleted__(FileInfo); 5582 if(!NT_SUCCESS(RC)) 5583 return RC; 5584 5585 AdPrint(("UDFPretendFileDeleted__: set UDF_FI_FLAG_FI_INTERNAL\n")); 5586 5587 DirNdx->FI_Flags |= UDF_FI_FLAG_FI_INTERNAL; 5588 if(DirNdx->FName.Buffer) { 5589 MyFreePool__(DirNdx->FName.Buffer); 5590 DirNdx->FName.Buffer = NULL; 5591 DirNdx->FName.Length = 5592 DirNdx->FName.MaximumLength = 0; 5593 } 5594 return STATUS_SUCCESS; 5595 } // end UDFPretendFileDeleted__() 5596 #endif //UDF_READ_ONLY_BUILD 5597