X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fwgtpkg-workdir.c;h=ea376666d0829664e1c1cd0284490057865d29f6;hb=d0cb2a7a1e068a38b4a0c3216ccdbce0e33ecffb;hp=0c184a5b6e5e2ec461ed9b57716a548bbfac6d9c;hpb=bf7b5918fcc07713a29b9ca32f766b65b15a4ec2;p=src%2Fapp-framework-main.git diff --git a/src/wgtpkg-workdir.c b/src/wgtpkg-workdir.c index 0c184a5..ea37666 100644 --- a/src/wgtpkg-workdir.c +++ b/src/wgtpkg-workdir.c @@ -1,5 +1,7 @@ /* - Copyright 2015 IoT.bzh + Copyright (C) 2015-2018 IoT.bzh + + author: José Bollo Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,153 +16,223 @@ limitations under the License. */ +#define _GNU_SOURCE #include #include +#include +#include #include -#include #include +#include +#include +#include #include +#include -#include "wgtpkg.h" - -#ifndef PREDIR -#define PREDIR "./" -#endif - -static int mode = 0700; -static char workdir[PATH_MAX]; - -/* removes recursively the content of a directory */ -static int clean_dir() -{ - int cr; - DIR *dir; - struct dirent *ent; - struct { - struct dirent entry; - char spare[PATH_MAX]; - } entry; - - dir = opendir("."); - if (dir == NULL) { - syslog(LOG_ERR, "opendir failed in clean_dir"); - return -1; - } +#include "verbose.h" +#include "wgtpkg-workdir.h" +#include "utils-dir.h" - cr = -1; - for (;;) { - if (readdir_r(dir, &entry.entry, &ent) != 0) { - syslog(LOG_ERR, "readdir_r failed in clean_dir"); - goto error; - } - if (ent == NULL) - break; - if (ent->d_name[0] == '.' && (ent->d_name[1] == 0 - || (ent->d_name[1] == '.' && ent->d_name[2] == 0))) - continue; - cr = unlink(ent->d_name); - if (!cr) - continue; - if (errno != EISDIR) { - syslog(LOG_ERR, "unlink of %s failed in clean_dir", ent->d_name); - goto error; - } - if (chdir(ent->d_name)) { - syslog(LOG_ERR, "enter directory %s failed in clean_dir", ent->d_name); - goto error; - } - cr = clean_dir(); - if (cr) - goto error; - if (chdir("..")) - goto error; - cr = rmdir(ent->d_name); - if (cr) { - syslog(LOG_ERR, "rmdir of %s failed in clean_dir", ent->d_name); - goto error; - } - } - cr = 0; -error: - closedir(dir); - return cr; -} +static const mode_t dirmode = 0755; +char workdir[PATH_MAX] = { 0, }; +int workdirfd = -1; -/* removes the content of the working directory */ -int enter_workdir(int clean) +/* removes the working directory */ +void remove_workdir() { - int rc = chdir(workdir); - if (rc) - syslog(LOG_ERR, "entring workdir %s failed", workdir); - else if (clean) - rc = clean_dir(); - return rc; + assert(workdirfd >= 0); + remove_directory_content_fd(workdirfd); + close(workdirfd); + workdirfd = -1; + rmdir(workdir); + workdir[0] = 0; } -/* removes the working directory */ -void remove_workdir() +static void put_workdir(int fd, const char *name, size_t length) { - enter_workdir(1); - chdir(".."); - unlink(workdir); + /* close the previous directory if any */ + if (workdirfd >= 0) + close(workdirfd); + + /* copy the name and the fd if existing */ + if (fd < 0) { + workdir[0] = '.'; + workdir[1] = 0; + workdirfd = AT_FDCWD; + } else { + + assert(length < sizeof workdir); + memcpy(workdir, name, 1 + length); + workdirfd = fd; + } } int set_workdir(const char *name, int create) { - int rc; + int rc, dirfd; size_t length; - struct stat s; /* check the length */ length = strlen(name); if (length >= sizeof workdir) { - syslog(LOG_ERR, "workdir name too long"); + ERROR("workdir name too long"); + errno = EINVAL; return -1; } - rc = stat(name, &s); - if (rc) { + /* check if . */ + if (length == 1 && name[0] == '.') { + put_workdir(AT_FDCWD, name, length); + return 0; + } + + /* opens the directory */ + dirfd = openat(AT_FDCWD, name, O_PATH|O_DIRECTORY|O_RDONLY); + if (dirfd < 0) { + if (errno != ENOENT) { + ERROR("error while opening workdir %s: %m", name); + return -1; + } if (!create) { - syslog(LOG_ERR, "no workdir %s", name); + ERROR("workdir %s doesn't exist", name); return -1; } - rc = mkdir(name, mode); + rc = mkdirat(AT_FDCWD, name, dirmode); if (rc) { - syslog(LOG_ERR, "can't create workdir %s", name); + ERROR("can't create workdir %s", name); + return -1; + } + dirfd = openat(AT_FDCWD, name, O_PATH|O_DIRECTORY|O_RDONLY); + if (dirfd < 0) { + ERROR("can't open workdir %s", name); return -1; } - - } else if (!S_ISDIR(s.st_mode)) { - syslog(LOG_ERR, "%s isn't a directory", name); - return -1; } - memcpy(workdir, name, 1+length); + + /* record new workdir */ + put_workdir(dirfd, name, length); return 0; } -/* install the widgets of the list */ -int make_workdir(int reuse) +int make_workdir(const char *root, const char *prefix, int reuse) { - int i; + int i, n, r, l; + + put_workdir(AT_FDCWD, ".", 1); + + n = snprintf(workdir, sizeof workdir, "%s/%s", root, prefix); + if (n >= (int)sizeof workdir) { + ERROR("workdir prefix too long"); + errno = EINVAL; + return -1; + } + r = (int)(sizeof workdir) - n; /* create a temporary directory */ for (i = 0 ; ; i++) { if (i == INT_MAX) { - syslog(LOG_ERR, "exhaustion of workdirs"); + ERROR("exhaustion of workdirs"); + return -1; + } + l = snprintf(workdir + n, (unsigned)r, "%d", i); + if (l >= r) { + ERROR("computed workdir too long"); + errno = EINVAL; return -1; } - sprintf(workdir, PREDIR "PACK%d", i); - if (!mkdir(workdir, mode)) + if (!mkdirat(AT_FDCWD, workdir, dirmode)) break; if (errno != EEXIST) { - syslog(LOG_ERR, "error in creation of workdir %s: %m", workdir); + ERROR("error in creation of workdir %s: %m", workdir); return -1; } if (reuse) break; } + workdirfd = openat(AT_FDCWD, workdir, O_RDONLY|O_DIRECTORY); + if (workdirfd < 0) { + ERROR("error in onnection to workdir %s: %m", workdir); + rmdir(workdir); + return -1; + } return 0; } +int move_workdir(const char *dest, int parents, int force) +{ + int rc; + size_t len; + struct stat s; + char *copy; + const char *iter; + + /* check length */ + if (strlen(dest) >= sizeof workdir) { + ERROR("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)) { + ERROR("in move_workdir, can't overwrite regular file %s", dest); + errno = EEXIST; + return -1; + } + if (!force) { + ERROR("in move_workdir, can't overwrite regular file %s", dest); + errno = EEXIST; + return -1; + } + rc = remove_directory_content(dest); + if (rc) { + ERROR("in move_workdir, can't clean dir %s", dest); + return rc; + } + rc = rmdir(dest); + if (rc) { + ERROR("in move_workdir, can't remove dir %s", dest); + return rc; + } + } else { + /* check parent of dest */ + iter = strrchr(dest, '/'); + len = iter ? (size_t)(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)) { + ERROR("in move_workdir, '%s' isn't a directory", copy); + errno = ENOTDIR; + return -1; + } + } else if (!parents) { + /* parent entry not found but not allowed to create it */ + ERROR("in move_workdir, parent directory '%s' not found: %m", copy); + return -1; + } else if (create_directory(copy, dirmode, 1)) { + ERROR("in move_workdir, creation of directory %s failed: %m", copy); + return -1; + } + } + } + + /* try to rename now */ + close(workdirfd); + workdirfd = -1; + rc = renameat(AT_FDCWD, workdir, AT_FDCWD, dest); + if (rc) { + ERROR("in move_workdir, renameat failed %s -> %s: %m", workdir, dest); + return -1; + } + + return set_workdir(dest, 0); +} +