📄 find.c
字号:
#endif
LockFAT(pvol);
dwError = NewCluster(pvol, UNKNOWN_CLUSTER, &pdi->di_clusEntry);
if (dwError == ERROR_SUCCESS && pdi->di_clusEntry == UNKNOWN_CLUSTER)
dwError = ERROR_DISK_FULL;
if (dwError) {
UnlockFAT(pvol);
return dwError;
}
DEBUGMSG(ZONE_APIS,(DBGTEXT("FATFS!CreateName: new cluster for %s returned %d'\r\n"), pwsName, pdi->di_clusEntry));
// We must mark this cluster USED right now, because if we have
// to grow the directory containing this new directory, we don't
// want it scarfing up the same cluster. Besides, this will likely
// save us a redundant write to the FAT in that case.
dwError = PACK(pvol, pdi->di_clusEntry, EOF_CLUSTER, NULL);
if (dwError)
goto exit;
}
pos = pdi->di_pos;
if (pdi->di_cdeFree)
pos = pdi->di_posFree;
// Remember the original size of the directory stream so we can tell
// later if ResizeStream grew it.
cbOldSize = pstmDir->s_size;
posEnd = pos + cdeNeed * sizeof(DIRENTRY);
if (posEnd > pdi->di_pos) {
// Directory may need to grow. First, make sure we're not
// trying to push the directory beyond MAX_DIRENTRIES.
if (posEnd/sizeof(DIRENTRY) > MAX_DIRENTRIES) {
dwError = ERROR_DISK_FULL; goto exit;
}
// Now make sure directory is large enough. Make a special
// call to ResizeStream to grow if necessary but never shrink. We
// treat this as a general error rather than a write error, because
// ResizeStream can fail simply because the disk is full.
dwError = ResizeStream(pstmDir, posEnd, RESIZESTREAM_NONE);
if (dwError)
goto exit;
}
clde = 0;
plde = pldeEnd = NULL;
cwTail = pdi->di_cwTail;
pwsTail = pdi->di_pwsTail;
// Advance cwTail by 1 character to encompass the NULL that OpenName and
// FindFirst stored. We don't need to store a NULL if the name fits into
// the LFN entries perfectly however.
if (cwTail < LDE_NAME_LEN)
cwTail++;
while (cdeNeed > 1) {
if( plde >= pldeEnd ) {
if( dwError = ReadStream( pstmDir, pos, &plde, &pldeEnd ))
goto exit;
#ifdef TFAT
// clone the buffer; If this existed before...
if(pvol->v_fTfat)
{
dwError = CloneDirCluster( pvol, pstmDir, pstmDir->s_pbufCur->b_blk, NULL );
if( ERROR_DISK_FULL == dwError ) {
goto exit;
}
else if (CLONE_CLUSTER_COMPLETE == dwError) {
// The current buffer might be changed in CloneDirCluster
// update plde to with the new buffer
if( dwError = ReadStream( pstmDir, pos, &plde, &pldeEnd )) {
DEBUGMSG (TRUE, (TEXT("FATFSD!TFAT: ERROR!!!! ReadStream failed after CloneDirCluster\n")));
ASSERT (0); // It is bad if happens
goto exit;
}
}
// CloneDirCluster succeeded...let's assert it's right
ASSERT( pos >= pstmDir->s_runList.r_StartPosition &&
pos < pstmDir->s_runList.r_EndPosition);
}
#endif
}
dwError = ModifyStreamBuffer(pstmDir, plde, sizeof(LFNDIRENTRY));
if (dwError)
goto exit;
memset(plde, 0xFF, sizeof(LFNDIRENTRY));
plde->lde_ord = (BYTE)(cdeNeed-1);
if (clde++ == 0) {
// The first LFN entry must be specially marked. This is
// also a good time to compute the checksum of the short name.
chksum = ChkSumName(pdi->di_achOEM);
plde->lde_ord |= LN_ORD_LAST_MASK;
}
plde->lde_attr = ATTR_LONG;
plde->lde_flags = 0;
plde->lde_chksum = chksum;
plde->lde_clusFirst = 0;
cw = cwTail >= LDE_LEN1? LDE_LEN1 : cwTail;
memcpy(plde->lde_name1, pwsTail, cw*sizeof(WCHAR));
cw = cwTail >= LDE_LEN1+LDE_LEN2? LDE_LEN2 : cwTail-LDE_LEN1;
if (cw > 0)
memcpy(plde->lde_name2, pwsTail+LDE_LEN1, cw*sizeof(WCHAR));
cw = cwTail >= LDE_LEN1+LDE_LEN2+LDE_LEN3? LDE_LEN3 : cwTail-LDE_LEN1-LDE_LEN2;
if (cw > 0)
memcpy(plde->lde_name3, pwsTail+LDE_LEN1+LDE_LEN2, cw*sizeof(WCHAR));
pwsTail -= LDE_NAME_LEN;
cwTail = LDE_NAME_LEN;
plde++;
pos += sizeof(LFNDIRENTRY);
cdeNeed--;
}
// Now write the primary DIRENTRY
pde = (PDIRENTRY)plde;
if( pde >= ( PDIRENTRY )pldeEnd ) {
if( dwError = ReadStream( pstmDir, pos, &pde, &pdeEnd ))
goto exit;
#ifdef TFAT
// clone the buffer, if it wasn't just added by resizestream
if(pvol->v_fTfat)
{
dwError = CloneDirCluster( pvol, pstmDir, pstmDir->s_pbufCur->b_blk, NULL );
if( ERROR_DISK_FULL == dwError ) {
goto exit;
}
else if (CLONE_CLUSTER_COMPLETE == dwError) {
// The current buffer might be changed in CloneDirCluster
// update plde with the new buffer
if( dwError = ReadStream( pstmDir, pos, &pde, &pdeEnd )) {
DEBUGMSG (TRUE, (TEXT("FATFSD!TFAT: ERROR!!!! ReadStream failed after CloneDirCluster\n")));
ASSERT (0); // It is bad if happens
goto exit;
}
}
}
#endif
}
dwError = ModifyStreamBuffer(pstmDir, pde, sizeof(DIRENTRY));
if (dwError)
goto exit;
CreateDirEntry(pstmDir, pde, pdeClone, (BYTE)flName, pdi->di_clusEntry);
memcpy(pde->de_name, pdi->di_achOEM, sizeof(pde->de_name));
// TEST_BREAK
PWR_BREAK_NOTIFY(23);
// If ResizeStream had to add any new clusters, then any portion
// we haven't written yet needs to be zeroed.
if (cbOldSize != pstmDir->s_size && posEnd < pstmDir->s_size) {
PBUF pbuf = pstmDir->s_pbufCur;
// Because WriteStreamData (usually doesn't but) may involve filling a
// new buffer, and we don't want to lose the hold we've got on the current
// stream buffer, we have to apply another hold.
HoldBuffer(pbuf);
WriteStreamData(pstmDir, posEnd, NULL, pstmDir->s_size-posEnd, NULL, FALSE);
ReleaseStreamBuffer(pstmDir, FALSE);
AssignStreamBuffer(pstmDir, pbuf, FALSE);
UnholdBuffer(pbuf);
}
// Commit all buffers associated with the directory stream, held or not,
// and don't release the current stream buffer either.
dwError = WriteStreamBuffers(pstmDir);
exit:
if (pdi->di_clusEntry != UNKNOWN_CLUSTER) {
// Since we pre-allocated a cluster for this new stream (namely di_clusEntry),
// if there was an error, then we want to de-allocate that cluster.
if (dwError) {
PACK(pvol, pdi->di_clusEntry, FREE_CLUSTER, NULL);
pdi->di_clusEntry = UNKNOWN_CLUSTER;
}
#ifdef TFAT
if (!pvol->v_fTfat)
#endif
UnlockFAT(pvol);
}
// Make sure any changes made to the FAT are written now, too. Even if we
// didn't have to pre-allocate a cluster for the new stream, we might have had to
// resize the directory containing it (which would have affected the FAT as well),
// and since we call ResizeStream without RESIZESTREAM_UPDATEFAT in order to minimize
// writes to the FAT, it's a good idea to have an explicit write somewhere....
if (!dwError) {
WriteStreamBuffers(pvol->v_pstmFAT);
}
#ifdef TFAT
if (pvol->v_fTfat)
UnlockFAT (pvol);
#endif
if (!dwError) {
// Update the DIRINFO structure, so that the caller has all
// the same info that a successful FindNext would have returned.
pdi->di_pde = pde;
pdi->di_pos = pos;
SETSID(&pdi->di_sid, pos, pstmDir->s_clusFirst);
// I can tell you're wondering why we're reloading di_clusEntry
// from the DIRENTRY, since we passed di_clusEntry to CreateDirEntry
// in the first place, so wouldn't they already be the same? The
// answer is NO if CreateDirEntry was also given a pde to clone;
// in that case, we DO need to reload di_clusEntry from the DIRENTRY.
pdi->di_clusEntry = GETDIRENTRYCLUSTER(pvol,pde);
if (pdi->di_clusEntry == NO_CLUSTER)
pdi->di_clusEntry = UNKNOWN_CLUSTER;
}
return dwError;
}
/* DestroyName - destroy a DIRENTRY in the specified directory stream
*
* ENTRY
* pstmDir - pointer to directory stream
* pdi - pointer to DIRINFO (information returned by search)
*
* EXIT
* Error code (0 if success, non-zero if error)
*
* NOTES
* The DIRINFO structure identifies what DIRENTRY to blow away. The
* stream's current buffer must be held and must contain the entry to
* be deleted.
*
* A deliberate peculiarity of this function is that it does not extract
* clusFirst from the DIRENTRY to determine what clusters to decommit.
* It relies on the (normally identical) clusEntry field in the DIRINFO
* structure instead. The reason is to give caller's the option of leaving
* the cluster chain intact, in case they're simply destroying a name as
* part of, say, a RENAME operation.
*/
DWORD DestroyName(PDSTREAM pstmDir, PDIRINFO pdi)
{
DWORD dwError;
PDIRENTRY pde, pdeEnd;
PVOLUME pvol = pstmDir->s_pvol;
#ifdef DEBUG
char achName[sizeof(pdi->di_pde->de_name)];
#endif
#ifdef TFAT
DWORD blkNew;
#endif
// We kill the directory entries first and THEN any clusters
// so that in the event of a crash, you're more likely to end up
// with orphaned clusters than cross-linkable clusters. However,
// *guaranteeing* that would require changing the very first
// ModifyStreamBuffer's commit parm to TRUE, which is undesirable.
// Since the stream's buffer has been held for us, and that buffer
// contains the primary DIRENTRY for this file, kill that entry first.
ASSERT(pdi->di_pde);
DEBUGMSGW(ZONE_APIS,(DBGTEXTW("FATFS!Enter DestroyName (%.11hs)\r\n"), pdi->di_pde->de_name));
// TFAT, LockFAT around WriteAndReleaseStreamBuffers(pstmDir) and FreezeClusters
// the direntry matches what's in the FAT
LockFAT(pvol);
#ifdef TFAT
if (pvol->v_fTfat) {
// we need to clone the current buffer
// before we make any modifications!
if (CLONE_CLUSTER_COMPLETE == CloneDirCluster( pvol, pstmDir, pstmDir->s_pbufCur->b_blk, &blkNew ))
{
// The current buffer might be changed in CloneDirCluster
// update plde to with the new buffer
if( dwError = ReadStream( pstmDir, pdi->di_pos, &pdi->di_pde, NULL))
goto exit;
}
}
#endif
dwError = ModifyStreamBuffer(pstmDir, pdi->di_pde, sizeof(DIRENTRY));
if (dwError)
goto exit;
#ifdef DEBUG
memcpy(achName, pdi->di_pde->de_name, sizeof(pdi->di_pde->de_name));
#endif
pdi->di_pde->de_name[0] = DIRFREE;
// Now see if there were also LFN entries that need to be killed;
// since all the LFN entries have to be associated with the entry above,
// we can just kill every entry we find until we reach a non-LFN entry.
if (pdi->di_posLFN != INVALID_POS) {
while(( dwError = ReadStream( pstmDir, pdi->di_posLFN, &pde, &pdeEnd )) == ERROR_SUCCESS ) {
#ifdef TFAT
if (pvol->v_fTfat) {
// We need to check if we need to clone the block for TFAT vols.
if(pstmDir->s_pbufCur->b_blk != blkNew ) {
// If we read in a different block than we replaced
// earlier, we need to replace this one as well.
if (CLONE_CLUSTER_COMPLETE == CloneDirCluster( pvol, pstmDir, pstmDir->s_pbufCur->b_blk, &blkNew ))
{
// The current buffer might be changed in CloneDirCluster
// update plde to with the new buffer
if( dwError = ReadStream( pstmDir, pdi->di_posLFN, &pde, &pdeEnd )) {
RETAILMSG (TRUE, (TEXT("FATFSD!TFAT: ERROR!!!! ReadStream failed after CloneDirCluster\n")));
ASSERT (0); // It is bad if happens
goto exit;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -