📄 fsdapis.cpp
字号:
//
// 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:
fsdapis.cpp
Abstract:
This file contains the FSDMGR entry points for all supported file
system APIs.
--*/
#define KEEP_SYSCALLS // for kernel.h only
#define NO_DEFINE_KCALL // for kernel.h only
#include "fsdmgrp.h"
#include "fsnotify.h"
#include "storemain.h"
#include "cdioctl.h"
#ifdef UNDER_CE
#include "fsioctl.h"
#endif
inline BOOL IsValidVolume(PVOL pVol)
{
PREFAST_ASSERT(OWNCRITICALSECTION(&csFSD));
// walk the global vol list to verify pVol has not been deregistered
PVOL pVolNext = dlVOLList.pVolNext;
while (pVolNext != (PVOL)&dlVOLList) {
if (pVol == pVolNext) {
return TRUE;
}
pVolNext = pVolNext->dlVol.pVolNext;
}
return FALSE;
}
void inline MarkVolume( PVOL pVol, DWORD dwFlags)
{
LockFSDMgr();
__try {
if (IsValidVolume(pVol)) {
pVol->dwFlags |= dwFlags;
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
ASSERT(0);
}
UnlockFSDMgr();
}
void inline UnmarkVolume( PVOL pVol, DWORD dwFlags)
{
LockFSDMgr();
__try {
if (IsValidVolume(pVol)) {
pVol->dwFlags &= ~dwFlags;
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
ASSERT(0);
}
UnlockFSDMgr();
}
void inline WaitForVolume(PVOL pVol)
{
DWORD dwDelay = 0;
extern DWORD g_dwWaitIODelay;
LockFSDMgr();
__try {
if (IsValidVolume(pVol) && !(VOL_DEINIT & pVol->dwFlags)) {
ASSERT(VALIDSIG(pVol, VOL_SIG));
// if the volume is currently unavailable, stall
if (VOL_UNAVAILABLE & pVol->dwFlags) {
dwDelay = g_dwWaitIODelay;
DEBUGMSG(ZONE_POWER, (TEXT("FSDMGR!WaitForVolume: blocking file i/o for %u ms on unavailable volume %s\r\n"), dwDelay, pVol->wsVol));
}
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
ASSERT(0);
}
UnlockFSDMgr();
if (dwDelay) {
// stall in case the device could come back online
Sleep(dwDelay);
}
}
void inline WaitForHandle(PHDL pHdl)
{
DWORD dwDelay = 0;
extern DWORD g_dwWaitIODelay;
LockFSDMgr();
__try {
if (!(pHdl->dwFlags & HDL_INVALID) && pHdl->pVol) {
ASSERT(VALIDSIG(pHdl->pVol, VOL_SIG));
// if the volume is currently unavailable, stall
if (VOL_UNAVAILABLE & pHdl->pVol->dwFlags) {
dwDelay = g_dwWaitIODelay;
DEBUGMSG(ZONE_POWER, (TEXT("FSDMGR!WaitForHandle: blocking file i/o for %u ms on unavailable volume %s\r\n"), dwDelay, pHdl->pVol->wsVol));
}
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
ASSERT(0);
}
UnlockFSDMgr();
if (dwDelay) {
// stall in case the device could come back online
Sleep(dwDelay);
}
}
/* TryEnterVolume - Tracks threads entering an FSD volume API
*
* ENTRY
* pVol -> VOL structure
*
* EXIT
* Returns TRUE if the volume can be entered, FALSE if the volume
* is not available.
*
* NOTES
* We track threads on a per-volume basis so that we will block
* volume deinitialization until all threads have stopped accessing
* the volume.
*/
BOOL TryEnterVolume(PVOL pVol)
{
BOOL bRet = FALSE;
HANDLE hActivityEvent = NULL;
LockFSDMgr();
__try {
// check to see that the volume is available
if (IsValidVolume(pVol) &&
!(pVol->dwFlags & VOL_UNAVAILABLE) &&
!(pVol->dwFlags & VOL_DEINIT)) {
ASSERT(VALIDSIG(pVol, VOL_SIG));
hActivityEvent = pVol->pDsk->hActivityEvent;
// indicate that a new thread has entered the volume
pVol->cThreads++;
bRet = TRUE;
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
ASSERT(0);
}
UnlockFSDMgr();
if (hActivityEvent) {
// Set the Activity timer every time a volume is entered
// so that Power Manager will know this device is being used
SetEvent(hActivityEvent);
}
if (!bRet) {
// Indicate to the caller that the device is not available
SetLastError(ERROR_DEVICE_NOT_AVAILABLE);
}
return bRet;
}
/* TryEnterHandle - Tracks threads entering an FSD handle API
*
* ENTRY
* pHdl -> PHDL structure
*
* EXIT
* Returns TRUE if the volume can be entered and the handle is
* valid, FALSE if the volume is not available.
*
* NOTES
* We track threads on a per-volume basis so that we will block
* volume deinitialization until all threads have stopped accessing
* the volume.
*/
BOOL TryEnterHandle(PHDL pHdl)
{
BOOL bRet = FALSE;
HANDLE hActivityEvent = NULL;
LockFSDMgr();
__try {
// check to see that the handle is valid and the volume is available
if (!(pHdl->dwFlags & HDL_INVALID)
// we don't need to call IsValidVolume here because it will have
// been set to NULL (and the handle will have been flagged INVALID)
// during cleanup if the volume went away
&& pHdl->pVol
&& !(pHdl->pVol->dwFlags & VOL_UNAVAILABLE)
&& !(pHdl->pVol->dwFlags & VOL_DEINIT)) {
ASSERT(VALIDSIG(pHdl->pVol, VOL_SIG));
hActivityEvent = pHdl->pVol->pDsk->hActivityEvent;
// indicate that a new thread has entered the volume
pHdl->pVol->cThreads++;
bRet = TRUE;
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
ASSERT(0);
}
UnlockFSDMgr();
if (bRet && hActivityEvent) {
// set the Activity timer every time a volume is entered
// so that Power Manager will know this device is being used
SetEvent(hActivityEvent);
}
if (!bRet) {
// Indicate to the caller that the device is not available
SetLastError(ERROR_DEVICE_NOT_AVAILABLE);
}
return bRet;
}
/* ExitVolume - Tracks threads leaving an FSD (and can signal when the last one leaves)
*
* ENTRY
* pVol -> VOL structure
*
* EXIT
* None
*
* NOTES
* See TryEnterVolume for notes.
*/
void ExitVolume(PVOL pVol)
{
ASSERT(VALIDSIG(pVol, VOL_SIG));
LockFSDMgr();
__try {
pVol->cThreads--;
if ((VOL_DEINIT & pVol->dwFlags) && (pVol->cThreads == 0)) {
// this is the last thread leaving a de-allocated volume, so signal
// the final thread exit event so that volume cleanup will complete
ASSERT(pVol->hThreadExitEvent != NULL);
SetEvent(pVol->hThreadExitEvent);
}
} __except(EXCEPTION_EXECUTE_HANDLER) {
ASSERT(0);
}
UnlockFSDMgr();
}
/* ExitHandle - Tracks threads leaving an FSD handle call
*
* ENTRY
* pHdl -> PHDL structure
*
* EXIT
* None
*
* NOTES
* See TryEnterHandle for notes.
*/
inline void ExitHandle(PHDL pHdl)
{
// just exit the volume, there is no special exit code for handles
return ExitVolume(pHdl->pVol);
}
#ifdef UNDER_CE
BOOL MapSgBuffers(PSG_REQ pSgReq ,DWORD InBufLen)
{
if (pSgReq && InBufLen >= (sizeof(SG_REQ) + sizeof(SG_BUF) * (pSgReq->sr_num_sg - 1))) {
DWORD dwIndex;
for (dwIndex=0; dwIndex < pSgReq -> sr_num_sg; dwIndex++) {
pSgReq->sr_sglist[dwIndex].sb_buf =
(PUCHAR)MapCallerPtr((LPVOID)pSgReq->sr_sglist[dwIndex].sb_buf,pSgReq->sr_sglist[dwIndex].sb_len);
}
}
else // Parameter Wrong.
return FALSE;
return TRUE;
}
BOOL MapSgBuffers(PCDROM_READ pCdrom ,DWORD InBufLen)
{
if (pCdrom && InBufLen >= (sizeof(CDROM_READ) + sizeof(SGX_BUF) * (pCdrom->sgcount - 1))) {
DWORD dwIndex;
for (dwIndex=0; dwIndex < pCdrom-> sgcount; dwIndex++) {
pCdrom->sglist[dwIndex].sb_buf =
(PUCHAR)MapCallerPtr((LPVOID)pCdrom->sglist[dwIndex].sb_buf,pCdrom->sglist[dwIndex].sb_len);
}
}
else // Parameter Wrong.
return FALSE;
return TRUE;
}
#else
// NT stub
BOOL MapSgBuffers(PSG_REQ pSgReq ,DWORD InBufLen)
{
return TRUE;
}
// NT stub
BOOL MapSgBuffers(PCDROM_READ pCdrom ,DWORD InBufLen)
{
return TRUE;
}
#endif // UNDER_CE
BOOL ReadWriteFileSg (DWORD dwIoControlCode, PHDL pHdl, FILE_SEGMENT_ELEMENT aSegmentArray[], DWORD nNumberOfBytes, LPDWORD lpReserved, LPOVERLAPPED lpOverlapped)
{
PFSD pFSD = pHdl->pVol->pDsk->pFSD;
BOOL bRet = FALSE;
if (!aSegmentArray) {
SetLastError (ERROR_INVALID_PARAMETER);
return FALSE;
}
if ((dwIoControlCode == IOCTL_FILE_READ_SCATTER && !pFSD->pReadFileScatter) ||
(dwIoControlCode == IOCTL_FILE_WRITE_GATHER && !pFSD->pWriteFileGather))
{
SetLastError(ERROR_NOT_SUPPORTED);
return FALSE;
}
SYSTEM_INFO SystemInfo;
GetSystemInfo (&SystemInfo);
DWORD dwNumPages = nNumberOfBytes / SystemInfo.dwPageSize;
#ifdef UNDER_CE
aSegmentArray = (FILE_SEGMENT_ELEMENT*)MapCallerPtr (aSegmentArray, SystemInfo.dwPageSize);
if (aSegmentArray) {
for (DWORD i = 0; i < dwNumPages; i++) {
aSegmentArray[i].Buffer = MapCallerPtr (aSegmentArray[i].Buffer, SystemInfo.dwPageSize);
}
}
lpReserved = (LPDWORD)MapCallerPtr (lpReserved, SystemInfo.dwPageSize);
#endif
if (dwIoControlCode == IOCTL_FILE_READ_SCATTER) {
__try {
bRet = pFSD->pReadFileScatter(pHdl->dwHdlData, aSegmentArray, nNumberOfBytes, lpReserved, lpOverlapped);
} __except(ReportFault(GetExceptionInformation(), 0), EXCEPTION_EXECUTE_HANDLER) {
bRet = FALSE;
}
} else {
__try {
bRet = pFSD->pWriteFileGather(pHdl->dwHdlData, aSegmentArray, nNumberOfBytes, lpReserved, lpOverlapped);
} __except(ReportFault(GetExceptionInformation(), 0), EXCEPTION_EXECUTE_HANDLER) {
bRet = FALSE;
}
}
return bRet;
}
/* FSDMGR_CloseVolume - Called when a volume is being deregistered
*
* ENTRY
* pVol -> VOL structure
*
* EXIT
* Always returns TRUE (that's what OUR stub always does, and it's
* expected that that's what FSDs will do too, if they even care to hook
* this entry point).
*/
BOOL FSDMGR_CloseVolume(PVOL pVol)
{
// FSD_CloseVolume export is called from DeinitEx()
return TRUE;
}
/* FSDMGR_CreateDirectoryW - Create a new subdirectory
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -