int uio_stat(uio_DirHandle *dir, const char *path, struct stat *statBuf) { uio_PDirHandle *pReadDir; uio_MountInfo *readMountInfo; char *name; int result; if (uio_getPhysicalAccess(dir, path, O_RDONLY, 0, &readMountInfo, &pReadDir, NULL, NULL, NULL, NULL, &name) == -1) { if (uio_statDir(dir, path, statBuf) == -1) { // errno is set return -1; } return 0; } if (pReadDir->pRoot->handler->stat == NULL) { uio_PDirHandle_unref(pReadDir); uio_free(name); errno = ENOSYS; return -1; } result = (pReadDir->pRoot->handler->stat)(pReadDir, name, statBuf); uio_PDirHandle_unref(pReadDir); uio_free(name); return result; }
// Pre: there are no more references to PRoot or anything inside it. int uio_GPRoot_umount(uio_PRoot *pRoot) { uio_PDirHandle *topDirHandle; uio_GPDir *topDir; topDirHandle = uio_PRoot_getRootDirHandle(pRoot); topDir = topDirHandle->extra; if (pRoot->extra->flags & uio_GPRoot_PERSISTENT) uio_GPDir_deepPersistentUnref(topDir); uio_PDirHandle_unref(topDirHandle); (void) pRoot; return 0; }
int uio_mkdir(uio_DirHandle *dir, const char *path, mode_t mode) { uio_PDirHandle *pReadDir, *pWriteDir; uio_MountInfo *readMountInfo, *writeMountInfo; char *name; uio_PDirHandle *newDirHandle; if (uio_getPhysicalAccess(dir, path, O_WRONLY | O_CREAT | O_EXCL, 0, &readMountInfo, &pReadDir, NULL, &writeMountInfo, &pWriteDir, NULL, &name) == -1) { // errno is set if (errno == EISDIR) errno = EEXIST; return -1; } uio_PDirHandle_unref(pReadDir); if (pWriteDir->pRoot->handler->mkdir == NULL) { uio_free(name); uio_PDirHandle_unref(pWriteDir); errno = ENOSYS; return -1; } newDirHandle = (pWriteDir->pRoot->handler->mkdir)(pWriteDir, name, mode); if (newDirHandle == NULL) { int savedErrno = errno; uio_free(name); uio_PDirHandle_unref(pWriteDir); errno = savedErrno; return -1; } uio_PDirHandle_unref(pWriteDir); uio_PDirHandle_unref(newDirHandle); uio_free(name); return 0; }
// inPath and *outPath may point to the same location int uio_getFileLocation(uio_DirHandle *dir, const char *inPath, int flags, uio_MountHandle **mountHandle, char **outPath) { uio_PDirHandle *readPDirHandle, *writePDirHandle; uio_MountInfo *readMountInfo, *writeMountInfo, *mountInfo; char *name; char *readPRootPath, *writePRootPath, *pRootPath; if (uio_getPhysicalAccess(dir, inPath, flags, 0, &readMountInfo, &readPDirHandle, &readPRootPath, &writeMountInfo, &writePDirHandle, &writePRootPath, &name) == -1) { // errno is set return -1; } // TODO: This code is partly the same as the code in uio_open(). // probably some code could be put in a seperate function. if ((flags & O_ACCMODE) == O_RDONLY) { // WritePDirHandle is not filled in. uio_PDirHandle_unref(readPDirHandle); pRootPath = readPRootPath; mountInfo = readMountInfo; } else if (readPDirHandle == writePDirHandle) { // In general, the dirs can be the same even when the handles are // not the same. But here it works, because uio_getPhysicalAccess // guarantees it. uio_PDirHandle_unref(readPDirHandle); uio_PDirHandle_unref(writePDirHandle); pRootPath = readPRootPath; mountInfo = readMountInfo; uio_free(writePRootPath); } else { // need to write uio_PDirEntryHandle *entry; entry = uio_getPDirEntryHandle(readPDirHandle, name); if (entry != NULL) { // file already exists uio_PDirEntryHandle_unref(entry); if ((flags & O_CREAT) == O_CREAT && (flags & O_EXCL) == O_EXCL) { uio_free(name); uio_PDirHandle_unref(readPDirHandle); uio_free(readPRootPath); uio_PDirHandle_unref(writePDirHandle); uio_free(writePRootPath); errno = EEXIST; return -1; } if ((flags & O_TRUNC) == O_TRUNC) { // No use copying the file to the writable dir. // As it doesn't exists there, O_TRUNC needs to be turned off // though. flags &= ~O_TRUNC; } else { // file needs to be copied if (uio_copyFilePhysical(readPDirHandle, name, writePDirHandle, name) == -1) { int savedErrno = errno; uio_free(name); uio_PDirHandle_unref(readPDirHandle); uio_free(readPRootPath); uio_PDirHandle_unref(writePDirHandle); uio_free(writePRootPath); errno = savedErrno; return -1; } } } else { // file does not exist if (((flags & O_ACCMODE) == O_RDONLY) || (flags & O_CREAT) != O_CREAT) { uio_free(name); uio_PDirHandle_unref(readPDirHandle); uio_free(readPRootPath); uio_PDirHandle_unref(writePDirHandle); uio_free(writePRootPath); errno = ENOENT; return -1; } } uio_PDirHandle_unref(readPDirHandle); uio_PDirHandle_unref(writePDirHandle); pRootPath = writePRootPath; mountInfo = writeMountInfo; uio_free(readPRootPath); } uio_free(name); *mountHandle = mountInfo->mountHandle; *outPath = pRootPath; return 0; }
static void uio_PDirHandles_delete(uio_PDirHandle *pDirHandles[], int numPDirHandles) { while (numPDirHandles--) uio_PDirHandle_unref(pDirHandles[numPDirHandles]); uio_free(pDirHandles); }
uio_Handle * uio_open(uio_DirHandle *dir, const char *path, int flags, mode_t mode) { uio_PDirHandle *readPDirHandle, *writePDirHandle, *pDirHandle; uio_MountInfo *readMountInfo, *writeMountInfo; char *name; uio_Handle *handle; if (uio_getPhysicalAccess(dir, path, flags, 0, &readMountInfo, &readPDirHandle, NULL, &writeMountInfo, &writePDirHandle, NULL, &name) == -1) { // errno is set return NULL; } if ((flags & O_ACCMODE) == O_RDONLY) { // WritePDirHandle is not filled in. pDirHandle = readPDirHandle; } else if (readPDirHandle == writePDirHandle) { // In general, the dirs can be the same even when the handles are // not the same. But here it works, because uio_getPhysicalAccess // guarantees it. uio_PDirHandle_unref(writePDirHandle); pDirHandle = readPDirHandle; } else { // need to write uio_PDirEntryHandle *entry; entry = uio_getPDirEntryHandle(readPDirHandle, name); if (entry != NULL) { // file already exists uio_PDirEntryHandle_unref(entry); if ((flags & O_CREAT) == O_CREAT && (flags & O_EXCL) == O_EXCL) { uio_free(name); uio_PDirHandle_unref(readPDirHandle); uio_PDirHandle_unref(writePDirHandle); errno = EEXIST; return NULL; } if ((flags & O_TRUNC) == O_TRUNC) { // No use copying the file to the writable dir. // As it doesn't exists there, O_TRUNC needs to be turned off // though. flags &= ~O_TRUNC; } else { // file needs to be copied if (uio_copyFilePhysical(readPDirHandle, name, writePDirHandle, name) == -1) { int savedErrno = errno; uio_free(name); uio_PDirHandle_unref(readPDirHandle); uio_PDirHandle_unref(writePDirHandle); errno = savedErrno; return NULL; } } } else { // file does not exist if (((flags & O_ACCMODE) == O_RDONLY) || (flags & O_CREAT) != O_CREAT) { uio_free(name); uio_PDirHandle_unref(readPDirHandle); uio_PDirHandle_unref(writePDirHandle); errno = ENOENT; return NULL; } } uio_PDirHandle_unref(readPDirHandle); pDirHandle = writePDirHandle; } handle = (pDirHandle->pRoot->handler->open)(pDirHandle, name, flags, mode); // Also adds a new entry to the physical dir if appropriate. if (handle == NULL) { int savedErrno = errno; uio_free(name); uio_PDirHandle_unref(pDirHandle); errno = savedErrno; return NULL; } uio_free(name); uio_PDirHandle_unref(pDirHandle); return handle; }
int uio_rename(uio_DirHandle *oldDir, const char *oldPath, uio_DirHandle *newDir, const char *newPath) { uio_PDirHandle *oldPReadDir, *newPReadDir, *newPWriteDir; uio_MountInfo *oldReadMountInfo, *newReadMountInfo, *newWriteMountInfo; char *oldName, *newName; int retVal; if (uio_getPhysicalAccess(oldDir, oldPath, O_RDONLY, 0, &oldReadMountInfo, &oldPReadDir, NULL, NULL, NULL, NULL, &oldName) == -1) { // errno is set return -1; } if (uio_getPhysicalAccess(newDir, newPath, O_WRONLY | O_CREAT | O_EXCL, uio_GPA_NOWRITE, &newReadMountInfo, &newPReadDir, NULL, &newWriteMountInfo, &newPWriteDir, NULL, &newName) == -1) { int savedErrno = errno; uio_PDirHandle_unref(oldPReadDir); uio_free(oldName); errno = savedErrno; return -1; } if (oldReadMountInfo != newWriteMountInfo) { uio_PDirHandle_unref(oldPReadDir); uio_PDirHandle_unref(newPReadDir); uio_PDirHandle_unref(newPWriteDir); uio_free(oldName); uio_free(newName); errno = EXDEV; return -1; } if (uio_mountInfoIsReadOnly(oldReadMountInfo)) { // XXX: Doesn't uio_getPhysicalAccess already handle this? // It doesn't return EROFS though; perhaps it should. uio_PDirHandle_unref(oldPReadDir); uio_PDirHandle_unref(newPReadDir); uio_PDirHandle_unref(newPWriteDir); uio_free(oldName); uio_free(newName); errno = EROFS; return -1; } if (oldReadMountInfo->pDirHandle->pRoot->handler->rename == NULL) { uio_PDirHandle_unref(oldPReadDir); uio_PDirHandle_unref(newPReadDir); uio_PDirHandle_unref(newPWriteDir); uio_free(oldName); uio_free(newName); errno = ENOSYS; return -1; } retVal = (oldReadMountInfo->pDirHandle->pRoot->handler->rename)( oldPReadDir, oldName, newPWriteDir, newName); if (retVal == -1) { int savedErrno = errno; uio_PDirHandle_unref(oldPReadDir); uio_PDirHandle_unref(newPReadDir); uio_PDirHandle_unref(newPWriteDir); uio_free(oldName); uio_free(newName); errno = savedErrno; return -1; } uio_PDirHandle_unref(oldPReadDir); uio_PDirHandle_unref(newPReadDir); uio_PDirHandle_unref(newPWriteDir); uio_free(oldName); uio_free(newName); return 0; }
/* * Function name: uio_mountDir * Description: Grafts a directory from inside a physical fileSystem * into the locical filesystem, at a specified directory. * Arguments: destRep - the repository where the newly mounted dir * is to be grafted. * mountPoint - the path to the directory where the dir * is to be grafted. * fsType - the file system type of physical fileSystem * pointed to by sourcePath. * sourceDir - the directory to which 'sourcePath' is to * be taken relative. * sourcePath - a path relative to sourceDir, which contains * the file/directory to be mounted. * If sourceDir and sourcePath are NULL, the file * system of the operating system will be used. * inPath - the location relative to the root of the newly * mounted fileSystem, pointing to the directory * that is to be grafted. * Note: If fsType is uio_FSTYPE_STDIO, inPath is * relative to the root of the filesystem, NOT to * the current working dir. * autoMount - array of automount options in function * in this mountPoint. * flags - one of uio_MOUNT_TOP, uio_MOUNT_BOTTOM, * uio_MOUNT_BELOW, uio_MOUNT_ABOVE, specifying * the precedence of this mount, OR'ed with * one or more of the following flags: * uio_MOUNT_RDONLY (no writing is allowed) * relative - If 'flags' includes uio_MOUNT_BELOW or * uio_MOUNT_ABOVE, this is the mount handle * where the new mount is relative to. * Otherwise, it should be NULL. * Returns: a handle suitable for uio_unmountDir() * NULL if an error occured. In this case 'errno' is set. */ uio_MountHandle * uio_mountDir(uio_Repository *destRep, const char *mountPoint, uio_FileSystemID fsType, uio_DirHandle *sourceDir, const char *sourcePath, const char *inPath, uio_AutoMount **autoMount, int flags, uio_MountHandle *relative) { uio_PRoot *pRoot; uio_Handle *handle; uio_FileSystemHandler *handler; uio_MountInfo *relativeInfo; switch (flags & uio_MOUNT_LOCATION_MASK) { case uio_MOUNT_TOP: case uio_MOUNT_BOTTOM: if (relative != NULL) { errno = EINVAL; return NULL; } relativeInfo = NULL; break; case uio_MOUNT_BELOW: case uio_MOUNT_ABOVE: if (relative == NULL) { errno = EINVAL; return NULL; } relativeInfo = relative->mountInfo; break; default: abort(); } if (mountPoint[0] == '/') mountPoint++; if (!validPathName(mountPoint, strlen(mountPoint))) { errno = EINVAL; return NULL; } // TODO: check if the filesystem is already mounted, and if so, reuse it. // A RO filedescriptor will need to be replaced though if the // filesystem needs to be remounted RW now. if (sourceDir == NULL) { if (sourcePath != NULL) { // bad: sourceDir is NULL, but sourcePath isn't errno = EINVAL; return NULL; } handle = NULL; } else { if (sourcePath == NULL) { // bad: sourcePath is NULL, but sourceDir isn't errno = EINVAL; return NULL; } handle = uio_open(sourceDir, sourcePath, ((flags & uio_MOUNT_RDONLY) == uio_MOUNT_RDONLY ? O_RDONLY : O_RDWR) #ifdef WIN32 | O_BINARY #endif , 0); if (handle == NULL) { // errno is set return NULL; } } handler = uio_getFileSystemHandler(fsType); if (handler == NULL) { if (handle) uio_close(handle); errno = ENODEV; return NULL; } assert(handler->mount != NULL); pRoot = (handler->mount)(handle, flags); if (pRoot == NULL) { int savedErrno; savedErrno = errno; if (handle) uio_close(handle); errno = savedErrno; return NULL; } if (handle) { // Close this reference to handle. // The physical layer may store the link in pRoot, in which it // will be cleaned up from uio_unmount(). uio_close(handle); } // The new file system is ready, now we need to find the specified // dir inside it and put it in its place in the mountTree. { uio_PDirHandle *endDirHandle; const char *endInPath; char *dirName; uio_MountInfo *mountInfo; uio_MountTree *mountTree; uio_PDirHandle *pRootHandle; #ifdef BACKSLASH_IS_PATH_SEPARATOR char *unixPath; unixPath = dosToUnixPath(inPath); inPath = unixPath; #endif /* BACKSLASH_IS_PATH_SEPARATOR */ if (inPath[0] == '/') inPath++; pRootHandle = uio_PRoot_getRootDirHandle(pRoot); uio_walkPhysicalPath(pRootHandle, inPath, strlen(inPath), &endDirHandle, &endInPath); if (*endInPath != '\0') { // Path inside the filesystem to mount does not exist. #ifdef BACKSLASH_IS_PATH_SEPARATOR uio_free(unixPath); #endif /* BACKSLASH_IS_PATH_SEPARATOR */ uio_PDirHandle_unref(endDirHandle); uio_PRoot_unrefMount(pRoot); errno = ENOENT; return NULL; } dirName = uio_malloc(endInPath - inPath + 1); memcpy(dirName, inPath, endInPath - inPath); dirName[endInPath - inPath] = '\0'; #ifdef BACKSLASH_IS_PATH_SEPARATOR // InPath is a copy with the paths fixed. uio_free(unixPath); #endif /* BACKSLASH_IS_PATH_SEPARATOR */ mountInfo = uio_MountInfo_new(fsType, NULL, endDirHandle, dirName, autoMount, NULL, flags); uio_repositoryAddMount(destRep, mountInfo, flags & uio_MOUNT_LOCATION_MASK, relativeInfo); mountTree = uio_mountTreeAddMountInfo(destRep, destRep->mountTree, mountInfo, mountPoint, flags & uio_MOUNT_LOCATION_MASK, relativeInfo); // mountTree is the node in destRep->mountTree where mountInfo // leads to. mountInfo->mountTree = mountTree; mountInfo->mountHandle = uio_MountHandle_new(destRep, mountInfo); return mountInfo->mountHandle; } }
void uio_MountInfo_delete(uio_MountInfo *mountInfo) { uio_free(mountInfo->dirName); uio_PDirHandle_unref(mountInfo->pDirHandle); uio_MountInfo_free(mountInfo); }