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

📄 path.c

📁 Windows操作系统中文件系统过滤驱动和设备驱动之间的相似
💻 C
📖 第 1 页 / 共 4 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
/*++


Module Name:

    path.c

Abstract:

    This file contains the path based API routines for the FAT file system.

Revision History:

--*/


#ifdef PATH_CACHING
#define PARENT_PATH_CACHING
#endif

#include "fatfs.h"

CONST WCHAR szDotDot[3] = TEXTW("..");


/*  FAT_CreateDirectoryW - Create a new subdirectory
 *
 *  ENTRY
 *      pvol - pointer to VOLUME
 *      pwsPathName - pointer to name of new subdirectory
 *      lpSecurityAttributes - pointer to security attributes (ignored)
 *
 *  EXIT
 *      TRUE if successful, FALSE if not (call GetLastError for error code)
 */

BOOL FAT_CreateDirectoryW(PVOLUME pvol, PCWSTR pwsPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
{
    int len;
    PWSTR pwsLast;
    PDSTREAM pstm, pstmDir;
    DIRENTRY adeDir[2];
    DWORD dwError;
    int flName = NAME_DIR | NAME_NEW | NAME_CREATE | ATTR_DIRECTORY;
    DSID sid, sidParent;
    DWORD cchFilePath = 0;
    
    DEBUGMSGW(ZONE_APIS,(DBGTEXTW("FATFS!FAT_CreateDirectoryW(%d chars: %-.64s)\r\n"), wcslen(pwsPathName), pwsPathName));

    if (!FATEnter(pvol, LOGID_CREATEDIRECTORY))
        return FALSE;

    if (pvol->v_flags & (VOLF_INVALID | VOLF_UNMOUNTED | VOLF_FROZEN | VOLF_LOCKED)) {
        dwError = ERROR_ACCESS_DENIED;
        goto error;
    }

    if (pvol->v_flags & VOLF_READONLY) {
        dwError = ERROR_WRITE_PROTECT;
        goto error;
    }

    // The following code would be simpler than OpenPath+OpenName:
    //
    //      OpenName((PDSTREAM)pvol, pwsPathName, 0, &flName);
    //
    // but we also need to know some information about the parent directory
    // stream, so we have to open the path first.  And we keep it open across
    // creation of the "." and ".." entries, to insure that the cluster of the
    // parent directory doesn't change.

    pstmDir = OpenPath(pvol, pwsPathName, &pwsLast, &len, flName, UNKNOWN_CLUSTER);
    if (!pstmDir) {
        FATExit(pvol, LOGID_CREATEDIRECTORY);
        DEBUGMSGW(ZONE_APIS || ZONE_ERRORS,(DBGTEXTW("FATFS!FAT_CreateDirectoryW(%d chars: %-.64s) returned FALSE (%d)\r\n"), wcslen(pwsPathName), pwsPathName, GetLastError()));
        return FALSE;
    }

    ASSERT(pvol == pstmDir->s_pvol);

    // If the length of the last element is zero, the caller must be trying to
    // (re)create the root directory, which of course already exists.

    if (len == 0) {
        dwError = ERROR_ALREADY_EXISTS;
        goto exit;
    }

    // If the length of the existing path, plus the length of the proposed
    // new directory, plus a separating backslash and a null terminator exceeds the maximum allowed
    // directory path, fail the call.

    // ASSERT(pstmDir->s_cwPath + (DWORD)len + 1 == wcslen(pwsPathName) + ((pwsPathName[0] != TEXTW('\\')) && (pwsPathName[0] != TEXTW('/'))) - ((pwsLast[len] == TEXT('\\')) || (pwsLast[len] == TEXT('/'))));

    cchFilePath = pvol->v_cwsHostRoot + pstmDir->s_cwPath + len + 2;
    if (cchFilePath > MAX_PATH || pvol->v_cwsHostRoot > MAX_PATH || len > MAX_PATH) {
        dwError = ERROR_FILENAME_EXCED_RANGE;
        goto exit;
    }

    dwError = ERROR_SUCCESS;

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

    PREFAST_SUPPRESS (508, "");
    pstm = OpenName(pstmDir, pwsLast, len, &flName);
    if (!pstm) {
        CloseStream(pstmDir);
        FATExit(pvol, LOGID_CREATEDIRECTORY);
#ifdef TFAT
        if (pvol->v_fTfat)
            UnlockFAT (pvol);
#endif            
        DEBUGMSGW(ZONE_APIS || ZONE_ERRORS,(DBGTEXTW("FATFS!FAT_CreateDirectoryW(%d chars: %-.64s) returned FALSE (%d)\r\n"), wcslen(pwsPathName), pwsPathName, GetLastError()));
        return FALSE;
    }

    // When OpenStream (called by OpenName) initialized the stream structure
    // for this new directory, since it was a directory, it initialized s_size
    // to MAX_DIRSIZE, because the size field in a directory's DIRENTRY is
    // never valid.  In this case however, we KNOW the size of the stream is
    // zero, so we set it to zero to help WriteStreamData realize that it doesn't
    // need to read the cluster it's about to write.

    pstm->s_size = 0;
    
    // Build the "." and ".." entries now.  WriteStreamData is the best choice,
    // because it handles lots of stuff, including resizing and not reading
    // data we're going to overwrite anyway.  NOTE: The FAT32 specification
    // dictates that ".." entries that point to their volume's root directory
    // should contain 0 in their cluster field, just like FAT12 and FAT16 volumes,
    // for better application compatibility. -JTP

    CreateDirEntry(pstm, &adeDir[0], NULL, ATTR_DIRECTORY, pstm->s_clusFirst);
    CreateDirEntry(pstm, &adeDir[1], NULL, ATTR_DIRECTORY, ISROOTDIR(pstmDir)? NO_CLUSTER : pstmDir->s_clusFirst);

    adeDir[0].de_name[0] =
    adeDir[1].de_name[0] = adeDir[1].de_name[1] = '.';

    WriteStreamData(pstm, 0, adeDir, sizeof(adeDir), NULL, FALSE);

#ifdef TFAT
        // TFAT: File the rest of the cluster with volumes,  In order to avoid modify the first cluster, 
        // so new file/dir can be created in the second cluster, moving directories is restricted.
    if (pvol->v_fTfat) {
        DIRENTRY adeVolume;
        DWORD    offset;
        int	     iVolumeNo;

        CreateDirEntry( pstm, &adeVolume, NULL, ATTR_VOLUME_ID, NO_CLUSTER );
        memcpy(adeVolume.de_name, "DONT_DEL000", sizeof (adeVolume.de_name));
        		
        for (offset = sizeof(adeDir), iVolumeNo = 0; offset < pvol->v_cbClus; offset += sizeof(adeVolume), iVolumeNo++)
        {
            adeVolume.de_name[8]  = '0' + (iVolumeNo / 100);
            adeVolume.de_name[9]  = '0' + ((iVolumeNo / 10) % 10);
            adeVolume.de_name[10] = '0' + (iVolumeNo % 10);

            WriteStreamData(pstm, offset, &adeVolume, sizeof(adeVolume), NULL, FALSE);
        }
        CommitStream (pstm, TRUE);
    }
    else 

#endif
    {
        // ZERO the rest of the cluster
        WriteStreamData(pstm, sizeof(adeDir), NULL, pvol->v_cbClus-sizeof(adeDir), NULL, FALSE);
    }

    CloseStream(pstmDir);
    pstmDir = NULL;

#ifdef TFAT
    if (pvol->v_fTfat) {
        UnlockFAT(pvol);
    }
#endif

#ifdef PATH_CACHING
    PathCacheCreate(pvol, pwsPathName, 0, pstm);
#endif

    memcpy (&sid, &pstm->s_sid, sizeof(DSID));
    memcpy (&sidParent, &pstm->s_sidParent, sizeof(DSID));

    CloseStream(pstm);
    FILESYSTEMNOTIFICATION(pvol, DB_CEOID_CREATED, 0, SHCNE_MKDIR, &sid, &sidParent, NULL, NULL, NULL, DBGTEXTW("FAT_CreateDirectoryW"));


  exit:
    if (pstmDir)
        CloseStream(pstmDir);

    if (dwError) {
      error:
        SetLastError(dwError);
    }

    FATExit(pvol, LOGID_CREATEDIRECTORY);

#ifdef TFAT
    if (pvol->v_fTfat && (dwError == ERROR_SUCCESS)) {
        dwError = CommitTransactions (pvol);
    }
#endif

    DEBUGMSGW(ZONE_APIS || ZONE_ERRORS && dwError,(DBGTEXTW("FATFS!FAT_CreateDirectoryW(%d chars: %-.64s) returned 0x%x (%d)\r\n"), wcslen(pwsPathName), pwsPathName, dwError == ERROR_SUCCESS, dwError));

    return dwError == ERROR_SUCCESS;
}


/*  FAT_RemoveDirectoryW - Destroy an existing subdirectory
 *
 *  ENTRY
 *      pvol - pointer to VOLUME
 *      pwsPathName - pointer to name of existing subdirectory
 *
 *  EXIT
 *      TRUE if successful, FALSE if not (call GetLastError for error code)
 */

BOOL FAT_RemoveDirectoryW(PVOLUME pvol, PCWSTR pwsPathName)
{
    PDSTREAM pstmDir;
    SHANDLE sh;
    DIRINFO di;
    WIN32_FIND_DATAW fd;
    DWORD dwError = ERROR_SUCCESS;
#ifdef SHELL_CALLBACK_NOTIFICATION
    CEOIDINFO oiOld;
#endif
    DWORD dwSHCNE = 0;
    DSID sidParent; 

    DEBUGMSGW(ZONE_APIS,(DBGTEXTW("FATFS!FAT_RemoveDirectoryW(%d chars: %-.64s)\r\n"), wcslen(pwsPathName), pwsPathName));

    if (!FATEnter(pvol, LOGID_REMOVEDIRECTORY))
        return FALSE;

    if (pvol->v_flags & (VOLF_INVALID | VOLF_UNMOUNTED | VOLF_FROZEN | VOLF_LOCKED)) {
        dwError = ERROR_ACCESS_DENIED;
        goto error;
    }

    if (pvol->v_flags & VOLF_READONLY) {
        dwError = ERROR_WRITE_PROTECT;
        goto error;
    }

    // FindFirst will call SetLastError appropriately, so
    // all we have to do is bail if it doesn't return a stream.

    sh.sh_flags = SHF_BYNAME;
    pstmDir = FindFirst(pvol, pwsPathName, &sh, &di, &fd, NAME_DIR, UNKNOWN_CLUSTER);
    if (!pstmDir) {
        FATExit(pvol, LOGID_REMOVEDIRECTORY);
        DEBUGMSGW(ZONE_APIS || ZONE_ERRORS,(DBGTEXTW("FATFS!FAT_RemoveDirectoryW(%d chars: %-.64s) returned FALSE (%d)\r\n"), wcslen(pwsPathName), pwsPathName, GetLastError()));
        return FALSE;
    }

    if (fd.dwFileAttributes == INVALID_ATTR) {
        CloseStream(pstmDir);
        FATExit(pvol, LOGID_REMOVEDIRECTORY);
        DEBUGMSGW(ZONE_APIS || ZONE_ERRORS,(DBGTEXTW("FATFS!FAT_RemoveDirectoryW(%d chars: %-.64s) returned FALSE (%d)\r\n"), wcslen(pwsPathName), pwsPathName, GetLastError()));
        return FALSE;
    }

    if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
        dwError = ERROR_ACCESS_DENIED;
        goto exit;
    }

    // Retrieve the fully-qualified pathname of the source, in case we need
    // it for the FILESYSTEMNOTIFICATION at the end of the function.  We have to
    // do the wacky buffer holding/unholding because pstmDir's current buffer is
    // in a known state, and we can't tolerate GetSIDInfo mucking that state up.

#ifdef SHELL_CALLBACK_NOTIFICATION
    if (pfnShell && ZONE_SHELLMSGS) {
        PBUF pbuf = pstmDir->s_pbufCur;
        HoldBuffer(pbuf);
        GetSIDInfo(pvol, &di.di_sid, &oiOld);
        ReleaseStreamBuffer(pstmDir, FALSE);
        AssignStreamBuffer(pstmDir, pbuf, FALSE);
        UnholdBuffer(pbuf);
    }
#endif

    // Before we can kill the DIRENTRY, we need to open it as a
    // stream and call FindNext to see if there are any files in it.

    if (di.di_clusEntry != UNKNOWN_CLUSTER) {

        ASSERT(di.di_clusEntry != FAT_PSEUDO_CLUSTER &&
               di.di_clusEntry != ROOT_PSEUDO_CLUSTER);

        sh.sh_pstm = OpenStream(pstmDir->s_pvol,
                                di.di_clusEntry,
                                &di.di_sid,
                                pstmDir, &di, OPENSTREAM_CREATE);
        if (sh.sh_pstm) {
            sh.sh_pos = 0;
            sh.sh_flags = SHF_BYNAME | SHF_WILD;
            sh.sh_cwPattern = 1;
            sh.sh_awcPattern[0] = TEXTW('*');

            dwError = FindNext(&sh, NULL, &fd);
            if (!dwError) {
                CloseStream(sh.sh_pstm);
                dwError = ERROR_DIR_NOT_EMPTY;
                goto exit;
            }

            // Check for search handles to this directory
            if (sh.sh_pstm->s_dlOpenHandles.pfhNext != (PFHANDLE)&sh.sh_pstm->s_dlOpenHandles) {
                CloseStream(sh.sh_pstm);
                dwError = ERROR_SHARING_VIOLATION;
                goto exit;
            }
            
            CloseStream(sh.sh_pstm);

        }
    }


    // If we're still here, then the directory stream is empty (except for
    // "." and ".." entries, which we didn't ask FindNext to find anyway), so
    // we can nuke the DIRENTRY and its associated clusters.

    dwError = DestroyName(pstmDir, &di);
    // TEST_BREAK
    PWR_BREAK_NOTIFY(31);

    if (!dwError) {

        dwSHCNE = SHCNE_RMDIR;
        memcpy (&sidParent, &pstmDir->s_sid, sizeof(DSID));

#ifdef PATH_CACHING
        if (PathCacheInvalidate(pvol, pwsPathName)) {

#ifdef PARENT_PATH_CACHING            
            if (!ISROOTDIR(pstmDir)) {

                
                sh.sh_pstm = pstmDir;
                sh.sh_pos = 0;
                sh.sh_flags = SHF_BYNAME | SHF_DOTDOT;
                sh.sh_cwPattern = ARRAYSIZE(szDotDot)-1;
                memcpy(sh.sh_awcPattern, szDotDot, sizeof(szDotDot));

                if (FindNext(&sh, &di, &fd) == ERROR_SUCCESS &&
                    di.di_clusEntry != UNKNOWN_CLUSTER) {

                    sh.sh_pstm = OpenStream(pstmDir->s_pvol,
                                            di.di_clusEntry, NULL,
                                            NULL, NULL, OPENSTREAM_CREATE);

                    
                    if (sh.sh_pstm) {
                        PathCacheCreate(pvol, pwsPathName, -2, sh.sh_pstm);
                        CloseStream(sh.sh_pstm);
                    }
                }
            }
#endif  // PARENT_PATH_CACHING
        }
#endif  // PATH_CACHING
    }

  exit:

    CloseStream(pstmDir);

    if (dwSHCNE)
        FILESYSTEMNOTIFICATION(pvol, 0, DB_CEOID_DIRECTORY_DELETED, dwSHCNE, NULL, NULL, &di.di_sid, &sidParent, &oiOld, DBGTEXTW("FAT_RemoveDirectoryW"));

    if (dwError) {
      error:
        SetLastError(dwError);
    }

    FATExit(pvol, LOGID_REMOVEDIRECTORY);

#ifdef TFAT
    if (pvol->v_fTfat && (dwError == ERROR_SUCCESS))
        dwError = CommitTransactions (pvol);
#endif

    DEBUGMSGW(ZONE_APIS || ZONE_ERRORS && dwError,(DBGTEXTW("FATFS!FAT_RemoveDirectoryW(%d chars: %-.64s) returned 0x%x (%d)\r\n"), wcslen(pwsPathName), pwsPathName, dwError == ERROR_SUCCESS, dwError));

    return dwError == ERROR_SUCCESS;
}


/*  FAT_GetFileAttributesW - Get file/subdirectory attributes
 *
 *  ENTRY
 *      pvol - pointer to VOLUME
 *      pwsFileName - pointer to name of existing file/subdirectory
 *

⌨️ 快捷键说明

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