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

📄 stream.c

📁 WinCE5.0部分核心源码
💻 C
📖 第 1 页 / 共 5 页
字号:
                }

                len -= cb;
                pos += cb;

                // Once we get this far at least once through the loop,
                // we need to make sure the stream data is flagged as dirty.

                pstm->s_flags |= STF_DIRTY;
                pstm->s_flags &= ~STF_WRITE_TIME;

                // Furthermore, if we just wrote beyond the "official"
                // size of the stream, then update the "official" size

                if (pos > pstm->s_size) {
                    pstm->s_size = pos;
                    fSizeChanged = TRUE;
                }

                // This is where all successful WriteStreamData calls
                // end up (except when len is ZERO to begin with, of course).

                if (len == 0)
                    goto exit;
            }

            dwError = UnpackRun(pstm);
            if ((dwError == ERROR_INVALID_DATA) || ((dwUnpackError ==  ERROR_HANDLE_EOF) && (dwError == ERROR_HANDLE_EOF))){
                if (dwRetries++ == MAX_UNPACK_RETRIES) {
                    dwError = ERROR_DISK_FULL;
                    goto exit;
                }    
             }    
            dwUnpackError = dwError;

        } while (dwUnpackError == ERROR_SUCCESS);

        // We've run out of cluster runs, and we still have len bytes
        // to write at pos.  Resize the stream to encompass that boundary
        // and try to continue.
        
    } while ((dwError = ResizeStream(pstm, pos + len, RESIZESTREAM_SHRINK|RESIZESTREAM_UPDATEFAT)) == ERROR_SUCCESS);

    DEBUGMSG(ZONE_ERRORS,(DBGTEXT("FATFS!WriteStreamData failed (%d)\r\n"), dwError));

  exit:
    if (fCommit) {

        DWORD dw;

        
        if (pstm->s_flags & STF_DIRTY_CLUS) {
            dw = CommitStream(pstm, FALSE);
            if (!dwError)
                dwError = dw;
        }
#ifdef TFAT
        else if (pstm->s_pvol->v_fTfat && (pstm->s_pvol->v_flFATFS & FATFS_TRANS_DATA) && !(pstm->s_attr & ATTR_DIRECTORY) && fSizeChanged) {
            // Update the directory entry with the new size if we changed the file size
            // without calling ResizeStream (didn't need a new cluster).
            UpdateDirEntryCluster(pstm);
        }
#endif

        dw = ReleaseStreamBuffer(pstm, FALSE);
        if (!dwError)
            dwError = dw;
    }

#ifdef TFAT
    if (pstm->s_pvol->v_fTfat && (pstm->s_pvol->v_flFATFS & FATFS_TRANS_DATA)) {
        UnlockFAT (pstm->s_pvol);
    }
#endif

    return dwError;
}


/*  ResizeStream - truncate or extend a stream
 *
 *  ENTRY
 *      pstm - pointer to DSTREAM
 *      cbNew - new size of stream
 *      dwResizeFlags - zero or more RESIZESTREAM flags;  RESIZESTREAM_SHRINK
 *      forces shrinking (instead of simply insuring that the stream is at least
 *      as large as cbNew), and RESIZESTREAM_UPDATEFAT requests that changes to 
 *      the FAT be written.
 *
 *  EXIT
 *      ERROR_SUCCESS (0) if successful, non-zero if not
 *
 *      Truncating streams should only fail due to "hard" error conditions
 *      (eg, write-protected media), whereas extending a stream can also fail
 *      due to "soft" error conditions (eg, disk is full, or non-cluster-mapped
 *      stream -- like the root directory -- is full).
 */

DWORD ResizeStream (PDSTREAM pstm, DWORD cbNew, DWORD dwResizeFlags)
{
    PVOLUME pvol;
    DWORD dwError = ERROR_SUCCESS;
    DWORD posEnd, clus, clusEnd, clusPrev;
    DWORD clusRun, clusRunEnd, cclusRun, cbRun;
    BOOL bFirstClusChanged = FALSE;

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

    DEBUGMSG(ZONE_STREAMS,(DBGTEXT("FATFS!ResizeStream: changing size from 0x%x to 0x%x for '%.11hs'\r\n"), pstm->s_size, cbNew, pstm->s_achOEM));

    // Early exit if stream size already matches desired size.

    if (pstm->s_size == cbNew)
        return ERROR_SUCCESS;

    
    
    if (pstm->s_clusFirst < DATA_CLUSTER)
        return cbNew <= pstm->s_run.r_end? ERROR_SUCCESS : ERROR_DISK_FULL;

    pvol = pstm->s_pvol;

    if (pvol->v_flags & VOLF_READONLY)
        return ERROR_WRITE_PROTECT;

    dwError = PositionStream(pstm, cbNew, &clusEnd);
    if (dwError) {
        ASSERT (0);  // Something wrong with cluster chain or FAT
        return dwError;
    }

    // If clusEnd is UNKNOWN_CLUSTER, then the new size was past EOF, so
    // we need to add clusters until we have enough to reach the specified size.

    if (clusEnd == UNKNOWN_CLUSTER) {

        // pstm->s_run.r_clusThis should contain the first cluster of the
        // last run in a file's cluster chain.  pstm->s_run.r_end is the
        // position immediately past the last cluster (which we store in posEnd).

        posEnd = pstm->s_run.r_end;

        // Assert that the reason we're here is that the stream is not
        // large enough.

        ASSERT(posEnd < cbNew);

        // The RUN only remembers a starting cluster (r_clusThis) and a
        // length (pstm->s_run.r_end - pstm->s_run.r_start), which we must
        // convert into an ending cluster (clusEnd).  If clusEnd is
        // UNKNOWN_CLUSTER, then the stream currently contains no clusters!

        clusEnd = pstm->s_run.r_clusThis;

        if (clusEnd != UNKNOWN_CLUSTER) {
            ASSERT(pstm->s_run.r_clusThis != 0);
            ASSERT(pstm->s_run.r_end > pstm->s_run.r_start);

            clusEnd = pstm->s_run.r_clusThis +
                      ((pstm->s_run.r_end - pstm->s_run.r_start-1) >>
                       (pvol->v_log2cblkClus + pvol->v_log2cbBlk));
        }

        LockFAT(pvol);

        cclusRun = cbRun = 0;
        clusRunEnd = UNKNOWN_CLUSTER;
        clusPrev = clusRun = NO_CLUSTER;

        // If we have the number of free clusters cached, then let's calculate
        // the minimum number of clusters we'll need, and if there are not enough
        // free clusters to satisfy the request, then force an error.

        if (pvol->v_cclusFree != UNKNOWN_CLUSTER) {
            if (pvol->v_cclusFree == 0 || pvol->v_cclusFree < (cbNew - posEnd + pvol->v_cbClus - 1) / pvol->v_cbClus)
                dwError = ERROR_DISK_FULL;
        }

        do {
            if (dwError) {
                DEBUGMSG(ZONE_ERRORS,(DBGTEXT("FATFS!ResizeStream: ran out of free clusters\r\n")));
                clus = UNKNOWN_CLUSTER;
                break;
            }

            dwError = NewCluster(pvol, clusEnd, &clus);
            if (dwError == ERROR_SUCCESS && clus == UNKNOWN_CLUSTER)
                dwError = ERROR_DISK_FULL;
            if (dwError != ERROR_SUCCESS) {
                DEBUGMSG(ZONE_ERRORS,(DBGTEXT("FATFS!ResizeStream: cannot allocate new cluster (%d)\r\n"), dwError));
                break;          // can't allocate any more clusters
            }

            DEBUGMSG(ZONE_STREAMS,(DBGTEXT("FATFS!ResizeStream: new cluster for %.11hs returned %d'\r\n"), pstm->s_achOEM, clus));        

            // Link clus onto the end of the stream's cluster chain.  If
            // the previous end was UNKNOWN_CLUSTER, then record clus in the
            // stream's clusFirst field;  otherwise, link clus onto clusEnd.

            if (clusEnd == UNKNOWN_CLUSTER) {
                pstm->s_clusFirst = clus;
                pstm->s_flags |= STF_DIRTY | STF_DIRTY_CLUS;
                bFirstClusChanged = TRUE;
            }
            else {

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

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

            // posEnd advances, and clus becomes the new clusEnd

            posEnd += pvol->v_cbClus;

            // Remember the first new cluster we allocate, and keep
            // track of the extent to which the new cluster(s) form a run.

            if (clusRunEnd == UNKNOWN_CLUSTER) {

                if (clusRun == NO_CLUSTER)
                    clusRun = clus;

                if (clusRun + cclusRun == clus) {
                    cclusRun++;
                    cbRun += pvol->v_cbClus;
                }
                else
                    clusRunEnd = clus;          // end of the RUN
            }

            if (clusEnd != UNKNOWN_CLUSTER)
                clusPrev = clusEnd;

            clusEnd = clus;

        } while (posEnd < cbNew);

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

#ifdef TFAT
        if (!dwError && clusEnd != UNKNOWN_CLUSTER) {
#else
        if (clusEnd != UNKNOWN_CLUSTER) {
#endif

            // 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;
                }
            }

            // 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, pstm->s_run.r_end, 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))
                    posEnd = cbNew;

                // If there's no net change in size, don't dirty the stream.

                ASSERT(pstm->s_size != posEnd); 
                if (pstm->s_size != posEnd) {
                    pstm->s_size = posEnd;
                    pstm->s_flags |= STF_DIRTY;
                }

                // We need to update the stream's RUN info;  the easiest
                // way to do this is call RewindStream, but that can be quite
                // expensive later, in terms of unnecessary calls to UnpackRun.

                pstm->s_run.r_start = pstm->s_run.r_end;
                pstm->s_run.r_end = pstm->s_run.r_end + cbRun;
                pstm->s_run.r_blk = CLUSTERTOBLOCK(pvol, clusRun);
                pstm->s_run.r_clusPrev = pstm->s_run.r_clusThis;
                if (pstm->s_run.r_clusPrev == UNKNOWN_CLUSTER)
                    pstm->s_run.r_clusPrev = NO_CLUSTER;
                pstm->s_run.r_clusThis = clusRun;
                pstm->s_run.r_clusNext = clusRunEnd;
            }
        }

#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 

⌨️ 快捷键说明

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