[RTL][NTDLL]
[reactos.git] / reactos / drivers / filesystems / udfs / Include / Sys_spec_lib.cpp
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;
243 NTSTATUS status;
244 PtrUDFNTRequiredFCB NtReqFcb;
245
246 KdPrint(("@=%#x, FileDirNdx %x\n", &Vcb, FileDirNdx));
247
248 ASSERT((ULONG)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 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"));
258 } _SEH2_END;
259
260 if(FileDirNdx->FileInfo) {
261 KdPrint((" 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 KdPrint((" 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 KdPrint((" 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 KdPrint((" !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 KdPrint((" !UDFReadFileEntry\n"));
306 MyFreePool__(FileEntry);
307 FileEntry = NULL;
308 goto get_name_only;
309 }
310 ReadSizes = TRUE;
311 } else {
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;
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 KdPrint((" direct\n"));
329 if(FileEntry->descTag.tagIdent == TID_FILE_ENTRY) {
330 KdPrint((" TID_FILE_ENTRY\n"));
331 if(ReadSizes) {
332 KdPrint((" 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 KdPrint((" 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 KdPrint((" PEXTENDED_FILE_ENTRY\n"));
355 if(ReadSizes) {
356 KdPrint((" 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 KdPrint((" 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 KdPrint((" ???\n"));
378 goto get_name_only;
379 }
380
381 get_attr_only:
382
383 KdPrint((" 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 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;
412 }
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;
418 }
419 KdPrint((" AllocationSize=%I64x, NTFileInfo->EndOfFile=%I64x", NTFileInfo->AllocationSize.QuadPart, NTFileInfo->EndOfFile.QuadPart));
420 // free tmp buffer (if any)
421 KdPrint(("\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)
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)
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