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