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

📄 stream.c

📁 Windows操作系统中文件系统过滤驱动和设备驱动之间的相似
💻 C
📖 第 1 页 / 共 4 页
字号:
                break;
            }

            // posEnd advances, and clus becomes the new clusEnd

            posEnd += pvol->v_cbClus;

            if (clusEnd != UNKNOWN_CLUSTER)
                clusPrev = clusEnd;

            clusEnd = clus;

        } while (posEnd < cbNew);

        // If the stream has any new clusters at all...

        if (clusEnd != UNKNOWN_CLUSTER) {

            // If a PACK fails, we're having trouble writing to the FAT

            if (clus != UNKNOWN_CLUSTER) {
                if (PACK(pvol, clusEnd, EOF_CLUSTER, NULL) != ERROR_SUCCESS) {
                    DEBUGMSG(ZONE_ERRORS,(DBGTEXT("FATFS!ResizeStream: trouble terminating new FAT chain\r\n")));
                    clus = UNKNOWN_CLUSTER;
                }

                AppendRunList(&pstm->s_runList, posEnd, EOF_CLUSTER);
            }
            
            if (pstm->s_size != posEnd) {
                pstm->s_size = posEnd;
                pstm->s_flags |= STF_DIRTY;
            }

            // If we couldn't allocate all the clusters we needed,
            // then (try to) resize the stream to its original size.

            if (clus == UNKNOWN_CLUSTER) {
                DEBUGMSG(ZONE_ERRORS,(DBGTEXT("FATFS!ResizeStream: shrinking FAT chain back down...\r\n")));
                ResizeStream(pstm, oldSize, dwResizeFlags | RESIZESTREAM_SHRINK);
                dwError = ERROR_DISK_FULL;
            }
            else {

                // It's important that we record the cluster-granular
                // size for directories, because when CreateName grows a
                // directory, it uses this size to calculate how much data
                // has to be zeroed.  For all other streams, it's important
                // to record only the exact number of bytes requested.

                if (!(pstm->s_attr & ATTR_DIRECTORY)) {
                    pstm->s_size = cbNew;
                }

            }
        }

#ifdef TFAT
        // Need to update the parent dir in all cases for a file and only if the 
        // first cluster changed for a directory.
        if (pvol->v_fTfat && (!(pstm->s_attr & ATTR_DIRECTORY) || bFirstClusChanged))
            UpdateDirEntryCluster(pstm);
#endif

        // Commit and release FAT buffers now

        if (dwResizeFlags & RESIZESTREAM_UPDATEFAT) {
            
            BOOL fTempWriteThru = FALSE;            

            // If stream is write-through, but FAT stream is not, temporarily make it so that the 
            // modified FAT buffers will be write-through.            
            if ((pstm->s_flags & STF_WRITETHRU) && !(pvol->v_pstmFAT->s_flags & STF_WRITETHRU)) {
                 fTempWriteThru = TRUE;
                 pvol->v_pstmFAT->s_flags |= STF_WRITETHRU;
            }
            
            WriteAndReleaseStreamBuffers(pvol->v_pstmFAT);
            
            if (fTempWriteThru)
                pvol->v_pstmFAT->s_flags &= ~STF_WRITETHRU;
        }

        UnlockFAT(pvol);

        DEBUGMSG(ZONE_STREAMS || ZONE_ERRORS && dwError,(DBGTEXT("FATFS!ResizeStream(GROW) returned %d for '%.11hs'\r\n"), dwError, pstm->s_achOEM));
        return dwError;
    }

    // If shrinking was not enabled, then we're done

    if (!(dwResizeFlags & RESIZESTREAM_SHRINK))
        return ERROR_SUCCESS;

    // We enter the FAT's critical section even though we're just freeing
    // clusters, because in the process, we could alter the FAT stream's
    // current buffer, and that could mess up someone else accessing the FAT.

    LockFAT(pvol);

    // If clusEnd is NO_CLUSTER, then all the file's clusters can be freed;
    // set pstm->s_clusFirst to UNKNOWN_CLUSTER, which will get propagated
    // as ZERO to the DIRENTRY when the stream is committed (CommitStream will
    // eventually do that, because we also set STF_DIRTY, below).

    if (clusEnd == NO_CLUSTER) {

        // clusEnd becomes the first cluster to free.

        
        if (pstm->s_clusFirst != UNKNOWN_CLUSTER)
            pstm->s_flags |= STF_DIRTY_CLUS;

        clusEnd = pstm->s_clusFirst;
        pstm->s_clusFirst = UNKNOWN_CLUSTER;
        bFirstClusChanged = TRUE;
    }
    else {
        dwError = PACK(pvol, clusEnd, EOF_CLUSTER, &clusEnd);
    }

    // Update the stream's new size
    pstm->s_size = cbNew;
    pstm->s_flags |= STF_DIRTY;
    
    // Now free all the remaining clusters in the chain.

