?? 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;
DWORD dwSHCNE = 0;
DEBUGMSGW(ZONE_APIS,(DBGTEXTW("FATFS!FAT_CreateFileW(%d chars: %s)\r\n"), wcslen(lpFileName), lpFileName));
if (!FATEnter(pvol, LOGID_CREATEFILE)) {
DEBUGMSG(ZONE_APIS || ZONE_ERRORS,(DBGTEXT("FATFS!FAT_CreateFileW bailing...\r\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, flName & NAME_TRUNCATE)) {
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 = (PFHANDLE)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, sizeof(FHANDLE));
if (pfh) {
if (!(hFile = FSDMGR_CreateFileHandle( pvol->v_hVol, hProc, (PFILE)pfh))) {
DEBUGFREE(sizeof(FHANDLE));
VERIFYTRUE(HeapFree(hHeap, 0, 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) || (pvol->v_flFATFS & FATFS_FORCE_WRITETHROUGH))
pstm->s_flags |= STF_WRITETHRU;
#ifdef TFAT
if (pstm->s_pstmParent)
LeaveCriticalSection(&pstm->s_cs);
#endif
if (flName & NAME_VOLUME)
{
pfh->fh_flags |= FHF_VOLUME;
}
else if (flName & NAME_CREATED)
{
dwSHCNE = SHCNE_CREATE;
}
else if (flName & NAME_TRUNCATE)
{
#ifdef TFAT
// TFAT, now that we plan to shrink the file, we may clone the dir
// so enter the parent CS first before re-entering its own CS
if(pstm->s_pstmParent) {
EnterCriticalSection(&pstm->s_pstmParent->s_cs);
EnterCriticalSection(&pstm->s_cs);
}
#endif
if (dwError = ResizeStream(pstm, 0, RESIZESTREAM_SHRINK|RESIZESTREAM_UPDATEFAT))
{
#ifdef TFAT
// pstm->s_cs will be left on exit
if(pstm->s_pstmParent)
LeaveCriticalSection(&pstm->s_pstmParent->s_cs);
#endif
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);
#ifdef TFAT
if (pvol->v_fTfat && (STF_WRITETHRU & pstm->s_flags))
{
// stream modified, commit transations if in write-through mode
dwError = CommitTransactions (pstm->s_pvol);
}
#endif
dwSHCNE = SHCNE_UPDATEITEM;
#ifdef TFAT
if(pstm->s_pstmParent) {
LeaveCriticalSection(&pstm->s_cs);
LeaveCriticalSection(&pstm->s_pstmParent->s_cs);
}
#endif
}
#ifdef TFAT
if (!pstm->s_pstmParent)
#endif
LeaveCriticalSection(&pstm->s_cs);
// Don't send notification for special file handles (like VOL:)
if (dwSHCNE && pstm->s_sid.sid_clusDir)
FILESYSTEMNOTIFICATION(pvol, DB_CEOID_CHANGED, 0, dwSHCNE, &pstm->s_sid, &pstm->s_sidParent, NULL, NULL, NULL, DBGTEXTW("FAT_CreateFileW"));
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(pvol, LOGID_CREATEFILE);
DEBUGMSGW(ZONE_APIS || ZONE_ERRORS && !pfh, (DBGTEXTW("FATFS!FAT_CreateFileW(%-.64s) returned 0x%x (%d)\r\n"), lpFileName, pfh, dwError));
return pfh? hFile : INVALID_HANDLE_VALUE;
}
BOOL FAT_CloseFile(PFHANDLE pfh)
{
DWORD dwReturn = ERROR_SUCCESS;
DWORD dwError = ERROR_SUCCESS;
PDSTREAM pstm;
PVOLUME pvol;
#ifdef TFAT_TIMING_TEST
DWORD dwTickCnt=GetTickCount();
#endif
DSID sid, sidParent;
#ifdef TFAT
PDSTREAM pstmParent;
#endif
pstm = pfh->fh_pstm;
ASSERT(pstm);
pvol = pstm->s_pvol;
ASSERT(pvol);
if (!BufEnter(pvol, TRUE))
return FALSE;
DEBUGMSG(ZONE_APIS,(DBGTEXT("FATFS!FAT_CloseFile(0x%x, %.11hs: %d)\r\n"), pfh, pfh->fh_pstm->s_achOEM, pfh->fh_pstm->s_clusFirst));
if (pfh->fh_flags & FHF_LOCKED)
UnlockVolume(pvol);
#ifdef TFAT
// TFAT, if it was open for write, we may need to clone the parent dir
pstmParent = pstm->s_pstmParent;
if(pvol->v_fTfat && pstmParent && (pfh->fh_mode & FH_MODE_WRITE))
{
EnterCriticalSection(&pvol->v_csStms);
pstmParent->s_refs++; // prevent the parent stream to be closed
LeaveCriticalSection(&pvol->v_csStms);
EnterCriticalSection(&pstmParent->s_cs);
}
#endif
EnterCriticalSection(&pstm->s_cs);
// unlock locks owned by this handle
if (!(pfh->fh_flags & (FHF_VOLUME | FHF_UNMOUNTED))) {
FSDMGR_RemoveFileLockEx(AcquireFileLockState, ReleaseFileLockState, (DWORD)pfh);
}
RemoveItem((PDLINK)&pfh->fh_dlOpenHandles);
#ifndef TFAT
dwError = CommitBufferSet( (PDSTREAM)pvol, -1);
// If we get an error, attempt to continue the rest of the close process
if (dwError != ERROR_SUCCESS)
dwReturn = dwError;
#endif
memcpy (&sid, &pstm->s_sid, sizeof(DSID));
memcpy (&sidParent, &pstm->s_sidParent, sizeof(DSID));
dwError = CloseStream(pstm);
if (dwError != ERROR_SUCCESS)
dwReturn = dwError;
#ifdef TFAT
if(pvol->v_fTfat && pstmParent && (pfh->fh_mode & FH_MODE_WRITE))
{
dwError = CloseStream(pstmParent);
if (dwError != ERROR_SUCCESS)
dwReturn = dwError;
}
// Sync FAT only if a file was opened for write
if (pvol->v_fTfat && (pfh->fh_mode & FH_MODE_WRITE))
{
#ifdef TFAT_TIMING_TEST
RETAILMSG(1, (L"FAT_CloseFile takes %ld\r\n", GetTickCount()-dwTickCnt));
#endif
dwError = CommitTransactions (pvol);
}
else
dwError = CommitBufferSet( (PDSTREAM)pvol, -1);
#endif
if (dwError != ERROR_SUCCESS)
dwReturn = dwError;
// Don't send notification for special file handles (like VOL:)
if (sid.sid_clusDir && (pfh->fh_mode & FH_MODE_WRITE))
FILESYSTEMNOTIFICATION(pvol, DB_CEOID_CHANGED, 0, SHCNE_UPDATEITEM, &sid, &sidParent, NULL, NULL, NULL, DBGTEXTW("CloseFile"));
DEBUGFREE(sizeof(FHANDLE));
VERIFYTRUE(HeapFree(hHeap, 0, pfh));
BufExit(pvol);
if (dwReturn != ERROR_SUCCESS)
{
DEBUGMSG(ZONE_APIS,(DBGTEXT("FATFS!FAT_CloseFile returned FALSE (%d)\r\n"), dwReturn));
SetLastError (dwReturn);
}
else
{
DEBUGMSG(ZONE_APIS,(DBGTEXT("FATFS!FAT_CloseFile returned TRUE (0)\r\n")));
}
return (dwReturn == ERROR_SUCCESS);
}
DWORD FATFSReadFile(
PFHANDLE pfh,
LPVOID buffer,
DWORD nBytesToRead,
LPDWORD lpNumBytesRead,
LPOVERLAPPED lpOverlapped,
LPDWORD lpdwLowOffset,
LPDWORD lpdwHighOffset)
{
PDSTREAM pstm;
DWORD dwError = ERROR_GEN_FAILURE;
DWORD cbRead = 0;
pstm = pfh->fh_pstm;
ASSERT(pstm);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -