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