📄 path.c
字号:
// and then got an error creating the destination) in that rare case
// where we have to recreate the source. See "that rare case" below.
memcpy(shSrc.sh_awcPattern, fd.cFileName, sizeof(shSrc.sh_awcPattern));
// Because the second FindFirst (below) could operate on the same
// stream that the first FindFirst (above) just operated on, and because
// we don't want to lose the first FindFirst's current buffer, we record
// what that buffer is and apply our own hold to it.
pbufSrc = pstmSrc->s_pbufCur;
HoldBuffer(pbufSrc);
// If the source is a directory, don't allow the destination path to
// contain the source stream's cluster.
if (bAttrSrc & ATTR_DIRECTORY)
clusFail = diSrc.di_clusEntry;
shDst.sh_flags = SHF_BYNAME | SHF_CREATE;
pstmDst = FindFirst(pvol, pwsNewFileName, &shDst, &diDst, &fd, NAME_FILE | NAME_DIR, clusFail);
if (!pstmDst) {
dwError = GetLastError();
goto exit2;
}
if (pvol->v_cwsHostRoot+pstmDst->s_cwPath+shDst.sh_cwPattern+2 > MAX_PATH) {
dwError = ERROR_FILENAME_EXCED_RANGE;
goto exit2;
}
// Good, both directory streams exist, and we already know that the file
// DOES exist in the source. Confirm it does NOT exist in the destination.
if (fd.dwFileAttributes != INVALID_ATTR) {
// There is one case where the destination is allowed to exist,
// and that is when the destination DIRENTRY is the same as the source,
// but the original names are NOT the same, implying that the caller simply
// wants to change some portion of the *case* of the (long) filename.
if (diSrc.di_sid.sid_clusDir == diDst.di_sid.sid_clusDir &&
diSrc.di_sid.sid_ordDir == diDst.di_sid.sid_ordDir &&
memcmp(fd.cFileName, shDst.sh_awcPattern, (shDst.sh_cwPattern+1)*sizeof(WCHAR)) != 0) {
// Since the destination exists, we shall destroy the source and search
// again. We copy the source DIRENTRY first, so that CreateName will still
// have a valid DIRENTRY to clone, and then we zap diSrc.di_clusEntry so that
// DestroyName doesn't try to decommit the file's clusters (if any).
deClone = *diSrc.di_pde;
pdeClone = &deClone;
diSrc.di_clusEntry = UNKNOWN_CLUSTER;
if (dwError = DestroyName(pstmSrc, &diSrc))
goto exit1;
// We know that FindNext should fail now, but we still need to call
// again so that it will fill diDst with the latest available DIRENTRY
// information (which CreateName needs to do its job).
shDst.sh_pos = 0;
shDst.sh_flags = SHF_BYNAME | SHF_CREATE;
if ((dwError = FindNext(&shDst, &diDst, &fd)) != ERROR_FILE_NOT_FOUND)
goto exit1;
}
else {
dwError = ERROR_ALREADY_EXISTS;
goto exit1;
}
}
else {
pdeClone = diSrc.di_pde;
SetLastError(0);
}
// Good, the new name does NOT (or no longer) exists in the destination,
// so we can now attempt to create it.
#ifdef TFAT
// For TFAT, lock the FAT so that a SyncFATs operation cannot be done
// by another thread in between the CreateName of the dst and the
// DestroyName of the src.
if (pvol->v_fTfat)
LockFAT (pvol);
#endif
if (dwError = CreateName(pstmDst, shDst.sh_awcPattern, &diDst, pdeClone, bAttrSrc)) {
// If we had to delete the original name to make way for the new
// name, then we must try to recreate the original. Whatever error
// occurs is irrelevant (and hopefully, NO error will occur, or the
// user is going to be upset with us -JTP).
if (pdeClone == &deClone) {
// Cross your fingers and handle "that rare case" now...
shSrc.sh_pos = 0;
shSrc.sh_flags = SHF_BYNAME | SHF_CREATE;
if (FindNext(&shSrc, &diSrc, &fd) == ERROR_FILE_NOT_FOUND)
CreateName(pstmSrc, shSrc.sh_awcPattern, &diSrc, pdeClone, bAttrSrc);
}
#ifdef TFAT
if (pvol->v_fTfat)
UnlockFAT (pvol);
#endif
goto exit1;
}
// TEST_BREAK
PWR_BREAK_NOTIFY(32);
// If the source still exists (ie, if pdeClone is still pointing
// to the original source DIRENTRY), then it is time to destroy it.
if (pdeClone == diSrc.di_pde) {
// Hold the destination's current buffer in case there's an error
// on the DestroyName (we want to guarantee we can clean up).
PBUF pbufDst = pstmDst->s_pbufCur;
HoldBuffer(pbufDst);
// Before we can operate on the source again, we need to make sure
// its current buffer is still assigned (ie, held). If FindFirst
// for the destination had to walk THROUGH the source stream, the
// source's current buffer could have become unheld, or it might be
// holding a different buffer now (that can happen when both source
// and destination streams are the SAME).
ReleaseStreamBuffer(pstmSrc, FALSE);
AssignStreamBuffer(pstmSrc, pbufSrc, FALSE);
// Ready to destroy the old name (if we haven't already destroyed it).
// Zap clusEntry so it doesn't try to decommit the file's clusters too.
diSrc.di_clusEntry = UNKNOWN_CLUSTER;
if (dwError = DestroyName(pstmSrc, &diSrc)) {
// An error occurred. Destroy the new name, taking care to zap
// clusEntry so it doesn't try to decommit the file's clusters too.
// We deliberately ignore any error destroying the new name, because
// we're already in an error recovery path.
ReleaseStreamBuffer(pstmDst, FALSE);
AssignStreamBuffer(pstmDst, pbufDst, FALSE);
diDst.di_clusEntry = UNKNOWN_CLUSTER;
DestroyName(pstmDst, &diDst);
}
UnholdBuffer(pbufDst);
}
#ifdef TFAT
if (pvol->v_fTfat)
UnlockFAT (pvol);
#endif
// If a DIRENTRY for a directory moved to a different stream,
// then we have to fix up the ".." entry inside that directory too.
if (!dwError && (bAttrSrc & ATTR_DIR_MASK) == ATTR_DIRECTORY) {
PDSTREAM pstm;
DWORD dwFlags = OPENSTREAM_REFRESH;
#ifdef PATH_CACHING
PathCacheInvalidate(pvol, pwsOldFileName);
#endif
ASSERT(diDst.di_clusEntry != UNKNOWN_CLUSTER &&
diDst.di_clusEntry != FAT_PSEUDO_CLUSTER &&
diDst.di_clusEntry != ROOT_PSEUDO_CLUSTER);
// If the directory that was just moved has an open stream,
// then update its parent information
UpdateSourceStream (pvol, &diSrc.di_sid, &diDst, pstmDst);
// We always open the directory stream now, to refresh the stream
// if it's currently open (or cached), and to create it if we also
// need to change the ".." entry (ie, if the directory moved). That's
// why we check the condition (pstmSrc != pstmDst) *after* calling
// OpenStream instead of *before*. It may look inefficient, but there's
// an intentional side-effect.
if (pstmSrc != pstmDst)
dwFlags |= OPENSTREAM_CREATE;
if (pstm = OpenStream(pstmDst->s_pvol,
diDst.di_clusEntry,
&diDst.di_sid,
pstmDst, &diDst, dwFlags)) {
if (pstmSrc != pstmDst) {
PDIRENTRY pde;
#ifdef TFAT
if (pvol->v_fTfat)
DEBUGMSG (TRUE, (TEXT("FATFSD!FAT_MoveFileW: Moving folder to a different location is not transaction safe!!\r\n")));
#endif
if (ReadStream(pstm, sizeof(DIRENTRY), &pde, NULL) == ERROR_SUCCESS) {
DWORD dw = ModifyStreamBuffer(pstm, pde, sizeof(DIRENTRY));
if (!dw) {
DWORD clusFirst = (ISROOTDIR(pstmDst)? NO_CLUSTER : pstmDst->s_clusFirst);
SETDIRENTRYCLUSTER(pstmDst->s_pvol, pde, clusFirst);
// TEST_BREAK
PWR_BREAK_NOTIFY(33);
}
}
}
CloseStream(pstm);
}
}
if (!(bAttrSrc & ATTR_DIR_MASK)) {
shDst.sh_pos = 0;
shDst.sh_flags = SHF_BYNAME | SHF_CREATE;
dwError = FindNext(&shDst, &diDst, &fd);
UpdateSourceStream (pvol, &diSrc.di_sid, &diDst, pstmDst);
}
memcpy (&sidDstParent, &pstmDst->s_sid, sizeof(DSID));
memcpy (&sidSrcParent, &pstmSrc->s_sid, sizeof(DSID));
exit1:
CloseStream(pstmDst);
exit2:
UnholdBuffer(pbufSrc);
exit3:
CloseStream(pstmSrc);
CloseRoot(pvol);
if (dwError) {
error:
SetLastError(dwError);
}
else {
FILESYSTEMNOTIFICATION(pvol,
DB_CEOID_CREATED,
bAttrSrc & ATTR_DIRECTORY? DB_CEOID_DIRECTORY_DELETED : DB_CEOID_FILE_DELETED,
bAttrSrc & ATTR_DIRECTORY? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM,
&diDst.di_sid,
&sidDstParent,
&diSrc.di_sid,
&sidSrcParent,
&oiOld,
DBGTEXTW("FAT_MoveFileW"));
#ifdef TFAT
if (pvol->v_fTfat)
dwError = CommitTransactions (pvol);
#endif
}
FATExit(pvol, LOGID_MOVEFILE);
DEBUGMSGW(ZONE_APIS || ZONE_ERRORS && dwError,(DBGTEXTW("FATFS!FAT_MoveFileW(%s->%s) returned 0x%x (%d)\r\n"), pwsOldFileName, pwsNewFileName, dwError == ERROR_SUCCESS, dwError));
return dwError == ERROR_SUCCESS;
}
BOOL FAT_RegisterFileSystemNotification(PVOLUME pvol, HWND hwnd)
{
DEBUGMSG(ZONE_APIS,(DBGTEXT("FATFS!FAT_RegisterFileSystemNotification(0x%x)\r\n"), hwnd));
#ifdef SHELL_MESSAGE_NOTIFICATION
hwndShellNotify = hwnd;
return TRUE;
#else
return FALSE;
#endif
}
BOOL FAT_RegisterFileSystemFunction(PVOLUME pvol, SHELLFILECHANGEFUNC_t pfn)
{
DEBUGMSG(ZONE_APIS,(DBGTEXT("FATFS!FAT_RegisterFileSystemFunction(0x%x)\r\n"), pfn));
#ifdef SHELL_CALLBACK_NOTIFICATION
pfnShell = pfn;
return TRUE;
#else
return FALSE;
#endif
}
/* FAT_OidGetInfo - Get file information by OID
*
* ENTRY
* pvol - pointer to VOLUME
* oid - OID of interest
* poi - pointer to OID information to return
*
* EXIT
* TRUE if successful, FALSE if not (call GetLastError for error code)
*/
BOOL FAT_OidGetInfo(PVOLUME pvol, CEOID oid, CEOIDINFO *poi)
{
DWORD dwError = ERROR_INVALID_FUNCTION;
DEBUGMSG(ZONE_APIS,(DBGTEXT("FATFS!FAT_OidGetInfo(0x%x)\r\n"), oid));
if (!FATEnter(NULL, LOGID_NONE))
return FALSE;
#ifndef DISABLE_OIDS
if (pvol->v_flags & (VOLF_INVALID | VOLF_UNMOUNTED | VOLF_FROZEN | VOLF_WRITELOCKED))
dwError = ERROR_ACCESS_DENIED;
else if (AFSFROMOID(oid) != (DWORD)(int)pvol->v_volID)
dwError = ERROR_INVALID_PARAMETER;
else {
DSID sid;
SETSIDFROMOID(&sid, oid);
dwError = GetSIDInfo(pvol, &sid, poi);
}
if (!dwError) {
FATExit(pvol, LOGID_NONE);
DEBUGMSGW(ZONE_APIS,(DBGTEXTW("FATFS!FAT_OidGetInfo returned TRUE (0x%x,0x%x,0x%x,%d chars: %s)\r\n"), poi->wObjType, poi->infFile.dwAttributes, poi->infFile.oidParent, wcslen(poi->infFile.szFileName), poi->infFile.szFileName));
return TRUE;
}
#endif
SetLastError(dwError);
FATExit(pvol, LOGID_NONE);
DEBUGMSG(ZONE_APIS || ZONE_ERRORS,(DBGTEXT("FATFS!FAT_OidGetInfo(0x%x) returned FALSE (%d)\r\n"), oid, dwError));
return FALSE;
}
BOOL FAT_PrestoChangoFileName(PVOLUME pvol, PCWSTR pwsOldFile, PCWSTR pwsNewFile)
{
BOOL fSuccess;
DEBUGMSGW(ZONE_APIS,(DBGTEXTW("FATFS!FAT_PrestoChangoFileName(%s<-%s)\r\n"), pwsOldFile, pwsNewFile));
if (pvol->v_flags & (VOLF_INVALID | VOLF_UNMOUNTED | VOLF_FROZEN | VOLF_LOCKED)) {
SetLastError(ERROR_ACCESS_DENIED);
fSuccess = FALSE;
}
else {
if (fSuccess = FAT_DeleteFileW(pvol, pwsOldFile))
fSuccess = FAT_MoveFileW(pvol, pwsNewFile, pwsOldFile);
}
DEBUGMSG(ZONE_APIS || ZONE_ERRORS && !fSuccess,(DBGTEXT("FATFS!FAT_PrestoChangoFileName returned 0x%x (%d)\r\n"), fSuccess, fSuccess? 0 : GetLastError()));
return fSuccess;
}
BOOL CalculateFreeClustersInRAM(PVOLUME pvol)
{
LPBYTE pFATBuffer = NULL;
LPBYTE pCurEntry = NULL;
DWORD dwClus;
DWORD dwFATSize = pvol->v_csecFAT << pvol->v_log2cbSec;
BOOL fFAT16 = ((pvol->v_flags & VOLF_16BIT_FAT) != 0);
DWORD cbFATEntry;
DWORD dwBufferSize;
DWORD dwSectorsRead = 0;
BOOL fRet = FALSE;
// Don't do this for FAT12 because the FAT is small anyway.
if (pvol->v_flags & VOLF_12BIT_FAT) {
return FALSE;
}
// Check for overflow of dwFATSize
if ((0xffffffff >> pvol->v_log2cbSec) < pvol->v_csecFAT) {
return FALSE;
}
cbFATEntry = (fFAT16) ? sizeof(WORD) : sizeof(DWORD);
// Check for invalid FAT size
if (dwFATSize / cbFATEntry < pvol->v_clusMax) {
ASSERT(0);
return FALSE;
}
// 获取单个fat表和1m的最小值
dwBufferSize = min (dwFATSize, MAX_FREE_SPACE_CHUNK_SIZE);
pFATBuffer = (LPBYTE)VirtualAlloc (NULL, dwBufferSize, MEM_COMMIT, PAGE_READWRITE);
if (!pFATBuffer) {
goto exit;
}
// Ensure that the free list size is a multiple of a DWORD
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -