2 * PROJECT: ReactOS FAT file system driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/filesystems/fastfat/create.c
5 * PURPOSE: Create routines
6 * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
9 /* INCLUDES *****************************************************************/
17 RtlUpcaseUnicodeStringToCountedOemString(
18 IN OUT POEM_STRING DestinationString
,
19 IN PCUNICODE_STRING SourceString
,
20 IN BOOLEAN AllocateDestinationString
24 /* FUNCTIONS *****************************************************************/
28 FatiOpenRootDcb(IN PFAT_IRP_CONTEXT IrpContext
,
29 IN PFILE_OBJECT FileObject
,
31 IN PACCESS_MASK DesiredAccess
,
32 IN USHORT ShareAccess
,
33 IN ULONG CreateDisposition
)
37 DPRINT1("Opening root directory\n");
39 Iosb
.Status
= STATUS_NOT_IMPLEMENTED
;
46 FatiCreate(IN PFAT_IRP_CONTEXT IrpContext
,
50 BOOLEAN CreateDirectory
;
51 BOOLEAN SequentialOnly
;
52 BOOLEAN NoIntermediateBuffering
;
53 BOOLEAN OpenDirectory
;
55 BOOLEAN OpenTargetDirectory
;
56 BOOLEAN DirectoryFile
;
57 BOOLEAN NonDirectoryFile
;
58 BOOLEAN NoEaKnowledge
;
59 BOOLEAN DeleteOnClose
;
60 BOOLEAN TemporaryFile
;
61 ULONG CreateDisposition
;
70 PFILE_OBJECT FileObject
;
71 PFILE_OBJECT RelatedFO
;
72 UNICODE_STRING FileName
;
74 PFILE_FULL_EA_INFORMATION EaBuffer
;
75 PACCESS_MASK DesiredAccess
;
84 PIO_STACK_LOCATION IrpSp
;
85 BOOLEAN EndBackslash
= FALSE
, OpenedAsDos
;
86 UNICODE_STRING RemainingPart
, FirstName
, NextName
;
87 OEM_STRING AnsiFirstName
;
89 Iosb
.Status
= STATUS_SUCCESS
;
91 /* Get current IRP stack location */
92 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
94 DPRINT1("FatCommonCreate\n", 0 );
95 DPRINT1("Irp = %08lx\n", Irp
);
96 DPRINT1("\t->Flags = %08lx\n", Irp
->Flags
);
97 DPRINT1("\t->FileObject = %08lx\n", IrpSp
->FileObject
);
98 DPRINT1("\t->RelatedFileObject = %08lx\n", IrpSp
->FileObject
->RelatedFileObject
);
99 DPRINT1("\t->FileName = %wZ\n", &IrpSp
->FileObject
->FileName
);
100 DPRINT1("\t->AllocationSize.LowPart = %08lx\n", Irp
->Overlay
.AllocationSize
.LowPart
);
101 DPRINT1("\t->AllocationSize.HighPart = %08lx\n", Irp
->Overlay
.AllocationSize
.HighPart
);
102 DPRINT1("\t->SystemBuffer = %08lx\n", Irp
->AssociatedIrp
.SystemBuffer
);
103 DPRINT1("\t->DesiredAccess = %08lx\n", IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
);
104 DPRINT1("\t->Options = %08lx\n", IrpSp
->Parameters
.Create
.Options
);
105 DPRINT1("\t->FileAttributes = %04x\n", IrpSp
->Parameters
.Create
.FileAttributes
);
106 DPRINT1("\t->ShareAccess = %04x\n", IrpSp
->Parameters
.Create
.ShareAccess
);
107 DPRINT1("\t->EaLength = %08lx\n", IrpSp
->Parameters
.Create
.EaLength
);
109 /* Apply a special hack for Win32, idea taken from FASTFAT reference driver from WDK */
110 if ((IrpSp
->FileObject
->FileName
.Length
> sizeof(WCHAR
)) &&
111 (IrpSp
->FileObject
->FileName
.Buffer
[1] == L
'\\') &&
112 (IrpSp
->FileObject
->FileName
.Buffer
[0] == L
'\\'))
114 /* Remove a leading slash */
115 IrpSp
->FileObject
->FileName
.Length
-= sizeof(WCHAR
);
116 RtlMoveMemory(&IrpSp
->FileObject
->FileName
.Buffer
[0],
117 &IrpSp
->FileObject
->FileName
.Buffer
[1],
118 IrpSp
->FileObject
->FileName
.Length
);
120 /* Check again: if there are still two leading slashes,
121 exit with an error */
122 if ((IrpSp
->FileObject
->FileName
.Length
> sizeof(WCHAR
)) &&
123 (IrpSp
->FileObject
->FileName
.Buffer
[1] == L
'\\') &&
124 (IrpSp
->FileObject
->FileName
.Buffer
[0] == L
'\\'))
126 FatCompleteRequest( IrpContext
, Irp
, STATUS_OBJECT_NAME_INVALID
);
128 DPRINT1("FatiCreate: STATUS_OBJECT_NAME_INVALID\n");
129 return STATUS_OBJECT_NAME_INVALID
;
133 /* Make sure we have SecurityContext */
134 ASSERT(IrpSp
->Parameters
.Create
.SecurityContext
!= NULL
);
136 /* Get necessary data out of IRP */
137 FileObject
= IrpSp
->FileObject
;
138 FileName
= FileObject
->FileName
;
139 RelatedFO
= FileObject
->RelatedFileObject
;
140 AllocationSize
= Irp
->Overlay
.AllocationSize
.LowPart
;
141 EaBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
142 DesiredAccess
= &IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
;
143 Options
= IrpSp
->Parameters
.Create
.Options
;
144 FileAttributes
= (UCHAR
)(IrpSp
->Parameters
.Create
.FileAttributes
& ~FILE_ATTRIBUTE_NORMAL
);
145 ShareAccess
= IrpSp
->Parameters
.Create
.ShareAccess
;
146 EaLength
= IrpSp
->Parameters
.Create
.EaLength
;
148 /* Set VPB to related object's VPB if it exists */
150 FileObject
->Vpb
= RelatedFO
->Vpb
;
152 /* Prepare file attributes mask */
153 FileAttributes
&= (FILE_ATTRIBUTE_READONLY
|
154 FILE_ATTRIBUTE_HIDDEN
|
155 FILE_ATTRIBUTE_SYSTEM
|
156 FILE_ATTRIBUTE_ARCHIVE
);
158 /* Get the volume control object */
159 Vcb
= &((PVOLUME_DEVICE_OBJECT
)IrpSp
->DeviceObject
)->Vcb
;
162 DirectoryFile
= BooleanFlagOn(Options
, FILE_DIRECTORY_FILE
);
163 NonDirectoryFile
= BooleanFlagOn(Options
, FILE_NON_DIRECTORY_FILE
);
164 SequentialOnly
= BooleanFlagOn(Options
, FILE_SEQUENTIAL_ONLY
);
165 NoIntermediateBuffering
= BooleanFlagOn(Options
, FILE_NO_INTERMEDIATE_BUFFERING
);
166 NoEaKnowledge
= BooleanFlagOn(Options
, FILE_NO_EA_KNOWLEDGE
);
167 DeleteOnClose
= BooleanFlagOn(Options
, FILE_DELETE_ON_CLOSE
);
168 TemporaryFile
= BooleanFlagOn(IrpSp
->Parameters
.Create
.FileAttributes
,
169 FILE_ATTRIBUTE_TEMPORARY
);
170 IsPagingFile
= BooleanFlagOn(IrpSp
->Flags
, SL_OPEN_PAGING_FILE
);
171 OpenTargetDirectory
= BooleanFlagOn(IrpSp
->Flags
, SL_OPEN_TARGET_DIRECTORY
);
173 /* Calculate create disposition */
174 CreateDisposition
= (Options
>> 24) & 0x000000ff;
176 /* Get Create/Open directory flags based on it */
177 CreateDirectory
= (BOOLEAN
)(DirectoryFile
&&
178 ((CreateDisposition
== FILE_CREATE
) ||
179 (CreateDisposition
== FILE_OPEN_IF
)));
181 OpenDirectory
= (BOOLEAN
)(DirectoryFile
&&
182 ((CreateDisposition
== FILE_OPEN
) ||
183 (CreateDisposition
== FILE_OPEN_IF
)));
185 /* Validate parameters: directory/nondirectory mismatch and
186 AllocationSize being more than 4GB */
187 if ((DirectoryFile
&& NonDirectoryFile
) ||
188 Irp
->Overlay
.AllocationSize
.HighPart
!= 0)
190 FatCompleteRequest(IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
192 DPRINT1("FatiCreate: STATUS_INVALID_PARAMETER\n", 0);
193 return STATUS_INVALID_PARAMETER
;
196 /* Acquire the VCB lock exclusively */
197 if (!FatAcquireExclusiveVcb(IrpContext
, Vcb
))
199 // TODO: Postpone the IRP for later processing
201 return STATUS_NOT_IMPLEMENTED
;
204 // TODO: Verify the VCB
206 /* If VCB is locked, then no file openings are possible */
207 if (Vcb
->State
& VCB_STATE_FLAG_LOCKED
)
209 DPRINT1("This volume is locked\n");
210 Status
= STATUS_ACCESS_DENIED
;
212 /* Cleanup and return */
213 FatReleaseVcb(IrpContext
, Vcb
);
217 // TODO: Check if the volume is write protected and disallow DELETE_ON_CLOSE
219 // TODO: Make sure EAs aren't supported on FAT32
221 /* Check if it's a volume open request */
222 if (FileName
.Length
== 0)
224 /* Test related FO to be sure */
226 FatDecodeFileObject(RelatedFO
, &DecodedVcb
, &Fcb
, &Ccb
) == UserVolumeOpen
)
228 /* It is indeed a volume open request */
229 DPRINT1("Volume open request, not implemented now!\n");
234 /* Check if this is a relative open */
237 // RelatedFO will be a parent directory
243 if ((FileName
.Length
== sizeof(WCHAR
)) &&
244 (FileName
.Buffer
[0] == L
'\\'))
246 /* Check if it's ok to open it */
247 if (NonDirectoryFile
)
249 DPRINT1("Trying to open root dir as a file\n");
251 /* Cleanup and return */
252 FatReleaseVcb(IrpContext
, Vcb
);
253 return STATUS_FILE_IS_A_DIRECTORY
;
256 /* Check delete on close on a root dir */
259 /* Cleanup and return */
260 FatReleaseVcb(IrpContext
, Vcb
);
261 return STATUS_CANNOT_DELETE
;
264 /* Call root directory open routine */
265 Iosb
= FatiOpenRootDcb(IrpContext
,
272 Irp
->IoStatus
.Information
= Iosb
.Information
;
274 /* Cleanup and return */
275 FatReleaseVcb(IrpContext
, Vcb
);
281 ParentDcb
= Vcb
->RootDcb
;
282 DPRINT1("ParentDcb %p\n", ParentDcb
);
285 /* Check for backslash at the end */
286 if (FileName
.Length
&&
287 FileName
.Buffer
[FileName
.Length
/ sizeof(WCHAR
) - 1] == L
'\\')
290 FileName
.Length
-= sizeof(WCHAR
);
292 /* Remember we cut it */
296 /* Ensure the name is set */
297 if (!ParentDcb
->FullFileName
.Buffer
)
299 DPRINT1("ParentDcb->FullFileName.Buffer is NULL\n");
302 /* Check max path length */
303 if (ParentDcb
->FullFileName
.Length
+ FileName
.Length
+ sizeof(WCHAR
) <= FileName
.Length
)
305 DPRINT1("Max length is way off\n");
306 Iosb
.Status
= STATUS_OBJECT_NAME_INVALID
;
310 /* Loop through FCBs to find a good one */
315 /* Dissect the name */
316 RemainingPart
= FileName
;
317 while (RemainingPart
.Length
)
319 FsRtlDissectName(RemainingPart
, &FirstName
, &NextName
);
321 /* Check for validity */
322 if ((NextName
.Length
&& NextName
.Buffer
[0] == L
'\\') ||
323 (NextName
.Length
> 255 * sizeof(WCHAR
)))
325 /* The name is invalid */
326 DPRINT1("Invalid name found\n");
327 Iosb
.Status
= STATUS_OBJECT_NAME_INVALID
;
331 /* Convert the name to ANSI */
332 AnsiFirstName
.Buffer
= ExAllocatePool(PagedPool
, FirstName
.Length
);
333 AnsiFirstName
.Length
= 0;
334 AnsiFirstName
.MaximumLength
= FirstName
.Length
;
335 Status
= RtlUpcaseUnicodeStringToCountedOemString(&AnsiFirstName
, &FirstName
, FALSE
);
337 if (!NT_SUCCESS(Status
))
339 DPRINT1("RtlUpcaseUnicodeStringToCountedOemString() failed with 0x%08x\n", Status
);
342 AnsiFirstName
.Length
= 0;
346 /* Find the coresponding FCB */
347 NextFcb
= FatFindFcb(IrpContext
,
348 &Fcb
->Dcb
.SplayLinksAnsi
,
349 (PSTRING
)&AnsiFirstName
,
353 /* Check if we found anything */
354 if (!NextFcb
&& Fcb
->Dcb
.SplayLinksUnicode
)
359 /* Move to the next FCB */
363 RemainingPart
= NextName
;
366 /* Break out of this loop if nothing can be found */
368 NextName
.Length
== 0 ||
369 FatNodeType(NextFcb
) == FAT_NTC_FCB
)
375 /* Ensure remaining name doesn't start from a backslash */
376 if (RemainingPart
.Length
&&
377 RemainingPart
.Buffer
[0] == L
'\\')
380 RemainingPart
.Buffer
++;
381 RemainingPart
.Length
-= sizeof(WCHAR
);
384 if (Fcb
->Condition
== FcbGood
)
386 /* Good FCB, break out of the loop */
395 /* We have a valid FCB now */
396 if (!RemainingPart
.Length
)
398 DPRINT1("It's possible to open an existing FCB\n");
402 /* During parsing we encountered a part which has no attached FCB/DCB.
403 Check that the parent is really DCB and not FCB */
404 if (FatNodeType(Fcb
) != FAT_NTC_ROOT_DCB
&&
405 FatNodeType(Fcb
) != FAT_NTC_DCB
)
407 DPRINT1("Weird FCB node type %x, expected DCB or root DCB\n", FatNodeType(Fcb
));
411 /* Create additional DCBs for all path items */
415 FsRtlDissectName(RemainingPart
, &FirstName
, &RemainingPart
);
417 /* Check for validity */
418 if ((RemainingPart
.Length
&& RemainingPart
.Buffer
[0] == L
'\\') ||
419 (NextName
.Length
> 255 * sizeof(WCHAR
)))
421 /* The name is invalid */
422 DPRINT1("Invalid name found\n");
423 Iosb
.Status
= STATUS_OBJECT_NAME_INVALID
;
427 /* Convert the name to ANSI */
428 AnsiFirstName
.Buffer
= ExAllocatePool(PagedPool
, FirstName
.Length
);
429 AnsiFirstName
.Length
= 0;
430 AnsiFirstName
.MaximumLength
= FirstName
.Length
;
431 Status
= RtlUpcaseUnicodeStringToCountedOemString(&AnsiFirstName
, &FirstName
, FALSE
);
433 if (!NT_SUCCESS(Status
))
438 DPRINT1("FirstName %wZ, RemainingPart %wZ\n", &FirstName
, &RemainingPart
);
440 /* Break if came to the end */
441 if (!RemainingPart
.Length
) break;
443 // TODO: Create a DCB for this entry
446 // Simulate that we opened the file
447 //Iosb.Information = FILE_OPENED;
448 Irp
->IoStatus
.Information
= FILE_OPENED
;
449 FileObject
->SectionObjectPointer
= (PSECTION_OBJECT_POINTERS
)0x1;
452 /* Complete the request */
453 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
460 FatCreate(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
462 PFAT_IRP_CONTEXT IrpContext
;
464 //PVOLUME_DEVICE_OBJECT VolumeDO = (PVOLUME_DEVICE_OBJECT)DeviceObject;
466 DPRINT1("FatCreate()\n");
468 /* If it's called with our Disk FS device object - it's always open */
469 // TODO: Add check for CDROM FS device object
470 if (DeviceObject
== FatGlobalData
.DiskDeviceObject
)
472 /* Complete the request and return success */
473 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
474 Irp
->IoStatus
.Information
= FILE_OPENED
;
476 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
478 return STATUS_SUCCESS
;
481 /* Enter FsRtl critical region */
482 FsRtlEnterFileSystem();
484 /* Build an irp context */
485 IrpContext
= FatBuildIrpContext(Irp
, TRUE
);
487 /* Call internal function */
488 Status
= FatiCreate(IrpContext
, Irp
);
490 /* Leave FsRtl critical region */
491 FsRtlExitFileSystem();