2 * Copyright (C) 2019 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
8 #include <common/compat/directory-handle.hpp>
9 #include <common/error.hpp>
10 #include <common/macros.hpp>
11 #include <common/runas.hpp>
12 #include <common/credentials.hpp>
13 #include <lttng/constant.h>
14 #include <common/dynamic-array.hpp>
16 #include <sys/types.h>
23 * This compatibility layer shares a common "base" that is implemented
24 * in terms of an internal API. This file contains two implementations
25 * of the internal API below.
28 int lttng_directory_handle_mkdir(
29 const struct lttng_directory_handle
*handle
,
30 const char *path
, mode_t mode
);
32 int _run_as_mkdir(const struct lttng_directory_handle
*handle
, const char *path
,
33 mode_t mode
, uid_t uid
, gid_t gid
);
35 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
36 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
);
38 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
39 const char *filename
, int flags
, mode_t mode
);
41 int _run_as_open(const struct lttng_directory_handle
*handle
,
43 int flags
, mode_t mode
, uid_t uid
, gid_t gid
);
45 int lttng_directory_handle_unlink(
46 const struct lttng_directory_handle
*handle
,
47 const char *filename
);
49 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
50 const char *filename
, uid_t uid
, gid_t gid
);
52 int _lttng_directory_handle_rename(
53 const struct lttng_directory_handle
*old_handle
,
55 const struct lttng_directory_handle
*new_handle
,
56 const char *new_name
);
58 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
60 const struct lttng_directory_handle
*new_handle
,
61 const char *new_name
, uid_t uid
, gid_t gid
);
63 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
66 int lttng_directory_handle_rmdir(
67 const struct lttng_directory_handle
*handle
, const char *name
);
69 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
70 const char *name
, uid_t uid
, gid_t gid
);
72 int _run_as_rmdir_recursive(
73 const struct lttng_directory_handle
*handle
, const char *name
,
74 uid_t uid
, gid_t gid
, int flags
);
76 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
);
78 void lttng_directory_handle_release(struct urcu_ref
*ref
);
83 * Special inode number reserved to represent the "current working directory".
84 * ino_t is spec'ed as being an unsigned integral type.
86 #define RESERVED_AT_FDCWD_INO \
88 uint64_t reserved_val; \
89 switch (sizeof(ino_t)) { \
91 reserved_val = UINT32_MAX; \
94 reserved_val = UINT64_MAX; \
99 (ino_t) reserved_val; \
102 struct lttng_directory_handle
*lttng_directory_handle_create(const char *path
)
104 lttng_directory_handle cwd_handle
{};
105 cwd_handle
.dirfd
= AT_FDCWD
;
107 /* Open a handle to the CWD if NULL is passed. */
108 return lttng_directory_handle_create_from_handle(path
, &cwd_handle
);
111 struct lttng_directory_handle
*lttng_directory_handle_create_from_handle(
113 const struct lttng_directory_handle
*ref_handle
)
116 struct lttng_directory_handle
*handle
= NULL
;
119 handle
= lttng_directory_handle_copy(ref_handle
);
123 ERR("Failed to initialize directory handle: provided path is an empty string");
127 dirfd
= openat(ref_handle
->dirfd
, path
, O_RDONLY
| O_DIRECTORY
| O_CLOEXEC
);
129 PERROR("Failed to initialize directory handle to \"%s\"", path
);
133 handle
= lttng_directory_handle_create_from_dirfd(dirfd
);
141 PERROR("Failed to close directory file descriptor");
146 struct lttng_directory_handle
*lttng_directory_handle_create_from_dirfd(
150 struct lttng_directory_handle
*handle
= (lttng_directory_handle
*) zmalloc(sizeof(*handle
));
151 struct stat stat_buf
;
157 if (dirfd
!= AT_FDCWD
) {
158 ret
= fstat(dirfd
, &stat_buf
);
160 PERROR("Failed to fstat directory file descriptor %i", dirfd
);
161 lttng_directory_handle_release(&handle
->ref
);
166 handle
->directory_inode
= RESERVED_AT_FDCWD_INO
;
168 handle
->dirfd
= dirfd
;
169 urcu_ref_init(&handle
->ref
);
175 void lttng_directory_handle_release(struct urcu_ref
*ref
)
178 struct lttng_directory_handle
*handle
=
179 container_of(ref
, struct lttng_directory_handle
, ref
);
181 if (handle
->destroy_cb
) {
182 handle
->destroy_cb(handle
, handle
->destroy_cb_data
);
185 if (handle
->dirfd
== AT_FDCWD
|| handle
->dirfd
== -1) {
188 ret
= close(handle
->dirfd
);
190 PERROR("Failed to close directory file descriptor of directory handle");
193 lttng_directory_handle_invalidate(handle
);
197 struct lttng_directory_handle
*lttng_directory_handle_copy(
198 const struct lttng_directory_handle
*handle
)
200 struct lttng_directory_handle
*new_handle
= NULL
;
202 if (handle
->dirfd
== AT_FDCWD
) {
203 new_handle
= lttng_directory_handle_create_from_dirfd(AT_FDCWD
);
205 const int new_dirfd
= dup(handle
->dirfd
);
207 if (new_dirfd
== -1) {
208 PERROR("Failed to duplicate directory file descriptor of directory handle");
211 new_handle
= lttng_directory_handle_create_from_dirfd(
213 if (!new_handle
&& close(new_dirfd
)) {
214 PERROR("Failed to close directory file descriptor of directory handle");
221 bool lttng_directory_handle_equals(const struct lttng_directory_handle
*lhs
,
222 const struct lttng_directory_handle
*rhs
)
224 return lhs
->directory_inode
== rhs
->directory_inode
;
228 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
)
233 int lttng_directory_handle_stat(const struct lttng_directory_handle
*handle
,
234 const char *path
, struct stat
*st
)
236 return fstatat(handle
->dirfd
, path
, st
, 0);
239 bool lttng_directory_handle_uses_fd(
240 const struct lttng_directory_handle
*handle
)
242 return handle
->dirfd
!= AT_FDCWD
;
246 int lttng_directory_handle_mkdir(
247 const struct lttng_directory_handle
*handle
,
248 const char *path
, mode_t mode
)
250 return mkdirat(handle
->dirfd
, path
, mode
);
254 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
255 const char *filename
, int flags
, mode_t mode
)
257 return openat(handle
->dirfd
, filename
, flags
, mode
);
261 int _run_as_open(const struct lttng_directory_handle
*handle
,
262 const char *filename
,
263 int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
265 return run_as_openat(handle
->dirfd
, filename
, flags
, mode
, uid
, gid
);
269 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
270 const char *filename
, uid_t uid
, gid_t gid
)
272 return run_as_unlinkat(handle
->dirfd
, filename
, uid
, gid
);
276 int lttng_directory_handle_unlink(
277 const struct lttng_directory_handle
*handle
,
278 const char *filename
)
280 return unlinkat(handle
->dirfd
, filename
, 0);
284 int _run_as_mkdir(const struct lttng_directory_handle
*handle
,
285 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
287 return run_as_mkdirat(handle
->dirfd
, path
, mode
, uid
, gid
);
291 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
292 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
294 return run_as_mkdirat_recursive(handle
->dirfd
, path
, mode
, uid
, gid
);
298 int _lttng_directory_handle_rename(
299 const struct lttng_directory_handle
*old_handle
,
300 const char *old_name
,
301 const struct lttng_directory_handle
*new_handle
,
302 const char *new_name
)
304 return renameat(old_handle
->dirfd
, old_name
,
305 new_handle
->dirfd
, new_name
);
309 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
310 const char *old_name
,
311 const struct lttng_directory_handle
*new_handle
,
312 const char *new_name
, uid_t uid
, gid_t gid
)
314 return run_as_renameat(old_handle
->dirfd
, old_name
, new_handle
->dirfd
,
319 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
322 DIR *dir_stream
= NULL
;
323 int fd
= openat(handle
->dirfd
, path
, O_RDONLY
);
329 dir_stream
= fdopendir(fd
);
333 PERROR("Failed to open directory stream");
336 PERROR("Failed to close file descriptor to %s", path
);
346 int lttng_directory_handle_rmdir(
347 const struct lttng_directory_handle
*handle
, const char *name
)
349 int ret
= unlinkat(handle
->dirfd
, name
, AT_REMOVEDIR
);
351 PERROR("Failed to remove directory `%s`", name
);
358 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
359 const char *name
, uid_t uid
, gid_t gid
)
361 return run_as_rmdirat(handle
->dirfd
, name
, uid
, gid
);
365 int _run_as_rmdir_recursive(
366 const struct lttng_directory_handle
*handle
, const char *name
,
367 uid_t uid
, gid_t gid
, int flags
)
369 return run_as_rmdirat_recursive(handle
->dirfd
, name
, uid
, gid
, flags
);
372 #else /* HAVE_DIRFD */
375 int get_full_path(const struct lttng_directory_handle
*handle
,
376 const char *subdirectory
, char *fullpath
, size_t size
)
379 const bool subdirectory_is_absolute
=
380 subdirectory
&& *subdirectory
== '/';
381 const char * const base
= subdirectory_is_absolute
?
382 subdirectory
: handle
->base_path
;
383 const char * const end
= subdirectory
&& !subdirectory_is_absolute
?
385 const size_t base_len
= strlen(base
);
386 const size_t end_len
= end
? strlen(end
) : 0;
387 const bool add_separator_slash
= end
&& base
[base_len
- 1] != '/';
388 const bool add_trailing_slash
= end
&& end
[end_len
- 1] != '/';
390 ret
= snprintf(fullpath
, size
, "%s%s%s%s",
392 add_separator_slash
? "/" : "",
394 add_trailing_slash
? "/" : "");
395 if (ret
== -1 || ret
>= size
) {
396 ERR("Failed to format subdirectory from directory handle");
406 struct lttng_directory_handle
*_lttng_directory_handle_create(char *path
)
408 struct lttng_directory_handle
*handle
= zmalloc(sizeof(*handle
));
413 urcu_ref_init(&handle
->ref
);
414 handle
->base_path
= path
;
419 struct lttng_directory_handle
*lttng_directory_handle_create(
423 const char *cwd
= "";
424 size_t cwd_len
, path_len
;
425 char cwd_buf
[LTTNG_PATH_MAX
] = {};
426 char handle_buf
[LTTNG_PATH_MAX
] = {};
427 struct lttng_directory_handle
*new_handle
= NULL
;
428 bool add_cwd_slash
= false, add_trailing_slash
= false;
429 const struct lttng_directory_handle cwd_handle
= {
430 .base_path
= handle_buf
,
433 path_len
= path
? strlen(path
) : 0;
434 add_trailing_slash
= path
&& path
[path_len
- 1] != '/';
435 if (!path
|| (path
&& *path
!= '/')) {
436 cwd
= getcwd(cwd_buf
, sizeof(cwd_buf
));
438 PERROR("Failed to initialize directory handle, can't get current working directory");
442 cwd_len
= strlen(cwd
);
444 ERR("Failed to initialize directory handle, current working directory path has a length of 0");
448 add_cwd_slash
= cwd
[cwd_len
- 1] != '/';
451 ret
= snprintf(handle_buf
, sizeof(handle_buf
), "%s%s%s%s",
453 add_cwd_slash
? "/" : "",
455 add_trailing_slash
? "/" : "");
456 if (ret
== -1 || ret
>= LTTNG_PATH_MAX
) {
457 ERR("Failed to initialize directory handle, failed to format directory path");
461 new_handle
= lttng_directory_handle_create_from_handle(path
, &cwd_handle
);
466 struct lttng_directory_handle
*lttng_directory_handle_create_from_handle(
468 const struct lttng_directory_handle
*ref_handle
)
471 size_t path_len
, handle_path_len
;
472 bool add_trailing_slash
;
473 struct stat stat_buf
;
474 struct lttng_directory_handle
*new_handle
= NULL
;
475 char *new_path
= NULL
;
477 LTTNG_ASSERT(ref_handle
&& ref_handle
->base_path
);
479 ret
= lttng_directory_handle_stat(ref_handle
, path
, &stat_buf
);
481 PERROR("Failed to create directory handle");
483 } else if (!S_ISDIR(stat_buf
.st_mode
)) {
484 char full_path
[LTTNG_PATH_MAX
];
486 /* Best effort for logging purposes. */
487 ret
= get_full_path(ref_handle
, path
, full_path
,
493 ERR("Failed to initialize directory handle to \"%s\": not a directory",
498 new_handle
= lttng_directory_handle_copy(ref_handle
);
502 path_len
= strlen(path
);
504 ERR("Failed to initialize directory handle: provided path is an empty string");
509 new_path
= strdup(path
);
513 /* Takes ownership of new_path. */
514 new_handle
= _lttng_directory_handle_create(new_path
);
519 add_trailing_slash
= path
[path_len
- 1] != '/';
521 handle_path_len
= strlen(ref_handle
->base_path
) + path_len
+
522 !!add_trailing_slash
;
523 if (handle_path_len
>= LTTNG_PATH_MAX
) {
524 ERR("Failed to initialize directory handle as the resulting path's length (%zu bytes) exceeds the maximal allowed length (%d bytes)",
525 handle_path_len
, LTTNG_PATH_MAX
);
528 new_path
= zmalloc(handle_path_len
);
530 PERROR("Failed to initialize directory handle");
534 ret
= sprintf(new_handle
->base_path
, "%s%s%s",
535 ref_handle
->base_path
,
537 add_trailing_slash
? "/" : "");
538 if (ret
== -1 || ret
>= handle_path_len
) {
539 ERR("Failed to initialize directory handle: path formatting failed");
542 new_handle
= _lttng_directory_handle_create(new_path
);
549 struct lttng_directory_handle
*lttng_directory_handle_create_from_dirfd(
552 LTTNG_ASSERT(dirfd
== AT_FDCWD
);
553 return lttng_directory_handle_create(NULL
);
557 void lttng_directory_handle_release(struct urcu_ref
*ref
)
559 struct lttng_directory_handle
*handle
=
560 container_of(ref
, struct lttng_directory_handle
, ref
);
562 free(handle
->base_path
);
563 lttng_directory_handle_invalidate(handle
);
567 struct lttng_directory_handle
*lttng_directory_handle_copy(
568 const struct lttng_directory_handle
*handle
)
570 struct lttng_directory_handle
*new_handle
= NULL
;
571 char *new_path
= NULL
;
573 if (handle
->base_path
) {
574 new_path
= strdup(handle
->base_path
);
579 new_handle
= _lttng_directory_handle_create(new_path
);
584 bool lttng_directory_handle_equals(const struct lttng_directory_handle
*lhs
,
585 const struct lttng_directory_handle
*rhs
)
587 return strcmp(lhs
->base_path
, rhs
->base_path
) == 0;
591 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
)
593 handle
->base_path
= NULL
;
596 int lttng_directory_handle_stat(const struct lttng_directory_handle
*handle
,
597 const char *subdirectory
, struct stat
*st
)
600 char fullpath
[LTTNG_PATH_MAX
];
602 ret
= get_full_path(handle
, subdirectory
, fullpath
, sizeof(fullpath
));
608 ret
= stat(fullpath
, st
);
613 bool lttng_directory_handle_uses_fd(
614 const struct lttng_directory_handle
*handle
)
620 int lttng_directory_handle_mkdir(const struct lttng_directory_handle
*handle
,
621 const char *subdirectory
, mode_t mode
)
624 char fullpath
[LTTNG_PATH_MAX
];
626 ret
= get_full_path(handle
, subdirectory
, fullpath
, sizeof(fullpath
));
632 ret
= mkdir(fullpath
, mode
);
638 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
639 const char *filename
, int flags
, mode_t mode
)
642 char fullpath
[LTTNG_PATH_MAX
];
644 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
650 ret
= open(fullpath
, flags
, mode
);
656 int lttng_directory_handle_unlink(
657 const struct lttng_directory_handle
*handle
,
658 const char *filename
)
661 char fullpath
[LTTNG_PATH_MAX
];
663 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
669 ret
= unlink(fullpath
);
675 int _run_as_mkdir(const struct lttng_directory_handle
*handle
, const char *path
,
676 mode_t mode
, uid_t uid
, gid_t gid
)
679 char fullpath
[LTTNG_PATH_MAX
];
681 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
687 ret
= run_as_mkdir(fullpath
, mode
, uid
, gid
);
693 int _run_as_open(const struct lttng_directory_handle
*handle
,
694 const char *filename
,
695 int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
698 char fullpath
[LTTNG_PATH_MAX
];
700 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
706 ret
= run_as_open(fullpath
, flags
, mode
, uid
, gid
);
712 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
713 const char *filename
, uid_t uid
, gid_t gid
)
716 char fullpath
[LTTNG_PATH_MAX
];
718 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
724 ret
= run_as_unlink(fullpath
, uid
, gid
);
730 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
731 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
734 char fullpath
[LTTNG_PATH_MAX
];
736 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
742 ret
= run_as_mkdir_recursive(fullpath
, mode
, uid
, gid
);
748 int _lttng_directory_handle_rename(
749 const struct lttng_directory_handle
*old_handle
,
750 const char *old_name
,
751 const struct lttng_directory_handle
*new_handle
,
752 const char *new_name
)
755 char old_fullpath
[LTTNG_PATH_MAX
];
756 char new_fullpath
[LTTNG_PATH_MAX
];
758 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
759 sizeof(old_fullpath
));
764 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
765 sizeof(new_fullpath
));
771 ret
= rename(old_fullpath
, new_fullpath
);
777 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
778 const char *old_name
,
779 const struct lttng_directory_handle
*new_handle
,
780 const char *new_name
, uid_t uid
, gid_t gid
)
783 char old_fullpath
[LTTNG_PATH_MAX
];
784 char new_fullpath
[LTTNG_PATH_MAX
];
786 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
787 sizeof(old_fullpath
));
792 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
793 sizeof(new_fullpath
));
799 ret
= run_as_rename(old_fullpath
, new_fullpath
, uid
, gid
);
805 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
809 DIR *dir_stream
= NULL
;
810 char fullpath
[LTTNG_PATH_MAX
];
812 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
818 dir_stream
= opendir(fullpath
);
824 int lttng_directory_handle_rmdir(
825 const struct lttng_directory_handle
*handle
, const char *name
)
828 char fullpath
[LTTNG_PATH_MAX
];
830 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
836 ret
= rmdir(fullpath
);
842 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
843 const char *name
, uid_t uid
, gid_t gid
)
846 char fullpath
[LTTNG_PATH_MAX
];
848 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
854 ret
= run_as_rmdir(fullpath
, uid
, gid
);
860 int _run_as_rmdir_recursive(
861 const struct lttng_directory_handle
*handle
, const char *name
,
862 uid_t uid
, gid_t gid
, int flags
)
865 char fullpath
[LTTNG_PATH_MAX
];
867 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
873 ret
= run_as_rmdir_recursive(fullpath
, uid
, gid
, flags
);
878 #endif /* HAVE_DIRFD */
880 /* Common implementation. */
883 * On some filesystems (e.g. nfs), mkdir will validate access rights before
884 * checking for the existence of the path element. This means that on a setup
885 * where "/home/" is a mounted NFS share, and running as an unpriviledged user,
886 * recursively creating a path of the form "/home/my_user/trace/" will fail with
887 * EACCES on mkdir("/home", ...).
889 * Checking the path for existence allows us to work around this behaviour.
892 int create_directory_check_exists(const struct lttng_directory_handle
*handle
,
893 const char *path
, mode_t mode
)
898 ret
= lttng_directory_handle_stat(handle
, path
, &st
);
900 if (S_ISDIR(st
.st_mode
)) {
901 /* Directory exists, skip. */
904 /* Exists, but is not a directory. */
909 } else if (errno
!= ENOENT
) {
914 * Let mkdir handle other errors as the caller expects mkdir
917 ret
= lttng_directory_handle_mkdir(handle
, path
, mode
);
923 int create_directory_recursive(const struct lttng_directory_handle
*handle
,
924 const char *path
, mode_t mode
)
926 char *p
, tmp
[LTTNG_PATH_MAX
];
932 ret
= lttng_strncpy(tmp
, path
, sizeof(tmp
));
934 ERR("Failed to create directory: provided path's length (%zu bytes) exceeds the maximal allowed length (%zu bytes)",
935 strlen(path
) + 1, sizeof(tmp
));
940 if (tmp
[len
- 1] == '/') {
944 for (p
= tmp
+ 1; *p
; p
++) {
947 if (tmp
[strlen(tmp
) - 1] == '.' &&
948 tmp
[strlen(tmp
) - 2] == '.' &&
949 tmp
[strlen(tmp
) - 3] == '/') {
950 ERR("Using '/../' is not permitted in the trace path (%s)",
955 ret
= create_directory_check_exists(handle
, tmp
, mode
);
957 if (errno
!= EACCES
) {
958 PERROR("Failed to create directory \"%s\"",
968 ret
= create_directory_check_exists(handle
, tmp
, mode
);
970 PERROR("mkdirat recursive last element");
977 bool lttng_directory_handle_get(struct lttng_directory_handle
*handle
)
979 return urcu_ref_get_unless_zero(&handle
->ref
);
982 void lttng_directory_handle_put(struct lttng_directory_handle
*handle
)
987 LTTNG_ASSERT(handle
->ref
.refcount
);
988 urcu_ref_put(&handle
->ref
, lttng_directory_handle_release
);
991 int lttng_directory_handle_create_subdirectory_as_user(
992 const struct lttng_directory_handle
*handle
,
993 const char *subdirectory
,
994 mode_t mode
, const struct lttng_credentials
*creds
)
999 /* Run as current user. */
1000 ret
= create_directory_check_exists(handle
,
1001 subdirectory
, mode
);
1003 ret
= _run_as_mkdir(handle
, subdirectory
, mode
,
1004 lttng_credentials_get_uid(creds
),
1005 lttng_credentials_get_gid(creds
));
1011 int lttng_directory_handle_create_subdirectory_recursive_as_user(
1012 const struct lttng_directory_handle
*handle
,
1013 const char *subdirectory_path
,
1014 mode_t mode
, const struct lttng_credentials
*creds
)
1019 /* Run as current user. */
1020 ret
= create_directory_recursive(handle
,
1021 subdirectory_path
, mode
);
1023 ret
= _run_as_mkdir_recursive(handle
, subdirectory_path
,
1024 mode
, lttng_credentials_get_uid(creds
), lttng_credentials_get_gid(creds
));
1030 int lttng_directory_handle_create_subdirectory(
1031 const struct lttng_directory_handle
*handle
,
1032 const char *subdirectory
,
1035 return lttng_directory_handle_create_subdirectory_as_user(
1036 handle
, subdirectory
, mode
, NULL
);
1039 int lttng_directory_handle_create_subdirectory_recursive(
1040 const struct lttng_directory_handle
*handle
,
1041 const char *subdirectory_path
,
1044 return lttng_directory_handle_create_subdirectory_recursive_as_user(
1045 handle
, subdirectory_path
, mode
, NULL
);
1048 int lttng_directory_handle_open_file_as_user(
1049 const struct lttng_directory_handle
*handle
,
1050 const char *filename
,
1051 int flags
, mode_t mode
,
1052 const struct lttng_credentials
*creds
)
1057 /* Run as current user. */
1058 ret
= lttng_directory_handle_open(handle
, filename
, flags
,
1061 ret
= _run_as_open(handle
, filename
, flags
, mode
,
1062 lttng_credentials_get_uid(creds
), lttng_credentials_get_gid(creds
));
1067 int lttng_directory_handle_open_file(
1068 const struct lttng_directory_handle
*handle
,
1069 const char *filename
,
1070 int flags
, mode_t mode
)
1072 return lttng_directory_handle_open_file_as_user(handle
, filename
, flags
,
1076 int lttng_directory_handle_unlink_file_as_user(
1077 const struct lttng_directory_handle
*handle
,
1078 const char *filename
,
1079 const struct lttng_credentials
*creds
)
1084 /* Run as current user. */
1085 ret
= lttng_directory_handle_unlink(handle
, filename
);
1087 ret
= _run_as_unlink(handle
, filename
, lttng_credentials_get_uid(creds
), lttng_credentials_get_gid(creds
));
1092 int lttng_directory_handle_unlink_file(
1093 const struct lttng_directory_handle
*handle
,
1094 const char *filename
)
1096 return lttng_directory_handle_unlink_file_as_user(handle
,
1100 int lttng_directory_handle_rename(
1101 const struct lttng_directory_handle
*old_handle
,
1102 const char *old_name
,
1103 const struct lttng_directory_handle
*new_handle
,
1104 const char *new_name
)
1106 return lttng_directory_handle_rename_as_user(old_handle
, old_name
,
1107 new_handle
, new_name
, NULL
);
1110 int lttng_directory_handle_rename_as_user(
1111 const struct lttng_directory_handle
*old_handle
,
1112 const char *old_name
,
1113 const struct lttng_directory_handle
*new_handle
,
1114 const char *new_name
,
1115 const struct lttng_credentials
*creds
)
1120 /* Run as current user. */
1121 ret
= _lttng_directory_handle_rename(old_handle
,
1122 old_name
, new_handle
, new_name
);
1124 ret
= _run_as_rename(old_handle
, old_name
, new_handle
,
1125 new_name
, lttng_credentials_get_uid(creds
), lttng_credentials_get_gid(creds
));
1130 int lttng_directory_handle_remove_subdirectory(
1131 const struct lttng_directory_handle
*handle
,
1134 return lttng_directory_handle_remove_subdirectory_as_user(handle
, name
,
1138 int lttng_directory_handle_remove_subdirectory_as_user(
1139 const struct lttng_directory_handle
*handle
,
1141 const struct lttng_credentials
*creds
)
1146 /* Run as current user. */
1147 ret
= lttng_directory_handle_rmdir(handle
, name
);
1149 ret
= _run_as_rmdir(handle
, name
, lttng_credentials_get_uid(creds
), lttng_credentials_get_gid(creds
));
1154 struct rmdir_frame
{
1155 ssize_t parent_frame_idx
;
1158 /* Size including '\0'. */
1163 void rmdir_frame_fini(void *data
)
1166 struct rmdir_frame
*frame
= (rmdir_frame
*) data
;
1168 ret
= closedir(frame
->dir
);
1170 PERROR("Failed to close directory stream");
1175 int remove_directory_recursive(const struct lttng_directory_handle
*handle
,
1176 const char *path
, int flags
)
1179 struct lttng_dynamic_array frames
;
1180 size_t current_frame_idx
= 0;
1181 struct rmdir_frame initial_frame
= {
1182 .parent_frame_idx
= -1,
1183 .dir
= lttng_directory_handle_opendir(handle
, path
),
1185 .path_size
= strlen(path
) + 1,
1187 struct lttng_dynamic_buffer current_path
;
1188 const char separator
= '/';
1190 lttng_dynamic_buffer_init(¤t_path
);
1191 lttng_dynamic_array_init(&frames
, sizeof(struct rmdir_frame
),
1194 if (flags
& ~(LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
|
1195 LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG
)) {
1196 ERR("Unknown flags %d", flags
);
1201 if (!initial_frame
.dir
) {
1202 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
&&
1204 DBG("Cannot rmdir \"%s\": root does not exist", path
);
1208 PERROR("Failed to rmdir \"%s\"", path
);
1214 ret
= lttng_dynamic_array_add_element(&frames
, &initial_frame
);
1216 ERR("Failed to push context frame during recursive directory removal");
1217 rmdir_frame_fini(&initial_frame
);
1221 ret
= lttng_dynamic_buffer_append(
1222 ¤t_path
, path
, initial_frame
.path_size
);
1224 ERR("Failed to set initial path during recursive directory removal");
1229 while (lttng_dynamic_array_get_count(&frames
) > 0) {
1230 struct dirent
*entry
;
1231 struct rmdir_frame
*current_frame
=
1232 (rmdir_frame
*) lttng_dynamic_array_get_element(
1233 &frames
, current_frame_idx
);
1235 LTTNG_ASSERT(current_frame
->dir
);
1236 ret
= lttng_dynamic_buffer_set_size(
1237 ¤t_path
, current_frame
->path_size
);
1239 current_path
.data
[current_path
.size
- 1] = '\0';
1241 while ((entry
= readdir(current_frame
->dir
))) {
1244 if (!strcmp(entry
->d_name
, ".") ||
1245 !strcmp(entry
->d_name
, "..")) {
1249 /* Set current_path to the entry's path. */
1250 ret
= lttng_dynamic_buffer_set_size(
1251 ¤t_path
, current_path
.size
- 1);
1253 ret
= lttng_dynamic_buffer_append(¤t_path
,
1254 &separator
, sizeof(separator
));
1258 ret
= lttng_dynamic_buffer_append(¤t_path
,
1260 strlen(entry
->d_name
) + 1);
1265 if (lttng_directory_handle_stat(
1266 handle
, current_path
.data
, &st
)) {
1267 if ((flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
) &&
1271 PERROR("Failed to stat \"%s\"",
1277 if (!S_ISDIR(st
.st_mode
)) {
1278 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
) {
1279 current_frame
->empty
= false;
1282 /* Not empty, abort. */
1283 DBG("Directory \"%s\" is not empty; refusing to remove directory",
1289 struct rmdir_frame new_frame
= {
1290 .parent_frame_idx
= (ssize_t
) current_frame_idx
,
1291 .dir
= lttng_directory_handle_opendir(
1295 .path_size
= current_path
.size
,
1298 if (!new_frame
.dir
) {
1299 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
&&
1301 DBG("Non-existing directory stream during recursive directory removal");
1304 PERROR("Failed to open directory stream during recursive directory removal");
1309 ret
= lttng_dynamic_array_add_element(
1310 &frames
, &new_frame
);
1312 ERR("Failed to push context frame during recursive directory removal");
1313 rmdir_frame_fini(&new_frame
);
1316 current_frame_idx
++;
1317 /* We break iteration on readdir. */
1325 /* Pop rmdir frame. */
1326 if (current_frame
->empty
) {
1327 ret
= lttng_directory_handle_rmdir(
1328 handle
, current_path
.data
);
1330 if ((flags
& LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG
) ||
1332 PERROR("Failed to remove \"%s\" during recursive directory removal",
1336 DBG("Non-existing directory stream during recursive directory removal");
1338 } else if (current_frame
->parent_frame_idx
>= 0) {
1339 struct rmdir_frame
*parent_frame
;
1341 parent_frame
= (rmdir_frame
*) lttng_dynamic_array_get_element(&frames
,
1342 current_frame
->parent_frame_idx
);
1343 LTTNG_ASSERT(parent_frame
);
1344 parent_frame
->empty
= false;
1346 ret
= lttng_dynamic_array_remove_element(
1347 &frames
, current_frame_idx
);
1349 ERR("Failed to pop context frame during recursive directory removal");
1352 current_frame_idx
--;
1355 lttng_dynamic_array_reset(&frames
);
1356 lttng_dynamic_buffer_reset(¤t_path
);
1360 int lttng_directory_handle_remove_subdirectory_recursive(
1361 const struct lttng_directory_handle
*handle
,
1365 return lttng_directory_handle_remove_subdirectory_recursive_as_user(
1366 handle
, name
, NULL
, flags
);
1369 int lttng_directory_handle_remove_subdirectory_recursive_as_user(
1370 const struct lttng_directory_handle
*handle
,
1372 const struct lttng_credentials
*creds
,
1378 /* Run as current user. */
1379 ret
= remove_directory_recursive(handle
, name
, flags
);
1381 ret
= _run_as_rmdir_recursive(handle
, name
, lttng_credentials_get_uid(creds
),
1382 lttng_credentials_get_gid(creds
), flags
);