diff --git a/sc2/src/sc2code/libs/uio/Makeinfo b/sc2/src/sc2code/libs/uio/Makeinfo index 02bb2a3ae..4b6a4e176 100644 --- a/sc2/src/sc2code/libs/uio/Makeinfo +++ b/sc2/src/sc2code/libs/uio/Makeinfo @@ -1,7 +1,8 @@ uqm_SUBDIRS="stdio" uqm_CFILES="charhashtable.c defaultfs.c fileblock.c fstypes.c gphys.c hashtable.c io.c ioaux.c match.c mount.c - mounttree.c paths.c physical.c uiostream.c uioutils.c" + mounttree.c paths.c physical.c uiostream.c uioutils.c + utils.c" if [ -n "$uqm_USE_ZIP_IO" ]; then uqm_SUBDIRS="$uqm_SUBDIRS zip" diff --git a/sc2/src/sc2code/libs/uio/debug.c b/sc2/src/sc2code/libs/uio/debug.c index e4aa69929..d65a71316 100644 --- a/sc2/src/sc2code/libs/uio/debug.c +++ b/sc2/src/sc2code/libs/uio/debug.c @@ -32,6 +32,7 @@ #include "debug.h" #include "uioport.h" #include "io.h" +#include "utils.h" #include "types.h" #include "mem.h" #include "uioutils.h" @@ -134,11 +135,11 @@ debugMountOne(uio_Repository *destRep, const char *mountPoint, mountHandle = uio_mountDir(destRep, mountPoint, fsType, sourceDir, sourcePath, inPath, autoMount, flags, relative); if (mountHandle == NULL) { - int saveErrno = errno; + int savedErrno = errno; fprintf(stderr, "Could not mount '%s' and graft '%s' from that " "into the repository at '%s': %s\n", sourcePath, inPath, mountPoint, strerror(errno)); - errno = saveErrno; + errno = savedErrno; } return mountHandle; } @@ -213,9 +214,15 @@ initRepository(void) { uio_closeDir(rootDir); } } + mountHandles[8] = debugMountOne(repository, "/tmp/", + uio_FSTYPE_STDIO, NULL, NULL, "/tmp/", autoMount, + uio_MOUNT_TOP, NULL); + +#if 1 mountHandles[8] = debugMountOne(repository, "/root/root/", uio_FSTYPE_STDIO, NULL, NULL, "/", autoMount, uio_MOUNT_TOP | uio_MOUNT_RDONLY, NULL); +#endif } @@ -432,40 +439,55 @@ debugCmdCd(DebugContext *debugContext, int argc, char *argv[]) { static int debugCmdExec(DebugContext *debugContext, int argc, char *argv[]) { int i; - char **newArgs; + const char **newArgs; int errCode = 0; + uio_StdioAccessHandle **handles; + uio_DirHandle *tempDir; if (argc < 2) { fprintf(debugContext->err, "Invalid number of arguments.\n"); return 1; } + tempDir = uio_openDirRelative(debugContext->cwd, "/tmp", 0); + if (tempDir == 0) { + fprintf(debugContext->err, "Could not open temp dir: %s.\n", + strerror(errno)); + return 1; + } + newArgs = uio_malloc(argc * sizeof (char *)); newArgs[0] = argv[1]; + handles = uio_malloc(argc * sizeof (uio_StdioAccessHandle *)); + handles[0] = NULL; for (i = 2; i < argc; i++) { - int retVal; - uio_FileSystemID fsID; - uio_MountHandle *mountHandle; - - retVal = uio_getFileLocation(debugContext->cwd, argv[i], O_RDONLY, - &mountHandle, &newArgs[i - 1]); - if (retVal == -1) { - // No match; we keep what's typed litterally. +#if 0 + if (argv[i][0] == '-') { + // Don't try to parse arguments that start with '-'. + // They are probably option flags. newArgs[i - 1] = argv[i]; - continue; } - - fsID = uio_getMountFileSystemType(mountHandle); - if (fsID != uio_FSTYPE_STDIO) { - // Wrong file system type. +#endif + handles[i - 1] = uio_getStdioAccess(debugContext->cwd, argv[i], + O_RDONLY, tempDir); + if (handles[i - 1] == NULL) { + if (errno == ENOENT) { + // No match; we keep what's typed litterally. + newArgs[i - 1] = argv[i]; + continue; + } + + // error fprintf(debugContext->err, - "Cannot execute: %s is not in a stdio filesystem.\n", - argv[i]); - errCode = 0; + "Cannot execute: Cannot get stdio access to %s: %s.\n", + argv[i], strerror(errno)); + errCode = 1; argc = i + 1; goto err; } + + newArgs[i - 1] = uio_StdioAccessHandle_getPath(handles[i - 1]); } newArgs[argc - 1] = NULL; @@ -486,7 +508,7 @@ debugCmdExec(DebugContext *debugContext, int argc, char *argv[]) { break; case 0: // child - execvp(newArgs[0], newArgs); + execvp(newArgs[0], (char * const *) newArgs); fprintf(debugContext->err, "Error: execvp() failed: %s.\n", strerror(errno)); _exit(EXIT_FAILURE); @@ -528,11 +550,13 @@ debugCmdExec(DebugContext *debugContext, int argc, char *argv[]) { #endif err: - for (i = 1; i < argc; i++) { - if (argv[i] != newArgs[i - 1]) - uio_free(newArgs[i - 1]); + for (i = 1; i < argc - 1; i++) { + if (handles[i] != NULL) + uio_releaseStdioAccess(handles[i]); } + uio_free(handles); uio_free(newArgs); + uio_closeDir(tempDir); return errCode; } @@ -822,11 +846,11 @@ debugCmdStat(DebugContext *debugContext, int argc, char *argv[]) { if (uio_stat(debugContext->cwd, argv[1], &statBuf) == -1) { // errno is set - int saveErrno; - saveErrno = errno; + int savedErrno; + savedErrno = errno; fprintf(debugContext->err, "Could not stat file: %s\n", strerror(errno)); - errno = saveErrno; + errno = savedErrno; return 1; } diff --git a/sc2/src/sc2code/libs/uio/doc/todo b/sc2/src/sc2code/libs/uio/doc/todo index 1e3ffcb2c..633453fbe 100644 --- a/sc2/src/sc2code/libs/uio/doc/todo +++ b/sc2/src/sc2code/libs/uio/doc/todo @@ -1,6 +1,9 @@ Needed before use in UQM: - documentation - configuring for HAVE_REGEX and GLOB +- when doing uio_getStdioPhysical(), if write access is required, but + not available on the original location, also copy the file to the + temporary dir. Documentation: - use doxygen @@ -35,6 +38,7 @@ Bugs: - uio_Stream file might get unaligned (not sure). - 'openDir(repository, "dir/")' will have the trailing '/' in the dirHandle, which will cause problems. +- 'openDirRelative(repository, "/")' causes segfaults lateron - 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. diff --git a/sc2/src/sc2code/libs/uio/io.c b/sc2/src/sc2code/libs/uio/io.c index a4b7478e8..6c186e22c 100644 --- a/sc2/src/sc2code/libs/uio/io.c +++ b/sc2/src/sc2code/libs/uio/io.c @@ -51,9 +51,9 @@ static inline void uio_PDirHandle_free(uio_PDirHandle *pDirHandle); static inline uio_PFileHandle *uio_PFileHandle_alloc(void); static inline void uio_PFileHandle_free(uio_PFileHandle *pFileHandle); -static uio_DirHandle *uio_newDirHandle(uio_Repository *repository, char *path, +static uio_DirHandle *uio_DirHandle_new(uio_Repository *repository, char *path, char *rootEnd); -static inline uio_DirHandle *uio_allocDirHandle(void); +static inline uio_DirHandle *uio_DirHandle_alloc(void); static inline void uio_DirHandle_free(uio_DirHandle *dirHandle); static inline uio_Handle *uio_Handle_alloc(void); @@ -354,10 +354,10 @@ uio_rename(uio_DirHandle *oldDir, const char *oldPath, if (uio_getPhysicalAccess(newDir, newPath, O_WRONLY | O_CREAT | O_EXCL, uio_GPA_NOWRITE, &newReadMountInfo, &newPReadDir, NULL, &newWriteMountInfo, &newPWriteDir, NULL, &newName) == -1) { - int saveErrno = errno; + int savedErrno = errno; uio_PDirHandle_unref(oldPReadDir); uio_free(oldName); - errno = saveErrno; + errno = savedErrno; return -1; } @@ -393,13 +393,13 @@ uio_rename(uio_DirHandle *oldDir, const char *oldPath, retVal = oldReadMountInfo->pDirHandle->pRoot->handler->rename( oldPReadDir, oldName, newPReadDir, newName); if (retVal == -1) { - int saveErrno = errno; + int savedErrno = errno; uio_PDirHandle_unref(oldPReadDir); uio_PDirHandle_unref(newPReadDir); uio_PDirHandle_unref(newPWriteDir); uio_free(oldName); uio_free(newName); - errno = saveErrno; + errno = savedErrno; return -1; } @@ -469,9 +469,9 @@ uio_statDir(uio_DirHandle *dirHandle, const char *path, } if (uio_statOneDir(pDirHandles[0], statBuf) == -1) { - int saveErrno = errno; + int savedErrno = errno; uio_PDirHandles_delete(pDirHandles, numPDirHandles); - errno = saveErrno; + errno = savedErrno; return -1; } // TODO: atm, fstat'ing a dir will show the info for the topmost @@ -484,9 +484,9 @@ uio_statDir(uio_DirHandle *dirHandle, const char *path, if (statOneDir(pDirHandles[i], &statOne) == -1) { // errno is set - int saveErrno = errno; + int savedErrno = errno; uio_PDirHandles_delete(pDirHandles, numPDirHandles); - errno = saveErrno; + errno = savedErrno; return -1; } @@ -536,10 +536,10 @@ uio_mkdir(uio_DirHandle *dir, const char *path, mode_t mode) { newDirHandle = pWriteDir->pRoot->handler->mkdir(pWriteDir, name, mode); if (newDirHandle == NULL) { - int saveErrno = errno; + int savedErrno = errno; uio_free(name); uio_PDirHandle_unref(pWriteDir); - errno = saveErrno; + errno = savedErrno; return -1; } @@ -597,11 +597,11 @@ uio_open(uio_DirHandle *dir, const char *path, int flags, mode_t mode) { // file needs to be copied if (uio_copyFilePhysical(readPDirHandle, name, writePDirHandle, name) == -1) { - int saveErrno = errno; + int savedErrno = errno; uio_free(name); uio_PDirHandle_unref(readPDirHandle); uio_PDirHandle_unref(writePDirHandle); - errno = saveErrno; + errno = savedErrno; return NULL; } } @@ -623,10 +623,10 @@ uio_open(uio_DirHandle *dir, const char *path, int flags, mode_t mode) { handle = pDirHandle->pRoot->handler->open(pDirHandle, name, flags, mode); // Also adds a new entry to the physical dir if appropriate. if (handle == NULL) { - int saveErrno = errno; + int savedErrno = errno; uio_free(name); uio_PDirHandle_unref(pDirHandle); - errno = saveErrno; + errno = savedErrno; return NULL; } @@ -640,14 +640,17 @@ uio_openDir(uio_Repository *repository, const char *path, int flags) { uio_DirHandle *dirHandle; const char * const rootStr = "/"; - dirHandle = uio_newDirHandle(repository, + dirHandle = uio_DirHandle_new(repository, unconst(rootStr), unconst(rootStr)); + // dirHandle->path will be replaced before uio_openDir() + // exits() if (uio_verifyPath(dirHandle, path, &dirHandle->path) == -1) { - int saveErrno = errno; + int savedErrno = errno; uio_DirHandle_free(dirHandle); - errno = saveErrno; + errno = savedErrno; return NULL; } + // dirHandle->path is no longer equal to 'path' at this point. // TODO: increase ref in repository? dirHandle->rootEnd = dirHandle->path; if (flags & uio_OD_ROOT) @@ -665,12 +668,12 @@ uio_openDirRelative(uio_DirHandle *base, const char *path, int flags) { return NULL; } if (flags & uio_OD_ROOT) { - dirHandle = uio_newDirHandle(base->repository, + dirHandle = uio_DirHandle_new(base->repository, newPath, newPath + strlen(newPath)); // TODO: increase ref in base->repository? } else { // use the root of the base dir - dirHandle = uio_newDirHandle(base->repository, + dirHandle = uio_DirHandle_new(base->repository, newPath, newPath + (base->rootEnd - base->path)); } return dirHandle; @@ -678,8 +681,7 @@ uio_openDirRelative(uio_DirHandle *base, const char *path, int flags) { int uio_closeDir(uio_DirHandle *dirHandle) { - uio_free(dirHandle->path); - uio_DirHandle_free(dirHandle); + uio_DirHandle_unref(dirHandle); return 0; } @@ -765,12 +767,12 @@ uio_rmdir(uio_DirHandle *dirHandle, const char *path) { err: { - int saveErrno = errno; + int savedErrno = errno; uio_PDirHandles_delete(pDirHandles, numPDirHandles); uio_free(items); if (entry != NULL) uio_PDirEntryHandle_unref(entry); - errno = saveErrno; + errno = savedErrno; return -1; } } @@ -875,12 +877,12 @@ uio_unlink(uio_DirHandle *dirHandle, const char *path) { err: { - int saveErrno = errno; + int savedErrno = errno; uio_PDirHandles_delete(pDirHandles, numPDirHandles); uio_free(items); if (entry != NULL) uio_PDirEntryHandle_unref(entry); - errno = saveErrno; + errno = savedErrno; return -1; } } @@ -945,13 +947,13 @@ uio_getFileLocation(uio_DirHandle *dir, const char *inPath, // file needs to be copied if (uio_copyFilePhysical(readPDirHandle, name, writePDirHandle, name) == -1) { - int saveErrno = errno; + int savedErrno = errno; uio_free(name); uio_PDirHandle_unref(readPDirHandle); uio_free(readPRootPath); uio_PDirHandle_unref(writePDirHandle); uio_free(writePRootPath); - errno = saveErrno; + errno = savedErrno; return -1; } } @@ -1054,16 +1056,16 @@ uio_getDirList(uio_DirHandle *dirHandle, const char *path, const char *pattern, matchType); { - int saveErrno; - saveErrno = errno; + int savedErrno; + savedErrno = errno; uio_PDirHandles_delete(pDirHandles, numPDirHandles); - errno = saveErrno; + errno = savedErrno; } return result; } // Names and newNames may point to the same location. -// &numNames and numNewNames may point to the same location. +// numNewNames may point to &numNames. static void uio_filterDoubleNames(const char * const *names, int numNames, const char **newNames, int *numNewNames) { @@ -1538,19 +1540,27 @@ uio_Handle_free(uio_Handle *handle) { uio_free(handle); } +// ref count set to 1 static uio_DirHandle * -uio_newDirHandle(uio_Repository *repository, char *path, char *rootEnd) { +uio_DirHandle_new(uio_Repository *repository, char *path, char *rootEnd) { uio_DirHandle *result; - result = uio_allocDirHandle(); + result = uio_DirHandle_alloc(); + result->ref = 1; result->repository = repository; result->path = path; result->rootEnd = rootEnd; return result; } +void +uio_DirHandle_delete(uio_DirHandle *dirHandle) { + uio_free(dirHandle->path); + uio_DirHandle_free(dirHandle); +} + static inline uio_DirHandle * -uio_allocDirHandle(void) { +uio_DirHandle_alloc(void) { uio_DirHandle *result = uio_malloc(sizeof (uio_DirHandle)); #ifdef uio_MEM_DEBUG uio_MemDebug_debugAlloc(uio_DirHandle, (void *) result); diff --git a/sc2/src/sc2code/libs/uio/ioaux.c b/sc2/src/sc2code/libs/uio/ioaux.c index 82586bfca..fde0a7492 100644 --- a/sc2/src/sc2code/libs/uio/ioaux.c +++ b/sc2/src/sc2code/libs/uio/ioaux.c @@ -124,9 +124,9 @@ uio_makePath(uio_PDirHandle *pDirHandle, const char *path, size_t pathLen, newPDirHandle = mkdirFun(pDirHandle, buf, mode); if (newPDirHandle == NULL) { - int saveErrno = errno; + int savedErrno = errno; uio_PDirHandle_unref(pDirHandle); - errno = saveErrno; + errno = savedErrno; return NULL; } uio_PDirHandle_unref(pDirHandle); @@ -366,8 +366,8 @@ uio_getPhysicalAccess(uio_DirHandle *dirHandle, const char *path, // component is present in this dir. entry = uio_getPDirEntryHandle(pDirHandle, rest); if (entry != NULL) { - // Entry is not a dir, as otherwise uio_getPDirEntryHandle - // wouldn't have stopped where it did. + // 'rest' exists, and it is not a dir, as otherwise + // uio_getPDirEntryHandle wouldn't have stopped where it did. uio_PDirEntryHandle_unref(entry); readItem = item; if (readPDirHandle != NULL) @@ -378,7 +378,9 @@ uio_getPhysicalAccess(uio_DirHandle *dirHandle, const char *path, entryExists = true; break; } else { - if (readItem == NULL) { + // 'rest' doesn't exist + // We're only interested in this dir if we want to write too. + if (((flags & O_ACCMODE) != O_RDONLY) && readItem == NULL) { // Keep the first one. readItem = item; assert(readPDirHandle == NULL); @@ -490,17 +492,17 @@ uio_getPhysicalAccess(uio_DirHandle *dirHandle, const char *path, writePDirHandle = uio_makePath(writeItem->mountInfo->pDirHandle, pRootPath, rest - pRootPath, 0777); if (writePDirHandle == NULL) { - int saveErrno; + int savedErrno; if (errno == ENOSYS) { // mkdir not supported. We want to report that we failed // because of an error in the underlying layer. // EIO sounds like the best choice. errno = EIO; } - saveErrno = errno; + savedErrno = errno; uio_PDirHandle_unref(readPDirHandle); uio_free(fullPath); - errno = saveErrno; + errno = savedErrno; return -1; } rest++; // skip the '/' diff --git a/sc2/src/sc2code/libs/uio/iointrn.h b/sc2/src/sc2code/libs/uio/iointrn.h index 83c52fa41..2ada4ea65 100644 --- a/sc2/src/sc2code/libs/uio/iointrn.h +++ b/sc2/src/sc2code/libs/uio/iointrn.h @@ -50,6 +50,7 @@ struct uio_Handle { }; struct uio_DirHandle { + int ref; struct uio_Repository *repository; char *path; // does not contain any '.' or '..' @@ -102,6 +103,7 @@ struct uio_EntriesContext { uio_Handle *uio_Handle_new(uio_PRoot *root, uio_NativeHandle native, int openFlags); void uio_Handle_delete(uio_Handle *handle); +void uio_DirHandle_delete(uio_DirHandle *dirHandle); uio_PDirEntryHandle *uio_getPDirEntryHandle( const uio_PDirHandle *dirHandle, const char *name); @@ -130,6 +132,19 @@ uio_Handle_unref(uio_Handle *handle) { uio_Handle_delete(handle); } +static inline void +uio_DirHandle_ref(uio_DirHandle *dirHandle) { + dirHandle->ref++; +} + +static inline void +uio_DirHandle_unref(uio_DirHandle *dirHandle) { + assert(dirHandle->ref > 0); + dirHandle->ref--; + if (dirHandle->ref == 0) + uio_DirHandle_delete(dirHandle); +} + static inline uio_bool uio_PDirEntryHandle_isDir(const uio_PDirEntryHandle *handle) { return (handle->flags & uio_PDirEntryHandle_TYPEMASK) == diff --git a/sc2/src/sc2code/libs/uio/paths.c b/sc2/src/sc2code/libs/uio/paths.c index 8b83aff5f..b26ad117e 100644 --- a/sc2/src/sc2code/libs/uio/paths.c +++ b/sc2/src/sc2code/libs/uio/paths.c @@ -188,6 +188,7 @@ joinPathsAbsolute(const char *first, const char *second) { result = uio_malloc(secondLen + 2); result[0] = '/'; memcpy(&result[1], second, secondLen); + result[secondLen + 1] = '\0'; return result; } diff --git a/sc2/src/sc2code/libs/uio/physical.c b/sc2/src/sc2code/libs/uio/physical.c index 3e09d4d84..d5fdec1d6 100644 --- a/sc2/src/sc2code/libs/uio/physical.c +++ b/sc2/src/sc2code/libs/uio/physical.c @@ -63,12 +63,57 @@ uio_PRoot_new(uio_PDirHandle *topDirHandle, pRoot->handle = handle; pRoot->extra = extra; pRoot->flags = flags; +#ifdef uio_PROOT_HAVE_CLOSE_HANDLERS + pRoot->numCloseHandlers = 0; + pRoot->closeHandlers = NULL; +#endif return pRoot; } +#ifdef uio_PROOT_HAVE_CLOSE_HANDLERS +// Closehandlers code disabled. +// It was only meant for internal use, but I don't need it any more. +// Keeping it around for a while until I'm confident I won't need it in the +// future. + +void +uio_PRoot_addCloseHandler(uio_PRoot *pRoot, void (*fun)(void *), void *arg) { + pRoot->numCloseHandlers++; + pRoot->closeHandlers = uio_realloc(pRoot->closeHandlers, + pRoot->numCloseHandlers * sizeof (uio_PRoot_CloseHandler)); + pRoot->closeHandlers[pRoot->numCloseHandlers - 1].fun = fun; + pRoot->closeHandlers[pRoot->numCloseHandlers - 1].arg = arg; +} + +void +uio_PRoot_callCloseHandlers(uio_PRoot *pRoot) { + int i; + + i = pRoot->numCloseHandlers; + while (i--) { + uio_PRoot_CloseHandler *closeHandler; + + closeHandler = &pRoot->closeHandlers[i]; + (closeHandler->fun)(closeHandler->arg); + } +} + +void +uio_PRoot_removeCloseHandlers(uio_PRoot *pRoot) { + pRoot->numCloseHandlers = 0; + if (pRoot->closeHandlers != NULL) + uio_free(pRoot->closeHandlers); + pRoot->closeHandlers = NULL; +} +#endif + static inline void uio_PRoot_delete(uio_PRoot *pRoot) { +#ifdef uio_PROOT_HAVE_CLOSE_HANDLERS + uio_PRoot_callCloseHandlers(pRoot); + uio_PRoot_removeCloseHandlers(pRoot); +#endif assert(pRoot->handler->umount != NULL); pRoot->handler->umount(pRoot); if (pRoot->handle) diff --git a/sc2/src/sc2code/libs/uio/physical.h b/sc2/src/sc2code/libs/uio/physical.h index 3de3b0a33..da336a15f 100644 --- a/sc2/src/sc2code/libs/uio/physical.h +++ b/sc2/src/sc2code/libs/uio/physical.h @@ -28,6 +28,7 @@ typedef void *uio_NativeEntriesContext; // 'forward' declarations typedef struct uio_PRoot uio_PRoot; +typedef struct uio_PRoot_CloseHandler uio_PRoot_CloseHandler; #include "iointrn.h" @@ -55,14 +56,31 @@ struct uio_PRoot { /* The handle through which this PRoot is opened, * this is NULL for the top PRoot */ // TODO: move this to extra? +#ifdef uio_PROOT_HAVE_CLOSE_HANDLERS + int numCloseHandlers; + uio_PRoot_CloseHandler *closeHandlers; +#endif uio_PRootExtra extra; /* extra internal data for some filesystem types */ }; +#ifdef uio_PROOT_HAVE_CLOSE_HANDLERS +struct uio_PRoot_CloseHandler { + void (*fun)(void *); + void *arg; +}; +#endif + void uio_PRoot_deletePRootExtra(uio_PRoot *pRoot); uio_PRoot *uio_PRoot_new(uio_PDirHandle *topDirHandle, uio_FileSystemHandler *handler, uio_Handle *handle, uio_PRootExtra extra, int flags); +#ifdef uio_PROOT_HAVE_CLOSE_HANDLERS +void uio_PRoot_addCloseHandler(uio_PRoot *pRoot, void (*fun)(void *), + void *arg); +void uio_PRoot_callCloseHandlers(uio_PRoot *pRoot); +void uio_PRoot_removeCloseHandlers(uio_PRoot *pRoot); +#endif uio_PDirHandle *uio_PRoot_getRootDirHandle(uio_PRoot *pRoot); void uio_PRoot_refHandle(uio_PRoot *pRoot); void uio_PRoot_unrefHandle(uio_PRoot *pRoot); diff --git a/sc2/src/sc2code/libs/uio/stdio/stdio.c b/sc2/src/sc2code/libs/uio/stdio/stdio.c index cc85e47f3..5e7e01bfc 100644 --- a/sc2/src/sc2code/libs/uio/stdio/stdio.c +++ b/sc2/src/sc2code/libs/uio/stdio/stdio.c @@ -137,9 +137,9 @@ stdio_stat(uio_PDirHandle *pDirHandle, const char *name, result = stat(path, statBuf); if (result == -1) { - int saveErrno = errno; + int savedErrno = errno; uio_free(path); - errno = saveErrno; + errno = savedErrno; return -1; } @@ -159,9 +159,9 @@ stdio_mkdir(uio_PDirHandle *pDirHandle, const char *name, mode_t mode) { } if (MKDIR(path, mode) == -1) { - int saveErrno = errno; + int savedErrno = errno; uio_free(path); - errno = saveErrno; + errno = savedErrno; return NULL; } uio_free(path); @@ -244,10 +244,10 @@ stdio_rename(uio_PDirHandle *oldPDirHandle, const char *oldName, result = rename(oldPath, newPath); if (result == -1) { - int saveErrno = errno; + int savedErrno = errno; uio_free(oldPath); uio_free(newPath); - errno = saveErrno; + errno = savedErrno; return -1; } @@ -283,9 +283,9 @@ stdio_rmdir(uio_PDirHandle *pDirHandle, const char *name) { result = rmdir(path); if (result == -1) { - int saveErrno = errno; + int savedErrno = errno; uio_free(path); - errno = saveErrno; + errno = savedErrno; return -1; } @@ -319,9 +319,9 @@ stdio_unlink(uio_PDirHandle *pDirHandle, const char *name) { result = unlink(path); if (result == -1) { - int saveErrno = errno; + int savedErrno = errno; uio_free(path); - errno = saveErrno; + errno = savedErrno; return -1; } diff --git a/sc2/src/sc2code/libs/uio/uioutils.h b/sc2/src/sc2code/libs/uio/uioutils.h index 54b4abb3c..309cc1681 100644 --- a/sc2/src/sc2code/libs/uio/uioutils.h +++ b/sc2/src/sc2code/libs/uio/uioutils.h @@ -18,8 +18,8 @@ * */ -#ifndef _UTILS_H -#define _UTILS_H +#ifndef _UIOUTILS_H +#define _UIOUTILS_H #include @@ -88,5 +88,5 @@ minu(unsigned int i1, unsigned int i2) { } -#endif +#endif /* _UIOUTILS_H */ diff --git a/sc2/src/sc2code/libs/uio/utils.c b/sc2/src/sc2code/libs/uio/utils.c new file mode 100644 index 000000000..6aabe0627 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/utils.c @@ -0,0 +1,366 @@ +/* + * Copyright (C) 2003 Serge van den Boom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * Nota bene: later versions of the GNU General Public License do not apply + * to this program. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include + +#include "iointrn.h" +#include "ioaux.h" +#include "utils.h" + +static int uio_copyError(uio_Handle *srcHandle, uio_Handle *dstHandle, + uio_DirHandle *unlinkHandle, const char *unlinkPath, uio_uint8 *buf); + +struct uio_StdioAccessHandle { + uio_DirHandle *tempRoot; + char *tempDirName; + uio_DirHandle *tempDir; + char *fileName; + char *stdioPath; +}; + +static inline uio_StdioAccessHandle *uio_StdioAccessHandle_new( + uio_DirHandle *tempRoot, char *tempDirName, + uio_DirHandle *tempDir, char *fileName, + char *stdioPath); +static inline void uio_StdioAccessHandle_delete( + uio_StdioAccessHandle *handle); +static inline uio_StdioAccessHandle *uio_StdioAccessHandle_alloc(void); +static inline void uio_StdioAccessHandle_free(uio_StdioAccessHandle *handle); + +/* + * Copy a file with path srcName to a file with name newName. + * If the destination already exists, the operation fails. + * Links are followed. + * Special files (fifos, char devices, block devices, etc) will be + * read as long as there is data available and the destination will be + * a regular file with that data. + * The new file will have the same permissions as the old. + * If an error occurs during copying, an attempt will be made to + * remove the copy. + */ +int +uio_copyFile(uio_DirHandle *srcDir, const char *srcName, + uio_DirHandle *dstDir, const char *newName) { + uio_Handle *src, *dst; + struct stat sb; +#define BUFSIZE 65536 + uio_uint8 *buf, *bufPtr; + ssize_t numInBuf, numWritten; + + src = uio_open(srcDir, srcName, O_RDONLY +#ifdef WIN32 + | O_BINARY +#endif + , 0); + if (src == NULL) + return -1; + + if (uio_fstat(src, &sb) == -1) + return uio_copyError(src, NULL, NULL, NULL, NULL); + + dst = uio_open(dstDir, newName, O_WRONLY | O_CREAT | O_EXCL +#ifdef WIN32 + | O_BINARY +#endif + , sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)); + if (dst == NULL) + return uio_copyError(src, NULL, NULL, NULL, NULL); + + buf = uio_malloc(BUFSIZE); + // This was originally a statically allocated buffer, + // but as this function might be run from a thread with + // a small Stack, this is better. + while (1) { + numInBuf = uio_read(src, buf, BUFSIZE); + if (numInBuf == -1) { + if (errno == EINTR) + continue; + return uio_copyError(src, dst, dstDir, newName, buf); + } + if (numInBuf == 0) + break; + + bufPtr = buf; + do + { + numWritten = uio_write(dst, bufPtr, numInBuf); + if (numWritten == -1) { + if (errno == EINTR) + continue; + return uio_copyError(src, dst, dstDir, newName, buf); + } + numInBuf -= numWritten; + bufPtr += numWritten; + } while (numInBuf > 0); + } + + uio_free(buf); + uio_close(src); + uio_close(dst); + errno = 0; + return 0; +} + +/* + * Closes srcHandle if it's not -1. + * Closes dstHandle if it's not -1. + * Removes unlinkpath from the unlinkHandle dir if it's not NULL. + * Frees 'buf' if not NULL. + * Always returns -1. + * errno is what was before the call. + */ +static int +uio_copyError(uio_Handle *srcHandle, uio_Handle *dstHandle, + uio_DirHandle *unlinkHandle, const char *unlinkPath, uio_uint8 *buf) { + int savedErrno; + + savedErrno = errno; + +#ifdef DEBUG + fprintf(stderr, "Error while copying: %s\n", strerror(errno)); +#endif + + if (srcHandle != NULL) + uio_close(srcHandle); + + if (dstHandle != NULL) + uio_close(dstHandle); + + if (unlinkPath != NULL) + uio_unlink(unlinkHandle, unlinkPath); + + if (buf != NULL) + uio_free(buf); + + errno = savedErrno; + return -1; +} + +#define NUM_TEMP_RETRIES 16 + // Retry this many times to create a temporary dir, before giving + // up. If undefined, keep trying indefinately. + +uio_StdioAccessHandle * +uio_getStdioAccess(uio_DirHandle *dir, const char *path, int flags, + uio_DirHandle *tempDir) { + int res; + uio_MountHandle *mountHandle; + const char *name; + char *newPath; + char *tempDirName; + uio_DirHandle *newDir; + uio_FileSystemID fsID; + + res = uio_getFileLocation(dir, path, flags, &mountHandle, &newPath); + if (res == -1) { + // errno is set + return NULL; + } + + fsID = uio_getMountFileSystemType(mountHandle); + if (fsID == uio_FSTYPE_STDIO) { + // Current location is usable. + return uio_StdioAccessHandle_new(NULL, NULL, NULL, NULL, newPath); + } + uio_free(newPath); + + { + uio_uint32 dirNum; + int i; + + // Current location is not usable. Create a directory with a + // generated name, as a temporary location to store a copy of + // the file. + dirNum = (uio_uint32) time(NULL); + tempDirName = uio_malloc(sizeof "01234567"); + for (i = 0; ; i++) { +#ifdef NUM_TEMP_RETRIES + if (i >= NUM_TEMP_RETRIES) { + // Using ENOSPC to report that we couldn't create a + // temporary dir, getting EEXIST. + uio_free(tempDirName); + errno = ENOSPC; + return NULL; + } +#endif + + sprintf(tempDirName, "%08lx", (unsigned long) dirNum + i); + + res = uio_mkdir(tempDir, tempDirName, 0700); + if (res == -1) { + int savedErrno; + if (errno == EEXIST) + continue; + savedErrno = errno; +#ifdef DEBUG + fprintf(stderr, "Error: Could not create temporary dir: %s\n", + strerror(errno)); +#endif + uio_free(tempDirName); + errno = savedErrno; + return NULL; + } + break; + } + + newDir = uio_openDirRelative(tempDir, tempDirName, 0); + if (newDir == NULL) { +#ifdef DEBUG + fprintf(stderr, "Error: Could not open temporary dir: %s\n", + strerror(errno)); +#endif + res = uio_rmdir(tempDir, tempDirName); +#ifdef DEBUG + if (res == -1) + fprintf(stderr, "Warning: Could not remove temporary dir: " + "%s.\n", strerror(errno)); +#endif + uio_free(tempDirName); + errno = EIO; + return NULL; + } + + // Get the last component of path. This should be the file to + // access. + name = strrchr(path, '/'); + if (name == NULL) + name = path; + + // Copy the file + res = uio_copyFile(dir, path, newDir, name); + if (res == -1) { + int savedErrno = errno; +#ifdef DEBUG + fprintf(stderr, "Error: Could not copy file to temporary dir: " + "%s\n", strerror(errno)); +#endif + uio_closeDir(newDir); + uio_free(tempDirName); + errno = savedErrno; + return NULL; + } + } + + res = uio_getFileLocation(newDir, name, flags, &mountHandle, &newPath); + if (res == -1) { + int savedErrno = errno; + fprintf(stderr, "Error: %s: Could not get location of temporary " + "dir: %s.\n", __FUNCTION__, strerror(errno)); + uio_closeDir(newDir); + uio_free(tempDirName); + errno = savedErrno; + return NULL; + } + + fsID = uio_getMountFileSystemType(mountHandle); + if (fsID != uio_FSTYPE_STDIO) { + // Temp dir isn't on a stdio fs either. + fprintf(stderr, "Error: %s: Temporary file location isn't on a " + "stdio filesystem.\n", __FUNCTION__); + uio_closeDir(newDir); + uio_free(tempDirName); + uio_free(newPath); +// errno = EXDEV; + errno = EINVAL; + return NULL; + } + + uio_DirHandle_ref(tempDir); + return uio_StdioAccessHandle_new(tempDir, tempDirName, newDir, + uio_strdup(name), newPath); +} + +void +uio_releaseStdioAccess(uio_StdioAccessHandle *handle) { + if (handle->tempDir != NULL) { + if (uio_unlink(handle->tempDir, handle->fileName) == -1) { +#ifdef DEBUG + fprintf(stderr, "Error: Could not remove temporary file: " + "%s\n", strerror(errno)); +#endif + } + + // Need to free this handle in advance. There should be no handles + // to a dir left when removing it. + uio_DirHandle_unref(handle->tempDir); + handle->tempDir = NULL; + + if (uio_rmdir(handle->tempRoot, handle->tempDirName) == -1) { +#ifdef DEBUG + fprintf(stderr, "Error: Could not remove temporary directory: " + "%s\n", strerror(errno)); +#endif + } + } + + uio_StdioAccessHandle_delete(handle); +} + +const char * +uio_StdioAccessHandle_getPath(uio_StdioAccessHandle *handle) { + return (const char *) handle->stdioPath; +} + +// references to tempRoot and tempDir are not increased. +// no copies of arguments are made. +// By calling this function control of the values is transfered to +// the handle. +static inline uio_StdioAccessHandle * +uio_StdioAccessHandle_new( + uio_DirHandle *tempRoot, char *tempDirName, + uio_DirHandle *tempDir, char *fileName, char *stdioPath) { + uio_StdioAccessHandle *result; + + result = uio_StdioAccessHandle_alloc(); + result->tempRoot = tempRoot; + result->tempDirName = tempDirName; + result->tempDir = tempDir; + result->fileName = fileName; + result->stdioPath = stdioPath; + + return result; +} + +static inline void +uio_StdioAccessHandle_delete(uio_StdioAccessHandle *handle) { + if (handle->tempDir != NULL) + uio_DirHandle_unref(handle->tempDir); + if (handle->fileName != NULL) + uio_free(handle->fileName); + if (handle->tempRoot != NULL) + uio_DirHandle_unref(handle->tempRoot); + if (handle->tempDirName != NULL) + uio_free(handle->tempDirName); + uio_free(handle->stdioPath); + uio_StdioAccessHandle_free(handle); +} + +static inline uio_StdioAccessHandle * +uio_StdioAccessHandle_alloc(void) { + return uio_malloc(sizeof (uio_StdioAccessHandle)); +} + +static inline void +uio_StdioAccessHandle_free(uio_StdioAccessHandle *handle) { + uio_free(handle); +} + diff --git a/sc2/src/sc2code/libs/uio/utils.h b/sc2/src/sc2code/libs/uio/utils.h new file mode 100644 index 000000000..5813bce33 --- /dev/null +++ b/sc2/src/sc2code/libs/uio/utils.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2003 Serge van den Boom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * Nota bene: later versions of the GNU General Public License do not apply + * to this program. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _UTILS_H +#define _UTILS_H + +#ifdef uio_INTERNAL +typedef struct uio_StdioAccessHandle uio_StdioAccessHandle; +#else +typedef void uio_StdioAccessHandle; +#endif + +int uio_copyFile(uio_DirHandle *srcDir, const char *srcName, + uio_DirHandle *dstDir, const char *newName); +uio_StdioAccessHandle *uio_getStdioAccess(uio_DirHandle *dir, + const char *path, int flags, uio_DirHandle *tempDir); +const char *uio_StdioAccessHandle_getPath(uio_StdioAccessHandle *handle); +void uio_releaseStdioAccess(uio_StdioAccessHandle *handle); + + +#endif /* _UTILS_H */ + diff --git a/sc2/src/sc2code/libs/uio/zip/zip.c b/sc2/src/sc2code/libs/uio/zip/zip.c index e09ff0abd..69b9f6eb8 100644 --- a/sc2/src/sc2code/libs/uio/zip/zip.c +++ b/sc2/src/sc2code/libs/uio/zip/zip.c @@ -580,13 +580,13 @@ zip_mount(uio_Handle *handle, int flags) { rootDirHandle = uio_PRoot_getRootDirHandle(result); if (zip_fillDirStructure(rootDirHandle->extra, handle) == -1) { - int saveErrno = errno; + int savedErrno = errno; #ifdef DEBUG fprintf(stderr, "Error: failed to read the zip directory " "structure - %d.\n", errno); #endif uio_GPRoot_umount(result); - errno = saveErrno; + errno = savedErrno; return NULL; } @@ -662,11 +662,11 @@ zip_fillDirStructureCentral(uio_GPDir *top, uio_Handle *handle) { err: { - int saveErrno = errno; + int savedErrno = errno; if (fileBlock != NULL) uio_closeFileBlock(fileBlock); - errno = saveErrno; + errno = savedErrno; return -1; } } @@ -845,10 +845,10 @@ zip_findEndOfCentralDirectoryRecord(uio_Handle *handle, bufLen = uio_accessFileBlock(fileBlock, startPos, endPos - startPos + 4, &buf); if (bufLen == -1) { - int saveErrno = errno; + int savedErrno = errno; fprintf(stderr, "Error: Read error while searching for " "'end-of-central-directory record'.\n"); - errno = saveErrno; + errno = savedErrno; return -1; } if (bufLen != endPos - startPos + 4) { @@ -973,8 +973,8 @@ zip_fillDirStructureLocal(uio_GPDir *top, uio_Handle *handle) { pos = uio_lseek(handle, 0, SEEK_SET); if (pos == -1) { - int saveErrno = errno; - errno = saveErrno; + int savedErrno = errno; + errno = savedErrno; return -1; } if (pos != 0) { @@ -1015,10 +1015,10 @@ zip_fillDirStructureLocal(uio_GPDir *top, uio_Handle *handle) { err: { - int saveErrno = errno; + int savedErrno = errno; uio_closeFileBlock(fileBlock); - errno = saveErrno; + errno = savedErrno; return -1; } } @@ -1209,9 +1209,9 @@ zip_updateFileDataFromLocalHeader(uio_Handle *handle, } if (zip_updatePFileDataFromLocalFileHeader(gPFileData, fileBlock, gPFileData->headerOffset) == -1) { - int saveErrno = errno; + int savedErrno = errno; uio_closeFileBlock(fileBlock); - errno = saveErrno; + errno = savedErrno; return -1; } if (gPFileData->ctime == (time_t) 0) diff --git a/sc2/src/sc2code/libs/uioutils.h b/sc2/src/sc2code/libs/uioutils.h new file mode 100644 index 000000000..6748dd144 --- /dev/null +++ b/sc2/src/sc2code/libs/uioutils.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2003 Serge van den Boom + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * Nota bene: later versions of the GNU General Public License do not apply + * to this program. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _UIOUTILS_H +#define _UIOUTILS_H + +#include "uio/utils.h" + +#endif /* _UIOUTILS_H */ +