//////////////////////////////////////////////////////////////////// // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine // All rights reserved // This file was released under the GPLv2 on June 2015. //////////////////////////////////////////////////////////////////// /************************************************************************* * * File: Sys_Spec.cpp * * Module: UDF File System Driver * (both User and Kernel mode execution) * * Description: * Contains system-secific code * *************************************************************************/ /* This routine converts UDF timestamp to NT time */ LONGLONG UDFTimeToNT( IN PUDF_TIME_STAMP UdfTime ) { LONGLONG NtTime; TIME_FIELDS TimeFields; TimeFields.Milliseconds = (USHORT)(UdfTime->centiseconds * 10 + UdfTime->hundredsOfMicroseconds / 100); TimeFields.Second = (USHORT)(UdfTime->second); TimeFields.Minute = (USHORT)(UdfTime->minute); TimeFields.Hour = (USHORT)(UdfTime->hour); TimeFields.Day = (USHORT)(UdfTime->day); TimeFields.Month = (USHORT)(UdfTime->month); TimeFields.Year = (USHORT)((UdfTime->year < 1601) ? 1601 : UdfTime->year); if (!RtlTimeFieldsToTime(&TimeFields, (PLARGE_INTEGER)&NtTime)) { NtTime = 0; } else { ExLocalTimeToSystemTime( (PLARGE_INTEGER)&NtTime, (PLARGE_INTEGER)&NtTime ); } return NtTime; } // end UDFTimeToNT() /* This routine converts NT time to UDF timestamp */ VOID UDFTimeToUDF( IN LONGLONG NtTime, OUT PUDF_TIME_STAMP UdfTime ) { if(!NtTime) return; LONGLONG LocalTime; TIME_FIELDS TimeFields; ExSystemTimeToLocalTime( (PLARGE_INTEGER)&NtTime, (PLARGE_INTEGER)&LocalTime ); RtlTimeToTimeFields( (PLARGE_INTEGER)&LocalTime, &TimeFields ); LocalTime /= 10; // microseconds UdfTime->microseconds = (UCHAR)(NtTime % 100); LocalTime /= 100; // hundreds of microseconds UdfTime->hundredsOfMicroseconds = (UCHAR)(NtTime % 100); LocalTime /= 100; // centiseconds UdfTime->centiseconds = (UCHAR)(TimeFields.Milliseconds / 10); UdfTime->second = (UCHAR)(TimeFields.Second); UdfTime->minute = (UCHAR)(TimeFields.Minute); UdfTime->hour = (UCHAR)(TimeFields.Hour); UdfTime->day = (UCHAR)(TimeFields.Day); UdfTime->month = (UCHAR)(TimeFields.Month); UdfTime->year = (USHORT)(TimeFields.Year); UdfTime->typeAndTimezone = (TIMESTAMP_TYPE_LOCAL << 14); } // end UDFTimeToUDF() /* */ ULONG UDFAttributesToNT( IN PDIR_INDEX_ITEM FileDirNdx, IN tag* FileEntry ) { ASSERT(FileDirNdx); if( (FileDirNdx->FI_Flags & UDF_FI_FLAG_SYS_ATTR) && !(FileDirNdx->FI_Flags & UDF_FI_FLAG_LINKED)) return FileDirNdx->SysAttr; ULONG NTAttr = 0; ULONG attr = 0; //permissions USHORT Flags = 0; USHORT Type = 0; UCHAR FCharact = 0; if(!FileEntry) { if(!FileDirNdx->FileInfo) return 0; ValidateFileInfo(FileDirNdx->FileInfo); FileEntry = FileDirNdx->FileInfo->Dloc->FileEntry; } if(FileEntry->tagIdent == TID_FILE_ENTRY) { attr = ((PFILE_ENTRY)FileEntry)->permissions; Flags = ((PFILE_ENTRY)FileEntry)->icbTag.flags; Type = ((PFILE_ENTRY)FileEntry)->icbTag.fileType; if(((PFILE_ENTRY)FileEntry)->fileLinkCount > 1) FileDirNdx->FI_Flags |= UDF_FI_FLAG_LINKED; } else { attr = ((PEXTENDED_FILE_ENTRY)FileEntry)->permissions; Flags = ((PEXTENDED_FILE_ENTRY)FileEntry)->icbTag.flags; Type = ((PEXTENDED_FILE_ENTRY)FileEntry)->icbTag.fileType; if(((PEXTENDED_FILE_ENTRY)FileEntry)->fileLinkCount > 1) FileDirNdx->FI_Flags |= UDF_FI_FLAG_LINKED; } FCharact = FileDirNdx->FileCharacteristics; if(Flags & ICB_FLAG_SYSTEM) NTAttr |= FILE_ATTRIBUTE_SYSTEM; if(Flags & ICB_FLAG_ARCHIVE) NTAttr |= FILE_ATTRIBUTE_ARCHIVE; if((Type == UDF_FILE_TYPE_DIRECTORY) || (Type == UDF_FILE_TYPE_STREAMDIR) || (FCharact & FILE_DIRECTORY)) { NTAttr |= FILE_ATTRIBUTE_DIRECTORY; #ifdef UDF_DBG } else { //NTAttr |= FILE_ATTRIBUTE_NORMAL; #endif } if(FCharact & FILE_HIDDEN) NTAttr |= FILE_ATTRIBUTE_HIDDEN; if( !(attr & PERM_O_WRITE) && !(attr & PERM_G_WRITE) && !(attr & PERM_U_WRITE) && !(attr & PERM_O_DELETE) && !(attr & PERM_G_DELETE) && !(attr & PERM_U_DELETE) ) { NTAttr |= FILE_ATTRIBUTE_READONLY; } FileDirNdx->SysAttr = NTAttr; return NTAttr; } // end UDFAttributesToNT() /* */ VOID UDFAttributesToUDF( IN PDIR_INDEX_ITEM FileDirNdx, IN tag* FileEntry, IN ULONG NTAttr ) { PULONG attr; //permissions PUSHORT Flags; PUCHAR Type; PUCHAR FCharact; NTAttr &= UDF_VALID_FILE_ATTRIBUTES; if(!FileEntry) { ASSERT(FileDirNdx); if(!FileDirNdx->FileInfo) return; ValidateFileInfo(FileDirNdx->FileInfo); FileEntry = FileDirNdx->FileInfo->Dloc->FileEntry; FileDirNdx->FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; } if(FileEntry->tagIdent == TID_FILE_ENTRY) { attr = &((PFILE_ENTRY)FileEntry)->permissions; Flags = &((PFILE_ENTRY)FileEntry)->icbTag.flags; Type = &((PFILE_ENTRY)FileEntry)->icbTag.fileType; } else { attr = &((PEXTENDED_FILE_ENTRY)FileEntry)->permissions; Flags = &((PEXTENDED_FILE_ENTRY)FileEntry)->icbTag.flags; Type = &((PEXTENDED_FILE_ENTRY)FileEntry)->icbTag.fileType; } FCharact = &(FileDirNdx->FileCharacteristics); if((*FCharact & FILE_DIRECTORY) || (*Type == UDF_FILE_TYPE_STREAMDIR) || (*Type == UDF_FILE_TYPE_DIRECTORY)) { *FCharact |= FILE_DIRECTORY; if(*Type != UDF_FILE_TYPE_STREAMDIR) *Type = UDF_FILE_TYPE_DIRECTORY; *attr |= (PERM_O_EXEC | PERM_G_EXEC | PERM_U_EXEC); NTAttr |= FILE_ATTRIBUTE_DIRECTORY; NTAttr &= ~FILE_ATTRIBUTE_NORMAL; } else { *FCharact &= ~FILE_DIRECTORY; *Type = UDF_FILE_TYPE_REGULAR; *attr &= ~(PERM_O_EXEC | PERM_G_EXEC | PERM_U_EXEC); } if(NTAttr & FILE_ATTRIBUTE_SYSTEM) { *Flags |= ICB_FLAG_SYSTEM; } else { *Flags &= ~ICB_FLAG_SYSTEM; } if(NTAttr & FILE_ATTRIBUTE_ARCHIVE) { *Flags |= ICB_FLAG_ARCHIVE; } else { *Flags &= ~ICB_FLAG_ARCHIVE; } if(NTAttr & FILE_ATTRIBUTE_HIDDEN) { *FCharact |= FILE_HIDDEN; } else { *FCharact &= ~FILE_HIDDEN; } *attr |= (PERM_O_READ | PERM_G_READ | PERM_U_READ); if(!(NTAttr & FILE_ATTRIBUTE_READONLY)) { *attr |= (PERM_O_WRITE | PERM_G_WRITE | PERM_U_WRITE | PERM_O_DELETE | PERM_G_DELETE | PERM_U_DELETE | PERM_O_CHATTR | PERM_G_CHATTR | PERM_U_CHATTR); } else { *attr &= ~(PERM_O_WRITE | PERM_G_WRITE | PERM_U_WRITE | PERM_O_DELETE | PERM_G_DELETE | PERM_U_DELETE | PERM_O_CHATTR | PERM_G_CHATTR | PERM_U_CHATTR); } FileDirNdx->SysAttr = NTAttr; if(FileDirNdx->FileInfo) FileDirNdx->FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; FileDirNdx->FI_Flags |= UDF_FI_FLAG_FI_MODIFIED; return; } // end UDFAttributesToUDF() #ifndef _CONSOLE /* This routine fills PFILE_BOTH_DIR_INFORMATION structure (NT) */ NTSTATUS UDFFileDirInfoToNT( IN PVCB Vcb, IN PDIR_INDEX_ITEM FileDirNdx, OUT PFILE_BOTH_DIR_INFORMATION NTFileInfo ) { PFILE_ENTRY FileEntry; UNICODE_STRING UdfName; UNICODE_STRING DosName; PEXTENDED_FILE_ENTRY ExFileEntry; USHORT Ident; BOOLEAN ReadSizes; NTSTATUS status; PtrUDFNTRequiredFCB NtReqFcb; UDFPrint(("@=%#x, FileDirNdx %x\n", &Vcb, FileDirNdx)); ASSERT((ULONG_PTR)NTFileInfo > 0x1000); RtlZeroMemory(NTFileInfo, sizeof(FILE_BOTH_DIR_INFORMATION)); DosName.Buffer = (PWCHAR)&(NTFileInfo->ShortName); DosName.MaximumLength = sizeof(NTFileInfo->ShortName); // 12*sizeof(WCHAR) _SEH2_TRY { UDFPrint((" DirInfoToNT: %*.*S\n", FileDirNdx->FName.Length/sizeof(WCHAR), FileDirNdx->FName.Length/sizeof(WCHAR), FileDirNdx->FName)); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { UDFPrint((" DirInfoToNT: exception when printing file name\n")); } _SEH2_END; if(FileDirNdx->FileInfo) { UDFPrint((" FileInfo\n")); // validate FileInfo ValidateFileInfo(FileDirNdx->FileInfo); if(UDFGetFileLinkCount(FileDirNdx->FileInfo) > 1) FileDirNdx->FI_Flags |= UDF_FI_FLAG_LINKED; FileEntry = (PFILE_ENTRY)(FileDirNdx->FileInfo->Dloc->FileEntry); // read required sizes from Fcb (if any) if file is not linked // otherwise we should read them from FileEntry if(FileDirNdx->FileInfo->Fcb) { UDFPrint((" Fcb\n")); NtReqFcb = FileDirNdx->FileInfo->Fcb->NTRequiredFCB; NTFileInfo->CreationTime.QuadPart = NtReqFcb->CreationTime.QuadPart; NTFileInfo->LastWriteTime.QuadPart = NtReqFcb->LastWriteTime.QuadPart; NTFileInfo->LastAccessTime.QuadPart = NtReqFcb->LastAccessTime.QuadPart; NTFileInfo->ChangeTime.QuadPart = NtReqFcb->ChangeTime.QuadPart; // NTFileInfo->AllocationSize.QuadPart = NtReqFcb->CommonFCBHeader.AllocationSize.QuadPart; NTFileInfo->AllocationSize.QuadPart = FileDirNdx->AllocationSize; /* FileDirNdx->FileSize = NTFileInfo->EndOfFile.QuadPart = NtReqFcb->CommonFCBHeader.FileSize.QuadPart;*/ NTFileInfo->EndOfFile.QuadPart = FileDirNdx->FileSize; if(FileDirNdx->FI_Flags & UDF_FI_FLAG_SYS_ATTR) { UDFPrint((" SYS_ATTR\n")); NTFileInfo->FileAttributes = FileDirNdx->SysAttr; goto get_name_only; } FileDirNdx->CreationTime = NTFileInfo->CreationTime.QuadPart; FileDirNdx->LastWriteTime = NTFileInfo->LastWriteTime.QuadPart; FileDirNdx->LastAccessTime = NTFileInfo->LastAccessTime.QuadPart; FileDirNdx->ChangeTime = NTFileInfo->ChangeTime.QuadPart; goto get_attr_only; } ASSERT(FileEntry); } else if(!(FileDirNdx->FI_Flags & UDF_FI_FLAG_SYS_ATTR) || (FileDirNdx->FI_Flags & UDF_FI_FLAG_LINKED)) { LONG_AD feloc; UDFPrint((" !SYS_ATTR\n")); FileEntry = (PFILE_ENTRY)MyAllocatePool__(NonPagedPool, Vcb->LBlockSize); if(!FileEntry) return STATUS_INSUFFICIENT_RESOURCES; feloc.extLength = Vcb->LBlockSize; feloc.extLocation = FileDirNdx->FileEntryLoc; if(!NT_SUCCESS(status = UDFReadFileEntry(Vcb, &feloc, FileEntry, &Ident))) { UDFPrint((" !UDFReadFileEntry\n")); MyFreePool__(FileEntry); FileEntry = NULL; goto get_name_only; } ReadSizes = TRUE; } else { UDFPrint((" FileDirNdx\n")); NTFileInfo->CreationTime.QuadPart = FileDirNdx->CreationTime; NTFileInfo->LastWriteTime.QuadPart = FileDirNdx->LastWriteTime; NTFileInfo->LastAccessTime.QuadPart = FileDirNdx->LastAccessTime; NTFileInfo->ChangeTime.QuadPart = FileDirNdx->ChangeTime; NTFileInfo->FileAttributes = FileDirNdx->SysAttr; NTFileInfo->AllocationSize.QuadPart = FileDirNdx->AllocationSize; NTFileInfo->EndOfFile.QuadPart = FileDirNdx->FileSize; NTFileInfo->EaSize = 0; FileEntry = NULL; goto get_name_only; } if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) goto get_name_only; UDFPrint((" direct\n")); if(FileEntry->descTag.tagIdent == TID_FILE_ENTRY) { UDFPrint((" TID_FILE_ENTRY\n")); if(ReadSizes) { UDFPrint((" ReadSizes\n")); // Times FileDirNdx->CreationTime = NTFileInfo->CreationTime.QuadPart = FileDirNdx->LastWriteTime = NTFileInfo->LastWriteTime.QuadPart = UDFTimeToNT(&(FileEntry->modificationTime)); FileDirNdx->LastAccessTime = NTFileInfo->LastAccessTime.QuadPart = UDFTimeToNT(&(FileEntry->accessTime)); FileDirNdx->ChangeTime = NTFileInfo->ChangeTime.QuadPart = UDFTimeToNT(&(FileEntry->attrTime)); // FileSize FileDirNdx->FileSize = NTFileInfo->EndOfFile.QuadPart = FileEntry->informationLength; UDFPrint((" informationLength=%I64x, lengthAllocDescs=%I64x\n", FileEntry->informationLength, FileEntry->lengthAllocDescs )); // AllocSize FileDirNdx->AllocationSize = NTFileInfo->AllocationSize.QuadPart = (FileEntry->informationLength + Vcb->LBlockSize - 1) & ~((LONGLONG)(Vcb->LBlockSize) - 1); } // NTFileInfo->EaSize = 0;//FileEntry->lengthExtendedAttr; } else if(FileEntry->descTag.tagIdent == TID_EXTENDED_FILE_ENTRY) { ExFileEntry = (PEXTENDED_FILE_ENTRY)FileEntry; UDFPrint((" PEXTENDED_FILE_ENTRY\n")); if(ReadSizes) { UDFPrint((" ReadSizes\n")); // Times FileDirNdx->CreationTime = NTFileInfo->CreationTime.QuadPart = UDFTimeToNT(&(ExFileEntry->createTime)); FileDirNdx->LastWriteTime = NTFileInfo->LastWriteTime.QuadPart = UDFTimeToNT(&(ExFileEntry->modificationTime)); FileDirNdx->LastAccessTime = NTFileInfo->LastAccessTime.QuadPart = UDFTimeToNT(&(ExFileEntry->accessTime)); FileDirNdx->ChangeTime = NTFileInfo->ChangeTime.QuadPart = UDFTimeToNT(&(ExFileEntry->attrTime)); // FileSize FileDirNdx->FileSize = NTFileInfo->EndOfFile.QuadPart = ExFileEntry->informationLength; UDFPrint((" informationLength=%I64x, lengthAllocDescs=%I64x\n", FileEntry->informationLength, FileEntry->lengthAllocDescs )); // AllocSize FileDirNdx->AllocationSize = NTFileInfo->AllocationSize.QuadPart = (ExFileEntry->informationLength + Vcb->LBlockSize - 1) & ~((LONGLONG)(Vcb->LBlockSize) - 1); } // NTFileInfo->EaSize = 0;//ExFileEntry->lengthExtendedAttr; } else { UDFPrint((" ???\n")); goto get_name_only; } get_attr_only: UDFPrint((" get_attr")); // do some substitutions if(!FileDirNdx->CreationTime) { FileDirNdx->CreationTime = NTFileInfo->CreationTime.QuadPart = Vcb->VolCreationTime; } if(!FileDirNdx->LastAccessTime) { FileDirNdx->LastAccessTime = NTFileInfo->LastAccessTime.QuadPart = FileDirNdx->CreationTime; } if(!FileDirNdx->LastWriteTime) { FileDirNdx->LastWriteTime = NTFileInfo->LastWriteTime.QuadPart = FileDirNdx->CreationTime; } if(!FileDirNdx->ChangeTime) { FileDirNdx->ChangeTime = NTFileInfo->ChangeTime.QuadPart = FileDirNdx->CreationTime; } FileDirNdx->SysAttr = NTFileInfo->FileAttributes = UDFAttributesToNT(FileDirNdx, (tag*)FileEntry); FileDirNdx->FI_Flags |= UDF_FI_FLAG_SYS_ATTR; get_name_only: // get filename in standard Unicode format UdfName = FileDirNdx->FName; NTFileInfo->FileNameLength = UdfName.Length; RtlCopyMemory((PCHAR)&(NTFileInfo->FileName), (PCHAR)(UdfName.Buffer), UdfName.MaximumLength); if(!(FileDirNdx->FI_Flags & UDF_FI_FLAG_DOS)) { UDFPrint((" !UDF_FI_FLAG_DOS")); UDFDOSName(Vcb, &DosName, &UdfName, (FileDirNdx->FI_Flags & UDF_FI_FLAG_KEEP_NAME) ? TRUE : FALSE); NTFileInfo->ShortNameLength = (UCHAR)DosName.Length; } // report zero EOF & AllocSize for Dirs if(FileDirNdx->FileCharacteristics & FILE_DIRECTORY) { UDFPrint((" FILE_DIRECTORY")); NTFileInfo->AllocationSize.QuadPart = NTFileInfo->EndOfFile.QuadPart = 0; } UDFPrint((" AllocationSize=%I64x, NTFileInfo->EndOfFile=%I64x", NTFileInfo->AllocationSize.QuadPart, NTFileInfo->EndOfFile.QuadPart)); // free tmp buffer (if any) UDFPrint(("\n")); if(FileEntry && !FileDirNdx->FileInfo) MyFreePool__(FileEntry); return STATUS_SUCCESS; } // end UDFFileDirInfoToNT() #endif //_CONSOLE #ifndef UDF_READ_ONLY_BUILD /* This routine changes xxxTime field(s) in (Ext)FileEntry */ VOID UDFSetFileXTime( IN PUDF_FILE_INFO FileInfo, IN LONGLONG* CrtTime, IN LONGLONG* AccTime, IN LONGLONG* AttrTime, IN LONGLONG* ChgTime ) { USHORT Ident; PDIR_INDEX_ITEM DirNdx; ValidateFileInfo(FileInfo); FileInfo->Dloc->FE_Flags |= UDF_FE_FLAG_FE_MODIFIED; DirNdx = UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo), FileInfo->Index); Ident = FileInfo->Dloc->FileEntry->tagIdent; if(Ident == TID_FILE_ENTRY) { PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry); if(AccTime) { if(DirNdx && *AccTime) DirNdx->LastAccessTime = *AccTime; UDFTimeToUDF(*AccTime, &(fe->accessTime)); } if(AttrTime) { if(DirNdx && *AttrTime) DirNdx->ChangeTime = *AttrTime; UDFTimeToUDF(*AttrTime, &(fe->attrTime)); } if(ChgTime) { if(DirNdx && *ChgTime) DirNdx->CreationTime = DirNdx->LastWriteTime = *ChgTime; UDFTimeToUDF(*ChgTime, &(fe->modificationTime)); } else if(CrtTime) { if(DirNdx && *CrtTime) DirNdx->CreationTime = DirNdx->LastWriteTime = *CrtTime; UDFTimeToUDF(*CrtTime, &(fe->modificationTime)); } } else if(Ident == TID_EXTENDED_FILE_ENTRY) { PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry); if(AccTime) { if(DirNdx && *AccTime) DirNdx->LastAccessTime = *AccTime; UDFTimeToUDF(*AccTime, &(fe->accessTime)); } if(AttrTime) { if(DirNdx && *AttrTime) DirNdx->ChangeTime = *AttrTime; UDFTimeToUDF(*AttrTime, &(fe->attrTime)); } if(ChgTime) { if(DirNdx && *ChgTime) DirNdx->LastWriteTime = *ChgTime; UDFTimeToUDF(*ChgTime, &(fe->modificationTime)); } if(CrtTime) { if(DirNdx && *CrtTime) DirNdx->CreationTime = *CrtTime; UDFTimeToUDF(*CrtTime, &(fe->createTime)); } } } // end UDFSetFileXTime() #endif //UDF_READ_ONLY_BUILD /* This routine gets xxxTime field(s) in (Ext)FileEntry */ VOID UDFGetFileXTime( IN PUDF_FILE_INFO FileInfo, OUT LONGLONG* CrtTime, OUT LONGLONG* AccTime, OUT LONGLONG* AttrTime, OUT LONGLONG* ChgTime ) { USHORT Ident; ValidateFileInfo(FileInfo); Ident = FileInfo->Dloc->FileEntry->tagIdent; if(Ident == TID_FILE_ENTRY) { PFILE_ENTRY fe = (PFILE_ENTRY)(FileInfo->Dloc->FileEntry); if(AccTime) *AccTime = UDFTimeToNT(&(fe->accessTime)); if(AttrTime) *AttrTime = UDFTimeToNT(&(fe->attrTime)); if(ChgTime) *ChgTime = UDFTimeToNT(&(fe->modificationTime)); if(CrtTime) { (*CrtTime) = *ChgTime; } } else if(Ident == TID_EXTENDED_FILE_ENTRY) { PEXTENDED_FILE_ENTRY fe = (PEXTENDED_FILE_ENTRY)(FileInfo->Dloc->FileEntry); if(AccTime) *AccTime = UDFTimeToNT(&(fe->accessTime)); if(AttrTime) *AttrTime = UDFTimeToNT(&(fe->attrTime)); if(ChgTime) *ChgTime = UDFTimeToNT(&(fe->modificationTime)); if(CrtTime) *CrtTime = UDFTimeToNT(&(fe->createTime)); } if(CrtTime) { if(!(*CrtTime)) KeQuerySystemTime((PLARGE_INTEGER)CrtTime); if(AccTime && !(*AccTime)) (*AccTime) = *CrtTime; if(AttrTime && !(*AttrTime)) (*AttrTime) = *CrtTime; if(AccTime && !(*AccTime)) (*AccTime) = *CrtTime; } } // end UDFGetFileXTime() VOID UDFNormalizeFileName( IN PUNICODE_STRING FName, IN USHORT valueCRC ) { PWCHAR buffer; USHORT len; len = FName->Length/sizeof(WCHAR); buffer = FName->Buffer; // check for '', '.' & '..' if(!len) return; if(!buffer[len-1]) { FName->Length-=sizeof(WCHAR); len--; } if(!len) return; if(buffer[0] == UNICODE_PERIOD) { if(len == 1) return; if((buffer[1] == UNICODE_PERIOD) && (len == 2)) return; } // check for trailing '.' for(len--;len;len--) { if( ((buffer[len] == UNICODE_PERIOD) || (buffer[len] == UNICODE_SPACE)) ) { FName->Length-=sizeof(WCHAR); buffer[len] = 0; } else break; } } // end UDFNormalizeFileName() #ifndef _CONSOLE void __fastcall UDFDOSNameOsNative( IN OUT PUNICODE_STRING DosName, IN PUNICODE_STRING UdfName, IN BOOLEAN KeepIntact ) { PWCHAR dosName = DosName->Buffer; PWCHAR udfName = UdfName->Buffer; uint32 udfLen = UdfName->Length / sizeof(WCHAR); GENERATE_NAME_CONTEXT Ctx; if(KeepIntact && (udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) { if((udfLen != 2) || (udfName[1] == UNICODE_PERIOD)) { RtlCopyMemory(dosName, udfName, UdfName->Length); DosName->Length = UdfName->Length; return; } } RtlZeroMemory(&Ctx, sizeof(GENERATE_NAME_CONTEXT)); RtlGenerate8dot3Name(UdfName, FALSE, &Ctx, DosName); } // UDFDOSNameOsNative() #endif //_CONSOLE /*VOID UDFNormalizeFileName( IN PUNICODE_STRING FName, IN USHORT valueCRC ) { WCHAR _newName[UDF_NAME_LEN+5]; PWCHAR newName = (PWCHAR)(&_newName); PWCHAR udfName = FName->Buffer; LONG udfLen = FName->Length >> 1; LONG index, newIndex = 0, extIndex = 0, newExtIndex = 0, trailIndex = 0; BOOLEAN needsCRC = FALSE, hasExt = FALSE; WCHAR ext[UDF_EXT_SIZE], current; // handle CurrentDir ('.') and ParentDir ('..') cases if((udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) { if((udfLen != 2) || (udfName[1] == UNICODE_PERIOD)) return; } for (index = 0 ; index < udfLen ; index++) { current = udfName[index]; // Look for illegal or unprintable characters. if (UDFIsIllegalChar(current) || !UnicodeIsPrint(current)) { needsCRC = TRUE; current = ILLEGAL_CHAR_MARK; // Skip Illegal characters(even spaces), // but not periods. while(index+1 < udfLen && (UDFIsIllegalChar(udfName[index+1]) || !UnicodeIsPrint(udfName[index+1])) && udfName[index+1] != UNICODE_PERIOD) index++; } // Record position of extension, if one is found. if ((current == UNICODE_PERIOD) && ((udfLen - index -1) <= UDF_EXT_SIZE)) { if (udfLen == index + 1) { // A trailing period is NOT an extension. hasExt = FALSE; } else { hasExt = TRUE; extIndex = index; newExtIndex = newIndex; } } else if((current != UNICODE_PERIOD) && (current != UNICODE_SPACE)) { trailIndex = index; } // if (newIndex < MAXLEN) // tshi is always TRUE for WINNT newName[newIndex] = current; newIndex++; // For OS2, 95 & NT, truncate any trailing periods and\or spaces. if (trailIndex != (newIndex - 1)) { newIndex = trailIndex + 1; needsCRC = TRUE; hasExt = FALSE; // Trailing period does not make an extension. } } if (needsCRC) { int localExtIndex = 0; if (hasExt) { int maxFilenameLen; // Translate extension, and store it in ext. for(index = 0; index maxFilenameLen) { newIndex = maxFilenameLen; } else { newIndex = newExtIndex; } } else if (newIndex > UDF_NAME_LEN - 5) { //If no extension, make sure to leave room for CRC. newIndex = UDF_NAME_LEN - 5; } newName[newIndex++] = UNICODE_CRC_MARK; // Add mark for CRC. //Calculate CRC from original filename from FileIdentifier. // valueCRC = UDFUnicodeCksum(fidName, fidNameLen); // / Convert 16-bits of CRC to hex characters. newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12]; newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8]; newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4]; newName[newIndex++] = hexChar[(valueCRC & 0x000f)]; // Place a translated extension at end, if found. if (hasExt) { newName[newIndex++] = UNICODE_PERIOD; for (index = 0;index < localExtIndex ;index++ ) { newName[newIndex++] = ext[index]; } } } if(FName->Length == (USHORT)newIndex*sizeof(WCHAR)) { RtlCopyMemory(FName->Buffer, newName, newIndex*sizeof(WCHAR)); return; } MyFreePool__(FName->Buffer); FName->Buffer = (PWCHAR)MyAllocatePool__(UDF_FILENAME_MT, (newIndex+1)*sizeof(WCHAR)); if(FName->Buffer) { FName->Buffer[newIndex] = 0; RtlCopyMemory(FName->Buffer, newName, newIndex*sizeof(WCHAR)); } FName->Length = (USHORT)newIndex*sizeof(WCHAR); FName->MaximumLength = (USHORT)(newIndex+1)*sizeof(WCHAR); }*/ /*PUDF_FILE_INFO UDFAllocFileInfo( return ExAllocateFromZone(&(UDFGlobalData.FileInfoZoneHeader)); )*/ #define STRING_BUFFER_ALIGNMENT (32) #define STRING_BUFFER_ALIGN(sz) (((sz)+STRING_BUFFER_ALIGNMENT)&(~((ULONG)(STRING_BUFFER_ALIGNMENT-1)))) NTSTATUS MyAppendUnicodeStringToString_( IN PUNICODE_STRING Str1, IN PUNICODE_STRING Str2 #ifdef UDF_TRACK_UNICODE_STR ,IN PCHAR Tag #endif ) { PWCHAR tmp; USHORT i; #ifdef UDF_TRACK_UNICODE_STR #define UDF_UNC_STR_TAG Tag #else #define UDF_UNC_STR_TAG "AppUStr" #endif tmp = Str1->Buffer; i = Str1->Length + Str2->Length + sizeof(WCHAR); ASSERT(Str1->MaximumLength); if(i > Str1->MaximumLength) { if(!MyReallocPool__((PCHAR)tmp, Str1->MaximumLength, (PCHAR*)&tmp, STRING_BUFFER_ALIGN(i)*2) ) { return STATUS_INSUFFICIENT_RESOURCES; } Str1->MaximumLength = i*2; Str1->Buffer = tmp; } RtlCopyMemory(((PCHAR)tmp)+Str1->Length, Str2->Buffer, Str2->Length); /* tmp = (PWCHAR)MyAllocatePoolTag__(NonPagedPool, i = Str1->Length + Str2->Length + sizeof(WCHAR), UDF_UNC_STR_TAG); if(!tmp) return STATUS_INSUFFICIENT_RESOURCES; RtlCopyMemory(tmp, Str1->Buffer, Str1->Length); RtlCopyMemory(((PCHAR)tmp)+Str1->Length, Str2->Buffer, Str2->Length);*/ tmp[(i / sizeof(WCHAR)) - 1] = 0; Str1->Length = i - sizeof(WCHAR); //MyFreePool__(Str1->Buffer); #ifdef UDF_DBG if(Str1->Buffer && (Str1->Length >= 2*sizeof(WCHAR))) { ASSERT((Str1->Buffer[0] != L'\\') || (Str1->Buffer[1] != L'\\')); } #endif // UDF_DBG return STATUS_SUCCESS; #undef UDF_UNC_STR_TAG } // end MyAppendUnicodeStringToString() NTSTATUS MyAppendUnicodeToString_( IN PUNICODE_STRING Str1, IN PCWSTR Str2 #ifdef UDF_TRACK_UNICODE_STR ,IN PCHAR Tag #endif ) { PWCHAR tmp; USHORT i; #ifdef UDF_TRACK_UNICODE_STR #define UDF_UNC_STR_TAG Tag #else #define UDF_UNC_STR_TAG "AppStr" #endif #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__) __asm push ebx __asm push esi __asm xor ebx,ebx __asm mov esi,Str2 Scan_1: __asm cmp [word ptr esi+ebx],0 __asm je EO_Scan __asm add ebx,2 __asm jmp Scan_1 EO_Scan: __asm mov i,bx __asm pop esi __asm pop ebx #else // NO X86 optimization, use generic C/C++ i=0; while(Str2[i]) { i++; } i *= sizeof(WCHAR); #endif // _X86_ tmp = Str1->Buffer; ASSERT(Str1->MaximumLength); if((Str1->Length+i+sizeof(WCHAR)) > Str1->MaximumLength) { if(!MyReallocPool__((PCHAR)tmp, Str1->MaximumLength, (PCHAR*)&tmp, STRING_BUFFER_ALIGN(i + Str1->Length + sizeof(WCHAR))*2 ) ) { return STATUS_INSUFFICIENT_RESOURCES; } Str1->MaximumLength = STRING_BUFFER_ALIGN(i + sizeof(WCHAR))*2; Str1->Buffer = tmp; } RtlCopyMemory(((PCHAR)tmp)+Str1->Length, Str2, i); i+=Str1->Length; tmp[(i / sizeof(WCHAR))] = 0; Str1->Length = i; #ifdef UDF_DBG /* if(Str1->Buffer && (Str1->Length >= 2*sizeof(WCHAR))) { ASSERT((Str1->Buffer[0] != L'\\') || (Str1->Buffer[1] != L'\\')); }*/ #endif // UDF_DBG return STATUS_SUCCESS; #undef UDF_UNC_STR_TAG } // end MyAppendUnicodeToString_() NTSTATUS MyInitUnicodeString( IN PUNICODE_STRING Str1, IN PCWSTR Str2 ) { USHORT i; #if defined(_X86_) && defined(_MSC_VER) && !defined(__clang__) __asm push ebx __asm push esi __asm xor ebx,ebx __asm mov esi,Str2 Scan_1: __asm cmp [word ptr esi+ebx],0 __asm je EO_Scan __asm add ebx,2 __asm jmp Scan_1 EO_Scan: __asm mov i,bx __asm pop esi __asm pop ebx #else // NO X86 optimization, use generic C/C++ i=0; while(Str2[i]) { i++; } i *= sizeof(WCHAR); #endif // _X86_ Str1->MaximumLength = STRING_BUFFER_ALIGN((Str1->Length = i) + sizeof(WCHAR)); Str1->Buffer = (PWCHAR)MyAllocatePool__(NonPagedPool, Str1->MaximumLength); if(!Str1->Buffer) return STATUS_INSUFFICIENT_RESOURCES; RtlCopyMemory(Str1->Buffer, Str2, i); Str1->Buffer[i/sizeof(WCHAR)] = 0; return STATUS_SUCCESS; } // end MyInitUnicodeString() NTSTATUS MyCloneUnicodeString( IN PUNICODE_STRING Str1, IN PUNICODE_STRING Str2 ) { Str1->MaximumLength = STRING_BUFFER_ALIGN((Str1->Length = Str2->Length) + sizeof(WCHAR)); Str1->Buffer = (PWCHAR)MyAllocatePool__(NonPagedPool, Str1->MaximumLength); if(!Str1->Buffer) return STATUS_INSUFFICIENT_RESOURCES; ASSERT(Str2->Buffer); RtlCopyMemory(Str1->Buffer, Str2->Buffer, Str2->Length); Str1->Buffer[Str1->Length/sizeof(WCHAR)] = 0; return STATUS_SUCCESS; } // end MyCloneUnicodeString() /* This routine checks do we needn't read something from disk to obtain Attributes & so on */ BOOLEAN UDFIsDirInfoCached( IN PVCB Vcb, IN PUDF_FILE_INFO DirInfo ) { PDIR_INDEX_HDR hDirNdx = DirInfo->Dloc->DirIndex; PDIR_INDEX_ITEM DirNdx; for(uint_di i=2; (DirNdx = UDFDirIndex(hDirNdx,i)); i++) { if(!(DirNdx->FI_Flags & UDF_FI_FLAG_SYS_ATTR) || (DirNdx->FI_Flags & UDF_FI_FLAG_LINKED)) return FALSE; } return TRUE; } // end UDFIsDirInfoCached() #ifndef UDF_READ_ONLY_BUILD NTSTATUS UDFDoesOSAllowFileToBeTargetForRename__( IN PUDF_FILE_INFO FileInfo ) { #ifndef _CONSOLE NTSTATUS RC; #endif //_CONSOLE if(UDFIsADirectory(FileInfo)) return STATUS_ACCESS_DENIED; if(!FileInfo->ParentFile) return STATUS_ACCESS_DENIED; if(UDFAttributesToNT(UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo),FileInfo->Index), FileInfo->Dloc->FileEntry) & FILE_ATTRIBUTE_READONLY) return STATUS_ACCESS_DENIED; if(!FileInfo->Fcb) return STATUS_SUCCESS; #ifndef _CONSOLE RC = UDFCheckAccessRights(NULL, NULL, FileInfo->Fcb, NULL, DELETE, 0); if(!NT_SUCCESS(RC)) return RC; #endif //_CONSOLE if(!FileInfo->Fcb) return STATUS_SUCCESS; // RC = UDFMarkStreamsForDeletion(FileInfo->Fcb->Vcb, FileInfo->Fcb, TRUE); // Delete /* RC = UDFSetDispositionInformation(FileInfo->Fcb, NULL, FileInfo->Fcb->Vcb, NULL, TRUE); if(NT_SUCCESS(RC)) { FileInfo->Fcb->FCBFlags |= UDF_FCB_DELETED; if(UDFGetFileLinkCount(FileInfo) <= 1) { FileInfo->Fcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_DELETED; } } return RC;*/ return STATUS_ACCESS_DENIED; } // end UDFDoesOSAllowFileToBeTargetForRename__() NTSTATUS UDFDoesOSAllowFileToBeUnlinked__( IN PUDF_FILE_INFO FileInfo ) { PDIR_INDEX_HDR hCurDirNdx; PDIR_INDEX_ITEM CurDirNdx; uint_di i; // IO_STATUS_BLOCK IoStatus; ASSERT(FileInfo->Dloc); if(!FileInfo->ParentFile) return STATUS_CANNOT_DELETE; if(FileInfo->Dloc->SDirInfo) return STATUS_CANNOT_DELETE; if(!UDFIsADirectory(FileInfo)) return STATUS_SUCCESS; // UDFFlushAFile(FileInfo->Fcb, NULL, &IoStatus, 0); hCurDirNdx = FileInfo->Dloc->DirIndex; // check if we can delete all files for(i=2; (CurDirNdx = UDFDirIndex(hCurDirNdx,i)); i++) { // try to open Stream if(CurDirNdx->FileInfo) return STATUS_CANNOT_DELETE; } // return UDFCheckAccessRights(NULL, NULL, FileInfo->Fcb, NULL, DELETE, 0); return STATUS_SUCCESS; } // end UDFDoesOSAllowFileToBeUnlinked__() NTSTATUS UDFDoesOSAllowFilePretendDeleted__( IN PUDF_FILE_INFO FileInfo ) { PDIR_INDEX_HDR hDirNdx = UDFGetDirIndexByFileInfo(FileInfo); if(!hDirNdx) return STATUS_CANNOT_DELETE; PDIR_INDEX_ITEM DirNdx = UDFDirIndex(hDirNdx, FileInfo->Index); if(!DirNdx) return STATUS_CANNOT_DELETE; // we can't hide file that is not marked as deleted if(!(DirNdx->FileCharacteristics & FILE_DELETED)) { BrutePoint(); #ifndef _CONSOLE if(!(FileInfo->Fcb->FCBFlags & (UDF_FCB_DELETE_ON_CLOSE | UDF_FCB_DELETED) )) #endif //_CONSOLE return STATUS_CANNOT_DELETE; } return STATUS_SUCCESS; } #endif //UDF_READ_ONLY_BUILD