📄 find.c
字号:
// If the stream we've opened can currently be demand-paged,
// then we MUST temporarily release the stream's CS around the
// memory manager calls that CloseStream could make (eg, LocalFree).
if (pstm && (pstm->s_flags & STF_DEMANDPAGED))
LeaveCriticalSection(&pstm->s_cs);
#endif
CloseStream(pstmPrev);
if (!pstm)
break;
#ifdef DEMAND_PAGING_DEADLOCKS
if (pstm->s_flags & STF_DEMANDPAGED)
EnterCriticalSection(&pstm->s_cs);
#endif
#ifdef PATH_CACHING
PathCacheCreate(pvol, pwsOrig, pwsPath-pwsOrig, pstm);
#endif
// If the starting cluster of the stream we just opened
// matches clusFail, someone is trying to force a stream
// to become its own parent. Close the current stream
// and fail the call.
if (pstm->s_clusFirst == clusFail) {
dwError = ERROR_ACCESS_DENIED;
break;
}
}
} while (*pwsPath++);
}
__except (EXCEPTION_EXECUTE_HANDLER) {
dwError = ERROR_INVALID_PARAMETER;
}
// The only time the length of the final element is allowed to be zero
// is when there is no previous stream (ie, the caller specified the root)
if (len == 0 && pstmPrev != NULL)
dwError = ERROR_PATH_NOT_FOUND;
if (dwError) {
SetLastError(dwError);
if (pstm) {
CloseStream(pstm);
pstm = NULL;
}
}
ASSERT(!pstm || pstm->s_cwPath + (DWORD)len + 1 >= wcslen(pwsOrig) + (pwsOrig[0] != TEXTW('\\')) - (pws[len] == TEXTW('\\')));
*ppwsTail = pws;
*plen = len;
exit:
return pstm;
}
/* OpenName - Open stream for last element of a path
*
* ENTRY
* pstmDir - pointer to directory stream (or volume)
* pwsName - pointer to name
* cwName - length of name (0 if pstmDir is a volume instead)
* pflName - pointer to NAME_* flags (eg, NAME_FILE, NAME_DIR),
* along with initial file attributes (eg, ATTR_DIRECTORY) if NAME_CREATE
*
* EXIT
* pointer to stream, NULL if error (call GetLastError for error code)
*/
PDSTREAM OpenName(PDSTREAM pstmDir, PCWSTR pwsName, int cwName, int *pflName)
{
SHANDLE sh;
DIRINFO di;
WIN32_FIND_DATAW fd;
PDSTREAM pstmTmp = NULL;
PDSTREAM pstmRet = NULL;
int flName = *pflName;
DWORD dwError = ERROR_SUCCESS;
ASSERT(pstmDir && cwName <= MAX_LFN_LEN);
if (cwName == 0) {
pstmTmp = OpenPath((PVOLUME)pstmDir, pwsName, &pwsName, &cwName, *pflName, UNKNOWN_CLUSTER);
if (pstmTmp == NULL)
goto exit;
// cwName is zero when the caller tries to open the root dir.
// We allow the root to be FOUND in some cases, but never OPENED.
if (cwName == 0) {
dwError = ERROR_ACCESS_DENIED;
goto exit;
}
// If the length of the existing path, plus the length of the proposed
// filename, plus 3 (for a drive letter, colon and separating backslash)
// or the length of the WINCE root, whichever is larger, exceeds the
// maximum allowed path, fail the call. WINCE doesn't use drive letters,
// but down-level systems may need to.
if (pstmTmp->s_cwPath + max(3,pstmTmp->s_pvol->v_cwsHostRoot) + cwName + 2 > MAX_PATH) {
dwError = ERROR_FILENAME_EXCED_RANGE;
goto exit;
}
pstmDir = pstmTmp;
}
__try {
// Check for special volume names now, if the caller allows them.
// We allow them, however, only if they're specified in the root.
// Furthermore, since they aren't true streams, we return the root
// stream, since it simplifies our life if all handles are always
// associated with some stream.
if ((flName & NAME_VOLUME) && ISROOTDIR(pstmDir)) {
if (_wcsicmp(pwsName, TEXTW("VOL:")) == 0) {
pstmRet = pstmDir;
EnterCriticalSection(&pstmRet->s_cs);
pstmRet->s_refs++; // bump root stream ref and cs counts, too
goto exit;
}
}
// If the volume isn't valid, special volume names are the only names
// allowed at this point, so fail the call.
if (pstmDir->s_pvol->v_flags & VOLF_INVALID) {
dwError = ERROR_ACCESS_DENIED;
goto exit;
}
sh.sh_pstm = pstmDir;
sh.sh_pos = 0;
sh.sh_flags = SHF_BYNAME;
// If this is a potential "creation" situation, tell the search code
if (flName & NAME_CREATE)
sh.sh_flags |= SHF_CREATE;
sh.sh_cwPattern = (WORD)cwName;
memcpy(sh.sh_awcPattern, pwsName, cwName*sizeof(WCHAR));
sh.sh_awcPattern[cwName] = 0;
}
__except (EXCEPTION_EXECUTE_HANDLER) {
dwError = ERROR_INVALID_PARAMETER;
goto exit;
}
dwError = FindNext(&sh, &di, &fd);
if (dwError) {
// No matching entry found. If creation of a new entry is allowed,
// then attempt to create one, using the DIRINFO saved from the
// FindNext call. If successful, it will update the DIRINFO structure,
// and the rest of the code will simply think that FindNext succeeded.
SetLastError(ERROR_SUCCESS);
if (flName & NAME_CREATE) {
if (dwError != ERROR_INVALID_NAME) {
dwError = CreateName(pstmDir, sh.sh_awcPattern, &di, NULL, flName);
// Force the NAME_NEW bit off now, so that if CreateName
// succeeded, we don't outsmart ourselves and fool the code
// below into thinking that the file already existed.
// Ditto for the NAME_MODE_WRITE (aka GENERIC_WRITE) bit,
// because callers are allowed to create and write to new R/O
// files. It's only *existing* R/O files they're not allowed
// to write to.
flName &= ~(NAME_NEW | NAME_MODE_WRITE);
if (!dwError) {
*pflName |= NAME_CREATED;
ASSERT(pstmDir->s_pbufCur);
}
}
}
else {
dwError = (flName & NAME_DIR? ERROR_PATH_NOT_FOUND : ERROR_FILE_NOT_FOUND);
}
}
else {
// If file already exists and OPEN_ALWAYS or CREATE_ALWAYS was specified
// we need to return ERROR_ALREADY_EXISTS for NT compatibility.
if ((flName & NAME_CREATE) || (flName & NAME_TRUNCATE))
SetLastError(ERROR_ALREADY_EXISTS);
ASSERT(pstmDir->s_pbufCur);
}
if (!dwError) {
// NOTE that in this code path, the directory stream's buffer remains
// held (either because FindNext succeeded, or because it failed but
// CreateName succeeded). So don't forget to call ReleaseStreamBuffer!
if (flName & NAME_NEW) {
// Even though ERROR_FILE_EXISTS seems a more logical error to return
// when someone tries to create a new directory and a file already exists
// with the same name, both Win95 and NT return ERROR_ALREADY_EXISTS,
// so I'm blindly following their convention. -JTP
dwError = (di.di_pde->de_attr & ATTR_DIRECTORY) || (flName & NAME_DIR)?
ERROR_ALREADY_EXISTS : ERROR_FILE_EXISTS;
}
else if (!(di.di_pde->de_attr & ATTR_DIRECTORY) && (flName & NAME_DIR)) {
dwError = ERROR_PATH_NOT_FOUND;
}
else if ((di.di_pde->de_attr & ATTR_DIRECTORY) && !(flName & NAME_DIR)) {
dwError = ERROR_ACCESS_DENIED;
}
else if ((di.di_pde->de_attr & ATTR_READ_ONLY) && (flName & NAME_MODE_WRITE)) {
dwError = ERROR_ACCESS_DENIED;
}
else {
ASSERT(di.di_sid.sid_clusDir != 0 &&
di.di_clusEntry != FAT_PSEUDO_CLUSTER && di.di_clusEntry != ROOT_PSEUDO_CLUSTER);
pstmRet = OpenStream(pstmDir->s_pvol,
di.di_clusEntry,
&di.di_sid,
pstmDir, &di, OPENSTREAM_CREATE);
if (!pstmRet)
dwError = ERROR_OUTOFMEMORY;
else
ASSERT(pstmRet->s_cwPath > pstmDir->s_cwPath + di.di_cwName);
}
ReleaseStreamBuffer(pstmDir, FALSE);
}
exit:
if (dwError)
SetLastError(dwError);
// If we opened the directory stream on the caller's behalf, close it now;
// otherwise, it's his, so leave it alone.
if (pstmTmp)
CloseStream(pstmTmp);
return pstmRet;
}
DWORD CreateName(PDSTREAM pstmDir, PCWSTR pwsName, PDIRINFO pdi, PDIRENTRY pdeClone, int flName)
{
PVOLUME pvol;
PDIRENTRY pde, pdeEnd;
DWORD pos, posEnd, clde;
PLFNDIRENTRY plde, pldeEnd;
BYTE chksum;
int cw, cwTail;
PCWSTR pwsTail;
DWORD cbOldSize;
int cdeNeed = pdi->di_cdeNeed;
DWORD dwError = ERROR_SUCCESS;
ASSERT(cdeNeed >= 1 && pdi->di_clusEntry == UNKNOWN_CLUSTER && pdeClone != INVALID_PTR);
if (pdi->di_achOEM[0] == 0)
return ERROR_DISK_FULL;
pvol = pstmDir->s_pvol;
if (pvol->v_flags & VOLF_READONLY)
return ERROR_WRITE_PROTECT;
// To simplify CreateDirectory, if this is a new ATTR_DIRECTORY entry,
// pre-allocate the one cluster that the directory will want later anyway.
// This will save us work later (for example, we won't have to recommit
// the DIRENTRY just to update the clusFirst field).
if ((flName & (NAME_CREATE | ATTR_DIRECTORY)) == (NAME_CREATE | ATTR_DIRECTORY)) {
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;
}
// 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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -