NTSTATUS PvfsCanonicalPathName( PSTR *ppszPath, IO_FILE_NAME IoPath ) { PPVFS_CCB pRootCcb = NULL; NTSTATUS ntError = STATUS_SUCCESS; PSTR pszFilename = NULL; PSTR pszCompletePath = NULL; if (IoPath.FileName) { ntError = PvfsWC16CanonicalPathName(&pszFilename, IoPath.FileName); BAIL_ON_NT_STATUS(ntError); } if (IoPath.RootFileHandle) { ntError = PvfsAcquireCCB(IoPath.RootFileHandle, &pRootCcb); BAIL_ON_NT_STATUS(ntError); ntError = LwRtlCStringAllocatePrintf( &pszCompletePath, "%s%s%s", pRootCcb->pszFilename, (pszFilename ? (*pszFilename == '/' ? "" : "/") : ""), (pszFilename ? pszFilename : "")); BAIL_ON_NT_STATUS(ntError); } else { pszCompletePath = pszFilename; pszFilename = NULL; } if (!pszCompletePath) { ntError = STATUS_OBJECT_NAME_INVALID; BAIL_ON_NT_STATUS(ntError); } *ppszPath = pszCompletePath; cleanup: LwRtlCStringFree(&pszFilename); if (pRootCcb) { PvfsReleaseCCB(pRootCcb); } return ntError; error: LwRtlCStringFree(&pszCompletePath); goto cleanup; }
VOID NtRegCloseConfig( PLWREG_CONFIG_REG pReg ) { if (pReg) { LwRtlCStringFree(&pReg->pszConfigKey); LwRtlCStringFree(&pReg->pszPolicyKey); if (pReg->hConnection) { if ( pReg->hKey ) { NtRegCloseKey(pReg->hConnection, pReg->hKey); pReg->hKey = NULL; } NtRegCloseServer(pReg->hConnection); pReg->hConnection = NULL; } RTL_FREE(&pReg); } }
NTSTATUS PvfsSysStatByFileName( IN PPVFS_FILE_NAME FileName, IN OUT PPVFS_STAT Stat ) { NTSTATUS ntError = STATUS_SUCCESS; PSTR fileName = NULL; ntError = PvfsLookupStreamDiskFileName(&fileName, FileName); BAIL_ON_NT_STATUS(ntError); ntError = PvfsSysStat(fileName, Stat); BAIL_ON_NT_STATUS(ntError); cleanup: if (fileName) { LwRtlCStringFree(&fileName); } return ntError; error: goto cleanup; }
NTSTATUS PvfsSysMkDirByFileName( IN PPVFS_FILE_NAME DirectoryName, mode_t mode ) { NTSTATUS ntError = STATUS_SUCCESS; PSTR directoryName = NULL; PVFS_BAIL_ON_INVALID_FILENAME(DirectoryName, ntError); // Data stream is not directory if (!PvfsIsDefaultStreamName(DirectoryName)) { ntError = STATUS_NOT_A_DIRECTORY; BAIL_ON_NT_STATUS(ntError); } ntError = PvfsLookupStreamDiskFileName(&directoryName, DirectoryName); BAIL_ON_NT_STATUS(ntError); ntError = PvfsSysMkDir(directoryName, mode); BAIL_ON_NT_STATUS(ntError); error: if (directoryName) { LwRtlCStringFree(&directoryName); } return ntError; }
NTSTATUS PvfsSysChownByFileName( IN PPVFS_FILE_NAME pFileName, uid_t uid, gid_t gid ) { NTSTATUS ntError = STATUS_SUCCESS; int unixerr = 0; PSTR pszFilename = NULL; ntError = PvfsLookupStreamDiskFileName(&pszFilename, pFileName); BAIL_ON_NT_STATUS(ntError); if (chown(pszFilename, uid, gid) == -1) { PVFS_BAIL_ON_UNIX_ERROR(unixerr, ntError); } error: if (pszFilename) { LwRtlCStringFree(&pszFilename); } return ntError; }
static NTSTATUS PvfsFindParentFCB( PPVFS_FCB *ppParentFcb, PCSTR pszFilename ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PPVFS_FCB pFcb = NULL; PSTR pszDirname = NULL; PPVFS_CB_TABLE_ENTRY pBucket = NULL; if (LwRtlCStringIsEqual(pszFilename, "/", TRUE)) { ntError = STATUS_SUCCESS; *ppParentFcb = NULL; goto cleanup; } ntError = PvfsFileDirname(&pszDirname, pszFilename); BAIL_ON_NT_STATUS(ntError); ntError = PvfsCbTableGetBucket(&pBucket, &gPvfsDriverState.FcbTable, pszDirname); BAIL_ON_NT_STATUS(ntError); ntError = PvfsCbTableLookup((PPVFS_CONTROL_BLOCK*)OUT_PPVOID(&pFcb), pBucket, pszDirname); if (ntError == STATUS_OBJECT_NAME_NOT_FOUND) { ntError = PvfsCreateFCB( &pFcb, pszDirname, FALSE, 0, 0); } BAIL_ON_NT_STATUS(ntError); *ppParentFcb = PvfsReferenceFCB(pFcb); cleanup: if (pFcb) { PvfsReleaseFCB(&pFcb); } if (pszDirname) { LwRtlCStringFree(&pszDirname); } return ntError; error: goto cleanup; }
VOID SrvStatsConfigFreeContents( PSRV_STATISTICS_CONFIG pConfig ) { LwRtlCStringFree(&pConfig->pszProviderPath); memset(pConfig, 0, sizeof(*pConfig)); }
NTSTATUS NtRegReadConfigEnum( PLWREG_CONFIG_REG pReg, PCSTR pszName, BOOLEAN bUsePolicy, DWORD dwMin, DWORD dwMax, const PCSTR *ppszEnumNames, PDWORD pdwValue ) { NTSTATUS ntStatus = STATUS_SUCCESS; PSTR pszValue = NULL; DWORD dwEnumIndex = 0; ntStatus = NtRegReadConfigString( pReg, pszName, bUsePolicy, &pszValue, NULL); BAIL_ON_NT_STATUS(ntStatus); if (pszValue != NULL ) { for (dwEnumIndex = 0; dwEnumIndex <= dwMax - dwMin; dwEnumIndex++) { if(LwRtlCStringCompare( pszValue, ppszEnumNames[dwEnumIndex], FALSE) == 0) { *pdwValue = dwEnumIndex + dwMin; break; } } } cleanup: LwRtlCStringFree(&pszValue); return ntStatus; error: goto cleanup; }
DWORD DNSGetPtrNameForAddr( PSTR* ppszRecordName, PSOCKADDR_IN pAddr ) { DWORD dwError = 0; PSTR pszRecordName = NULL; DWORD dwIPV4Addr = ntohl(pAddr->sin_addr.s_addr); if (pAddr->sin_family != AF_INET) { dwError = LWDNS_ERROR_INVALID_IP_ADDRESS; BAIL_ON_LWDNS_ERROR(dwError); } dwError = LwRtlCStringAllocatePrintf( &pszRecordName, "%d.%d.%d.%d.in-addr.arpa", (dwIPV4Addr >> 0) & 255, (dwIPV4Addr >> 8) & 255, (dwIPV4Addr >> 16) & 255, (dwIPV4Addr >> 24) & 255 ); if (dwError) { dwError = ENOMEM; BAIL_ON_LWDNS_ERROR(dwError); } *ppszRecordName = pszRecordName; cleanup: return dwError; error: *ppszRecordName = NULL; LwRtlCStringFree(&pszRecordName); goto cleanup; }
static VOID PvfsNotifyFullReportCtxFree( PPVFS_NOTIFY_REPORT_RECORD *ppReport ) { PPVFS_NOTIFY_REPORT_RECORD pReport = NULL; if (ppReport && *ppReport) { pReport = (PPVFS_NOTIFY_REPORT_RECORD)*ppReport; if (pReport->pFcb) { PvfsReleaseFCB(&pReport->pFcb); } LwRtlCStringFree(&pReport->pszFilename); PVFS_FREE(ppReport); } return; }
NTSTATUS PvfsAccessCheckFileEnumerate( PPVFS_CCB pCcb, PCSTR pszRelativeFilename ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PACCESS_TOKEN pToken = pCcb->pUserToken; PSTR pszFilename = NULL; ACCESS_MASK AccessMask = 0; ACCESS_MASK GrantedAccess = 0; PSECURITY_DESCRIPTOR_ABSOLUTE pSecDesc = NULL; BYTE pRelativeSecDescBuffer[SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE]; ULONG ulRelativeSecDescLength = SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE; BOOLEAN bGranted = FALSE; SECURITY_INFORMATION SecInfo = (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION); ACCESS_MASK Desired = (FILE_READ_ATTRIBUTES| FILE_READ_EA| FILE_READ_DATA| READ_CONTROL); PSID pOwner = NULL; BOOLEAN bOwnerDefaulted = FALSE; /* Create the absolute path */ ntError = LwRtlCStringAllocatePrintf( &pszFilename, "%s/%s", pCcb->pScb->pOwnerFcb->pszFilename, pszRelativeFilename); BAIL_ON_NT_STATUS(ntError); /* Check the file object itself */ ntError = PvfsGetSecurityDescriptorFilename( pszFilename, SecInfo, (PSECURITY_DESCRIPTOR_RELATIVE)((PVOID)pRelativeSecDescBuffer), &ulRelativeSecDescLength); BAIL_ON_NT_STATUS(ntError); ntError = PvfsSecurityAclSelfRelativeToAbsoluteSD( &pSecDesc, (PSECURITY_DESCRIPTOR_RELATIVE)((PVOID)pRelativeSecDescBuffer)); BAIL_ON_NT_STATUS(ntError); // Tests against NTFS/Win2003R2 show that the file/directory object // owner is always granted FILE_READ_ATTRIBUTE ntError = RtlGetOwnerSecurityDescriptor( pSecDesc, &pOwner, &bOwnerDefaulted); BAIL_ON_NT_STATUS(ntError); if (RtlIsSidMemberOfToken(pToken, pOwner)) { ClearFlag(Desired, FILE_READ_ATTRIBUTES); SetFlag(GrantedAccess, FILE_READ_ATTRIBUTES); } /* Now check access */ bGranted = RtlAccessCheck( pSecDesc, pToken, Desired, GrantedAccess, &gPvfsDriverState.GenericSecurityMap, &AccessMask, &ntError); if (!bGranted) { ntError = STATUS_ACCESS_DENIED; } BAIL_ON_NT_STATUS(ntError); cleanup: if (pszFilename) { LwRtlCStringFree(&pszFilename); } if (pSecDesc) { PvfsFreeAbsoluteSecurityDescriptor(&pSecDesc); } return ntError; error: goto cleanup; }
NTSTATUS PvfsSysRemoveByFileName( IN PPVFS_FILE_NAME FileName ) { NTSTATUS ntError = STATUS_SUCCESS; PSTR fileName = NULL; PSTR streamDir = NULL; PVFS_STAT streamDirStat = { 0 }; PVFS_STAT fileStat = { 0 }; PSTR pszMetaDataPath = NULL; ntError = PvfsLookupStreamDiskFileName(&fileName, FileName); BAIL_ON_NT_STATUS(ntError); ntError = PvfsSysStat(fileName, &fileStat); if (ntError == STATUS_SUCCESS) { if(S_ISDIR(fileStat.s_mode)) { ntError = LwRtlCStringAllocatePrintf( &pszMetaDataPath, "%s/%s", fileName, PVFS_STREAM_METADATA_DIR_NAME); BAIL_ON_NT_STATUS(ntError); if (PvfsSysIsEmptyDir(pszMetaDataPath)) { ntError = PvfsSysRemove(pszMetaDataPath); BAIL_ON_NT_STATUS(ntError); } } } BAIL_ON_NT_STATUS(ntError); ntError = PvfsSysRemove(fileName); BAIL_ON_NT_STATUS(ntError); if (PvfsIsDefaultStreamName(FileName)) { // Have to remove the stream directory as well ntError = PvfsLookupStreamDirectoryPath(&streamDir, FileName); BAIL_ON_NT_STATUS(ntError); ntError = PvfsSysStat(streamDir, &streamDirStat); if (ntError == STATUS_SUCCESS) { ntError = PvfsSysRemoveDir(streamDir) ; BAIL_ON_NT_STATUS(ntError); } else { // Squash the error is the stream directory did not exist ntError = STATUS_SUCCESS; } BAIL_ON_NT_STATUS(ntError); } error: if (fileName) { LwRtlCStringFree(&fileName); } if (streamDir) { LwRtlCStringFree(&streamDir); } if (pszMetaDataPath) { LwRtlCStringFree(&pszMetaDataPath); } return ntError; }
NTSTATUS PvfsLookupPath( PSTR *ppszDiskPath, PCSTR pszPath, BOOLEAN bCaseSensitive ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PVFS_STAT Stat = {0}; PSTR pszDiskPath = NULL; /* Check the cache */ ntError = PvfsPathCacheLookup(&pszDiskPath, pszPath); if (ntError == STATUS_SUCCESS) { /* Check that the path is still good. If not fallback to manual checks */ ntError = PvfsSysStat(pszDiskPath, &Stat); if (ntError == STATUS_SUCCESS) { *ppszDiskPath = pszDiskPath; pszDiskPath = NULL; goto cleanup; } LwRtlCStringFree(&pszDiskPath); pszDiskPath = NULL; } /* See if we are lucky */ ntError = PvfsSysStat(pszPath, &Stat); if (ntError == STATUS_SUCCESS) { ntError = RtlCStringDuplicate(ppszDiskPath, pszPath); BAIL_ON_NT_STATUS(ntError); ntError = PvfsPathCacheAdd(*ppszDiskPath); BAIL_ON_NT_STATUS(ntError); goto cleanup; } /* Done if use case sensitive matches */ if (bCaseSensitive) { ntError = STATUS_OBJECT_NAME_NOT_FOUND; BAIL_ON_NT_STATUS(ntError); } /* Resolve the path */ ntError = PvfsResolvePath(ppszDiskPath, pszPath); BAIL_ON_NT_STATUS(ntError); /* This should succeed now */ ntError = PvfsSysStat(*ppszDiskPath, &Stat); BAIL_ON_NT_STATUS(ntError); cleanup: LwRtlCStringFree(&pszDiskPath); return ntError; error: LwRtlCStringFree(ppszDiskPath); goto cleanup; }
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 PvfsRenameFile( PPVFS_CCB pCcb, PPVFS_FILE_NAME pNewFileName ) { NTSTATUS ntError = STATUS_SUCCESS; PPVFS_CB_TABLE scbTable = &gPvfsDriverState.ScbTable; PPVFS_CB_TABLE_ENTRY pTargetBucket = NULL; PPVFS_CB_TABLE_ENTRY pCurrentBucket = NULL; BOOLEAN renameLock = FALSE; BOOLEAN targetBucketLock = FALSE; BOOLEAN currentBucketLock = FALSE; PPVFS_FCB pFcb = NULL; PLW_LIST_LINKS scbCursorLink = NULL; PPVFS_SCB scbCursor = NULL; BOOLEAN scbMutexLock = FALSE; BOOLEAN fcbListLocked = FALSE; PPVFS_FILE_NAME origTargetFileName = NULL; PPVFS_FILE_NAME scbCursorFileName = NULL; PSTR origFullStreamName = NULL; PSTR newFullStreamName = NULL; // The CCB holds out reference down the chain so no need to take a new one pFcb = pCcb->pScb->pOwnerFcb; ntError = PvfsAllocateFileNameFromScb(&origTargetFileName, pCcb->pScb); BAIL_ON_NT_STATUS(ntError); LWIO_LOCK_RWMUTEX_EXCLUSIVE(renameLock, &scbTable->rwLock); LWIO_LOCK_RWMUTEX_SHARED(fcbListLocked, &pFcb->rwScbLock); ntError = PvfsRenameFCB(pFcb, pCcb, pNewFileName); BAIL_ON_NT_STATUS(ntError); for (scbCursorLink = PvfsListTraverse(pFcb->pScbList, NULL); scbCursorLink; scbCursorLink = PvfsListTraverse(pFcb->pScbList, scbCursorLink)) { scbCursor = LW_STRUCT_FROM_FIELD( scbCursorLink, PVFS_SCB, FcbList); ntError = PvfsAllocateFileNameFromScb(&scbCursorFileName, scbCursor); BAIL_ON_NT_STATUS(ntError); ntError = PvfsAllocateCStringFromFileName( &newFullStreamName, scbCursorFileName); BAIL_ON_NT_STATUS(ntError); ntError = PvfsRenameBaseFileName( scbCursorFileName, PvfsGetCStringBaseFileName(origTargetFileName)); BAIL_ON_NT_STATUS(ntError); ntError = PvfsAllocateCStringFromFileName( &origFullStreamName, scbCursorFileName); BAIL_ON_NT_STATUS(ntError); pCurrentBucket = scbCursor->BaseControlBlock.pBucket; ntError = PvfsCbTableGetBucket(&pTargetBucket, scbTable, newFullStreamName); BAIL_ON_NT_STATUS(ntError); LWIO_LOCK_MUTEX(scbMutexLock, &scbCursor->BaseControlBlock.Mutex); LWIO_LOCK_RWMUTEX_EXCLUSIVE(currentBucketLock, &pCurrentBucket->rwLock); if (pCurrentBucket != pTargetBucket) { // Will be moved to a new bucket in the table LWIO_LOCK_RWMUTEX_EXCLUSIVE(targetBucketLock, &pTargetBucket->rwLock); } ntError = PvfsCbTableRemove_inlock( (PPVFS_CONTROL_BLOCK)scbCursor, origFullStreamName); LWIO_ASSERT(STATUS_SUCCESS == ntError); ntError = PvfsCbTableAdd_inlock( pTargetBucket, newFullStreamName, (PPVFS_CONTROL_BLOCK)scbCursor); if (STATUS_SUCCESS != ntError) { LWIO_LOG_ERROR( "Failed to rename stream \"%s\" (%s)\n", newFullStreamName, LwNtStatusToName(ntError)); } LWIO_UNLOCK_RWMUTEX(targetBucketLock, &pTargetBucket->rwLock); LWIO_UNLOCK_RWMUTEX(currentBucketLock, &pCurrentBucket->rwLock); LWIO_UNLOCK_MUTEX(scbMutexLock, &scbCursor->BaseControlBlock.Mutex); if (origFullStreamName) { LwRtlCStringFree(&origFullStreamName); } if (newFullStreamName) { LwRtlCStringFree(&newFullStreamName); } } error: LWIO_UNLOCK_MUTEX(scbMutexLock, &scbCursor->BaseControlBlock.Mutex); LWIO_UNLOCK_RWMUTEX(targetBucketLock, &pTargetBucket->rwLock); LWIO_UNLOCK_RWMUTEX(currentBucketLock, &pCurrentBucket->rwLock); LWIO_UNLOCK_RWMUTEX(fcbListLocked, &pFcb->rwScbLock); LWIO_UNLOCK_RWMUTEX(renameLock, &scbTable->rwLock); if (origTargetFileName) { PvfsFreeFileName(origTargetFileName); } if (origFullStreamName) { LwRtlCStringFree(&origFullStreamName); } if (newFullStreamName) { LwRtlCStringFree(&newFullStreamName); } return ntError; }
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 PvfsRenameFCB( PPVFS_FCB pFcb, PPVFS_CCB pCcb, PPVFS_FILE_NAME pNewFilename ) { NTSTATUS ntError = STATUS_SUCCESS; PPVFS_CB_TABLE fcbTable = &gPvfsDriverState.FcbTable; PPVFS_FCB pNewParentFcb = NULL; PPVFS_FCB pOldParentFcb = NULL; PPVFS_FCB pTargetFcb = NULL; PPVFS_CB_TABLE_ENTRY pTargetBucket = NULL; PPVFS_CB_TABLE_ENTRY pCurrentBucket = NULL; BOOLEAN currentFcbControl = FALSE; BOOLEAN targetFcbListLocked = FALSE; BOOLEAN targetBucketLocked = FALSE; BOOLEAN currentBucketLocked = FALSE; BOOLEAN fcbRwLocked = FALSE; BOOLEAN renameLock = FALSE; PPVFS_FILE_NAME currentFileName = NULL; /* If the target has an existing SCB, remove it from the Table and let the existing ref counters play out (e.g. pending change notifies. */ BAIL_ON_INVALID_PTR(pNewFilename, ntError); ntError = PvfsFindParentFCB(&pNewParentFcb, pNewFilename->FileName); BAIL_ON_NT_STATUS(ntError); ntError = PvfsAllocateFileNameFromScb(¤tFileName, pCcb->pScb); BAIL_ON_NT_STATUS(ntError); // Obtain all locks for the rename LWIO_LOCK_RWMUTEX_EXCLUSIVE(renameLock, &fcbTable->rwLock); LWIO_LOCK_MUTEX(currentFcbControl, &pFcb->BaseControlBlock.Mutex); pCurrentBucket = pFcb->BaseControlBlock.pBucket; ntError = PvfsCbTableGetBucket( &pTargetBucket, fcbTable, pNewFilename->FileName); BAIL_ON_NT_STATUS(ntError); LWIO_LOCK_RWMUTEX_EXCLUSIVE(currentBucketLocked, &pCurrentBucket->rwLock); if (pCurrentBucket != pTargetBucket) { LWIO_LOCK_RWMUTEX_EXCLUSIVE(targetBucketLocked, &pTargetBucket->rwLock); } // Do the rename work now ntError = PvfsCbTableLookup_inlock( (PPVFS_CONTROL_BLOCK*)OUT_PPVOID(&pTargetFcb), pTargetBucket, pNewFilename->FileName); if (ntError == STATUS_SUCCESS) { if (pTargetFcb != pFcb) { // Remove an existing FCB for the target file/stream (if one exists) // But make sure it is a different FCB LWIO_LOCK_RWMUTEX_SHARED(targetFcbListLocked, &pTargetFcb->rwScbLock); if (pTargetFcb->OpenHandleCount > 0 ) { // if TargetScb has open handles cannot rename // This except in the batch-oplock case ntError = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntError); } LWIO_UNLOCK_RWMUTEX(targetFcbListLocked, &pTargetFcb->rwScbLock); // TODO - How to get the Control Mutex without violating the // lock heirarchy? Does it matter at all ? ntError = PvfsRemoveStreamObjects(pTargetFcb); LWIO_ASSERT(STATUS_SUCCESS == ntError); ntError = PvfsCbTableRemove_inlock( (PPVFS_CONTROL_BLOCK)pTargetFcb, pTargetFcb->pszFilename); LWIO_ASSERT(STATUS_SUCCESS == ntError); } } ntError = PvfsSysRenameByFileName(currentFileName, pNewFilename); // Ignore the error here and continue ntError = PvfsPathCacheRemove(currentFileName); // Ignore the error here and continue /* Remove the SCB from the table, update the lookup key, and then re-add. Otherwise you will get memory corruption as a freed pointer gets left in the Table because if cannot be located using the current (updated) filename. Another reason to use the dev/inode pair instead if we could solve the "Create New File" issue. */ // Remove FCB ntError = PvfsCbTableRemove_inlock( (PPVFS_CONTROL_BLOCK)pFcb, pFcb->pszFilename); LWIO_ASSERT(STATUS_SUCCESS == ntError); // Rename FCB & Update parent links LWIO_LOCK_RWMUTEX_EXCLUSIVE(fcbRwLocked, &pFcb->BaseControlBlock.RwLock); LwRtlCStringFree(&pFcb->pszFilename); ntError = LwRtlCStringDuplicate(&pFcb->pszFilename, pNewFilename->FileName); BAIL_ON_NT_STATUS(ntError); if (pNewParentFcb != pFcb->pParentFcb) { pOldParentFcb = pFcb->pParentFcb; pFcb->pParentFcb = pNewParentFcb; pNewParentFcb = NULL; } LWIO_UNLOCK_RWMUTEX(fcbRwLocked, &pFcb->BaseControlBlock.RwLock); // Re-Add SCB ntError = PvfsCbTableAdd_inlock( pTargetBucket, pFcb->pszFilename, (PPVFS_CONTROL_BLOCK)pFcb); BAIL_ON_NT_STATUS(ntError); error: // Release all locks .. Whew! LWIO_UNLOCK_RWMUTEX(targetFcbListLocked, &pTargetFcb->rwScbLock); LWIO_UNLOCK_RWMUTEX(targetBucketLocked, &pTargetBucket->rwLock); LWIO_UNLOCK_RWMUTEX(currentBucketLocked, &pCurrentBucket->rwLock); LWIO_UNLOCK_RWMUTEX(fcbRwLocked, &pFcb->BaseControlBlock.RwLock); LWIO_UNLOCK_MUTEX(currentFcbControl, &pFcb->BaseControlBlock.Mutex); LWIO_UNLOCK_RWMUTEX(renameLock, &fcbTable->rwLock); if (pNewParentFcb) { PvfsReleaseFCB(&pNewParentFcb); } if (pOldParentFcb) { PvfsReleaseFCB(&pOldParentFcb); } if (pTargetFcb) { PvfsReleaseFCB(&pTargetFcb); } if (currentFileName) { PvfsFreeFileName(currentFileName); } return ntError; }
NTSTATUS PvfsRemoveStreamObjects( IN PPVFS_FCB pFcb ) { NTSTATUS status = STATUS_SUCCESS; BOOLEAN scbBucketLocked = FALSE; BOOLEAN scbLocked = FALSE; PLW_LIST_LINKS scbCursorLink = NULL; PPVFS_SCB scbCursor = NULL; PPVFS_FILE_NAME streamName = NULL; PSTR fullStreamName = NULL; PPVFS_CB_TABLE_ENTRY scbCursorBucket = NULL; for (scbCursorLink = PvfsListTraverse(pFcb->pScbList, NULL); scbCursorLink; scbCursorLink = PvfsListTraverse(pFcb->pScbList, scbCursorLink)) { scbCursor = LW_STRUCT_FROM_FIELD( scbCursorLink, PVFS_SCB, FcbList); LWIO_ASSERT(scbCursor->OpenHandleCount == 0); status = PvfsAllocateFileNameFromScb(&streamName, scbCursor); BAIL_ON_NT_STATUS(status); status = PvfsAllocateCStringFromFileName(&fullStreamName, streamName); BAIL_ON_NT_STATUS(status); LWIO_LOCK_MUTEX(scbLocked, &scbCursor->BaseControlBlock.Mutex); scbCursorBucket = scbCursor->BaseControlBlock.pBucket; LWIO_LOCK_RWMUTEX_EXCLUSIVE(scbBucketLocked, &scbCursorBucket->rwLock); status = PvfsCbTableRemove_inlock( (PPVFS_CONTROL_BLOCK)scbCursor, fullStreamName); LWIO_ASSERT(STATUS_SUCCESS == status); LWIO_UNLOCK_RWMUTEX(scbBucketLocked, &scbCursorBucket->rwLock); LWIO_UNLOCK_MUTEX(scbLocked, &scbCursor->BaseControlBlock.Mutex); if (streamName) { PvfsFreeFileName(streamName); streamName = NULL; } if (fullStreamName) { LwRtlCStringFree(&fullStreamName); } } error: LWIO_UNLOCK_RWMUTEX(scbBucketLocked, &scbCursorBucket->rwLock); LWIO_UNLOCK_MUTEX(scbLocked, &scbCursor->BaseControlBlock.Mutex); if (streamName) { PvfsFreeFileName(streamName); } if (fullStreamName) { LwRtlCStringFree(&fullStreamName); } return status; }
NTSTATUS PvfsSysRenameByFileName( IN PPVFS_FILE_NAME OriginalFileName, IN PPVFS_FILE_NAME NewFileName ) { NTSTATUS ntError = STATUS_SUCCESS; int unixerr = 0; PSTR oldFilename = NULL; PSTR newFilename = NULL; PSTR oldStreamDir = NULL; PSTR newStreamDir = NULL; PSTR newStreamDirParent = NULL; PVFS_STAT streamDirStat = { 0 }; ntError = PvfsLookupStreamDiskFileName(&oldFilename, OriginalFileName); BAIL_ON_NT_STATUS(ntError); ntError = PvfsLookupStreamDiskFileName(&newFilename, NewFileName); BAIL_ON_NT_STATUS(ntError); if (rename(oldFilename, newFilename) == -1 ) { PVFS_BAIL_ON_UNIX_ERROR(unixerr, ntError); } if (PvfsIsDefaultStreamName(OriginalFileName)) { // Have to rename the stream directory as well ntError = PvfsLookupStreamDirectoryPath(&oldStreamDir, OriginalFileName); BAIL_ON_NT_STATUS(ntError); ntError = PvfsLookupStreamDirectoryPath(&newStreamDir, NewFileName); BAIL_ON_NT_STATUS(ntError); ntError = PvfsSysStat(oldStreamDir, &streamDirStat); if (ntError == STATUS_SUCCESS) { ntError = PvfsFileDirname(&newStreamDirParent, newStreamDir); BAIL_ON_NT_STATUS(ntError); LwRtlZeroMemory(&streamDirStat, sizeof(streamDirStat)); ntError = PvfsSysStat(newStreamDirParent, &streamDirStat); switch (ntError) { case STATUS_SUCCESS: if (!S_ISDIR(streamDirStat.s_mode)) { ntError = STATUS_NOT_A_DIRECTORY; } break; case STATUS_OBJECT_NAME_NOT_FOUND: ntError = PvfsSysMkDir( newStreamDirParent, (mode_t)gPvfsDriverConfig.CreateDirectoryMode); break; default: break; } BAIL_ON_NT_STATUS(ntError); if (rename(oldStreamDir, newStreamDir) == -1) { // We are now in an inconstsent state -- What should we do? // We cannot safely roll back to the original name // as someone else may have it. Let's BAIL for now although // in the future we may decide that this should just log an error // but not fail PVFS_BAIL_ON_UNIX_ERROR(unixerr, ntError); } } // Squash the error is the stream directory did not exist ntError = STATUS_SUCCESS; } error: if (oldFilename) { LwRtlCStringFree(&oldFilename); } if (newFilename) { LwRtlCStringFree(&newFilename); } if (oldStreamDir) { LwRtlCStringFree(&oldStreamDir); } if (newStreamDir) { LwRtlCStringFree(&newStreamDir); } if (newStreamDirParent) { LwRtlCStringFree(&newStreamDirParent); } return ntError; }
NTSTATUS NtRegReadConfigMultiString( PLWREG_CONFIG_REG pReg, PCSTR pszName, BOOLEAN bUsePolicy, PSTR *ppszValue, PDWORD pdwSize ) { NTSTATUS ntStatus = STATUS_SUCCESS; BOOLEAN bGotValue = FALSE; PSTR pszValue = NULL; char szValue[MAX_VALUE_LENGTH]; DWORD dwType = 0; DWORD dwSize = 0; if (bUsePolicy) { if (!pReg->pszPolicyKey) { ntStatus = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntStatus); } dwSize = sizeof(szValue); memset(szValue, 0, dwSize); ntStatus = NtRegGetValueA( pReg->hConnection, pReg->hKey, pReg->pszPolicyKey, pszName, RRF_RT_REG_MULTI_SZ, &dwType, szValue, &dwSize); if (!ntStatus) { bGotValue = TRUE; } } if (!bGotValue ) { dwSize = sizeof(szValue); memset(szValue, 0, dwSize); ntStatus = NtRegGetValueA( pReg->hConnection, pReg->hKey, pReg->pszConfigKey, pszName, RRF_RT_REG_MULTI_SZ, &dwType, szValue, &dwSize); if (!ntStatus) { bGotValue = TRUE; } } if (bGotValue) { ntStatus = LW_RTL_ALLOCATE(&pszValue, char, dwSize); BAIL_ON_NT_STATUS(ntStatus); memcpy(pszValue, szValue, dwSize); LwRtlCStringFree(ppszValue); *ppszValue = pszValue; pszValue = NULL; if (pdwSize) { *pdwSize = dwSize; } } ntStatus = 0; cleanup: LwRtlCStringFree(&pszValue); return ntStatus; error: goto cleanup; }