3588b47b20adb22dabc4844b4433751b519e9d6f
[reactos.git] / reactos / drivers / filesystems / ext2 / src / fileinfo.c
1 /*
2 * COPYRIGHT: See COPYRIGHT.TXT
3 * PROJECT: Ext2 File System Driver for WinNT/2K/XP
4 * FILE: fileinfo.c
5 * PROGRAMMER: Matt Wu <mattwu@163.com>
6 * HOMEPAGE: http://www.ext2fsd.com
7 * UPDATE HISTORY:
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include "ext2fs.h"
13 #include <linux/ext4.h>
14
15 /* GLOBALS ***************************************************************/
16
17 extern PEXT2_GLOBAL Ext2Global;
18
19 /* DEFINITIONS *************************************************************/
20
21 #ifdef ALLOC_PRAGMA
22 #pragma alloc_text(PAGE, Ext2QueryFileInformation)
23 #pragma alloc_text(PAGE, Ext2SetFileInformation)
24 #pragma alloc_text(PAGE, Ext2ExpandFile)
25 #pragma alloc_text(PAGE, Ext2TruncateFile)
26 #pragma alloc_text(PAGE, Ext2SetDispositionInfo)
27 #pragma alloc_text(PAGE, Ext2SetRenameInfo)
28 #pragma alloc_text(PAGE, Ext2DeleteFile)
29 #endif
30
31 NTSTATUS
32 Ext2QueryFileInformation (IN PEXT2_IRP_CONTEXT IrpContext)
33 {
34 PDEVICE_OBJECT DeviceObject;
35 NTSTATUS Status = STATUS_UNSUCCESSFUL;
36 PFILE_OBJECT FileObject;
37 PEXT2_VCB Vcb;
38 PEXT2_FCB Fcb;
39 PEXT2_MCB Mcb;
40 PEXT2_CCB Ccb;
41 PIRP Irp;
42 PIO_STACK_LOCATION IoStackLocation;
43 FILE_INFORMATION_CLASS FileInformationClass;
44 ULONG Length;
45 PVOID Buffer;
46 BOOLEAN FcbResourceAcquired = FALSE;
47
48 _SEH2_TRY {
49
50 ASSERT(IrpContext != NULL);
51 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
52 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
53
54 DeviceObject = IrpContext->DeviceObject;
55
56 //
57 // This request is not allowed on the main device object
58 //
59 if (IsExt2FsDevice(DeviceObject)) {
60 Status = STATUS_INVALID_DEVICE_REQUEST;
61 _SEH2_LEAVE;
62 }
63
64 FileObject = IrpContext->FileObject;
65 Fcb = (PEXT2_FCB) FileObject->FsContext;
66 if (Fcb == NULL) {
67 Status = STATUS_INVALID_PARAMETER;
68 _SEH2_LEAVE;
69 }
70
71 //
72 // This request is not allowed on volumes
73 //
74 if (Fcb->Identifier.Type == EXT2VCB) {
75 Status = STATUS_INVALID_PARAMETER;
76 _SEH2_LEAVE;
77 }
78
79 if (!((Fcb->Identifier.Type == EXT2FCB) &&
80 (Fcb->Identifier.Size == sizeof(EXT2_FCB)))) {
81 Status = STATUS_INVALID_PARAMETER;
82 _SEH2_LEAVE;
83 }
84
85 Vcb = Fcb->Vcb;
86
87 {
88 if (!ExAcquireResourceSharedLite(
89 &Fcb->MainResource,
90 IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)
91 )) {
92
93 Status = STATUS_PENDING;
94 _SEH2_LEAVE;
95 }
96
97 FcbResourceAcquired = TRUE;
98 }
99
100 Ccb = (PEXT2_CCB) FileObject->FsContext2;
101 ASSERT(Ccb != NULL);
102 ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
103 (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
104 Mcb = Ccb->SymLink;
105 if (!Mcb)
106 Mcb = Fcb->Mcb;
107
108 Irp = IrpContext->Irp;
109 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
110 FileInformationClass =
111 IoStackLocation->Parameters.QueryFile.FileInformationClass;
112
113 Length = IoStackLocation->Parameters.QueryFile.Length;
114 Buffer = Irp->AssociatedIrp.SystemBuffer;
115 RtlZeroMemory(Buffer, Length);
116
117 switch (FileInformationClass) {
118
119 case FileBasicInformation:
120 {
121 PFILE_BASIC_INFORMATION FileBasicInformation;
122
123 if (Length < sizeof(FILE_BASIC_INFORMATION)) {
124 Status = STATUS_BUFFER_OVERFLOW;
125 _SEH2_LEAVE;
126 }
127
128 FileBasicInformation = (PFILE_BASIC_INFORMATION) Buffer;
129
130 FileBasicInformation->CreationTime = Mcb->CreationTime;
131 FileBasicInformation->LastAccessTime = Mcb->LastAccessTime;
132 FileBasicInformation->LastWriteTime = Mcb->LastWriteTime;
133 FileBasicInformation->ChangeTime = Mcb->ChangeTime;
134
135 FileBasicInformation->FileAttributes = Mcb->FileAttr;
136 if (IsLinkInvalid(Mcb)) {
137 ClearFlag(FileBasicInformation->FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
138 }
139 if (FileBasicInformation->FileAttributes == 0) {
140 FileBasicInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL;
141 }
142
143 Irp->IoStatus.Information = sizeof(FILE_BASIC_INFORMATION);
144 Status = STATUS_SUCCESS;
145 }
146 break;
147
148 case FileStandardInformation:
149 {
150 PFILE_STANDARD_INFORMATION FSI;
151
152 if (Length < sizeof(FILE_STANDARD_INFORMATION)) {
153 Status = STATUS_BUFFER_OVERFLOW;
154 _SEH2_LEAVE;
155 }
156
157 FSI = (PFILE_STANDARD_INFORMATION) Buffer;
158
159 FSI->NumberOfLinks = Mcb->Inode.i_nlink;
160
161 if (IsVcbReadOnly(Fcb->Vcb))
162 FSI->DeletePending = FALSE;
163 else
164 FSI->DeletePending = IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING);
165
166 if (IsLinkInvalid(Mcb)) {
167 FSI->Directory = FALSE;
168 FSI->AllocationSize.QuadPart = 0;
169 FSI->EndOfFile.QuadPart = 0;
170 } else if (IsMcbDirectory(Mcb)) {
171 FSI->Directory = TRUE;
172 FSI->AllocationSize.QuadPart = 0;
173 FSI->EndOfFile.QuadPart = 0;
174 } else {
175 FSI->Directory = FALSE;
176 FSI->AllocationSize = Fcb->Header.AllocationSize;
177 FSI->EndOfFile = Fcb->Header.FileSize;
178 }
179
180 Irp->IoStatus.Information = sizeof(FILE_STANDARD_INFORMATION);
181 Status = STATUS_SUCCESS;
182 }
183 break;
184
185 case FileInternalInformation:
186 {
187 PFILE_INTERNAL_INFORMATION FileInternalInformation;
188
189 if (Length < sizeof(FILE_INTERNAL_INFORMATION)) {
190 Status = STATUS_BUFFER_OVERFLOW;
191 _SEH2_LEAVE;
192 }
193
194 FileInternalInformation = (PFILE_INTERNAL_INFORMATION) Buffer;
195
196 /* we use the inode number as the internal index */
197 FileInternalInformation->IndexNumber.QuadPart = (LONGLONG)Mcb->Inode.i_ino;
198
199 Irp->IoStatus.Information = sizeof(FILE_INTERNAL_INFORMATION);
200 Status = STATUS_SUCCESS;
201 }
202 break;
203
204
205 case FileEaInformation:
206 {
207 PFILE_EA_INFORMATION FileEaInformation;
208
209 if (Length < sizeof(FILE_EA_INFORMATION)) {
210 Status = STATUS_BUFFER_OVERFLOW;
211 _SEH2_LEAVE;
212 }
213
214 FileEaInformation = (PFILE_EA_INFORMATION) Buffer;
215
216 // Romfs doesn't have any extended attributes
217 FileEaInformation->EaSize = 0;
218
219 Irp->IoStatus.Information = sizeof(FILE_EA_INFORMATION);
220 Status = STATUS_SUCCESS;
221 }
222 break;
223
224 case FileNameInformation:
225 {
226 PFILE_NAME_INFORMATION FileNameInformation;
227 ULONG BytesToCopy = 0;
228
229 if (Length < (ULONG)FIELD_OFFSET(FILE_NAME_INFORMATION, FileName) +
230 Mcb->FullName.Length) {
231 BytesToCopy = Length - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
232 Status = STATUS_BUFFER_OVERFLOW;
233 } else {
234 BytesToCopy = Mcb->FullName.Length;
235 Status = STATUS_SUCCESS;
236 }
237
238 FileNameInformation = (PFILE_NAME_INFORMATION) Buffer;
239 FileNameInformation->FileNameLength = Mcb->FullName.Length;
240
241 RtlCopyMemory(
242 FileNameInformation->FileName,
243 Mcb->FullName.Buffer,
244 BytesToCopy );
245
246 Irp->IoStatus.Information = BytesToCopy +
247 + FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
248 }
249 break;
250
251 case FilePositionInformation:
252 {
253 PFILE_POSITION_INFORMATION FilePositionInformation;
254
255 if (Length < sizeof(FILE_POSITION_INFORMATION)) {
256 Status = STATUS_BUFFER_OVERFLOW;
257 _SEH2_LEAVE;
258 }
259
260 FilePositionInformation = (PFILE_POSITION_INFORMATION) Buffer;
261 FilePositionInformation->CurrentByteOffset =
262 FileObject->CurrentByteOffset;
263
264 Irp->IoStatus.Information = sizeof(FILE_POSITION_INFORMATION);
265 Status = STATUS_SUCCESS;
266 }
267 break;
268
269 case FileAllInformation:
270 {
271 PFILE_ALL_INFORMATION FileAllInformation;
272 PFILE_BASIC_INFORMATION FileBasicInformation;
273 PFILE_STANDARD_INFORMATION FSI;
274 PFILE_INTERNAL_INFORMATION FileInternalInformation;
275 PFILE_EA_INFORMATION FileEaInformation;
276 PFILE_POSITION_INFORMATION FilePositionInformation;
277 PFILE_NAME_INFORMATION FileNameInformation;
278
279 if (Length < sizeof(FILE_ALL_INFORMATION)) {
280 Status = STATUS_BUFFER_OVERFLOW;
281 _SEH2_LEAVE;
282 }
283
284 FileAllInformation = (PFILE_ALL_INFORMATION) Buffer;
285
286 FileBasicInformation =
287 &FileAllInformation->BasicInformation;
288
289 FSI =
290 &FileAllInformation->StandardInformation;
291
292 FileInternalInformation =
293 &FileAllInformation->InternalInformation;
294
295 FileEaInformation =
296 &FileAllInformation->EaInformation;
297
298 FilePositionInformation =
299 &FileAllInformation->PositionInformation;
300
301 FileNameInformation =
302 &FileAllInformation->NameInformation;
303
304 FileBasicInformation->CreationTime = Mcb->CreationTime;
305 FileBasicInformation->LastAccessTime = Mcb->LastAccessTime;
306 FileBasicInformation->LastWriteTime = Mcb->LastWriteTime;
307 FileBasicInformation->ChangeTime = Mcb->ChangeTime;
308
309 FileBasicInformation->FileAttributes = Mcb->FileAttr;
310 if (IsMcbSymLink(Mcb) && IsFileDeleted(Mcb->Target)) {
311 ClearFlag(FileBasicInformation->FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
312 }
313 if (FileBasicInformation->FileAttributes == 0) {
314 FileBasicInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL;
315 }
316
317 FSI->NumberOfLinks = Mcb->Inode.i_nlink;
318
319 if (IsVcbReadOnly(Fcb->Vcb))
320 FSI->DeletePending = FALSE;
321 else
322 FSI->DeletePending = IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING);
323
324 if (IsLinkInvalid(Mcb)) {
325 FSI->Directory = FALSE;
326 FSI->AllocationSize.QuadPart = 0;
327 FSI->EndOfFile.QuadPart = 0;
328 } else if (IsDirectory(Fcb)) {
329 FSI->Directory = TRUE;
330 FSI->AllocationSize.QuadPart = 0;
331 FSI->EndOfFile.QuadPart = 0;
332 } else {
333 FSI->Directory = FALSE;
334 FSI->AllocationSize = Fcb->Header.AllocationSize;
335 FSI->EndOfFile = Fcb->Header.FileSize;
336 }
337
338 // The "inode number"
339 FileInternalInformation->IndexNumber.QuadPart = (LONGLONG)Mcb->Inode.i_ino;
340
341 // Romfs doesn't have any extended attributes
342 FileEaInformation->EaSize = 0;
343
344 FilePositionInformation->CurrentByteOffset =
345 FileObject->CurrentByteOffset;
346
347 FileNameInformation->FileNameLength = Mcb->ShortName.Length;
348
349 if (Length < sizeof(FILE_ALL_INFORMATION) +
350 Mcb->ShortName.Length - sizeof(WCHAR)) {
351 Irp->IoStatus.Information = sizeof(FILE_ALL_INFORMATION);
352 Status = STATUS_BUFFER_OVERFLOW;
353 RtlCopyMemory(
354 FileNameInformation->FileName,
355 Mcb->ShortName.Buffer,
356 Length - FIELD_OFFSET(FILE_ALL_INFORMATION,
357 NameInformation.FileName)
358 );
359 _SEH2_LEAVE;
360 }
361
362 RtlCopyMemory(
363 FileNameInformation->FileName,
364 Mcb->ShortName.Buffer,
365 Mcb->ShortName.Length
366 );
367
368 Irp->IoStatus.Information = sizeof(FILE_ALL_INFORMATION) +
369 Mcb->ShortName.Length - sizeof(WCHAR);
370 #if 0
371 sizeof(FILE_ACCESS_INFORMATION) -
372 sizeof(FILE_MODE_INFORMATION) -
373 sizeof(FILE_ALIGNMENT_INFORMATION);
374 #endif
375
376 Status = STATUS_SUCCESS;
377 }
378 break;
379
380 /*
381 case FileAlternateNameInformation:
382 {
383 // TODO: Handle FileAlternateNameInformation
384
385 // Here we would like to use RtlGenerate8dot3Name but I don't
386 // know how to use the argument PGENERATE_NAME_CONTEXT
387 }
388 */
389
390 case FileNetworkOpenInformation:
391 {
392 PFILE_NETWORK_OPEN_INFORMATION PFNOI;
393
394 if (Length < sizeof(FILE_NETWORK_OPEN_INFORMATION)) {
395 Status = STATUS_BUFFER_OVERFLOW;
396 _SEH2_LEAVE;
397 }
398
399 PFNOI = (PFILE_NETWORK_OPEN_INFORMATION) Buffer;
400
401 PFNOI->FileAttributes = Mcb->FileAttr;
402 if (IsLinkInvalid(Mcb)) {
403 ClearFlag(PFNOI->FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
404 PFNOI->AllocationSize.QuadPart = 0;
405 PFNOI->EndOfFile.QuadPart = 0;
406 } else if (IsDirectory(Fcb)) {
407 PFNOI->AllocationSize.QuadPart = 0;
408 PFNOI->EndOfFile.QuadPart = 0;
409 } else {
410 PFNOI->AllocationSize = Fcb->Header.AllocationSize;
411 PFNOI->EndOfFile = Fcb->Header.FileSize;
412 }
413
414 if (PFNOI->FileAttributes == 0) {
415 PFNOI->FileAttributes = FILE_ATTRIBUTE_NORMAL;
416 }
417
418 PFNOI->CreationTime = Mcb->CreationTime;
419 PFNOI->LastAccessTime = Mcb->LastAccessTime;
420 PFNOI->LastWriteTime = Mcb->LastWriteTime;
421 PFNOI->ChangeTime = Mcb->ChangeTime;
422
423
424 Irp->IoStatus.Information =
425 sizeof(FILE_NETWORK_OPEN_INFORMATION);
426 Status = STATUS_SUCCESS;
427 }
428 break;
429
430 #if (_WIN32_WINNT >= 0x0500)
431
432 case FileAttributeTagInformation:
433 {
434 PFILE_ATTRIBUTE_TAG_INFORMATION FATI;
435
436 if (Length < sizeof(FILE_ATTRIBUTE_TAG_INFORMATION)) {
437 Status = STATUS_BUFFER_OVERFLOW;
438 _SEH2_LEAVE;
439 }
440
441 FATI = (PFILE_ATTRIBUTE_TAG_INFORMATION) Buffer;
442 FATI->FileAttributes = Mcb->FileAttr;
443 if (IsLinkInvalid(Mcb)) {
444 ClearFlag(FATI->FileAttributes, FILE_ATTRIBUTE_DIRECTORY);
445 }
446 if (FATI->FileAttributes == 0) {
447 FATI->FileAttributes = FILE_ATTRIBUTE_NORMAL;
448 }
449 FATI->ReparseTag = IO_REPARSE_TAG_RESERVED_ZERO;
450 Irp->IoStatus.Information = sizeof(FILE_ATTRIBUTE_TAG_INFORMATION);
451 Status = STATUS_SUCCESS;
452 }
453 break;
454 #endif // (_WIN32_WINNT >= 0x0500)
455
456 case FileStreamInformation:
457 Status = STATUS_INVALID_PARAMETER;
458 break;
459
460 default:
461 DEBUG(DL_WRN, ( "Ext2QueryInformation: invalid class: %d\n",
462 FileInformationClass));
463 Status = STATUS_INVALID_PARAMETER; /* STATUS_INVALID_INFO_CLASS; */
464 break;
465 }
466
467 } _SEH2_FINALLY {
468
469 if (FcbResourceAcquired) {
470 ExReleaseResourceLite(&Fcb->MainResource);
471 }
472
473 if (!IrpContext->ExceptionInProgress) {
474 if (Status == STATUS_PENDING ||
475 Status == STATUS_CANT_WAIT) {
476 Status = Ext2QueueRequest(IrpContext);
477 } else {
478 Ext2CompleteIrpContext(IrpContext, Status);
479 }
480 }
481 } _SEH2_END;
482
483 return Status;
484 }
485
486
487 NTSTATUS
488 Ext2SetFileInformation (IN PEXT2_IRP_CONTEXT IrpContext)
489 {
490 PDEVICE_OBJECT DeviceObject;
491 NTSTATUS Status = STATUS_UNSUCCESSFUL;
492 PEXT2_VCB Vcb;
493 PFILE_OBJECT FileObject;
494 PEXT2_FCB Fcb;
495 PEXT2_CCB Ccb;
496 PEXT2_MCB Mcb;
497 PIRP Irp;
498 PIO_STACK_LOCATION IoStackLocation;
499 FILE_INFORMATION_CLASS FileInformationClass;
500
501 ULONG NotifyFilter = 0;
502
503 ULONG Length;
504 PVOID Buffer;
505
506 BOOLEAN VcbMainResourceAcquired = FALSE;
507 BOOLEAN FcbMainResourceAcquired = FALSE;
508 BOOLEAN FcbPagingIoResourceAcquired = FALSE;
509
510 _SEH2_TRY {
511
512 ASSERT(IrpContext != NULL);
513
514 ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
515 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
516 DeviceObject = IrpContext->DeviceObject;
517
518 //
519 // This request is not allowed on the main device object
520 //
521 if (IsExt2FsDevice(DeviceObject)) {
522 Status = STATUS_INVALID_DEVICE_REQUEST;
523 _SEH2_LEAVE;
524 }
525
526 /* check io stack location of irp stack */
527 Irp = IrpContext->Irp;
528 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
529 FileInformationClass =
530 IoStackLocation->Parameters.SetFile.FileInformationClass;
531 Length = IoStackLocation->Parameters.SetFile.Length;
532 Buffer = Irp->AssociatedIrp.SystemBuffer;
533
534 /* check Vcb */
535 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
536 ASSERT(Vcb != NULL);
537 ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
538 (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
539 if (!IsMounted(Vcb)) {
540 Status = STATUS_INVALID_DEVICE_REQUEST;
541 _SEH2_LEAVE;
542 }
543
544 /* we need grab Vcb in case it's a rename operation */
545 if (FileInformationClass == FileRenameInformation) {
546 if (!ExAcquireResourceExclusiveLite(
547 &Vcb->MainResource,
548 IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
549 Status = STATUS_PENDING;
550 _SEH2_LEAVE;
551 }
552 VcbMainResourceAcquired = TRUE;
553 }
554
555 if (IsVcbReadOnly(Vcb)) {
556 if (FileInformationClass != FilePositionInformation) {
557 Status = STATUS_MEDIA_WRITE_PROTECTED;
558 _SEH2_LEAVE;
559 }
560 }
561
562 if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) {
563 Status = STATUS_ACCESS_DENIED;
564 _SEH2_LEAVE;
565 }
566
567 FileObject = IrpContext->FileObject;
568 Fcb = (PEXT2_FCB) FileObject->FsContext;
569
570 // This request is issued to volumes, just return success
571 if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
572 Status = STATUS_SUCCESS;
573 _SEH2_LEAVE;
574 }
575 ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
576 (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
577
578 if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) {
579 Status = STATUS_FILE_DELETED;
580 _SEH2_LEAVE;
581 }
582
583 Ccb = (PEXT2_CCB) FileObject->FsContext2;
584 ASSERT(Ccb != NULL);
585 ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
586 (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
587 Mcb = Ccb->SymLink;
588 if (Mcb) {
589 if (IsFlagOn(Mcb->Flags, MCB_FILE_DELETED)) {
590 Status = STATUS_FILE_DELETED;
591 _SEH2_LEAVE;
592 }
593 } else {
594 Mcb = Fcb->Mcb;
595 }
596
597 if ( !IsDirectory(Fcb) && !FlagOn(Fcb->Flags, FCB_PAGE_FILE) &&
598 ((FileInformationClass == FileEndOfFileInformation) ||
599 (FileInformationClass == FileValidDataLengthInformation) ||
600 (FileInformationClass == FileAllocationInformation))) {
601
602 Status = FsRtlCheckOplock( &Fcb->Oplock,
603 Irp,
604 IrpContext,
605 NULL,
606 NULL );
607
608 if (Status != STATUS_SUCCESS) {
609 _SEH2_LEAVE;
610 }
611
612 //
613 // Set the flag indicating if Fast I/O is possible
614 //
615
616 Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb);
617 }
618
619 /* for renaming, we must not get any Fcb locks here, function
620 Ext2SetRenameInfo will get Dcb resource exclusively. */
621 if (!IsFlagOn(Fcb->Flags, FCB_PAGE_FILE) &&
622 FileInformationClass != FileRenameInformation) {
623
624 if (!ExAcquireResourceExclusiveLite(
625 &Fcb->MainResource,
626 IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
627 Status = STATUS_PENDING;
628 _SEH2_LEAVE;
629 }
630
631 FcbMainResourceAcquired = TRUE;
632
633 if ( FileInformationClass == FileAllocationInformation ||
634 FileInformationClass == FileEndOfFileInformation ||
635 FileInformationClass == FileValidDataLengthInformation) {
636
637 if (!ExAcquireResourceExclusiveLite(
638 &Fcb->PagingIoResource,
639 IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
640 Status = STATUS_PENDING;
641 DbgBreak();
642 _SEH2_LEAVE;
643 }
644 FcbPagingIoResourceAcquired = TRUE;
645 }
646 }
647
648 switch (FileInformationClass) {
649
650 case FileBasicInformation:
651 {
652 PFILE_BASIC_INFORMATION FBI = (PFILE_BASIC_INFORMATION) Buffer;
653 struct inode *Inode = &Mcb->Inode;
654
655 if (FBI->CreationTime.QuadPart != 0 && FBI->CreationTime.QuadPart != -1) {
656 Inode->i_ctime = Ext2LinuxTime(FBI->CreationTime);
657 Mcb->CreationTime = Ext2NtTime(Inode->i_ctime);
658 NotifyFilter |= FILE_NOTIFY_CHANGE_CREATION;
659 }
660
661 if (FBI->LastAccessTime.QuadPart != 0 && FBI->LastAccessTime.QuadPart != -1) {
662 Inode->i_atime = Ext2LinuxTime(FBI->LastAccessTime);
663 Mcb->LastAccessTime = Ext2NtTime(Inode->i_atime);
664 NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
665 }
666
667 if (FBI->LastWriteTime.QuadPart != 0 && FBI->LastWriteTime.QuadPart != -1) {
668 Inode->i_mtime = Ext2LinuxTime(FBI->LastWriteTime);
669 Mcb->LastWriteTime = Ext2NtTime(Inode->i_mtime);
670 NotifyFilter |= FILE_NOTIFY_CHANGE_LAST_WRITE;
671 SetFlag(Ccb->Flags, CCB_LAST_WRITE_UPDATED);
672 }
673
674 if (FBI->ChangeTime.QuadPart !=0 && FBI->ChangeTime.QuadPart != -1) {
675 Mcb->ChangeTime = FBI->ChangeTime;
676 }
677
678 if (FBI->FileAttributes != 0) {
679
680 BOOLEAN bIsDirectory = IsDirectory(Fcb);
681 NotifyFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES;
682
683 if (IsFlagOn(FBI->FileAttributes, FILE_ATTRIBUTE_READONLY)) {
684 Ext2SetOwnerReadOnly(Inode->i_mode);
685 } else {
686 Ext2SetOwnerWritable(Inode->i_mode);
687 }
688
689 if (FBI->FileAttributes & FILE_ATTRIBUTE_TEMPORARY) {
690 SetFlag(FileObject->Flags, FO_TEMPORARY_FILE);
691 } else {
692 ClearFlag(FileObject->Flags, FO_TEMPORARY_FILE);
693 }
694
695 Mcb->FileAttr = FBI->FileAttributes;
696 if (bIsDirectory) {
697 SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY);
698 ClearFlag(Mcb->FileAttr, FILE_ATTRIBUTE_NORMAL);
699 }
700 }
701
702 if (NotifyFilter != 0) {
703 if (Ext2SaveInode(IrpContext, Vcb, Inode)) {
704 Status = STATUS_SUCCESS;
705 }
706 }
707
708 ClearFlag(NotifyFilter, FILE_NOTIFY_CHANGE_LAST_ACCESS);
709 Status = STATUS_SUCCESS;
710 }
711
712 break;
713
714 case FileAllocationInformation:
715 {
716 PFILE_ALLOCATION_INFORMATION FAI = (PFILE_ALLOCATION_INFORMATION)Buffer;
717 LARGE_INTEGER AllocationSize;
718
719 if (IsMcbDirectory(Mcb) || IsMcbSpecialFile(Mcb)) {
720 Status = STATUS_INVALID_DEVICE_REQUEST;
721 _SEH2_LEAVE;
722 } else {
723 Status = STATUS_SUCCESS;
724 }
725
726 /* set Mcb to it's target */
727 if (IsMcbSymLink(Mcb)) {
728 ASSERT(Fcb->Mcb == Mcb->Target);
729 }
730 Mcb = Fcb->Mcb;
731
732 /* get user specified allocationsize aligned with BLOCK_SIZE */
733 AllocationSize.QuadPart = CEILING_ALIGNED(ULONGLONG,
734 (ULONGLONG)FAI->AllocationSize.QuadPart,
735 (ULONGLONG)BLOCK_SIZE);
736
737 if (AllocationSize.QuadPart > Fcb->Header.AllocationSize.QuadPart) {
738
739 Status = Ext2ExpandFile(IrpContext, Vcb, Mcb, &AllocationSize);
740 Fcb->Header.AllocationSize = AllocationSize;
741 NotifyFilter = FILE_NOTIFY_CHANGE_SIZE;
742 SetLongFlag(Fcb->Flags, FCB_ALLOC_IN_SETINFO);
743
744 } else if (AllocationSize.QuadPart < Fcb->Header.AllocationSize.QuadPart) {
745
746 if (MmCanFileBeTruncated(&(Fcb->SectionObject), &AllocationSize)) {
747
748 /* truncate file blocks */
749 Status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &AllocationSize);
750
751 if (NT_SUCCESS(Status)) {
752 ClearLongFlag(Fcb->Flags, FCB_ALLOC_IN_CREATE);
753 }
754
755 NotifyFilter = FILE_NOTIFY_CHANGE_SIZE;
756 Fcb->Header.AllocationSize.QuadPart = AllocationSize.QuadPart;
757 if (Mcb->Inode.i_size > (loff_t)AllocationSize.QuadPart) {
758 Mcb->Inode.i_size = AllocationSize.QuadPart;
759 }
760 Fcb->Header.FileSize.QuadPart = Mcb->Inode.i_size;
761 if (Fcb->Header.ValidDataLength.QuadPart > Fcb->Header.FileSize.QuadPart) {
762 Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
763 }
764
765 } else {
766
767 Status = STATUS_USER_MAPPED_FILE;
768 DbgBreak();
769 _SEH2_LEAVE;
770 }
771 }
772
773 if (NotifyFilter) {
774
775 SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
776 SetLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);
777 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
778 if (CcIsFileCached(FileObject)) {
779 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
780 }
781 }
782
783 DEBUG(DL_IO, ("Ext2SetInformation: %wZ NewSize=%I64xh AllocationSize=%I64xh "
784 "FileSize=%I64xh VDL=%I64xh i_size=%I64xh status = %xh\n",
785 &Fcb->Mcb->ShortName, AllocationSize.QuadPart,
786 Fcb->Header.AllocationSize.QuadPart,
787 Fcb->Header.FileSize.QuadPart, Fcb->Header.ValidDataLength.QuadPart,
788 Mcb->Inode.i_size, Status));
789 }
790
791 break;
792
793 case FileEndOfFileInformation:
794 {
795 PFILE_END_OF_FILE_INFORMATION FEOFI = (PFILE_END_OF_FILE_INFORMATION) Buffer;
796 LARGE_INTEGER NewSize, OldSize, EndOfFile;
797
798 if (IsMcbDirectory(Mcb) || IsMcbSpecialFile(Mcb)) {
799 Status = STATUS_INVALID_DEVICE_REQUEST;
800 _SEH2_LEAVE;
801 } else {
802 Status = STATUS_SUCCESS;
803 }
804
805 /* set Mcb to it's target */
806 if (IsMcbSymLink(Mcb)) {
807 ASSERT(Fcb->Mcb == Mcb->Target);
808 }
809 Mcb = Fcb->Mcb;
810
811 OldSize = Fcb->Header.AllocationSize;
812 EndOfFile = FEOFI->EndOfFile;
813
814 if (IoStackLocation->Parameters.SetFile.AdvanceOnly) {
815
816 if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {
817 _SEH2_LEAVE;
818 }
819
820 if (EndOfFile.QuadPart > Fcb->Header.FileSize.QuadPart) {
821 EndOfFile.QuadPart = Fcb->Header.FileSize.QuadPart;
822 }
823
824 if (EndOfFile.QuadPart > Fcb->Header.ValidDataLength.QuadPart) {
825 Fcb->Header.ValidDataLength.QuadPart = EndOfFile.QuadPart;
826 NotifyFilter = FILE_NOTIFY_CHANGE_SIZE;
827 }
828
829 _SEH2_LEAVE;
830 }
831
832 NewSize.QuadPart = CEILING_ALIGNED(ULONGLONG,
833 EndOfFile.QuadPart, BLOCK_SIZE);
834
835 if (NewSize.QuadPart > OldSize.QuadPart) {
836
837 Fcb->Header.AllocationSize = NewSize;
838 Status = Ext2ExpandFile(
839 IrpContext,
840 Vcb,
841 Mcb,
842 &(Fcb->Header.AllocationSize)
843 );
844 NotifyFilter = FILE_NOTIFY_CHANGE_SIZE;
845 SetLongFlag(Fcb->Flags, FCB_ALLOC_IN_SETINFO);
846
847
848 } else if (NewSize.QuadPart == OldSize.QuadPart) {
849
850 /* we are luck ;) */
851 Status = STATUS_SUCCESS;
852
853 } else {
854
855 /* don't truncate file data since it's still being written */
856 if (IsFlagOn(Fcb->Flags, FCB_ALLOC_IN_WRITE)) {
857
858 Status = STATUS_SUCCESS;
859
860 } else {
861
862 if (!MmCanFileBeTruncated(&(Fcb->SectionObject), &NewSize)) {
863 Status = STATUS_USER_MAPPED_FILE;
864 DbgBreak();
865 _SEH2_LEAVE;
866 }
867
868 /* truncate file blocks */
869 Status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &NewSize);
870
871 /* restore original file size */
872 if (NT_SUCCESS(Status)) {
873 ClearLongFlag(Fcb->Flags, FCB_ALLOC_IN_CREATE);
874 }
875
876 /* update file allocateion size */
877 Fcb->Header.AllocationSize.QuadPart = NewSize.QuadPart;
878
879 ASSERT((loff_t)NewSize.QuadPart >= Mcb->Inode.i_size);
880 if ((loff_t)Fcb->Header.FileSize.QuadPart < Mcb->Inode.i_size) {
881 Fcb->Header.FileSize.QuadPart = Mcb->Inode.i_size;
882 }
883 if (Fcb->Header.ValidDataLength.QuadPart > Fcb->Header.FileSize.QuadPart) {
884 Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
885 }
886
887 SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
888 SetLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);
889 }
890
891 NotifyFilter = FILE_NOTIFY_CHANGE_SIZE;
892 }
893
894 if (NT_SUCCESS(Status)) {
895
896 Fcb->Header.FileSize.QuadPart = Mcb->Inode.i_size = EndOfFile.QuadPart;
897 if (CcIsFileCached(FileObject)) {
898 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
899 }
900
901 if (Fcb->Header.FileSize.QuadPart >= 0x80000000 &&
902 !IsFlagOn(SUPER_BLOCK->s_feature_ro_compat, EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) {
903 SetFlag(SUPER_BLOCK->s_feature_ro_compat, EXT2_FEATURE_RO_COMPAT_LARGE_FILE);
904 Ext2SaveSuper(IrpContext, Vcb);
905 }
906
907 SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
908 SetLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);
909 NotifyFilter = FILE_NOTIFY_CHANGE_SIZE;
910 }
911
912
913 Ext2SaveInode( IrpContext, Vcb, &Mcb->Inode);
914
915 DEBUG(DL_IO, ("Ext2SetInformation: FileEndOfFileInformation %wZ EndofFile=%I64xh "
916 "AllocatieonSize=%I64xh FileSize=%I64xh VDL=%I64xh i_size=%I64xh status = %xh\n",
917 &Fcb->Mcb->ShortName, EndOfFile.QuadPart, Fcb->Header.AllocationSize.QuadPart,
918 Fcb->Header.FileSize.QuadPart, Fcb->Header.ValidDataLength.QuadPart,
919 Mcb->Inode.i_size, Status));
920 }
921
922 break;
923
924 case FileValidDataLengthInformation:
925 {
926 PFILE_VALID_DATA_LENGTH_INFORMATION FVDL = (PFILE_VALID_DATA_LENGTH_INFORMATION) Buffer;
927 LARGE_INTEGER NewVDL;
928
929 if (IsMcbDirectory(Mcb) || IsMcbSpecialFile(Mcb)) {
930 Status = STATUS_INVALID_DEVICE_REQUEST;
931 _SEH2_LEAVE;
932 } else {
933 Status = STATUS_SUCCESS;
934 }
935
936 NewVDL = FVDL->ValidDataLength;
937 if ((NewVDL.QuadPart < Fcb->Header.ValidDataLength.QuadPart)) {
938 Status = STATUS_INVALID_PARAMETER;
939 _SEH2_LEAVE;
940 }
941 if (NewVDL.QuadPart > Fcb->Header.FileSize.QuadPart)
942 NewVDL = Fcb->Header.FileSize;
943
944 if (!MmCanFileBeTruncated(FileObject->SectionObjectPointer,
945 &NewVDL)) {
946 Status = STATUS_USER_MAPPED_FILE;
947 _SEH2_LEAVE;
948 }
949
950 Fcb->Header.ValidDataLength = NewVDL;
951 FileObject->Flags |= FO_FILE_MODIFIED;
952 if (CcIsFileCached(FileObject)) {
953 CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
954 }
955 }
956
957 break;
958
959 case FileDispositionInformation:
960 {
961 PFILE_DISPOSITION_INFORMATION FDI = (PFILE_DISPOSITION_INFORMATION)Buffer;
962
963 Status = Ext2SetDispositionInfo(IrpContext, Vcb, Fcb, Ccb, FDI->DeleteFile);
964
965 DEBUG(DL_INF, ( "Ext2SetInformation: SetDispositionInformation: DeleteFile=%d %wZ status = %xh\n",
966 FDI->DeleteFile, &Mcb->ShortName, Status));
967 }
968
969 break;
970
971 case FileRenameInformation:
972 {
973 Status = Ext2SetRenameInfo(IrpContext, Vcb, Fcb, Ccb);
974 }
975
976 break;
977
978 //
979 // This is the only set file information request supported on read
980 // only file systems
981 //
982 case FilePositionInformation:
983 {
984 PFILE_POSITION_INFORMATION FilePositionInformation;
985
986 if (Length < sizeof(FILE_POSITION_INFORMATION)) {
987 Status = STATUS_INVALID_PARAMETER;
988 _SEH2_LEAVE;
989 }
990
991 FilePositionInformation = (PFILE_POSITION_INFORMATION) Buffer;
992
993 if ((FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) &&
994 (FilePositionInformation->CurrentByteOffset.LowPart &
995 DeviceObject->AlignmentRequirement) ) {
996 Status = STATUS_INVALID_PARAMETER;
997 _SEH2_LEAVE;
998 }
999
1000 FileObject->CurrentByteOffset =
1001 FilePositionInformation->CurrentByteOffset;
1002
1003 Status = STATUS_SUCCESS;
1004 _SEH2_LEAVE;
1005 }
1006
1007 break;
1008
1009 case FileLinkInformation:
1010
1011 Status = STATUS_INVALID_DEVICE_REQUEST;
1012 break;
1013
1014 default:
1015 DEBUG(DL_WRN, ( "Ext2SetInformation: invalid class: %d\n",
1016 FileInformationClass));
1017 Status = STATUS_INVALID_PARAMETER;/* STATUS_INVALID_INFO_CLASS; */
1018 }
1019
1020 } _SEH2_FINALLY {
1021
1022 if (FcbPagingIoResourceAcquired) {
1023 ExReleaseResourceLite(&Fcb->PagingIoResource);
1024 }
1025
1026 if (NT_SUCCESS(Status) && (NotifyFilter != 0)) {
1027 Ext2NotifyReportChange(
1028 IrpContext,
1029 Vcb,
1030 Mcb,
1031 NotifyFilter,
1032 FILE_ACTION_MODIFIED );
1033
1034 }
1035
1036 if (FcbMainResourceAcquired) {
1037 ExReleaseResourceLite(&Fcb->MainResource);
1038 }
1039
1040 if (VcbMainResourceAcquired) {
1041 ExReleaseResourceLite(&Vcb->MainResource);
1042 }
1043
1044 if (!IrpContext->ExceptionInProgress) {
1045 if (Status == STATUS_PENDING ||
1046 Status == STATUS_CANT_WAIT ) {
1047 DbgBreak();
1048 Status = Ext2QueueRequest(IrpContext);
1049 } else {
1050 Ext2CompleteIrpContext(IrpContext, Status);
1051 }
1052 }
1053 } _SEH2_END;
1054
1055 return Status;
1056 }
1057
1058 ULONG
1059 Ext2TotalBlocks(
1060 PEXT2_VCB Vcb,
1061 PLARGE_INTEGER Size,
1062 PULONG pMeta
1063 )
1064 {
1065 ULONG Blocks, Meta =0, Remain;
1066
1067 Blocks = (ULONG)((Size->QuadPart + BLOCK_SIZE - 1) >> BLOCK_BITS);
1068 if (Blocks <= EXT2_NDIR_BLOCKS)
1069 goto errorout;
1070 Blocks -= EXT2_NDIR_BLOCKS;
1071
1072 Meta += 1;
1073 if (Blocks <= Vcb->max_blocks_per_layer[1]) {
1074 goto errorout;
1075 }
1076 Blocks -= Vcb->max_blocks_per_layer[1];
1077
1078 level2:
1079
1080 if (Blocks <= Vcb->max_blocks_per_layer[2]) {
1081 Meta += 1 + ((Blocks + BLOCK_SIZE/4 - 1) >> (BLOCK_BITS - 2));
1082 goto errorout;
1083 }
1084 Meta += 1 + BLOCK_SIZE/4;
1085 Blocks -= Vcb->max_blocks_per_layer[2];
1086
1087 if (Blocks > Vcb->max_blocks_per_layer[3]) {
1088 Blocks = Vcb->max_blocks_per_layer[3];
1089 }
1090
1091 ASSERT(Vcb->max_blocks_per_layer[2]);
1092 Remain = Blocks % Vcb->max_blocks_per_layer[2];
1093 Blocks = Blocks / Vcb->max_blocks_per_layer[2];
1094 Meta += 1 + Blocks * (1 + BLOCK_SIZE/4);
1095 if (Remain) {
1096 Blocks = Remain;
1097 goto level2;
1098 }
1099
1100 errorout:
1101
1102 if (pMeta)
1103 *pMeta = Meta;
1104 Blocks = (ULONG)((Size->QuadPart + BLOCK_SIZE - 1) >> BLOCK_BITS);
1105 return (Blocks + Meta);
1106 }
1107
1108 NTSTATUS
1109 Ext2BlockMap(
1110 IN PEXT2_IRP_CONTEXT IrpContext,
1111 IN PEXT2_VCB Vcb,
1112 IN PEXT2_MCB Mcb,
1113 IN ULONG Index,
1114 IN BOOLEAN bAlloc,
1115 OUT PULONG pBlock,
1116 OUT PULONG Number
1117 )
1118 {
1119 NTSTATUS status;
1120
1121 if (INODE_HAS_EXTENT(&Mcb->Inode)) {
1122 status = Ext2MapExtent(IrpContext, Vcb, Mcb, Index,
1123 bAlloc, pBlock, Number );
1124 } else {
1125 status = Ext2MapIndirect(IrpContext, Vcb, Mcb, Index,
1126 bAlloc, pBlock, Number );
1127 }
1128
1129 return status;
1130 }
1131
1132
1133 NTSTATUS
1134 Ext2ExpandFile(
1135 PEXT2_IRP_CONTEXT IrpContext,
1136 PEXT2_VCB Vcb,
1137 PEXT2_MCB Mcb,
1138 PLARGE_INTEGER Size
1139 )
1140 {
1141 NTSTATUS status = STATUS_SUCCESS;
1142 ULONG Start = 0;
1143 ULONG End = 0;
1144
1145 Start = (ULONG)((Mcb->Inode.i_size + BLOCK_SIZE - 1) >> BLOCK_BITS);
1146 End = (ULONG)((Size->QuadPart + BLOCK_SIZE - 1) >> BLOCK_BITS);
1147
1148 /* it's a truncate operation, not expanding */
1149 if (Start >= End) {
1150 Size->QuadPart = ((LONGLONG) Start) << BLOCK_BITS;
1151 return STATUS_SUCCESS;
1152 }
1153
1154 /* ignore special files */
1155 if (IsMcbSpecialFile(Mcb)) {
1156 return STATUS_INVALID_DEVICE_REQUEST;
1157 }
1158
1159 /* expandind file extents */
1160 if (INODE_HAS_EXTENT(&Mcb->Inode)) {
1161
1162 status = Ext2ExpandExtent(IrpContext, Vcb, Mcb, Start, End, Size);
1163
1164 } else {
1165
1166 BOOLEAN do_expand;
1167
1168 #if EXT2_PRE_ALLOCATION_SUPPORT
1169 do_expand = TRUE;
1170 #else
1171 do_expand = (IrpContext->MajorFunction == IRP_MJ_WRITE) ||
1172 IsMcbDirectory(Mcb);
1173 #endif
1174 if (!do_expand)
1175 goto errorout;
1176
1177 status = Ext2ExpandIndirect(IrpContext, Vcb, Mcb, Start, End, Size);
1178 }
1179
1180 errorout:
1181 return status;
1182 }
1183
1184
1185 NTSTATUS
1186 Ext2TruncateFile(
1187 PEXT2_IRP_CONTEXT IrpContext,
1188 PEXT2_VCB Vcb,
1189 PEXT2_MCB Mcb,
1190 PLARGE_INTEGER Size
1191 )
1192 {
1193 NTSTATUS status = STATUS_SUCCESS;
1194
1195 if (INODE_HAS_EXTENT(&Mcb->Inode)) {
1196 status = Ext2TruncateExtent(IrpContext, Vcb, Mcb, Size);
1197 } else {
1198 status = Ext2TruncateIndirect(IrpContext, Vcb, Mcb, Size);
1199 }
1200
1201 /* check and clear data/meta mcb extents */
1202 if (Size->QuadPart == 0) {
1203
1204 /* check and remove all data extents */
1205 if (Ext2ListExtents(&Mcb->Extents)) {
1206 DbgBreak();
1207 }
1208 Ext2ClearAllExtents(&Mcb->Extents);
1209 /* check and remove all meta extents */
1210 if (Ext2ListExtents(&Mcb->MetaExts)) {
1211 DbgBreak();
1212 }
1213 Ext2ClearAllExtents(&Mcb->MetaExts);
1214 ClearLongFlag(Mcb->Flags, MCB_ZONE_INITED);
1215 }
1216
1217 return status;
1218 }
1219
1220 NTSTATUS
1221 Ext2IsFileRemovable(
1222 IN PEXT2_IRP_CONTEXT IrpContext,
1223 IN PEXT2_VCB Vcb,
1224 IN PEXT2_FCB Fcb,
1225 IN PEXT2_CCB Ccb
1226 )
1227 {
1228 PEXT2_MCB Mcb = Fcb->Mcb;
1229
1230 if (Mcb->Inode.i_ino == EXT2_ROOT_INO) {
1231 return STATUS_CANNOT_DELETE;
1232 }
1233
1234 if (IsMcbDirectory(Mcb)) {
1235 if (!Ext2IsDirectoryEmpty(IrpContext, Vcb, Mcb)) {
1236 return STATUS_DIRECTORY_NOT_EMPTY;
1237 }
1238 }
1239
1240 if (!MmFlushImageSection(&Fcb->SectionObject,
1241 MmFlushForDelete )) {
1242 return STATUS_CANNOT_DELETE;
1243 }
1244
1245 if (IsMcbDirectory(Mcb)) {
1246 FsRtlNotifyFullChangeDirectory(
1247 Vcb->NotifySync,
1248 &Vcb->NotifyList,
1249 Ccb,
1250 NULL,
1251 FALSE,
1252 FALSE,
1253 0,
1254 NULL,
1255 NULL,
1256 NULL
1257 );
1258 }
1259
1260 return STATUS_SUCCESS;
1261 }
1262
1263 NTSTATUS
1264 Ext2SetDispositionInfo(
1265 PEXT2_IRP_CONTEXT IrpContext,
1266 PEXT2_VCB Vcb,
1267 PEXT2_FCB Fcb,
1268 PEXT2_CCB Ccb,
1269 BOOLEAN bDelete
1270 )
1271 {
1272 PIRP Irp = IrpContext->Irp;
1273 PIO_STACK_LOCATION IrpSp;
1274 NTSTATUS status = STATUS_SUCCESS;
1275 PEXT2_MCB Mcb = Fcb->Mcb;
1276
1277 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1278
1279 DEBUG(DL_INF, ( "Ext2SetDispositionInfo: bDelete=%x\n", bDelete));
1280
1281 if (bDelete) {
1282
1283 DEBUG(DL_INF, ( "Ext2SetDispositionInformation: Removing %wZ.\n",
1284 &Mcb->FullName));
1285
1286 /* always allow deleting on symlinks */
1287 if (Ccb->SymLink == NULL) {
1288 status = Ext2IsFileRemovable(IrpContext, Vcb, Fcb, Ccb);
1289 }
1290
1291 if (NT_SUCCESS(status)) {
1292 SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING);
1293 IrpSp->FileObject->DeletePending = TRUE;
1294 }
1295
1296 } else {
1297
1298 ClearLongFlag(Fcb->Flags, FCB_DELETE_PENDING);
1299 IrpSp->FileObject->DeletePending = FALSE;
1300 }
1301
1302 return status;
1303 }
1304
1305 NTSTATUS
1306 Ext2SetRenameInfo(
1307 PEXT2_IRP_CONTEXT IrpContext,
1308 PEXT2_VCB Vcb,
1309 PEXT2_FCB Fcb,
1310 PEXT2_CCB Ccb
1311 )
1312 {
1313 PEXT2_MCB Mcb = Fcb->Mcb;
1314
1315 PEXT2_FCB TargetDcb = NULL; /* Dcb of target directory */
1316 PEXT2_MCB TargetMcb = NULL;
1317 PEXT2_FCB ParentDcb = NULL; /* Dcb of it's current parent */
1318 PEXT2_MCB ParentMcb = NULL;
1319
1320 PEXT2_FCB ExistingFcb = NULL; /* Target file Fcb if it exists*/
1321 PEXT2_MCB ExistingMcb = NULL;
1322
1323 UNICODE_STRING FileName;
1324
1325 NTSTATUS Status;
1326
1327 PIRP Irp;
1328 PIO_STACK_LOCATION IrpSp;
1329
1330 PFILE_OBJECT FileObject;
1331 PFILE_OBJECT TargetObject;
1332
1333 struct dentry *NewEntry = NULL;
1334
1335 BOOLEAN ReplaceIfExists;
1336 BOOLEAN bMove = FALSE;
1337 BOOLEAN bTargetRemoved = FALSE;
1338
1339 BOOLEAN bNewTargetDcb = FALSE;
1340 BOOLEAN bNewParentDcb = FALSE;
1341
1342 PFILE_RENAME_INFORMATION FRI;
1343
1344 if (Ccb->SymLink) {
1345 Mcb = Ccb->SymLink;
1346 }
1347
1348 if (Mcb->Inode.i_ino == EXT2_ROOT_INO) {
1349 Status = STATUS_INVALID_PARAMETER;
1350 goto errorout;
1351 }
1352
1353 Irp = IrpContext->Irp;
1354 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1355
1356 FileObject = IrpSp->FileObject;
1357 TargetObject = IrpSp->Parameters.SetFile.FileObject;
1358 ReplaceIfExists = IrpSp->Parameters.SetFile.ReplaceIfExists;
1359
1360 FRI = (PFILE_RENAME_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
1361
1362 if (TargetObject == NULL) {
1363
1364 UNICODE_STRING NewName;
1365
1366 NewName.Buffer = FRI->FileName;
1367 NewName.MaximumLength = NewName.Length = (USHORT)FRI->FileNameLength;
1368
1369 while (NewName.Length > 0 && NewName.Buffer[NewName.Length/2 - 1] == L'\\') {
1370 NewName.Buffer[NewName.Length/2 - 1] = 0;
1371 NewName.Length -= 2;
1372 }
1373
1374 while (NewName.Length > 0 && NewName.Buffer[NewName.Length/2 - 1] != L'\\') {
1375 NewName.Length -= 2;
1376 }
1377
1378 NewName.Buffer = (USHORT *)((UCHAR *)NewName.Buffer + NewName.Length);
1379 NewName.Length = (USHORT)(FRI->FileNameLength - NewName.Length);
1380
1381 FileName = NewName;
1382
1383 TargetMcb = Mcb->Parent;
1384 if (IsMcbSymLink(TargetMcb)) {
1385 TargetMcb = TargetMcb->Target;
1386 ASSERT(!IsMcbSymLink(TargetMcb));
1387 }
1388
1389 if (TargetMcb == NULL || FileName.Length >= EXT2_NAME_LEN*2) {
1390 Status = STATUS_OBJECT_NAME_INVALID;
1391 goto errorout;
1392 }
1393
1394 } else {
1395
1396 TargetDcb = (PEXT2_FCB)(TargetObject->FsContext);
1397
1398 if (!TargetDcb || TargetDcb->Vcb != Vcb) {
1399
1400 DbgBreak();
1401
1402 Status = STATUS_INVALID_PARAMETER;
1403 goto errorout;
1404 }
1405
1406 TargetMcb = TargetDcb->Mcb;
1407 FileName = TargetObject->FileName;
1408 }
1409
1410 if (FsRtlDoesNameContainWildCards(&FileName)) {
1411 Status = STATUS_OBJECT_NAME_INVALID;
1412 goto errorout;
1413 }
1414
1415 if (TargetMcb->Inode.i_ino == Mcb->Parent->Inode.i_ino) {
1416 if (FsRtlAreNamesEqual( &FileName,
1417 &(Mcb->ShortName),
1418 FALSE,
1419 NULL )) {
1420 Status = STATUS_SUCCESS;
1421 goto errorout;
1422 }
1423 } else {
1424 bMove = TRUE;
1425 }
1426
1427 TargetDcb = TargetMcb->Fcb;
1428 if (TargetDcb == NULL) {
1429 TargetDcb = Ext2AllocateFcb(Vcb, TargetMcb);
1430 if (TargetDcb) {
1431 Ext2ReferXcb(&TargetDcb->ReferenceCount);
1432 bNewTargetDcb = TRUE;
1433 }
1434 }
1435 if (TargetDcb) {
1436 SetLongFlag(TargetDcb->Flags, FCB_STATE_BUSY);
1437 }
1438
1439 ParentMcb = Mcb->Parent;
1440 ParentDcb = ParentMcb->Fcb;
1441
1442 if ((TargetMcb->Inode.i_ino != ParentMcb->Inode.i_ino)) {
1443
1444 if (ParentDcb == NULL) {
1445 ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
1446 if (ParentDcb) {
1447 Ext2ReferXcb(&ParentDcb->ReferenceCount);
1448 bNewParentDcb = TRUE;
1449 }
1450 }
1451 if (ParentDcb) {
1452 SetLongFlag(ParentDcb->Flags, FCB_STATE_BUSY);
1453 }
1454 }
1455
1456 if (!TargetDcb || !ParentDcb) {
1457 Status = STATUS_INSUFFICIENT_RESOURCES;
1458 goto errorout;
1459 }
1460
1461 DEBUG(DL_RES, ("Ext2SetRenameInfo: rename %wZ to %wZ\\%wZ\n",
1462 &Mcb->FullName, &TargetMcb->FullName, &FileName));
1463
1464 Status = Ext2LookupFile(
1465 IrpContext,
1466 Vcb,
1467 &FileName,
1468 TargetMcb,
1469 &ExistingMcb,
1470 0
1471 );
1472
1473 if (NT_SUCCESS(Status) && ExistingMcb != Mcb) {
1474
1475 if (!ReplaceIfExists) {
1476
1477 Status = STATUS_OBJECT_NAME_COLLISION;
1478 DEBUG(DL_RES, ("Ext2SetRenameInfo: Target file %wZ exists\n",
1479 &ExistingMcb->FullName));
1480 goto errorout;
1481
1482 } else {
1483
1484 if ( (ExistingFcb = ExistingMcb->Fcb) && !IsMcbSymLink(ExistingMcb) ) {
1485
1486 Status = Ext2IsFileRemovable(IrpContext, Vcb, ExistingFcb, Ccb);
1487 if (!NT_SUCCESS(Status)) {
1488 DEBUG(DL_REN, ("Ext2SetRenameInfo: Target file %wZ cannot be removed.\n",
1489 &ExistingMcb->FullName));
1490 goto errorout;
1491 }
1492 }
1493
1494 Status = Ext2DeleteFile(IrpContext, Vcb, ExistingFcb, ExistingMcb);
1495 if (!NT_SUCCESS(Status)) {
1496 DEBUG(DL_REN, ("Ext2SetRenameInfo: Failed to delete %wZ with status: %xh.\n",
1497 &FileName, Status));
1498
1499 goto errorout;
1500 }
1501
1502 bTargetRemoved = TRUE;
1503 }
1504 }
1505
1506 /* remove directory entry of old name */
1507 Status = Ext2RemoveEntry(IrpContext, Vcb, ParentDcb, Mcb);
1508 if (!NT_SUCCESS(Status)) {
1509 DEBUG(DL_REN, ("Ext2SetRenameInfo: Failed to remove entry %wZ with status %xh.\n",
1510 &Mcb->FullName, Status));
1511 DbgBreak();
1512 goto errorout;
1513 }
1514
1515 /* add new entry for new target name */
1516 Status = Ext2AddEntry(IrpContext, Vcb, TargetDcb, &Mcb->Inode, &FileName, &NewEntry);
1517 if (!NT_SUCCESS(Status)) {
1518 DEBUG(DL_REN, ("Ext2SetRenameInfo: Failed to add entry for %wZ with status: %xh.\n",
1519 &FileName, Status));
1520 Ext2AddEntry(IrpContext, Vcb, ParentDcb, &Mcb->Inode, &Mcb->ShortName, &NewEntry);
1521 goto errorout;
1522 }
1523
1524 /* correct the inode number in .. entry */
1525 if (IsMcbDirectory(Mcb)) {
1526 Status = Ext2SetParentEntry(
1527 IrpContext, Vcb, Fcb,
1528 ParentMcb->Inode.i_ino,
1529 TargetMcb->Inode.i_ino );
1530 if (!NT_SUCCESS(Status)) {
1531 DEBUG(DL_REN, ("Ext2SetRenameInfo: Failed to set parent refer of %wZ with %xh.\n",
1532 &Mcb->FullName, Status));
1533 DbgBreak();
1534 goto errorout;
1535 }
1536 }
1537
1538 /* Update current dentry from the newly created one. We need keep the original
1539 dentry to assure children's links are valid if current entry is a directory */
1540 if (Mcb->de) {
1541 char *np = Mcb->de->d_name.name;
1542 *(Mcb->de) = *NewEntry;
1543 NewEntry->d_name.name = np;
1544 }
1545
1546 if (bTargetRemoved) {
1547 Ext2NotifyReportChange(
1548 IrpContext,
1549 Vcb,
1550 ExistingMcb,
1551 (IsMcbDirectory(ExistingMcb) ?
1552 FILE_NOTIFY_CHANGE_DIR_NAME :
1553 FILE_NOTIFY_CHANGE_FILE_NAME ),
1554 FILE_ACTION_REMOVED);
1555 }
1556
1557 if (NT_SUCCESS(Status)) {
1558
1559 if (bMove) {
1560 Ext2NotifyReportChange(
1561 IrpContext,
1562 Vcb,
1563 Mcb,
1564 (IsDirectory(Fcb) ?
1565 FILE_NOTIFY_CHANGE_DIR_NAME :
1566 FILE_NOTIFY_CHANGE_FILE_NAME ),
1567 FILE_ACTION_REMOVED);
1568
1569 } else {
1570 Ext2NotifyReportChange(
1571 IrpContext,
1572 Vcb,
1573 Mcb,
1574 (IsDirectory(Fcb) ?
1575 FILE_NOTIFY_CHANGE_DIR_NAME :
1576 FILE_NOTIFY_CHANGE_FILE_NAME ),
1577 FILE_ACTION_RENAMED_OLD_NAME);
1578
1579 }
1580
1581 if (TargetMcb->Inode.i_ino != ParentMcb->Inode.i_ino) {
1582 Ext2RemoveMcb(Vcb, Mcb);
1583 Ext2InsertMcb(Vcb, TargetMcb, Mcb);
1584 }
1585
1586 if (!Ext2BuildName( &Mcb->ShortName,
1587 &FileName, NULL )) {
1588 Status = STATUS_INSUFFICIENT_RESOURCES;
1589 goto errorout;
1590 }
1591
1592 if (!Ext2BuildName( &Mcb->FullName,
1593 &FileName,
1594 &TargetMcb->FullName)) {
1595 Status = STATUS_INSUFFICIENT_RESOURCES;
1596 goto errorout;
1597 }
1598
1599 if (bMove) {
1600 Ext2NotifyReportChange(
1601 IrpContext,
1602 Vcb,
1603 Mcb,
1604 (IsDirectory(Fcb) ?
1605 FILE_NOTIFY_CHANGE_DIR_NAME :
1606 FILE_NOTIFY_CHANGE_FILE_NAME ),
1607 FILE_ACTION_ADDED);
1608 } else {
1609 Ext2NotifyReportChange(
1610 IrpContext,
1611 Vcb,
1612 Mcb,
1613 (IsDirectory(Fcb) ?
1614 FILE_NOTIFY_CHANGE_DIR_NAME :
1615 FILE_NOTIFY_CHANGE_FILE_NAME ),
1616 FILE_ACTION_RENAMED_NEW_NAME );
1617
1618 }
1619 }
1620
1621 errorout:
1622
1623 if (NewEntry)
1624 Ext2FreeEntry(NewEntry);
1625
1626 if (TargetDcb) {
1627 if (ParentDcb && ParentDcb->Inode->i_ino != TargetDcb->Inode->i_ino) {
1628 ClearLongFlag(ParentDcb->Flags, FCB_STATE_BUSY);
1629 }
1630 ClearLongFlag(TargetDcb->Flags, FCB_STATE_BUSY);
1631 }
1632
1633 if (bNewTargetDcb) {
1634 ASSERT(TargetDcb != NULL);
1635 if (Ext2DerefXcb(&TargetDcb->ReferenceCount) == 0) {
1636 Ext2FreeFcb(TargetDcb);
1637 TargetDcb = NULL;
1638 } else {
1639 DEBUG(DL_RES, ( "Ext2SetRenameInfo: TargetDcb is resued by other threads.\n"));
1640 }
1641 }
1642
1643 if (bNewParentDcb) {
1644 ASSERT(ParentDcb != NULL);
1645 if (Ext2DerefXcb(&ParentDcb->ReferenceCount) == 0) {
1646 Ext2FreeFcb(ParentDcb);
1647 ParentDcb = NULL;
1648 } else {
1649 DEBUG(DL_RES, ( "Ext2SetRenameInfo: ParentDcb is resued by other threads.\n"));
1650 }
1651 }
1652
1653 if (ExistingMcb)
1654 Ext2DerefMcb(ExistingMcb);
1655
1656 return Status;
1657 }
1658
1659 ULONG
1660 Ext2InodeType(PEXT2_MCB Mcb)
1661 {
1662 if (IsMcbSymLink(Mcb)) {
1663 return EXT2_FT_SYMLINK;
1664 }
1665
1666 if (IsMcbDirectory(Mcb)) {
1667 return EXT2_FT_DIR;
1668 }
1669
1670 return EXT2_FT_REG_FILE;
1671 }
1672
1673 NTSTATUS
1674 Ext2DeleteFile(
1675 PEXT2_IRP_CONTEXT IrpContext,
1676 PEXT2_VCB Vcb,
1677 PEXT2_FCB Fcb,
1678 PEXT2_MCB Mcb
1679 )
1680 {
1681 PEXT2_FCB Dcb = NULL;
1682
1683 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1684
1685 BOOLEAN VcbResourceAcquired = FALSE;
1686 BOOLEAN FcbPagingIoAcquired = FALSE;
1687 BOOLEAN FcbResourceAcquired = FALSE;
1688 BOOLEAN DcbResourceAcquired = FALSE;
1689
1690 LARGE_INTEGER Size;
1691 LARGE_INTEGER SysTime;
1692
1693 BOOLEAN bNewDcb = FALSE;
1694
1695 DEBUG(DL_INF, ( "Ext2DeleteFile: File %wZ (%xh) will be deleted!\n",
1696 &Mcb->FullName, Mcb->Inode.i_ino));
1697
1698 if (IsFlagOn(Mcb->Flags, MCB_FILE_DELETED)) {
1699 return STATUS_SUCCESS;
1700 }
1701
1702 if (!IsMcbSymLink(Mcb) && IsMcbDirectory(Mcb)) {
1703 if (!Ext2IsDirectoryEmpty(IrpContext, Vcb, Mcb)) {
1704 return STATUS_DIRECTORY_NOT_EMPTY;
1705 }
1706 }
1707
1708
1709 _SEH2_TRY {
1710
1711 Ext2ReferMcb(Mcb);
1712
1713 ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
1714 VcbResourceAcquired = TRUE;
1715
1716 if (!(Dcb = Mcb->Parent->Fcb)) {
1717 Dcb = Ext2AllocateFcb(Vcb, Mcb->Parent);
1718 if (Dcb) {
1719 Ext2ReferXcb(&Dcb->ReferenceCount);
1720 bNewDcb = TRUE;
1721 }
1722 }
1723
1724 if (Dcb) {
1725 SetLongFlag(Dcb->Flags, FCB_STATE_BUSY);
1726 DcbResourceAcquired =
1727 ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
1728
1729 /* remove it's entry form it's parent */
1730 Status = Ext2RemoveEntry(IrpContext, Vcb, Dcb, Mcb);
1731 }
1732
1733 if (NT_SUCCESS(Status)) {
1734
1735 SetFlag(Mcb->Flags, MCB_FILE_DELETED);
1736 Ext2RemoveMcb(Vcb, Mcb);
1737
1738 if (Fcb) {
1739 FcbResourceAcquired =
1740 ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE);
1741
1742 FcbPagingIoAcquired =
1743 ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, TRUE);
1744 }
1745
1746 if (DcbResourceAcquired) {
1747 ExReleaseResourceLite(&Dcb->MainResource);
1748 DcbResourceAcquired = FALSE;
1749 }
1750
1751 if (VcbResourceAcquired) {
1752 ExReleaseResourceLite(&Vcb->MainResource);
1753 VcbResourceAcquired = FALSE;
1754 }
1755
1756 if (IsMcbSymLink(Mcb)) {
1757 if (Mcb->Inode.i_nlink > 0) {
1758 Status = STATUS_CANNOT_DELETE;
1759 _SEH2_LEAVE;
1760 }
1761 } else if (!IsMcbDirectory(Mcb)) {
1762 if (Mcb->Inode.i_nlink > 0) {
1763 _SEH2_LEAVE;
1764 }
1765 } else {
1766 if (Mcb->Inode.i_nlink >= 2) {
1767 _SEH2_LEAVE;
1768 }
1769 }
1770
1771 if (S_ISLNK(Mcb->Inode.i_mode)) {
1772
1773 /* for symlink, we should do differenctly */
1774 if (Mcb->Inode.i_size > EXT2_LINKLEN_IN_INODE) {
1775 Size.QuadPart = (LONGLONG)0;
1776 Status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &Size);
1777 }
1778
1779 } else {
1780
1781 /* truncate file size */
1782 Size.QuadPart = (LONGLONG)0;
1783 Status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &Size);
1784
1785 /* check file offset mappings */
1786 DEBUG(DL_EXT, ("Ext2DeleteFile ...: %wZ\n", &Mcb->FullName));
1787
1788 if (Fcb) {
1789 Fcb->Header.AllocationSize.QuadPart = Size.QuadPart;
1790 if (Fcb->Header.FileSize.QuadPart > Size.QuadPart) {
1791 Fcb->Header.FileSize.QuadPart = Size.QuadPart;
1792 Fcb->Mcb->Inode.i_size = Size.QuadPart;
1793 }
1794 if (Fcb->Header.ValidDataLength.QuadPart > Fcb->Header.FileSize.QuadPart) {
1795 Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
1796 }
1797 } else if (Mcb) {
1798 /* Update the inode's data length . It should be ZERO if succeeds. */
1799 if (Mcb->Inode.i_size > (loff_t)Size.QuadPart) {
1800 Mcb->Inode.i_size = Size.QuadPart;
1801 }
1802 }
1803 }
1804
1805 /* set delete time and free the inode */
1806 KeQuerySystemTime(&SysTime);
1807 Mcb->Inode.i_nlink = 0;
1808 Mcb->Inode.i_dtime = Ext2LinuxTime(SysTime);
1809 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
1810 Ext2FreeInode(IrpContext, Vcb, Mcb->Inode.i_ino, Ext2InodeType(Mcb));
1811 }
1812
1813 } _SEH2_FINALLY {
1814
1815 if (FcbPagingIoAcquired) {
1816 ExReleaseResourceLite(&Fcb->PagingIoResource);
1817 }
1818
1819 if (FcbResourceAcquired) {
1820 ExReleaseResourceLite(&Fcb->MainResource);
1821 }
1822
1823 if (DcbResourceAcquired) {
1824 ExReleaseResourceLite(&Dcb->MainResource);
1825 }
1826
1827 if (Dcb) {
1828 ClearLongFlag(Dcb->Flags, FCB_STATE_BUSY);
1829 if (bNewDcb) {
1830 if (Ext2DerefXcb(&Dcb->ReferenceCount) == 0) {
1831 Ext2FreeFcb(Dcb);
1832 } else {
1833 DEBUG(DL_ERR, ( "Ext2DeleteFile: Dcb %wZ used by other threads.\n",
1834 &Mcb->FullName ));
1835 }
1836 }
1837 }
1838 if (VcbResourceAcquired) {
1839 ExReleaseResourceLite(&Vcb->MainResource);
1840 }
1841
1842 Ext2DerefMcb(Mcb);
1843 } _SEH2_END;
1844
1845 DEBUG(DL_INF, ( "Ext2DeleteFile: %wZ Succeed... EXT2SB->S_FREE_BLOCKS = %I64xh .\n",
1846 &Mcb->FullName, ext3_free_blocks_count(SUPER_BLOCK)));
1847
1848 return Status;
1849 }