2 * Copyright (C) 2019 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 * SPDX-License-Identifier: GPL-2.0-only
8 #include <common/compat/directory-handle.h>
9 #include <common/error.h>
10 #include <common/macros.h>
11 #include <common/runas.h>
12 #include <common/credentials.h>
13 #include <lttng/constant.h>
14 #include <common/dynamic-array.h>
17 #include <sys/types.h>
24 * This compatibility layer shares a common "base" that is implemented
25 * in terms of an internal API. This file contains two implementations
26 * of the internal API below.
29 int lttng_directory_handle_mkdir(
30 const struct lttng_directory_handle
*handle
,
31 const char *path
, mode_t mode
);
33 int _run_as_mkdir(const struct lttng_directory_handle
*handle
, const char *path
,
34 mode_t mode
, uid_t uid
, gid_t gid
);
36 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
37 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
);
39 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
40 const char *filename
, int flags
, mode_t mode
);
42 int _run_as_open(const struct lttng_directory_handle
*handle
,
44 int flags
, mode_t mode
, uid_t uid
, gid_t gid
);
46 int lttng_directory_handle_unlink(
47 const struct lttng_directory_handle
*handle
,
48 const char *filename
);
50 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
51 const char *filename
, uid_t uid
, gid_t gid
);
53 int _lttng_directory_handle_rename(
54 const struct lttng_directory_handle
*old_handle
,
56 const struct lttng_directory_handle
*new_handle
,
57 const char *new_name
);
59 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
61 const struct lttng_directory_handle
*new_handle
,
62 const char *new_name
, uid_t uid
, gid_t gid
);
64 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
67 int lttng_directory_handle_rmdir(
68 const struct lttng_directory_handle
*handle
, const char *name
);
70 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
71 const char *name
, uid_t uid
, gid_t gid
);
73 int _run_as_rmdir_recursive(
74 const struct lttng_directory_handle
*handle
, const char *name
,
75 uid_t uid
, gid_t gid
, int flags
);
77 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
);
79 void lttng_directory_handle_release(struct urcu_ref
*ref
);
84 * Special inode number reserved to represent the "current working directory".
85 * ino_t is spec'ed as being an unsigned integral type.
87 #define RESERVED_AT_FDCWD_INO \
89 uint64_t reserved_val; \
90 switch (sizeof(ino_t)) { \
92 reserved_val = UINT32_MAX; \
95 reserved_val = UINT64_MAX; \
100 (ino_t) reserved_val; \
104 struct lttng_directory_handle
*lttng_directory_handle_create(const char *path
)
106 const struct lttng_directory_handle cwd_handle
= {
110 /* Open a handle to the CWD if NULL is passed. */
111 return lttng_directory_handle_create_from_handle(path
, &cwd_handle
);
115 struct lttng_directory_handle
*lttng_directory_handle_create_from_handle(
117 const struct lttng_directory_handle
*ref_handle
)
120 struct lttng_directory_handle
*handle
= NULL
;
123 handle
= lttng_directory_handle_copy(ref_handle
);
127 ERR("Failed to initialize directory handle: provided path is an empty string");
131 dirfd
= openat(ref_handle
->dirfd
, path
, O_RDONLY
| O_DIRECTORY
| O_CLOEXEC
);
133 PERROR("Failed to initialize directory handle to \"%s\"", path
);
137 handle
= lttng_directory_handle_create_from_dirfd(dirfd
);
145 PERROR("Failed to close directory file descriptor");
151 struct lttng_directory_handle
*lttng_directory_handle_create_from_dirfd(
155 struct lttng_directory_handle
*handle
= zmalloc(sizeof(*handle
));
156 struct stat stat_buf
;
162 if (dirfd
!= AT_FDCWD
) {
163 ret
= fstat(dirfd
, &stat_buf
);
165 PERROR("Failed to fstat directory file descriptor %i", dirfd
);
166 lttng_directory_handle_release(&handle
->ref
);
169 handle
->directory_inode
= RESERVED_AT_FDCWD_INO
;
171 handle
->dirfd
= dirfd
;
172 urcu_ref_init(&handle
->ref
);
178 void lttng_directory_handle_release(struct urcu_ref
*ref
)
181 struct lttng_directory_handle
*handle
=
182 container_of(ref
, struct lttng_directory_handle
, ref
);
184 if (handle
->destroy_cb
) {
185 handle
->destroy_cb(handle
, handle
->destroy_cb_data
);
188 if (handle
->dirfd
== AT_FDCWD
|| handle
->dirfd
== -1) {
191 ret
= close(handle
->dirfd
);
193 PERROR("Failed to close directory file descriptor of directory handle");
196 lttng_directory_handle_invalidate(handle
);
201 struct lttng_directory_handle
*lttng_directory_handle_copy(
202 const struct lttng_directory_handle
*handle
)
204 struct lttng_directory_handle
*new_handle
= NULL
;
206 if (handle
->dirfd
== AT_FDCWD
) {
207 new_handle
= lttng_directory_handle_create_from_dirfd(AT_FDCWD
);
209 const int new_dirfd
= dup(handle
->dirfd
);
211 if (new_dirfd
== -1) {
212 PERROR("Failed to duplicate directory file descriptor of directory handle");
215 new_handle
= lttng_directory_handle_create_from_dirfd(
217 if (!new_handle
&& close(new_dirfd
)) {
218 PERROR("Failed to close directory file descriptor of directory handle");
226 bool lttng_directory_handle_equals(const struct lttng_directory_handle
*lhs
,
227 const struct lttng_directory_handle
*rhs
)
229 return lhs
->directory_inode
== rhs
->directory_inode
;
233 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
)
239 int lttng_directory_handle_stat(const struct lttng_directory_handle
*handle
,
240 const char *path
, struct stat
*st
)
242 return fstatat(handle
->dirfd
, path
, st
, 0);
246 bool lttng_directory_handle_uses_fd(
247 const struct lttng_directory_handle
*handle
)
249 return handle
->dirfd
!= AT_FDCWD
;
253 int lttng_directory_handle_mkdir(
254 const struct lttng_directory_handle
*handle
,
255 const char *path
, mode_t mode
)
257 return mkdirat(handle
->dirfd
, path
, mode
);
261 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
262 const char *filename
, int flags
, mode_t mode
)
264 return openat(handle
->dirfd
, filename
, flags
, mode
);
268 int _run_as_open(const struct lttng_directory_handle
*handle
,
269 const char *filename
,
270 int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
272 return run_as_openat(handle
->dirfd
, filename
, flags
, mode
, uid
, gid
);
276 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
277 const char *filename
, uid_t uid
, gid_t gid
)
279 return run_as_unlinkat(handle
->dirfd
, filename
, uid
, gid
);
283 int lttng_directory_handle_unlink(
284 const struct lttng_directory_handle
*handle
,
285 const char *filename
)
287 return unlinkat(handle
->dirfd
, filename
, 0);
291 int _run_as_mkdir(const struct lttng_directory_handle
*handle
,
292 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
294 return run_as_mkdirat(handle
->dirfd
, path
, mode
, uid
, gid
);
298 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
299 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
301 return run_as_mkdirat_recursive(handle
->dirfd
, path
, mode
, uid
, gid
);
305 int _lttng_directory_handle_rename(
306 const struct lttng_directory_handle
*old_handle
,
307 const char *old_name
,
308 const struct lttng_directory_handle
*new_handle
,
309 const char *new_name
)
311 return renameat(old_handle
->dirfd
, old_name
,
312 new_handle
->dirfd
, new_name
);
316 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
317 const char *old_name
,
318 const struct lttng_directory_handle
*new_handle
,
319 const char *new_name
, uid_t uid
, gid_t gid
)
321 return run_as_renameat(old_handle
->dirfd
, old_name
, new_handle
->dirfd
,
326 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
329 DIR *dir_stream
= NULL
;
330 int fd
= openat(handle
->dirfd
, path
, O_RDONLY
);
336 dir_stream
= fdopendir(fd
);
340 PERROR("Failed to open directory stream");
343 PERROR("Failed to close file descriptor to %s", path
);
353 int lttng_directory_handle_rmdir(
354 const struct lttng_directory_handle
*handle
, const char *name
)
356 return unlinkat(handle
->dirfd
, name
, AT_REMOVEDIR
);
360 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
361 const char *name
, uid_t uid
, gid_t gid
)
363 return run_as_rmdirat(handle
->dirfd
, name
, uid
, gid
);
367 int _run_as_rmdir_recursive(
368 const struct lttng_directory_handle
*handle
, const char *name
,
369 uid_t uid
, gid_t gid
, int flags
)
371 return run_as_rmdirat_recursive(handle
->dirfd
, name
, uid
, gid
, flags
);
374 #else /* COMPAT_DIRFD */
377 int get_full_path(const struct lttng_directory_handle
*handle
,
378 const char *subdirectory
, char *fullpath
, size_t size
)
381 const bool subdirectory_is_absolute
=
382 subdirectory
&& *subdirectory
== '/';
383 const char * const base
= subdirectory_is_absolute
?
384 subdirectory
: handle
->base_path
;
385 const char * const end
= subdirectory
&& !subdirectory_is_absolute
?
387 const size_t base_len
= strlen(base
);
388 const size_t end_len
= end
? strlen(end
) : 0;
389 const bool add_separator_slash
= end
&& base
[base_len
- 1] != '/';
390 const bool add_trailing_slash
= end
&& end
[end_len
- 1] != '/';
392 ret
= snprintf(fullpath
, size
, "%s%s%s%s",
394 add_separator_slash
? "/" : "",
396 add_trailing_slash
? "/" : "");
397 if (ret
== -1 || ret
>= size
) {
398 ERR("Failed to format subdirectory from directory handle");
408 struct lttng_directory_handle
*_lttng_directory_handle_create(char *path
)
410 struct lttng_directory_handle
*handle
= zmalloc(sizeof(*handle
));
415 urcu_ref_init(&handle
->ref
);
416 handle
->base_path
= path
;
422 struct lttng_directory_handle
*lttng_directory_handle_create(
426 const char *cwd
= "";
427 size_t cwd_len
, path_len
;
428 char cwd_buf
[LTTNG_PATH_MAX
] = {};
429 char handle_buf
[LTTNG_PATH_MAX
] = {};
430 struct lttng_directory_handle
*new_handle
= NULL
;
431 bool add_cwd_slash
= false, add_trailing_slash
= false;
432 const struct lttng_directory_handle cwd_handle
= {
433 .base_path
= handle_buf
,
436 path_len
= path
? strlen(path
) : 0;
437 add_trailing_slash
= path
&& path
[path_len
- 1] != '/';
438 if (!path
|| (path
&& *path
!= '/')) {
439 cwd
= getcwd(cwd_buf
, sizeof(cwd_buf
));
441 PERROR("Failed to initialize directory handle, can't get current working directory");
445 cwd_len
= strlen(cwd
);
447 ERR("Failed to initialize directory handle, current working directory path has a length of 0");
451 add_cwd_slash
= cwd
[cwd_len
- 1] != '/';
454 ret
= snprintf(handle_buf
, sizeof(handle_buf
), "%s%s%s%s",
456 add_cwd_slash
? "/" : "",
458 add_trailing_slash
? "/" : "");
459 if (ret
== -1 || ret
>= LTTNG_PATH_MAX
) {
460 ERR("Failed to initialize directory handle, failed to format directory path");
464 new_handle
= lttng_directory_handle_create_from_handle(path
, &cwd_handle
);
470 struct lttng_directory_handle
*lttng_directory_handle_create_from_handle(
472 const struct lttng_directory_handle
*ref_handle
)
475 size_t path_len
, handle_path_len
;
476 bool add_trailing_slash
;
477 struct stat stat_buf
;
478 struct lttng_directory_handle
*new_handle
= NULL
;
479 char *new_path
= NULL
;
481 assert(ref_handle
&& ref_handle
->base_path
);
483 ret
= lttng_directory_handle_stat(ref_handle
, path
, &stat_buf
);
485 PERROR("Failed to create directory handle");
487 } else if (!S_ISDIR(stat_buf
.st_mode
)) {
488 char full_path
[LTTNG_PATH_MAX
];
490 /* Best effort for logging purposes. */
491 ret
= get_full_path(ref_handle
, path
, full_path
,
497 ERR("Failed to initialize directory handle to \"%s\": not a directory",
502 new_handle
= lttng_directory_handle_copy(ref_handle
);
506 path_len
= strlen(path
);
508 ERR("Failed to initialize directory handle: provided path is an empty string");
513 new_path
= strdup(path
);
517 /* Takes ownership of new_path. */
518 new_handle
= _lttng_directory_handle_create(new_path
);
523 add_trailing_slash
= path
[path_len
- 1] != '/';
525 handle_path_len
= strlen(ref_handle
->base_path
) + path_len
+
526 !!add_trailing_slash
;
527 if (handle_path_len
>= LTTNG_PATH_MAX
) {
528 ERR("Failed to initialize directory handle as the resulting path's length (%zu bytes) exceeds the maximal allowed length (%d bytes)",
529 handle_path_len
, LTTNG_PATH_MAX
);
532 new_path
= zmalloc(handle_path_len
);
534 PERROR("Failed to initialize directory handle");
538 ret
= sprintf(new_handle
->base_path
, "%s%s%s",
539 ref_handle
->base_path
,
541 add_trailing_slash
? "/" : "");
542 if (ret
== -1 || ret
>= handle_path_len
) {
543 ERR("Failed to initialize directory handle: path formatting failed");
546 new_handle
= _lttng_directory_handle_create(new_path
);
554 struct lttng_directory_handle
*lttng_directory_handle_create_from_dirfd(
557 assert(dirfd
== AT_FDCWD
);
558 return lttng_directory_handle_create(NULL
);
562 void lttng_directory_handle_release(struct urcu_ref
*ref
)
564 struct lttng_directory_handle
*handle
=
565 container_of(ref
, struct lttng_directory_handle
, ref
);
567 free(handle
->base_path
);
568 lttng_directory_handle_invalidate(handle
);
573 struct lttng_directory_handle
*lttng_directory_handle_copy(
574 const struct lttng_directory_handle
*handle
)
576 struct lttng_directory_handle
*new_handle
= NULL
;
577 char *new_path
= NULL
;
579 if (handle
->base_path
) {
580 new_path
= strdup(handle
->base_path
);
585 new_handle
= _lttng_directory_handle_create(new_path
);
591 bool lttng_directory_handle_equals(const struct lttng_directory_handle
*lhs
,
592 const struct lttng_directory_handle
*rhs
)
594 return strcmp(lhs
->path
, rhs
->path
) == 0;
598 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
)
600 handle
->base_path
= NULL
;
604 int lttng_directory_handle_stat(const struct lttng_directory_handle
*handle
,
605 const char *subdirectory
, struct stat
*st
)
608 char fullpath
[LTTNG_PATH_MAX
];
610 ret
= get_full_path(handle
, subdirectory
, fullpath
, sizeof(fullpath
));
616 ret
= stat(fullpath
, st
);
622 bool lttng_directory_handle_uses_fd(
623 const struct lttng_directory_handle
*handle
)
629 int lttng_directory_handle_mkdir(const struct lttng_directory_handle
*handle
,
630 const char *subdirectory
, mode_t mode
)
633 char fullpath
[LTTNG_PATH_MAX
];
635 ret
= get_full_path(handle
, subdirectory
, fullpath
, sizeof(fullpath
));
641 ret
= mkdir(fullpath
, mode
);
647 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
648 const char *filename
, int flags
, mode_t mode
)
651 char fullpath
[LTTNG_PATH_MAX
];
653 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
659 ret
= open(fullpath
, flags
, mode
);
665 int lttng_directory_handle_unlink(
666 const struct lttng_directory_handle
*handle
,
667 const char *filename
)
670 char fullpath
[LTTNG_PATH_MAX
];
672 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
678 ret
= unlink(fullpath
);
684 int _run_as_mkdir(const struct lttng_directory_handle
*handle
, const char *path
,
685 mode_t mode
, uid_t uid
, gid_t gid
)
688 char fullpath
[LTTNG_PATH_MAX
];
690 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
696 ret
= run_as_mkdir(fullpath
, mode
, uid
, gid
);
702 int _run_as_open(const struct lttng_directory_handle
*handle
,
703 const char *filename
,
704 int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
707 char fullpath
[LTTNG_PATH_MAX
];
709 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
715 ret
= run_as_open(fullpath
, flags
, mode
, uid
, gid
);
721 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
722 const char *filename
, uid_t uid
, gid_t gid
)
725 char fullpath
[LTTNG_PATH_MAX
];
727 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
733 ret
= run_as_unlink(fullpath
, uid
, gid
);
739 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
740 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
743 char fullpath
[LTTNG_PATH_MAX
];
745 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
751 ret
= run_as_mkdir_recursive(fullpath
, mode
, uid
, gid
);
757 int _lttng_directory_handle_rename(
758 const struct lttng_directory_handle
*old_handle
,
759 const char *old_name
,
760 const struct lttng_directory_handle
*new_handle
,
761 const char *new_name
)
764 char old_fullpath
[LTTNG_PATH_MAX
];
765 char new_fullpath
[LTTNG_PATH_MAX
];
767 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
768 sizeof(old_fullpath
));
773 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
774 sizeof(new_fullpath
));
780 ret
= rename(old_fullpath
, new_fullpath
);
786 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
787 const char *old_name
,
788 const struct lttng_directory_handle
*new_handle
,
789 const char *new_name
, uid_t uid
, gid_t gid
)
792 char old_fullpath
[LTTNG_PATH_MAX
];
793 char new_fullpath
[LTTNG_PATH_MAX
];
795 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
796 sizeof(old_fullpath
));
801 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
802 sizeof(new_fullpath
));
808 ret
= run_as_rename(old_fullpath
, new_fullpath
, uid
, gid
);
814 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
818 DIR *dir_stream
= NULL
;
819 char fullpath
[LTTNG_PATH_MAX
];
821 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
827 dir_stream
= opendir(fullpath
);
833 int lttng_directory_handle_rmdir(
834 const struct lttng_directory_handle
*handle
, const char *name
)
837 char fullpath
[LTTNG_PATH_MAX
];
839 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
845 ret
= rmdir(fullpath
);
851 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
852 const char *name
, uid_t uid
, gid_t gid
)
855 char fullpath
[LTTNG_PATH_MAX
];
857 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
863 ret
= run_as_rmdir(fullpath
, uid
, gid
);
869 int _run_as_rmdir_recursive(
870 const struct lttng_directory_handle
*handle
, const char *name
,
871 uid_t uid
, gid_t gid
, int flags
)
874 char fullpath
[LTTNG_PATH_MAX
];
876 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
882 ret
= run_as_rmdir_recursive(fullpath
, uid
, gid
, flags
);
887 #endif /* COMPAT_DIRFD */
889 /* Common implementation. */
892 * On some filesystems (e.g. nfs), mkdir will validate access rights before
893 * checking for the existence of the path element. This means that on a setup
894 * where "/home/" is a mounted NFS share, and running as an unpriviledged user,
895 * recursively creating a path of the form "/home/my_user/trace/" will fail with
896 * EACCES on mkdir("/home", ...).
898 * Checking the path for existence allows us to work around this behaviour.
901 int create_directory_check_exists(const struct lttng_directory_handle
*handle
,
902 const char *path
, mode_t mode
)
907 ret
= lttng_directory_handle_stat(handle
, path
, &st
);
909 if (S_ISDIR(st
.st_mode
)) {
910 /* Directory exists, skip. */
913 /* Exists, but is not a directory. */
918 } else if (errno
!= ENOENT
) {
923 * Let mkdir handle other errors as the caller expects mkdir
926 ret
= lttng_directory_handle_mkdir(handle
, path
, mode
);
932 int create_directory_recursive(const struct lttng_directory_handle
*handle
,
933 const char *path
, mode_t mode
)
935 char *p
, tmp
[LTTNG_PATH_MAX
];
941 ret
= lttng_strncpy(tmp
, path
, sizeof(tmp
));
943 ERR("Failed to create directory: provided path's length (%zu bytes) exceeds the maximal allowed length (%zu bytes)",
944 strlen(path
) + 1, sizeof(tmp
));
949 if (tmp
[len
- 1] == '/') {
953 for (p
= tmp
+ 1; *p
; p
++) {
956 if (tmp
[strlen(tmp
) - 1] == '.' &&
957 tmp
[strlen(tmp
) - 2] == '.' &&
958 tmp
[strlen(tmp
) - 3] == '/') {
959 ERR("Using '/../' is not permitted in the trace path (%s)",
964 ret
= create_directory_check_exists(handle
, tmp
, mode
);
966 if (errno
!= EACCES
) {
967 PERROR("Failed to create directory \"%s\"",
977 ret
= create_directory_check_exists(handle
, tmp
, mode
);
979 PERROR("mkdirat recursive last element");
987 bool lttng_directory_handle_get(struct lttng_directory_handle
*handle
)
989 return urcu_ref_get_unless_zero(&handle
->ref
);
993 void lttng_directory_handle_put(struct lttng_directory_handle
*handle
)
998 assert(handle
->ref
.refcount
);
999 urcu_ref_put(&handle
->ref
, lttng_directory_handle_release
);
1003 int lttng_directory_handle_create_subdirectory_as_user(
1004 const struct lttng_directory_handle
*handle
,
1005 const char *subdirectory
,
1006 mode_t mode
, const struct lttng_credentials
*creds
)
1011 /* Run as current user. */
1012 ret
= create_directory_check_exists(handle
,
1013 subdirectory
, mode
);
1015 ret
= _run_as_mkdir(handle
, subdirectory
,
1016 mode
, creds
->uid
, creds
->gid
);
1023 int lttng_directory_handle_create_subdirectory_recursive_as_user(
1024 const struct lttng_directory_handle
*handle
,
1025 const char *subdirectory_path
,
1026 mode_t mode
, const struct lttng_credentials
*creds
)
1031 /* Run as current user. */
1032 ret
= create_directory_recursive(handle
,
1033 subdirectory_path
, mode
);
1035 ret
= _run_as_mkdir_recursive(handle
, subdirectory_path
,
1036 mode
, creds
->uid
, creds
->gid
);
1043 int lttng_directory_handle_create_subdirectory(
1044 const struct lttng_directory_handle
*handle
,
1045 const char *subdirectory
,
1048 return lttng_directory_handle_create_subdirectory_as_user(
1049 handle
, subdirectory
, mode
, NULL
);
1053 int lttng_directory_handle_create_subdirectory_recursive(
1054 const struct lttng_directory_handle
*handle
,
1055 const char *subdirectory_path
,
1058 return lttng_directory_handle_create_subdirectory_recursive_as_user(
1059 handle
, subdirectory_path
, mode
, NULL
);
1063 int lttng_directory_handle_open_file_as_user(
1064 const struct lttng_directory_handle
*handle
,
1065 const char *filename
,
1066 int flags
, mode_t mode
,
1067 const struct lttng_credentials
*creds
)
1072 /* Run as current user. */
1073 ret
= lttng_directory_handle_open(handle
, filename
, flags
,
1076 ret
= _run_as_open(handle
, filename
, flags
, mode
,
1077 creds
->uid
, creds
->gid
);
1083 int lttng_directory_handle_open_file(
1084 const struct lttng_directory_handle
*handle
,
1085 const char *filename
,
1086 int flags
, mode_t mode
)
1088 return lttng_directory_handle_open_file_as_user(handle
, filename
, flags
,
1093 int lttng_directory_handle_unlink_file_as_user(
1094 const struct lttng_directory_handle
*handle
,
1095 const char *filename
,
1096 const struct lttng_credentials
*creds
)
1101 /* Run as current user. */
1102 ret
= lttng_directory_handle_unlink(handle
, filename
);
1104 ret
= _run_as_unlink(handle
, filename
, creds
->uid
, creds
->gid
);
1110 int lttng_directory_handle_unlink_file(
1111 const struct lttng_directory_handle
*handle
,
1112 const char *filename
)
1114 return lttng_directory_handle_unlink_file_as_user(handle
,
1119 int lttng_directory_handle_rename(
1120 const struct lttng_directory_handle
*old_handle
,
1121 const char *old_name
,
1122 const struct lttng_directory_handle
*new_handle
,
1123 const char *new_name
)
1125 return lttng_directory_handle_rename_as_user(old_handle
, old_name
,
1126 new_handle
, new_name
, NULL
);
1130 int lttng_directory_handle_rename_as_user(
1131 const struct lttng_directory_handle
*old_handle
,
1132 const char *old_name
,
1133 const struct lttng_directory_handle
*new_handle
,
1134 const char *new_name
,
1135 const struct lttng_credentials
*creds
)
1140 /* Run as current user. */
1141 ret
= _lttng_directory_handle_rename(old_handle
,
1142 old_name
, new_handle
, new_name
);
1144 ret
= _run_as_rename(old_handle
, old_name
, new_handle
,
1145 new_name
, creds
->uid
, creds
->gid
);
1151 int lttng_directory_handle_remove_subdirectory(
1152 const struct lttng_directory_handle
*handle
,
1155 return lttng_directory_handle_remove_subdirectory_as_user(handle
, name
,
1160 int lttng_directory_handle_remove_subdirectory_as_user(
1161 const struct lttng_directory_handle
*handle
,
1163 const struct lttng_credentials
*creds
)
1168 /* Run as current user. */
1169 ret
= lttng_directory_handle_rmdir(handle
, name
);
1171 ret
= _run_as_rmdir(handle
, name
, creds
->uid
, creds
->gid
);
1176 struct rmdir_frame
{
1177 ssize_t parent_frame_idx
;
1180 /* Size including '\0'. */
1185 void rmdir_frame_fini(void *data
)
1188 struct rmdir_frame
*frame
= data
;
1190 ret
= closedir(frame
->dir
);
1192 PERROR("Failed to close directory stream");
1197 int remove_directory_recursive(const struct lttng_directory_handle
*handle
,
1198 const char *path
, int flags
)
1201 struct lttng_dynamic_array frames
;
1202 size_t current_frame_idx
= 0;
1203 struct rmdir_frame initial_frame
= {
1204 .parent_frame_idx
= -1,
1205 .dir
= lttng_directory_handle_opendir(handle
, path
),
1207 .path_size
= strlen(path
) + 1,
1209 struct lttng_dynamic_buffer current_path
;
1210 const char separator
= '/';
1212 lttng_dynamic_buffer_init(¤t_path
);
1213 lttng_dynamic_array_init(&frames
, sizeof(struct rmdir_frame
),
1216 if (flags
& ~(LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
|
1217 LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG
)) {
1218 ERR("Unknown flags %d", flags
);
1223 if (!initial_frame
.dir
) {
1224 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
&&
1226 DBG("Cannot rmdir \"%s\": root does not exist", path
);
1230 PERROR("Failed to rmdir \"%s\"", path
);
1236 ret
= lttng_dynamic_array_add_element(&frames
, &initial_frame
);
1238 ERR("Failed to push context frame during recursive directory removal");
1239 rmdir_frame_fini(&initial_frame
);
1243 ret
= lttng_dynamic_buffer_append(
1244 ¤t_path
, path
, initial_frame
.path_size
);
1246 ERR("Failed to set initial path during recursive directory removal");
1251 while (lttng_dynamic_array_get_count(&frames
) > 0) {
1252 struct dirent
*entry
;
1253 struct rmdir_frame
*current_frame
=
1254 lttng_dynamic_array_get_element(
1255 &frames
, current_frame_idx
);
1257 assert(current_frame
->dir
);
1258 ret
= lttng_dynamic_buffer_set_size(
1259 ¤t_path
, current_frame
->path_size
);
1261 current_path
.data
[current_path
.size
- 1] = '\0';
1263 while ((entry
= readdir(current_frame
->dir
))) {
1266 if (!strcmp(entry
->d_name
, ".") ||
1267 !strcmp(entry
->d_name
, "..")) {
1271 /* Set current_path to the entry's path. */
1272 ret
= lttng_dynamic_buffer_set_size(
1273 ¤t_path
, current_path
.size
- 1);
1275 ret
= lttng_dynamic_buffer_append(¤t_path
,
1276 &separator
, sizeof(separator
));
1280 ret
= lttng_dynamic_buffer_append(¤t_path
,
1282 strlen(entry
->d_name
) + 1);
1287 if (lttng_directory_handle_stat(
1288 handle
, current_path
.data
, &st
)) {
1289 if ((flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
) &&
1293 PERROR("Failed to stat \"%s\"",
1299 if (!S_ISDIR(st
.st_mode
)) {
1300 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
) {
1301 current_frame
->empty
= false;
1304 /* Not empty, abort. */
1305 DBG("Directory \"%s\" is not empty; refusing to remove directory",
1311 struct rmdir_frame new_frame
= {
1312 .path_size
= current_path
.size
,
1313 .dir
= lttng_directory_handle_opendir(
1317 .parent_frame_idx
= current_frame_idx
,
1320 if (!new_frame
.dir
) {
1321 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
&&
1323 DBG("Non-existing directory stream during recursive directory removal");
1326 PERROR("Failed to open directory stream during recursive directory removal");
1331 ret
= lttng_dynamic_array_add_element(
1332 &frames
, &new_frame
);
1334 ERR("Failed to push context frame during recursive directory removal");
1335 rmdir_frame_fini(&new_frame
);
1338 current_frame_idx
++;
1339 /* We break iteration on readdir. */
1347 /* Pop rmdir frame. */
1348 if (current_frame
->empty
) {
1349 ret
= lttng_directory_handle_rmdir(
1350 handle
, current_path
.data
);
1352 if ((flags
& LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG
) ||
1354 PERROR("Failed to remove \"%s\" during recursive directory removal",
1358 DBG("Non-existing directory stream during recursive directory removal");
1360 } else if (current_frame
->parent_frame_idx
>= 0) {
1361 struct rmdir_frame
*parent_frame
;
1363 parent_frame
= lttng_dynamic_array_get_element(&frames
,
1364 current_frame
->parent_frame_idx
);
1365 assert(parent_frame
);
1366 parent_frame
->empty
= false;
1368 ret
= lttng_dynamic_array_remove_element(
1369 &frames
, current_frame_idx
);
1371 ERR("Failed to pop context frame during recursive directory removal");
1374 current_frame_idx
--;
1377 lttng_dynamic_array_reset(&frames
);
1378 lttng_dynamic_buffer_reset(¤t_path
);
1383 int lttng_directory_handle_remove_subdirectory_recursive(
1384 const struct lttng_directory_handle
*handle
,
1388 return lttng_directory_handle_remove_subdirectory_recursive_as_user(
1389 handle
, name
, NULL
, flags
);
1393 int lttng_directory_handle_remove_subdirectory_recursive_as_user(
1394 const struct lttng_directory_handle
*handle
,
1396 const struct lttng_credentials
*creds
,
1402 /* Run as current user. */
1403 ret
= remove_directory_recursive(handle
, name
, flags
);
1405 ret
= _run_as_rmdir_recursive(handle
, name
, creds
->uid
,