diff --git a/sc2/src/sc2code/libs/uio/debug.c b/sc2/src/sc2code/libs/uio/debug.c index e416968fd..6b1d170ae 100644 --- a/sc2/src/sc2code/libs/uio/debug.c +++ b/sc2/src/sc2code/libs/uio/debug.c @@ -63,6 +63,7 @@ static int debugCmdLs(DebugContext *debugContext, int argc, char *argv[]); static int debugCmdMem(DebugContext *debugContext, int argc, char *argv[]); static int debugCmdMkDir(DebugContext *debugContext, int argc, char *argv[]); static int debugCmdMount(DebugContext *debugContext, int argc, char *argv[]); +static int debugCmdMv(DebugContext *debugContext, int argc, char *argv[]); static int debugCmdPwd(DebugContext *debugContext, int argc, char *argv[]); static int debugCmdRm(DebugContext *debugContext, int argc, char *argv[]); static int debugCmdRmDir(DebugContext *debugContext, int argc, char *argv[]); @@ -92,6 +93,7 @@ DebugCommand debugCommands[] = { { "mem", debugCmdMem }, { "mkdir", debugCmdMkDir }, { "mount", debugCmdMount }, + { "mv", debugCmdMv }, { "pwd", debugCmdPwd }, { "rm", debugCmdRm }, { "rmdir", debugCmdRmDir }, @@ -634,6 +636,24 @@ debugCmdMount(DebugContext *debugContext, int argc, char *argv[]) { return 0; } +static int +debugCmdMv(DebugContext *debugContext, int argc, char *argv[]) { + int retVal; + + if (argc != 3) { + fprintf(debugContext->err, "Invalid number of arguments.\n"); + return 1; + } + + retVal = uio_rename(debugContext->cwd, argv[1], + debugContext->cwd, argv[2]); + if (retVal == -1) { + fprintf(debugContext->err, "Could not rename: %s\n", strerror(errno)); + return 1; + } + return 0; +} + static int debugCmdPwd(DebugContext *debugContext, int argc, char *argv[]) { uio_DirHandle_print(debugContext->cwd, debugContext->out); diff --git a/sc2/src/sc2code/libs/uio/doc/todo b/sc2/src/sc2code/libs/uio/doc/todo index d3c3de46e..dae859a1c 100644 --- a/sc2/src/sc2code/libs/uio/doc/todo +++ b/sc2/src/sc2code/libs/uio/doc/todo @@ -35,6 +35,9 @@ Bugs: - uio_Stream file might get unaligned (not sure). - 'openDir(repository, "dir/")' will have the trailing '/' in the dirHandle, which will cause problems. +- uio_rename() doesn't work on directories + uio_GetPhysicalAccess() needs to be changed so that it works the same on + dirs as on files. stat() can be cleaned up too then. Extra features (not necessary for UQM): - Make functions to use for uio_malloc, uio_free and uio_realloc @@ -56,6 +59,11 @@ Extra features (not necessary for UQM): is accessed with the long vs the short ("PROGRA~1") name, or when capitalisation is involved. - accept non-dir, non-regular-file dir entries in stdio. +- Add non-merging mounts. Make 'merging' an option for the mount. +- make uio_rename() work cross-fs, or provide a wrapper which does that. + (the system rename() doesn't work cross-fs either, so keeping uio_rename() + as it is makes sense, as I'm trying to stay close to the system functions, + even though hiding file systems from the user would be nicer) Optimisations (not necessary for UQM): - use mmap for fileBlocks diff --git a/sc2/src/sc2code/libs/uio/fstypes.h b/sc2/src/sc2code/libs/uio/fstypes.h index 8a7416e54..27986d6fe 100644 --- a/sc2/src/sc2code/libs/uio/fstypes.h +++ b/sc2/src/sc2code/libs/uio/fstypes.h @@ -65,10 +65,12 @@ struct uio_FileSystemHandler { int (*fstat) (uio_Handle *, struct stat *); int (*stat) (uio_PDirHandle *, const char *, struct stat *); - uio_PDirHandle * (*mkdir) (uio_PDirHandle *, const char *, mode_t); - uio_Handle * (*open) (uio_PDirHandle *, const char *, int, + uio_PDirHandle * (*mkdir) (uio_PDirHandle *, const char *, mode_t); + uio_Handle * (*open) (uio_PDirHandle *, const char *, int, mode_t); ssize_t (*read) (uio_Handle *, void *, size_t); + int (*rename) (uio_PDirHandle *, const char *, + uio_PDirHandle *, const char *); int (*rmdir) (uio_PDirHandle *, const char *); off_t (*seek) (uio_Handle *, off_t, int); ssize_t (*write) (uio_Handle *, const void *, size_t); diff --git a/sc2/src/sc2code/libs/uio/io.c b/sc2/src/sc2code/libs/uio/io.c index f895fe436..c5c8fb5af 100644 --- a/sc2/src/sc2code/libs/uio/io.c +++ b/sc2/src/sc2code/libs/uio/io.c @@ -329,6 +329,81 @@ uio_close(uio_Handle *handle) { return 0; } +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, &oldName) == -1) { + // errno is set + return -1; + } + + if (uio_getPhysicalAccess(newDir, newPath, O_WRONLY | O_CREAT | O_EXCL, + uio_GPA_NOWRITE, &newReadMountInfo, &newPReadDir, + &newWriteMountInfo, &newPWriteDir, &newName) == -1) { + int saveErrno = errno; + uio_PDirHandle_unref(oldPReadDir); + uio_free(oldName); + errno = saveErrno; + 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)) { + 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, newPReadDir, newName); + if (retVal == -1) { + int saveErrno = errno; + uio_PDirHandle_unref(oldPReadDir); + uio_PDirHandle_unref(newPReadDir); + uio_PDirHandle_unref(newPWriteDir); + uio_free(oldName); + uio_free(newName); + errno = saveErrno; + return -1; + } + + uio_PDirHandle_unref(oldPReadDir); + uio_PDirHandle_unref(newPReadDir); + uio_PDirHandle_unref(newPWriteDir); + uio_free(oldName); + uio_free(newName); + return 0; +} + int uio_fstat(uio_Handle *handle, struct stat *statBuf) { if (handle->root->handler->fstat == NULL) { @@ -345,7 +420,7 @@ uio_stat(uio_DirHandle *dir, const char *path, struct stat *statBuf) { char *name; int result; - if (uio_getPhysicalAccess(dir, path, O_RDONLY, + if (uio_getPhysicalAccess(dir, path, O_RDONLY, 0, &readMountInfo, &pReadDir, NULL, NULL, &name) == -1) { if (uio_statDir(dir, path, statBuf) == -1) { @@ -435,7 +510,7 @@ uio_mkdir(uio_DirHandle *dir, const char *path, mode_t mode) { char *name; uio_PDirHandle *newDirHandle; - if (uio_getPhysicalAccess(dir, path, O_WRONLY | O_CREAT | O_EXCL, + if (uio_getPhysicalAccess(dir, path, O_WRONLY | O_CREAT | O_EXCL, 0, &readMountInfo, &pReadDir, &writeMountInfo, &pWriteDir, &name) == -1) { // errno is set @@ -474,7 +549,7 @@ uio_open(uio_DirHandle *dir, const char *path, int flags, mode_t mode) { char *name; uio_Handle *handle; - if (uio_getPhysicalAccess(dir, path, flags, + if (uio_getPhysicalAccess(dir, path, flags, 0, &readMountInfo, &readPDirHandle, &writeMountInfo, &writePDirHandle, &name) == -1) { // errno is set diff --git a/sc2/src/sc2code/libs/uio/io.h b/sc2/src/sc2code/libs/uio/io.h index 036b8c0af..6ab56dafe 100644 --- a/sc2/src/sc2code/libs/uio/io.h +++ b/sc2/src/sc2code/libs/uio/io.h @@ -94,6 +94,10 @@ uio_Handle *uio_open(uio_DirHandle *dir, const char *file, int flags, // Close a file descriptor for a file opened by uio_open int uio_close(uio_Handle *handle); +// Rename or move a file or directory. +int uio_rename(uio_DirHandle *oldDir, const char *oldPath, + uio_DirHandle *newDir, const char *newPath); + // Fstat a file descriptor int uio_fstat(uio_Handle *handle, struct stat *statBuf); diff --git a/sc2/src/sc2code/libs/uio/ioaux.c b/sc2/src/sc2code/libs/uio/ioaux.c index e5d9ce0f8..deebdc8a3 100644 --- a/sc2/src/sc2code/libs/uio/ioaux.c +++ b/sc2/src/sc2code/libs/uio/ioaux.c @@ -257,6 +257,12 @@ copyError(int error, * Either O_RDONLY, O_RDWR, O_WRONLY. They may be * OR'd with other values accepted by open(). These * are ignored. + * extraFlags - either 0 or uio_GPA_NOWRITE + * When 0, the path will be created if it doesn't + * exist in the writing location, but does exist + * in the reading location. With uio_GPA_NOWRITE, it + * won't be created, and -1 will be returned and errno + * will be set to ENOENT. * mountInfoReadPtr - pointer to location where the pointer * to the MountInfo structure for the reading location * should be stored. @@ -272,8 +278,8 @@ copyError(int error, * to by readPDirHandlePtr, the handles will be the * same too. * restPtr - pointer to a newly created string with as contents - * the last component of 'path'. - * The caller is responsible for freeing this. + * the last component of 'path'. + * The caller is responsible for freeing this. * Returns: 0 - success * -1 - failure (errno set) * NB: This is the function that would most benefit from @@ -283,7 +289,7 @@ copyError(int error, */ int uio_getPhysicalAccess(uio_DirHandle *dirHandle, const char *path, - int flags, + int flags, int extraFlags, uio_MountInfo **mountInfoReadPtr, uio_PDirHandle **readPDirHandlePtr, uio_MountInfo **mountInfoWritePtr, uio_PDirHandle **writePDirHandlePtr, char **restPtr) { @@ -433,6 +439,15 @@ uio_getPhysicalAccess(uio_DirHandle *dirHandle, const char *path, // There exists no path for a write dir, so it will have to be created. // writeMountInfo indicates the physical tree where it should end up. + + if (extraFlags & uio_GPA_NOWRITE) { + // The caller has specified that the path should not be created. + uio_PDirHandle_unref(readPDirHandle); + uio_free(fullPath); + errno = ENOENT; + return -1; + } + pRootPath = uio_mountTreeItemRestPath(writeItem, tree->lastComp, fullPath); diff --git a/sc2/src/sc2code/libs/uio/ioaux.h b/sc2/src/sc2code/libs/uio/ioaux.h index 68093631a..5a2e7e3a1 100644 --- a/sc2/src/sc2code/libs/uio/ioaux.h +++ b/sc2/src/sc2code/libs/uio/ioaux.h @@ -33,9 +33,10 @@ uio_PDirHandle *uio_makePath(uio_PDirHandle *pDirHandle, const char *path, int uio_copyFilePhysical(uio_PDirHandle *fromDir, const char *fromName, uio_PDirHandle *toDir, const char *toName); int uio_getPhysicalAccess(uio_DirHandle *dirHandle, const char *path, - int flags, uio_MountInfo **mountInfoReadPtr, + int flags, int extraFlags, uio_MountInfo **mountInfoReadPtr, uio_PDirHandle **readPDirHandlePtr, uio_MountInfo **mountInfoWritePtr, uio_PDirHandle **writePDirHandlePtr, char **restPtr); +#define uio_GPA_NOWRITE 1 int uio_getPathPhysicalDirs(uio_DirHandle *dirHandle, const char *path, size_t pathLen, uio_PDirHandle ***resPDirHandles, int *resNumPDirHandles, uio_MountTreeItem ***resItems); diff --git a/sc2/src/sc2code/libs/uio/stdio/stdio.c b/sc2/src/sc2code/libs/uio/stdio/stdio.c index dbc0d0a9b..cc85e47f3 100644 --- a/sc2/src/sc2code/libs/uio/stdio/stdio.c +++ b/sc2/src/sc2code/libs/uio/stdio/stdio.c @@ -18,6 +18,9 @@ * */ +// The GPDir structures and functions are used for caching only. + + #include "./stdio.h" #ifdef WIN32 @@ -71,6 +74,7 @@ uio_FileSystemHandler stdio_fileSystemHandler = { /* .mkdir = */ stdio_mkdir, /* .open = */ stdio_open, /* .read = */ stdio_read, + /* .rename = */ stdio_rename, /* .rmdir = */ stdio_rmdir, /* .seek = */ stdio_seek, /* .write = */ stdio_write, @@ -201,10 +205,12 @@ stdio_open(uio_PDirHandle *pDirHandle, const char *file, int flags, } uio_free(path); +#if 0 if (flags & O_CREAT) { if (uio_GPDir_getGPDirEntry(pDirHandle->extra, file) == NULL) stdio_addFile(pDirHandle->extra, file); } +#endif handle = uio_malloc(sizeof (stdio_Handle)); handle->fd = fd; @@ -217,6 +223,53 @@ stdio_read(uio_Handle *handle, void *buf, size_t count) { return read(handle->native->fd, buf, count); } +int +stdio_rename(uio_PDirHandle *oldPDirHandle, const char *oldName, + uio_PDirHandle *newPDirHandle, const char *newName) { + char *newPath, *oldPath; + int result; + + oldPath = joinPaths(stdio_getPath(oldPDirHandle->extra), oldName); + if (oldPath == NULL) { + // errno is set + return -1; + } + + newPath = joinPaths(stdio_getPath(newPDirHandle->extra), newName); + if (newPath == NULL) { + // errno is set + uio_free(oldPath); + return -1; + } + + result = rename(oldPath, newPath); + if (result == -1) { + int saveErrno = errno; + uio_free(oldPath); + uio_free(newPath); + errno = saveErrno; + return -1; + } + + uio_free(oldPath); + uio_free(newPath); + + { + // update the GPDir structure + uio_GPDirEntry *entry; + + // TODO: add locking + entry = uio_GPDir_getGPDirEntry(oldPDirHandle->extra, oldName); + if (entry != NULL) { + uio_GPDirEntries_remove(oldPDirHandle->extra->entries, oldName); + uio_GPDirEntries_add(newPDirHandle->extra->entries, newName, + entry); + } + } + + return result; +} + int stdio_rmdir(uio_PDirHandle *pDirHandle, const char *name) { char *path; diff --git a/sc2/src/sc2code/libs/uio/stdio/stdio.h b/sc2/src/sc2code/libs/uio/stdio/stdio.h index a1145fd29..a5a16735b 100644 --- a/sc2/src/sc2code/libs/uio/stdio/stdio.h +++ b/sc2/src/sc2code/libs/uio/stdio/stdio.h @@ -87,6 +87,8 @@ int stdio_fstat(uio_Handle *handle, struct stat *statBuf); int stdio_stat(uio_PDirHandle *pDirHandle, const char *name, struct stat *statBuf); ssize_t stdio_read(uio_Handle *handle, void *buf, size_t count); +int stdio_rename(uio_PDirHandle *oldPDirHandle, const char *oldName, + uio_PDirHandle *newPDirHandle, const char *newName); int stdio_rmdir(uio_PDirHandle *pDirHandle, const char *name); off_t stdio_seek(uio_Handle *handle, off_t offset, int whence); ssize_t stdio_write(uio_Handle *handle, const void *buf, size_t count); diff --git a/sc2/src/sc2code/libs/uio/zip/zip.c b/sc2/src/sc2code/libs/uio/zip/zip.c index fa975c08a..6c273a1b7 100644 --- a/sc2/src/sc2code/libs/uio/zip/zip.c +++ b/sc2/src/sc2code/libs/uio/zip/zip.c @@ -102,6 +102,7 @@ uio_FileSystemHandler zip_fileSystemHandler = { /* .mkdir = */ NULL, /* .open = */ zip_open, /* .read = */ zip_read, + /* .rename = */ NULL, /* .rmdir = */ NULL, /* .seek = */ zip_seek, /* .write = */ NULL,