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 FatiOpenExistingFile(IN PFAT_IRP_CONTEXT IrpContext
,
47 IN PFILE_OBJECT FileObject
,
50 IN PACCESS_MASK DesiredAccess
,
51 IN USHORT ShareAccess
,
52 IN ULONG AllocationSize
,
53 IN PFILE_FULL_EA_INFORMATION EaBuffer
,
55 IN UCHAR FileAttributes
,
56 IN ULONG CreateDisposition
,
57 IN BOOLEAN IsPagingFile
,
58 IN BOOLEAN DeleteOnClose
,
61 IO_STATUS_BLOCK Iosb
= {{0}};
63 CHAR AnsiNameBuf
[512];
68 /* Check for create file option and fail */
69 if (CreateDisposition
== FILE_CREATE
)
71 Iosb
.Status
= STATUS_OBJECT_NAME_COLLISION
;
75 // TODO: Check more params
77 /* Convert the name to ANSI */
78 AnsiName
.Buffer
= AnsiNameBuf
;
80 AnsiName
.MaximumLength
= sizeof(AnsiNameBuf
);
81 RtlZeroMemory(AnsiNameBuf
, sizeof(AnsiNameBuf
));
82 Status
= RtlUpcaseUnicodeStringToCountedOemString(&AnsiName
, &FileObject
->FileName
, FALSE
);
83 if (!NT_SUCCESS(Status
))
88 /* Open the file with FullFAT */
89 FileHandle
= FF_Open(Vcb
->Ioman
, AnsiName
.Buffer
, FF_MODE_READ
, NULL
);
93 Iosb
.Status
= STATUS_OBJECT_NAME_NOT_FOUND
; // FIXME: A shortcut for now
97 /* Create a new FCB for this file */
98 Fcb
= FatCreateFcb(IrpContext
, Vcb
, ParentDcb
, FileHandle
);
100 // TODO: Check if overwrite is needed
102 // This is usual file open branch, without overwriting!
103 /* Set context and section object pointers */
104 FatSetFileObject(FileObject
,
108 FileObject
->SectionObjectPointer
= &Fcb
->SectionObjectPointers
;
110 Iosb
.Status
= STATUS_SUCCESS
;
111 Iosb
.Information
= FILE_OPENED
;
118 FatiCreate(IN PFAT_IRP_CONTEXT IrpContext
,
121 /* Boolean options */
122 BOOLEAN CreateDirectory
;
123 BOOLEAN SequentialOnly
;
124 BOOLEAN NoIntermediateBuffering
;
125 BOOLEAN OpenDirectory
;
126 BOOLEAN IsPagingFile
;
127 BOOLEAN OpenTargetDirectory
;
128 BOOLEAN DirectoryFile
;
129 BOOLEAN NonDirectoryFile
;
130 BOOLEAN NoEaKnowledge
;
131 BOOLEAN DeleteOnClose
;
132 BOOLEAN TemporaryFile
;
133 ULONG CreateDisposition
;
136 PVCB Vcb
, DecodedVcb
;
142 PFILE_OBJECT FileObject
;
143 PFILE_OBJECT RelatedFO
;
144 UNICODE_STRING FileName
;
145 ULONG AllocationSize
;
146 PFILE_FULL_EA_INFORMATION EaBuffer
;
147 PACCESS_MASK DesiredAccess
;
149 UCHAR FileAttributes
;
155 IO_STATUS_BLOCK Iosb
;
156 PIO_STACK_LOCATION IrpSp
;
157 BOOLEAN EndBackslash
= FALSE
, OpenedAsDos
;
158 UNICODE_STRING RemainingPart
, FirstName
, NextName
;
159 OEM_STRING AnsiFirstName
;
161 Iosb
.Status
= STATUS_SUCCESS
;
163 /* Get current IRP stack location */
164 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
166 DPRINT1("FatCommonCreate\n", 0 );
167 DPRINT1("Irp = %08lx\n", Irp
);
168 DPRINT1("\t->Flags = %08lx\n", Irp
->Flags
);
169 DPRINT1("\t->FileObject = %08lx\n", IrpSp
->FileObject
);
170 DPRINT1("\t->RelatedFileObject = %08lx\n", IrpSp
->FileObject
->RelatedFileObject
);
171 DPRINT1("\t->FileName = %wZ\n", &IrpSp
->FileObject
->FileName
);
172 DPRINT1("\t->AllocationSize.LowPart = %08lx\n", Irp
->Overlay
.AllocationSize
.LowPart
);
173 DPRINT1("\t->AllocationSize.HighPart = %08lx\n", Irp
->Overlay
.AllocationSize
.HighPart
);
174 DPRINT1("\t->SystemBuffer = %08lx\n", Irp
->AssociatedIrp
.SystemBuffer
);
175 DPRINT1("\t->DesiredAccess = %08lx\n", IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
);
176 DPRINT1("\t->Options = %08lx\n", IrpSp
->Parameters
.Create
.Options
);
177 DPRINT1("\t->FileAttributes = %04x\n", IrpSp
->Parameters
.Create
.FileAttributes
);
178 DPRINT1("\t->ShareAccess = %04x\n", IrpSp
->Parameters
.Create
.ShareAccess
);
179 DPRINT1("\t->EaLength = %08lx\n", IrpSp
->Parameters
.Create
.EaLength
);
181 /* Apply a special hack for Win32, idea taken from FASTFAT reference driver from WDK */
182 if ((IrpSp
->FileObject
->FileName
.Length
> sizeof(WCHAR
)) &&
183 (IrpSp
->FileObject
->FileName
.Buffer
[1] == L
'\\') &&
184 (IrpSp
->FileObject
->FileName
.Buffer
[0] == L
'\\'))
186 /* Remove a leading slash */
187 IrpSp
->FileObject
->FileName
.Length
-= sizeof(WCHAR
);
188 RtlMoveMemory(&IrpSp
->FileObject
->FileName
.Buffer
[0],
189 &IrpSp
->FileObject
->FileName
.Buffer
[1],
190 IrpSp
->FileObject
->FileName
.Length
);
192 /* Check again: if there are still two leading slashes,
193 exit with an error */
194 if ((IrpSp
->FileObject
->FileName
.Length
> sizeof(WCHAR
)) &&
195 (IrpSp
->FileObject
->FileName
.Buffer
[1] == L
'\\') &&
196 (IrpSp
->FileObject
->FileName
.Buffer
[0] == L
'\\'))
198 FatCompleteRequest( IrpContext
, Irp
, STATUS_OBJECT_NAME_INVALID
);
200 DPRINT1("FatiCreate: STATUS_OBJECT_NAME_INVALID\n");
201 return STATUS_OBJECT_NAME_INVALID
;
205 /* Make sure we have SecurityContext */
206 ASSERT(IrpSp
->Parameters
.Create
.SecurityContext
!= NULL
);
208 /* Get necessary data out of IRP */
209 FileObject
= IrpSp
->FileObject
;
210 FileName
= FileObject
->FileName
;
211 RelatedFO
= FileObject
->RelatedFileObject
;
212 AllocationSize
= Irp
->Overlay
.AllocationSize
.LowPart
;
213 EaBuffer
= Irp
->AssociatedIrp
.SystemBuffer
;
214 DesiredAccess
= &IrpSp
->Parameters
.Create
.SecurityContext
->DesiredAccess
;
215 Options
= IrpSp
->Parameters
.Create
.Options
;
216 FileAttributes
= (UCHAR
)(IrpSp
->Parameters
.Create
.FileAttributes
& ~FILE_ATTRIBUTE_NORMAL
);
217 ShareAccess
= IrpSp
->Parameters
.Create
.ShareAccess
;
218 EaLength
= IrpSp
->Parameters
.Create
.EaLength
;
220 /* Set VPB to related object's VPB if it exists */
222 FileObject
->Vpb
= RelatedFO
->Vpb
;
224 /* Prepare file attributes mask */
225 FileAttributes
&= (FILE_ATTRIBUTE_READONLY
|
226 FILE_ATTRIBUTE_HIDDEN
|
227 FILE_ATTRIBUTE_SYSTEM
|
228 FILE_ATTRIBUTE_ARCHIVE
);
230 /* Get the volume control object */
231 Vcb
= &((PVOLUME_DEVICE_OBJECT
)IrpSp
->DeviceObject
)->Vcb
;
234 DirectoryFile
= BooleanFlagOn(Options
, FILE_DIRECTORY_FILE
);
235 NonDirectoryFile
= BooleanFlagOn(Options
, FILE_NON_DIRECTORY_FILE
);
236 SequentialOnly
= BooleanFlagOn(Options
, FILE_SEQUENTIAL_ONLY
);
237 NoIntermediateBuffering
= BooleanFlagOn(Options
, FILE_NO_INTERMEDIATE_BUFFERING
);
238 NoEaKnowledge
= BooleanFlagOn(Options
, FILE_NO_EA_KNOWLEDGE
);
239 DeleteOnClose
= BooleanFlagOn(Options
, FILE_DELETE_ON_CLOSE
);
240 TemporaryFile
= BooleanFlagOn(IrpSp
->Parameters
.Create
.FileAttributes
,
241 FILE_ATTRIBUTE_TEMPORARY
);
242 IsPagingFile
= BooleanFlagOn(IrpSp
->Flags
, SL_OPEN_PAGING_FILE
);
243 OpenTargetDirectory
= BooleanFlagOn(IrpSp
->Flags
, SL_OPEN_TARGET_DIRECTORY
);
245 /* Calculate create disposition */
246 CreateDisposition
= (Options
>> 24) & 0x000000ff;
248 /* Get Create/Open directory flags based on it */
249 CreateDirectory
= (BOOLEAN
)(DirectoryFile
&&
250 ((CreateDisposition
== FILE_CREATE
) ||
251 (CreateDisposition
== FILE_OPEN_IF
)));
253 OpenDirectory
= (BOOLEAN
)(DirectoryFile
&&
254 ((CreateDisposition
== FILE_OPEN
) ||
255 (CreateDisposition
== FILE_OPEN_IF
)));
257 /* Validate parameters: directory/nondirectory mismatch and
258 AllocationSize being more than 4GB */
259 if ((DirectoryFile
&& NonDirectoryFile
) ||
260 Irp
->Overlay
.AllocationSize
.HighPart
!= 0)
262 FatCompleteRequest(IrpContext
, Irp
, STATUS_INVALID_PARAMETER
);
264 DPRINT1("FatiCreate: STATUS_INVALID_PARAMETER\n", 0);
265 return STATUS_INVALID_PARAMETER
;
268 /* Acquire the VCB lock exclusively */
269 if (!FatAcquireExclusiveVcb(IrpContext
, Vcb
))
271 // TODO: Postpone the IRP for later processing
273 return STATUS_NOT_IMPLEMENTED
;
276 // TODO: Verify the VCB
278 /* If VCB is locked, then no file openings are possible */
279 if (Vcb
->State
& VCB_STATE_FLAG_LOCKED
)
281 DPRINT1("This volume is locked\n");
282 Status
= STATUS_ACCESS_DENIED
;
284 /* Cleanup and return */
285 FatReleaseVcb(IrpContext
, Vcb
);
289 // TODO: Check if the volume is write protected and disallow DELETE_ON_CLOSE
291 // TODO: Make sure EAs aren't supported on FAT32
293 /* Check if it's a volume open request */
294 if (FileName
.Length
== 0)
296 /* Test related FO to be sure */
298 FatDecodeFileObject(RelatedFO
, &DecodedVcb
, &Fcb
, &Ccb
) == UserVolumeOpen
)
300 /* It is indeed a volume open request */
301 DPRINT1("Volume open request, not implemented now!\n");
306 /* Check if this is a relative open */
309 // RelatedFO will be a parent directory
315 if ((FileName
.Length
== sizeof(WCHAR
)) &&
316 (FileName
.Buffer
[0] == L
'\\'))
318 /* Check if it's ok to open it */
319 if (NonDirectoryFile
)
321 DPRINT1("Trying to open root dir as a file\n");
323 /* Cleanup and return */
324 FatReleaseVcb(IrpContext
, Vcb
);
325 return STATUS_FILE_IS_A_DIRECTORY
;
328 /* Check delete on close on a root dir */
331 /* Cleanup and return */
332 FatReleaseVcb(IrpContext
, Vcb
);
333 return STATUS_CANNOT_DELETE
;
336 /* Call root directory open routine */
337 Iosb
= FatiOpenRootDcb(IrpContext
,
344 Irp
->IoStatus
.Information
= Iosb
.Information
;
346 /* Cleanup and return */
347 FatReleaseVcb(IrpContext
, Vcb
);
353 ParentDcb
= Vcb
->RootDcb
;
354 DPRINT1("ParentDcb %p\n", ParentDcb
);
357 /* Check for backslash at the end */
358 if (FileName
.Length
&&
359 FileName
.Buffer
[FileName
.Length
/ sizeof(WCHAR
) - 1] == L
'\\')
362 FileName
.Length
-= sizeof(WCHAR
);
364 /* Remember we cut it */
368 /* Ensure the name is set */
369 if (!ParentDcb
->FullFileName
.Buffer
)
371 DPRINT1("ParentDcb->FullFileName.Buffer is NULL\n");
374 /* Check max path length */
375 if (ParentDcb
->FullFileName
.Length
+ FileName
.Length
+ sizeof(WCHAR
) <= FileName
.Length
)
377 DPRINT1("Max length is way off\n");
378 Iosb
.Status
= STATUS_OBJECT_NAME_INVALID
;
382 /* Loop through FCBs to find a good one */
387 /* Dissect the name */
388 RemainingPart
= FileName
;
389 while (RemainingPart
.Length
)
391 FsRtlDissectName(RemainingPart
, &FirstName
, &NextName
);
393 /* Check for validity */
394 if ((NextName
.Length
&& NextName
.Buffer
[0] == L
'\\') ||
395 (NextName
.Length
> 255 * sizeof(WCHAR
)))
397 /* The name is invalid */
398 DPRINT1("Invalid name found\n");
399 Iosb
.Status
= STATUS_OBJECT_NAME_INVALID
;
403 /* Convert the name to ANSI */
404 AnsiFirstName
.Buffer
= ExAllocatePool(PagedPool
, FirstName
.Length
);
405 AnsiFirstName
.Length
= 0;
406 AnsiFirstName
.MaximumLength
= FirstName
.Length
;
407 Status
= RtlUpcaseUnicodeStringToCountedOemString(&AnsiFirstName
, &FirstName
, FALSE
);
409 if (!NT_SUCCESS(Status
))
411 DPRINT1("RtlUpcaseUnicodeStringToCountedOemString() failed with 0x%08x\n", Status
);
414 AnsiFirstName
.Length
= 0;
418 /* Find the coresponding FCB */
419 NextFcb
= FatFindFcb(IrpContext
,
420 &Fcb
->Dcb
.SplayLinksAnsi
,
421 (PSTRING
)&AnsiFirstName
,
425 /* Check if we found anything */
426 if (!NextFcb
&& Fcb
->Dcb
.SplayLinksUnicode
)
431 /* Move to the next FCB */
435 RemainingPart
= NextName
;
438 /* Break out of this loop if nothing can be found */
440 NextName
.Length
== 0 ||
441 FatNodeType(NextFcb
) == FAT_NTC_FCB
)
447 /* Ensure remaining name doesn't start from a backslash */
448 if (RemainingPart
.Length
&&
449 RemainingPart
.Buffer
[0] == L
'\\')
452 RemainingPart
.Buffer
++;
453 RemainingPart
.Length
-= sizeof(WCHAR
);
456 if (Fcb
->Condition
== FcbGood
)
458 /* Good FCB, break out of the loop */
467 /* We have a valid FCB now */
468 if (!RemainingPart
.Length
)
470 DPRINT1("It's possible to open an existing FCB\n");
474 /* During parsing we encountered a part which has no attached FCB/DCB.
475 Check that the parent is really DCB and not FCB */
476 if (FatNodeType(Fcb
) != FAT_NTC_ROOT_DCB
&&
477 FatNodeType(Fcb
) != FAT_NTC_DCB
)
479 DPRINT1("Weird FCB node type %x, expected DCB or root DCB\n", FatNodeType(Fcb
));
483 /* Create additional DCBs for all path items */
487 FsRtlDissectName(RemainingPart
, &FirstName
, &RemainingPart
);
489 /* Check for validity */
490 if ((RemainingPart
.Length
&& RemainingPart
.Buffer
[0] == L
'\\') ||
491 (NextName
.Length
> 255 * sizeof(WCHAR
)))
493 /* The name is invalid */
494 DPRINT1("Invalid name found\n");
495 Iosb
.Status
= STATUS_OBJECT_NAME_INVALID
;
499 /* Convert the name to ANSI */
500 AnsiFirstName
.Buffer
= ExAllocatePool(PagedPool
, FirstName
.Length
);
501 AnsiFirstName
.Length
= 0;
502 AnsiFirstName
.MaximumLength
= FirstName
.Length
;
503 Status
= RtlUpcaseUnicodeStringToCountedOemString(&AnsiFirstName
, &FirstName
, FALSE
);
505 if (!NT_SUCCESS(Status
))
510 DPRINT1("FirstName %wZ, RemainingPart %wZ\n", &FirstName
, &RemainingPart
);
512 /* Break if came to the end */
513 if (!RemainingPart
.Length
) break;
515 /* Create a DCB for this entry */
516 ParentDcb
= FatCreateDcb(IrpContext
,
521 FatSetFullNameInFcb(ParentDcb
, &FirstName
);
524 // TODO: Try to open directory
526 /* If end backslash here, then it's definately not permitted,
527 since we're opening files here */
530 /* Complete the request */
531 Iosb
.Status
= STATUS_OBJECT_NAME_INVALID
;
532 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
536 /* Try to open the file */
537 Iosb
= FatiOpenExistingFile(IrpContext
,
552 Irp
->IoStatus
.Information
= Iosb
.Information
;
555 /* Complete the request */
556 FatCompleteRequest(IrpContext
, Irp
, Iosb
.Status
);
563 FatCreate(PDEVICE_OBJECT DeviceObject
, PIRP Irp
)
565 PFAT_IRP_CONTEXT IrpContext
;
567 //PVOLUME_DEVICE_OBJECT VolumeDO = (PVOLUME_DEVICE_OBJECT)DeviceObject;
569 DPRINT1("FatCreate()\n");
571 /* If it's called with our Disk FS device object - it's always open */
572 // TODO: Add check for CDROM FS device object
573 if (DeviceObject
== FatGlobalData
.DiskDeviceObject
)
575 /* Complete the request and return success */
576 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
577 Irp
->IoStatus
.Information
= FILE_OPENED
;
579 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
581 return STATUS_SUCCESS
;
584 /* Enter FsRtl critical region */
585 FsRtlEnterFileSystem();
587 /* Build an irp context */
588 IrpContext
= FatBuildIrpContext(Irp
, TRUE
);
590 /* Call internal function */
591 Status
= FatiCreate(IrpContext
, Irp
);
593 /* Leave FsRtl critical region */
594 FsRtlExitFileSystem();