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

📄 stream.c

📁 Windows操作系统中文件系统过滤驱动和设备驱动之间的相似
💻 C
📖 第 1 页 / 共 4 页
字号:
                // I need to switch back to non-local time to perform the
                // necessary comparison.

                DEBUGMSG(ZONE_STREAMS && ZONE_LOGIO,(DBGTEXT("FATFS!CommitStream: current (truncated) local system time: y=%d,m=%d,d=%d,h=%d,m=%d,s=%d\r\n"), stTmp.wYear, stTmp.wMonth, stTmp.wDay, stTmp.wHour, stTmp.wMinute, stTmp.wSecond));
                SystemTimeToFileTime(&stTmp, &ftTmp1);

                DEBUGMSG(ZONE_STREAMS && ZONE_LOGIO,(DBGTEXT("FATFS!CommitStream: current (truncated) local file time: %08x,%08x\r\n"), ftTmp1.dwLowDateTime, ftTmp1.dwHighDateTime));
                LocalFileTimeToFileTime(&ftTmp1, &ftTmp2);

                DEBUGMSG(ZONE_STREAMS && ZONE_LOGIO,(DBGTEXT("FATFS!CommitStream: current (truncated) file time: %08x,%08x\r\n"), ftTmp2.dwLowDateTime, ftTmp2.dwHighDateTime));
                if (pstm->s_ftAccess.dwLowDateTime != ftTmp2.dwLowDateTime ||
                    pstm->s_ftAccess.dwHighDateTime != ftTmp2.dwHighDateTime) {

                    pstm->s_ftAccess = ftTmp2;
                    pstm->s_flags |= STF_ACCESS_TIME | STF_DIRTY_INFO;
                }
            }

            if (pstm->s_flags & STF_DIRTY) {

                PBUF pbuf = NULL;

                // We don't specify a stream for FindBuffer, because we're
                // not trying to find a buffer for THIS stream, but rather its
                // directory's stream.

                // Also note this means we need to call CommitBuffer and UnholdBuffer
                // when we're done (instead of the usual ModifyStreamBuffer).

                if (pstm->s_blkDir == INVALID_BLOCK) {
                    DEBUGMSGBREAK(TRUE,(DBGTEXT("FATFS!CommitStream: invalid blkDir!\r\n")));
                    dwError = ERROR_INVALID_BLOCK;
                }
                else
#ifdef TFAT
                    if (!pstm->s_pvol->v_fTfat)
#endif        
                        dwError = FindBuffer(pstm->s_pvol, pstm->s_blkDir, NULL, FALSE, &pbuf);

                if (dwError == ERROR_SUCCESS) 
                {
                    PDIRENTRY pde;
                    DWORD     clusFirst;
                
#ifdef TFAT
                    if (pstm->s_pvol->v_fTfat) {                       
                        DWORD     blkDir;

                        LockFAT (pstm->s_pvol);

                        blkDir = pstm->s_blkDir;
                        ASSERT(pstm->s_offDir<pstm->s_pvol->v_cbClus);
                        
                        // A dir cluster is being modified, lets clone it first
                        CloneDirCluster(pstm->s_pvol, pstm->s_pstmParent, blkDir, &blkDir);

                        if (!(dwError = FindBuffer(pstm->s_pvol, blkDir, NULL, FALSE, &pbuf)))
                        {
                            pde = (PDIRENTRY)(pbuf->b_pdata + pstm->s_offDir);
                            dwError = ModifyBuffer(pbuf, pde, sizeof(DIRENTRY));
                        }

                        UnlockFAT (pstm->s_pvol);                       
                    }
                    else 
#endif
                    {
                        pde = (PDIRENTRY)(pbuf->b_pdata + pstm->s_offDir);
                        dwError = ModifyBuffer(pbuf, pde, sizeof(DIRENTRY));               
                    }

                    if (!dwError) {

                        pstm->s_attr |= ATTR_ARCHIVE;
                        pde->de_attr = pstm->s_attr;

                        pde->de_size = pstm->s_size;

                        clusFirst = pstm->s_clusFirst;
                        if (clusFirst == UNKNOWN_CLUSTER)
                            clusFirst = NO_CLUSTER;
                        SETDIRENTRYCLUSTER(pstm->s_pvol, pde, clusFirst);

                        if (pstm->s_flags & STF_CREATE_TIME) {
                            FileTimeToDOSTime(&pstm->s_ftCreate,
                                            &pde->de_createdDate,
                                            &pde->de_createdTime,
                                            &pde->de_createdTimeMsec);
                            pstm->s_flags &= ~STF_CREATE_TIME;
                        }

                        // A dirty data stream always gets a new write time, unless
                        // STF_WRITE_TIME is set, in which case someone has already set a
                        // specific write time.

                        if ((pstm->s_flags & (STF_DIRTY_DATA | STF_WRITE_TIME)) == STF_DIRTY_DATA) {

                            // We could simply call GetSystemTimeAsFileTime,
                            // with s_ftWrite as the destination, but if both
                            // last access and last write times are being updated,
                            // I prefer to insure that both times are identical.

                            FILETIME ftTmp;
                            SystemTimeToFileTime(&stLocal, &ftTmp);
                            LocalFileTimeToFileTime(&ftTmp, &pstm->s_ftWrite);
                            pstm->s_flags |= STF_WRITE_TIME;
                        }

                        if (pstm->s_flags & STF_WRITE_TIME) {
                            FileTimeToDOSTime(&pstm->s_ftWrite,
                                            &pde->de_date,
                                            &pde->de_time, NULL);
                            pstm->s_flags &= ~STF_WRITE_TIME;
                        }

                        if (pstm->s_flags & STF_ACCESS_TIME) {
                            FileTimeToDOSTime(&pstm->s_ftAccess,
                                            &pde->de_lastAccessDate, NULL, NULL);
                            pstm->s_flags &= ~STF_ACCESS_TIME;
                        }

                        if (fAll) {

                            BOOL fTempWriteThru = FALSE;            

                            // If stream is write-through, but directory stream is not, temporarily make it so that the 
                            // modified directory buffers will be write-through.            
                            if (pbuf->b_pstm && (pstm->s_flags & STF_WRITETHRU) && !(pbuf->b_pstm->s_flags & STF_WRITETHRU)) {
                                 fTempWriteThru = TRUE;
                                 pbuf->b_pstm->s_flags |= STF_WRITETHRU;
                            }
                            
                            dwError = CommitBuffer(pbuf, FALSE);
                            
                            if (fTempWriteThru && pbuf->b_pstm)
                                pbuf->b_pstm->s_flags &= ~STF_WRITETHRU;
                        }
                    }
                    // TEST_BREAK
                    PWR_BREAK_NOTIFY(41);

                    // Unhold the buffer that FindBuffer held for us.
                    // If FindBuffer failed, pbuf will be NULL.
                    if (pbuf) {
                        UnholdBuffer(pbuf);
                    }

#if 0
                    if (!dwError)
                        FILESYSTEMNOTIFICATION(pstm->s_pvol, DB_CEOID_CHANGED, 0, SHCNE_UPDATEITEM, &pstm->s_sid, &pstm->s_sidParent, NULL, NULL, NULL, DBGTEXTW("CommitStream"));
#endif                  

                    // Even if the buffer couldn't be written, the dirt has still
                    // moved from the stream's data structure to the buffer

                    pstm->s_flags &= ~(STF_DIRTY | STF_DIRTY_CLUS);
                }

                // If there was some error getting a buffer however, note that the
                // stream remains dirty.
            }
        }
    }
    else {

        // CommitAndReleaseStreamBuffers would have insured the release for us,
        // but since we can't do a commit, we'll have to insure the release ourselves.

        ReleaseStreamBuffer(pstm, FALSE);
        dwError = !(pstm->s_flags & STF_DIRTY)? ERROR_SUCCESS : ERROR_ACCESS_DENIED;
    }

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


/*  RewindStream
 *
 *  ENTRY
 *      pstm - pointer to DSTREAM
 *      pos - position within DSTREAM to rewind to, or INVALID_POS to reinitialize
 *
 *  EXIT
 *      None
 */

void RewindStream(PDSTREAM pstm, DWORD pos)
{
    if (pstm->s_clusFirst >= DATA_CLUSTER) {
        ResetRunList (&pstm->s_runList, pstm->s_clusFirst);
    }
}


/*  SeekStream
 *
 *  ENTRY
 *      pstm - pointer to DSTREAM
 *      pos - position within DSTREAM to seek to
 *
 *  EXIT
 *      0 if successful, error code if not
 *      (eg, ERROR_HANDLE_EOF if end of cluster chain reached)
 */
//判断pos是否在流pstm的run的有效范围内,实在所有的run内进行判断,而不仅仅是在当前run内进行判断
DWORD SeekStream(PDSTREAM pstm, DWORD pos)
{
    DWORD dwError;
    ASSERT(OWNCRITICALSECTION(&pstm->s_cs));

    if ((pos == INVALID_POS) || (pos < pstm->s_runList.r_StartPosition)) {
        RewindStream(pstm, pos);
    }

    // Locate the data run which contains the position requested.

    do {        

        if (pos < pstm->s_runList.r_EndPosition)
            return ERROR_SUCCESS;
        //如果pos不在pstm-->s_runlist的有效范围,则以当前run的最后一个cluster进行挂载
        DEBUGMSG(ZONE_LOGIO && (pstm->s_flags & STF_DEMANDPAGED),(DBGTEXT("FATFS!SeekStream(DP): begin unpack\r\n")));
        dwError = UnpackRun(pstm);
        DEBUGMSG(ZONE_LOGIO && (pstm->s_flags & STF_DEMANDPAGED),(DBGTEXT("FATFS!SeekStream(DP): end unpack\r\n")));

        if (dwError)
            break;

    } while (TRUE);

    return dwError;
}


/*  PositionStream - Find cluster containing (or preceding) specified position
 *
 *  ENTRY
 *      pstm - pointer to DSTREAM
 *      pos - offset within stream to seek to
 *
 *  EXIT
 *      There are three general cases that callers are concerned about:
 *
 *          UNKNOWN_CLUSTER:    the specified position does not lie
 *                              within a cluster (ie, is beyond EOF)
 *
 *          NO_CLUSTER:         the specified position does not require a
 *                              cluster (in other words, pos is ZERO)
 *
 *          Valid cluster:      return the cluster CONTAINING pos.
 */

DWORD PositionStream(PDSTREAM pstm, DWORD pos, PDWORD pdwClus)
{
    DWORD dwError = ERROR_SUCCESS;

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

    if (!pdwClus) {
        return ERROR_INVALID_DATA;
    }
    
    dwError = SeekStream (pstm, pos);
    
    if (dwError != ERROR_SUCCESS) {
        *pdwClus = UNKNOWN_CLUSTER;
    }
    else {
        dwError = GetClusterAtPosition(&pstm->s_runList, pos, pdwClus);
    }
    
    // TEST_BREAK
    PWR_BREAK_NOTIFY(42);
    
    return dwError;
}


/*  ReadStream
 *
 *  Returns a pointer (to a buffer) containing data from the requested
 *  stream position, and the amount of data available in the buffer.  ppvEnd
 *  is optional as long as the caller knows that the size and alignment of
 *  its data is such that all the data will be buffered;  directory streams
 *  are an example of this:  as long as the caller calls ReadStream before
 *  examining each DIRENTRY record, the caller can be assured that the entire
 *  DIRENTRY is in the buffer (that would not, however, be a particularly
 *  efficient way to scan a directory stream. -JTP)
 *
 *  ENTRY
 *      pstm - pointer to DSTREAM
 *      pos - position within DSTREAM to read from
 *      ppvStart - pointer to pointer to receive starting address of data
 *      ppvEnd - pointer to pointer to receive ending address of data
 *
 *  EXIT
 *      0 if successful, error code if not (eg, error reading the disk, or
 *      ERROR_HANDLE_EOF if the end of the stream has been reached).
 */

