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