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 * 8 * File: Sys_Spec.cpp 9 * 10 * Module: UDF File System Driver 11 * (both User and Kernel mode execution) 12 * 13 * Description: 14 * Contains system-secific code 15 * 16 *************************************************************************/ 17 18 19 /* 20 This routine converts UDF timestamp to NT time 21 */ 22 LONGLONG 23 UDFTimeToNT( 24 IN PUDF_TIME_STAMP UdfTime 25 ) 26 { 27 LONGLONG NtTime; 28 TIME_FIELDS TimeFields; 29 30 TimeFields.Milliseconds = (USHORT)(UdfTime->centiseconds * 10 + UdfTime->hundredsOfMicroseconds / 100); 31 TimeFields.Second = (USHORT)(UdfTime->second); 32 TimeFields.Minute = (USHORT)(UdfTime->minute); 33 TimeFields.Hour = (USHORT)(UdfTime->hour); 34 TimeFields.Day = (USHORT)(UdfTime->day); 35 TimeFields.Month = (USHORT)(UdfTime->month); 36 TimeFields.Year = (USHORT)((UdfTime->year < 1601) ? 1601 : UdfTime->year); 37 38 if (!RtlTimeFieldsToTime(&TimeFields, (PLARGE_INTEGER)&NtTime)) { 39 NtTime = 0; 40 } else { 41 ExLocalTimeToSystemTime( (PLARGE_INTEGER)&NtTime, (PLARGE_INTEGER)&NtTime ); 42 } 43 44 return NtTime; 45 } // end UDFTimeToNT() 46 47 48 /* 49 This routine converts NT time to UDF timestamp 50 */ 51 VOID 52 UDFTimeToUDF( 53 IN LONGLONG NtTime, 54 OUT PUDF_TIME_STAMP UdfTime 55 ) 56 { 57 if(!NtTime) return; 58 LONGLONG LocalTime; 59 60 TIME_FIELDS TimeFields; 61 62 ExSystemTimeToLocalTime( (PLARGE_INTEGER)&NtTime, (PLARGE_INTEGER)&LocalTime ); 63 RtlTimeToTimeFields( (PLARGE_INTEGER)&LocalTime, &TimeFields ); 64 65 LocalTime /= 10; // microseconds 66 UdfTime->microseconds = (UCHAR)(NtTime % 100); 67 LocalTime /= 100; // hundreds of microseconds 68 UdfTime->hundredsOfMicroseconds = (UCHAR)(NtTime % 100); 69 LocalTime /= 100; // centiseconds 70 UdfTime->centiseconds = (UCHAR)(TimeFields.Milliseconds / 10); 71 UdfTime->second = (UCHAR)(TimeFields.Second); 72 UdfTime->minute = (UCHAR)(TimeFields.Minute); 73 UdfTime->hour = (UCHAR)(TimeFields.Hour); 74 UdfTime->day = (UCHAR)(TimeFields.Day); 75 UdfTime->month = (UCHAR)(TimeFields.Month); 76 UdfTime->year = (USHORT)(TimeFields.Year); 77 UdfTime->typeAndTimezone = (TIMESTAMP_TYPE_LOCAL << 14); 78 } // end UDFTimeToUDF() 79 80 /* 81 */ 82 ULONG 83 UDFAttributesToNT( 84 IN PDIR_INDEX_ITEM FileDirNdx, 85 IN tag* FileEntry 86 ) 87 { 88 ASSERT(FileDirNdx); 89 if( (FileDirNdx->FI_Flags & UDF_FI_FLAG_SYS_ATTR) && 90 !(FileDirNdx->FI_Flags & UDF_FI_FLAG_LINKED)) 91 return FileDirNdx->SysAttr; 92 93 ULONG NTAttr = 0; 94 ULONG attr = 0; //permissions 95 USHORT Flags = 0; 96 USHORT Type = 0; 97 UCHAR FCharact = 0; 98 99 if(!FileEntry) { 100 if(!FileDirNdx->FileInfo) 101 return 0; 102 ValidateFileInfo(FileDirNdx->FileInfo); 103 FileEntry = FileDirNdx->FileInfo->Dloc->FileEntry; 104 } 105 if(FileEntry->tagIdent == TID_FILE_ENTRY) { 106 attr = ((PFILE_ENTRY)FileEntry)->permissions; 107 Flags = ((PFILE_ENTRY)FileEntry)->icbTag.flags; 108 Type = ((PFILE_ENTRY)FileEntry)->icbTag.fileType; 109 if(((PFILE_ENTRY)FileEntry)->fileLinkCount > 1) 110 FileDirNdx->FI_Flags |= UDF_FI_FLAG_LINKED; 111 } else { 112 attr = ((PEXTENDED_FILE_ENTRY)FileEntry)->permissions; 113 Flags = ((PEXTENDED_FILE_ENTRY)FileEntry)->icbTag.flags; 114 Type = ((PEXTENDED_FILE_ENTRY)FileEntry)->icbTag.fileType; 115 if(((PEXTENDED_FILE_ENTRY)FileEntry)->fileLinkCount > 1) 116 FileDirNdx->FI_Flags |= UDF_FI_FLAG_LINKED; 117 } 118 FCharact = FileDirNdx->FileCharacteristics; 119 120 if(Flags & ICB_FLAG_SYSTEM) NTAttr |= FILE_ATTRIBUTE_SYSTEM; 121 if(Flags & ICB_FLAG_ARCHIVE) NTAttr |= FILE_ATTRIBUTE_ARCHIVE; 122 if((Type == UDF_FILE_TYPE_DIRECTORY) || 123 (Type == UDF_FILE_TYPE_STREAMDIR) || 124 (FCharact & FILE_DIRECTORY)) { 125 NTAttr |= FILE_ATTRIBUTE_DIRECTORY; 126 #ifdef UDF_DBG 127 } else { 128 //NTAttr |= FILE_ATTRIBUTE_NORMAL; 129 #endif 130 } 131 if(FCharact & FILE_HIDDEN) NTAttr |= FILE_ATTRIBUTE_HIDDEN; 132 if( !(attr & PERM_O_WRITE) && 133 !(attr & PERM_G_WRITE) && 134 !(attr & PERM_U_WRITE) && 135 !(attr & PERM_O_DELETE) && 136 !(attr & PERM_G_DELETE) && 137 !(attr & PERM_U_DELETE) ) { 138 NTAttr |= FILE_ATTRIBUTE_READONLY; 139 } 140 FileDirNdx->SysAttr = NTAttr; 141 return NTAttr; 142 } // end UDFAttributesToNT() 143 144 /* 145 */ 146 VOID 147 UDFAttributesToUDF( 148 IN PDIR_INDEX_ITEM FileDirNdx, 149 IN tag* FileEntry, 150 IN ULONG NTAttr 151 ) 152 { 153 PULONG attr; //permissions 154 PUSHORT Flags; 155 PUCHAR Type; 156 PUCHAR FCharact; 157 158 NTAttr &= UDF_VALID_FILE_ATTRIBUTES; 159 160 if(!FileEntry) { 161 ASSERT(FileDirNdx); 162 if(!FileDirNdx->FileInfo) 163 return; 164 ValidateFileInfo(FileDirNdx->FileInfo); 165 FileEntry = FileDirNdx->FileInfo->Dloc->FileEntry; 166 FileDirNdx->FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; 167 } 168 if(FileEntry->tagIdent == TID_FILE_ENTRY) { 169 attr = &((PFILE_ENTRY)FileEntry)->permissions; 170 Flags = &((PFILE_ENTRY)FileEntry)->icbTag.flags; 171 Type = &((PFILE_ENTRY)FileEntry)->icbTag.fileType; 172 } else { 173 attr = &((PEXTENDED_FILE_ENTRY)FileEntry)->permissions; 174 Flags = &((PEXTENDED_FILE_ENTRY)FileEntry)->icbTag.flags; 175 Type = &((PEXTENDED_FILE_ENTRY)FileEntry)->icbTag.fileType; 176 } 177 FCharact = &(FileDirNdx->FileCharacteristics); 178 179 if((*FCharact & FILE_DIRECTORY) || 180 (*Type == UDF_FILE_TYPE_STREAMDIR) || 181 (*Type == UDF_FILE_TYPE_DIRECTORY)) { 182 *FCharact |= FILE_DIRECTORY; 183 if(*Type != UDF_FILE_TYPE_STREAMDIR) 184 *Type = UDF_FILE_TYPE_DIRECTORY; 185 *attr |= (PERM_O_EXEC | PERM_G_EXEC | PERM_U_EXEC); 186 NTAttr |= FILE_ATTRIBUTE_DIRECTORY; 187 NTAttr &= ~FILE_ATTRIBUTE_NORMAL; 188 } else { 189 *FCharact &= ~FILE_DIRECTORY; 190 *Type = UDF_FILE_TYPE_REGULAR; 191 *attr &= ~(PERM_O_EXEC | PERM_G_EXEC | PERM_U_EXEC); 192 } 193 194 if(NTAttr & FILE_ATTRIBUTE_SYSTEM) { 195 *Flags |= ICB_FLAG_SYSTEM; 196 } else { 197 *Flags &= ~ICB_FLAG_SYSTEM; 198 } 199 if(NTAttr & FILE_ATTRIBUTE_ARCHIVE) { 200 *Flags |= ICB_FLAG_ARCHIVE; 201 } else { 202 *Flags &= ~ICB_FLAG_ARCHIVE; 203 } 204 if(NTAttr & FILE_ATTRIBUTE_HIDDEN) { 205 *FCharact |= FILE_HIDDEN; 206 } else { 207 *FCharact &= ~FILE_HIDDEN; 208 } 209 *attr |= (PERM_O_READ | PERM_G_READ | PERM_U_READ); 210 if(!(NTAttr & FILE_ATTRIBUTE_READONLY)) { 211 *attr |= (PERM_O_WRITE | PERM_G_WRITE | PERM_U_WRITE | 212 PERM_O_DELETE | PERM_G_DELETE | PERM_U_DELETE | 213 PERM_O_CHATTR | PERM_G_CHATTR | PERM_U_CHATTR); 214 } else { 215 *attr &= ~(PERM_O_WRITE | PERM_G_WRITE | PERM_U_WRITE | 216 PERM_O_DELETE | PERM_G_DELETE | PERM_U_DELETE | 217 PERM_O_CHATTR | PERM_G_CHATTR | PERM_U_CHATTR); 218 } 219 FileDirNdx->SysAttr = NTAttr; 220 if(FileDirNdx->FileInfo) 221 FileDirNdx->FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; 222 FileDirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; 223 return; 224 } // end UDFAttributesToUDF() 225 226 #ifndef _CONSOLE 227 /* 228 This routine fills PFILE_BOTH_DIR_INFORMATION structure (NT) 229 */ 230 NTSTATUS 231 UDFFileDirInfoToNT( 232 IN PVCB Vcb, 233 IN PDIR_INDEX_ITEM FileDirNdx, 234 OUT PFILE_BOTH_DIR_INFORMATION NTFileInfo 235 ) 236 { 237 PFILE_ENTRY FileEntry; 238 UNICODE_STRING UdfName; 239 UNICODE_STRING DosName; 240 PEXTENDED_FILE_ENTRY ExFileEntry; 241 USHORT Ident; 242 BOOLEAN ReadSizes = FALSE; 243 NTSTATUS status; 244 PtrUDFNTRequiredFCB NtReqFcb; 245 246 UDFPrint(("@=%#x, FileDirNdx %x\n", &Vcb, FileDirNdx)); 247 248 ASSERT((ULONG_PTR)NTFileInfo > 0x1000); 249 RtlZeroMemory(NTFileInfo, sizeof(FILE_BOTH_DIR_INFORMATION)); 250 251 DosName.Buffer = (PWCHAR)&(NTFileInfo->ShortName); 252 DosName.MaximumLength = sizeof(NTFileInfo->ShortName); // 12*sizeof(WCHAR) 253 254 _SEH2_TRY { 255 UDFPrint((" DirInfoToNT: %*.*S\n", FileDirNdx->FName.Length/sizeof(WCHAR), FileDirNdx->FName.Length/sizeof(WCHAR), FileDirNdx->FName)); 256 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { 257 UDFPrint((" DirInfoToNT: exception when printing file name\n")); 258 } _SEH2_END; 259 260 if(FileDirNdx->FileInfo) { 261 UDFPrint((" FileInfo\n")); 262 // validate FileInfo 263 ValidateFileInfo(FileDirNdx->FileInfo); 264 if(UDFGetFileLinkCount(FileDirNdx->FileInfo) > 1) 265 FileDirNdx->FI_Flags |= UDF_FI_FLAG_LINKED; 266 FileEntry = (PFILE_ENTRY)(FileDirNdx->FileInfo->Dloc->FileEntry); 267 // read required sizes from Fcb (if any) if file is not linked 268 // otherwise we should read them from FileEntry 269 if(FileDirNdx->FileInfo->Fcb) { 270 UDFPrint((" Fcb\n")); 271 NtReqFcb = FileDirNdx->FileInfo->Fcb->NTRequiredFCB; 272 NTFileInfo->CreationTime.QuadPart = NtReqFcb->CreationTime.QuadPart; 273 NTFileInfo->LastWriteTime.QuadPart = NtReqFcb->LastWriteTime.QuadPart; 274 NTFileInfo->LastAccessTime.QuadPart = NtReqFcb->LastAccessTime.QuadPart; 275 NTFileInfo->ChangeTime.QuadPart = NtReqFcb->ChangeTime.QuadPart; 276 // NTFileInfo->AllocationSize.QuadPart = NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart; 277 NTFileInfo->AllocationSize.QuadPart = FileDirNdx->AllocationSize; 278 /* FileDirNdx->FileSize = 279 NTFileInfo->EndOfFile.QuadPart = NtReqFcb->CommonFCBHeader.FileSize.QuadPart;*/ 280 NTFileInfo->EndOfFile.QuadPart = FileDirNdx->FileSize; 281 if(FileDirNdx->FI_Flags & UDF_FI_FLAG_SYS_ATTR) { 282 UDFPrint((" SYS_ATTR\n")); 283 NTFileInfo->FileAttributes = FileDirNdx->SysAttr; 284 goto get_name_only; 285 } 286 FileDirNdx->CreationTime = NTFileInfo->CreationTime.QuadPart; 287 FileDirNdx->LastWriteTime = NTFileInfo->LastWriteTime.QuadPart; 288 FileDirNdx->LastAccessTime = NTFileInfo->LastAccessTime.QuadPart; 289 FileDirNdx->ChangeTime = NTFileInfo->ChangeTime.QuadPart; 290 goto get_attr_only; 291 } 292 ASSERT(FileEntry); 293 } else if(!(FileDirNdx->FI_Flags & UDF_FI_FLAG_SYS_ATTR) || 294 (FileDirNdx->FI_Flags & UDF_FI_FLAG_LINKED)) { 295 LONG_AD feloc; 296 297 UDFPrint((" !SYS_ATTR\n")); 298 FileEntry = (PFILE_ENTRY)MyAllocatePool__(NonPagedPool, Vcb->LBlockSize); 299 if(!FileEntry) return STATUS_INSUFFICIENT_RESOURCES; 300 301 feloc.extLength = Vcb->LBlockSize; 302 feloc.extLocation = FileDirNdx->FileEntryLoc; 303 304 if(!NT_SUCCESS(status = UDFReadFileEntry(Vcb, &feloc, FileEntry, &Ident))) { 305 UDFPrint((" !UDFReadFileEntry\n")); 306 MyFreePool__(FileEntry); 307 FileEntry = NULL; 308 goto get_name_only; 309 } 310 ReadSizes = TRUE; 311 } else { 312 UDFPrint((" FileDirNdx\n")); 313 NTFileInfo->CreationTime.QuadPart = FileDirNdx->CreationTime; 314 NTFileInfo->LastWriteTime.QuadPart = FileDirNdx->LastWriteTime; 315 NTFileInfo->LastAccessTime.QuadPart = FileDirNdx->LastAccessTime; 316 NTFileInfo->ChangeTime.QuadPart = FileDirNdx->ChangeTime; 317 NTFileInfo->FileAttributes = FileDirNdx->SysAttr; 318 NTFileInfo->AllocationSize.QuadPart = FileDirNdx->AllocationSize; 319 NTFileInfo->EndOfFile.QuadPart = FileDirNdx->FileSize; 320 NTFileInfo->EaSize = 0; 321 FileEntry = NULL; 322 goto get_name_only; 323 } 324 325 if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) 326 goto get_name_only; 327 328 UDFPrint((" direct\n")); 329 if(FileEntry->descTag.tagIdent == TID_FILE_ENTRY) { 330 UDFPrint((" TID_FILE_ENTRY\n")); 331 if(ReadSizes) { 332 UDFPrint((" ReadSizes\n")); 333 // Times 334 FileDirNdx->CreationTime = NTFileInfo->CreationTime.QuadPart = 335 FileDirNdx->LastWriteTime = NTFileInfo->LastWriteTime.QuadPart = UDFTimeToNT(&(FileEntry->modificationTime)); 336 FileDirNdx->LastAccessTime = NTFileInfo->LastAccessTime.QuadPart = UDFTimeToNT(&(FileEntry->accessTime)); 337 FileDirNdx->ChangeTime = NTFileInfo->ChangeTime.QuadPart = UDFTimeToNT(&(FileEntry->attrTime)); 338 // FileSize 339 FileDirNdx->FileSize = 340 NTFileInfo->EndOfFile.QuadPart = 341 FileEntry->informationLength; 342 UDFPrint((" informationLength=%I64x, lengthAllocDescs=%I64x\n", 343 FileEntry->informationLength, 344 FileEntry->lengthAllocDescs 345 )); 346 // AllocSize 347 FileDirNdx->AllocationSize = 348 NTFileInfo->AllocationSize.QuadPart = 349 (FileEntry->informationLength + Vcb->LBlockSize - 1) & ~((LONGLONG)(Vcb->LBlockSize) - 1); 350 } 351 // NTFileInfo->EaSize = 0;//FileEntry->lengthExtendedAttr; 352 } else if(FileEntry->descTag.tagIdent == TID_EXTENDED_FILE_ENTRY) { 353 ExFileEntry = (PEXTENDED_FILE_ENTRY)FileEntry; 354 UDFPrint((" PEXTENDED_FILE_ENTRY\n")); 355 if(ReadSizes) { 356 UDFPrint((" ReadSizes\n")); 357 // Times 358 FileDirNdx->CreationTime = NTFileInfo->CreationTime.QuadPart = UDFTimeToNT(&(ExFileEntry->createTime)); 359 FileDirNdx->LastWriteTime = NTFileInfo->LastWriteTime.QuadPart = UDFTimeToNT(&(ExFileEntry->modificationTime)); 360 FileDirNdx->LastAccessTime = NTFileInfo->LastAccessTime.QuadPart = UDFTimeToNT(&(ExFileEntry->accessTime)); 361 FileDirNdx->ChangeTime = NTFileInfo->ChangeTime.QuadPart = UDFTimeToNT(&(ExFileEntry->attrTime)); 362 // FileSize 363 FileDirNdx->FileSize = 364 NTFileInfo->EndOfFile.QuadPart = 365 ExFileEntry->informationLength; 366 UDFPrint((" informationLength=%I64x, lengthAllocDescs=%I64x\n", 367 FileEntry->informationLength, 368 FileEntry->lengthAllocDescs 369 )); 370 // AllocSize 371 FileDirNdx->AllocationSize = 372 NTFileInfo->AllocationSize.QuadPart = 373 (ExFileEntry->informationLength + Vcb->LBlockSize - 1) & ~((LONGLONG)(Vcb->LBlockSize) - 1); 374 } 375 // NTFileInfo->EaSize = 0;//ExFileEntry->lengthExtendedAttr; 376 } else { 377 UDFPrint((" ???\n")); 378 goto get_name_only; 379 } 380 381 get_attr_only: 382 383 UDFPrint((" get_attr")); 384 // do some substitutions 385 if(!FileDirNdx->CreationTime) { 386 FileDirNdx->CreationTime = NTFileInfo->CreationTime.QuadPart = Vcb->VolCreationTime; 387 } 388 if(!FileDirNdx->LastAccessTime) { 389 FileDirNdx->LastAccessTime = NTFileInfo->LastAccessTime.QuadPart = FileDirNdx->CreationTime; 390 } 391 if(!FileDirNdx->LastWriteTime) { 392 FileDirNdx->LastWriteTime = NTFileInfo->LastWriteTime.QuadPart = FileDirNdx->CreationTime; 393 } 394 if(!FileDirNdx->ChangeTime) { 395 FileDirNdx->ChangeTime = NTFileInfo->ChangeTime.QuadPart = FileDirNdx->CreationTime; 396 } 397 398 FileDirNdx->SysAttr = 399 NTFileInfo->FileAttributes = UDFAttributesToNT(FileDirNdx, (tag*)FileEntry); 400 FileDirNdx->FI_Flags |= UDF_FI_FLAG_SYS_ATTR; 401 402 get_name_only: 403 // get filename in standard Unicode format 404 UdfName = FileDirNdx->FName; 405 NTFileInfo->FileNameLength = UdfName.Length; 406 RtlCopyMemory((PCHAR)&(NTFileInfo->FileName), (PCHAR)(UdfName.Buffer), UdfName.MaximumLength); 407 if(!(FileDirNdx->FI_Flags & UDF_FI_FLAG_DOS)) { 408 UDFPrint((" !UDF_FI_FLAG_DOS")); 409 UDFDOSName(Vcb, &DosName, &UdfName, 410 (FileDirNdx->FI_Flags & UDF_FI_FLAG_KEEP_NAME) ? TRUE : FALSE); 411 NTFileInfo->ShortNameLength = (UCHAR)DosName.Length; 412 } 413 // report zero EOF & AllocSize for Dirs 414 if(FileDirNdx->FileCharacteristics & FILE_DIRECTORY) { 415 UDFPrint((" FILE_DIRECTORY")); 416 NTFileInfo->AllocationSize.QuadPart = 417 NTFileInfo->EndOfFile.QuadPart = 0; 418 } 419 UDFPrint((" AllocationSize=%I64x, NTFileInfo->EndOfFile=%I64x", NTFileInfo->AllocationSize.QuadPart, NTFileInfo->EndOfFile.QuadPart)); 420 // free tmp buffer (if any) 421 UDFPrint(("\n")); 422 if(FileEntry && !FileDirNdx->FileInfo) 423 MyFreePool__(FileEntry); 424 return STATUS_SUCCESS; 425 } // end UDFFileDirInfoToNT() 426 427 #endif //_CONSOLE 428 429 #ifndef UDF_READ_ONLY_BUILD 430 /* 431 This routine changes xxxTime field(s) in (Ext)FileEntry 432 */ 433 VOID 434 UDFSetFileXTime( 435 IN PUDF_FILE_INFO FileInfo, 436 IN LONGLONG* CrtTime, 437 IN LONGLONG* AccTime, 438 IN LONGLONG* AttrTime, 439 IN LONGLONG* ChgTime 440 ) 441 { 442 USHORT Ident; 443 PDIR_INDEX_ITEM DirNdx; 444 445 ValidateFileInfo(FileInfo); 446 447 FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; 448 DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index); 449 Ident = FileInfo->Dloc->FileEntry->tagIdent; 450 451 if(Ident == TID_FILE_ENTRY) { 452 PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry); 453 454 if(AccTime) { 455 if(DirNdx && *AccTime) DirNdx->LastAccessTime = *AccTime; 456 UDFTimeToUDF(*AccTime, &(fe->accessTime)); 457 } 458 if(AttrTime) { 459 if(DirNdx && *AttrTime) DirNdx->ChangeTime = *AttrTime; 460 UDFTimeToUDF(*AttrTime, &(fe->attrTime)); 461 } 462 if(ChgTime) { 463 if(DirNdx && *ChgTime) DirNdx->CreationTime = 464 DirNdx->LastWriteTime = *ChgTime; 465 UDFTimeToUDF(*ChgTime, &(fe->modificationTime)); 466 } else 467 if(CrtTime) { 468 if(DirNdx && *CrtTime) DirNdx->CreationTime = 469 DirNdx->LastWriteTime = *CrtTime; 470 UDFTimeToUDF(*CrtTime, &(fe->modificationTime)); 471 } 472 473 } else if(Ident == TID_EXTENDED_FILE_ENTRY) { 474 PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry); 475 476 if(AccTime) { 477 if(DirNdx && *AccTime) DirNdx->LastAccessTime = *AccTime; 478 UDFTimeToUDF(*AccTime, &(fe->accessTime)); 479 } 480 if(AttrTime) { 481 if(DirNdx && *AttrTime) DirNdx->ChangeTime = *AttrTime; 482 UDFTimeToUDF(*AttrTime, &(fe->attrTime)); 483 } 484 if(ChgTime) { 485 if(DirNdx && *ChgTime) DirNdx->LastWriteTime = *ChgTime; 486 UDFTimeToUDF(*ChgTime, &(fe->modificationTime)); 487 } 488 if(CrtTime) { 489 if(DirNdx && *CrtTime) DirNdx->CreationTime = *CrtTime; 490 UDFTimeToUDF(*CrtTime, &(fe->createTime)); 491 } 492 493 } 494 } // end UDFSetFileXTime() 495 #endif //UDF_READ_ONLY_BUILD 496 497 /* 498 This routine gets xxxTime field(s) in (Ext)FileEntry 499 */ 500 VOID 501 UDFGetFileXTime( 502 IN PUDF_FILE_INFO FileInfo, 503 OUT LONGLONG* CrtTime, 504 OUT LONGLONG* AccTime, 505 OUT LONGLONG* AttrTime, 506 OUT LONGLONG* ChgTime 507 ) 508 { 509 USHORT Ident; 510 511 ValidateFileInfo(FileInfo); 512 513 Ident = FileInfo->Dloc->FileEntry->tagIdent; 514 515 if(Ident == TID_FILE_ENTRY) { 516 PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry); 517 518 if(AccTime) *AccTime = UDFTimeToNT(&(fe->accessTime)); 519 if(AttrTime) *AttrTime = UDFTimeToNT(&(fe->attrTime)); 520 if(ChgTime) *ChgTime = UDFTimeToNT(&(fe->modificationTime)); 521 if(CrtTime) { 522 (*CrtTime) = *ChgTime; 523 } 524 525 } else if(Ident == TID_EXTENDED_FILE_ENTRY) { 526 PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry); 527 528 if(AccTime) *AccTime = UDFTimeToNT(&(fe->accessTime)); 529 if(AttrTime) *AttrTime = UDFTimeToNT(&(fe->attrTime)); 530 if(ChgTime) *ChgTime = UDFTimeToNT(&(fe->modificationTime)); 531 if(CrtTime) *CrtTime = UDFTimeToNT(&(fe->createTime)); 532 533 } 534 if(CrtTime) { 535 if(!(*CrtTime)) 536 KeQuerySystemTime((PLARGE_INTEGER)CrtTime); 537 if(AccTime && !(*AccTime)) (*AccTime) = *CrtTime; 538 if(AttrTime && !(*AttrTime)) (*AttrTime) = *CrtTime; 539 if(AccTime && !(*AccTime)) (*AccTime) = *CrtTime; 540 } 541 } // end UDFGetFileXTime() 542 543 VOID 544 UDFNormalizeFileName( 545 IN PUNICODE_STRING FName, 546 IN USHORT valueCRC 547 ) 548 { 549 PWCHAR buffer; 550 USHORT len; 551 552 len = FName->Length/sizeof(WCHAR); 553 buffer = FName->Buffer; 554 555 // check for '', '.' & '..' 556 if(!len) return; 557 if(!buffer[len-1]) { 558 FName->Length-=sizeof(WCHAR); 559 len--; 560 } 561 if(!len) return; 562 if(buffer[0] == UNICODE_PERIOD) { 563 if(len == 1) return; 564 if((buffer[1] == UNICODE_PERIOD) && (len == 2)) return; 565 } 566 567 // check for trailing '.' 568 for(len--;len;len--) { 569 if( ((buffer[len] == UNICODE_PERIOD) || (buffer[len] == UNICODE_SPACE)) ) { 570 FName->Length-=sizeof(WCHAR); 571 buffer[len] = 0; 572 } else 573 break; 574 } 575 } // end UDFNormalizeFileName() 576 577 #ifndef _CONSOLE 578 579 void 580 __fastcall 581 UDFDOSNameOsNative( 582 IN OUT PUNICODE_STRING DosName, 583 IN PUNICODE_STRING UdfName, 584 IN BOOLEAN KeepIntact 585 ) 586 { 587 PWCHAR dosName = DosName->Buffer; 588 PWCHAR udfName = UdfName->Buffer; 589 uint32 udfLen = UdfName->Length / sizeof(WCHAR); 590 GENERATE_NAME_CONTEXT Ctx; 591 592 if(KeepIntact && 593 (udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) { 594 if((udfLen != 2) || (udfName[1] == UNICODE_PERIOD)) { 595 RtlCopyMemory(dosName, udfName, UdfName->Length); 596 DosName->Length = UdfName->Length; 597 return; 598 } 599 } 600 RtlZeroMemory(&Ctx, sizeof(GENERATE_NAME_CONTEXT)); 601 RtlGenerate8dot3Name(UdfName, FALSE, &Ctx, DosName); 602 603 } // UDFDOSNameOsNative() 604 605 #endif //_CONSOLE 606 607 /*VOID 608 UDFNormalizeFileName( 609 IN PUNICODE_STRING FName, 610 IN USHORT valueCRC 611 ) 612 { 613 WCHAR _newName[UDF_NAME_LEN+5]; 614 PWCHAR newName = (PWCHAR)(&_newName); 615 PWCHAR udfName = FName->Buffer; 616 LONG udfLen = FName->Length >> 1; 617 618 LONG index, newIndex = 0, extIndex = 0, newExtIndex = 0, trailIndex = 0; 619 BOOLEAN needsCRC = FALSE, hasExt = FALSE; 620 WCHAR ext[UDF_EXT_SIZE], current; 621 622 // handle CurrentDir ('.') and ParentDir ('..') cases 623 if((udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) { 624 if((udfLen != 2) || (udfName[1] == UNICODE_PERIOD)) 625 return; 626 } 627 628 for (index = 0 ; index < udfLen ; index++) { 629 current = udfName[index]; 630 631 // Look for illegal or unprintable characters. 632 if (UDFIsIllegalChar(current) || !UnicodeIsPrint(current)) { 633 needsCRC = TRUE; 634 current = ILLEGAL_CHAR_MARK; 635 // Skip Illegal characters(even spaces), 636 // but not periods. 637 while(index+1 < udfLen && 638 (UDFIsIllegalChar(udfName[index+1]) || 639 !UnicodeIsPrint(udfName[index+1])) && 640 udfName[index+1] != UNICODE_PERIOD) 641 index++; 642 } 643 644 // Record position of extension, if one is found. 645 if ((current == UNICODE_PERIOD) && ((udfLen - index -1) <= UDF_EXT_SIZE)) { 646 if (udfLen == index + 1) { 647 // A trailing period is NOT an extension. 648 hasExt = FALSE; 649 } else { 650 hasExt = TRUE; 651 extIndex = index; 652 newExtIndex = newIndex; 653 } 654 } else if((current != UNICODE_PERIOD) && (current != UNICODE_SPACE)) { 655 trailIndex = index; 656 } 657 658 // if (newIndex < MAXLEN) // tshi is always TRUE for WINNT 659 newName[newIndex] = current; 660 newIndex++; 661 662 // For OS2, 95 & NT, truncate any trailing periods and\or spaces. 663 if (trailIndex != (newIndex - 1)) { 664 newIndex = trailIndex + 1; 665 needsCRC = TRUE; 666 hasExt = FALSE; // Trailing period does not make an extension. 667 } 668 } 669 670 if (needsCRC) { 671 int localExtIndex = 0; 672 if (hasExt) { 673 int maxFilenameLen; 674 // Translate extension, and store it in ext. 675 for(index = 0; index<UDF_EXT_SIZE && extIndex + index +1 < udfLen; index++ ) { 676 current = udfName[extIndex + index + 1]; 677 if (UDFIsIllegalChar(current) //|| !UnicodeIsPrint(current)) { 678 needsCRC = TRUE; 679 // Replace Illegal and non-displayable chars 680 // with underscore. 681 current = ILLEGAL_CHAR_MARK; 682 // Skip any other illegal or non-displayable 683 // characters. 684 while(index + 1 < UDF_EXT_SIZE && 685 (UDFIsIllegalChar(udfName[extIndex + index + 2]) || 686 !UnicodeIsPrint(udfName[extIndex + index + 2])) ) 687 index++; 688 } 689 ext[localExtIndex++] = current; 690 } 691 // Truncate filename to leave room for extension and CRC. 692 maxFilenameLen = ((UDF_NAME_LEN - 4) - localExtIndex - 1); 693 if (newIndex > maxFilenameLen) { 694 newIndex = maxFilenameLen; 695 } else { 696 newIndex = newExtIndex; 697 } 698 } else if (newIndex > UDF_NAME_LEN - 5) { 699 //If no extension, make sure to leave room for CRC. 700 newIndex = UDF_NAME_LEN - 5; 701 } 702 newName[newIndex++] = UNICODE_CRC_MARK; // Add mark for CRC. 703 //Calculate CRC from original filename from FileIdentifier. 704 // valueCRC = UDFUnicodeCksum(fidName, fidNameLen); 705 // / Convert 16-bits of CRC to hex characters. 706 newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12]; 707 newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8]; 708 newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4]; 709 newName[newIndex++] = hexChar[(valueCRC & 0x000f)]; 710 // Place a translated extension at end, if found. 711 if (hasExt) { 712 newName[newIndex++] = UNICODE_PERIOD; 713 for (index = 0;index < localExtIndex ;index++ ) { 714 newName[newIndex++] = ext[index]; 715 } 716 } 717 } 718 719 if(FName->Length == (USHORT)newIndex*sizeof(WCHAR)) { 720 RtlCopyMemory(FName->Buffer, newName, newIndex*sizeof(WCHAR)); 721 return; 722 } 723 MyFreePool__(FName->Buffer); 724 FName->Buffer = (PWCHAR)MyAllocatePool__(UDF_FILENAME_MT, (newIndex+1)*sizeof(WCHAR)); 725 if(FName->Buffer) { 726 FName->Buffer[newIndex] = 0; 727 RtlCopyMemory(FName->Buffer, newName, newIndex*sizeof(WCHAR)); 728 } 729 FName->Length = (USHORT)newIndex*sizeof(WCHAR); 730 FName->MaximumLength = (USHORT)(newIndex+1)*sizeof(WCHAR); 731 }*/ 732 733 /*PUDF_FILE_INFO 734 UDFAllocFileInfo( 735 return ExAllocateFromZone(&(UDFGlobalData.FileInfoZoneHeader)); 736 )*/ 737 738 #define STRING_BUFFER_ALIGNMENT (32) 739 #define STRING_BUFFER_ALIGN(sz) (((sz)+STRING_BUFFER_ALIGNMENT)&(~((ULONG)(STRING_BUFFER_ALIGNMENT-1)))) 740 741 NTSTATUS 742 MyAppendUnicodeStringToString_( 743 IN PUNICODE_STRING Str1, 744 IN PUNICODE_STRING Str2 745 #ifdef UDF_TRACK_UNICODE_STR 746 ,IN PCHAR Tag 747 #endif 748 ) 749 { 750 PWCHAR tmp; 751 USHORT i; 752 753 #ifdef UDF_TRACK_UNICODE_STR 754 #define UDF_UNC_STR_TAG Tag 755 #else 756 #define UDF_UNC_STR_TAG "AppUStr" 757 #endif 758 759 tmp = Str1->Buffer; 760 i = Str1->Length + Str2->Length + sizeof(WCHAR); 761 ASSERT(Str1->MaximumLength); 762 if(i > Str1->MaximumLength) { 763 if(!MyReallocPool__((PCHAR)tmp, Str1->MaximumLength, 764 (PCHAR*)&tmp, STRING_BUFFER_ALIGN(i)*2) ) { 765 return STATUS_INSUFFICIENT_RESOURCES; 766 } 767 Str1->MaximumLength = i*2; 768 Str1->Buffer = tmp; 769 } 770 RtlCopyMemory(((PCHAR)tmp)+Str1->Length, Str2->Buffer, Str2->Length); 771 772 /* tmp = (PWCHAR)MyAllocatePoolTag__(NonPagedPool, i = Str1->Length + Str2->Length + sizeof(WCHAR), UDF_UNC_STR_TAG); 773 if(!tmp) 774 return STATUS_INSUFFICIENT_RESOURCES; 775 RtlCopyMemory(tmp, Str1->Buffer, Str1->Length); 776 RtlCopyMemory(((PCHAR)tmp)+Str1->Length, Str2->Buffer, Str2->Length);*/ 777 tmp[(i / sizeof(WCHAR)) - 1] = 0; 778 Str1->Length = i - sizeof(WCHAR); 779 //MyFreePool__(Str1->Buffer); 780 #ifdef UDF_DBG 781 if(Str1->Buffer && (Str1->Length >= 2*sizeof(WCHAR))) { 782 ASSERT((Str1->Buffer[0] != L'\\') || (Str1->Buffer[1] != L'\\')); 783 } 784 #endif // UDF_DBG 785 return STATUS_SUCCESS; 786 787 #undef UDF_UNC_STR_TAG 788 789 } // end MyAppendUnicodeStringToString() 790 791 NTSTATUS 792 MyAppendUnicodeToString_( 793 IN PUNICODE_STRING Str1, 794 IN PCWSTR Str2 795 #ifdef UDF_TRACK_UNICODE_STR 796 ,IN PCHAR Tag 797 #endif 798 ) 799 { 800 PWCHAR tmp; 801 USHORT i; 802 803 #ifdef UDF_TRACK_UNICODE_STR 804 #define UDF_UNC_STR_TAG Tag 805 #else 806 #define UDF_UNC_STR_TAG "AppStr" 807 #endif 808 809 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__) 810 811 __asm push ebx 812 __asm push esi 813 814 __asm xor ebx,ebx 815 __asm mov esi,Str2 816 Scan_1: 817 __asm cmp [word ptr esi+ebx],0 818 __asm je EO_Scan 819 __asm add ebx,2 820 __asm jmp Scan_1 821 EO_Scan: 822 __asm mov i,bx 823 824 __asm pop esi 825 __asm pop ebx 826 827 #else // NO X86 optimization, use generic C/C++ 828 829 i=0; 830 while(Str2[i]) { 831 i++; 832 } 833 i *= sizeof(WCHAR); 834 835 #endif // _X86_ 836 837 tmp = Str1->Buffer; 838 ASSERT(Str1->MaximumLength); 839 if((Str1->Length+i+sizeof(WCHAR)) > Str1->MaximumLength) { 840 if(!MyReallocPool__((PCHAR)tmp, Str1->MaximumLength, 841 (PCHAR*)&tmp, STRING_BUFFER_ALIGN(i + Str1->Length + sizeof(WCHAR))*2 ) ) { 842 return STATUS_INSUFFICIENT_RESOURCES; 843 } 844 Str1->MaximumLength = STRING_BUFFER_ALIGN(i + sizeof(WCHAR))*2; 845 Str1->Buffer = tmp; 846 } 847 RtlCopyMemory(((PCHAR)tmp)+Str1->Length, Str2, i); 848 i+=Str1->Length; 849 tmp[(i / sizeof(WCHAR))] = 0; 850 Str1->Length = i; 851 #ifdef UDF_DBG 852 /* if(Str1->Buffer && (Str1->Length >= 2*sizeof(WCHAR))) { 853 ASSERT((Str1->Buffer[0] != L'\\') || (Str1->Buffer[1] != L'\\')); 854 }*/ 855 #endif // UDF_DBG 856 return STATUS_SUCCESS; 857 858 #undef UDF_UNC_STR_TAG 859 860 } // end MyAppendUnicodeToString_() 861 862 NTSTATUS 863 MyInitUnicodeString( 864 IN PUNICODE_STRING Str1, 865 IN PCWSTR Str2 866 ) 867 { 868 869 USHORT i; 870 871 #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__) 872 873 __asm push ebx 874 __asm push esi 875 876 __asm xor ebx,ebx 877 __asm mov esi,Str2 878 Scan_1: 879 __asm cmp [word ptr esi+ebx],0 880 __asm je EO_Scan 881 __asm add ebx,2 882 __asm jmp Scan_1 883 EO_Scan: 884 __asm mov i,bx 885 886 __asm pop esi 887 __asm pop ebx 888 889 #else // NO X86 optimization, use generic C/C++ 890 891 i=0; 892 while(Str2[i]) { 893 i++; 894 } 895 i *= sizeof(WCHAR); 896 897 #endif // _X86_ 898 899 Str1->MaximumLength = STRING_BUFFER_ALIGN((Str1->Length = i) + sizeof(WCHAR)); 900 Str1->Buffer = (PWCHAR)MyAllocatePool__(NonPagedPool, Str1->MaximumLength); 901 if(!Str1->Buffer) 902 return STATUS_INSUFFICIENT_RESOURCES; 903 RtlCopyMemory(Str1->Buffer, Str2, i); 904 Str1->Buffer[i/sizeof(WCHAR)] = 0; 905 return STATUS_SUCCESS; 906 907 } // end MyInitUnicodeString() 908 909 NTSTATUS 910 MyCloneUnicodeString( 911 IN PUNICODE_STRING Str1, 912 IN PUNICODE_STRING Str2 913 ) 914 { 915 Str1->MaximumLength = STRING_BUFFER_ALIGN((Str1->Length = Str2->Length) + sizeof(WCHAR)); 916 Str1->Buffer = (PWCHAR)MyAllocatePool__(NonPagedPool, Str1->MaximumLength); 917 if(!Str1->Buffer) 918 return STATUS_INSUFFICIENT_RESOURCES; 919 ASSERT(Str2->Buffer); 920 RtlCopyMemory(Str1->Buffer, Str2->Buffer, Str2->Length); 921 Str1->Buffer[Str1->Length/sizeof(WCHAR)] = 0; 922 return STATUS_SUCCESS; 923 924 } // end MyCloneUnicodeString() 925 926 /* 927 This routine checks do we needn't read something from disk to 928 obtain Attributes & so on 929 */ 930 BOOLEAN 931 UDFIsDirInfoCached( 932 IN PVCB Vcb, 933 IN PUDF_FILE_INFO DirInfo 934 ) 935 { 936 PDIR_INDEX_HDR hDirNdx = DirInfo->Dloc->DirIndex; 937 PDIR_INDEX_ITEM DirNdx; 938 for(uint_di i=2; (DirNdx = UDFDirIndex(hDirNdx,i)); i++) { 939 if(!(DirNdx->FI_Flags & UDF_FI_FLAG_SYS_ATTR) || 940 (DirNdx->FI_Flags & UDF_FI_FLAG_LINKED)) return FALSE; 941 } 942 return TRUE; 943 } // end UDFIsDirInfoCached() 944 945 #ifndef UDF_READ_ONLY_BUILD 946 NTSTATUS 947 UDFDoesOSAllowFileToBeTargetForRename__( 948 IN PUDF_FILE_INFO FileInfo 949 ) 950 { 951 #ifndef _CONSOLE 952 NTSTATUS RC; 953 #endif //_CONSOLE 954 955 if(UDFIsADirectory(FileInfo)) 956 return STATUS_ACCESS_DENIED; 957 if(!FileInfo->ParentFile) 958 return STATUS_ACCESS_DENIED; 959 960 if(UDFAttributesToNT(UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index), 961 FileInfo->Dloc->FileEntry) & FILE_ATTRIBUTE_READONLY) 962 return STATUS_ACCESS_DENIED; 963 964 if(!FileInfo->Fcb) 965 return STATUS_SUCCESS; 966 #ifndef _CONSOLE 967 RC = UDFCheckAccessRights(NULL, NULL, FileInfo->Fcb, NULL, DELETE, 0); 968 if(!NT_SUCCESS(RC)) 969 return RC; 970 #endif //_CONSOLE 971 if(!FileInfo->Fcb) 972 return STATUS_SUCCESS; 973 // RC = UDFMarkStreamsForDeletion(FileInfo->Fcb->Vcb, FileInfo->Fcb, TRUE); // Delete 974 /* RC = UDFSetDispositionInformation(FileInfo->Fcb, NULL, 975 FileInfo->Fcb->Vcb, NULL, TRUE); 976 if(NT_SUCCESS(RC)) { 977 FileInfo->Fcb->FCBFlags |= UDF_FCB_DELETED; 978 if(UDFGetFileLinkCount(FileInfo) <= 1) { 979 FileInfo->Fcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_DELETED; 980 } 981 } 982 return RC;*/ 983 return STATUS_ACCESS_DENIED; 984 985 } // end UDFDoesOSAllowFileToBeTargetForRename__() 986 987 NTSTATUS 988 UDFDoesOSAllowFileToBeUnlinked__( 989 IN PUDF_FILE_INFO FileInfo 990 ) 991 { 992 PDIR_INDEX_HDR hCurDirNdx; 993 PDIR_INDEX_ITEM CurDirNdx; 994 uint_di i; 995 // IO_STATUS_BLOCK IoStatus; 996 997 ASSERT(FileInfo->Dloc); 998 999 if(!FileInfo->ParentFile) 1000 return STATUS_CANNOT_DELETE; 1001 if(FileInfo->Dloc->SDirInfo) 1002 return STATUS_CANNOT_DELETE; 1003 if(!UDFIsADirectory(FileInfo)) 1004 return STATUS_SUCCESS; 1005 1006 // UDFFlushAFile(FileInfo->Fcb, NULL, &IoStatus, 0); 1007 hCurDirNdx = FileInfo->Dloc->DirIndex; 1008 // check if we can delete all files 1009 for(i=2; (CurDirNdx = UDFDirIndex(hCurDirNdx,i)); i++) { 1010 // try to open Stream 1011 if(CurDirNdx->FileInfo) 1012 return STATUS_CANNOT_DELETE; 1013 } 1014 // return UDFCheckAccessRights(NULL, NULL, FileInfo->Fcb, NULL, DELETE, 0); 1015 return STATUS_SUCCESS; 1016 } // end UDFDoesOSAllowFileToBeUnlinked__() 1017 1018 NTSTATUS 1019 UDFDoesOSAllowFilePretendDeleted__( 1020 IN PUDF_FILE_INFO FileInfo 1021 ) 1022 { 1023 PDIR_INDEX_HDR hDirNdx = UDFGetDirIndexByFileInfo(FileInfo); 1024 if(!hDirNdx) return STATUS_CANNOT_DELETE; 1025 PDIR_INDEX_ITEM DirNdx = UDFDirIndex(hDirNdx, FileInfo->Index); 1026 if(!DirNdx) return STATUS_CANNOT_DELETE; 1027 // we can't hide file that is not marked as deleted 1028 if(!(DirNdx->FileCharacteristics & FILE_DELETED)) { 1029 BrutePoint(); 1030 1031 #ifndef _CONSOLE 1032 if(!(FileInfo->Fcb->FCBFlags & (UDF_FCB_DELETE_ON_CLOSE | 1033 UDF_FCB_DELETED) )) 1034 #endif //_CONSOLE 1035 1036 return STATUS_CANNOT_DELETE; 1037 } 1038 return STATUS_SUCCESS; 1039 } 1040 #endif //UDF_READ_ONLY_BUILD 1041 1042