DWORD ReadStream(PDSTREAM pstm, DWORD pos, PVOID *ppvStart, PVOID *ppvEnd)
{
    DWORD dwError;

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

    dwError = SeekStream(pstm, pos);

    if (!dwError)
        dwError = ReadStreamBuffer(pstm, pos, 0, ppvStart, ppvEnd);

    return dwError;
}


/*  ReadStreamData
 *
 *  Whereas ReadStream returns a pointer (to a buffer) and a length,
 *  and then the caller reads whatever data it wants up to that length,
 *  this function takes a memory address and a length and simply reads
 *  that many bytes directly into that address, avoiding the use of
 *  disk buffers whenever possible.
 *
 *  Thus, unlike ReadStream, where the caller can never get more than a
 *  buffer's worth of data back at a time and probably needs to put a loop
 *  around its ReadStream call, ReadStreamData can read any amount of data
 *  with one call (no external loop).
 *
 *  ENTRY
 *      pstm - pointer to DSTREAM
 *      pos - position within DSTREAM to read from
 *      pvData - pointer to memory to read to
 *      len - length of data to read
 *      plenRead - pointer to DWORD for length read (optional)
 *
 *  EXIT
 *      0 if successful, error code if not (eg, error reading the disk)
 *
 *  NOTES
 *      To avoid using buffers
 */

DWORD ReadStreamData(PDSTREAM pstm, DWORD pos, PVOID pvData, DWORD len, PDWORD plenRead)
{
    DWORD cb;
    PBYTE pbStart, pbEnd;
    DWORD dwError = ERROR_SUCCESS;

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

    // Use cb to temporarily hold the maximum number of bytes that
    // can be read, and then adjust the length of the read downward as needed.

    cb = pos > pstm->s_size? 0 : pstm->s_size - pos;
    if (len > cb)
        len = cb;

    while (len) {

        // If we can lock a range of blocks outside the buffer pool,
        // in order to read their contents directly from disk to memory
        // instead of through the pool, do so.

        DWORD blk, cblk;

        if (dwError = SeekStream(pstm, pos))
            break;

        DEBUGMSG(ZONE_LOGIO && (pstm->s_flags & STF_DEMANDPAGED),(DBGTEXT("FATFS!ReadStreamData(DP): begin lockblocks for '%.11hs'\r\n"), pstm->s_achOEM));
        if (LockBlocks(pstm, pos, len, &blk, &cblk, FALSE)) {

            __try {
                DEBUGMSG(ZONE_LOGIO && (pstm->s_flags & STF_DEMANDPAGED),(DBGTEXT("FATFS!ReadStreamData(DP): begin readvolume\r\n")));
                dwError = ReadVolume(pstm->s_pvol, blk, cblk, pvData);
                DEBUGMSG(ZONE_LOGIO && (pstm->s_flags & STF_DEMANDPAGED),(DBGTEXT("FATFS!ReadStreamData(DP): end readvolume\r\n")));
                if (!dwError) {
                    cb = cblk << pstm->s_pvol->v_log2cbBlk;
                    (PBYTE)pvData += cb;
                    if (plenRead)
                        *plenRead += cb;
                }
            }
            __except (EXCEPTION_EXECUTE_HANDLER) {
                dwError = ERROR_INVALID_PARAMETER;
            }

            UnlockBlocks(pstm, blk, cblk, FALSE);
            if (dwError)
                break;
        }
        else {

            DEBUGMSG(ZONE_LOGIO && (pstm->s_flags & STF_DEMANDPAGED),(DBGTEXT("FATFS!ReadStreamData(DP): begin readstream\r\n")));
            dwError = ReadStream(pstm, pos, &pbStart, &pbEnd);
            DEBUGMSG(ZONE_LOGIO && (pstm->s_flags & STF_DEMANDPAGED),(DBGTEXT("FATFS!ReadStreamData(DP): begin readstream\r\n")));
            if (dwError)
                break;

            cb = pbEnd - pbStart;
            if (cb > len)
                cb = len;

⌨️ 快捷键说明

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