⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 find.c

📁 Windows操作系统中文件系统过滤驱动和设备驱动之间的相似
💻 C
📖 第 1 页 / 共 5 页
字号:

                // If this is the last element, exit.  We know that the
                // current character is either a NULL or slash.  If NULL,
                // we're done;  if not NULL, then if the character after
                // the current slash is NULL *and* the caller is looking
                // for a directory, again we're done.

                if (*pwsTempPath == 0)
                    break;

                if (*(pwsTempPath+1) == 0 && (flName & NAME_DIR))
                    break;

                flTmp = NAME_DIR;
                pstm = OpenName(pstmPrev = pstm, pws, len, &flTmp);
                ASSERT(!pstm || !pstm->s_cwPath || pstm->s_cwPath > pstmPrev->s_cwPath + 1);

#ifdef DEMAND_PAGING_DEADLOCKS
                // 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, pwsTempPath-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 (*pwsTempPath++);
    }
    __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 || pstm->s_cwPath + (DWORD)len + 1 >= wcslen(pwsOrig) + (pwsOrig[0] != TEXTW('\\')) - (pws[len] == TEXTW('\\')));

    *ppwsTail = pwsPath + wcslen(pwsPath) - len;

    // Adjust for a trailing backslash or forwardslash in a dir path.
    if ((*pwsTempPath == L'\\' || *pwsTempPath == L'/') && *(pwsTempPath+1) == 0 && (flName & NAME_DIR))
        (*ppwsTail)--;

    *plen = len;

#ifdef TFAT
    if (pwsOrig != pwsPath) {
        HeapFree (hHeap, 0, pwsOrig);
    }
#endif        

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);

    DEBUGMSGW(ZONE_APIS,(DBGTEXTW("FATFS!OpenName (%s, %d)\r\n"), pwsName, cwName));

    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 = min((WORD)cwName,ARRAYSIZE(sh.sh_awcPattern));
        memcpy(sh.sh_awcPattern, pwsName, sh.sh_cwPattern*sizeof(WCHAR));
        sh.sh_awcPattern[sh.sh_cwPattern] = 0;
    }
    __except (EXCEPTION_EXECUTE_HANDLER) {
        dwError = ERROR_INVALID_PARAMETER;
        goto exit;
    }

    dwError = FindNext(&sh, &di, &fd);

    DEBUGMSGW(ZONE_APIS,(DBGTEXTW("FATFS!OpenName. %s starts at cluster %d\r\n"), pwsName, di.di_clusEntry));

    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);
                // TEST_BREAK
                PWR_BREAK_NOTIFY(21);

                // 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 set last error to ERROR_ALREADY_EXISTS for NT compatibility.

        if ((flName & NAME_CREATE) || (flName & NAME_TRUNCATE)) 
            SetLastError(ERROR_ALREADY_EXISTS);
                    
        // If the file is read-only, then don't allow truncation.
        if ((flName & NAME_TRUNCATE) && (di.di_pde->de_attr & ATTR_READ_ONLY)) 
            dwError = ERROR_ACCESS_DENIED;

        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 || 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;

#ifdef TFAT
    if (pvol->v_fTfat)
        LockFAT (pvol);
#endif    

    // 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)) {

#ifdef TFAT
        if (!pvol->v_fTfat)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -