X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fcommon%2Futils.c;h=6e772671451aec4e90e9943dd4c78eddd087c083;hp=11018739be9ad9c7e6a83340a2434fdc2fc654c1;hb=a98e236e95719aa9c777a8cb1569a66daf0d576f;hpb=d1f721c52e3810dcb38429cb3beec9f80043aa57 diff --git a/src/common/utils.c b/src/common/utils.c index 11018739b..6e7726714 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -30,12 +30,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include "utils.h" #include "defaults.h" @@ -81,6 +83,8 @@ char *utils_partial_realpath(const char *path, char *resolved_path, size_t size) /* Resolve the canonical path of the first part of the path */ while (try_path != NULL && next != end) { + char *try_path_buf = NULL; + /* * If there is not any '/' left, we want to try with * the full path @@ -97,9 +101,16 @@ char *utils_partial_realpath(const char *path, char *resolved_path, size_t size) goto error; } + try_path_buf = zmalloc(LTTNG_PATH_MAX); + if (!try_path_buf) { + PERROR("zmalloc"); + goto error; + } + /* Try to resolve this part */ - try_path = realpath((char *)cut_path, NULL); + try_path = realpath((char *) cut_path, try_path_buf); if (try_path == NULL) { + free(try_path_buf); /* * There was an error, we just want to be assured it * is linked to an unexistent directory, if it's another @@ -116,6 +127,7 @@ char *utils_partial_realpath(const char *path, char *resolved_path, size_t size) } } else { /* Save the place we are before trying the next step */ + try_path_buf = NULL; free(try_path_prev); try_path_prev = try_path; prev = next; @@ -540,6 +552,44 @@ error: return fd; } +/* + * On some filesystems (e.g. nfs), mkdir will validate access rights before + * checking for the existence of the path element. This means that on a setup + * where "/home/" is a mounted NFS share, and running as an unpriviledged user, + * recursively creating a path of the form "/home/my_user/trace/" will fail with + * EACCES on mkdir("/home", ...). + * + * Performing a stat(...) on the path to check for existence allows us to + * work around this behaviour. + */ +static +int mkdir_check_exists(const char *path, mode_t mode) +{ + int ret = 0; + struct stat st; + + ret = stat(path, &st); + if (ret == 0) { + if (S_ISDIR(st.st_mode)) { + /* Directory exists, skip. */ + goto end; + } else { + /* Exists, but is not a directory. */ + errno = ENOTDIR; + ret = -1; + goto end; + } + } + + /* + * Let mkdir handle other errors as the caller expects mkdir + * semantics. + */ + ret = mkdir(path, mode); +end: + return ret; +} + /* * Create directory using the given path and mode. * @@ -551,7 +601,7 @@ int utils_mkdir(const char *path, mode_t mode, int uid, int gid) int ret; if (uid < 0 || gid < 0) { - ret = mkdir(path, mode); + ret = mkdir_check_exists(path, mode); } else { ret = run_as_mkdir(path, mode, uid, gid); } @@ -606,9 +656,9 @@ int _utils_mkdir_recursive_unsafe(const char *path, mode_t mode) ret = -1; goto error; } - ret = mkdir(tmp, mode); + ret = mkdir_check_exists(tmp, mode); if (ret < 0) { - if (errno != EEXIST) { + if (errno != EACCES) { PERROR("mkdir recursive"); ret = -errno; goto error; @@ -618,14 +668,10 @@ int _utils_mkdir_recursive_unsafe(const char *path, mode_t mode) } } - ret = mkdir(tmp, mode); + ret = mkdir_check_exists(tmp, mode); if (ret < 0) { - if (errno != EEXIST) { - PERROR("mkdir recursive last element"); - ret = -errno; - } else { - ret = 0; - } + PERROR("mkdir recursive last element"); + ret = -errno; } error: @@ -1220,14 +1266,15 @@ int utils_recursive_rmdir(const char *path) path_len = strlen(path); while ((entry = readdir(dir))) { - if (!strcmp(entry->d_name, ".") - || !strcmp(entry->d_name, "..")) - continue; - struct stat st; size_t name_len; char filename[PATH_MAX]; + if (!strcmp(entry->d_name, ".") + || !strcmp(entry->d_name, "..")) { + continue; + } + name_len = strlen(entry->d_name); if (path_len + name_len + 2 > sizeof(filename)) { ERR("Failed to remove file: path name too long (%s/%s)",