#ifdef TFAT    
    // TFAT - don't delete the cluster, freeze it instead
    if (pstm->s_pvol->v_fTfat) {
        DWORD clusFirst = NO_CLUSTER, clusNext = clusEnd;

        // Get the last cluster in the chain
        while (!dwError && clusNext >= DATA_CLUSTER && !ISEOF(pvol, clusNext))
        {
            if (NO_CLUSTER == clusFirst)
                clusFirst = clusEnd;
            
            clusEnd = clusNext;
            
            // get next cluster
            dwError = UNPACK( pvol, clusNext, &clusNext );
        }

        if (NO_CLUSTER != clusFirst)
            FreezeClusters (pvol, clusFirst, clusEnd);
        
        // Need to update the parent dir in all cases for a file and only if the 
        // first cluster changed for a directory.
        if (!(pstm->s_attr & ATTR_DIRECTORY) || bFirstClusChanged)       
            UpdateDirEntryCluster(pstm);
    }
    else 

#endif
    {
        while (!dwError && clusEnd >= DATA_CLUSTER && !ISEOF(pvol, clusEnd)) {
            FreeClustersOnDisk(pvol, clusEnd, 1);
            dwError = PACK(pvol, clusEnd, FREE_CLUSTER, &clusEnd);
        }

    }

    // Commit and release FAT buffers now.

    if (dwResizeFlags & RESIZESTREAM_UPDATEFAT)
        WriteAndReleaseStreamBuffers(pvol->v_pstmFAT);


    // We need to update the stream's run info

    dwError = TruncateRunList (&pstm->s_runList, cbNew);
    if (dwError == ERROR_SUCCESS) {
        DWORD dwEndPosition = (cbNew + pvol->v_cbClus - 1) & ~(pvol->v_cbClus - 1);  
        dwError = AppendRunList(&pstm->s_runList, dwEndPosition, EOF_CLUSTER);
    }

    UnlockFAT(pvol);
    
    DEBUGMSG(ZONE_STREAMS || ZONE_ERRORS && dwError,(DBGTEXT("FATFS!ResizeStream(SHRINK) returned %d for '%.11hs'\r\n"), dwError, pstm->s_achOEM));
    return dwError;
}


/*  CheckStreamHandles - Check for stream with open handles
 *
 *  ENTRY
 *      pvol - pointer to VOLUME
 *      psid - pointer to SID, or NULL to check all streams for open handles
 *
 *  EXIT
 *      TRUE if stream exists and has open handles, FALSE if not
 *
 *  NOTES
 *      This check excludes VOLUME-based handles, because it excludes VOLUME-
 *      based streams (ie, the FAT and root directory).
 */

BOOL CheckStreamHandles(PVOLUME pvol, PDSID psid)
{
    PDSTREAM pstm;
    BOOL fOpen = FALSE;

    EnterCriticalSection(&pvol->v_csStms);

    for (pstm = pvol->v_dlOpenStreams.pstmNext; pstm != (PDSTREAM)&pvol->v_dlOpenStreams; pstm = pstm->s_dlOpenStreams.pstmNext) {

        if (pstm->s_flags & STF_VOLUME)
            continue;

        if (psid == NULL || pstm->s_sid.sid_clusDir == psid->sid_clusDir && pstm->s_sid.sid_ordDir == psid->sid_ordDir) {
            fOpen = (pstm->s_dlOpenHandles.pfhNext != (PFHANDLE)&pstm->s_dlOpenHandles);
            if (psid || fOpen)
                break;
        }
    }
    LeaveCriticalSection(&pvol->v_csStms);
    return fOpen;
}


/*  UpdateSourceStream - Updates source stream after a MoveFile
 *
 *  ENTRY
 *      pvol - pointer to VOLUME
 *      psidSrc - pointer to SID of the source stream
 *      pdiDst - pointer to DIRINFO of destination file
 *      pstmDstParent - pointer to stream of parent directory of destination file
 *
 *  EXIT
 *      None
 *
 *  NOTES
 *      This is necessary in case there are open file handles that point to the
 *      source stream.
 */

VOID UpdateSourceStream (PVOLUME pvol, PDSID psidSrc, PDIRINFO pdiDst, PDSTREAM pstmDstParent)
{
    // Search through any open handles that carry the source stream
    // and update the stream to point to the destination
    PDSTREAM pstmSrc;

    EnterCriticalSection(&pvol->v_csStms);


    // Search for a stream that matches stream ID of source
    for (pstmSrc = pvol->v_dlOpenStreams.pstmNext; pstmSrc != (PDSTREAM)&pvol->v_dlOpenStreams;
       pstmSrc = pstmSrc->s_dlOpenStreams.pstmNext) {
        
        if (pstmSrc->s_sid.sid_clusDir == psidSrc->sid_clusDir && pstmSrc->s_sid.sid_ordDir == psidSrc->sid_ordDir) 
            break;
    }

    pstmSrc->s_refs++;
    LeaveCriticalSection(&pvol->v_csStms);

    // If we found a match, update stream's info so it refers to the destination file now
    if (pstmSrc != (PDSTREAM)&pvol->v_dlOpenStreams) {
        EnterCriticalSection (&pstmSrc->s_cs);

        memcpy(pstmSrc->s_achOEM, pdiDst->di_pde->de_name, sizeof(pdiDst->di_pde->de_name));
        pstmSrc->s_sid = pdiDst->di_sid;
        pstmSrc->s_sidParent = pstmDstParent->s_sid;
        pstmSrc->s_cwPath = pdiDst->di_cwName + pstmDstParent->s_cwPath + 1;

        if ((pstmDstParent->s_pbufCur) && !(pstmSrc->s_attr & ATTR_DIRECTORY)) {
            pstmSrc->s_blkDir = pstmDstParent->s_pbufCur->b_blk;
            pstmSrc->s_offDir = (PBYTE)pdiDst->di_pde - pstmDstParent->s_pbufCur->b_pdata;
        }

#ifdef TFAT
        // Update the parent stream, if needed
        if (pstmSrc->s_pvol->v_fTfat && pstmSrc->s_pstmParent && pstmSrc->s_pstmParent != pstmDstParent) {

            // Remove reference to the previous parent
            ASSERT(pstmSrc->s_pstmParent->s_refs);
            if(1 == pstmSrc->s_pstmParent->s_refs){
                EnterCriticalSection(&pstmSrc->s_pstmParent->s_cs);
                CloseStream(pstmSrc->s_pstmParent);
            } else{
                --pstmSrc->s_pstmParent->s_refs;
            }

            // Add reference to the new parent
            pstmSrc->s_pstmParent = pstmDstParent;
            pstmDstParent->s_refs++;
        }
#endif

        LeaveCriticalSection (&pstmSrc->s_cs);
    }

    pstmSrc->s_refs--;

}


