⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 path.c

📁 Windows操作系统中文件系统过滤驱动和设备驱动之间的相似
💻 C
📖 第 1 页 / 共 4 页
字号:
    // 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 + -