reactos/drivers/filesystems/udfs/Include/Sys_spec_lib.cpp

1042 lines
34 KiB
C++

////////////////////////////////////////////////////////////////////
// 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)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<UDF_EXT_SIZE && extIndex + index +1 < udfLen; index++ ) {
current = udfName[extIndex + index + 1];
if (UDFIsIllegalChar(current) //|| !UnicodeIsPrint(current)) {
needsCRC = TRUE;
// Replace Illegal and non-displayable chars
// with underscore.
current = ILLEGAL_CHAR_MARK;
// Skip any other illegal or non-displayable
// characters.
while(index + 1 < UDF_EXT_SIZE &&
(UDFIsIllegalChar(udfName[extIndex + index + 2]) ||
!UnicodeIsPrint(udfName[extIndex + index + 2])) )
index++;
}
ext[localExtIndex++] = current;
}
// Truncate filename to leave room for extension and CRC.
maxFilenameLen = ((UDF_NAME_LEN - 4) - localExtIndex - 1);
if (newIndex > 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