Make lttng_directory_handle reference countable
[lttng-tools.git] / src / common / compat / directory-handle.c
index 95be9ec3d7cfeada460dad1238e1ca06dac53695..d9d1e233757bdb76bbabdc51436ac13b02388574 100644 (file)
@@ -88,62 +88,79 @@ int _run_as_rmdir_recursive(
                uid_t uid, gid_t gid, int flags);
 static
 void lttng_directory_handle_invalidate(struct lttng_directory_handle *handle);
+static
+void lttng_directory_handle_release(struct urcu_ref *ref);
 
 #ifdef COMPAT_DIRFD
 
 LTTNG_HIDDEN
-int lttng_directory_handle_init(struct lttng_directory_handle *new_handle,
-               const char *path)
+struct lttng_directory_handle *lttng_directory_handle_create(const char *path)
 {
        const struct lttng_directory_handle cwd_handle = {
                .dirfd = AT_FDCWD,
        };
 
        /* Open a handle to the CWD if NULL is passed. */
-       return lttng_directory_handle_init_from_handle(new_handle,
-                       path,
-                       &cwd_handle);
+       return lttng_directory_handle_create_from_handle(path, &cwd_handle);
 }
 
 LTTNG_HIDDEN
-int lttng_directory_handle_init_from_handle(
-               struct lttng_directory_handle *new_handle, const char *path,
-               const struct lttng_directory_handle *handle)
+struct lttng_directory_handle *lttng_directory_handle_create_from_handle(
+               const char *path,
+               const struct lttng_directory_handle *ref_handle)
 {
-       int ret;
+       int dirfd;
+       struct lttng_directory_handle *handle = NULL;
 
        if (!path) {
-               ret = lttng_directory_handle_copy(handle, new_handle);
+               handle = lttng_directory_handle_copy(ref_handle);
                goto end;
        }
        if (!*path) {
                ERR("Failed to initialize directory handle: provided path is an empty string");
-               ret = -1;
                goto end;
        }
-       ret = openat(handle->dirfd, path, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
-       if (ret == -1) {
+
+       dirfd = openat(ref_handle->dirfd, path, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
+       if (dirfd == -1) {
                PERROR("Failed to initialize directory handle to \"%s\"", path);
                goto end;
        }
-       new_handle->dirfd = ret;
-       ret = 0;
+
+       handle = lttng_directory_handle_create_from_dirfd(dirfd);
+       if (!handle) {
+               goto error_close;
+       }
 end:
-       return ret;
+       return handle;
+error_close:
+       if (close(dirfd)) {
+               PERROR("Failed to close directory file descriptor");
+       }
+       return NULL;
 }
 
 LTTNG_HIDDEN
-int lttng_directory_handle_init_from_dirfd(
-               struct lttng_directory_handle *handle, int dirfd)
+struct lttng_directory_handle *lttng_directory_handle_create_from_dirfd(
+               int dirfd)
 {
+       struct lttng_directory_handle *handle = zmalloc(sizeof(*handle));
+
+       if (!handle) {
+               goto end;
+       }
        handle->dirfd = dirfd;
-       return 0;
+       urcu_ref_init(&handle->ref);
+end:
+       return handle;
 }
 
-LTTNG_HIDDEN
-void lttng_directory_handle_fini(struct lttng_directory_handle *handle)
+static
+void lttng_directory_handle_release(struct urcu_ref *ref)
 {
        int ret;
+       struct lttng_directory_handle *handle =
+                       container_of(ref, struct lttng_directory_handle, ref);
 
        if (handle->dirfd == AT_FDCWD || handle->dirfd == -1) {
                goto end;
@@ -151,28 +168,35 @@ void lttng_directory_handle_fini(struct lttng_directory_handle *handle)
        ret = close(handle->dirfd);
        if (ret == -1) {
                PERROR("Failed to close directory file descriptor of directory handle");
-               abort();
        }
 end:
        lttng_directory_handle_invalidate(handle);
+       free(handle);
 }
 
 LTTNG_HIDDEN
-int lttng_directory_handle_copy(const struct lttng_directory_handle *handle,
-               struct lttng_directory_handle *new_copy)
+struct lttng_directory_handle *lttng_directory_handle_copy(
+               const struct lttng_directory_handle *handle)
 {
-       int ret = 0;
+       struct lttng_directory_handle *new_handle = NULL;
 
        if (handle->dirfd == AT_FDCWD) {
-               new_copy->dirfd = handle->dirfd;
+               new_handle = lttng_directory_handle_create_from_dirfd(AT_FDCWD);
        } else {
-               new_copy->dirfd = dup(handle->dirfd);
-               if (new_copy->dirfd == -1) {
-                       PERROR("Failed to duplicate directory fd of directory handle");
-                       ret = -1;
+               const int new_dirfd = dup(handle->dirfd);
+
+               if (new_dirfd == -1) {
+                       PERROR("Failed to duplicate directory file descriptor of directory handle");
+                       goto end;
+               }
+               new_handle = lttng_directory_handle_create_from_dirfd(
+                               new_dirfd);
+               if (!new_handle && close(new_dirfd)) {
+                       PERROR("Failed to close directory file descriptor of directory handle");
                }
        }
-       return ret;
+end:
+       return new_handle;
 }
 
 static
@@ -343,8 +367,22 @@ end:
        return ret;
 }
 
+static
+struct lttng_directory_handle *_lttng_directory_handle_create(char *path)
+{
+       struct lttng_directory_handle *handle = zmalloc(sizeof(*handle));
+
+       if (!handle) {
+               goto end;
+       }
+       urcu_ref_init(&handle->ref);
+       handle->base_path = path;
+end:
+       return handle;
+}
+
 LTTNG_HIDDEN
-int lttng_directory_handle_init(struct lttng_directory_handle *handle,
+struct lttng_directory_handle *lttng_directory_handle_create(
                const char *path)
 {
        int ret;
@@ -352,6 +390,7 @@ int lttng_directory_handle_init(struct lttng_directory_handle *handle,
        size_t cwd_len, path_len;
        char cwd_buf[LTTNG_PATH_MAX] = {};
        char handle_buf[LTTNG_PATH_MAX] = {};
+       struct lttng_directory_handle *new_handle = NULL;
        bool add_cwd_slash = false, add_trailing_slash = false;
        const struct lttng_directory_handle cwd_handle = {
                .base_path = handle_buf,
@@ -385,25 +424,26 @@ int lttng_directory_handle_init(struct lttng_directory_handle *handle,
                goto end;
        }
 
-       ret = lttng_directory_handle_init_from_handle(handle, path,
-                       &cwd_handle);
+       new_handle = lttng_directory_handle_create_from_handle(path, &cwd_handle);
 end:
-       return ret;
+       return new_handle;
 }
 
 LTTNG_HIDDEN
-int lttng_directory_handle_init_from_handle(
-               struct lttng_directory_handle *new_handle, const char *path,
-               const struct lttng_directory_handle *handle)
+struct lttng_directory_handle *lttng_directory_handle_create_from_handle(
+               const char *path,
+               const struct lttng_directory_handle *ref_handle)
 {
        int ret;
        size_t path_len, handle_path_len;
        bool add_trailing_slash;
        struct stat stat_buf;
+       struct lttng_directory_handle *new_handle = NULL;
+       char *new_path = NULL;
 
-       assert(handle && handle->base_path);
+       assert(ref_handle && ref_handle->base_path);
 
-       ret = lttng_directory_handle_stat(handle, path, &stat_buf);
+       ret = lttng_directory_handle_stat(ref_handle, path, &stat_buf);
        if (ret == -1) {
                PERROR("Failed to create directory handle");
                goto end;
@@ -411,7 +451,7 @@ int lttng_directory_handle_init_from_handle(
                char full_path[LTTNG_PATH_MAX];
 
                /* Best effort for logging purposes. */
-               ret = get_full_path(handle, path, full_path,
+               ret = get_full_path(ref_handle, path, full_path,
                                sizeof(full_path));
                if (ret) {
                        full_path[0] = '\0';
@@ -419,11 +459,10 @@ int lttng_directory_handle_init_from_handle(
 
                ERR("Failed to initialize directory handle to \"%s\": not a directory",
                                full_path);
-               ret = -1;
                goto end;
        }
        if (!path) {
-               ret = lttng_directory_handle_copy(handle, new_handle);
+               new_handle = lttng_directory_handle_copy(ref_handle);
                goto end;
        }
 
@@ -434,62 +473,81 @@ int lttng_directory_handle_init_from_handle(
                goto end;
        }
        if (*path == '/') {
-               new_handle->base_path = strdup(path);
-               ret = new_handle->base_path ? 0 : -1;
+               new_path = strdup(path);
+               if (!new_path) {
+                       goto end;
+               }
+               /* Takes ownership of new_path. */
+               new_handle = _lttng_directory_handle_create(new_path);
+               new_path = NULL;
                goto end;
        }
 
        add_trailing_slash = path[path_len - 1] != '/';
 
-       handle_path_len = strlen(handle->base_path) + path_len +
+       handle_path_len = strlen(ref_handle->base_path) + path_len +
                        !!add_trailing_slash;
        if (handle_path_len >= LTTNG_PATH_MAX) {
                ERR("Failed to initialize directory handle as the resulting path's length (%zu bytes) exceeds the maximal allowed length (%d bytes)",
                                handle_path_len, LTTNG_PATH_MAX);
-               ret = -1;
                goto end;
        }
-       new_handle->base_path = zmalloc(handle_path_len);
-       if (!new_handle->base_path) {
+       new_path = zmalloc(handle_path_len);
+       if (!new_path) {
                PERROR("Failed to initialize directory handle");
-               ret = -1;
                goto end;
        }
 
        ret = sprintf(new_handle->base_path, "%s%s%s",
-                       handle->base_path,
+                       ref_handle->base_path,
                        path,
                        add_trailing_slash ? "/" : "");
        if (ret == -1 || ret >= handle_path_len) {
                ERR("Failed to initialize directory handle: path formatting failed");
-               ret = -1;
                goto end;
        }
+       new_handle = _lttng_directory_handle_create(new_path);
+       new_path = NULL;
 end:
-       return ret;
+       free(new_path);
+       return new_handle;
 }
 
 LTTNG_HIDDEN
-int lttng_directory_handle_init_from_dirfd(
-               struct lttng_directory_handle *handle, int dirfd)
+struct lttng_directory_handle *lttng_directory_handle_create_from_dirfd(
+               int dirfd)
 {
        assert(dirfd == AT_FDCWD);
-       return lttng_directory_handle_init(handle, NULL);
+       return lttng_directory_handle_create(NULL);
 }
 
-LTTNG_HIDDEN
-void lttng_directory_handle_fini(struct lttng_directory_handle *handle)
+static
+void lttng_directory_handle_release(struct urcu_ref *ref)
 {
+       struct lttng_directory_handle *handle =
+                       container_of(ref, struct lttng_directory_handle, ref);
+
        free(handle->base_path);
        lttng_directory_handle_invalidate(handle);
+       free(handle);
 }
 
 LTTNG_HIDDEN
-int lttng_directory_handle_copy(const struct lttng_directory_handle *handle,
-               struct lttng_directory_handle *new_copy)
+struct lttng_directory_handle *lttng_directory_handle_copy(
+               const struct lttng_directory_handle *handle)
 {
-       new_copy->base_path = strdup(handle->base_path);
-       return new_copy->base_path ? 0 : -1;
+       struct lttng_directory_handle *new_handle = NULL;
+       char *new_path = NULL;
+
+       if (handle->base_path) {
+               new_path = strdup(handle->base_path);
+               if (!new_path) {
+                       goto end;
+               }
+       }
+       new_handle = _lttng_directory_handle_create(new_path);
+end:
+       return new_handle;
 }
 
 static
@@ -819,16 +877,6 @@ end:
        return ret;
 }
 
-LTTNG_HIDDEN
-struct lttng_directory_handle
-lttng_directory_handle_move(struct lttng_directory_handle *original)
-{
-       const struct lttng_directory_handle tmp = *original;
-
-       lttng_directory_handle_invalidate(original);
-       return tmp;
-}
-
 static
 int create_directory_recursive(const struct lttng_directory_handle *handle,
                const char *path, mode_t mode)
@@ -884,6 +932,22 @@ error:
        return ret;
 }
 
+LTTNG_HIDDEN
+bool lttng_directory_handle_get(struct lttng_directory_handle *handle)
+{
+       return urcu_ref_get_unless_zero(&handle->ref);
+}
+
+LTTNG_HIDDEN
+void lttng_directory_handle_put(struct lttng_directory_handle *handle)
+{
+       if (!handle) {
+               return;
+       }
+       assert(handle->ref.refcount);
+       urcu_ref_put(&handle->ref, lttng_directory_handle_release);
+}
+
 LTTNG_HIDDEN
 int lttng_directory_handle_create_subdirectory_as_user(
                const struct lttng_directory_handle *handle,
This page took 0.027694 seconds and 4 git commands to generate.