📄 file.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
/*++
Module Name:
file.c
Abstract:
This file contains the handle based api routines for the FAT file system.
Revision History:
--*/
#include "fatfs.h"
#define KEEP_SYSCALLS
#define NO_DEFINE_KCALL
HANDLE FAT_CreateFileW(
PVOLUME pvol,
HANDLE hProc,
LPCWSTR lpFileName,
DWORD dwAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreate,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile)
{
BYTE mode;
int flName;
HANDLE hFile;
PFHANDLE pfh = NULL;
PDSTREAM pstm = NULL;
DWORD dwError = ERROR_SUCCESS;
BOOL bExists = FALSE;
DEBUGMSGW(ZONE_APIS,(DBGTEXTW("FATFS!FAT_CreateFileW(%d chars: %s)\n"), wcslen(lpFileName), lpFileName));
if (!FATEnter(pvol, LOGID_CREATEFILE)) {
DEBUGMSG(ZONE_APIS || ZONE_ERRORS,(DBGTEXT("FATFS!FAT_CreateFileW bailing...\n")));
return INVALID_HANDLE_VALUE;
}
if (pvol->v_flags & (VOLF_UNMOUNTED | VOLF_FROZEN | VOLF_WRITELOCKED)) {
dwError = ERROR_ACCESS_DENIED;
goto exit;
}
if (dwAccess & ~(GENERIC_READ | GENERIC_WRITE))
goto invalidParm;
if ((BYTE)dwFlagsAndAttributes == FILE_ATTRIBUTE_NORMAL)
dwFlagsAndAttributes &= ~0xFF;
else {
dwFlagsAndAttributes &= ~FILE_ATTRIBUTE_NORMAL;
if ((BYTE)dwFlagsAndAttributes & ~ATTR_CHANGEABLE)
goto invalidParm;
}
dwFlagsAndAttributes |= FILE_ATTRIBUTE_ARCHIVE;
if (dwShareMode & ~(FILE_SHARE_READ | FILE_SHARE_WRITE))
goto invalidParm;
// Validate creation flags and set flName for OpenName; we allow
// only files and volumes to be opened with this call (NOT directories).
flName = NAME_FILE | NAME_VOLUME;
switch (dwCreate) {
case CREATE_NEW:
flName |= NAME_NEW;
// Fall into the CREATE_ALWAYS case now...
case CREATE_ALWAYS:
flName |= NAME_CREATE | NAME_TRUNCATE;
// We don't simply fall into TRUNCATE_EXISTING, because
// on Win95 at least, you're allowed to create a file without
// specifying GENERIC_WRITE. It makes the resulting handle
// less than useful, but that's the way it works. -JTP
break;
case TRUNCATE_EXISTING:
if (!(dwAccess & GENERIC_WRITE)) {
dwError = ERROR_ACCESS_DENIED;
goto exit;
}
flName |= NAME_TRUNCATE;
break;
case OPEN_ALWAYS:
flName |= NAME_CREATE;
// Fall into the OPEN_EXISTING case now...
case OPEN_EXISTING:
break;
default:
invalidParm:
dwError = ERROR_INVALID_PARAMETER;
goto exit;
}
// If the volume is locked such that only read access is currently allowed
// (eg, scan in progress), then deny all requests that could modify the volume's
// state. Note that if the call wouldn't have succeeded anyway (for example,
// the caller specified CREATE_NEW but the file already exists), that error
// will be masked by this error for the duration of the read-lock; but handling
// the lock this way is much safer/simpler, and few if any callers will even
// really care. -JTP
if ((pvol->v_flags & VOLF_READLOCKED) &&
((flName & (NAME_CREATE | NAME_TRUNCATE)) || (dwAccess & GENERIC_WRITE))) {
dwError = ERROR_ACCESS_DENIED;
goto exit;
}
mode = (BYTE)(ShareToMode(dwShareMode) | AccessToMode(dwAccess));
flName |= (BYTE)(dwFlagsAndAttributes) | (mode << NAME_MODE_SHIFT);
pstm = OpenName((PDSTREAM)pvol, lpFileName, 0, &flName);
if (!pstm) {
DEBUGONLY(dwError = GetLastError());
goto abort;
}
// Save the fact that we might have a successfull stream creation on a file that already exists.
// OpenName sets the error and we save off the fact that it did.
if (GetLastError() == ERROR_ALREADY_EXISTS) {
bExists = TRUE;
}
// OpenName will return the root stream IFF a special volume
// name was specified. Which means that if the stream is NOT the
// root, then this is NOT a volume handle.
if (pstm != pstm->s_pvol->v_pstmRoot) {
flName &= ~NAME_VOLUME;
if (!CheckStreamSharing(pstm, mode)) {
dwError = ERROR_SHARING_VIOLATION;
goto exit;
}
}
#ifdef DEMAND_PAGING_DEADLOCKS
// If the stream we've opened can currently be demand-paged,
// then we MUST temporarily release the stream's CS around these
// memory manager calls.
if (pstm->s_flags & STF_DEMANDPAGED)
LeaveCriticalSection(&pstm->s_cs);
#endif
pfh = LocalAlloc(LPTR, sizeof(FHANDLE));
if (pfh) {
if (!(hFile = FSDMGR_CreateFileHandle( pvol->v_hVol, hProc, (PFILE)pfh))) {
DEBUGFREE(sizeof(FHANDLE));
VERIFYNULL(LocalFree(pfh));
pfh = NULL;
}
}
if (!pfh)
dwError = ERROR_OUTOFMEMORY;
#ifdef DEMAND_PAGING_DEADLOCKS
if (pstm->s_flags & STF_DEMANDPAGED)
EnterCriticalSection(&pstm->s_cs);
#endif
if (dwError)
goto exit;
pfh->fh_h = hFile;
pfh->fh_hProc = hProc;
pfh->fh_flags |= FHF_FHANDLE;
pfh->fh_mode = mode;
pfh->fh_pstm = pstm;
AddItem((PDLINK)&pstm->s_dlOpenHandles, (PDLINK)&pfh->fh_dlOpenHandles);
if (dwFlagsAndAttributes & FILE_FLAG_WRITE_THROUGH)
pstm->s_flags |= STF_WRITETHRU;
if (flName & NAME_VOLUME)
{
pfh->fh_flags |= FHF_VOLUME;
}
else if (flName & NAME_CREATED)
{
FILESYSTEMNOTIFICATION(pvol, DB_CEOID_CREATED, 0, SHCNE_CREATE, &pstm->s_sid, &pstm->s_sidParent, NULL, NULL, NULL, DBGTEXTW("FAT_CreateFileW"));
}
else if (flName & NAME_TRUNCATE)
{
if (dwError = ResizeStream(pstm, 0, RESIZESTREAM_SHRINK|RESIZESTREAM_UPDATEFAT))
goto exit;
// On NT and Win95, when an existing file is truncated, the attributes are
// updated to match those passed to CreateFile (and yes, if no truncation was
// required, then the existing file's attributes are preserved, so this really
// is the right place to propagate attributes). Also note that we don't need to
// explicitly mark the stream dirty, because ResizeStream already did that.
//Need to force attributes to be updated on new/truncated file
pstm->s_flags |= STF_DIRTY;
pstm->s_attr = (BYTE)dwFlagsAndAttributes;
CommitStream(pstm, FALSE);
FILESYSTEMNOTIFICATION(pvol, DB_CEOID_CHANGED, 0, SHCNE_UPDATEITEM, &pstm->s_sid, &pstm->s_sidParent, NULL, NULL, NULL, DBGTEXTW("FAT_CreateFileW"));
}
LeaveCriticalSection(&pstm->s_cs);
exit:
if (dwError) {
// If we got as far as creating a file handle, then leave the
// stream's critical section and let FAT_CloseFile do all the cleanup
// when it gets called (via the CloseFileHandle macro, which calls CloseHandle).
// Otherwise, we just need to close the stream and return. CloseStream
// will take care of leaving the stream's critical section and freeing the
// stream if necessary.
if (pfh) {
LeaveCriticalSection(&pstm->s_cs);
pstm = NULL;
CloseFileHandle(pfh);
pfh = NULL;
}
if (pstm)
CloseStream(pstm);
SetLastError(dwError);
} else {
// On a succesfull creation on a file that already existed ..set the error
if (bExists)
SetLastError(ERROR_ALREADY_EXISTS);
}
abort:
FATExit(LOGID_CREATEFILE);
DEBUGMSGW(ZONE_APIS || ZONE_ERRORS && !pfh, (DBGTEXTW("FATFS!FAT_CreateFileW(%-.64s) returned 0x%x (%d)\n"), lpFileName, pfh, dwError));
return pfh? hFile : INVALID_HANDLE_VALUE;
}
BOOL FAT_CloseFile(PFHANDLE pfh)
{
PDSTREAM pstm;
if (!BufEnter(TRUE))
return FALSE;
DEBUGMSG(ZONE_APIS,(DBGTEXT("FATFS!FAT_CloseFile(0x%x)\n"), pfh));
pstm = pfh->fh_pstm;
ASSERT(pstm);
if (pfh->fh_flags & FHF_LOCKED)
UnlockVolume(pstm->s_pvol);
EnterCriticalSection(&pstm->s_cs);
RemoveItem((PDLINK)&pfh->fh_dlOpenHandles);
CloseStream(pstm);
DEBUGFREE(sizeof(FHANDLE));
VERIFYNULL(LocalFree(pfh));
DEBUGMSG(ZONE_APIS,(DBGTEXT("FATFS!FAT_CloseFile returned TRUE (0)\n")));
BufExit();
return TRUE;
}
DWORD FATFSReadFile(
PFHANDLE pfh,
LPVOID buffer,
DWORD nBytesToRead,
LPDWORD lpNumBytesRead,
LPOVERLAPPED lpOverlapped,
LPDWORD lpdwLowOffset,
LPDWORD lpdwHighOffset)
{
PDSTREAM pstm;
DWORD dwError;
pstm = pfh->fh_pstm;
ASSERT(pstm);
EnterCriticalSection(&pstm->s_cs);
__try {
*lpNumBytesRead = 0;
if (!(pfh->fh_mode & FH_MODE_READ) || (pfh->fh_flags & (FHF_VOLUME | FHF_UNMOUNTED)))
dwError = ERROR_ACCESS_DENIED;
else {
if (!lpdwLowOffset) {
dwError = ReadStreamData(pstm, pfh->fh_pos, buffer, nBytesToRead, lpNumBytesRead);
pfh->fh_pos += *lpNumBytesRead;
}
else {
dwError = ReadStreamData(pstm, *lpdwLowOffset, buffer, nBytesToRead, lpNumBytesRead);
}
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
dwError = ERROR_INVALID_PARAMETER;
}
LeaveCriticalSection(&pstm->s_cs);
return dwError;
}
DWORD FATFSWriteFile(
PFHANDLE pfh,
LPCVOID buffer,
DWORD nBytesToWrite,
LPDWORD lpNumBytesWritten,
LPOVERLAPPED lpOverlapped,
LPDWORD lpdwLowOffset,
LPDWORD lpdwHighOffset)
{
PDSTREAM pstm;
DWORD dwError;
pstm = pfh->fh_pstm;
ASSERT(pstm);
EnterCriticalSection(&pstm->s_cs);
__try {
*lpNumBytesWritten = 0;
if (!(pfh->fh_mode & FH_MODE_WRITE) || (pfh->fh_flags & (FHF_VOLUME | FHF_UNMOUNTED)))
dwError = ERROR_ACCESS_DENIED;
else {
if (!lpdwLowOffset) {
dwError = WriteStreamData(pstm, pfh->fh_pos, buffer, nBytesToWrite, lpNumBytesWritten, TRUE);
pfh->fh_pos += *lpNumBytesWritten;
}
else {
dwError = WriteStreamData(pstm, *lpdwLowOffset, buffer, nBytesToWrite, lpNumBytesWritten, TRUE);
}
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
dwError = ERROR_INVALID_PARAMETER;
}
LeaveCriticalSection(&pstm->s_cs);
return dwError;
}
#if NUM_FILE_APIS == 13
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -