?? stream.c
字號:
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'\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\n")));
dwError = ReadVolume(pstm->s_pvol, blk, cblk, pvData);
DEBUGMSG(ZONE_LOGIO && (pstm->s_flags & STF_DEMANDPAGED),(DBGTEXT("FATFS!ReadStreamData(DP): end readvolume\n")));
if (!dwError) {
cb = cblk << BLOCK_LOG2;
(PBYTE)pvData += cb;
if (plenRead)
*plenRead += cb;
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
dwError = ERROR_INVALID_PARAMETER;
}
UnlockBlocks(blk, cblk, FALSE);
if (dwError)
break;
}
else {
DEBUGMSG(ZONE_LOGIO && (pstm->s_flags & STF_DEMANDPAGED),(DBGTEXT("FATFS!ReadStreamData(DP): begin readstream\n")));
dwError = ReadStream(pstm, pos, &pbStart, &pbEnd);
DEBUGMSG(ZONE_LOGIO && (pstm->s_flags & STF_DEMANDPAGED),(DBGTEXT("FATFS!ReadStreamData(DP): begin readstream\n")));
if (dwError)
break;
cb = pbEnd - pbStart;
if (cb > len)
cb = len;
__try {
memcpy(pvData, pbStart, cb);
(PBYTE)pvData += cb;
if (plenRead)
*plenRead += cb;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
dwError = ERROR_INVALID_PARAMETER;
}
ReleaseStreamBuffer(pstm, FALSE);
if (dwError)
break;
}
#ifdef DEBUG
if (ZONE_READVERIFY && ZONE_LOGIO) {
DWORD i, j;
for (i=0; i<cb; i++) {
DEBUGMSG(TRUE,(DBGTEXT("%02x "), pbStart[i]));
j = i+1;
if (j == cb || j % 16 == 0) {
j = j % 16;
if (j == 0)
j = i - 15;
else
j = i - j + 1;
while (j <= i) {
DEBUGMSG(TRUE,(DBGTEXT("%c"), pbStart[j]<' ' || pbStart[j]>=0x7F? '.' : pbStart[j]));
j++;
}
DEBUGMSG(TRUE,(DBGTEXT("\n")));
}
}
}
#endif
len -= cb;
pos += cb;
}
return dwError;
}
/* WriteStreamData
*
* Whereas ReadStream returns a pointer (to a buffer) and a length,
* and then the caller reads whatever data it wants up to that length
* (or modifies data up to that length and calls ModifyStreamBuffer), this
* function takes a pointer to data and its length, the position to write
* it, and simply writes it.
*
* 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, WriteStreamData can write any amount of data
* with one call (no external loop).
*
* The same effect could be achieved with a ReadStream/ModifyStreamBuffer
* loop, but there are two important differences: WriteStreamData can avoid
* the overhead of reading data that it's simply going to overwrite anyway,
* and it takes care of extending the stream if needed.
*
* So, I've changed ReadStreamBuffer to accept an "advisory" lenMod parm,
* allowing us to advise it how many bytes we plan to modify. This
* information percolates down to FindBuffer, allowing FindBuffer to avoid
* filling a buffer with disk data if the entire buffer contents are going
* to be modified anyway. -JTP
*
* ENTRY
* pstm - pointer to DSTREAM
* pos - position within DSTREAM to write to
* pvData - pointer to data to write (or NULL to write zeros)
* len - length of data to write
* plenWritten - pointer to DWORD for length written (optional)
* fCommit - TRUE to commit buffers as they are written
*
* EXIT
* 0 if successful, error code if not (eg, disk full, or error reading
* the disk to fill the non-modified portion of a buffer)
*
* NOTES
* If fCommit is FALSE, note that the last buffer modified will still
* be held (ie, the stream's current buffer).
*/
DWORD WriteStreamData(PDSTREAM pstm, DWORD pos, PCVOID pvData, DWORD len, PDWORD plenWritten, BOOL fCommit)
{
DWORD dwError;
PBYTE pbStart, pbEnd;
ASSERT(OWNCRITICALSECTION(&pstm->s_cs));
if (pstm->s_pvol->v_flags & VOLF_READONLY)
return ERROR_WRITE_PROTECT;
dwError = ERROR_SUCCESS;
// A write of 0 bytes always succeeds, and is not supposed to do
// anything other than cause the "last write" timestamp to eventually
// get updated.
if (len == 0) {
pstm->s_flags |= STF_DIRTY_DATA;
pstm->s_flags &= ~STF_WRITE_TIME;
goto exit;
}
do {
RewindStream(pstm, pos);
do {
// Locate the data run which contains the bytes requested.
while (pos < pstm->s_run.r_end) {
DWORD cb, blk, cblk;
if (pvData && LockBlocks(pstm, pos, len, &blk, &cblk, TRUE)) {
__try {
dwError = WriteVolume(pstm->s_pvol, blk, cblk, (PVOID)pvData);
if (!dwError) {
cb = cblk << BLOCK_LOG2;
(PBYTE)pvData += cb;
if (plenWritten)
*plenWritten += cb;
}
else
DEBUGMSG(ZONE_ERRORS,(DBGTEXT("FATFS!WriteStreamData: WriteVolume(block %d, %d blocks) failed (%d)\n"), blk, cblk, dwError));
}
__except (EXCEPTION_EXECUTE_HANDLER) {
dwError = ERROR_INVALID_PARAMETER;
}
UnlockBlocks(blk, cblk, TRUE);
if (dwError)
goto exit;
}
else {
dwError = ReadStreamBuffer(pstm,
pos,
pos+len < pstm->s_size? len : pstm->s_run.r_end - pos,
&pbStart,
&pbEnd);
if (dwError) {
DEBUGMSG(ZONE_ERRORS,(DBGTEXT("FATFS!WriteStreamData: ReadStreamBuffer(block %d) failed (%d)\n"), pstm->s_run.r_blk + ((pos - pstm->s_run.r_start) >> BLOCK_LOG2), dwError));
goto exit;
}
cb = pbEnd - pbStart;
if (cb > len)
cb = len;
dwError = ModifyStreamBuffer(pstm, pbStart, cb);
if (dwError)
goto exit;
if (pvData) {
__try {
memcpy(pbStart, pvData, cb);
(PBYTE)pvData += cb;
if (plenWritten)
*plenWritten += cb;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
dwError = ERROR_INVALID_PARAMETER;
goto exit;
}
}
else
memset(pbStart, 0, cb);
}
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;
// This is where all successful WriteStreamData calls
// end up (except when len is ZERO to begin with, of course).
if (len == 0)
goto exit;
}
} while (UnpackRun(pstm) == 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)\n"), dwError));
exit:
if (fCommit) {
DWORD dw;
if (pstm->s_flags & STF_DIRTY_CLUS) {
dw = CommitStream(pstm, FALSE);
if (!dwError)
dwError = dw;
}
dw = ReleaseStreamBuffer(pstm, FALSE);
if (!dwError)
dwError = dw;
}
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;
ASSERT(OWNCRITICALSECTION(&pstm->s_cs));
DEBUGMSG(ZONE_STREAMS,(DBGTEXT("FATFS!ResizeStream: changing size from 0x%x to 0x%x for '%.11hs'\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;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -