static BOOLEAN PvfsSysIsEmptyDir( PSTR pszDirname ) { NTSTATUS ntError = STATUS_SUCCESS; BOOLEAN isEmptyDir = TRUE; DIR *pDir = NULL; struct dirent *pDirEntry = NULL; struct dirent dirEntry = { 0 }; ntError = PvfsSysOpenDir(pszDirname, &pDir); BAIL_ON_NT_STATUS(ntError); for (ntError = PvfsSysReadDir(pDir, &dirEntry, &pDirEntry); pDirEntry; ntError = PvfsSysReadDir(pDir, &dirEntry, &pDirEntry)) { /* First check the error return */ BAIL_ON_NT_STATUS(ntError); if (!LwRtlCStringIsEqual(pDirEntry->d_name, ".", FALSE) && !LwRtlCStringIsEqual(pDirEntry->d_name, "..", FALSE)) { isEmptyDir = FALSE; break; } } error: if (pDir) { PvfsSysCloseDir(pDir); } return NT_SUCCESS(ntError) ? isEmptyDir : FALSE; }
static NTSTATUS PvfsSysRemoveDir( PSTR pszDirname ) { NTSTATUS ntError = STATUS_SUCCESS; DIR *pDir = NULL; struct dirent *pDirEntry = NULL; struct dirent dirEntry = { 0 }; PSTR pszPath = NULL; PVFS_STAT streamDirStat = { 0 }; ntError = PvfsSysOpenDir(pszDirname, &pDir); BAIL_ON_NT_STATUS(ntError); for (ntError = PvfsSysReadDir(pDir, &dirEntry, &pDirEntry); pDirEntry; ntError = PvfsSysReadDir(pDir, &dirEntry, &pDirEntry)) { /* First check the error return */ BAIL_ON_NT_STATUS(ntError); memset(&streamDirStat, 0, sizeof(PVFS_STAT)); if (pszPath) { LwRtlCStringFree(&pszPath); } ntError = LwRtlCStringAllocatePrintf( &pszPath, "%s/%s", pszDirname, pDirEntry->d_name); BAIL_ON_NT_STATUS(ntError); ntError = PvfsSysStat(pszPath, &streamDirStat); if (ntError == STATUS_SUCCESS) { if(S_ISDIR(streamDirStat.s_mode)) { if (!LwRtlCStringIsEqual(pDirEntry->d_name, ".", FALSE) && !LwRtlCStringIsEqual(pDirEntry->d_name, "..", FALSE)) { ntError = PvfsSysRemoveDir(pszPath); BAIL_ON_NT_STATUS(ntError); } } else { ntError = PvfsSysRemove(pszPath); BAIL_ON_NT_STATUS(ntError); } } else { // Squash the error is the stream directory did not exist ntError = STATUS_SUCCESS; } } ntError = PvfsSysCloseDir(pDir); BAIL_ON_NT_STATUS(ntError); pDir = NULL; ntError = PvfsSysRemove(pszDirname); BAIL_ON_NT_STATUS(ntError); error: if (pszPath) { LwRtlCStringFree(&pszPath); } if (pDir) { PvfsSysCloseDir(pDir); } return ntError; }
static NTSTATUS PvfsResolvePath( PSTR *ppszResolvedPath, PCSTR pszLookupPath ) { NTSTATUS ntError = STATUS_SUCCESS; PSTR pszCursor = NULL; PSTR pszComponent = NULL; PSTR pszPath = NULL; PVFS_STAT Stat = {0}; PSTR pszResolvedPath = NULL; PSTR pszResWorkingPath = NULL; PSTR pszWorkingPath = NULL; DWORD Length = PATH_MAX; DIR *pDir = NULL; struct dirent *pDirEntry = NULL; if (*pszLookupPath != '/') { ntError = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntError); } ntError = RTL_ALLOCATE(&pszResolvedPath, CHAR, Length); BAIL_ON_NT_STATUS(ntError); ntError = RTL_ALLOCATE(&pszWorkingPath, CHAR, PATH_MAX); BAIL_ON_NT_STATUS(ntError); ntError = RtlCStringDuplicate(&pszPath, pszLookupPath); BAIL_ON_NT_STATUS(ntError); pszComponent = pszPath + 1; while (pszComponent && (Length > 0)) { pDir = NULL; if ((pszCursor = strchr(pszComponent, '/')) != NULL) { *pszCursor = '\0'; } snprintf(pszWorkingPath, PATH_MAX-1, "%s/%s", pszResolvedPath, pszComponent); /* Try cache first */ ntError = PvfsPathCacheLookup(&pszResWorkingPath, pszWorkingPath); if(ntError == STATUS_SUCCESS) { strncpy(pszResolvedPath, pszResWorkingPath, PATH_MAX-1); Length = PATH_MAX - RtlCStringNumChars(pszResolvedPath); RtlCStringFree(&pszResWorkingPath); } /* Maybe an exact match on disk? */ else if (PvfsSysStat(pszWorkingPath, &Stat) == STATUS_SUCCESS) { strncpy(pszResolvedPath, pszWorkingPath, PATH_MAX-1); Length = PATH_MAX - RtlCStringNumChars(pszResolvedPath); RtlCStringFree(&pszResWorkingPath); ntError = PvfsPathCacheAdd(pszResolvedPath); BAIL_ON_NT_STATUS(ntError); } /* Do the work ourselves */ else { /* Enumerate directory entries and look for a match */ ntError = PvfsSysOpenDir(pszResolvedPath, &pDir); if (ntError == STATUS_NOT_A_DIRECTORY) { ntError = STATUS_OBJECT_PATH_NOT_FOUND; } BAIL_ON_NT_STATUS(ntError); for(ntError = PvfsSysReadDir(pDir, &pDirEntry); pDirEntry; ntError = PvfsSysReadDir(pDir, &pDirEntry)) { /* First check the error return */ BAIL_ON_NT_STATUS(ntError); if (RtlCStringIsEqual(pszComponent, pDirEntry->d_name, FALSE)) { break; } } /* Did we find a match? */ if (!pDirEntry) { /* Return code depends on whether the last component was not found or if an intermediate component was invalid */ if (pszCursor == NULL) { ntError = STATUS_OBJECT_NAME_NOT_FOUND; } else { ntError = STATUS_OBJECT_PATH_NOT_FOUND; } BAIL_ON_NT_STATUS(ntError); } strncat(pszResolvedPath, "/", Length-1); Length -= 1; strncat(pszResolvedPath, pDirEntry->d_name, Length-1); Length -= RtlCStringNumChars(pDirEntry->d_name); ntError = PvfsSysCloseDir(pDir); pDir = NULL; BAIL_ON_NT_STATUS(ntError); ntError = PvfsPathCacheAdd(pszResolvedPath); BAIL_ON_NT_STATUS(ntError); } /* Cleanup for next loop */ if (pszCursor) { *pszCursor = '/'; } if ((pszComponent = strchr(pszComponent, '/')) != NULL) { pszComponent++; } } /* Did we finish? */ if ((Length <= 0) && (pszComponent != NULL)) { ntError = STATUS_NAME_TOO_LONG; BAIL_ON_NT_STATUS(ntError); } *ppszResolvedPath = pszResolvedPath; pszResolvedPath = NULL; ntError = STATUS_SUCCESS; cleanup: RtlCStringFree(&pszPath); RtlCStringFree(&pszWorkingPath); RtlCStringFree(&pszResWorkingPath); RtlCStringFree(&pszResolvedPath); if (pDir) { PvfsSysCloseDir(pDir); } return ntError; error: goto cleanup; }
NTSTATUS PvfsSysOpenByFileName( OUT int *pFd, OUT PBOOLEAN pbCreateOwnerFile, IN PPVFS_FILE_NAME pFileName, IN int iFlags, IN mode_t Mode ) { NTSTATUS ntError = STATUS_SUCCESS; int fd = -1; int unixerr = 0; PSTR pszFilename = NULL; PVFS_STAT Stat = {0}; int Ownerfd = -1; PSTR pszStreamDirectoryName = NULL; PSTR pszMetadataPath = NULL; BOOLEAN bCreateOwnerFile = FALSE; // Need make sure the object (file/directory) exists // Before non-default stream objects can be created if (!PvfsIsDefaultStreamName(pFileName)) { ntError = PvfsSysStat(pFileName->FileName, &Stat); if (LW_STATUS_OBJECT_NAME_NOT_FOUND == ntError) { ntError = PvfsSysOpen( &Ownerfd, pFileName->FileName, iFlags, Mode); if (STATUS_SUCCESS == ntError) { bCreateOwnerFile = TRUE; } } BAIL_ON_NT_STATUS(ntError); ntError = PvfsLookupStreamDirectoryPath(&pszStreamDirectoryName, pFileName); BAIL_ON_NT_STATUS(ntError); ntError = PvfsFileDirname(&pszMetadataPath, pszStreamDirectoryName); BAIL_ON_NT_STATUS(ntError); ntError = PvfsSysOpenDir(pszMetadataPath, NULL); if (LW_STATUS_OBJECT_NAME_NOT_FOUND == ntError) { // create meta data directory ntError = PvfsSysMkDir( pszMetadataPath, (mode_t)gPvfsDriverConfig.CreateDirectoryMode); BAIL_ON_NT_STATUS(ntError); } BAIL_ON_NT_STATUS(ntError); ntError = PvfsSysOpenDir(pszStreamDirectoryName, NULL); if (LW_STATUS_OBJECT_NAME_NOT_FOUND == ntError) { // create stream directory for an object ntError = PvfsSysMkDir( pszStreamDirectoryName, (mode_t)gPvfsDriverConfig.CreateDirectoryMode); BAIL_ON_NT_STATUS(ntError); } BAIL_ON_NT_STATUS(ntError); ntError = LwRtlCStringAllocatePrintf( &pszFilename, "%s/%s", pszStreamDirectoryName, PvfsGetCStringBaseStreamName(pFileName)); BAIL_ON_NT_STATUS(ntError); } else { ntError = LwRtlCStringDuplicate(&pszFilename, PvfsGetCStringBaseFileName(pFileName)); BAIL_ON_NT_STATUS(ntError); } if ((fd = open(pszFilename, iFlags, Mode)) == -1) { PVFS_BAIL_ON_UNIX_ERROR(unixerr, ntError); } *pFd = fd; *pbCreateOwnerFile = bCreateOwnerFile; cleanup: if (pszFilename) { LwRtlCStringFree(&pszFilename); } if (pszStreamDirectoryName) { LwRtlCStringFree(&pszStreamDirectoryName); } if (pszMetadataPath) { LwRtlCStringFree(&pszMetadataPath); } if (Ownerfd != -1) { PvfsSysClose(Ownerfd); } return ntError; error: if (fd != -1) { PvfsSysClose(fd); } goto cleanup; }
NTSTATUS PvfsEnumerateDirectory( PPVFS_CCB pCcb, PIO_MATCH_FILE_SPEC pFileSpec, LONG Count, BOOLEAN bRescan ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; DIR *pDir = NULL; struct dirent *pDirEntry = NULL; struct dirent dirEntry = { 0 }; PSTR pszPattern = NULL; BOOLEAN bCaseSensitive = FALSE; PSTR pszDiskFilename = NULL; PVFS_STAT Stat = { 0 }; PSTR pszResolvedDirname = NULL; PSTR pszResolvedFilename = NULL; if (Count == 0) { ntError = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntError); } ntError = AllocateCStringFileSpec(&pszPattern, pFileSpec); BAIL_ON_NT_STATUS(ntError); if (bRescan) { if (pCcb->pDirContext->pDir) { PvfsSysCloseDir(pCcb->pDirContext->pDir); } PvfsFreeDirectoryContext(pCcb->pDirContext); pCcb->pDirContext = NULL; ntError = PvfsAllocateMemory( (PVOID)&pCcb->pDirContext, sizeof(PVFS_DIRECTORY_CONTEXT), TRUE); BAIL_ON_NT_STATUS(ntError); pCcb->pDirContext->bScanned = FALSE; } if (!pCcb->pDirContext->bScanned) { if (!strchr(pszPattern, '?') && !strchr(pszPattern, '*')) { // A single file name match is the equivalent of a Windows Stat() ntError = PvfsLookupFile( &pszDiskFilename, &Stat, pCcb->pScb->pOwnerFcb->pszFilename, pszPattern, pFileSpec->Options & IO_NAME_OPTION_CASE_SENSITIVE); BAIL_ON_NT_STATUS(ntError); ntError = PvfsFileSplitPath( &pszResolvedDirname, &pszResolvedFilename, pszDiskFilename); BAIL_ON_NT_STATUS(ntError); if (IsSetFlag(pCcb->Flags, PVFS_CCB_FLAG_ENABLE_ABE)) { ntError = PvfsAccessCheckFileEnumerate( pCcb, pszResolvedFilename); BAIL_ON_NT_STATUS(ntError); } ntError = PvfsDirContextAddEntry( pCcb->pDirContext, pszResolvedFilename); BAIL_ON_NT_STATUS(ntError); pCcb->pDirContext->bScanned = TRUE; // Success goto cleanup; } else { // Prepare to enumerate the entire directory ntError = PvfsSysOpenDir( pCcb->pScb->pOwnerFcb->pszFilename, &pCcb->pDirContext->pDir); BAIL_ON_NT_STATUS(ntError); pCcb->pDirContext->bScanned = TRUE; } } /* Loop to read entries */ pDir = pCcb->pDirContext->pDir; /* -1 means to fill in whatever you can including current and parent directory entries */ if (Count == -1) { /* Always add '.' and '..' first if thet match */ if (PvfsWildcardMatch(".", pszPattern, FALSE)) { ntError = PvfsDirContextAddEntry(pCcb->pDirContext, "."); BAIL_ON_NT_STATUS(ntError); } if (PvfsWildcardMatch("..", pszPattern, FALSE)) { ntError = PvfsDirContextAddEntry(pCcb->pDirContext, ".."); BAIL_ON_NT_STATUS(ntError); } } /* Loop through directory entries */ for(ntError = PvfsSysReadDir(pDir, &dirEntry, &pDirEntry); pDirEntry && ((Count == -1) || (pCcb->pDirContext->dwNumEntries < Count)); ntError = PvfsSysReadDir(pDir, &dirEntry, &pDirEntry)) { /* First check the error return */ BAIL_ON_NT_STATUS(ntError); /* We've already added the "." and ".." directories */ if (RtlCStringIsEqual(pDirEntry->d_name, ".", FALSE) || RtlCStringIsEqual(pDirEntry->d_name, "..", FALSE)) { continue; } if (PvfsWildcardMatch(pDirEntry->d_name, pszPattern, bCaseSensitive)) { if (IsSetFlag(pCcb->Flags, PVFS_CCB_FLAG_ENABLE_ABE)) { ntError = PvfsAccessCheckFileEnumerate( pCcb, pDirEntry->d_name); if (ntError != STATUS_SUCCESS) { continue; } } ntError = PvfsDirContextAddEntry(pCcb->pDirContext, pDirEntry->d_name); BAIL_ON_NT_STATUS(ntError); } } /* Bail if there were no matches */ if (pCcb->pDirContext->dwNumEntries == 0) { ntError = STATUS_NO_SUCH_FILE; BAIL_ON_NT_STATUS(ntError); } cleanup: RtlCStringFree(&pszResolvedFilename); RtlCStringFree(&pszResolvedDirname); RtlCStringFree(&pszDiskFilename); RtlCStringFree(&pszPattern); return ntError; error: goto cleanup; }