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