/*  StreamOpenedForExclAccess - Check if file is already open for exclusive access
 *
 *  ENTRY
 *      pvol - pointer to VOLUME
 *
 *  EXIT
 *      TRUE if file is already open for exclusive access, FALSE if not
 *
 *  NOTES
 *      This check excludes VOLUME-based handles, because it excludes VOLUME-
 *      based streams (ie, the FAT and root directory).
 */

BOOL StreamOpenedForExclAccess(PVOLUME pvol, PDSID psid)
{
    PDSTREAM pstm;
    PFHANDLE pfh, pfhEnd;
    BOOL fOpenedForExclAccess = FALSE;

    ASSERT(psid);

    EnterCriticalSection(&pvol->v_csStms);

    for (pstm = pvol->v_dlOpenStreams.pstmNext; 
           !fOpenedForExclAccess && pstm != (PDSTREAM)&pvol->v_dlOpenStreams;
           pstm = pstm->s_dlOpenStreams.pstmNext) {

        if (pstm->s_sid.sid_clusDir == psid->sid_clusDir && pstm->s_sid.sid_ordDir == psid->sid_ordDir) {

            // Walk the handle list. Return TRUE if any are opened for exclusive access.
            for(pfh = pstm->s_dlOpenHandles.pfhNext, pfhEnd = (PFHANDLE)&pstm->s_dlOpenHandles;
                  pfh != pfhEnd; pfh = pfh->fh_dlOpenHandles.pfhNext) {
                
                if ( (!(pfh->fh_mode & FH_MODE_SHARE_READ) || (pfh->fh_mode & FH_MODE_WRITE)) && 
                       !(pfh->fh_mode & FH_MODE_SHARE_WRITE)) {
                    fOpenedForExclAccess = TRUE;
                    break;
                }
            }
        }
    }
    LeaveCriticalSection(&pvol->v_csStms);
    return fOpenedForExclAccess;
}

/*  CheckStreamSharing - Check requested mode against stream
 *
 *  ENTRY
 *      pstm - pointer to DSTREAM
 *      mode - requested mode
 *
 *  EXIT
 *      TRUE if all handles for stream permit the specified mode, FALSE if not
 */

BOOL CheckStreamSharing(PDSTREAM pstm, int mode, BOOL fTruncate)
{
    BYTE bRequiredShare = 0;
    BYTE bExcludedAccess = 0;
    PFHANDLE pfh, pfhEnd;

    ASSERT(pstm);
    ASSERT(OWNCRITICALSECTION(&pstm->s_cs));

    // If user wants to open a file for read and/or write, all
    // open handles must have been opened for read sharing and/or 
    // write sharing respectively. Also, if user wants to truncate,
    // other handles must have write sharing.
    
    if (mode & FH_MODE_READ)
        bRequiredShare |= FH_MODE_SHARE_READ;

    if (fTruncate || (mode & FH_MODE_WRITE))
        bRequiredShare |= FH_MODE_SHARE_WRITE;

    // If user disallows a file for read sharing and/or write 
    // sharing, open handles cannot have been opened for read and/or 
    // write respectively

    if (!(mode & FH_MODE_SHARE_READ))
        bExcludedAccess |= FH_MODE_READ;

    if (!(mode & FH_MODE_SHARE_WRITE))
        bExcludedAccess |= FH_MODE_WRITE;

    pfh = pstm->s_dlOpenHandles.pfhNext;
    pfhEnd = (PFHANDLE)&pstm->s_dlOpenHandles;

    while (pfh != pfhEnd) {
        if ((pfh->fh_mode & bRequiredShare) != bRequiredShare)
            return FALSE;
        if (pfh->fh_mode & bExcludedAccess)
            return FALSE;        
        pfh = pfh->fh_dlOpenHandles.pfhNext;
    }
    return TRUE;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -