a72da5a94fe791c730ec3b062ddb70beac2f709b
[reactos.git] / reactos / drivers / filesystems / ext2 / src / create.c
1 /*
2 * COPYRIGHT: See COPYRIGHT.TXT
3 * PROJECT: Ext2 File System Driver for WinNT/2K/XP
4 * FILE: create.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
14 /* GLOBALS *****************************************************************/
15
16 extern PEXT2_GLOBAL Ext2Global;
17
18 /* DEFINITIONS *************************************************************/
19
20 #ifdef ALLOC_PRAGMA
21 #pragma alloc_text(PAGE, Ext2IsNameValid)
22 #pragma alloc_text(PAGE, Ext2FollowLink)
23 #pragma alloc_text(PAGE, Ext2IsSpecialSystemFile)
24 #pragma alloc_text(PAGE, Ext2LookupFile)
25 #pragma alloc_text(PAGE, Ext2ScanDir)
26 #pragma alloc_text(PAGE, Ext2CreateFile)
27 #pragma alloc_text(PAGE, Ext2CreateVolume)
28 #pragma alloc_text(PAGE, Ext2Create)
29 #pragma alloc_text(PAGE, Ext2CreateInode)
30 #pragma alloc_text(PAGE, Ext2SupersedeOrOverWriteFile)
31 #endif
32
33
34 BOOLEAN
35 Ext2IsNameValid(PUNICODE_STRING FileName)
36 {
37 USHORT i = 0;
38 PUSHORT pName = (PUSHORT) FileName->Buffer;
39
40 if (FileName == NULL) {
41 return FALSE;
42 }
43
44 while (i < (FileName->Length / sizeof(WCHAR))) {
45
46 if (pName[i] == 0) {
47 break;
48 }
49
50 if (pName[i] == L'|' || pName[i] == L':' ||
51 pName[i] == L'/' || pName[i] == L'*' ||
52 pName[i] == L'?' || pName[i] == L'\"' ||
53 pName[i] == L'<' || pName[i] == L'>' ) {
54
55 return FALSE;
56 }
57
58 i++;
59 }
60
61 return TRUE;
62 }
63
64
65 NTSTATUS
66 Ext2FollowLink (
67 IN PEXT2_IRP_CONTEXT IrpContext,
68 IN PEXT2_VCB Vcb,
69 IN PEXT2_MCB Parent,
70 IN PEXT2_MCB Mcb,
71 IN ULONG Linkdep
72 )
73 {
74 NTSTATUS Status = STATUS_LINK_FAILED;
75
76 UNICODE_STRING UniName;
77 OEM_STRING OemName;
78 BOOLEAN bOemBuffer = FALSE;
79
80 PEXT2_MCB Target = NULL;
81
82 USHORT i;
83
84 _SEH2_TRY {
85
86 RtlZeroMemory(&UniName, sizeof(UNICODE_STRING));
87 RtlZeroMemory(&OemName, sizeof(OEM_STRING));
88
89 /* exit if we jump into a possible symlink forever loop */
90 if ((Linkdep + 1) > EXT2_MAX_NESTED_LINKS ||
91 IoGetRemainingStackSize() < 1024) {
92 _SEH2_LEAVE;
93 }
94
95 /* read the symlink target path */
96 if (!Mcb->Inode.i_blocks) {
97
98 OemName.Buffer = (PUCHAR) (&Mcb->Inode.i_block[0]);
99 OemName.Length = (USHORT)Mcb->Inode.i_size;
100 OemName.MaximumLength = OemName.Length + 1;
101
102 } else {
103
104 OemName.Length = (USHORT)Mcb->Inode.i_size;
105 OemName.MaximumLength = OemName.Length + 1;
106 OemName.Buffer = Ext2AllocatePool(PagedPool,
107 OemName.MaximumLength,
108 'NL2E');
109 if (OemName.Buffer == NULL) {
110 Status = STATUS_INSUFFICIENT_RESOURCES;
111 _SEH2_LEAVE;
112 }
113 bOemBuffer = TRUE;
114 RtlZeroMemory(OemName.Buffer, OemName.MaximumLength);
115
116 Status = Ext2ReadSymlink(
117 IrpContext,
118 Vcb,
119 Mcb,
120 OemName.Buffer,
121 (ULONG)(Mcb->Inode.i_size),
122 NULL);
123 if (!NT_SUCCESS(Status)) {
124 _SEH2_LEAVE;
125 }
126 }
127
128 /* convert Linux slash to Windows backslash */
129 for (i=0; i < OemName.Length; i++) {
130 if (OemName.Buffer[i] == '/') {
131 OemName.Buffer[i] = '\\';
132 }
133 }
134
135 /* convert oem string to unicode string */
136 UniName.MaximumLength = (USHORT)Ext2OEMToUnicodeSize(Vcb, &OemName);
137 if (UniName.MaximumLength <= 0) {
138 Status = STATUS_INSUFFICIENT_RESOURCES;
139 _SEH2_LEAVE;
140 }
141
142 UniName.MaximumLength += 2;
143 UniName.Buffer = Ext2AllocatePool(PagedPool,
144 UniName.MaximumLength,
145 'NL2E');
146 if (UniName.Buffer == NULL) {
147 Status = STATUS_INSUFFICIENT_RESOURCES;
148 _SEH2_LEAVE;
149 }
150 RtlZeroMemory(UniName.Buffer, UniName.MaximumLength);
151 Status = Ext2OEMToUnicode(Vcb, &UniName, &OemName);
152 if (!NT_SUCCESS(Status)) {
153 Status = STATUS_INSUFFICIENT_RESOURCES;
154 _SEH2_LEAVE;
155 }
156
157 /* search the real target */
158 Status = Ext2LookupFile(
159 IrpContext,
160 Vcb,
161 &UniName,
162 Parent,
163 &Target,
164 Linkdep
165 );
166 if (Target == NULL) {
167 Status = STATUS_LINK_FAILED;
168 }
169
170 if (Target == NULL /* link target doesn't exist */ ||
171 Target == Mcb /* symlink points to itself */ ||
172 IsMcbSpecialFile(Target) /* target not resolved*/ ||
173 IsFileDeleted(Target) /* target deleted */ ) {
174
175 if (Target) {
176 ASSERT(Target->Refercount > 0);
177 Ext2DerefMcb(Target);
178 }
179 ClearLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
180 SetLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
181 Mcb->Target = NULL;
182
183 } else if (IsMcbSymLink(Target)) {
184
185 ASSERT(Target->Refercount > 0);
186 ASSERT(Target->Target != NULL);
187 Ext2ReferMcb(Target->Target);
188 Mcb->Target = Target->Target;
189 Ext2DerefMcb(Target);
190 ASSERT(!IsMcbSymLink(Target->Target));
191 SetLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
192 ClearLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
193 ASSERT(Mcb->Target->Refercount > 0);
194
195 } else {
196
197 Mcb->Target = Target;
198 SetLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
199 ClearLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
200 ASSERT(Mcb->Target->Refercount > 0);
201 }
202
203 /* add directory flag to file attribute */
204 if (Mcb->Target && IsMcbDirectory(Mcb->Target)) {
205 Mcb->FileAttr |= FILE_ATTRIBUTE_DIRECTORY;
206 }
207
208 } _SEH2_FINALLY {
209
210 if (bOemBuffer) {
211 Ext2FreePool(OemName.Buffer, 'NL2E');
212 }
213
214 if (UniName.Buffer) {
215 Ext2FreePool(UniName.Buffer, 'NL2E');
216 }
217 } _SEH2_END;
218
219 return Status;
220 }
221
222 BOOLEAN
223 Ext2IsSpecialSystemFile(
224 IN PUNICODE_STRING FileName,
225 IN BOOLEAN bDirectory
226 )
227 {
228 PWSTR SpecialFileList[] = {
229 L"pagefile.sys",
230 L"swapfile.sys",
231 L"hiberfil.sys",
232 NULL
233 };
234
235 PWSTR SpecialDirList[] = {
236 L"Recycled",
237 L"RECYCLER",
238 L"$RECYCLE.BIN",
239 NULL
240 };
241
242 PWSTR entryName;
243 ULONG length;
244 int i;
245
246 for (i = 0; TRUE; i++) {
247
248 if (bDirectory) {
249 entryName = SpecialDirList[i];
250 } else {
251 entryName = SpecialFileList[i];
252 }
253
254 if (NULL == entryName) {
255 break;
256 }
257
258 length = wcslen(entryName) * sizeof(WCHAR);
259 if (FileName->Length == length) {
260 if ( 0 == _wcsnicmp( entryName,
261 FileName->Buffer,
262 length / sizeof(WCHAR) )) {
263 return TRUE;
264 }
265 }
266 }
267
268 return FALSE;
269 }
270
271 NTSTATUS
272 Ext2LookupFile (
273 IN PEXT2_IRP_CONTEXT IrpContext,
274 IN PEXT2_VCB Vcb,
275 IN PUNICODE_STRING FullName,
276 IN PEXT2_MCB Parent,
277 OUT PEXT2_MCB * Ext2Mcb,
278 IN ULONG Linkdep
279 )
280 {
281 NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND;
282 UNICODE_STRING FileName;
283 PEXT2_MCB Mcb = NULL;
284 struct dentry *de = NULL;
285
286 USHORT i = 0, End;
287 ULONG Inode;
288
289 BOOLEAN bParent = FALSE;
290 BOOLEAN bDirectory = FALSE;
291 BOOLEAN LockAcquired = FALSE;
292 BOOLEAN bNotFollow = FALSE;
293
294 _SEH2_TRY {
295
296 ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
297 LockAcquired = TRUE;
298
299 bNotFollow = IsFlagOn(Linkdep, EXT2_LOOKUP_NOT_FOLLOW);
300 #ifndef __REACTOS__
301 Linkdep = ClearFlag(Linkdep, EXT2_LOOKUP_FLAG_MASK);
302 #else
303 ClearFlag(Linkdep, EXT2_LOOKUP_FLAG_MASK);
304 #endif
305
306 *Ext2Mcb = NULL;
307
308 DEBUG(DL_RES, ("Ext2LookupFile: %wZ\n", FullName));
309
310 /* check names and parameters */
311 if (FullName->Buffer[0] == L'\\') {
312 Parent = Vcb->McbTree;
313 } else if (Parent) {
314 bParent = TRUE;
315 } else {
316 Parent = Vcb->McbTree;
317 }
318
319 /* make sure the parent is NULL */
320 if (!IsMcbDirectory(Parent)) {
321 Status = STATUS_NOT_A_DIRECTORY;
322 _SEH2_LEAVE;
323 }
324
325 /* use symlink's target as parent directory */
326 if (IsMcbSymLink(Parent)) {
327 Parent = Parent->Target;
328 ASSERT(!IsMcbSymLink(Parent));
329 if (IsFileDeleted(Parent)) {
330 Status = STATUS_NOT_A_DIRECTORY;
331 _SEH2_LEAVE;
332 }
333 }
334
335 if (NULL == Parent) {
336 Status = STATUS_NOT_A_DIRECTORY;
337 _SEH2_LEAVE;
338 }
339
340 /* default is the parent Mcb*/
341 Ext2ReferMcb(Parent);
342 Mcb = Parent;
343
344 /* is empty file name or root node */
345 End = FullName->Length/sizeof(WCHAR);
346 if ( (End == 0) || (End == 1 &&
347 FullName->Buffer[0] == L'\\')) {
348 Status = STATUS_SUCCESS;
349 _SEH2_LEAVE;
350 }
351
352 /* is a directory expected ? */
353 if (FullName->Buffer[End - 1] == L'\\') {
354 bDirectory = TRUE;
355 }
356
357 /* loop with every sub name */
358 while (i < End) {
359
360 USHORT Start = 0;
361
362 /* zero the prefix '\' */
363 while (i < End && FullName->Buffer[i] == L'\\') i++;
364 Start = i;
365
366 /* zero the suffix '\' */
367 while (i < End && (FullName->Buffer[i] != L'\\')) i++;
368
369 if (i > Start) {
370
371 FileName = *FullName;
372 FileName.Buffer += Start;
373 FileName.Length = (USHORT)((i - Start) * 2);
374
375 /* make sure the parent is NULL */
376 if (!IsMcbDirectory(Parent)) {
377 Status = STATUS_NOT_A_DIRECTORY;
378 Ext2DerefMcb(Parent);
379 break;
380 }
381
382 if (IsMcbSymLink(Parent)) {
383 if (IsFileDeleted(Parent->Target)) {
384 Status = STATUS_NOT_A_DIRECTORY;
385 Ext2DerefMcb(Parent);
386 break;
387 } else {
388 Ext2ReferMcb(Parent->Target);
389 Ext2DerefMcb(Parent);
390 Parent = Parent->Target;
391 }
392 }
393
394 /* search cached Mcb nodes */
395 Mcb = Ext2SearchMcbWithoutLock(Parent, &FileName);
396
397 if (Mcb) {
398
399 /* derefer the parent Mcb */
400 Ext2DerefMcb(Parent);
401 Status = STATUS_SUCCESS;
402 Parent = Mcb;
403
404 if (IsMcbSymLink(Mcb) && IsFileDeleted(Mcb->Target) &&
405 Mcb->Refercount == 1) {
406
407 ASSERT(Mcb->Target);
408 ASSERT(Mcb->Target->Refercount > 0);
409 Ext2DerefMcb(Mcb->Target);
410 Mcb->Target = NULL;
411 ClearLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
412 SetLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
413 Mcb->FileAttr = FILE_ATTRIBUTE_NORMAL;
414 }
415
416 } else {
417
418 /* need create new Mcb node */
419
420 /* is a valid ext2 name */
421 if (!Ext2IsNameValid(&FileName)) {
422 Status = STATUS_OBJECT_NAME_INVALID;
423 Ext2DerefMcb(Parent);
424 break;
425 }
426
427 /* seach the disk */
428 de = NULL;
429 Status = Ext2ScanDir (
430 IrpContext,
431 Vcb,
432 Parent,
433 &FileName,
434 &Inode,
435 &de);
436
437 if (NT_SUCCESS(Status)) {
438
439 /* check it's real parent */
440 ASSERT (!IsMcbSymLink(Parent));
441
442 /* allocate Mcb ... */
443 Mcb = Ext2AllocateMcb(Vcb, &FileName, &Parent->FullName, 0);
444 if (!Mcb) {
445 Status = STATUS_INSUFFICIENT_RESOURCES;
446 Ext2DerefMcb(Parent);
447 break;
448 }
449 Mcb->de = de;
450 Mcb->de->d_inode = &Mcb->Inode;
451 Mcb->Inode.i_ino = Inode;
452 Mcb->Inode.i_sb = &Vcb->sb;
453 de = NULL;
454
455 /* load inode information */
456 if (!Ext2LoadInode(Vcb, &Mcb->Inode)) {
457 Status = STATUS_CANT_WAIT;
458 Ext2DerefMcb(Parent);
459 Ext2FreeMcb(Vcb, Mcb);
460 break;
461 }
462
463 /* set inode attribute */
464 if (!Ext2CheckFileAccess(Vcb, Mcb, Ext2FileCanWrite)) {
465 SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_READONLY);
466 }
467
468 if (S_ISDIR(Mcb->Inode.i_mode)) {
469 SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY);
470 } else {
471 if (S_ISREG(Mcb->Inode.i_mode)) {
472 SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_NORMAL);
473 } else if (S_ISLNK(Mcb->Inode.i_mode)) {
474 SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT);
475 } else {
476 SetLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
477 }
478 }
479
480 /* process special files under root directory */
481 if (IsMcbRoot(Parent)) {
482 /* set hidden and system attributes for
483 Recycled / RECYCLER / pagefile.sys */
484 BOOLEAN IsDirectory = IsMcbDirectory(Mcb);
485 if (Ext2IsSpecialSystemFile(&Mcb->ShortName, IsDirectory)) {
486 SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_HIDDEN);
487 SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_SYSTEM);
488 }
489 }
490
491 Mcb->CreationTime = Ext2NtTime(Mcb->Inode.i_ctime);
492 Mcb->LastAccessTime = Ext2NtTime(Mcb->Inode.i_atime);
493 Mcb->LastWriteTime = Ext2NtTime(Mcb->Inode.i_mtime);
494 Mcb->ChangeTime = Ext2NtTime(Mcb->Inode.i_mtime);
495
496 /* process symlink */
497 if (S_ISLNK(Mcb->Inode.i_mode) && !bNotFollow) {
498 Ext2FollowLink( IrpContext,
499 Vcb,
500 Parent,
501 Mcb,
502 Linkdep+1
503 );
504 }
505
506 /* add reference ... */
507 Ext2ReferMcb(Mcb);
508
509 /* add Mcb to it's parent tree*/
510 Ext2InsertMcb(Vcb, Parent, Mcb);
511
512 /* it's safe to deref Parent Mcb */
513 Ext2DerefMcb(Parent);
514
515 /* linking this Mcb*/
516 Ext2LinkTailMcb(Vcb, Mcb);
517
518 /* set parent to preare re-scan */
519 Parent = Mcb;
520
521 } else {
522
523 /* derefernce it's parent */
524 Ext2DerefMcb(Parent);
525 break;
526 }
527 }
528
529 } else {
530
531 /* there seems too many \ or / */
532 /* Mcb should be already set to Parent */
533 ASSERT(Mcb == Parent);
534 Status = STATUS_SUCCESS;
535 break;
536 }
537 }
538
539 } _SEH2_FINALLY {
540
541 if (de) {
542 Ext2FreeEntry(de);
543 }
544
545 if (NT_SUCCESS(Status)) {
546 if (bDirectory) {
547 if (IsMcbDirectory(Mcb)) {
548 *Ext2Mcb = Mcb;
549 } else {
550 Ext2DerefMcb(Mcb);
551 Status = STATUS_NOT_A_DIRECTORY;
552 }
553 } else {
554 *Ext2Mcb = Mcb;
555 }
556 }
557
558 if (LockAcquired) {
559 ExReleaseResourceLite(&Vcb->McbLock);
560 }
561 } _SEH2_END;
562
563 return Status;
564 }
565
566
567 NTSTATUS
568 Ext2ScanDir (
569 IN PEXT2_IRP_CONTEXT IrpContext,
570 IN PEXT2_VCB Vcb,
571 IN PEXT2_MCB Parent,
572 IN PUNICODE_STRING FileName,
573 OUT PULONG Inode,
574 OUT struct dentry **dentry
575 )
576 {
577 struct ext3_dir_entry_2 *dir_entry = NULL;
578 struct buffer_head *bh = NULL;
579 struct dentry *de = NULL;
580
581 NTSTATUS Status = STATUS_NO_SUCH_FILE;
582
583 DEBUG(DL_RES, ("Ext2ScanDir: %wZ\\%wZ\n", &Parent->FullName, FileName));
584
585 _SEH2_TRY {
586
587 /* grab parent's reference first */
588 Ext2ReferMcb(Parent);
589
590 /* bad request ! Can a man be pregnant ? Maybe:) */
591 if (!IsMcbDirectory(Parent)) {
592 Status = STATUS_NOT_A_DIRECTORY;
593 _SEH2_LEAVE;
594 }
595
596 /* parent is a symlink ? */
597 if IsMcbSymLink(Parent) {
598 if (Parent->Target) {
599 Ext2ReferMcb(Parent->Target);
600 Ext2DerefMcb(Parent);
601 Parent = Parent->Target;
602 ASSERT(!IsMcbSymLink(Parent));
603 } else {
604 DbgBreak();
605 Status = STATUS_NOT_A_DIRECTORY;
606 _SEH2_LEAVE;
607 }
608 }
609
610 de = Ext2BuildEntry(Vcb, Parent, FileName);
611 if (!de) {
612 DEBUG(DL_ERR, ( "Ex2ScanDir: failed to allocate dentry.\n"));
613 Status = STATUS_INSUFFICIENT_RESOURCES;
614 _SEH2_LEAVE;
615 }
616
617 bh = ext3_find_entry(IrpContext, de, &dir_entry);
618 if (dir_entry) {
619 Status = STATUS_SUCCESS;
620 *Inode = dir_entry->inode;
621 *dentry = de;
622 }
623
624 } _SEH2_FINALLY {
625
626 Ext2DerefMcb(Parent);
627
628 if (bh)
629 __brelse(bh);
630
631 if (!NT_SUCCESS(Status)) {
632 if (de)
633 Ext2FreeEntry(de);
634 }
635 } _SEH2_END;
636
637 return Status;
638 }
639
640 NTSTATUS Ext2AddDotEntries(struct ext2_icb *icb, struct inode *dir,
641 struct inode *inode)
642 {
643 struct ext3_dir_entry_2 * de;
644 struct buffer_head * bh;
645 ext3_lblk_t block = 0;
646 int rc = 0;
647
648 bh = ext3_append(icb, inode, &block, &rc);
649 if (!bh) {
650 goto errorout;
651 }
652
653 de = (struct ext3_dir_entry_2 *) bh->b_data;
654 de->inode = cpu_to_le32(inode->i_ino);
655 de->name_len = 1;
656 de->rec_len = cpu_to_le16(EXT3_DIR_REC_LEN(de->name_len));
657 strcpy (de->name, ".");
658 ext3_set_de_type(inode->i_sb, de, S_IFDIR);
659 de = (struct ext3_dir_entry_2 *)
660 ((char *) de + le16_to_cpu(de->rec_len));
661 de->inode = cpu_to_le32(dir->i_ino);
662 de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize-EXT3_DIR_REC_LEN(1));
663 de->name_len = 2;
664 strcpy (de->name, "..");
665 ext3_set_de_type(inode->i_sb, de, S_IFDIR);
666 inode->i_nlink = 2;
667 set_buffer_dirty(bh);
668 ext3_mark_inode_dirty(icb, inode);
669
670 errorout:
671 if (bh)
672 __brelse (bh);
673
674 return Ext2WinntError(rc);
675 }
676
677 NTSTATUS
678 Ext2CreateFile(
679 PEXT2_IRP_CONTEXT IrpContext,
680 PEXT2_VCB Vcb,
681 PBOOLEAN OpPostIrp
682 )
683 {
684 NTSTATUS Status = STATUS_UNSUCCESSFUL;
685 PIO_STACK_LOCATION IrpSp;
686 PEXT2_FCB Fcb = NULL;
687 PEXT2_MCB Mcb = NULL;
688 PEXT2_MCB SymLink = NULL;
689 PEXT2_CCB Ccb = NULL;
690
691 PEXT2_FCB ParentFcb = NULL;
692 PEXT2_MCB ParentMcb = NULL;
693
694 UNICODE_STRING FileName;
695 PIRP Irp;
696
697 ULONG Options;
698 ULONG CreateDisposition;
699
700 BOOLEAN bParentFcbCreated = FALSE;
701
702 #ifndef __REACTOS__
703 BOOLEAN bDir = FALSE;
704 #endif
705 BOOLEAN bFcbAllocated = FALSE;
706 BOOLEAN bCreated = FALSE;
707 BOOLEAN bMainResourceAcquired = FALSE;
708
709 BOOLEAN OpenDirectory;
710 BOOLEAN OpenTargetDirectory;
711 BOOLEAN CreateDirectory;
712 BOOLEAN SequentialOnly;
713 BOOLEAN NoIntermediateBuffering;
714 BOOLEAN IsPagingFile;
715 BOOLEAN DirectoryFile;
716 BOOLEAN NonDirectoryFile;
717 BOOLEAN NoEaKnowledge;
718 BOOLEAN DeleteOnClose;
719 BOOLEAN TemporaryFile;
720 BOOLEAN CaseSensitive;
721 BOOLEAN OpenReparsePoint;
722
723 ACCESS_MASK DesiredAccess;
724 ULONG ShareAccess;
725 ULONG CcbFlags = 0;
726
727 RtlZeroMemory(&FileName, sizeof(UNICODE_STRING));
728
729 Irp = IrpContext->Irp;
730 IrpSp = IoGetCurrentIrpStackLocation(Irp);
731
732 Options = IrpSp->Parameters.Create.Options;
733
734 DirectoryFile = IsFlagOn(Options, FILE_DIRECTORY_FILE);
735 OpenTargetDirectory = IsFlagOn(IrpSp->Flags, SL_OPEN_TARGET_DIRECTORY);
736
737 NonDirectoryFile = IsFlagOn(Options, FILE_NON_DIRECTORY_FILE);
738 SequentialOnly = IsFlagOn(Options, FILE_SEQUENTIAL_ONLY);
739 NoIntermediateBuffering = IsFlagOn( Options, FILE_NO_INTERMEDIATE_BUFFERING );
740 NoEaKnowledge = IsFlagOn(Options, FILE_NO_EA_KNOWLEDGE);
741 DeleteOnClose = IsFlagOn(Options, FILE_DELETE_ON_CLOSE);
742
743 /* Try to open reparse point (symlink) itself ? */
744 OpenReparsePoint = IsFlagOn(Options, FILE_OPEN_REPARSE_POINT);
745
746 CaseSensitive = IsFlagOn(IrpSp->Flags, SL_CASE_SENSITIVE);
747
748 TemporaryFile = IsFlagOn(IrpSp->Parameters.Create.FileAttributes,
749 FILE_ATTRIBUTE_TEMPORARY );
750
751 CreateDisposition = (Options >> 24) & 0x000000ff;
752
753 IsPagingFile = IsFlagOn(IrpSp->Flags, SL_OPEN_PAGING_FILE);
754
755 CreateDirectory = (BOOLEAN)(DirectoryFile &&
756 ((CreateDisposition == FILE_CREATE) ||
757 (CreateDisposition == FILE_OPEN_IF)));
758
759 OpenDirectory = (BOOLEAN)(DirectoryFile &&
760 ((CreateDisposition == FILE_OPEN) ||
761 (CreateDisposition == FILE_OPEN_IF)));
762
763 DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
764 ShareAccess = IrpSp->Parameters.Create.ShareAccess;
765
766 *OpPostIrp = FALSE;
767
768 _SEH2_TRY {
769
770 FileName.MaximumLength = IrpSp->FileObject->FileName.MaximumLength;
771 FileName.Length = IrpSp->FileObject->FileName.Length;
772
773 if (IrpSp->FileObject->RelatedFileObject) {
774 ParentFcb = (PEXT2_FCB)(IrpSp->FileObject->RelatedFileObject->FsContext);
775 }
776
777 if (ParentFcb) {
778 ParentMcb = ParentFcb->Mcb;
779 SetLongFlag(ParentFcb->Flags, FCB_STATE_BUSY);
780 Ext2ReferMcb(ParentMcb);
781 }
782
783 if (FileName.Length == 0) {
784
785 if (ParentFcb) {
786 Mcb = ParentFcb->Mcb;
787 Ext2ReferMcb(Mcb);
788 Status = STATUS_SUCCESS;
789 goto McbExisting;
790 } else {
791 DbgBreak();
792 Status = STATUS_INVALID_PARAMETER;
793 _SEH2_LEAVE;
794 }
795 }
796
797 FileName.Buffer = Ext2AllocatePool(
798 PagedPool,
799 FileName.MaximumLength,
800 EXT2_FNAME_MAGIC
801 );
802
803 if (!FileName.Buffer) {
804 DEBUG(DL_ERR, ( "Ex2CreateFile: failed to allocate FileName.\n"));
805 Status = STATUS_INSUFFICIENT_RESOURCES;
806 _SEH2_LEAVE;
807 }
808
809 INC_MEM_COUNT(PS_FILE_NAME, FileName.Buffer, FileName.MaximumLength);
810
811 RtlZeroMemory(FileName.Buffer, FileName.MaximumLength);
812 RtlCopyMemory(FileName.Buffer, IrpSp->FileObject->FileName.Buffer, FileName.Length);
813
814 if (ParentFcb && FileName.Buffer[0] == L'\\') {
815 Status = STATUS_INVALID_PARAMETER;
816 _SEH2_LEAVE;
817 }
818
819 if ((FileName.Length > sizeof(WCHAR)) &&
820 (FileName.Buffer[1] == L'\\') &&
821 (FileName.Buffer[0] == L'\\')) {
822
823 FileName.Length -= sizeof(WCHAR);
824
825 RtlMoveMemory( &FileName.Buffer[0],
826 &FileName.Buffer[1],
827 FileName.Length );
828
829 //
830 // Bad Name if there are still beginning backslashes.
831 //
832
833 if ((FileName.Length > sizeof(WCHAR)) &&
834 (FileName.Buffer[1] == L'\\') &&
835 (FileName.Buffer[0] == L'\\')) {
836
837 Status = STATUS_OBJECT_NAME_INVALID;
838 _SEH2_LEAVE;
839 }
840 }
841
842 if (IsFlagOn(Options, FILE_OPEN_BY_FILE_ID)) {
843 Status = STATUS_NOT_IMPLEMENTED;
844 _SEH2_LEAVE;
845 }
846
847 DEBUG(DL_INF, ( "Ext2CreateFile: %wZ Paging=%d Option: %xh:"
848 "Dir=%d NonDir=%d OpenTarget=%d NC=%d DeleteOnClose=%d\n",
849 &FileName, IsPagingFile, IrpSp->Parameters.Create.Options,
850 DirectoryFile, NonDirectoryFile, OpenTargetDirectory,
851 NoIntermediateBuffering, DeleteOnClose ));
852
853 DEBUG(DL_RES, ("Ext2CreateFile: Lookup 1st: %wZ at %S\n",
854 &FileName, ParentMcb ? ParentMcb->FullName.Buffer : L" "));
855 Status = Ext2LookupFile(
856 IrpContext,
857 Vcb,
858 &FileName,
859 ParentMcb,
860 &Mcb,
861 0 /* always follow link */
862 );
863 McbExisting:
864
865 if (!NT_SUCCESS(Status)) {
866
867 UNICODE_STRING PathName;
868 UNICODE_STRING RealName;
869 UNICODE_STRING RemainName;
870
871 #ifndef __REACTOS__
872 LONG i = 0;
873 #endif
874
875 PathName = FileName;
876 Mcb = NULL;
877
878 if (PathName.Buffer[PathName.Length/2 - 1] == L'\\') {
879 if (DirectoryFile) {
880 PathName.Length -=2;
881 PathName.Buffer[PathName.Length/2] = 0;
882 } else {
883 DirectoryFile = TRUE;
884 }
885 }
886
887 if (!ParentMcb) {
888 if (PathName.Buffer[0] != L'\\') {
889 Status = STATUS_OBJECT_PATH_NOT_FOUND;
890 _SEH2_LEAVE;
891 } else {
892 ParentMcb = Vcb->McbTree;
893 Ext2ReferMcb(ParentMcb);
894 }
895 }
896
897 Dissecting:
898
899 FsRtlDissectName(PathName, &RealName, &RemainName);
900
901 if (((RemainName.Length != 0) && (RemainName.Buffer[0] == L'\\')) ||
902 (RealName.Length >= 256 * sizeof(WCHAR))) {
903 Status = STATUS_OBJECT_NAME_INVALID;
904 _SEH2_LEAVE;
905 }
906
907 if (RemainName.Length != 0) {
908
909 PEXT2_MCB RetMcb = NULL;
910
911 DEBUG(DL_RES, ("Ext2CreateFile: Lookup 2nd: %wZ\\%wZ\n",
912 &ParentMcb->FullName, &RealName));
913
914 Status = Ext2LookupFile (
915 IrpContext,
916 Vcb,
917 &RealName,
918 ParentMcb,
919 &RetMcb,
920 0);
921
922 /* quit name resolving loop */
923 if (!NT_SUCCESS(Status)) {
924 if (Status == STATUS_NO_SUCH_FILE && RemainName.Length != 0) {
925 Status = STATUS_OBJECT_PATH_NOT_FOUND;
926 }
927 _SEH2_LEAVE;
928 }
929
930 /* deref ParentMcb */
931 Ext2DerefMcb(ParentMcb);
932
933 /* RetMcb is already refered */
934 ParentMcb = RetMcb;
935 PathName = RemainName;
936
937 /* symlink must use it's target */
938 if (IsMcbSymLink(ParentMcb)) {
939 Ext2ReferMcb(ParentMcb->Target);
940 Ext2DerefMcb(ParentMcb);
941 ParentMcb = ParentMcb->Target;
942 ASSERT(!IsMcbSymLink(ParentMcb));
943 }
944
945 goto Dissecting;
946 }
947
948 /* is name valid */
949 if ( FsRtlDoesNameContainWildCards(&RealName) ||
950 !Ext2IsNameValid(&RealName)) {
951 Status = STATUS_OBJECT_NAME_INVALID;
952 _SEH2_LEAVE;
953 }
954
955 /* clear BUSY bit from original ParentFcb */
956 if (ParentFcb) {
957 ClearLongFlag(ParentFcb->Flags, FCB_STATE_BUSY);
958 }
959
960 /* get the ParentFcb, allocate it if needed ... */
961 ParentFcb = ParentMcb->Fcb;
962 if (!ParentFcb) {
963 ParentFcb = Ext2AllocateFcb(Vcb, ParentMcb);
964 if (!ParentFcb) {
965 Status = STATUS_INSUFFICIENT_RESOURCES;
966 _SEH2_LEAVE;
967 }
968 bParentFcbCreated = TRUE;
969 Ext2ReferXcb(&ParentFcb->ReferenceCount);
970 }
971 SetLongFlag(ParentFcb->Flags, FCB_STATE_BUSY);
972
973 // We need to create a new one ?
974 if ((CreateDisposition == FILE_CREATE ) ||
975 (CreateDisposition == FILE_SUPERSEDE) ||
976 (CreateDisposition == FILE_OPEN_IF) ||
977 (CreateDisposition == FILE_OVERWRITE_IF)) {
978
979 if (IsVcbReadOnly(Vcb)) {
980 Status = STATUS_MEDIA_WRITE_PROTECTED;
981 _SEH2_LEAVE;
982 }
983
984 if (!Ext2CheckFileAccess(Vcb, ParentMcb, Ext2FileCanWrite)) {
985 Status = STATUS_ACCESS_DENIED;
986 _SEH2_LEAVE;
987 }
988
989 if (IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) {
990 IoSetHardErrorOrVerifyDevice( IrpContext->Irp,
991 Vcb->Vpb->RealDevice );
992 SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
993 Ext2RaiseStatus(IrpContext, STATUS_MEDIA_WRITE_PROTECTED);
994 }
995
996 if (DirectoryFile) {
997 if (TemporaryFile) {
998 DbgBreak();
999 Status = STATUS_INVALID_PARAMETER;
1000 _SEH2_LEAVE;
1001 }
1002 }
1003
1004 if (!ParentFcb) {
1005 Status = STATUS_OBJECT_PATH_NOT_FOUND;
1006 _SEH2_LEAVE;
1007 }
1008
1009 /* allocate inode and construct entry for this file */
1010 Status = Ext2CreateInode(
1011 IrpContext,
1012 Vcb,
1013 ParentFcb,
1014 DirectoryFile ? EXT2_FT_DIR : EXT2_FT_REG_FILE,
1015 IrpSp->Parameters.Create.FileAttributes,
1016 &RealName
1017 );
1018
1019 if (!NT_SUCCESS(Status)) {
1020 DbgBreak();
1021 _SEH2_LEAVE;
1022 }
1023
1024 bCreated = TRUE;
1025 DEBUG(DL_RES, ("Ext2CreateFile: Confirm creation: %wZ\\%wZ\n",
1026 &ParentMcb->FullName, &RealName));
1027
1028 Irp->IoStatus.Information = FILE_CREATED;
1029 Status = Ext2LookupFile (
1030 IrpContext,
1031 Vcb,
1032 &RealName,
1033 ParentMcb,
1034 &Mcb,
1035 0);
1036 if (!NT_SUCCESS(Status)) {
1037 DbgBreak();
1038 }
1039
1040 } else if (OpenTargetDirectory) {
1041
1042 if (IsVcbReadOnly(Vcb)) {
1043 Status = STATUS_MEDIA_WRITE_PROTECTED;
1044 _SEH2_LEAVE;
1045 }
1046
1047 if (!ParentFcb) {
1048 Status = STATUS_OBJECT_PATH_NOT_FOUND;
1049 _SEH2_LEAVE;
1050 }
1051
1052 RtlZeroMemory( IrpSp->FileObject->FileName.Buffer,
1053 IrpSp->FileObject->FileName.MaximumLength);
1054 IrpSp->FileObject->FileName.Length = RealName.Length;
1055
1056 RtlCopyMemory( IrpSp->FileObject->FileName.Buffer,
1057 RealName.Buffer,
1058 RealName.Length );
1059
1060 Fcb = ParentFcb;
1061 Mcb = Fcb->Mcb;
1062 Ext2ReferMcb(Mcb);
1063
1064 Irp->IoStatus.Information = FILE_DOES_NOT_EXIST;
1065 Status = STATUS_SUCCESS;
1066
1067 } else {
1068
1069 Status = STATUS_OBJECT_NAME_NOT_FOUND;
1070 _SEH2_LEAVE;
1071 }
1072
1073 } else { // File / Dir already exists.
1074
1075 /* here already get Mcb referred */
1076 if (OpenTargetDirectory) {
1077
1078 UNICODE_STRING RealName = FileName;
1079 USHORT i = 0;
1080
1081 while (RealName.Buffer[RealName.Length/2 - 1] == L'\\') {
1082 RealName.Length -= sizeof(WCHAR);
1083 RealName.Buffer[RealName.Length/2] = 0;
1084 }
1085 i = RealName.Length/2;
1086 while (i > 0 && RealName.Buffer[i - 1] != L'\\')
1087 i--;
1088
1089 if (IsVcbReadOnly(Vcb)) {
1090 Status = STATUS_MEDIA_WRITE_PROTECTED;
1091 Ext2DerefMcb(Mcb);
1092 _SEH2_LEAVE;
1093 }
1094
1095 Irp->IoStatus.Information = FILE_EXISTS;
1096 Status = STATUS_SUCCESS;
1097
1098 RtlZeroMemory( IrpSp->FileObject->FileName.Buffer,
1099 IrpSp->FileObject->FileName.MaximumLength);
1100 IrpSp->FileObject->FileName.Length = RealName.Length - i * sizeof(WCHAR);
1101 RtlCopyMemory( IrpSp->FileObject->FileName.Buffer, &RealName.Buffer[i],
1102 IrpSp->FileObject->FileName.Length );
1103
1104 // use's it's parent since it's open-target operation
1105 Ext2ReferMcb(Mcb->Parent);
1106 Ext2DerefMcb(Mcb);
1107 Mcb = Mcb->Parent;
1108
1109 goto Openit;
1110 }
1111
1112 // We can not create if one exists
1113 if (CreateDisposition == FILE_CREATE) {
1114 Irp->IoStatus.Information = FILE_EXISTS;
1115 Status = STATUS_OBJECT_NAME_COLLISION;
1116 Ext2DerefMcb(Mcb);
1117 _SEH2_LEAVE;
1118 }
1119
1120 /* directory forbits us to do the followings ... */
1121 if (IsMcbDirectory(Mcb)) {
1122
1123 if ((CreateDisposition != FILE_OPEN) &&
1124 (CreateDisposition != FILE_OPEN_IF)) {
1125
1126 Status = STATUS_OBJECT_NAME_COLLISION;
1127 Ext2DerefMcb(Mcb);
1128 _SEH2_LEAVE;
1129 }
1130
1131 if (NonDirectoryFile) {
1132 Status = STATUS_FILE_IS_A_DIRECTORY;
1133 Ext2DerefMcb(Mcb);
1134 _SEH2_LEAVE;
1135 }
1136
1137 if (Mcb->Inode.i_ino == EXT2_ROOT_INO) {
1138
1139 if (OpenTargetDirectory) {
1140 DbgBreak();
1141 Status = STATUS_INVALID_PARAMETER;
1142 Ext2DerefMcb(Mcb);
1143 _SEH2_LEAVE;
1144 }
1145 }
1146
1147 } else {
1148
1149 if (DirectoryFile) {
1150 Status = STATUS_NOT_A_DIRECTORY;;
1151 Ext2DerefMcb(Mcb);
1152 _SEH2_LEAVE;
1153 }
1154 }
1155
1156 Irp->IoStatus.Information = FILE_OPENED;
1157 }
1158
1159 Openit:
1160 /* Mcb should already be referred and symlink is too */
1161 if (Mcb) {
1162
1163 ASSERT(Mcb->Refercount > 0);
1164
1165 /* refer it's target if it's a symlink, so both refered */
1166 if (IsMcbSymLink(Mcb)) {
1167
1168 if (OpenReparsePoint) {
1169 /* set Ccb flag */
1170 CcbFlags = CCB_OPEN_REPARSE_POINT;
1171 } else if (IsFileDeleted(Mcb->Target)) {
1172 DbgBreak();
1173 SetLongFlag(Mcb->Flags, MCB_TYPE_SPECIAL);
1174 ClearLongFlag(Mcb->Flags, MCB_TYPE_SYMLINK);
1175 Ext2DerefMcb(Mcb->Target);
1176 Mcb->Target = NULL;
1177 } else {
1178 SymLink = Mcb;
1179 Mcb = Mcb->Target;
1180 Ext2ReferMcb(Mcb);
1181 ASSERT (!IsMcbSymLink(Mcb));
1182 }
1183 }
1184
1185 // Check readonly flag
1186 if (BooleanFlagOn(DesiredAccess, FILE_GENERIC_READ) &&
1187 !Ext2CheckFileAccess(Vcb, Mcb, Ext2FileCanRead)) {
1188 Status = STATUS_ACCESS_DENIED;
1189 _SEH2_LEAVE;
1190 }
1191 if (!Ext2CheckFileAccess(Vcb, Mcb, Ext2FileCanWrite)) {
1192 if (BooleanFlagOn(DesiredAccess, FILE_WRITE_DATA | FILE_APPEND_DATA |
1193 FILE_ADD_SUBDIRECTORY | FILE_DELETE_CHILD)) {
1194 Status = STATUS_ACCESS_DENIED;
1195 _SEH2_LEAVE;
1196 } else if (IsFlagOn(Options, FILE_DELETE_ON_CLOSE )) {
1197 Status = STATUS_CANNOT_DELETE;
1198 _SEH2_LEAVE;
1199 }
1200 }
1201
1202 Fcb = Mcb->Fcb;
1203 if (Fcb == NULL) {
1204
1205 /* allocate Fcb for this file */
1206 Fcb = Ext2AllocateFcb (Vcb, Mcb);
1207 if (Fcb) {
1208 bFcbAllocated = TRUE;
1209 } else {
1210 Status = STATUS_INSUFFICIENT_RESOURCES;
1211 }
1212 } else {
1213 if (IsPagingFile) {
1214 Status = STATUS_SHARING_VIOLATION;
1215 Fcb = NULL;
1216 }
1217 }
1218
1219 /* Now it's safe to defer Mcb */
1220 Ext2DerefMcb(Mcb);
1221 }
1222
1223 if (Fcb) {
1224
1225 /* grab Fcb's reference first to avoid the race between
1226 Ext2Close (it could free the Fcb we are accessing) */
1227 Ext2ReferXcb(&Fcb->ReferenceCount);
1228
1229 ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE);
1230 bMainResourceAcquired = TRUE;
1231
1232 /* Open target directory ? */
1233 if (NULL == Mcb) {
1234 DbgBreak();
1235 Mcb = Fcb->Mcb;
1236 }
1237
1238 /* check Mcb reference */
1239 ASSERT(Fcb->Mcb->Refercount > 0);
1240
1241 /* file delted ? */
1242 if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) {
1243 Status = STATUS_FILE_DELETED;
1244 _SEH2_LEAVE;
1245 }
1246
1247 if (DeleteOnClose && NULL == SymLink) {
1248 Status = Ext2IsFileRemovable(IrpContext, Vcb, Fcb, Ccb);
1249 if (!NT_SUCCESS(Status)) {
1250 _SEH2_LEAVE;
1251 }
1252 }
1253
1254 /* check access and oplock access for opened files */
1255 if (!bFcbAllocated && !IsDirectory(Fcb)) {
1256
1257 /* whether there's batch oplock grabed on the file */
1258 if (FsRtlCurrentBatchOplock(&Fcb->Oplock)) {
1259
1260 Irp->IoStatus.Information = FILE_OPBATCH_BREAK_UNDERWAY;
1261
1262 /* break the batch lock if the sharing check fails */
1263 Status = FsRtlCheckOplock( &Fcb->Oplock,
1264 IrpContext->Irp,
1265 IrpContext,
1266 Ext2OplockComplete,
1267 Ext2LockIrp );
1268
1269 if ( Status != STATUS_SUCCESS &&
1270 Status != STATUS_OPLOCK_BREAK_IN_PROGRESS) {
1271 *OpPostIrp = TRUE;
1272 _SEH2_LEAVE;
1273 }
1274 }
1275 }
1276
1277 if (bCreated) {
1278
1279 //
1280 // This file is just created.
1281 //
1282
1283 if (DirectoryFile) {
1284
1285 Status = Ext2AddDotEntries(IrpContext, &ParentMcb->Inode, &Mcb->Inode);
1286 if (!NT_SUCCESS(Status)) {
1287 Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb);
1288 _SEH2_LEAVE;
1289 }
1290
1291 } else {
1292
1293 if ((LONGLONG)ext3_free_blocks_count(SUPER_BLOCK) <=
1294 Ext2TotalBlocks(Vcb, &Irp->Overlay.AllocationSize, NULL)) {
1295 DbgBreak();
1296 Status = STATUS_DISK_FULL;
1297 _SEH2_LEAVE;
1298 }
1299
1300 /* disable data blocks allocation */
1301 #if 0
1302 Fcb->Header.AllocationSize.QuadPart =
1303 Irp->Overlay.AllocationSize.QuadPart;
1304
1305 if (Fcb->Header.AllocationSize.QuadPart > 0) {
1306 Status = Ext2ExpandFile(IrpContext,
1307 Vcb,
1308 Fcb->Mcb,
1309 &(Fcb->Header.AllocationSize)
1310 );
1311 SetLongFlag(Fcb->Flags, FCB_ALLOC_IN_CREATE);
1312 if (!NT_SUCCESS(Status)) {
1313 Fcb->Header.AllocationSize.QuadPart = 0;
1314 Ext2TruncateFile(IrpContext, Vcb, Fcb->Mcb,
1315 &Fcb->Header.AllocationSize);
1316 _SEH2_LEAVE;
1317 }
1318 }
1319 #endif
1320 }
1321
1322 } else {
1323
1324 //
1325 // This file alreayd exists.
1326 //
1327
1328 if (DeleteOnClose) {
1329
1330 if (IsVcbReadOnly(Vcb)) {
1331 Status = STATUS_MEDIA_WRITE_PROTECTED;
1332 _SEH2_LEAVE;
1333 }
1334
1335 if (IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) {
1336 Status = STATUS_MEDIA_WRITE_PROTECTED;
1337
1338 IoSetHardErrorOrVerifyDevice( IrpContext->Irp,
1339 Vcb->Vpb->RealDevice );
1340
1341 SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
1342
1343 Ext2RaiseStatus(IrpContext, STATUS_MEDIA_WRITE_PROTECTED);
1344 }
1345
1346 } else {
1347
1348 //
1349 // Just to Open file (Open/OverWrite ...)
1350 //
1351
1352 if ((!IsDirectory(Fcb)) && (IsFlagOn(IrpSp->FileObject->Flags,
1353 FO_NO_INTERMEDIATE_BUFFERING))) {
1354 Fcb->Header.IsFastIoPossible = FastIoIsPossible;
1355
1356 if (Fcb->SectionObject.DataSectionObject != NULL) {
1357
1358 if (Fcb->NonCachedOpenCount == Fcb->OpenHandleCount) {
1359
1360 if (!IsVcbReadOnly(Vcb)) {
1361 CcFlushCache(&Fcb->SectionObject, NULL, 0, NULL);
1362 ClearLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);
1363 }
1364
1365 CcPurgeCacheSection(&Fcb->SectionObject,
1366 NULL,
1367 0,
1368 FALSE );
1369 }
1370 }
1371 }
1372 }
1373 }
1374
1375 if (!IsDirectory(Fcb)) {
1376
1377 if (!IsVcbReadOnly(Vcb)) {
1378 if ((CreateDisposition == FILE_SUPERSEDE) && !IsPagingFile) {
1379 DesiredAccess |= DELETE;
1380 } else if (((CreateDisposition == FILE_OVERWRITE) ||
1381 (CreateDisposition == FILE_OVERWRITE_IF)) && !IsPagingFile) {
1382 DesiredAccess |= (FILE_WRITE_DATA | FILE_WRITE_EA |
1383 FILE_WRITE_ATTRIBUTES );
1384 }
1385 }
1386
1387 if (!bFcbAllocated) {
1388
1389 //
1390 // check the oplock state of the file
1391 //
1392
1393 Status = FsRtlCheckOplock( &Fcb->Oplock,
1394 IrpContext->Irp,
1395 IrpContext,
1396 Ext2OplockComplete,
1397 Ext2LockIrp );
1398
1399 if ( Status != STATUS_SUCCESS &&
1400 Status != STATUS_OPLOCK_BREAK_IN_PROGRESS) {
1401 *OpPostIrp = TRUE;
1402 _SEH2_LEAVE;
1403 }
1404 }
1405 }
1406
1407 if (Fcb->OpenHandleCount > 0) {
1408
1409 /* check the shrae access conflicts */
1410 Status = IoCheckShareAccess( DesiredAccess,
1411 ShareAccess,
1412 IrpSp->FileObject,
1413 &(Fcb->ShareAccess),
1414 TRUE );
1415 if (!NT_SUCCESS(Status)) {
1416 _SEH2_LEAVE;
1417 }
1418
1419 } else {
1420
1421 /* set share access rights */
1422 IoSetShareAccess( DesiredAccess,
1423 ShareAccess,
1424 IrpSp->FileObject,
1425 &(Fcb->ShareAccess) );
1426 }
1427
1428 Ccb = Ext2AllocateCcb(CcbFlags, SymLink);
1429 if (!Ccb) {
1430 Status = STATUS_INSUFFICIENT_RESOURCES;
1431 DbgBreak();
1432 _SEH2_LEAVE;
1433 }
1434
1435 if (DeleteOnClose)
1436 SetLongFlag(Ccb->Flags, CCB_DELETE_ON_CLOSE);
1437
1438 if (SymLink)
1439 Ccb->filp.f_dentry = SymLink->de;
1440 else
1441 Ccb->filp.f_dentry = Fcb->Mcb->de;
1442
1443 Ccb->filp.f_version = Fcb->Mcb->Inode.i_version;
1444 Ext2ReferXcb(&Fcb->OpenHandleCount);
1445 Ext2ReferXcb(&Fcb->ReferenceCount);
1446
1447 if (!IsDirectory(Fcb)) {
1448 if (NoIntermediateBuffering) {
1449 Fcb->NonCachedOpenCount++;
1450 SetFlag(IrpSp->FileObject->Flags, FO_CACHE_SUPPORTED);
1451 } else {
1452 SetFlag(IrpSp->FileObject->Flags, FO_CACHE_SUPPORTED);
1453 }
1454 }
1455
1456 Ext2ReferXcb(&Vcb->OpenHandleCount);
1457 Ext2ReferXcb(&Vcb->ReferenceCount);
1458
1459 IrpSp->FileObject->FsContext = (void*) Fcb;
1460 IrpSp->FileObject->FsContext2 = (void*) Ccb;
1461 IrpSp->FileObject->PrivateCacheMap = NULL;
1462 IrpSp->FileObject->SectionObjectPointer = &(Fcb->SectionObject);
1463
1464 DEBUG(DL_INF, ( "Ext2CreateFile: %wZ OpenCount=%u ReferCount=%u NonCachedCount=%u\n",
1465 &Fcb->Mcb->FullName, Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->NonCachedOpenCount));
1466
1467 Status = STATUS_SUCCESS;
1468
1469 if (bCreated) {
1470
1471 if (IsDirectory(Fcb)) {
1472 Ext2NotifyReportChange(
1473 IrpContext,
1474 Vcb,
1475 Fcb->Mcb,
1476 FILE_NOTIFY_CHANGE_DIR_NAME,
1477 FILE_ACTION_ADDED );
1478 } else {
1479 Ext2NotifyReportChange(
1480 IrpContext,
1481 Vcb,
1482 Fcb->Mcb,
1483 FILE_NOTIFY_CHANGE_FILE_NAME,
1484 FILE_ACTION_ADDED );
1485 }
1486
1487 } else if (!IsDirectory(Fcb)) {
1488
1489 if ( DeleteOnClose ||
1490 IsFlagOn(DesiredAccess, FILE_WRITE_DATA) ||
1491 (CreateDisposition == FILE_OVERWRITE) ||
1492 (CreateDisposition == FILE_OVERWRITE_IF)) {
1493 if (!MmFlushImageSection( &Fcb->SectionObject,
1494 MmFlushForWrite )) {
1495
1496 Status = DeleteOnClose ? STATUS_CANNOT_DELETE :
1497 STATUS_SHARING_VIOLATION;
1498 _SEH2_LEAVE;
1499 }
1500 }
1501
1502 if ((CreateDisposition == FILE_SUPERSEDE) ||
1503 (CreateDisposition == FILE_OVERWRITE) ||
1504 (CreateDisposition == FILE_OVERWRITE_IF)) {
1505
1506 if (IsDirectory(Fcb)) {
1507 Status = STATUS_FILE_IS_A_DIRECTORY;
1508 _SEH2_LEAVE;
1509 }
1510
1511 if (SymLink != NULL) {
1512 DbgBreak();
1513 Status = STATUS_INVALID_PARAMETER;
1514 _SEH2_LEAVE;
1515 }
1516
1517 if (IsVcbReadOnly(Vcb)) {
1518 Status = STATUS_MEDIA_WRITE_PROTECTED;
1519 _SEH2_LEAVE;
1520 }
1521
1522 if (IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) {
1523
1524 IoSetHardErrorOrVerifyDevice( IrpContext->Irp,
1525 Vcb->Vpb->RealDevice );
1526 SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
1527 Ext2RaiseStatus(IrpContext, STATUS_MEDIA_WRITE_PROTECTED);
1528 }
1529
1530 Status = Ext2SupersedeOrOverWriteFile(
1531 IrpContext,
1532 IrpSp->FileObject,
1533 Vcb,
1534 Fcb,
1535 &Irp->Overlay.AllocationSize,
1536 CreateDisposition );
1537
1538 if (!NT_SUCCESS(Status)) {
1539 DbgBreak();
1540 _SEH2_LEAVE;
1541 }
1542
1543 Ext2NotifyReportChange(
1544 IrpContext,
1545 Vcb,
1546 Fcb->Mcb,
1547 FILE_NOTIFY_CHANGE_LAST_WRITE |
1548 FILE_NOTIFY_CHANGE_ATTRIBUTES |
1549 FILE_NOTIFY_CHANGE_SIZE,
1550 FILE_ACTION_MODIFIED );
1551
1552
1553 if (CreateDisposition == FILE_SUPERSEDE) {
1554 Irp->IoStatus.Information = FILE_SUPERSEDED;
1555 } else {
1556 Irp->IoStatus.Information = FILE_OVERWRITTEN;
1557 }
1558 }
1559 }
1560
1561 } else {
1562 DbgBreak();
1563 _SEH2_LEAVE;
1564 }
1565
1566 } _SEH2_FINALLY {
1567
1568
1569 if (ParentMcb) {
1570 Ext2DerefMcb(ParentMcb);
1571 }
1572
1573 /* cleanup Fcb and Ccb, Mcb if necessary */
1574 if (!NT_SUCCESS(Status)) {
1575
1576 if (Ccb != NULL) {
1577
1578 DbgBreak();
1579
1580 ASSERT(Fcb != NULL);
1581 ASSERT(Fcb->Mcb != NULL);
1582
1583 DEBUG(DL_ERR, ("Ext2CreateFile: failed to create %wZ status = %xh\n",
1584 &Fcb->Mcb->FullName, Status));
1585
1586 Ext2DerefXcb(&Fcb->OpenHandleCount);
1587 Ext2DerefXcb(&Fcb->ReferenceCount);
1588
1589 if (!IsDirectory(Fcb)) {
1590 if (NoIntermediateBuffering) {
1591 Fcb->NonCachedOpenCount--;
1592 } else {
1593 ClearFlag(IrpSp->FileObject->Flags, FO_CACHE_SUPPORTED);
1594 }
1595 }
1596
1597 Ext2DerefXcb(&Vcb->OpenHandleCount);
1598 Ext2DerefXcb(&Vcb->ReferenceCount);
1599
1600 IoRemoveShareAccess(IrpSp->FileObject, &Fcb->ShareAccess);
1601
1602 IrpSp->FileObject->FsContext = NULL;
1603 IrpSp->FileObject->FsContext2 = NULL;
1604 IrpSp->FileObject->PrivateCacheMap = NULL;
1605 IrpSp->FileObject->SectionObjectPointer = NULL;
1606
1607 Ext2FreeCcb(Vcb, Ccb);
1608 }
1609 }
1610
1611 if (Fcb && Ext2DerefXcb(&Fcb->ReferenceCount) == 0) {
1612
1613 if (IsFlagOn(Fcb->Flags, FCB_ALLOC_IN_CREATE)) {
1614
1615 LARGE_INTEGER Size;
1616 ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, TRUE);
1617 _SEH2_TRY {
1618 Size.QuadPart = 0;
1619 Ext2TruncateFile(IrpContext, Vcb, Fcb->Mcb, &Size);
1620 } _SEH2_FINALLY {
1621 ExReleaseResourceLite(&Fcb->PagingIoResource);
1622 } _SEH2_END;
1623 }
1624
1625 if (bCreated) {
1626 Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb);
1627 }
1628
1629 Ext2FreeFcb(Fcb);
1630 Fcb = NULL;
1631 bMainResourceAcquired = FALSE;
1632 }
1633
1634 if (bMainResourceAcquired) {
1635 ExReleaseResourceLite(&Fcb->MainResource);
1636 }
1637
1638 /* free file name buffer */
1639 if (FileName.Buffer) {
1640 DEC_MEM_COUNT(PS_FILE_NAME, FileName.Buffer, FileName.MaximumLength);
1641 Ext2FreePool(FileName.Buffer, EXT2_FNAME_MAGIC);
1642 }
1643
1644 /* dereference parent Fcb, free it if it goes to zero */
1645 if (ParentFcb) {
1646 ClearLongFlag(ParentFcb->Flags, FCB_STATE_BUSY);
1647 if (bParentFcbCreated) {
1648 if (Ext2DerefXcb(&ParentFcb->ReferenceCount) == 0) {
1649 Ext2FreeFcb(ParentFcb);
1650 }
1651 }
1652 }
1653
1654 /* drop SymLink's refer: If succeeds, Ext2AllocateCcb should refer
1655 it already. It fails, we need release the refer to let it freed */
1656 if (SymLink) {
1657 Ext2DerefMcb(SymLink);
1658 }
1659 } _SEH2_END;
1660
1661 return Status;
1662 }
1663
1664 NTSTATUS
1665 Ext2CreateVolume(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb)
1666 {
1667 PIO_STACK_LOCATION IrpSp;
1668 PIRP Irp;
1669 PEXT2_CCB Ccb;
1670
1671 NTSTATUS Status;
1672
1673 ACCESS_MASK DesiredAccess;
1674 ULONG ShareAccess;
1675
1676 ULONG Options;
1677 BOOLEAN DirectoryFile;
1678 BOOLEAN OpenTargetDirectory;
1679
1680 ULONG CreateDisposition;
1681
1682 Irp = IrpContext->Irp;
1683 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1684
1685 Options = IrpSp->Parameters.Create.Options;
1686
1687 DirectoryFile = IsFlagOn(Options, FILE_DIRECTORY_FILE);
1688 OpenTargetDirectory = IsFlagOn(IrpSp->Flags, SL_OPEN_TARGET_DIRECTORY);
1689
1690 CreateDisposition = (Options >> 24) & 0x000000ff;
1691
1692 DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
1693 ShareAccess = IrpSp->Parameters.Create.ShareAccess;
1694
1695 if (DirectoryFile) {
1696 return STATUS_NOT_A_DIRECTORY;
1697 }
1698
1699 if (OpenTargetDirectory) {
1700 DbgBreak();
1701 return STATUS_INVALID_PARAMETER;
1702 }
1703
1704 if ( (CreateDisposition != FILE_OPEN) &&
1705 (CreateDisposition != FILE_OPEN_IF) ) {
1706 return STATUS_ACCESS_DENIED;
1707 }
1708
1709 if ( !FlagOn(ShareAccess, FILE_SHARE_READ) &&
1710 Vcb->OpenVolumeCount != 0 ) {
1711 return STATUS_SHARING_VIOLATION;
1712 }
1713
1714 Ccb = Ext2AllocateCcb(0, NULL);
1715 if (Ccb == NULL) {
1716 Status = STATUS_INSUFFICIENT_RESOURCES;
1717 goto errorout;
1718 }
1719
1720 Status = STATUS_SUCCESS;
1721
1722 if (Vcb->OpenVolumeCount > 0) {
1723 Status = IoCheckShareAccess( DesiredAccess, ShareAccess,
1724 IrpSp->FileObject,
1725 &(Vcb->ShareAccess), TRUE);
1726
1727 if (!NT_SUCCESS(Status)) {
1728 goto errorout;
1729 }
1730 } else {
1731 IoSetShareAccess( DesiredAccess, ShareAccess,
1732 IrpSp->FileObject,
1733 &(Vcb->ShareAccess) );
1734 }
1735
1736
1737 if (Vcb->OpenVolumeCount == 0 &&
1738 !IsFlagOn(ShareAccess, FILE_SHARE_READ) &&
1739 !IsFlagOn(ShareAccess, FILE_SHARE_WRITE) ){
1740
1741 if (!IsVcbReadOnly(Vcb)) {
1742 Ext2FlushFiles(IrpContext, Vcb, FALSE);
1743 Ext2FlushVolume(IrpContext, Vcb, FALSE);
1744 }
1745
1746 SetLongFlag(Vcb->Flags, VCB_VOLUME_LOCKED);
1747 Vcb->LockFile = IrpSp->FileObject;
1748 } else {
1749 if (FlagOn(DesiredAccess, FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA) ) {
1750 if (!IsVcbReadOnly(Vcb)) {
1751 Ext2FlushFiles(IrpContext, Vcb, FALSE);
1752 Ext2FlushVolume(IrpContext, Vcb, FALSE);
1753 }
1754 }
1755 }
1756
1757 IrpSp->FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
1758 IrpSp->FileObject->FsContext = Vcb;
1759 IrpSp->FileObject->FsContext2 = Ccb;
1760 IrpSp->FileObject->Vpb = Vcb->Vpb;
1761
1762 Ext2ReferXcb(&Vcb->ReferenceCount);
1763 Ext2ReferXcb(&Vcb->OpenHandleCount);
1764 Ext2ReferXcb(&Vcb->OpenVolumeCount);
1765
1766 Irp->IoStatus.Information = FILE_OPENED;
1767
1768 errorout:
1769
1770 return Status;
1771 }
1772
1773
1774 NTSTATUS
1775 Ext2Create (IN PEXT2_IRP_CONTEXT IrpContext)
1776 {
1777 PDEVICE_OBJECT DeviceObject;
1778 PIRP Irp;
1779 PIO_STACK_LOCATION IrpSp;
1780 PEXT2_VCB Vcb = 0;
1781 NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND;
1782 PEXT2_FCBVCB Xcb = NULL;
1783 BOOLEAN PostIrp = FALSE;
1784 BOOLEAN VcbResourceAcquired = FALSE;
1785
1786 DeviceObject = IrpContext->DeviceObject;
1787 Irp = IrpContext->Irp;
1788 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1789
1790 Xcb = (PEXT2_FCBVCB) (IrpSp->FileObject->FsContext);
1791
1792 if (IsExt2FsDevice(DeviceObject)) {
1793
1794 DEBUG(DL_INF, ( "Ext2Create: Create on main device object.\n"));
1795
1796 Status = STATUS_SUCCESS;
1797 Irp->IoStatus.Information = FILE_OPENED;
1798
1799 Ext2CompleteIrpContext(IrpContext, Status);
1800
1801 return Status;
1802 }
1803
1804 _SEH2_TRY {
1805
1806 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
1807 ASSERT(Vcb->Identifier.Type == EXT2VCB);
1808 IrpSp->FileObject->Vpb = Vcb->Vpb;
1809
1810 if (!IsMounted(Vcb)) {
1811 DbgBreak();
1812 if (IsFlagOn(Vcb->Flags, VCB_DEVICE_REMOVED)) {
1813 Status = STATUS_NO_SUCH_DEVICE;
1814 } else {
1815 Status = STATUS_VOLUME_DISMOUNTED;
1816 }
1817 _SEH2_LEAVE;
1818 }
1819
1820 if (!ExAcquireResourceExclusiveLite(
1821 &Vcb->MainResource, TRUE)) {
1822 Status = STATUS_PENDING;
1823 _SEH2_LEAVE;
1824 }
1825 VcbResourceAcquired = TRUE;
1826
1827 Ext2VerifyVcb(IrpContext, Vcb);
1828
1829 if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) {
1830 Status = STATUS_ACCESS_DENIED;
1831 if (IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
1832 Status = STATUS_VOLUME_DISMOUNTED;
1833 }
1834 _SEH2_LEAVE;
1835 }
1836
1837 if ( ((IrpSp->FileObject->FileName.Length == 0) &&
1838 (IrpSp->FileObject->RelatedFileObject == NULL)) ||
1839 (Xcb && Xcb->Identifier.Type == EXT2VCB) ) {
1840 Status = Ext2CreateVolume(IrpContext, Vcb);
1841 } else {
1842
1843 Status = Ext2CreateFile(IrpContext, Vcb, &PostIrp);
1844 }
1845
1846 } _SEH2_FINALLY {
1847
1848 if (VcbResourceAcquired) {
1849 ExReleaseResourceLite(&Vcb->MainResource);
1850 }
1851
1852 if (!IrpContext->ExceptionInProgress && !PostIrp) {
1853 if ( Status == STATUS_PENDING ||
1854 Status == STATUS_CANT_WAIT) {
1855 Status = Ext2QueueRequest(IrpContext);
1856 } else {
1857 Ext2CompleteIrpContext(IrpContext, Status);
1858 }
1859 }
1860 } _SEH2_END;
1861
1862 return Status;
1863 }
1864
1865 NTSTATUS
1866 Ext2CreateInode(
1867 PEXT2_IRP_CONTEXT IrpContext,
1868 PEXT2_VCB Vcb,
1869 PEXT2_FCB Parent,
1870 ULONG Type,
1871 ULONG FileAttr,
1872 PUNICODE_STRING FileName)
1873 {
1874 NTSTATUS Status;
1875 ULONG iGrp;
1876 ULONG iNo;
1877 struct inode Inode = { 0 };
1878 struct dentry *Dentry = NULL;
1879
1880 LARGE_INTEGER SysTime;
1881
1882 iGrp = (Parent->Inode->i_ino - 1) / BLOCKS_PER_GROUP;
1883
1884 DEBUG(DL_INF, ("Ext2CreateInode: %S in %S(Inode=%xh)\n",
1885 FileName->Buffer,
1886 Parent->Mcb->ShortName.Buffer,
1887 Parent->Inode->i_ino));
1888
1889 Status = Ext2NewInode(IrpContext, Vcb, iGrp, Type, &iNo);
1890 if (!NT_SUCCESS(Status)) {
1891 goto errorout;
1892 }
1893
1894 KeQuerySystemTime(&SysTime);
1895 Ext2ClearInode(IrpContext, Vcb, iNo);
1896 Inode.i_sb = &Vcb->sb;
1897 Inode.i_ino = iNo;
1898 Inode.i_ctime = Inode.i_mtime =
1899 Inode.i_atime = Ext2LinuxTime(SysTime);
1900 if (IsFlagOn(Vcb->Flags, VCB_USER_IDS)) {
1901 Inode.i_uid = Vcb->uid;
1902 Inode.i_gid = Vcb->gid;
1903 } else {
1904 Inode.i_uid = Parent->Mcb->Inode.i_uid;
1905 Inode.i_gid = Parent->Mcb->Inode.i_gid;
1906 }
1907 Inode.i_generation = Parent->Inode->i_generation;
1908 Inode.i_mode = S_IPERMISSION_MASK &
1909 Parent->Inode->i_mode;
1910 if (Type == EXT2_FT_DIR) {
1911 Inode.i_mode |= S_IFDIR;
1912 } else if (Type == EXT2_FT_REG_FILE) {
1913 Inode.i_mode &= S_IFATTR;
1914 Inode.i_mode |= S_IFREG;
1915 } else {
1916 DbgBreak();
1917 }
1918
1919 /* Force using extent */
1920 if (IsFlagOn(SUPER_BLOCK->s_feature_incompat, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
1921 Inode.i_flags |= EXT2_EXTENTS_FL;
1922 ext4_ext_tree_init(IrpContext, NULL, &Inode);
1923 /* ext4_ext_tree_init will save inode body */
1924 } else {
1925 /* save inode body to cache */
1926 Ext2SaveInode(IrpContext, Vcb, &Inode);
1927 }
1928
1929 /* add new entry to its parent */
1930 Status = Ext2AddEntry(
1931 IrpContext,
1932 Vcb,
1933 Parent,
1934 &Inode,
1935 FileName,
1936 &Dentry
1937 );
1938
1939 if (!NT_SUCCESS(Status)) {
1940 DbgBreak();
1941 Ext2FreeInode(IrpContext, Vcb, iNo, Type);
1942 goto errorout;
1943 }
1944
1945 DEBUG(DL_INF, ("Ext2CreateInode: New Inode = %xh (Type=%xh)\n",
1946 Inode.i_ino, Type));
1947
1948 errorout:
1949
1950 if (Dentry)
1951 Ext2FreeEntry(Dentry);
1952
1953 return Status;
1954 }
1955
1956
1957 NTSTATUS
1958 Ext2SupersedeOrOverWriteFile(
1959 IN PEXT2_IRP_CONTEXT IrpContext,
1960 IN PFILE_OBJECT FileObject,
1961 IN PEXT2_VCB Vcb,
1962 IN PEXT2_FCB Fcb,
1963 IN PLARGE_INTEGER AllocationSize,
1964 IN ULONG Disposition
1965 )
1966 {
1967 LARGE_INTEGER CurrentTime;
1968 LARGE_INTEGER Size;
1969
1970 KeQuerySystemTime(&CurrentTime);
1971
1972 Size.QuadPart = 0;
1973 if (!MmCanFileBeTruncated(&(Fcb->SectionObject), &(Size))) {
1974 return STATUS_USER_MAPPED_FILE;
1975 }
1976
1977 /* purge all file cache and shrink cache windows size */
1978 CcPurgeCacheSection(&Fcb->SectionObject, NULL, 0, FALSE);
1979 Fcb->Header.AllocationSize.QuadPart =
1980 Fcb->Header.FileSize.QuadPart =
1981 Fcb->Header.ValidDataLength.QuadPart = 0;
1982 CcSetFileSizes(FileObject,
1983 (PCC_FILE_SIZES)&Fcb->Header.AllocationSize);
1984
1985 Size.QuadPart = CEILING_ALIGNED(ULONGLONG,
1986 (ULONGLONG)AllocationSize->QuadPart,
1987 (ULONGLONG)BLOCK_SIZE);
1988
1989 if ((loff_t)Size.QuadPart > Fcb->Inode->i_size) {
1990 Ext2ExpandFile(IrpContext, Vcb, Fcb->Mcb, &Size);
1991 } else {
1992 Ext2TruncateFile(IrpContext, Vcb, Fcb->Mcb, &Size);
1993 }
1994
1995 Fcb->Header.AllocationSize = Size;
1996 if (Fcb->Header.AllocationSize.QuadPart > 0) {
1997 SetLongFlag(Fcb->Flags, FCB_ALLOC_IN_CREATE);
1998 CcSetFileSizes(FileObject,
1999 (PCC_FILE_SIZES)&Fcb->Header.AllocationSize );
2000 }
2001
2002 /* remove all extent mappings */
2003 DEBUG(DL_EXT, ("Ext2SuperSede ...: %wZ\n", &Fcb->Mcb->FullName));
2004 Fcb->Inode->i_size = 0;
2005
2006 if (Disposition == FILE_SUPERSEDE) {
2007 Fcb->Inode->i_ctime = Ext2LinuxTime(CurrentTime);
2008 }
2009 Fcb->Inode->i_atime =
2010 Fcb->Inode->i_mtime = Ext2LinuxTime(CurrentTime);
2011 Ext2SaveInode(IrpContext, Vcb, Fcb->Inode);
2012
2013 return STATUS_SUCCESS;
2014 }