-/* $Id: create.c,v 1.26 2001/06/14 21:05:08 jfilby Exp $
+/*
+ * ReactOS kernel
+ * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * COPYRIGHT: See COPYING in the top level directory
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/*
* PROJECT: ReactOS kernel
- * FILE: services/fs/vfat/create.c
+ * FILE: drivers/fs/vfat/create.c
* PURPOSE: VFAT Filesystem
* PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
-
+ * Hartmut Birr
*/
/* INCLUDES *****************************************************************/
-#include <ddk/ntddk.h>
-#include <wchar.h>
-#include <limits.h>
-
#define NDEBUG
-#include <debug.h>
-
#include "vfat.h"
-/* GLOBALS *******************************************************************/
-
-#define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24))
-
-#define TAG_CCB TAG('V', 'C', 'C', 'B')
-
/* FUNCTIONS *****************************************************************/
-BOOLEAN
-IsLastEntry (PVOID Block, ULONG Offset)
-/*
- * FUNCTION: Determine if the given directory entry is the last
- */
-{
- return (((FATDirEntry *) Block)[Offset].Filename[0] == 0);
-}
-
-BOOLEAN
-IsVolEntry (PVOID Block, ULONG Offset)
-/*
- * FUNCTION: Determine if the given directory entry is a vol entry
- */
+void vfat8Dot3ToString (PFAT_DIR_ENTRY pEntry, PUNICODE_STRING NameU)
{
- if ((((FATDirEntry *) Block)[Offset].Attrib) == 0x28)
- return TRUE;
- else
- return FALSE;
-}
+ OEM_STRING StringA;
+ USHORT Length;
+ CHAR cString[12];
-BOOLEAN
-IsDeletedEntry (PVOID Block, ULONG Offset)
-/*
- * FUNCTION: Determines if the given entry is a deleted one
- */
-{
- /* Checks special character */
+ RtlCopyMemory(cString, pEntry->ShortName, 11);
+ cString[11] = 0;
+ if (cString[0] == 0x05)
+ {
+ cString[0] = 0xe5;
+ }
- return ((((FATDirEntry *) Block)[Offset].Filename[0] == 0xe5) ||
- (((FATDirEntry *) Block)[Offset].Filename[0] == 0));
-}
+ StringA.Buffer = cString;
+ for (StringA.Length = 0;
+ StringA.Length < 8 && StringA.Buffer[StringA.Length] != ' ';
+ StringA.Length++);
+ StringA.MaximumLength = StringA.Length;
-static void vfat8Dot3ToString (PCHAR pBasename, PCHAR pExtension, PWSTR pName)
-{
- int fromIndex, toIndex;
+ RtlOemStringToUnicodeString(NameU, &StringA, FALSE);
- fromIndex = toIndex = 0;
- while (fromIndex < 8 && pBasename [fromIndex] != ' ')
- {
- pName [toIndex++] = pBasename [fromIndex++];
- }
- if (pExtension [0] != ' ')
- {
- pName [toIndex++] = L'.';
- fromIndex = 0;
- while (fromIndex < 3 && pBasename [fromIndex] != ' ')
+ if (pEntry->lCase & VFAT_CASE_LOWER_BASE)
{
- pName [toIndex++] = pExtension [fromIndex++];
+ RtlDowncaseUnicodeString(NameU, NameU, FALSE);
}
- }
- pName [toIndex] = L'\0';
-}
-
-static void vfat8Dot3ToVolumeLabel (PCHAR pBasename, PCHAR pExtension, PWSTR pName)
-{
- int fromIndex, toIndex;
-
- fromIndex = toIndex = 0;
- while (fromIndex < 8 && pBasename [fromIndex] != ' ')
- {
- pName [toIndex++] = pBasename [fromIndex++];
- }
- if (pExtension [0] != ' ')
- {
- fromIndex = 0;
- while (fromIndex < 3 && pBasename [fromIndex] != ' ')
+ if (cString[8] != ' ')
{
- pName [toIndex++] = pExtension [fromIndex++];
+ Length = NameU->Length;
+ NameU->Buffer += Length / sizeof(WCHAR);
+ if (!FAT_ENTRY_VOLUME(pEntry))
+ {
+ Length += sizeof(WCHAR);
+ NameU->Buffer[0] = L'.';
+ NameU->Buffer++;
+ }
+ NameU->Length = 0;
+ NameU->MaximumLength -= Length;
+
+ StringA.Buffer = &cString[8];
+ for (StringA.Length = 0;
+ StringA.Length < 3 && StringA.Buffer[StringA.Length] != ' ';
+ StringA.Length++);
+ StringA.MaximumLength = StringA.Length;
+ RtlOemStringToUnicodeString(NameU, &StringA, FALSE);
+ if (pEntry->lCase & VFAT_CASE_LOWER_EXT)
+ {
+ RtlDowncaseUnicodeString(NameU, NameU, FALSE);
+ }
+ NameU->Buffer -= Length / sizeof(WCHAR);
+ NameU->Length += Length;
+ NameU->MaximumLength += Length;
}
- }
- pName [toIndex] = L'\0';
+ NameU->Buffer[NameU->Length / sizeof(WCHAR)] = 0;
+ DPRINT("'%wZ'\n", NameU);
}
-BOOLEAN
-GetEntryName (PVOID Block, PULONG _Offset, PWSTR Name, PULONG _jloop,
- PDEVICE_EXTENSION DeviceExt, ULONG * _StartingSector)
+NTSTATUS
+ReadVolumeLabel (PDEVICE_EXTENSION DeviceExt, PVPB Vpb)
/*
- * FUNCTION: Retrieves the file name, be it in short or long file name format
+ * FUNCTION: Read the volume label
*/
{
- FATDirEntry *test;
- slot *test2;
- ULONG Offset = *_Offset;
- ULONG StartingSector = *_StartingSector;
- ULONG jloop = *_jloop;
- ULONG cpos;
-
- test = (FATDirEntry *) Block;
- test2 = (slot *) Block;
-
- *Name = 0;
-
- if (IsDeletedEntry (Block, Offset))
- {
- return (FALSE);
- }
-
- if (test2[Offset].attr == 0x0f)
- {
- vfat_initstr (Name, 256);
- vfat_wcsncpy (Name, test2[Offset].name0_4, 5);
- vfat_wcsncat (Name, test2[Offset].name5_10, 5, 6);
- vfat_wcsncat (Name, test2[Offset].name11_12, 11, 2);
-
- cpos = 0;
- while ((test2[Offset].id != 0x41) && (test2[Offset].id != 0x01) &&
- (test2[Offset].attr > 0))
- {
- Offset++;
- if (Offset == ENTRIES_PER_SECTOR)
- {
- Offset = 0;
- /* FIXME: Check status */
- GetNextSector (DeviceExt, StartingSector, &StartingSector, FALSE);
- jloop++;
- /* FIXME: Check status */
- VfatReadSectors (DeviceExt->StorageDevice,
- StartingSector, 1, Block);
- test2 = (slot *) Block;
- }
- cpos++;
- vfat_movstr (Name, 13, 0, cpos * 13);
- vfat_wcsncpy (Name, test2[Offset].name0_4, 5);
- vfat_wcsncat (Name, test2[Offset].name5_10, 5, 6);
- vfat_wcsncat (Name, test2[Offset].name11_12, 11, 2);
-
- }
-
- if (IsDeletedEntry (Block, Offset + 1))
- {
- Offset++;
- *_Offset = Offset;
- *_jloop = jloop;
- *_StartingSector = StartingSector;
- return (FALSE);
- }
-
- *_Offset = Offset;
- *_jloop = jloop;
- *_StartingSector = StartingSector;
+ PVOID Context = NULL;
+ ULONG DirIndex = 0;
+ PDIR_ENTRY Entry;
+ PVFATFCB pFcb;
+ LARGE_INTEGER FileOffset;
+ UNICODE_STRING NameU;
+ ULONG SizeDirEntry;
+ ULONG EntriesPerPage;
+ OEM_STRING StringO;
+
+ NameU.Buffer = Vpb->VolumeLabel;
+ NameU.Length = 0;
+ NameU.MaximumLength = sizeof(Vpb->VolumeLabel);
+ *(Vpb->VolumeLabel) = 0;
+ Vpb->VolumeLabelLength = 0;
- return (TRUE);
- }
+ if (DeviceExt->Flags & VCB_IS_FATX)
+ {
+ SizeDirEntry = sizeof(FATX_DIR_ENTRY);
+ EntriesPerPage = FATX_ENTRIES_PER_PAGE;
+ }
+ else
+ {
+ SizeDirEntry = sizeof(FAT_DIR_ENTRY);
+ EntriesPerPage = FAT_ENTRIES_PER_PAGE;
+ }
- vfat8Dot3ToString (test[Offset].Filename, test[Offset].Ext, Name);
+ ExAcquireResourceExclusiveLite (&DeviceExt->DirResource, TRUE);
+ pFcb = vfatOpenRootFCB (DeviceExt);
+ ExReleaseResourceLite (&DeviceExt->DirResource);
- *_Offset = Offset;
+ FileOffset.QuadPart = 0;
+ if (CcMapData(pFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, &Context, (PVOID*)&Entry))
+ {
+ while (TRUE)
+ {
+ if (ENTRY_VOLUME(DeviceExt, Entry))
+ {
+ /* copy volume label */
+ if (DeviceExt->Flags & VCB_IS_FATX)
+ {
+ StringO.Buffer = (PCHAR)Entry->FatX.Filename;
+ StringO.MaximumLength = StringO.Length = Entry->FatX.FilenameLength;
+ RtlOemStringToUnicodeString(&NameU, &StringO, FALSE);
+ }
+ else
+ {
+ vfat8Dot3ToString (&Entry->Fat, &NameU);
+ }
+ Vpb->VolumeLabelLength = NameU.Length;
+ break;
+ }
+ if (ENTRY_END(DeviceExt, Entry))
+ {
+ break;
+ }
+ DirIndex++;
+ Entry = (PDIR_ENTRY)((ULONG_PTR)Entry + SizeDirEntry);
+ if ((DirIndex % EntriesPerPage) == 0)
+ {
+ CcUnpinData(Context);
+ FileOffset.u.LowPart += PAGE_SIZE;
+ if (!CcMapData(pFcb->FileObject, &FileOffset, PAGE_SIZE, TRUE, &Context, (PVOID*)&Entry))
+ {
+ Context = NULL;
+ break;
+ }
+ }
+ }
+ if (Context)
+ {
+ CcUnpinData(Context);
+ }
+ }
+ ExAcquireResourceExclusiveLite (&DeviceExt->DirResource, TRUE);
+ vfatReleaseFCB (DeviceExt, pFcb);
+ ExReleaseResourceLite (&DeviceExt->DirResource);
- return (TRUE);
+ return STATUS_SUCCESS;
}
NTSTATUS
-ReadVolumeLabel (PDEVICE_EXTENSION DeviceExt, PVPB Vpb)
+FindFile (PDEVICE_EXTENSION DeviceExt,
+ PVFATFCB Parent,
+ PUNICODE_STRING FileToFindU,
+ PVFAT_DIRENTRY_CONTEXT DirContext,
+ BOOLEAN First)
/*
- * FUNCTION: Read the volume label
+ * FUNCTION: Find a file
*/
{
- ULONG i = 0;
- ULONG j;
- ULONG Size;
- char *block;
- ULONG StartingSector;
- ULONG NextCluster;
+ PWCHAR PathNameBuffer;
+ USHORT PathNameBufferLength;
NTSTATUS Status;
+ PVOID Context = NULL;
+ PVOID Page;
+ PVFATFCB rcFcb;
+ BOOLEAN Found;
+ UNICODE_STRING PathNameU;
+ UNICODE_STRING FileToFindUpcase;
+ BOOLEAN WildCard;
+
+ DPRINT ("FindFile(Parent %x, FileToFind '%wZ', DirIndex: %d)\n",
+ Parent, FileToFindU, DirContext->DirIndex);
+ DPRINT ("FindFile: Path %wZ)\n",&Parent->PathNameU);
+
+ PathNameBufferLength = LONGNAME_MAX_LENGTH * sizeof(WCHAR);
+ PathNameBuffer = ExAllocatePool(NonPagedPool, PathNameBufferLength + sizeof(WCHAR));
+ if (!PathNameBuffer)
+ {
+ CHECKPOINT1;
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
- Size = DeviceExt->rootDirectorySectors; /* FIXME : in fat32, no limit */
- StartingSector = DeviceExt->rootStart;
- NextCluster = 0;
+ PathNameU.Buffer = PathNameBuffer;
+ PathNameU.Length = 0;
+ PathNameU.MaximumLength = PathNameBufferLength;
- block = ExAllocatePool (NonPagedPool, BLOCKSIZE);
- DPRINT ("FindFile : start at sector %lx, entry %ld\n", StartingSector, i);
- for (j = 0; j < Size; j++)
- {
- /* FIXME: Check status */
- VfatReadSectors (DeviceExt->StorageDevice, StartingSector, 1, block);
+ DirContext->LongNameU.Length = 0;
+ DirContext->ShortNameU.Length = 0;
- for (i = 0; i < ENTRIES_PER_SECTOR; i++)
- {
- if (IsVolEntry ((PVOID) block, i))
- {
- FATDirEntry *test = (FATDirEntry *) block;
-
- /* copy volume label */
- vfat8Dot3ToVolumeLabel (test[i].Filename, test[i].Ext, Vpb->VolumeLabel);
- Vpb->VolumeLabelLength = wcslen (Vpb->VolumeLabel);
+ WildCard = FsRtlDoesNameContainWildCards(FileToFindU);
- ExFreePool (block);
- return (STATUS_SUCCESS);
+ if (WildCard == FALSE)
+ {
+ /* if there is no '*?' in the search name, than look first for an existing fcb */
+ RtlCopyUnicodeString(&PathNameU, &Parent->PathNameU);
+ if (!vfatFCBIsRoot(Parent))
+ {
+ PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = L'\\';
+ PathNameU.Length += sizeof(WCHAR);
+ }
+ RtlAppendUnicodeStringToString(&PathNameU, FileToFindU);
+ PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = 0;
+ rcFcb = vfatGrabFCBFromTable(DeviceExt, &PathNameU);
+ if (rcFcb)
+ {
+ ULONG startIndex = rcFcb->startIndex;
+ if ((rcFcb->Flags & FCB_IS_FATX_ENTRY) && !vfatFCBIsRoot(Parent))
+ {
+ startIndex += 2;
}
- if (IsLastEntry ((PVOID) block, i))
+ if(startIndex >= DirContext->DirIndex)
{
- *(Vpb->VolumeLabel) = 0;
- Vpb->VolumeLabelLength = 0;
- ExFreePool (block);
- return (STATUS_UNSUCCESSFUL);
+ RtlCopyUnicodeString(&DirContext->LongNameU, &rcFcb->LongNameU);
+ RtlCopyUnicodeString(&DirContext->ShortNameU, &rcFcb->ShortNameU);
+ RtlCopyMemory(&DirContext->DirEntry, &rcFcb->entry, sizeof(DIR_ENTRY));
+ DirContext->StartIndex = rcFcb->startIndex;
+ DirContext->DirIndex = rcFcb->dirIndex;
+ DPRINT("FindFile: new Name %wZ, DirIndex %d (%d)\n",
+ &DirContext->LongNameU, DirContext->DirIndex, DirContext->StartIndex);
+ Status = STATUS_SUCCESS;
}
- }
- /* not found in this sector, try next : */
-
- /* directory can be fragmented although it is best to keep them
- unfragmented.*/
- StartingSector++;
-
- if (DeviceExt->FatType == FAT32)
- {
- if (StartingSector == ClusterToSector (DeviceExt, NextCluster + 1))
+ else
{
- Status = GetNextCluster (DeviceExt, NextCluster, &NextCluster,
- FALSE);
- if (NextCluster == 0 || NextCluster == 0xffffffff)
- {
- *(Vpb->VolumeLabel) = 0;
- Vpb->VolumeLabelLength = 0;
- ExFreePool (block);
- return (STATUS_UNSUCCESSFUL);
- }
- StartingSector = ClusterToSector (DeviceExt, NextCluster);
+ CHECKPOINT1;
+ Status = STATUS_UNSUCCESSFUL;
}
+ vfatReleaseFCB(DeviceExt, rcFcb);
+ ExFreePool(PathNameBuffer);
+ return Status;
}
}
- *(Vpb->VolumeLabel) = 0;
- Vpb->VolumeLabelLength = 0;
- ExFreePool (block);
- return (STATUS_UNSUCCESSFUL);
-}
-
-
-NTSTATUS
-FindFile (PDEVICE_EXTENSION DeviceExt, PVFATFCB Fcb,
- PVFATFCB Parent, PWSTR FileToFind, ULONG * StartSector,
- ULONG * Entry)
-/*
- * FUNCTION: Find a file
- */
-{
- ULONG i, j;
- ULONG Size;
- char *block;
- WCHAR name[256];
- ULONG StartingSector;
- ULONG NextCluster;
- WCHAR TempStr[2];
- NTSTATUS Status;
- ULONG len;
-// DPRINT ("FindFile(Parent %x, FileToFind '%S')\n", Parent, FileToFind);
- DPRINT("FindFile: old Pathname %x, old Objectname %x)\n",Fcb->PathName, Fcb->ObjectName);
-
- if (wcslen (FileToFind) == 0)
- {
- CHECKPOINT;
- TempStr[0] = (WCHAR) '.';
- TempStr[1] = 0;
- FileToFind = (PWSTR)&TempStr;
- }
+ /* FsRtlIsNameInExpression need the searched string to be upcase,
+ * even if IgnoreCase is specified */
+ Status = RtlUpcaseUnicodeString(&FileToFindUpcase, FileToFindU, TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ CHECKPOINT;
+ ExFreePool(PathNameBuffer);
+ return Status;
+ }
- if (Parent == NULL || Parent->entry.FirstCluster == 1)
+ while(TRUE)
{
- Size = DeviceExt->rootDirectorySectors; /* FIXME : in fat32, no limit */
- StartingSector = DeviceExt->rootStart;
- NextCluster = 0;
- if (FileToFind[0] == 0 || (FileToFind[0] == '\\' && FileToFind[1] == 0)
- || (FileToFind[0] == '.' && FileToFind[1] == 0))
- {
- /* it's root : complete essentials fields then return ok */
- CHECKPOINT;
- memset (Fcb, 0, sizeof (VFATFCB));
- memset (Fcb->entry.Filename, ' ', 11);
- CHECKPOINT;
- Fcb->PathName[0]='\\';
- Fcb->ObjectName = &Fcb->PathName[1];
- Fcb->entry.FileSize = DeviceExt->rootDirectorySectors * BLOCKSIZE;
- Fcb->entry.Attrib = FILE_ATTRIBUTE_DIRECTORY;
- if (DeviceExt->FatType == FAT32)
- Fcb->entry.FirstCluster = 2;
- else
- Fcb->entry.FirstCluster = 1;
- if (StartSector)
- *StartSector = StartingSector;
- if (Entry)
- *Entry = 0;
- DPRINT("FindFile: new Pathname %S, new Objectname %S)\n",Fcb->PathName, Fcb->ObjectName);
- return (STATUS_SUCCESS);
+ Status = DeviceExt->GetNextDirEntry(&Context, &Page, Parent, DirContext, First);
+ First = FALSE;
+ if (Status == STATUS_NO_MORE_ENTRIES)
+ {
+ break;
+ }
+ if (ENTRY_VOLUME(DeviceExt, &DirContext->DirEntry))
+ {
+ DirContext->DirIndex++;
+ continue;
+ }
+ if (WildCard)
+ {
+ Found = FsRtlIsNameInExpression(&FileToFindUpcase, &DirContext->LongNameU, TRUE, NULL) ||
+ FsRtlIsNameInExpression(&FileToFindUpcase, &DirContext->ShortNameU, TRUE, NULL);
}
- }
- else
- {
- DPRINT ("Parent->entry.FileSize %x\n", Parent->entry.FileSize);
-
- Size = ULONG_MAX;
- if (DeviceExt->FatType == FAT32)
- NextCluster = Parent->entry.FirstCluster
- + Parent->entry.FirstClusterHigh * 65536;
else
- NextCluster = Parent->entry.FirstCluster;
- StartingSector = ClusterToSector (DeviceExt, NextCluster);
- if (Parent->entry.FirstCluster == 1 && DeviceExt->FatType != FAT32)
- {
- /* read of root directory in FAT16 or FAT12 */
- StartingSector = DeviceExt->rootStart;
+ {
+ Found = FsRtlAreNamesEqual(&DirContext->LongNameU, FileToFindU, TRUE, NULL) ||
+ FsRtlAreNamesEqual(&DirContext->ShortNameU, FileToFindU, TRUE, NULL);
}
- }
- block = ExAllocatePool (NonPagedPool, BLOCKSIZE);
- if (StartSector && (*StartSector))
- StartingSector = *StartSector;
- i = (Entry) ? (*Entry) : 0;
- for (j = 0; j < Size; j++)
- {
- /* FIXME: Check status */
- VfatReadSectors (DeviceExt->StorageDevice, StartingSector, 1, block);
- for (i = (Entry) ? (*Entry) : 0; i < ENTRIES_PER_SECTOR; i++)
- {
- if (IsVolEntry ((PVOID) block, i))
- continue;
- if (IsLastEntry ((PVOID) block, i))
- {
- if (StartSector)
- *StartSector = StartingSector;
- if (Entry)
- *Entry = i;
- ExFreePool (block);
- return (STATUS_UNSUCCESSFUL);
- }
- if (GetEntryName
- ((PVOID) block, &i, name, &j, DeviceExt, &StartingSector))
+ if (Found)
+ {
+ if (WildCard)
{
- if (wstrcmpjoki (name, FileToFind))
- {
- /* In the case of a long filename, the firstcluster is
- stored in the next record -- where it's short name is */
- if (((FATDirEntry *) block)[i].Attrib == 0x0f)
- i++;
- if (i == (ENTRIES_PER_SECTOR))
- {
- /* FIXME: Check status */
- GetNextSector (DeviceExt, StartingSector, &StartingSector, FALSE);
-
- /* FIXME: Check status */
- VfatReadSectors (DeviceExt->StorageDevice,
- StartingSector, 1, block);
- i = 0;
- }
- if (Parent && Parent->PathName)
- {
- len = wcslen(Parent->PathName);
- CHECKPOINT;
- memcpy(Fcb->PathName, Parent->PathName, len*sizeof(WCHAR));
- Fcb->ObjectName=&Fcb->PathName[len];
- }
- else
- Fcb->ObjectName=Fcb->PathName;
-
- Fcb->ObjectName[0]='\\';
- Fcb->ObjectName=&Fcb->ObjectName[1];
-
- memcpy (&Fcb->entry, &((FATDirEntry *) block)[i],
- sizeof (FATDirEntry));
- vfat_wcsncpy (Fcb->ObjectName, name, MAX_PATH);
- if (StartSector)
- *StartSector = StartingSector;
- if (Entry)
- *Entry = i;
- ExFreePool (block);
- DPRINT("FindFile: new Pathname %S, new Objectname %S)\n",Fcb->PathName, Fcb->ObjectName);
- return (STATUS_SUCCESS);
+ RtlCopyUnicodeString(&PathNameU, &Parent->PathNameU);
+ if (!vfatFCBIsRoot(Parent))
+ {
+ PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = L'\\';
+ PathNameU.Length += sizeof(WCHAR);
+ }
+ RtlAppendUnicodeStringToString(&PathNameU, &DirContext->LongNameU);
+ PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = 0;
+ rcFcb = vfatGrabFCBFromTable(DeviceExt, &PathNameU);
+ if (rcFcb != NULL)
+ {
+ RtlCopyMemory(&DirContext->DirEntry, &rcFcb->entry, sizeof(DIR_ENTRY));
+ vfatReleaseFCB(DeviceExt, rcFcb);
}
}
- }
- /* not found in this sector, try next : */
-
- /* directory can be fragmented although it is best to keep them
- unfragmented. Should we change this to also use GetNextSector?
- GetNextSector was originally implemented to handle the case above */
- if (Entry)
- *Entry = 0;
- StartingSector++;
- if ((Parent != NULL && Parent->entry.FirstCluster != 1)
- || DeviceExt->FatType == FAT32)
- {
- if (StartingSector == ClusterToSector (DeviceExt, NextCluster + 1))
+ DPRINT("%d\n", DirContext->LongNameU.Length);
+ DPRINT("FindFile: new Name %wZ, DirIndex %d\n",
+ &DirContext->LongNameU, DirContext->DirIndex);
+
+ if (Context)
{
- Status = GetNextCluster (DeviceExt, NextCluster, &NextCluster,
- FALSE);
- if (NextCluster == 0 || NextCluster == 0xffffffff)
- {
- if (StartSector)
- *StartSector = StartingSector;
- if (Entry)
- *Entry = i;
- ExFreePool (block);
- return (STATUS_UNSUCCESSFUL);
- }
- StartingSector = ClusterToSector (DeviceExt, NextCluster);
+ CcUnpinData(Context);
}
+ RtlFreeUnicodeString(&FileToFindUpcase);
+ ExFreePool(PathNameBuffer);
+ return STATUS_SUCCESS;
}
+ DirContext->DirIndex++;
}
- if (StartSector)
- *StartSector = StartingSector;
- if (Entry)
- *Entry = i;
- ExFreePool (block);
- return (STATUS_UNSUCCESSFUL);
-}
-
-NTSTATUS
-vfatMakeAbsoluteFilename (PFILE_OBJECT pFileObject,
- PWSTR pRelativeFileName,
- PWSTR *pAbsoluteFilename)
-{
- PWSTR rcName;
- PVFATFCB fcb;
- PVFATCCB ccb;
-
- DbgPrint ("try related for %S\n", pRelativeFileName);
- ccb = pFileObject->FsContext2;
- assert (ccb);
- fcb = ccb->pFcb;
- assert (fcb);
-
- /* verify related object is a directory and target name
- don't start with \. */
- if (!(fcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY)
- || (pRelativeFileName[0] != '\\'))
- {
- return STATUS_INVALID_PARAMETER;
- }
- /* construct absolute path name */
- assert (wcslen (fcb->PathName) + 1 + wcslen (pRelativeFileName) + 1
- <= MAX_PATH);
- rcName = ExAllocatePool (NonPagedPool, MAX_PATH);
- wcscpy (rcName, fcb->PathName);
- wcscat (rcName, L"\\");
- wcscat (rcName, pRelativeFileName);
- *pAbsoluteFilename = rcName;
+ if (Context)
+ {
+ CcUnpinData(Context);
+ }
- return STATUS_SUCCESS;
+ RtlFreeUnicodeString(&FileToFindUpcase);
+ ExFreePool(PathNameBuffer);
+ return Status;
}
NTSTATUS
-VfatOpenFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject,
- PWSTR FileName)
+VfatOpenFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, PVFATFCB* ParentFcb)
/*
* FUNCTION: Opens a file
*/
{
- PWSTR current = NULL;
- PWSTR next;
- PWSTR string;
-// PWSTR buffer; // used to store a pointer while checking MAX_PATH conformance
- PVFATFCB ParentFcb;
PVFATFCB Fcb;
- PVFATFCB Temp;
- PVFATCCB newCCB;
NTSTATUS Status;
- PWSTR AbsFileName = NULL;
- ULONG BytesPerCluster, FileCacheQuantum;
+ UNICODE_STRING PathNameU;
+ WCHAR Buffer[260];
- DPRINT ("VfatOpenFile(%08lx, %08lx, %S)\n", DeviceExt, FileObject, FileName);
+ DPRINT ("VfatOpenFile(%08lx, %08lx, '%wZ')\n", DeviceExt, FileObject, &FileObject->FileName);
- /* FIXME : treat relative name */
if (FileObject->RelatedFileObject)
{
- Status = vfatMakeAbsoluteFilename (FileObject->RelatedFileObject,
- FileName,
- &AbsFileName);
- FileName = AbsFileName;
- }
-
- /*
- * try first to find an existing FCB in memory
- */
- CHECKPOINT;
-
- Fcb = vfatGrabFCBFromTable (DeviceExt, FileName);
- if (Fcb != NULL)
- {
- FileObject->FsContext = (PVOID)&Fcb->RFCB;
- newCCB = ExAllocatePoolWithTag (NonPagedPool, sizeof (VFATCCB), TAG_CCB);
- memset (newCCB, 0, sizeof (VFATCCB));
- FileObject->Flags = FileObject->Flags |
- FO_FCB_IS_VALID | FO_DIRECT_CACHE_PAGING_READ;
- FileObject->SectionObjectPointers = &Fcb->SectionObjectPointers;
- FileObject->FsContext2 = newCCB;
- newCCB->pFcb = Fcb;
- newCCB->PtrFileObject = FileObject;
- if (AbsFileName)
- ExFreePool (AbsFileName);
- return STATUS_SUCCESS;
- }
-
- DPRINT ("FileName %S\n", FileName);
+ DPRINT ("'%wZ'\n", &FileObject->RelatedFileObject->FileName);
- string = FileName;
- ParentFcb = NULL;
- Fcb = vfatNewFCB (L"\\");
- next = &string[0];
-
- CHECKPOINT;
- if (*next == 0 || *(next+1) == 0) // root
- {
- memset (Fcb->entry.Filename, ' ', 11);
- Fcb->entry.FileSize = DeviceExt->rootDirectorySectors * BLOCKSIZE;
- Fcb->entry.Attrib = FILE_ATTRIBUTE_DIRECTORY;
- if (DeviceExt->FatType == FAT32)
- Fcb->entry.FirstCluster = 2;
- else
- Fcb->entry.FirstCluster = 1;
- /* FIXME : is 1 the good value for mark root? */
- ParentFcb = Fcb;
- DPRINT("%S filename, PathName: %S\n",FileName, ParentFcb->PathName);
- Fcb = NULL;
+ *ParentFcb = FileObject->RelatedFileObject->FsContext;
+ (*ParentFcb)->RefCount++;
}
else
{
- while (TRUE)
- {
- CHECKPOINT;
- *next = '\\';
- current = next + 1;
- next = wcschr (next + 1, '\\');
- if (next != NULL)
- {
- *next = 0;
- }
- else
- {
- /* reached the last path component */
- DPRINT ("exiting: current '%S'\n", current);
- break;
- }
+ *ParentFcb = NULL;
+ }
- DPRINT ("search for (%S) in (%S)\n", current, ParentFcb ? ParentFcb->PathName : L"");
- Status = FindFile (DeviceExt, Fcb, ParentFcb, current, NULL, NULL);
- if (Status != STATUS_SUCCESS)
- {
- CHECKPOINT;
- if (Fcb != NULL)
- ExFreePool (Fcb);
- if (ParentFcb != NULL)
- ExFreePool (ParentFcb);
- if (AbsFileName)
- ExFreePool (AbsFileName);
-
- DPRINT ("error STATUS_OBJECT_PATH_NOT_FOUND\n");
- return STATUS_OBJECT_PATH_NOT_FOUND;
- }
- Temp = Fcb;
- CHECKPOINT;
- if (ParentFcb == NULL)
- {
- CHECKPOINT;
- Fcb = vfatNewFCB (L"\\");
- }
- else
- Fcb = ParentFcb;
+ if (!DeviceExt->FatInfo.FixedMedia)
+ {
+ Status = VfatBlockDeviceIoControl (DeviceExt->StorageDevice,
+ IOCTL_DISK_CHECK_VERIFY,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ FALSE);
- if (*(Temp->ObjectName))
- {
- vfat_wcsncpy(Fcb->PathName+(Fcb->ObjectName-Fcb->PathName),Temp->PathName+(Fcb->ObjectName-Fcb->PathName), MAX_PATH);
+ if (Status == STATUS_VERIFY_REQUIRED)
- Fcb->ObjectName = &Fcb->PathName[wcslen(Fcb->PathName)];
- Fcb->ObjectName[0]='\\';
- Fcb->ObjectName=&Fcb->ObjectName[1];
- Fcb->ObjectName[0]=0;
- }
- CHECKPOINT;
- ParentFcb = Temp;
- }
-
- if( *current != L'\0' ){ //the file name is directory. there will be no last part.
- /* searching for last path component */
- DPRINT ("search for (%S) in (%S)\n", current, Fcb ? Fcb->PathName : L"");
- Status = FindFile (DeviceExt, Fcb, ParentFcb, current, NULL, NULL);
- if (Status != STATUS_SUCCESS)
{
- /* file does not exist */
- CHECKPOINT;
- if (Fcb != NULL)
- ExFreePool (Fcb);
- if (ParentFcb != NULL)
- ExFreePool (ParentFcb);
- if (AbsFileName)
- ExFreePool (AbsFileName);
-
- return STATUS_OBJECT_NAME_NOT_FOUND;
- }
+ PDEVICE_OBJECT DeviceToVerify;
- Temp = Fcb;
+ DPRINT ("Media change detected!\n");
+ DPRINT ("Device %p\n", DeviceExt->StorageDevice);
- Fcb = ParentFcb;
- ParentFcb = Temp;
- ParentFcb->ObjectName = &(wcschr (ParentFcb->ObjectName, '\\'))[1];
- }
+ DeviceToVerify = IoGetDeviceToVerify (PsGetCurrentThread ());
+
+ IoSetDeviceToVerify (PsGetCurrentThread (),
+ NULL);
+ Status = IoVerifyVolume (DeviceExt->StorageDevice,
+ FALSE);
+ }
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT ("Status %lx\n", Status);
+ *ParentFcb = NULL;
+ return Status;
+ }
}
- FileObject->Flags = FileObject->Flags |
- FO_FCB_IS_VALID | FO_DIRECT_CACHE_PAGING_READ;
- FileObject->SectionObjectPointers = &ParentFcb->SectionObjectPointers;
- memset(FileObject->SectionObjectPointers, 0,
- sizeof(SECTION_OBJECT_POINTERS));
- FileObject->FsContext = (PVOID)&ParentFcb->RFCB;
- newCCB = ExAllocatePoolWithTag (NonPagedPool, sizeof (VFATCCB), TAG_CCB);
- memset (newCCB, 0, sizeof (VFATCCB));
- FileObject->FsContext2 = newCCB;
- newCCB->pFcb = ParentFcb;
- newCCB->PtrFileObject = FileObject;
- ParentFcb->RefCount++;
- ParentFcb->pDevExt = DeviceExt;
- /* FIXME : initialize all fields in FCB and CCB */
-
- BytesPerCluster = DeviceExt->Boot->SectorsPerCluster * BLOCKSIZE;
- FileCacheQuantum = (BytesPerCluster >= PAGESIZE) ? BytesPerCluster : PAGESIZE;
- Status = CcRosInitializeFileCache(FileObject,
- &ParentFcb->RFCB.Bcb,
- FileCacheQuantum);
- if (!NT_SUCCESS(Status))
+ if (*ParentFcb)
+ {
+ (*ParentFcb)->RefCount++;
+ }
+
+ PathNameU.Buffer = Buffer;
+ PathNameU.Length = 0;
+ PathNameU.MaximumLength = sizeof(Buffer);
+ RtlCopyUnicodeString(&PathNameU, &FileObject->FileName);
+ if (PathNameU.Length > sizeof(WCHAR) &&
+ PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR) - 1] == L'\\')
{
- DbgPrint("CcRosInitializeFileCache failed\n");
- KeBugCheck(0);
+ PathNameU.Length -= sizeof(WCHAR);
}
- DPRINT ("file open, fcb=%x\n", ParentFcb);
- DPRINT ("FileSize %d\n", ParentFcb->entry.FileSize);
-
- vfatAddFCBToTable (DeviceExt, ParentFcb);
+ PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = 0;
- if (Fcb)
- ExFreePool (Fcb);
- if (AbsFileName)
- ExFreePool (AbsFileName);
- CHECKPOINT;
+ /* try first to find an existing FCB in memory */
+ DPRINT ("Checking for existing FCB in memory\n");
- return (STATUS_SUCCESS);
+ Status = vfatGetFCBForFile (DeviceExt, ParentFcb, &Fcb, &PathNameU);
+ if (!NT_SUCCESS (Status))
+ {
+ DPRINT ("Could not make a new FCB, status: %x\n", Status);
+ return Status;
+ }
+ if (Fcb->Flags & FCB_DELETE_PENDING)
+ {
+ vfatReleaseFCB (DeviceExt, Fcb);
+ return STATUS_DELETE_PENDING;
+ }
+ DPRINT ("Attaching FCB to fileObject\n");
+ Status = vfatAttachFCBToFileObject (DeviceExt, Fcb, FileObject);
+ if (!NT_SUCCESS(Status))
+ {
+ vfatReleaseFCB (DeviceExt, Fcb);
+ }
+ return Status;
}
-
NTSTATUS
VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp)
/*
ULONG RequestedDisposition, RequestedOptions;
PVFATCCB pCcb;
PVFATFCB pFcb;
- PWCHAR c;
+ PVFATFCB ParentFcb;
+ PWCHAR c, last;
+ BOOLEAN PagingFileCreate = FALSE;
+ LARGE_INTEGER AllocationSize;
+ BOOLEAN Dots;
+ UNICODE_STRING FileNameU;
+ /* Unpack the various parameters. */
Stack = IoGetCurrentIrpStackLocation (Irp);
- assert (Stack);
RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
RequestedOptions =
Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
- if ((RequestedOptions & FILE_DIRECTORY_FILE)
- && RequestedDisposition == FILE_SUPERSEDE)
- return STATUS_INVALID_PARAMETER;
+ PagingFileCreate = (Stack->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE;
FileObject = Stack->FileObject;
DeviceExt = DeviceObject->DeviceExtension;
- assert (DeviceExt);
-
+
+ /* Check their validity. */
+ if (RequestedOptions & FILE_DIRECTORY_FILE &&
+ RequestedDisposition == FILE_SUPERSEDE)
+ {
+ return(STATUS_INVALID_PARAMETER);
+ }
+
+ /* This a open operation for the volume itself */
+ if (FileObject->FileName.Length == 0 &&
+ FileObject->RelatedFileObject == NULL)
+ {
+ if (RequestedDisposition == FILE_CREATE ||
+ RequestedDisposition == FILE_OVERWRITE_IF ||
+ RequestedDisposition == FILE_SUPERSEDE)
+ {
+ return(STATUS_ACCESS_DENIED);
+ }
+ if (RequestedOptions & FILE_DIRECTORY_FILE)
+ {
+ return(STATUS_NOT_A_DIRECTORY);
+ }
+ pFcb = DeviceExt->VolumeFcb;
+ pCcb = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
+ if (pCcb == NULL)
+ {
+ return (STATUS_INSUFFICIENT_RESOURCES);
+ }
+ RtlZeroMemory(pCcb, sizeof(VFATCCB));
+ FileObject->SectionObjectPointer = &pFcb->SectionObjectPointers;
+ FileObject->FsContext = pFcb;
+ FileObject->FsContext2 = pCcb;
+ pFcb->RefCount++;
+
+ Irp->IoStatus.Information = FILE_OPENED;
+ return(STATUS_SUCCESS);
+ }
+
/*
- * Check for illegal characters in the file name
+ * Check for illegal characters and illegale dot sequences in the file name
*/
- c = FileObject->FileName.Buffer;
- while (*c != 0)
+ c = FileObject->FileName.Buffer + FileObject->FileName.Length / sizeof(WCHAR);
+ last = c - 1;
+ Dots = TRUE;
+ while (c-- > FileObject->FileName.Buffer)
{
- if (*c == L'*' || *c == L'?')
- {
- Irp->IoStatus.Information = 0;
- Irp->IoStatus.Status = STATUS_OBJECT_NAME_INVALID;
- return(STATUS_OBJECT_NAME_INVALID);
+ if (*c == L'\\' || c == FileObject->FileName.Buffer)
+ {
+ if (Dots && last > c)
+ {
+ return(STATUS_OBJECT_NAME_INVALID);
+ }
+ last = c - 1;
+ Dots = TRUE;
+ }
+ else if (*c != L'.')
+ {
+ Dots = FALSE;
+ }
+
+ if (*c != '\\' && vfatIsLongIllegal(*c))
+ {
+ return(STATUS_OBJECT_NAME_INVALID);
}
- c++;
}
- Status = VfatOpenFile (DeviceExt, FileObject, FileObject->FileName.Buffer);
+ /* Try opening the file. */
+ Status = VfatOpenFile (DeviceExt, FileObject, &ParentFcb);
/*
* If the directory containing the file to open doesn't exist then
* fail immediately
*/
- Irp->IoStatus.Information = 0;
- if (Status == STATUS_OBJECT_PATH_NOT_FOUND)
+ if (Status == STATUS_OBJECT_PATH_NOT_FOUND ||
+ Status == STATUS_INVALID_PARAMETER ||
+ Status == STATUS_DELETE_PENDING)
{
- Irp->IoStatus.Status = Status;
- return Status;
+ if (ParentFcb)
+ {
+ vfatReleaseFCB (DeviceExt, ParentFcb);
+ }
+ return(Status);
}
+ /*
+ * If the file open failed then create the required file
+ */
if (!NT_SUCCESS (Status))
{
- /*
- * If the file open failed then create the required file
- */
- if (RequestedDisposition == FILE_CREATE ||
- RequestedDisposition == FILE_OPEN_IF ||
- RequestedDisposition == FILE_OVERWRITE_IF ||
+ if (RequestedDisposition == FILE_CREATE ||
+ RequestedDisposition == FILE_OPEN_IF ||
+ RequestedDisposition == FILE_OVERWRITE_IF ||
RequestedDisposition == FILE_SUPERSEDE)
{
- CHECKPOINT;
- Status =
- addEntry (DeviceExt, FileObject, RequestedOptions,
- (Stack->Parameters.
- Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS));
+ ULONG Attributes;
+ Attributes = Stack->Parameters.Create.FileAttributes;
+
+ vfatSplitPathName(&FileObject->FileName, NULL, &FileNameU);
+ Status = VfatAddEntry (DeviceExt, &FileNameU, &pFcb, ParentFcb, RequestedOptions,
+ (UCHAR)(Attributes & FILE_ATTRIBUTE_VALID_FLAGS));
+ vfatReleaseFCB (DeviceExt, ParentFcb);
if (NT_SUCCESS (Status))
- Irp->IoStatus.Information = FILE_CREATED;
- /* FIXME set size if AllocationSize requested */
- /* FIXME set extended attributes? */
- /* FIXME set share access */
- /* IoSetShareAccess(DesiredAccess,ShareAccess,FileObject,
- * ((PVfatCCB)(FileObject->FsContext2))->pFcb->FCBShareAccess);
- */
+ {
+ Status = vfatAttachFCBToFileObject (DeviceExt, pFcb, FileObject);
+ if ( !NT_SUCCESS(Status) )
+ {
+ vfatReleaseFCB (DeviceExt, pFcb);
+ return Status;
+ }
+
+ Irp->IoStatus.Information = FILE_CREATED;
+
+ VfatSetAllocationSizeInformation(FileObject,
+ pFcb,
+ DeviceExt,
+ &Irp->Overlay.AllocationSize);
+ VfatSetExtendedAttributes(FileObject,
+ Irp->AssociatedIrp.SystemBuffer,
+ Stack->Parameters.Create.EaLength);
+
+ if (PagingFileCreate)
+ {
+ pFcb->Flags |= FCB_IS_PAGE_FILE;
+ }
+ }
+ else
+ {
+ return(Status);
+ }
+ }
+ else
+ {
+ vfatReleaseFCB (DeviceExt, ParentFcb);
+ return(Status);
}
}
else
{
- /*
- * Otherwise fail if the caller wanted to create a new file
- */
+ if (ParentFcb)
+ {
+ vfatReleaseFCB (DeviceExt, ParentFcb);
+ }
+ /* Otherwise fail if the caller wanted to create a new file */
if (RequestedDisposition == FILE_CREATE)
{
Irp->IoStatus.Information = FILE_EXISTS;
- Status = STATUS_OBJECT_NAME_COLLISION;
- }
- pCcb = FileObject->FsContext2;
- pFcb = pCcb->pFcb;
+ VfatCloseFile (DeviceExt, FileObject);
+ return(STATUS_OBJECT_NAME_COLLISION);
+ }
+
+ pFcb = FileObject->FsContext;
+
+ if (pFcb->OpenHandleCount != 0 &&
+ !(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ Status = IoCheckShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
+ Stack->Parameters.Create.ShareAccess,
+ FileObject,
+ &pFcb->FCBShareAccess,
+ FALSE);
+ if (!NT_SUCCESS(Status))
+ {
+ VfatCloseFile (DeviceExt, FileObject);
+ return(Status);
+ }
+ }
+
/*
- * If requested then delete the file and create a new one with the
- * same name
+ * Check the file has the requested attributes
*/
- if (RequestedDisposition == FILE_SUPERSEDE)
+ if (RequestedOptions & FILE_NON_DIRECTORY_FILE &&
+ *pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ VfatCloseFile (DeviceExt, FileObject);
+ return(STATUS_FILE_IS_A_DIRECTORY);
+ }
+ if (RequestedOptions & FILE_DIRECTORY_FILE &&
+ !(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
{
- ULONG Cluster, NextCluster;
- /* FIXME set size to 0 and free clusters */
- pFcb->entry.FileSize = 0;
- if (DeviceExt->FatType == FAT32)
- Cluster = pFcb->entry.FirstCluster
- + pFcb->entry.FirstClusterHigh * 65536;
+ VfatCloseFile (DeviceExt, FileObject);
+ return(STATUS_NOT_A_DIRECTORY);
+ }
+
+ if (PagingFileCreate)
+ {
+ /* FIXME:
+ * Do more checking for page files. It is possible,
+ * that the file was opened and closed previously
+ * as a normal cached file. In this case, the cache
+ * manager has referenced the fileobject and the fcb
+ * is held in memory. Try to remove the fileobject
+ * from cache manager and use the fcb.
+ */
+ if (pFcb->RefCount > 1)
+ {
+ if(!(pFcb->Flags & FCB_IS_PAGE_FILE))
+ {
+ VfatCloseFile(DeviceExt, FileObject);
+ return(STATUS_INVALID_PARAMETER);
+ }
+ }
else
- Cluster = pFcb->entry.FirstCluster;
- pFcb->entry.FirstCluster = 0;
- pFcb->entry.FirstClusterHigh = 0;
- updEntry (DeviceExt, FileObject);
- while (Cluster != 0xffffffff && Cluster > 1)
{
- Status = GetNextCluster (DeviceExt, Cluster, &NextCluster, TRUE);
- WriteCluster (DeviceExt, Cluster, 0);
- Cluster = NextCluster;
+ pFcb->Flags |= FCB_IS_PAGE_FILE;
+ }
+ }
+ else
+ {
+ if (pFcb->Flags & FCB_IS_PAGE_FILE)
+ {
+ VfatCloseFile(DeviceExt, FileObject);
+ return(STATUS_INVALID_PARAMETER);
}
}
- /*
- * Check the file has the requested attributes
- */
- if ((RequestedOptions & FILE_NON_DIRECTORY_FILE)
- && (pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
+
+ if (RequestedDisposition == FILE_OVERWRITE ||
+ RequestedDisposition == FILE_OVERWRITE_IF)
{
- Status = STATUS_FILE_IS_A_DIRECTORY;
+ AllocationSize.QuadPart = 0;
+ Status = VfatSetAllocationSizeInformation (FileObject,
+ pFcb,
+ DeviceExt,
+ &AllocationSize);
+ if (!NT_SUCCESS (Status))
+ {
+ VfatCloseFile (DeviceExt, FileObject);
+ return(Status);
+ }
}
- if ((RequestedOptions & FILE_DIRECTORY_FILE)
- && !(pFcb->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY))
+
+
+ /* Supersede the file */
+ if (RequestedDisposition == FILE_SUPERSEDE)
{
- Status = STATUS_NOT_A_DIRECTORY;
+ AllocationSize.QuadPart = 0;
+ VfatSetAllocationSizeInformation(FileObject, pFcb, DeviceExt, &AllocationSize);
+ Irp->IoStatus.Information = FILE_SUPERSEDED;
}
- /* FIXME : test share access */
- /* FIXME : test write access if requested */
- if (!NT_SUCCESS (Status))
- VfatCloseFile (DeviceExt, FileObject);
+ else if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF)
+ {
+ Irp->IoStatus.Information = FILE_OVERWRITTEN;
+ }
else
- Irp->IoStatus.Information = FILE_OPENED;
- /* FIXME : make supersed or overwrite if requested */
+ {
+ Irp->IoStatus.Information = FILE_OPENED;
+ }
}
- Irp->IoStatus.Status = Status;
+ if (pFcb->OpenHandleCount == 0 &&
+ !(*pFcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ IoSetShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess,
+ Stack->Parameters.Create.ShareAccess,
+ FileObject,
+ &pFcb->FCBShareAccess);
+ }
+ else
+ {
+ IoUpdateShareAccess(
+ FileObject,
+ &pFcb->FCBShareAccess
+ );
- return Status;
+ }
+
+ pFcb->OpenHandleCount++;
+
+ /* FIXME : test write access if requested */
+
+ return(Status);
}
-NTSTATUS STDCALL
-VfatCreate (PDEVICE_OBJECT DeviceObject, PIRP Irp)
+NTSTATUS VfatCreate (PVFAT_IRP_CONTEXT IrpContext)
/*
* FUNCTION: Create or open a file
*/
{
- NTSTATUS Status = STATUS_SUCCESS;
- PDEVICE_EXTENSION DeviceExt;
+ NTSTATUS Status;
- assert (DeviceObject);
- assert (Irp);
-
- if (DeviceObject->Size == sizeof (DEVICE_OBJECT))
+ ASSERT(IrpContext);
+
+ if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
{
/* DeviceObject represents FileSystem instead of logical volume */
- DbgPrint ("FsdCreate called with file system\n");
- Irp->IoStatus.Status = Status;
- Irp->IoStatus.Information = FILE_OPENED;
- IoCompleteRequest (Irp, IO_NO_INCREMENT);
- return (Status);
+ DPRINT ("FsdCreate called with file system\n");
+ IrpContext->Irp->IoStatus.Information = FILE_OPENED;
+ IrpContext->Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest (IrpContext->Irp, IO_DISK_INCREMENT);
+ VfatFreeIrpContext(IrpContext);
+ return(STATUS_SUCCESS);
}
- DeviceExt = DeviceObject->DeviceExtension;
- assert (DeviceExt);
- ExAcquireResourceExclusiveLite (&DeviceExt->DirResource, TRUE);
+ if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT))
+ {
+ return(VfatQueueRequest (IrpContext));
+ }
- Status = VfatCreateFile (DeviceObject, Irp);
-
- ExReleaseResourceLite (&DeviceExt->DirResource);
-
- Irp->IoStatus.Status = Status;
- IoCompleteRequest (Irp, IO_NO_INCREMENT);
+ IrpContext->Irp->IoStatus.Information = 0;
+ ExAcquireResourceExclusiveLite (&IrpContext->DeviceExt->DirResource, TRUE);
+ Status = VfatCreateFile (IrpContext->DeviceObject, IrpContext->Irp);
+ ExReleaseResourceLite (&IrpContext->DeviceExt->DirResource);
- return Status;
+ IrpContext->Irp->IoStatus.Status = Status;
+ IoCompleteRequest (IrpContext->Irp,
+ (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT));
+ VfatFreeIrpContext(IrpContext);
+ return(Status);
}
/* EOF */