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