1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*************************************************************************
10 * Module: UDF File System Driver
11 * (both User and Kernel mode execution)
14 * Contains system-secific code
16 *************************************************************************/
20 This routine converts UDF timestamp to NT time
24 IN PUDF_TIME_STAMP UdfTime
28 TIME_FIELDS TimeFields
;
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
);
38 if (!RtlTimeFieldsToTime(&TimeFields
, (PLARGE_INTEGER
)&NtTime
)) {
41 ExLocalTimeToSystemTime( (PLARGE_INTEGER
)&NtTime
, (PLARGE_INTEGER
)&NtTime
);
45 } // end UDFTimeToNT()
49 This routine converts NT time to UDF timestamp
54 OUT PUDF_TIME_STAMP UdfTime
60 TIME_FIELDS TimeFields
;
62 ExSystemTimeToLocalTime( (PLARGE_INTEGER
)&NtTime
, (PLARGE_INTEGER
)&LocalTime
);
63 RtlTimeToTimeFields( (PLARGE_INTEGER
)&LocalTime
, &TimeFields
);
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()
84 IN PDIR_INDEX_ITEM FileDirNdx
,
89 if( (FileDirNdx
->FI_Flags
& UDF_FI_FLAG_SYS_ATTR
) &&
90 !(FileDirNdx
->FI_Flags
& UDF_FI_FLAG_LINKED
))
91 return FileDirNdx
->SysAttr
;
94 ULONG attr
= 0; //permissions
100 if(!FileDirNdx
->FileInfo
)
102 ValidateFileInfo(FileDirNdx
->FileInfo
);
103 FileEntry
= FileDirNdx
->FileInfo
->Dloc
->FileEntry
;
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
;
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
;
118 FCharact
= FileDirNdx
->FileCharacteristics
;
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
;
128 //NTAttr |= FILE_ATTRIBUTE_NORMAL;
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
;
140 FileDirNdx
->SysAttr
= NTAttr
;
142 } // end UDFAttributesToNT()
148 IN PDIR_INDEX_ITEM FileDirNdx
,
153 PULONG attr
; //permissions
158 NTAttr
&= UDF_VALID_FILE_ATTRIBUTES
;
162 if(!FileDirNdx
->FileInfo
)
164 ValidateFileInfo(FileDirNdx
->FileInfo
);
165 FileEntry
= FileDirNdx
->FileInfo
->Dloc
->FileEntry
;
166 FileDirNdx
->FileInfo
->Dloc
->FE_Flags
|= UDF_FE_FLAG_FE_MODIFIED
;
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
;
173 attr
= &((PEXTENDED_FILE_ENTRY
)FileEntry
)->permissions
;
174 Flags
= &((PEXTENDED_FILE_ENTRY
)FileEntry
)->icbTag
.flags
;
175 Type
= &((PEXTENDED_FILE_ENTRY
)FileEntry
)->icbTag
.fileType
;
177 FCharact
= &(FileDirNdx
->FileCharacteristics
);
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
;
189 *FCharact
&= ~FILE_DIRECTORY
;
190 *Type
= UDF_FILE_TYPE_REGULAR
;
191 *attr
&= ~(PERM_O_EXEC
| PERM_G_EXEC
| PERM_U_EXEC
);
194 if(NTAttr
& FILE_ATTRIBUTE_SYSTEM
) {
195 *Flags
|= ICB_FLAG_SYSTEM
;
197 *Flags
&= ~ICB_FLAG_SYSTEM
;
199 if(NTAttr
& FILE_ATTRIBUTE_ARCHIVE
) {
200 *Flags
|= ICB_FLAG_ARCHIVE
;
202 *Flags
&= ~ICB_FLAG_ARCHIVE
;
204 if(NTAttr
& FILE_ATTRIBUTE_HIDDEN
) {
205 *FCharact
|= FILE_HIDDEN
;
207 *FCharact
&= ~FILE_HIDDEN
;
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
);
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
);
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
;
224 } // end UDFAttributesToUDF()
228 This routine fills PFILE_BOTH_DIR_INFORMATION structure (NT)
233 IN PDIR_INDEX_ITEM FileDirNdx
,
234 OUT PFILE_BOTH_DIR_INFORMATION NTFileInfo
237 PFILE_ENTRY FileEntry
;
238 UNICODE_STRING UdfName
;
239 UNICODE_STRING DosName
;
240 PEXTENDED_FILE_ENTRY ExFileEntry
;
244 PtrUDFNTRequiredFCB NtReqFcb
;
246 KdPrint(("@=%#x, FileDirNdx %x\n", &Vcb
, FileDirNdx
));
248 ASSERT((ULONG
)NTFileInfo
> 0x1000);
249 RtlZeroMemory(NTFileInfo
, sizeof(FILE_BOTH_DIR_INFORMATION
));
251 DosName
.Buffer
= (PWCHAR
)&(NTFileInfo
->ShortName
);
252 DosName
.MaximumLength
= sizeof(NTFileInfo
->ShortName
); // 12*sizeof(WCHAR)
255 KdPrint((" DirInfoToNT: %*.*S\n", FileDirNdx
->FName
.Length
/sizeof(WCHAR
), FileDirNdx
->FName
.Length
/sizeof(WCHAR
), FileDirNdx
->FName
));
256 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
257 KdPrint((" DirInfoToNT: exception when printing file name\n"));
260 if(FileDirNdx
->FileInfo
) {
261 KdPrint((" FileInfo\n"));
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
) {
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 KdPrint((" SYS_ATTR\n"));
283 NTFileInfo
->FileAttributes
= FileDirNdx
->SysAttr
;
286 FileDirNdx
->CreationTime
= NTFileInfo
->CreationTime
.QuadPart
;
287 FileDirNdx
->LastWriteTime
= NTFileInfo
->LastWriteTime
.QuadPart
;
288 FileDirNdx
->LastAccessTime
= NTFileInfo
->LastAccessTime
.QuadPart
;
289 FileDirNdx
->ChangeTime
= NTFileInfo
->ChangeTime
.QuadPart
;
293 } else if(!(FileDirNdx
->FI_Flags
& UDF_FI_FLAG_SYS_ATTR
) ||
294 (FileDirNdx
->FI_Flags
& UDF_FI_FLAG_LINKED
)) {
297 KdPrint((" !SYS_ATTR\n"));
298 FileEntry
= (PFILE_ENTRY
)MyAllocatePool__(NonPagedPool
, Vcb
->LBlockSize
);
299 if(!FileEntry
) return STATUS_INSUFFICIENT_RESOURCES
;
301 feloc
.extLength
= Vcb
->LBlockSize
;
302 feloc
.extLocation
= FileDirNdx
->FileEntryLoc
;
304 if(!NT_SUCCESS(status
= UDFReadFileEntry(Vcb
, &feloc
, FileEntry
, &Ident
))) {
305 KdPrint((" !UDFReadFileEntry\n"));
306 MyFreePool__(FileEntry
);
312 KdPrint((" 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;
325 if(Vcb
->VCBFlags
& UDF_VCB_FLAGS_RAW_DISK
)
328 KdPrint((" direct\n"));
329 if(FileEntry
->descTag
.tagIdent
== TID_FILE_ENTRY
) {
330 KdPrint((" TID_FILE_ENTRY\n"));
332 KdPrint((" ReadSizes\n"));
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
));
339 FileDirNdx
->FileSize
=
340 NTFileInfo
->EndOfFile
.QuadPart
=
341 FileEntry
->informationLength
;
342 KdPrint((" informationLength=%I64x, lengthAllocDescs=%I64x\n",
343 FileEntry
->informationLength
,
344 FileEntry
->lengthAllocDescs
347 FileDirNdx
->AllocationSize
=
348 NTFileInfo
->AllocationSize
.QuadPart
=
349 (FileEntry
->informationLength
+ Vcb
->LBlockSize
- 1) & ~((LONGLONG
)(Vcb
->LBlockSize
) - 1);
351 // NTFileInfo->EaSize = 0;//FileEntry->lengthExtendedAttr;
352 } else if(FileEntry
->descTag
.tagIdent
== TID_EXTENDED_FILE_ENTRY
) {
353 ExFileEntry
= (PEXTENDED_FILE_ENTRY
)FileEntry
;
354 KdPrint((" PEXTENDED_FILE_ENTRY\n"));
356 KdPrint((" ReadSizes\n"));
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
));
363 FileDirNdx
->FileSize
=
364 NTFileInfo
->EndOfFile
.QuadPart
=
365 ExFileEntry
->informationLength
;
366 KdPrint((" informationLength=%I64x, lengthAllocDescs=%I64x\n",
367 FileEntry
->informationLength
,
368 FileEntry
->lengthAllocDescs
371 FileDirNdx
->AllocationSize
=
372 NTFileInfo
->AllocationSize
.QuadPart
=
373 (ExFileEntry
->informationLength
+ Vcb
->LBlockSize
- 1) & ~((LONGLONG
)(Vcb
->LBlockSize
) - 1);
375 // NTFileInfo->EaSize = 0;//ExFileEntry->lengthExtendedAttr;
383 KdPrint((" get_attr"));
384 // do some substitutions
385 if(!FileDirNdx
->CreationTime
) {
386 FileDirNdx
->CreationTime
= NTFileInfo
->CreationTime
.QuadPart
= Vcb
->VolCreationTime
;
388 if(!FileDirNdx
->LastAccessTime
) {
389 FileDirNdx
->LastAccessTime
= NTFileInfo
->LastAccessTime
.QuadPart
= FileDirNdx
->CreationTime
;
391 if(!FileDirNdx
->LastWriteTime
) {
392 FileDirNdx
->LastWriteTime
= NTFileInfo
->LastWriteTime
.QuadPart
= FileDirNdx
->CreationTime
;
394 if(!FileDirNdx
->ChangeTime
) {
395 FileDirNdx
->ChangeTime
= NTFileInfo
->ChangeTime
.QuadPart
= FileDirNdx
->CreationTime
;
398 FileDirNdx
->SysAttr
=
399 NTFileInfo
->FileAttributes
= UDFAttributesToNT(FileDirNdx
, (tag
*)FileEntry
);
400 FileDirNdx
->FI_Flags
|= UDF_FI_FLAG_SYS_ATTR
;
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 KdPrint((" !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
;
413 // report zero EOF & AllocSize for Dirs
414 if(FileDirNdx
->FileCharacteristics
& FILE_DIRECTORY
) {
415 KdPrint((" FILE_DIRECTORY"));
416 NTFileInfo
->AllocationSize
.QuadPart
=
417 NTFileInfo
->EndOfFile
.QuadPart
= 0;
419 KdPrint((" AllocationSize=%I64x, NTFileInfo->EndOfFile=%I64x", NTFileInfo
->AllocationSize
.QuadPart
, NTFileInfo
->EndOfFile
.QuadPart
));
420 // free tmp buffer (if any)
422 if(FileEntry
&& !FileDirNdx
->FileInfo
)
423 MyFreePool__(FileEntry
);
424 return STATUS_SUCCESS
;
425 } // end UDFFileDirInfoToNT()
429 #ifndef UDF_READ_ONLY_BUILD
431 This routine changes xxxTime field(s) in (Ext)FileEntry
435 IN PUDF_FILE_INFO FileInfo
,
436 IN LONGLONG
* CrtTime
,
437 IN LONGLONG
* AccTime
,
438 IN LONGLONG
* AttrTime
,
443 PDIR_INDEX_ITEM DirNdx
;
445 ValidateFileInfo(FileInfo
);
447 FileInfo
->Dloc
->FE_Flags
|= UDF_FE_FLAG_FE_MODIFIED
;
448 DirNdx
= UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo
), FileInfo
->Index
);
449 Ident
= FileInfo
->Dloc
->FileEntry
->tagIdent
;
451 if(Ident
== TID_FILE_ENTRY
) {
452 PFILE_ENTRY fe
= (PFILE_ENTRY
)(FileInfo
->Dloc
->FileEntry
);
455 if(DirNdx
&& *AccTime
) DirNdx
->LastAccessTime
= *AccTime
;
456 UDFTimeToUDF(*AccTime
, &(fe
->accessTime
));
459 if(DirNdx
&& *AttrTime
) DirNdx
->ChangeTime
= *AttrTime
;
460 UDFTimeToUDF(*AttrTime
, &(fe
->attrTime
));
463 if(DirNdx
&& *ChgTime
) DirNdx
->CreationTime
=
464 DirNdx
->LastWriteTime
= *ChgTime
;
465 UDFTimeToUDF(*ChgTime
, &(fe
->modificationTime
));
468 if(DirNdx
&& *CrtTime
) DirNdx
->CreationTime
=
469 DirNdx
->LastWriteTime
= *CrtTime
;
470 UDFTimeToUDF(*CrtTime
, &(fe
->modificationTime
));
473 } else if(Ident
== TID_EXTENDED_FILE_ENTRY
) {
474 PEXTENDED_FILE_ENTRY fe
= (PEXTENDED_FILE_ENTRY
)(FileInfo
->Dloc
->FileEntry
);
477 if(DirNdx
&& *AccTime
) DirNdx
->LastAccessTime
= *AccTime
;
478 UDFTimeToUDF(*AccTime
, &(fe
->accessTime
));
481 if(DirNdx
&& *AttrTime
) DirNdx
->ChangeTime
= *AttrTime
;
482 UDFTimeToUDF(*AttrTime
, &(fe
->attrTime
));
485 if(DirNdx
&& *ChgTime
) DirNdx
->LastWriteTime
= *ChgTime
;
486 UDFTimeToUDF(*ChgTime
, &(fe
->modificationTime
));
489 if(DirNdx
&& *CrtTime
) DirNdx
->CreationTime
= *CrtTime
;
490 UDFTimeToUDF(*CrtTime
, &(fe
->createTime
));
494 } // end UDFSetFileXTime()
495 #endif //UDF_READ_ONLY_BUILD
498 This routine gets xxxTime field(s) in (Ext)FileEntry
502 IN PUDF_FILE_INFO FileInfo
,
503 OUT LONGLONG
* CrtTime
,
504 OUT LONGLONG
* AccTime
,
505 OUT LONGLONG
* AttrTime
,
506 OUT LONGLONG
* ChgTime
511 ValidateFileInfo(FileInfo
);
513 Ident
= FileInfo
->Dloc
->FileEntry
->tagIdent
;
515 if(Ident
== TID_FILE_ENTRY
) {
516 PFILE_ENTRY fe
= (PFILE_ENTRY
)(FileInfo
->Dloc
->FileEntry
);
518 if(AccTime
) *AccTime
= UDFTimeToNT(&(fe
->accessTime
));
519 if(AttrTime
) *AttrTime
= UDFTimeToNT(&(fe
->attrTime
));
520 if(ChgTime
) *ChgTime
= UDFTimeToNT(&(fe
->modificationTime
));
522 (*CrtTime
) = *ChgTime
;
525 } else if(Ident
== TID_EXTENDED_FILE_ENTRY
) {
526 PEXTENDED_FILE_ENTRY fe
= (PEXTENDED_FILE_ENTRY
)(FileInfo
->Dloc
->FileEntry
);
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
));
536 KeQuerySystemTime((PLARGE_INTEGER
)CrtTime
);
537 if(AccTime
&& !(*AccTime
)) (*AccTime
) = *CrtTime
;
538 if(AttrTime
&& !(*AttrTime
)) (*AttrTime
) = *CrtTime
;
539 if(AccTime
&& !(*AccTime
)) (*AccTime
) = *CrtTime
;
541 } // end UDFGetFileXTime()
544 UDFNormalizeFileName(
545 IN PUNICODE_STRING FName
,
552 len
= FName
->Length
/sizeof(WCHAR
);
553 buffer
= FName
->Buffer
;
555 // check for '', '.' & '..'
558 FName
->Length
-=sizeof(WCHAR
);
562 if(buffer
[0] == UNICODE_PERIOD
) {
564 if((buffer
[1] == UNICODE_PERIOD
) && (len
== 2)) return;
567 // check for trailing '.'
568 for(len
--;len
;len
--) {
569 if( ((buffer
[len
] == UNICODE_PERIOD
) || (buffer
[len
] == UNICODE_SPACE
)) ) {
570 FName
->Length
-=sizeof(WCHAR
);
575 } // end UDFNormalizeFileName()
582 IN OUT PUNICODE_STRING DosName
,
583 IN PUNICODE_STRING UdfName
,
584 IN BOOLEAN KeepIntact
587 PWCHAR dosName
= DosName
->Buffer
;
588 PWCHAR udfName
= UdfName
->Buffer
;
589 uint32 udfLen
= UdfName
->Length
/ sizeof(WCHAR
);
590 GENERATE_NAME_CONTEXT Ctx
;
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
;
600 RtlZeroMemory(&Ctx
, sizeof(GENERATE_NAME_CONTEXT
));
601 RtlGenerate8dot3Name(UdfName
, FALSE
, &Ctx
, DosName
);
603 } // UDFDOSNameOsNative()
608 UDFNormalizeFileName(
609 IN PUNICODE_STRING FName,
613 WCHAR _newName[UDF_NAME_LEN+5];
614 PWCHAR newName = (PWCHAR)(&_newName);
615 PWCHAR udfName = FName->Buffer;
616 LONG udfLen = FName->Length >> 1;
618 LONG index, newIndex = 0, extIndex = 0, newExtIndex = 0, trailIndex = 0;
619 BOOLEAN needsCRC = FALSE, hasExt = FALSE;
620 WCHAR ext[UDF_EXT_SIZE], current;
622 // handle CurrentDir ('.') and ParentDir ('..') cases
623 if((udfLen <= 2) && (udfName[0] == UNICODE_PERIOD)) {
624 if((udfLen != 2) || (udfName[1] == UNICODE_PERIOD))
628 for (index = 0 ; index < udfLen ; index++) {
629 current = udfName[index];
631 // Look for illegal or unprintable characters.
632 if (UDFIsIllegalChar(current) || !UnicodeIsPrint(current)) {
634 current = ILLEGAL_CHAR_MARK;
635 // Skip Illegal characters(even spaces),
637 while(index+1 < udfLen &&
638 (UDFIsIllegalChar(udfName[index+1]) ||
639 !UnicodeIsPrint(udfName[index+1])) &&
640 udfName[index+1] != UNICODE_PERIOD)
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.
652 newExtIndex = newIndex;
654 } else if((current != UNICODE_PERIOD) && (current != UNICODE_SPACE)) {
658 // if (newIndex < MAXLEN) // tshi is always TRUE for WINNT
659 newName[newIndex] = current;
662 // For OS2, 95 & NT, truncate any trailing periods and\or spaces.
663 if (trailIndex != (newIndex - 1)) {
664 newIndex = trailIndex + 1;
666 hasExt = FALSE; // Trailing period does not make an extension.
671 int localExtIndex = 0;
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)) {
679 // Replace Illegal and non-displayable chars
681 current = ILLEGAL_CHAR_MARK;
682 // Skip any other illegal or non-displayable
684 while(index + 1 < UDF_EXT_SIZE &&
685 (UDFIsIllegalChar(udfName[extIndex + index + 2]) ||
686 !UnicodeIsPrint(udfName[extIndex + index + 2])) )
689 ext[localExtIndex++] = current;
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;
696 newIndex = newExtIndex;
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;
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.
712 newName[newIndex++] = UNICODE_PERIOD;
713 for (index = 0;index < localExtIndex ;index++ ) {
714 newName[newIndex++] = ext[index];
719 if(FName->Length == (USHORT)newIndex*sizeof(WCHAR)) {
720 RtlCopyMemory(FName->Buffer, newName, newIndex*sizeof(WCHAR));
723 MyFreePool__(FName->Buffer);
724 FName->Buffer = (PWCHAR)MyAllocatePool__(UDF_FILENAME_MT, (newIndex+1)*sizeof(WCHAR));
726 FName->Buffer[newIndex] = 0;
727 RtlCopyMemory(FName->Buffer, newName, newIndex*sizeof(WCHAR));
729 FName->Length = (USHORT)newIndex*sizeof(WCHAR);
730 FName->MaximumLength = (USHORT)(newIndex+1)*sizeof(WCHAR);
735 return ExAllocateFromZone(&(UDFGlobalData.FileInfoZoneHeader));
738 #define STRING_BUFFER_ALIGNMENT (32)
739 #define STRING_BUFFER_ALIGN(sz) (((sz)+STRING_BUFFER_ALIGNMENT)&(~((ULONG)(STRING_BUFFER_ALIGNMENT-1))))
742 MyAppendUnicodeStringToString_(
743 IN PUNICODE_STRING Str1
,
744 IN PUNICODE_STRING Str2
745 #ifdef UDF_TRACK_UNICODE_STR
753 #ifdef UDF_TRACK_UNICODE_STR
754 #define UDF_UNC_STR_TAG Tag
756 #define UDF_UNC_STR_TAG "AppUStr"
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
;
767 Str1
->MaximumLength
= i
*2;
770 RtlCopyMemory(((PCHAR
)tmp
)+Str1
->Length
, Str2
->Buffer
, Str2
->Length
);
772 /* tmp = (PWCHAR)MyAllocatePoolTag__(NonPagedPool, i = Str1->Length + Str2->Length + sizeof(WCHAR), UDF_UNC_STR_TAG);
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);
781 if(Str1
->Buffer
&& (Str1
->Length
>= 2*sizeof(WCHAR
))) {
782 ASSERT((Str1
->Buffer
[0] != L
'\\') || (Str1
->Buffer
[1] != L
'\\'));
785 return STATUS_SUCCESS
;
787 #undef UDF_UNC_STR_TAG
789 } // end MyAppendUnicodeStringToString()
792 MyAppendUnicodeToString_(
793 IN PUNICODE_STRING Str1
,
795 #ifdef UDF_TRACK_UNICODE_STR
803 #ifdef UDF_TRACK_UNICODE_STR
804 #define UDF_UNC_STR_TAG Tag
806 #define UDF_UNC_STR_TAG "AppStr"
818 __asm cmp
[word ptr esi
+ebx
],0
828 #else // NO X86 optimization, use generic C/C++
839 ASSERT(Str1
->MaximumLength
);
840 if((Str1
->Length
+i
+sizeof(WCHAR
)) > Str1
->MaximumLength
) {
841 if(!MyReallocPool__((PCHAR
)tmp
, Str1
->MaximumLength
,
842 (PCHAR
*)&tmp
, STRING_BUFFER_ALIGN(i
+ Str1
->Length
+ sizeof(WCHAR
))*2 ) ) {
843 return STATUS_INSUFFICIENT_RESOURCES
;
845 Str1
->MaximumLength
= STRING_BUFFER_ALIGN(i
+ sizeof(WCHAR
))*2;
848 RtlCopyMemory(((PCHAR
)tmp
)+Str1
->Length
, Str2
, i
);
850 tmp
[(i
/ sizeof(WCHAR
))] = 0;
853 /* if(Str1->Buffer && (Str1->Length >= 2*sizeof(WCHAR))) {
854 ASSERT((Str1->Buffer[0] != L'\\') || (Str1->Buffer[1] != L'\\'));
857 return STATUS_SUCCESS
;
859 #undef UDF_UNC_STR_TAG
861 } // end MyAppendUnicodeToString_()
865 IN PUNICODE_STRING Str1
,
881 __asm cmp
[word ptr esi
+ebx
],0
891 #else // NO X86 optimization, use generic C/C++
901 Str1
->MaximumLength
= STRING_BUFFER_ALIGN((Str1
->Length
= i
) + sizeof(WCHAR
));
902 Str1
->Buffer
= (PWCHAR
)MyAllocatePool__(NonPagedPool
, Str1
->MaximumLength
);
904 return STATUS_INSUFFICIENT_RESOURCES
;
905 RtlCopyMemory(Str1
->Buffer
, Str2
, i
);
906 Str1
->Buffer
[i
/sizeof(WCHAR
)] = 0;
907 return STATUS_SUCCESS
;
909 } // end MyInitUnicodeString()
912 MyCloneUnicodeString(
913 IN PUNICODE_STRING Str1
,
914 IN PUNICODE_STRING Str2
917 Str1
->MaximumLength
= STRING_BUFFER_ALIGN((Str1
->Length
= Str2
->Length
) + sizeof(WCHAR
));
918 Str1
->Buffer
= (PWCHAR
)MyAllocatePool__(NonPagedPool
, Str1
->MaximumLength
);
920 return STATUS_INSUFFICIENT_RESOURCES
;
921 ASSERT(Str2
->Buffer
);
922 RtlCopyMemory(Str1
->Buffer
, Str2
->Buffer
, Str2
->Length
);
923 Str1
->Buffer
[Str1
->Length
/sizeof(WCHAR
)] = 0;
924 return STATUS_SUCCESS
;
926 } // end MyCloneUnicodeString()
929 This routine checks do we needn't read something from disk to
930 obtain Attributes & so on
935 IN PUDF_FILE_INFO DirInfo
938 PDIR_INDEX_HDR hDirNdx
= DirInfo
->Dloc
->DirIndex
;
939 PDIR_INDEX_ITEM DirNdx
;
940 for(uint_di i
=2; (DirNdx
= UDFDirIndex(hDirNdx
,i
)); i
++) {
941 if(!(DirNdx
->FI_Flags
& UDF_FI_FLAG_SYS_ATTR
) ||
942 (DirNdx
->FI_Flags
& UDF_FI_FLAG_LINKED
)) return FALSE
;
945 } // end UDFIsDirInfoCached()
947 #ifndef UDF_READ_ONLY_BUILD
949 UDFDoesOSAllowFileToBeTargetForRename__(
950 IN PUDF_FILE_INFO FileInfo
957 if(UDFIsADirectory(FileInfo
))
958 return STATUS_ACCESS_DENIED
;
959 if(!FileInfo
->ParentFile
)
960 return STATUS_ACCESS_DENIED
;
962 if(UDFAttributesToNT(UDFDirIndex(UDFGetDirIndexByFileInfo(FileInfo
),FileInfo
->Index
),
963 FileInfo
->Dloc
->FileEntry
) & FILE_ATTRIBUTE_READONLY
)
964 return STATUS_ACCESS_DENIED
;
967 return STATUS_SUCCESS
;
969 RC
= UDFCheckAccessRights(NULL
, NULL
, FileInfo
->Fcb
, NULL
, DELETE
, 0);
974 return STATUS_SUCCESS
;
975 // RC = UDFMarkStreamsForDeletion(FileInfo->Fcb->Vcb, FileInfo->Fcb, TRUE); // Delete
976 /* RC = UDFSetDispositionInformation(FileInfo->Fcb, NULL,
977 FileInfo->Fcb->Vcb, NULL, TRUE);
979 FileInfo->Fcb->FCBFlags |= UDF_FCB_DELETED;
980 if(UDFGetFileLinkCount(FileInfo) <= 1) {
981 FileInfo->Fcb->NTRequiredFCB->NtReqFCBFlags |= UDF_NTREQ_FCB_DELETED;
985 return STATUS_ACCESS_DENIED
;
987 } // end UDFDoesOSAllowFileToBeTargetForRename__()
990 UDFDoesOSAllowFileToBeUnlinked__(
991 IN PUDF_FILE_INFO FileInfo
994 PDIR_INDEX_HDR hCurDirNdx
;
995 PDIR_INDEX_ITEM CurDirNdx
;
997 // IO_STATUS_BLOCK IoStatus;
999 ASSERT(FileInfo
->Dloc
);
1001 if(!FileInfo
->ParentFile
)
1002 return STATUS_CANNOT_DELETE
;
1003 if(FileInfo
->Dloc
->SDirInfo
)
1004 return STATUS_CANNOT_DELETE
;
1005 if(!UDFIsADirectory(FileInfo
))
1006 return STATUS_SUCCESS
;
1008 // UDFFlushAFile(FileInfo->Fcb, NULL, &IoStatus, 0);
1009 hCurDirNdx
= FileInfo
->Dloc
->DirIndex
;
1010 // check if we can delete all files
1011 for(i
=2; (CurDirNdx
= UDFDirIndex(hCurDirNdx
,i
)); i
++) {
1012 // try to open Stream
1013 if(CurDirNdx
->FileInfo
)
1014 return STATUS_CANNOT_DELETE
;
1016 // return UDFCheckAccessRights(NULL, NULL, FileInfo->Fcb, NULL, DELETE, 0);
1017 return STATUS_SUCCESS
;
1018 } // end UDFDoesOSAllowFileToBeUnlinked__()
1021 UDFDoesOSAllowFilePretendDeleted__(
1022 IN PUDF_FILE_INFO FileInfo
1025 PDIR_INDEX_HDR hDirNdx
= UDFGetDirIndexByFileInfo(FileInfo
);
1026 if(!hDirNdx
) return STATUS_CANNOT_DELETE
;
1027 PDIR_INDEX_ITEM DirNdx
= UDFDirIndex(hDirNdx
, FileInfo
->Index
);
1028 if(!DirNdx
) return STATUS_CANNOT_DELETE
;
1029 // we can't hide file that is not marked as deleted
1030 if(!(DirNdx
->FileCharacteristics
& FILE_DELETED
)) {
1034 if(!(FileInfo
->Fcb
->FCBFlags
& (UDF_FCB_DELETE_ON_CLOSE
|
1038 return STATUS_CANNOT_DELETE
;
1040 return STATUS_SUCCESS
;
1042 #endif //UDF_READ_ONLY_BUILD