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

📄 find.c

📁 从大量的wince源代码中剥离出的fat文件系统源代码.移植性非常高. 里面带有source i.rar
💻 C
📖 第 1 页 / 共 5 页
字号:

        // 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)
            dwError = ReadStream(pstmDir, pos, &plde, &pldeEnd);

        if (dwError)
            goto exit;

        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)
        dwError = ReadStream(pstmDir, pos, &pde, &pdeEnd);

    if (dwError)
        goto exit;

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

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

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

    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;
    DELETE_SECTOR_INFO dsi;
#ifdef DEBUG
    char achName[sizeof(pdi->di_pde->de_name)];
#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);

    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 (ReadStream(pstmDir, pdi->di_posLFN, &pde, &pdeEnd) == ERROR_SUCCESS) {
            do {
                if (!ISLFNDIRENTRY(pde))
                    goto lfndone;
                if (ModifyStreamBuffer(pstmDir, pde, sizeof(DIRENTRY)) != ERROR_SUCCESS)
                    goto lfndone;
                pde->de_name[0] = DIRFREE;
            } while (pdi->di_posLFN += sizeof(DIRENTRY), ++pde < pdeEnd);
        }
      lfndone:
        ;
    }

    dwError = WriteAndReleaseStreamBuffers(pstmDir);

    // Now kill all the cluster entries associated with this file.
    // We enter the FAT's critical section even though we're just freeing
    // clusters, because in the process, we could alter the FAT stream's
    // current buffer, and that could mess up someone else accessing the FAT.

    if (dwError == ERROR_SUCCESS && pdi->di_clusEntry != UNKNOWN_CLUSTER) {

        DWORD dwData = FREE_CLUSTER;
        PVOLUME pvol = pstmDir->s_pvol;

#ifdef DEBUG
        if (ZONE_PROMPTS) {
            int i;
            FATUIDATA fui;
            fui.dwSize = sizeof(fui);
            fui.dwFlags = FATUI_YES | FATUI_NO | FATUI_CANCEL | FATUI_DEBUGMESSAGE;
            fui.idsEvent = (UINT)TEXTW("Preparing to delete clusters for '%1!.11hs!'.\n\nSelect Yes to delete, No to mark bad, or Cancel to leave allocated.");
            fui.idsEventCaption = IDS_FATUI_WARNING;
            fui.cuiParams = 1;
            fui.auiParams[0].dwType = UIPARAM_VALUE;
            fui.auiParams[0].dwValue = (DWORD)achName;

#ifdef FATUI
            i = FATUIEvent(hFATFS, pvol->v_pwsHostRoot+1, &fui);
            if (i == FATUI_CANCEL)
                goto exit;
            if (i == FATUI_NO)
                dwData = FAT32_BAD;
#else
            i = FATUI_YES;
#endif                
        }
#endif
        LockFAT(pvol);

        dsi.cbSize = sizeof(DELETE_SECTOR_INFO);
        dsi.numsectors = (1 << pvol->v_log2csecClus);
        while (pdi->di_clusEntry >= DATA_CLUSTER && !ISEOF(pvol, pdi->di_clusEntry)) {
            DWORD dwRet; 
#if 0            
            DeviceIoControl(pvol->v_pdsk->d_hdsk, 
                            IOCTL_DISK_DELETE_CLUSTER, 
                            &((DWORD)pdi->di_clusEntry), sizeof(DWORD), 
                            NULL, 0, 
                            &dwRet, 
                            NULL); 
#else
            dsi.startsector = (dsi.numsectors * pdi->di_clusEntry)+pstmDir->s_pvol->v_blkClusBias;
            FSDMGR_DiskIoControl((HDSK)pvol->v_pdsk->d_hdsk, 
                            IOCTL_DISK_DELETE_SECTORS, 
                            &dsi, sizeof(DELETE_SECTOR_INFO), 
                            NULL, 0, 
                            &dwRet, 
                            NULL); 
#endif                            

            dwError = PACK(pvol, pdi->di_clusEntry, dwData, &pdi->di_clusEntry);
            if (dwError)
                break;
        }

        WriteAndReleaseStreamBuffers(pvol->v_pstmFAT);
        UnlockFAT(pvol);
    }

exit:
    return dwError;
}


/*  FindFirst - find the directory stream containing the specified file
 *
 *  ENTRY
 *      pvol - pointer to VOLUME
 *      pwsPath - pointer to pathname
 *      psh - pointer to SHANDLE (required)
 *      pdi - pointer to DIRINFO (optional, NULL if not needed)
 *      pfd - pointer to WIN32_FIND_DATAW structure (required)
 *      flName - zero or more NAME_* flags (eg, NAME_FILE, NAME_DIR)
 *      clusFail - cluster of stream not allowed in path
 *      (normally, this is UNKNOWN_CLUSTER, to perform unrestricted opens)
 *
 *      Additionally, psh->sh_flags must be set appropriately.  At a minimum,
 *      it must contain SHF_BYNAME, but can also contain SHF_WILD, SHF_DOTDOT,
 *      and SHF_CREATE.
 *
 *  EXIT
 *      If successful, it will return the attributes of the file from
 *      the file's DIRENTRY, and if a pdi was supplied, it will be filled
 *      in and current stream buffer left held.
 *
 *      If not successful, the attributes will be set to INVALID_ATTR,
 *      and the current stream buffer will not held.
 *
 *      Finally, if the stream didn't exist, or no pdi was supplied, no
 *      stream will be returned.  Otherwise, the directory stream containing
 *      the specified file will be returned.
 */

PDSTREAM FindFirst(PVOLUME pvol, PCWSTR pwsPath, PSHANDLE psh, PDIRINFO pdi, PWIN32_FIND_DATAW pfd, int flName, DWORD clusFail)
{
    PWSTR pwsName;
    DWORD len;
    DWORD dwError = ERROR_SUCCESS;

    psh->sh_pstm = NULL;

    __try {
        pfd->dwFileAttributes = INVALID_ATTR;

        psh->sh_pstm = OpenPath(pvol, pwsPath, &pwsName, &len, flName, clusFail);

⌨️ 快捷键说明

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