X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fcommon%2Fcompat%2Fdirectory-handle.c;h=4dad7b75744a7d81305910a3d86556cca3179bf1;hp=d6fb7037b663396a190615772e7860f319eabaff;hb=f75c5439a7fe3d47edf68098f249421b701fceaf;hpb=2fdaeb7e6ba9952cc083027fbe591fd6b69cbe80;ds=sidebyside diff --git a/src/common/compat/directory-handle.c b/src/common/compat/directory-handle.c index d6fb7037b..4dad7b757 100644 --- a/src/common/compat/directory-handle.c +++ b/src/common/compat/directory-handle.c @@ -85,7 +85,7 @@ int _run_as_rmdir(const struct lttng_directory_handle *handle, static int _run_as_rmdir_recursive( const struct lttng_directory_handle *handle, const char *name, - uid_t uid, gid_t gid); + uid_t uid, gid_t gid, int flags); static void lttng_directory_handle_invalidate(struct lttng_directory_handle *handle); @@ -305,9 +305,9 @@ int _run_as_rmdir(const struct lttng_directory_handle *handle, static int _run_as_rmdir_recursive( const struct lttng_directory_handle *handle, const char *name, - uid_t uid, gid_t gid) + uid_t uid, gid_t gid, int flags) { - return run_as_rmdirat_recursive(handle->dirfd, name, uid, gid); + return run_as_rmdirat_recursive(handle->dirfd, name, uid, gid, flags); } #else /* COMPAT_DIRFD */ @@ -759,7 +759,7 @@ end: static int _run_as_rmdir_recursive( const struct lttng_directory_handle *handle, const char *name, - uid_t uid, gid_t gid) + uid_t uid, gid_t gid, int flags) { int ret; char fullpath[LTTNG_PATH_MAX]; @@ -770,7 +770,7 @@ int _run_as_rmdir_recursive( goto end; } - ret = run_as_rmdir_recursive(fullpath, uid, gid); + ret = run_as_rmdir_recursive(fullpath, uid, gid, flags); end: return ret; } @@ -1059,7 +1059,9 @@ int lttng_directory_handle_remove_subdirectory_as_user( } struct rmdir_frame { + ssize_t parent_frame_idx; DIR *dir; + bool empty; /* Size including '\0'. */ size_t path_size; }; @@ -1074,13 +1076,15 @@ void rmdir_frame_fini(void *data) static int remove_directory_recursive(const struct lttng_directory_handle *handle, - const char *path) + const char *path, int flags) { int ret; struct lttng_dynamic_array frames; size_t current_frame_idx = 0; struct rmdir_frame initial_frame = { + .parent_frame_idx = -1, .dir = lttng_directory_handle_opendir(handle, path), + .empty = true, .path_size = strlen(path) + 1, }; struct lttng_dynamic_buffer current_path; @@ -1088,7 +1092,27 @@ int remove_directory_recursive(const struct lttng_directory_handle *handle, lttng_dynamic_buffer_init(¤t_path); lttng_dynamic_array_init(&frames, sizeof(struct rmdir_frame), - rmdir_frame_fini); + rmdir_frame_fini); + + if (flags & ~(LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG | + LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG)) { + ERR("Unknown flags %d", flags); + ret = -1; + goto end; + } + + if (!initial_frame.dir) { + if (flags & LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG && + errno == ENOENT) { + DBG("Cannot rmdir \"%s\": root does not exist", path); + ret = 0; + goto end; + } else { + PERROR("Failed to rmdir \"%s\"", path); + ret = -1; + goto end; + } + } ret = lttng_dynamic_array_add_element(&frames, &initial_frame); if (ret) { @@ -1097,42 +1121,37 @@ int remove_directory_recursive(const struct lttng_directory_handle *handle, goto end; } - ret = lttng_dynamic_buffer_append(¤t_path, path, - initial_frame.path_size); - if (ret) { + ret = lttng_dynamic_buffer_append( + ¤t_path, path, initial_frame.path_size); + if (ret) { ERR("Failed to set initial path during recursive directory removal"); ret = -1; goto end; - } + } - while (lttng_dynamic_array_get_count(&frames) > 0) { + while (lttng_dynamic_array_get_count(&frames) > 0) { struct dirent *entry; struct rmdir_frame *current_frame = - lttng_dynamic_array_get_element(&frames, - current_frame_idx); + lttng_dynamic_array_get_element( + &frames, current_frame_idx); - if (!current_frame->dir) { - PERROR("Failed to open directory stream during recursive directory removal"); - ret = -1; - goto end; - } - ret = lttng_dynamic_buffer_set_size(¤t_path, - current_frame->path_size); + assert(current_frame->dir); + ret = lttng_dynamic_buffer_set_size( + ¤t_path, current_frame->path_size); assert(!ret); current_path.data[current_path.size - 1] = '\0'; while ((entry = readdir(current_frame->dir))) { struct stat st; - struct rmdir_frame new_frame; - if (!strcmp(entry->d_name, ".") - || !strcmp(entry->d_name, "..")) { + if (!strcmp(entry->d_name, ".") || + !strcmp(entry->d_name, "..")) { continue; } /* Set current_path to the entry's path. */ - ret = lttng_dynamic_buffer_set_size(¤t_path, - current_path.size - 1); + ret = lttng_dynamic_buffer_set_size( + ¤t_path, current_path.size - 1); assert(!ret); ret = lttng_dynamic_buffer_append(¤t_path, &separator, sizeof(separator)); @@ -1146,8 +1165,12 @@ int remove_directory_recursive(const struct lttng_directory_handle *handle, goto end; } - if (lttng_directory_handle_stat(handle, - current_path.data, &st)) { + if (lttng_directory_handle_stat( + handle, current_path.data, &st)) { + if ((flags & LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG) && + errno == ENOENT) { + break; + } PERROR("Failed to stat \"%s\"", current_path.data); ret = -1; @@ -1155,42 +1178,81 @@ int remove_directory_recursive(const struct lttng_directory_handle *handle, } if (!S_ISDIR(st.st_mode)) { - /* Not empty, abort. */ - DBG("Directory \"%s\" is not empty; refusing to remove directory", - current_path.data); - ret = -1; - goto end; + if (flags & LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG) { + current_frame->empty = false; + break; + } else { + /* Not empty, abort. */ + DBG("Directory \"%s\" is not empty; refusing to remove directory", + current_path.data); + ret = -1; + goto end; + } + } else { + struct rmdir_frame new_frame = { + .path_size = current_path.size, + .dir = lttng_directory_handle_opendir( + handle, + current_path.data), + .empty = true, + .parent_frame_idx = current_frame_idx, + }; + + if (!new_frame.dir) { + if (flags & LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG && + errno == ENOENT) { + DBG("Non-existing directory stream during recursive directory removal"); + break; + } else { + PERROR("Failed to open directory stream during recursive directory removal"); + ret = -1; + goto end; + } + } + ret = lttng_dynamic_array_add_element( + &frames, &new_frame); + if (ret) { + ERR("Failed to push context frame during recursive directory removal"); + rmdir_frame_fini(&new_frame); + goto end; + } + current_frame_idx++; + /* We break iteration on readdir. */ + break; } + } + if (entry) { + continue; + } - new_frame.path_size = current_path.size; - new_frame.dir = lttng_directory_handle_opendir(handle, - current_path.data); - ret = lttng_dynamic_array_add_element(&frames, - &new_frame); - if (ret) { - ERR("Failed to push context frame during recursive directory removal"); - rmdir_frame_fini(&new_frame); - goto end; - } - current_frame_idx++; - break; - } - if (!entry) { - ret = lttng_directory_handle_rmdir(handle, - current_path.data); - if (ret) { - PERROR("Failed to remove \"%s\" during recursive directory removal", - current_path.data); - goto end; - } - ret = lttng_dynamic_array_remove_element(&frames, - current_frame_idx); + /* Pop rmdir frame. */ + if (current_frame->empty) { + ret = lttng_directory_handle_rmdir( + handle, current_path.data); if (ret) { - ERR("Failed to pop context frame during recursive directory removal"); - goto end; + if ((flags & LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG) || + errno != ENOENT) { + PERROR("Failed to remove \"%s\" during recursive directory removal", + current_path.data); + goto end; + } + DBG("Non-existing directory stream during recursive directory removal"); } - current_frame_idx--; - } + } else if (current_frame->parent_frame_idx >= 0) { + struct rmdir_frame *parent_frame; + + parent_frame = lttng_dynamic_array_get_element(&frames, + current_frame->parent_frame_idx); + assert(parent_frame); + parent_frame->empty = false; + } + ret = lttng_dynamic_array_remove_element( + &frames, current_frame_idx); + if (ret) { + ERR("Failed to pop context frame during recursive directory removal"); + goto end; + } + current_frame_idx--; } end: lttng_dynamic_array_reset(&frames); @@ -1201,26 +1263,28 @@ end: LTTNG_HIDDEN int lttng_directory_handle_remove_subdirectory_recursive( const struct lttng_directory_handle *handle, - const char *name) + const char *name, + int flags) { return lttng_directory_handle_remove_subdirectory_recursive_as_user( - handle, name, NULL); + handle, name, NULL, flags); } LTTNG_HIDDEN int lttng_directory_handle_remove_subdirectory_recursive_as_user( const struct lttng_directory_handle *handle, const char *name, - const struct lttng_credentials *creds) + const struct lttng_credentials *creds, + int flags) { int ret; if (!creds) { /* Run as current user. */ - ret = remove_directory_recursive(handle, name); + ret = remove_directory_recursive(handle, name, flags); } else { ret = _run_as_rmdir_recursive(handle, name, creds->uid, - creds->gid); + creds->gid, flags); } return ret; }