📄 stream.c
字号:
if (pos == pstm->s_run.r_start) {
*pdwClus = pstm->s_run.r_clusPrev;
break;
}
if (pos <= pstm->s_run.r_end) {
*pdwClus = pstm->s_run.r_clusThis +
((pos - pstm->s_run.r_start - 1) >>
(pstm->s_pvol->v_log2cblkClus + pstm->s_pvol->v_log2cbBlk));
break;
}
// TEST_BREAK
PWR_BREAK_NOTIFY(42);
dwError = UnpackRun (pstm);
if (dwError != ERROR_SUCCESS) {
// This is OK, just means position is past EOF.
if (dwError == ERROR_HANDLE_EOF)
dwError = ERROR_SUCCESS;
*pdwClus = UNKNOWN_CLUSTER;
break;
}
} while (TRUE);
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;
__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("\r\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).
*/
#define MAX_UNPACK_RETRIES 20
DWORD WriteStreamData(PDSTREAM pstm, DWORD pos, PCVOID pvData, DWORD len, PDWORD plenWritten, BOOL fCommit)
{
DWORD dwError, dwUnpackError;
PBYTE pbStart, pbEnd;
DWORD dwRetries;
BOOL fSizeChanged = FALSE;
dwUnpackError = ERROR_SUCCESS;
dwRetries = 0;
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;
}
#ifdef TFAT
// If CloneStream fails (most likely because no room to copy), then fail the write
if (pstm->s_pvol->v_fTfat && (pstm->s_pvol->v_flFATFS & FATFS_TRANS_DATA)) {
LockFAT (pstm->s_pvol);
dwError = CloneStream(pstm, pos, len );
if (dwError != ERROR_SUCCESS)
goto exit;
}
#endif
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;
dwUnpackError = ERROR_SUCCESS;
if (pvData && LockBlocks(pstm, pos, len, &blk, &cblk, TRUE)) {
__try {
dwError = WriteVolume(pstm->s_pvol, blk, cblk, (PVOID)pvData, pstm->s_flags & STF_WRITETHRU);
if (!dwError) {
cb = cblk << pstm->s_pvol->v_log2cbBlk;
(PBYTE)pvData += cb;
if (plenWritten)
*plenWritten += cb;
}
else
DEBUGMSG(ZONE_ERRORS,(DBGTEXT("FATFS!WriteStreamData: WriteVolume(block %d, %d blocks) failed (%d)\r\n"), blk, cblk, dwError));
}
__except (EXCEPTION_EXECUTE_HANDLER) {
dwError = ERROR_INVALID_PARAMETER;
}
UnlockBlocks(pstm, 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)\r\n"), pstm->s_run.r_blk + ((pos - pstm->s_run.r_start) >> pstm->s_pvol->v_log2cbBlk), 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -