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