📄 stream.c
字号:
// 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 + -