dirwr.c
来自「这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统」· C语言 代码 · 共 739 行 · 第 1/2 页
C
739 行
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: drivers/fs/vfat/dirwr.c
* PURPOSE: VFAT Filesystem : write in directory
*
*/
/* INCLUDES *****************************************************************/
#define NDEBUG
#include "vfat.h"
NTSTATUS
VfatUpdateEntry (PVFATFCB pFcb)
/*
* update an existing FAT entry
*/
{
PVOID Context;
PDIR_ENTRY PinEntry;
LARGE_INTEGER Offset;
ULONG SizeDirEntry;
ULONG dirIndex;
ASSERT(pFcb);
ASSERT(pFcb->parentFcb);
if (pFcb->Flags & FCB_IS_FATX_ENTRY)
{
SizeDirEntry = sizeof(FATX_DIR_ENTRY);
dirIndex = pFcb->startIndex;
}
else
{
SizeDirEntry = sizeof(FAT_DIR_ENTRY);
dirIndex = pFcb->dirIndex;
}
DPRINT ("updEntry dirIndex %d, PathName \'%wZ\'\n", dirIndex, &pFcb->PathNameU);
if (vfatFCBIsRoot(pFcb) || (pFcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME)))
{
return STATUS_SUCCESS;
}
ASSERT (pFcb->parentFcb);
Offset.u.HighPart = 0;
Offset.u.LowPart = dirIndex * SizeDirEntry;
if (CcPinRead (pFcb->parentFcb->FileObject, &Offset, SizeDirEntry,
TRUE, &Context, (PVOID*)&PinEntry))
{
pFcb->Flags &= ~FCB_IS_DIRTY;
RtlCopyMemory(PinEntry, &pFcb->entry, SizeDirEntry);
CcSetDirtyPinnedData(Context, NULL);
CcUnpinData(Context);
return STATUS_SUCCESS;
}
else
{
DPRINT1 ("Failed write to \'%wZ\'.\n", &pFcb->parentFcb->PathNameU);
return STATUS_UNSUCCESSFUL;
}
}
BOOLEAN
vfatFindDirSpace(PDEVICE_EXTENSION DeviceExt,
PVFATFCB pDirFcb,
ULONG nbSlots,
PULONG start)
{
/*
* try to find contiguous entries frees in directory,
* extend a directory if is neccesary
*/
LARGE_INTEGER FileOffset;
ULONG i, count, size, nbFree = 0;
PDIR_ENTRY pFatEntry;
PVOID Context = NULL;
NTSTATUS Status;
ULONG SizeDirEntry;
FileOffset.QuadPart = 0;
if (DeviceExt->Flags & VCB_IS_FATX)
SizeDirEntry = sizeof(FATX_DIR_ENTRY);
else
SizeDirEntry = sizeof(FAT_DIR_ENTRY);
count = pDirFcb->RFCB.FileSize.u.LowPart / SizeDirEntry;
size = DeviceExt->FatInfo.BytesPerCluster / SizeDirEntry;
for (i = 0; i < count; i++, pFatEntry = (PDIR_ENTRY)((ULONG_PTR)pFatEntry + SizeDirEntry))
{
if (Context == NULL || (i % size) == 0)
{
if (Context)
{
CcUnpinData(Context);
}
// FIXME: check return value
CcPinRead (pDirFcb->FileObject, &FileOffset, DeviceExt->FatInfo.BytesPerCluster,
TRUE, &Context, (PVOID*)&pFatEntry);
FileOffset.u.LowPart += DeviceExt->FatInfo.BytesPerCluster;
}
if (ENTRY_END(DeviceExt, pFatEntry))
{
break;
}
if (ENTRY_DELETED(DeviceExt, pFatEntry))
{
nbFree++;
}
else
{
nbFree = 0;
}
if (nbFree == nbSlots)
{
break;
}
}
if (Context)
{
CcUnpinData(Context);
Context = NULL;
}
if (nbFree == nbSlots)
{
// found enough contiguous free slots
*start = i - nbSlots + 1;
}
else
{
*start = i - nbFree;
if (*start + nbSlots > count)
{
LARGE_INTEGER AllocationSize;
CHECKPOINT;
// extend the directory
if (vfatFCBIsRoot(pDirFcb) && DeviceExt->FatInfo.FatType != FAT32)
{
// We can't extend a root directory on a FAT12/FAT16/FATX partition
return FALSE;
}
AllocationSize.QuadPart = pDirFcb->RFCB.FileSize.u.LowPart + DeviceExt->FatInfo.BytesPerCluster;
Status = VfatSetAllocationSizeInformation(pDirFcb->FileObject, pDirFcb,
DeviceExt, &AllocationSize);
if (!NT_SUCCESS(Status))
{
return FALSE;
}
// clear the new dir cluster
FileOffset.u.LowPart = (ULONG)(pDirFcb->RFCB.FileSize.QuadPart -
DeviceExt->FatInfo.BytesPerCluster);
CcPinRead (pDirFcb->FileObject, &FileOffset, DeviceExt->FatInfo.BytesPerCluster,
TRUE, &Context, (PVOID*)&pFatEntry);
if (DeviceExt->Flags & VCB_IS_FATX)
memset(pFatEntry, 0xff, DeviceExt->FatInfo.BytesPerCluster);
else
RtlZeroMemory(pFatEntry, DeviceExt->FatInfo.BytesPerCluster);
}
else if (*start + nbSlots < count)
{
// clear the entry after the last new entry
FileOffset.u.LowPart = (*start + nbSlots) * SizeDirEntry;
CcPinRead (pDirFcb->FileObject, &FileOffset, SizeDirEntry,
TRUE, &Context, (PVOID*)&pFatEntry);
if (DeviceExt->Flags & VCB_IS_FATX)
memset(pFatEntry, 0xff, SizeDirEntry);
else
RtlZeroMemory(pFatEntry, SizeDirEntry);
}
if (Context)
{
CcSetDirtyPinnedData(Context, NULL);
CcUnpinData(Context);
}
}
DPRINT ("nbSlots %d nbFree %d, entry number %d\n", nbSlots, nbFree, *start);
return TRUE;
}
static NTSTATUS
FATAddEntry (PDEVICE_EXTENSION DeviceExt,
PUNICODE_STRING NameU,
PVFATFCB* Fcb,
PVFATFCB ParentFcb,
ULONG RequestedOptions,
UCHAR ReqAttr)
/*
create a new FAT entry
*/
{
PVOID Context = NULL;
PFAT_DIR_ENTRY pFatEntry;
slot *pSlots;
USHORT nbSlots = 0, j, posCar;
PUCHAR Buffer;
BOOLEAN needTilde = FALSE, needLong = FALSE;
BOOLEAN lCaseBase = FALSE, uCaseBase, lCaseExt = FALSE, uCaseExt;
ULONG CurrentCluster;
LARGE_INTEGER SystemTime, FileOffset;
NTSTATUS Status = STATUS_SUCCESS;
ULONG size;
long i;
OEM_STRING NameA;
CHAR aName[13];
BOOLEAN IsNameLegal;
BOOLEAN SpacesFound;
VFAT_DIRENTRY_CONTEXT DirContext;
WCHAR LongNameBuffer[LONGNAME_MAX_LENGTH + 1];
WCHAR ShortNameBuffer[13];
DPRINT ("addEntry: Name='%wZ', Dir='%wZ'\n", NameU, &ParentFcb->PathNameU);
DirContext.LongNameU = *NameU;
nbSlots = (DirContext.LongNameU.Length / sizeof(WCHAR) + 12) / 13 + 1; //nb of entry needed for long name+normal entry
DPRINT ("NameLen= %d, nbSlots =%d\n", DirContext.LongNameU.Length / sizeof(WCHAR), nbSlots);
Buffer = ExAllocatePool (NonPagedPool, (nbSlots - 1) * sizeof (FAT_DIR_ENTRY));
if (Buffer == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory (Buffer, (nbSlots - 1) * sizeof (FAT_DIR_ENTRY));
pSlots = (slot *) Buffer;
NameA.Buffer = aName;
NameA.Length = 0;
NameA.MaximumLength = sizeof(aName);
DirContext.ShortNameU.Buffer = ShortNameBuffer;
DirContext.ShortNameU.Length = 0;
DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer);
RtlZeroMemory(&DirContext.DirEntry.Fat, sizeof(FAT_DIR_ENTRY));
IsNameLegal = RtlIsNameLegalDOS8Dot3(&DirContext.LongNameU, &NameA, &SpacesFound);
if (!IsNameLegal || SpacesFound)
{
GENERATE_NAME_CONTEXT NameContext;
VFAT_DIRENTRY_CONTEXT SearchContext;
WCHAR ShortSearchName[13];
needTilde = TRUE;
needLong = TRUE;
RtlZeroMemory(&NameContext, sizeof(GENERATE_NAME_CONTEXT));
SearchContext.LongNameU.Buffer = LongNameBuffer;
SearchContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);
SearchContext.ShortNameU.Buffer = ShortSearchName;
SearchContext.ShortNameU.MaximumLength = sizeof(ShortSearchName);
for (i = 0; i < 100; i++)
{
RtlGenerate8dot3Name(&DirContext.LongNameU, FALSE, &NameContext, &DirContext.ShortNameU);
DirContext.ShortNameU.Buffer[DirContext.ShortNameU.Length / sizeof(WCHAR)] = 0;
SearchContext.DirIndex = 0;
Status = FindFile (DeviceExt, ParentFcb, &DirContext.ShortNameU, &SearchContext, TRUE);
if (!NT_SUCCESS(Status))
{
break;
}
}
if (i == 100) /* FIXME : what to do after this ? */
{
ExFreePool (Buffer);
CHECKPOINT;
return STATUS_UNSUCCESSFUL;
}
IsNameLegal = RtlIsNameLegalDOS8Dot3(&DirContext.ShortNameU, &NameA, &SpacesFound);
aName[NameA.Length]=0;
}
else
{
aName[NameA.Length] = 0;
for (posCar = 0; posCar < DirContext.LongNameU.Length / sizeof(WCHAR); posCar++)
{
if (DirContext.LongNameU.Buffer[posCar] == L'.')
{
break;
}
}
/* check if the name and the extension contains upper case characters */
RtlDowncaseUnicodeString(&DirContext.ShortNameU, &DirContext.LongNameU, FALSE);
DirContext.ShortNameU.Buffer[DirContext.ShortNameU.Length / sizeof(WCHAR)] = 0;
uCaseBase = wcsncmp(DirContext.LongNameU.Buffer,
DirContext.ShortNameU.Buffer, posCar) ? TRUE : FALSE;
if (posCar < DirContext.LongNameU.Length/sizeof(WCHAR))
{
i = DirContext.LongNameU.Length / sizeof(WCHAR) - posCar;
uCaseExt = wcsncmp(DirContext.LongNameU.Buffer + posCar,
DirContext.ShortNameU.Buffer + posCar, i) ? TRUE : FALSE;
}
else
{
uCaseExt = FALSE;
}
/* check if the name and the extension contains lower case characters */
RtlUpcaseUnicodeString(&DirContext.ShortNameU, &DirContext.LongNameU, FALSE);
DirContext.ShortNameU.Buffer[DirContext.ShortNameU.Length / sizeof(WCHAR)] = 0;
lCaseBase = wcsncmp(DirContext.LongNameU.Buffer,
DirContext.ShortNameU.Buffer, posCar) ? TRUE : FALSE;
if (posCar < DirContext.LongNameU.Length / sizeof(WCHAR))
{
i = DirContext.LongNameU.Length / sizeof(WCHAR) - posCar;
lCaseExt = wcsncmp(DirContext.LongNameU.Buffer + posCar,
DirContext.ShortNameU.Buffer + posCar, i) ? TRUE : FALSE;
}
else
{
lCaseExt = FALSE;
}
if ((lCaseBase && uCaseBase) || (lCaseExt && uCaseExt))
{
needLong = TRUE;
}
}
DPRINT ("'%s', '%wZ', needTilde=%d, needLong=%d\n",
aName, &DirContext.LongNameU, needTilde, needLong);
memset(DirContext.DirEntry.Fat.ShortName, ' ', 11);
for (i = 0; i < 8 && aName[i] && aName[i] != '.'; i++)
{
DirContext.DirEntry.Fat.Filename[i] = aName[i];
}
if (aName[i] == '.')
{
i++;
for (j = 8; j < 11 && aName[i]; j++, i++)
{
DirContext.DirEntry.Fat.Filename[j] = aName[i];
}
}
if (DirContext.DirEntry.Fat.Filename[0] == 0xe5)
{
DirContext.DirEntry.Fat.Filename[0] = 0x05;
}
if (needLong)
{
RtlCopyMemory(LongNameBuffer, DirContext.LongNameU.Buffer, DirContext.LongNameU.Length);
DirContext.LongNameU.Buffer = LongNameBuffer;
DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);
DirContext.LongNameU.Buffer[DirContext.LongNameU.Length / sizeof(WCHAR)] = 0;
memset(DirContext.LongNameU.Buffer + DirContext.LongNameU.Length / sizeof(WCHAR) + 1, 0xff,
DirContext.LongNameU.MaximumLength - DirContext.LongNameU.Length - sizeof(WCHAR));
}
else
{
nbSlots = 1;
if (lCaseBase)
{
DirContext.DirEntry.Fat.lCase |= VFAT_CASE_LOWER_BASE;
}
if (lCaseExt)
{
DirContext.DirEntry.Fat.lCase |= VFAT_CASE_LOWER_EXT;
}
}
DPRINT ("dos name=%11.11s\n", DirContext.DirEntry.Fat.Filename);
/* set attributes */
DirContext.DirEntry.Fat.Attrib = ReqAttr;
if (RequestedOptions & FILE_DIRECTORY_FILE)
{
DirContext.DirEntry.Fat.Attrib |= FILE_ATTRIBUTE_DIRECTORY;
}
/* set dates and times */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?