+
+ rename_directory = lttng_directory_handle_create_from_handle(
+ path, chunk->session_output_directory);
+ if (!rename_directory) {
+ ERR("Failed to get handle to trace chunk rename directory");
+ status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+ goto end;
+ }
+
+ /* Move toplevel directories. */
+ for (i = 0; i < count; i++) {
+ const char *top_level_name =
+ lttng_dynamic_pointer_array_get_pointer(
+ &chunk->top_level_directories, i);
+
+ ret = lttng_directory_handle_rename_as_user(
+ chunk->chunk_directory,
+ top_level_name,
+ rename_directory,
+ top_level_name,
+ LTTNG_OPTIONAL_GET(chunk->credentials).use_current_user ?
+ NULL :
+ &chunk->credentials.value.user);
+ if (ret) {
+ PERROR("Failed to move \"%s\" to trace chunk rename directory",
+ top_level_name);
+ status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+ goto end;
+ }
+ }
+ /* Release old handle. */
+ lttng_directory_handle_put(chunk->chunk_directory);
+ /*
+ * Transfer new handle reference to chunk as the current chunk
+ * handle.
+ */
+ chunk->chunk_directory = rename_directory;
+ rename_directory = NULL;
+ } else if (old_path) {
+ size_t i, count = lttng_dynamic_pointer_array_get_count(
+ &chunk->top_level_directories);
+ const bool reference_acquired = lttng_directory_handle_get(
+ chunk->session_output_directory);
+
+ LTTNG_ASSERT(reference_acquired);
+ rename_directory = chunk->session_output_directory;
+
+ /* Move toplevel directories. */
+ for (i = 0; i < count; i++) {
+ const char *top_level_name =
+ lttng_dynamic_pointer_array_get_pointer(
+ &chunk->top_level_directories, i);
+
+ ret = lttng_directory_handle_rename_as_user(
+ chunk->chunk_directory,
+ top_level_name,
+ rename_directory,
+ top_level_name,
+ LTTNG_OPTIONAL_GET(chunk->credentials).use_current_user ?
+ NULL :
+ &chunk->credentials.value.user);
+ if (ret) {
+ PERROR("Failed to move \"%s\" to trace chunk rename directory",
+ top_level_name);
+ status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+ goto end;
+ }
+ }
+ /* Release old handle. */
+ lttng_directory_handle_put(chunk->chunk_directory);
+ /*
+ * Transfer new handle reference to chunk as the current chunk
+ * handle.
+ */
+ chunk->chunk_directory = rename_directory;
+ rename_directory = NULL;
+
+ /* Remove old directory. */
+ status = lttng_directory_handle_remove_subdirectory(
+ chunk->session_output_directory,
+ old_path);
+ if (status != LTTNG_TRACE_CHUNK_STATUS_OK) {
+ ERR("Error removing subdirectory '%s' file when deleting chunk",
+ old_path);
+ goto end;
+ }
+ } else {
+ /* Unexpected !old_path && !path. */
+ status = LTTNG_TRACE_CHUNK_STATUS_INVALID_ARGUMENT;
+ goto end;
+ }
+
+skip_move:
+ new_path = strdup(path);
+ if (!new_path) {
+ ERR("Failed to allocate new trace chunk path");
+ status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+ goto end;
+ }
+ free(chunk->path);
+ chunk->path = new_path;
+end:
+ lttng_directory_handle_put(rename_directory);
+ return status;
+}
+
+enum lttng_trace_chunk_status lttng_trace_chunk_rename_path(
+ struct lttng_trace_chunk *chunk, const char *path)
+
+{
+ enum lttng_trace_chunk_status status;
+
+ pthread_mutex_lock(&chunk->lock);
+ status = lttng_trace_chunk_rename_path_no_lock(chunk, path);
+ pthread_mutex_unlock(&chunk->lock);
+
+ return status;
+}
+
+enum lttng_trace_chunk_status lttng_trace_chunk_get_credentials(
+ struct lttng_trace_chunk *chunk,
+ struct lttng_credentials *credentials)
+{
+ enum lttng_trace_chunk_status status = LTTNG_TRACE_CHUNK_STATUS_OK;
+
+ pthread_mutex_lock(&chunk->lock);
+ if (chunk->credentials.is_set) {
+ if (chunk->credentials.value.use_current_user) {
+ LTTNG_OPTIONAL_SET(&credentials->uid, geteuid());
+ LTTNG_OPTIONAL_SET(&credentials->gid, getegid());
+ } else {
+ *credentials = chunk->credentials.value.user;
+ }
+ } else {
+ status = LTTNG_TRACE_CHUNK_STATUS_NONE;
+ }
+ pthread_mutex_unlock(&chunk->lock);
+ return status;
+}
+
+enum lttng_trace_chunk_status lttng_trace_chunk_set_credentials(
+ struct lttng_trace_chunk *chunk,
+ const struct lttng_credentials *user_credentials)
+{
+ enum lttng_trace_chunk_status status = LTTNG_TRACE_CHUNK_STATUS_OK;
+ const struct chunk_credentials credentials = {
+ .user = *user_credentials,
+ .use_current_user = false,
+ };
+
+ pthread_mutex_lock(&chunk->lock);
+ if (chunk->credentials.is_set) {
+ status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+ goto end;
+ }
+ LTTNG_OPTIONAL_SET(&chunk->credentials, credentials);
+end:
+ pthread_mutex_unlock(&chunk->lock);
+ return status;
+}
+
+enum lttng_trace_chunk_status lttng_trace_chunk_set_credentials_current_user(
+ struct lttng_trace_chunk *chunk)
+{
+ enum lttng_trace_chunk_status status = LTTNG_TRACE_CHUNK_STATUS_OK;
+ const struct chunk_credentials credentials = {
+ .use_current_user = true,
+ };
+
+ pthread_mutex_lock(&chunk->lock);
+ if (chunk->credentials.is_set) {
+ status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+ goto end;
+ }
+ LTTNG_OPTIONAL_SET(&chunk->credentials, credentials);
+end:
+ pthread_mutex_unlock(&chunk->lock);
+ return status;
+}
+
+
+enum lttng_trace_chunk_status lttng_trace_chunk_set_as_owner(
+ struct lttng_trace_chunk *chunk,
+ struct lttng_directory_handle *session_output_directory)
+{
+ int ret;
+ enum lttng_trace_chunk_status status = LTTNG_TRACE_CHUNK_STATUS_OK;
+ struct lttng_directory_handle *chunk_directory_handle = NULL;
+ bool reference_acquired;
+
+ pthread_mutex_lock(&chunk->lock);
+ if (chunk->mode.is_set) {
+ status = LTTNG_TRACE_CHUNK_STATUS_INVALID_OPERATION;
+ goto end;
+ }
+ if (!chunk->credentials.is_set) {
+ /*
+ * Fatal error, credentials must be set before a
+ * directory is created.
+ */
+ ERR("Credentials of trace chunk are unset: refusing to set session output directory");
+ status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+ goto end;
+ }
+ if (chunk->path && chunk->path[0] != '\0') {
+ ret = lttng_directory_handle_create_subdirectory_as_user(
+ session_output_directory,
+ chunk->path,
+ DIR_CREATION_MODE,
+ !chunk->credentials.value.use_current_user ?
+ &chunk->credentials.value.user : NULL);
+ if (ret) {
+ PERROR("Failed to create chunk output directory \"%s\"",
+ chunk->path);
+ status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+ goto end;
+ }
+ chunk_directory_handle =
+ chunk->fd_tracker ?
+ fd_tracker_create_directory_handle_from_handle(
+ chunk->fd_tracker,
+ session_output_directory,
+ chunk->path) :
+ lttng_directory_handle_create_from_handle(
+ chunk->path,
+ session_output_directory);
+ if (!chunk_directory_handle) {
+ /* The function already logs on all error paths. */
+ status = LTTNG_TRACE_CHUNK_STATUS_ERROR;
+ goto end;
+ }
+ } else {
+ /*
+ * A nameless chunk does not need its own output directory.
+ * The session's output directory will be used.
+ */
+ reference_acquired = lttng_directory_handle_get(
+ session_output_directory);
+
+ LTTNG_ASSERT(reference_acquired);
+ chunk_directory_handle = session_output_directory;
+ }
+ chunk->chunk_directory = chunk_directory_handle;
+ chunk_directory_handle = NULL;
+ reference_acquired = lttng_directory_handle_get(
+ session_output_directory);
+ LTTNG_ASSERT(reference_acquired);
+ chunk->session_output_directory = session_output_directory;
+ LTTNG_OPTIONAL_SET(&chunk->mode, TRACE_CHUNK_MODE_OWNER);
+end: