X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;ds=inline;f=src%2Fwgtpkg-workdir.c;h=59da1e6ac7ed2cdc505eaece01ae34e36aa6893c;hb=9ab266df6642c6e930e03b3024d7c3d53ef88bbc;hp=12cfa24ee0964c83cf464f1b7e0f5cbb4e9e74cc;hpb=f3d64b7c741677cd28e2a11deed67196cd02b46a;p=src%2Fapp-framework-main.git diff --git a/src/wgtpkg-workdir.c b/src/wgtpkg-workdir.c index 12cfa24..59da1e6 100644 --- a/src/wgtpkg-workdir.c +++ b/src/wgtpkg-workdir.c @@ -22,13 +22,16 @@ #include #include #include +#include #include #include +#include "verbose.h" #include "wgtpkg.h" -static int mode = 0700; -static char workdir[PATH_MAX]; +static int mode = 0755; +char workdir[PATH_MAX] = { 0, }; +int workdirfd = -1; /* removes recursively the content of a directory */ static int clean_dirfd(int dirfd) @@ -41,9 +44,14 @@ static int clean_dirfd(int dirfd) char spare[PATH_MAX]; } entry; + dirfd = dup(dirfd); + if (dirfd < 0) { + syslog(LOG_ERR, "failed to dup the dirfd"); + return -1; + } dir = fdopendir(dirfd); if (dir == NULL) { - syslog(LOG_ERR, "opendir failed in clean_dirfd"); + syslog(LOG_ERR, "fdopendir failed in clean_dirfd"); return -1; } @@ -101,30 +109,21 @@ static int clean_dir(const char *directory) return rc; } -/* removes the content of the working directory */ -int enter_workdir(int clean) -{ - int rc = chdir(workdir); - if (rc) - syslog(LOG_ERR, "entring workdir %s failed", workdir); - else if (clean) - rc = clean_dir(workdir); - return rc; -} - /* removes the working directory */ void remove_workdir() { - enter_workdir(1); - chdir(".."); + assert(workdirfd >= 0); + clean_dirfd(workdirfd); + close(workdirfd); + workdirfd = -1; rmdir(workdir); + workdir[0] = 0; } -int set_workdir(const char *name, int create) +static int set_real_workdir(const char *name, int create) { - int rc; + int rc, dirfd; size_t length; - struct stat s; /* check the length */ length = strlen(name); @@ -134,9 +133,10 @@ int set_workdir(const char *name, int create) return -1; } - rc = stat(name, &s); - if (rc) { - if (!create) { + /* opens the directory */ + dirfd = openat(AT_FDCWD, name, O_DIRECTORY|O_RDONLY); + if (dirfd < 0) { + if (!create || errno != ENOENT) { syslog(LOG_ERR, "no workdir %s", name); return -1; } @@ -145,17 +145,40 @@ int set_workdir(const char *name, int create) syslog(LOG_ERR, "can't create workdir %s", name); return -1; } - - } else if (!S_ISDIR(s.st_mode)) { - syslog(LOG_ERR, "%s isn't a directory", name); - errno = ENOTDIR; - return -1; + dirfd = open(name, O_PATH|O_DIRECTORY); + if (dirfd < 0) { + syslog(LOG_ERR, "can't open workdir %s", name); + return -1; + } } + + /* close the previous directory if any */ + if (workdirfd >= 0) + close(workdirfd); + workdirfd = dirfd; memcpy(workdir, name, 1+length); return 0; } -int make_workdir_base(const char *root, const char *prefix, int reuse) +int set_workdir(const char *name, int create) +{ + char *rp; + int rc; + + if (name[0] == '/') + return set_real_workdir(name, create); + + rp = realpath(name, NULL); + if (!rp) { + syslog(LOG_ERR, "realpath failed for %s", name); + return -1; + } + rc = set_real_workdir(rp, create); + free(rp); + return rc; +} + +static int make_real_workdir_base(const char *root, const char *prefix, int reuse) { int i, n, r, l; @@ -167,6 +190,10 @@ int make_workdir_base(const char *root, const char *prefix, int reuse) } r = (int)(sizeof workdir) - n; + if (workdirfd >= 0) + close(workdirfd); + workdirfd = -1; + /* create a temporary directory */ for (i = 0 ; ; i++) { if (i == INT_MAX) { @@ -188,25 +215,157 @@ int make_workdir_base(const char *root, const char *prefix, int reuse) if (reuse) break; } + workdirfd = openat(AT_FDCWD, workdir, O_RDONLY|O_DIRECTORY); + if (workdirfd < 0) { + syslog(LOG_ERR, "error in onnection to workdir %s: %m", workdir); + rmdir(workdir); + return -1; + } return 0; } +int make_workdir_base(const char *root, const char *prefix, int reuse) +{ + char *rp; + int rc; + + if (root[0] == '/') + return make_real_workdir_base(root, prefix, reuse); + + rp = realpath(root, NULL); + if (!rp) { + syslog(LOG_ERR, "realpath failed for %s", root); + return -1; + } + rc = make_real_workdir_base(rp, prefix, reuse); + free(rp); + return rc; +} + int make_workdir(int reuse) { return make_workdir_base(".", "PACK", reuse); } -int workdirfd() +static int move_real_workdir(const char *dest, int parents, int force) { - int result = open(workdir, O_PATH|O_DIRECTORY); - if (result < 0) - syslog(LOG_ERR, "can't get fd for workdir %.*s: %m", PATH_MAX, workdir); - return result; + int rc, len, l; + struct stat s; + char *copy; + const char *iter; + + /* check length */ + if (strlen(dest) >= sizeof workdir) { + syslog(LOG_ERR, "destination dirname too long"); + errno = EINVAL; + return -1; + } + + /* if an existing directory exist remove it if force */ + rc = stat(dest, &s); + if (rc == 0) { + if (!S_ISDIR(s.st_mode)) { + syslog(LOG_ERR, "in move_real_workdir, can't overwrite regular file %s", dest); + errno = EEXIST; + return -1; + } + if (!force) { + syslog(LOG_ERR, "in move_real_workdir, can't overwrite regular file %s", dest); + errno = EEXIST; + return -1; + } + rc = clean_dir(dest); + if (rc) { + syslog(LOG_ERR, "in move_real_workdir, can't clean dir %s", dest); + return rc; + } + rc = rmdir(dest); + if (rc) { + syslog(LOG_ERR, "in move_real_workdir, can't remove dir %s", dest); + return rc; + } + } else { + /* check parent of dest */ + iter = strrchr(dest, '/'); + len = iter ? iter - dest : 0; + if (len) { + /* is parent existing? */ + copy = strndupa(dest, len); + rc = stat(copy, &s); + if (!rc) { + /* found an entry */ + if (!S_ISDIR(s.st_mode)) { + syslog(LOG_ERR, "in move_real_workdir, '%s' isn't a directory", copy); + errno = ENOTDIR; + return -1; + } + } else if (!parents) { + /* parent entry not found but not allowed to create it */ + syslog(LOG_ERR, "in move_real_workdir, parent directory '%s' not found: %m", copy); + return -1; + } else { + /* parent entries to be created */ + l = len; + for(;;) { + /* backward loop */ + rc = mkdir(copy, mode); + if (!rc) + break; + if (errno != ENOENT) { + syslog(LOG_ERR, "in move_real_workdir, mkdir '%s' failed: %m", copy); + return -1; + } + while (l && copy[l] != '/') + l--; + if (l == 0) { + syslog(LOG_ERR, "in move_real_workdir, internal error"); + errno = EINVAL; + return -1; + } + copy[l] = 0; + } + while(l < len) { + /* forward loop */ + copy[l] = '/'; + while (copy[++l]); + rc = mkdir(copy, mode); + if (rc && errno != EEXIST) { + syslog(LOG_ERR, "in move_real_workdir, mkdir '%s' failed: %m", copy); + return -1; + } + } + } + } + } + + /* try to rename now */ + close(workdirfd); + workdirfd = -1; + rc = renameat(AT_FDCWD, workdir, AT_FDCWD, dest); + if (rc) { + syslog(LOG_ERR, "in move_real_workdir, renameat failed %s -> %s: %m", workdir, dest); + return -1; + } + + return set_real_workdir(dest, 0); } int move_workdir(const char *dest, int parents, int force) { - + char *rp; + int rc; + + if (dest[0] == '/') + return move_real_workdir(dest, parents, force); + + rp = realpath(dest, NULL); + if (!rp) { + syslog(LOG_ERR, "realpath failed for %s", dest); + return -1; + } + rc = move_real_workdir(rp, parents, force); + free(rp); + return rc; }