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>
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; \
103 struct lttng_directory_handle
*lttng_directory_handle_create(const char *path
)
105 const struct lttng_directory_handle cwd_handle
= {
109 /* Open a handle to the CWD if NULL is passed. */
110 return lttng_directory_handle_create_from_handle(path
, &cwd_handle
);
114 struct lttng_directory_handle
*lttng_directory_handle_create_from_handle(
116 const struct lttng_directory_handle
*ref_handle
)
119 struct lttng_directory_handle
*handle
= NULL
;
122 handle
= lttng_directory_handle_copy(ref_handle
);
126 ERR("Failed to initialize directory handle: provided path is an empty string");
130 dirfd
= openat(ref_handle
->dirfd
, path
, O_RDONLY
| O_DIRECTORY
| O_CLOEXEC
);
132 PERROR("Failed to initialize directory handle to \"%s\"", path
);
136 handle
= lttng_directory_handle_create_from_dirfd(dirfd
);
144 PERROR("Failed to close directory file descriptor");
150 struct lttng_directory_handle
*lttng_directory_handle_create_from_dirfd(
154 struct lttng_directory_handle
*handle
= zmalloc(sizeof(*handle
));
155 struct stat stat_buf
;
161 if (dirfd
!= AT_FDCWD
) {
162 ret
= fstat(dirfd
, &stat_buf
);
164 PERROR("Failed to fstat directory file descriptor %i", dirfd
);
165 lttng_directory_handle_release(&handle
->ref
);
170 handle
->directory_inode
= RESERVED_AT_FDCWD_INO
;
172 handle
->dirfd
= dirfd
;
173 urcu_ref_init(&handle
->ref
);
179 void lttng_directory_handle_release(struct urcu_ref
*ref
)
182 struct lttng_directory_handle
*handle
=
183 container_of(ref
, struct lttng_directory_handle
, ref
);
185 if (handle
->destroy_cb
) {
186 handle
->destroy_cb(handle
, handle
->destroy_cb_data
);
189 if (handle
->dirfd
== AT_FDCWD
|| handle
->dirfd
== -1) {
192 ret
= close(handle
->dirfd
);
194 PERROR("Failed to close directory file descriptor of directory handle");
197 lttng_directory_handle_invalidate(handle
);
202 struct lttng_directory_handle
*lttng_directory_handle_copy(
203 const struct lttng_directory_handle
*handle
)
205 struct lttng_directory_handle
*new_handle
= NULL
;
207 if (handle
->dirfd
== AT_FDCWD
) {
208 new_handle
= lttng_directory_handle_create_from_dirfd(AT_FDCWD
);
210 const int new_dirfd
= dup(handle
->dirfd
);
212 if (new_dirfd
== -1) {
213 PERROR("Failed to duplicate directory file descriptor of directory handle");
216 new_handle
= lttng_directory_handle_create_from_dirfd(
218 if (!new_handle
&& close(new_dirfd
)) {
219 PERROR("Failed to close directory file descriptor of directory handle");
227 bool lttng_directory_handle_equals(const struct lttng_directory_handle
*lhs
,
228 const struct lttng_directory_handle
*rhs
)
230 return lhs
->directory_inode
== rhs
->directory_inode
;
234 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
)
240 int lttng_directory_handle_stat(const struct lttng_directory_handle
*handle
,
241 const char *path
, struct stat
*st
)
243 return fstatat(handle
->dirfd
, path
, st
, 0);
247 bool lttng_directory_handle_uses_fd(
248 const struct lttng_directory_handle
*handle
)
250 return handle
->dirfd
!= AT_FDCWD
;
254 int lttng_directory_handle_mkdir(
255 const struct lttng_directory_handle
*handle
,
256 const char *path
, mode_t mode
)
258 return mkdirat(handle
->dirfd
, path
, mode
);
262 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
263 const char *filename
, int flags
, mode_t mode
)
265 return openat(handle
->dirfd
, filename
, flags
, mode
);
269 int _run_as_open(const struct lttng_directory_handle
*handle
,
270 const char *filename
,
271 int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
273 return run_as_openat(handle
->dirfd
, filename
, flags
, mode
, uid
, gid
);
277 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
278 const char *filename
, uid_t uid
, gid_t gid
)
280 return run_as_unlinkat(handle
->dirfd
, filename
, uid
, gid
);
284 int lttng_directory_handle_unlink(
285 const struct lttng_directory_handle
*handle
,
286 const char *filename
)
288 return unlinkat(handle
->dirfd
, filename
, 0);
292 int _run_as_mkdir(const struct lttng_directory_handle
*handle
,
293 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
295 return run_as_mkdirat(handle
->dirfd
, path
, mode
, uid
, gid
);
299 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
300 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
302 return run_as_mkdirat_recursive(handle
->dirfd
, path
, mode
, uid
, gid
);
306 int _lttng_directory_handle_rename(
307 const struct lttng_directory_handle
*old_handle
,
308 const char *old_name
,
309 const struct lttng_directory_handle
*new_handle
,
310 const char *new_name
)
312 return renameat(old_handle
->dirfd
, old_name
,
313 new_handle
->dirfd
, new_name
);
317 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
318 const char *old_name
,
319 const struct lttng_directory_handle
*new_handle
,
320 const char *new_name
, uid_t uid
, gid_t gid
)
322 return run_as_renameat(old_handle
->dirfd
, old_name
, new_handle
->dirfd
,
327 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
330 DIR *dir_stream
= NULL
;
331 int fd
= openat(handle
->dirfd
, path
, O_RDONLY
);
337 dir_stream
= fdopendir(fd
);
341 PERROR("Failed to open directory stream");
344 PERROR("Failed to close file descriptor to %s", path
);
354 int lttng_directory_handle_rmdir(
355 const struct lttng_directory_handle
*handle
, const char *name
)
357 int ret
= unlinkat(handle
->dirfd
, name
, AT_REMOVEDIR
);
359 PERROR("Failed to remove directory `%s`", name
);
366 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
367 const char *name
, uid_t uid
, gid_t gid
)
369 return run_as_rmdirat(handle
->dirfd
, name
, uid
, gid
);
373 int _run_as_rmdir_recursive(
374 const struct lttng_directory_handle
*handle
, const char *name
,
375 uid_t uid
, gid_t gid
, int flags
)
377 return run_as_rmdirat_recursive(handle
->dirfd
, name
, uid
, gid
, flags
);
380 #else /* HAVE_DIRFD */
383 int get_full_path(const struct lttng_directory_handle
*handle
,
384 const char *subdirectory
, char *fullpath
, size_t size
)
387 const bool subdirectory_is_absolute
=
388 subdirectory
&& *subdirectory
== '/';
389 const char * const base
= subdirectory_is_absolute
?
390 subdirectory
: handle
->base_path
;
391 const char * const end
= subdirectory
&& !subdirectory_is_absolute
?
393 const size_t base_len
= strlen(base
);
394 const size_t end_len
= end
? strlen(end
) : 0;
395 const bool add_separator_slash
= end
&& base
[base_len
- 1] != '/';
396 const bool add_trailing_slash
= end
&& end
[end_len
- 1] != '/';
398 ret
= snprintf(fullpath
, size
, "%s%s%s%s",
400 add_separator_slash
? "/" : "",
402 add_trailing_slash
? "/" : "");
403 if (ret
== -1 || ret
>= size
) {
404 ERR("Failed to format subdirectory from directory handle");
414 struct lttng_directory_handle
*_lttng_directory_handle_create(char *path
)
416 struct lttng_directory_handle
*handle
= zmalloc(sizeof(*handle
));
421 urcu_ref_init(&handle
->ref
);
422 handle
->base_path
= path
;
428 struct lttng_directory_handle
*lttng_directory_handle_create(
432 const char *cwd
= "";
433 size_t cwd_len
, path_len
;
434 char cwd_buf
[LTTNG_PATH_MAX
] = {};
435 char handle_buf
[LTTNG_PATH_MAX
] = {};
436 struct lttng_directory_handle
*new_handle
= NULL
;
437 bool add_cwd_slash
= false, add_trailing_slash
= false;
438 const struct lttng_directory_handle cwd_handle
= {
439 .base_path
= handle_buf
,
442 path_len
= path
? strlen(path
) : 0;
443 add_trailing_slash
= path
&& path
[path_len
- 1] != '/';
444 if (!path
|| (path
&& *path
!= '/')) {
445 cwd
= getcwd(cwd_buf
, sizeof(cwd_buf
));
447 PERROR("Failed to initialize directory handle, can't get current working directory");
451 cwd_len
= strlen(cwd
);
453 ERR("Failed to initialize directory handle, current working directory path has a length of 0");
457 add_cwd_slash
= cwd
[cwd_len
- 1] != '/';
460 ret
= snprintf(handle_buf
, sizeof(handle_buf
), "%s%s%s%s",
462 add_cwd_slash
? "/" : "",
464 add_trailing_slash
? "/" : "");
465 if (ret
== -1 || ret
>= LTTNG_PATH_MAX
) {
466 ERR("Failed to initialize directory handle, failed to format directory path");
470 new_handle
= lttng_directory_handle_create_from_handle(path
, &cwd_handle
);
476 struct lttng_directory_handle
*lttng_directory_handle_create_from_handle(
478 const struct lttng_directory_handle
*ref_handle
)
481 size_t path_len
, handle_path_len
;
482 bool add_trailing_slash
;
483 struct stat stat_buf
;
484 struct lttng_directory_handle
*new_handle
= NULL
;
485 char *new_path
= NULL
;
487 LTTNG_ASSERT(ref_handle
&& ref_handle
->base_path
);
489 ret
= lttng_directory_handle_stat(ref_handle
, path
, &stat_buf
);
491 PERROR("Failed to create directory handle");
493 } else if (!S_ISDIR(stat_buf
.st_mode
)) {
494 char full_path
[LTTNG_PATH_MAX
];
496 /* Best effort for logging purposes. */
497 ret
= get_full_path(ref_handle
, path
, full_path
,
503 ERR("Failed to initialize directory handle to \"%s\": not a directory",
508 new_handle
= lttng_directory_handle_copy(ref_handle
);
512 path_len
= strlen(path
);
514 ERR("Failed to initialize directory handle: provided path is an empty string");
519 new_path
= strdup(path
);
523 /* Takes ownership of new_path. */
524 new_handle
= _lttng_directory_handle_create(new_path
);
529 add_trailing_slash
= path
[path_len
- 1] != '/';
531 handle_path_len
= strlen(ref_handle
->base_path
) + path_len
+
532 !!add_trailing_slash
;
533 if (handle_path_len
>= LTTNG_PATH_MAX
) {
534 ERR("Failed to initialize directory handle as the resulting path's length (%zu bytes) exceeds the maximal allowed length (%d bytes)",
535 handle_path_len
, LTTNG_PATH_MAX
);
538 new_path
= zmalloc(handle_path_len
);
540 PERROR("Failed to initialize directory handle");
544 ret
= sprintf(new_handle
->base_path
, "%s%s%s",
545 ref_handle
->base_path
,
547 add_trailing_slash
? "/" : "");
548 if (ret
== -1 || ret
>= handle_path_len
) {
549 ERR("Failed to initialize directory handle: path formatting failed");
552 new_handle
= _lttng_directory_handle_create(new_path
);
560 struct lttng_directory_handle
*lttng_directory_handle_create_from_dirfd(
563 LTTNG_ASSERT(dirfd
== AT_FDCWD
);
564 return lttng_directory_handle_create(NULL
);
568 void lttng_directory_handle_release(struct urcu_ref
*ref
)
570 struct lttng_directory_handle
*handle
=
571 container_of(ref
, struct lttng_directory_handle
, ref
);
573 free(handle
->base_path
);
574 lttng_directory_handle_invalidate(handle
);
579 struct lttng_directory_handle
*lttng_directory_handle_copy(
580 const struct lttng_directory_handle
*handle
)
582 struct lttng_directory_handle
*new_handle
= NULL
;
583 char *new_path
= NULL
;
585 if (handle
->base_path
) {
586 new_path
= strdup(handle
->base_path
);
591 new_handle
= _lttng_directory_handle_create(new_path
);
597 bool lttng_directory_handle_equals(const struct lttng_directory_handle
*lhs
,
598 const struct lttng_directory_handle
*rhs
)
600 return strcmp(lhs
->base_path
, rhs
->base_path
) == 0;
604 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
)
606 handle
->base_path
= NULL
;
610 int lttng_directory_handle_stat(const struct lttng_directory_handle
*handle
,
611 const char *subdirectory
, struct stat
*st
)
614 char fullpath
[LTTNG_PATH_MAX
];
616 ret
= get_full_path(handle
, subdirectory
, fullpath
, sizeof(fullpath
));
622 ret
= stat(fullpath
, st
);
628 bool lttng_directory_handle_uses_fd(
629 const struct lttng_directory_handle
*handle
)
635 int lttng_directory_handle_mkdir(const struct lttng_directory_handle
*handle
,
636 const char *subdirectory
, mode_t mode
)
639 char fullpath
[LTTNG_PATH_MAX
];
641 ret
= get_full_path(handle
, subdirectory
, fullpath
, sizeof(fullpath
));
647 ret
= mkdir(fullpath
, mode
);
653 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
654 const char *filename
, int flags
, mode_t mode
)
657 char fullpath
[LTTNG_PATH_MAX
];
659 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
665 ret
= open(fullpath
, flags
, mode
);
671 int lttng_directory_handle_unlink(
672 const struct lttng_directory_handle
*handle
,
673 const char *filename
)
676 char fullpath
[LTTNG_PATH_MAX
];
678 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
684 ret
= unlink(fullpath
);
690 int _run_as_mkdir(const struct lttng_directory_handle
*handle
, const char *path
,
691 mode_t mode
, uid_t uid
, gid_t gid
)
694 char fullpath
[LTTNG_PATH_MAX
];
696 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
702 ret
= run_as_mkdir(fullpath
, mode
, uid
, gid
);
708 int _run_as_open(const struct lttng_directory_handle
*handle
,
709 const char *filename
,
710 int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
713 char fullpath
[LTTNG_PATH_MAX
];
715 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
721 ret
= run_as_open(fullpath
, flags
, mode
, uid
, gid
);
727 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
728 const char *filename
, uid_t uid
, gid_t gid
)
731 char fullpath
[LTTNG_PATH_MAX
];
733 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
739 ret
= run_as_unlink(fullpath
, uid
, gid
);
745 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
746 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
749 char fullpath
[LTTNG_PATH_MAX
];
751 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
757 ret
= run_as_mkdir_recursive(fullpath
, mode
, uid
, gid
);
763 int _lttng_directory_handle_rename(
764 const struct lttng_directory_handle
*old_handle
,
765 const char *old_name
,
766 const struct lttng_directory_handle
*new_handle
,
767 const char *new_name
)
770 char old_fullpath
[LTTNG_PATH_MAX
];
771 char new_fullpath
[LTTNG_PATH_MAX
];
773 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
774 sizeof(old_fullpath
));
779 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
780 sizeof(new_fullpath
));
786 ret
= rename(old_fullpath
, new_fullpath
);
792 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
793 const char *old_name
,
794 const struct lttng_directory_handle
*new_handle
,
795 const char *new_name
, uid_t uid
, gid_t gid
)
798 char old_fullpath
[LTTNG_PATH_MAX
];
799 char new_fullpath
[LTTNG_PATH_MAX
];
801 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
802 sizeof(old_fullpath
));
807 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
808 sizeof(new_fullpath
));
814 ret
= run_as_rename(old_fullpath
, new_fullpath
, uid
, gid
);
820 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
824 DIR *dir_stream
= NULL
;
825 char fullpath
[LTTNG_PATH_MAX
];
827 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
833 dir_stream
= opendir(fullpath
);
839 int lttng_directory_handle_rmdir(
840 const struct lttng_directory_handle
*handle
, const char *name
)
843 char fullpath
[LTTNG_PATH_MAX
];
845 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
851 ret
= rmdir(fullpath
);
857 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
858 const char *name
, uid_t uid
, gid_t gid
)
861 char fullpath
[LTTNG_PATH_MAX
];
863 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
869 ret
= run_as_rmdir(fullpath
, uid
, gid
);
875 int _run_as_rmdir_recursive(
876 const struct lttng_directory_handle
*handle
, const char *name
,
877 uid_t uid
, gid_t gid
, int flags
)
880 char fullpath
[LTTNG_PATH_MAX
];
882 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
888 ret
= run_as_rmdir_recursive(fullpath
, uid
, gid
, flags
);
893 #endif /* HAVE_DIRFD */
895 /* Common implementation. */
898 * On some filesystems (e.g. nfs), mkdir will validate access rights before
899 * checking for the existence of the path element. This means that on a setup
900 * where "/home/" is a mounted NFS share, and running as an unpriviledged user,
901 * recursively creating a path of the form "/home/my_user/trace/" will fail with
902 * EACCES on mkdir("/home", ...).
904 * Checking the path for existence allows us to work around this behaviour.
907 int create_directory_check_exists(const struct lttng_directory_handle
*handle
,
908 const char *path
, mode_t mode
)
913 ret
= lttng_directory_handle_stat(handle
, path
, &st
);
915 if (S_ISDIR(st
.st_mode
)) {
916 /* Directory exists, skip. */
919 /* Exists, but is not a directory. */
924 } else if (errno
!= ENOENT
) {
929 * Let mkdir handle other errors as the caller expects mkdir
932 ret
= lttng_directory_handle_mkdir(handle
, path
, mode
);
938 int create_directory_recursive(const struct lttng_directory_handle
*handle
,
939 const char *path
, mode_t mode
)
941 char *p
, tmp
[LTTNG_PATH_MAX
];
947 ret
= lttng_strncpy(tmp
, path
, sizeof(tmp
));
949 ERR("Failed to create directory: provided path's length (%zu bytes) exceeds the maximal allowed length (%zu bytes)",
950 strlen(path
) + 1, sizeof(tmp
));
955 if (tmp
[len
- 1] == '/') {
959 for (p
= tmp
+ 1; *p
; p
++) {
962 if (tmp
[strlen(tmp
) - 1] == '.' &&
963 tmp
[strlen(tmp
) - 2] == '.' &&
964 tmp
[strlen(tmp
) - 3] == '/') {
965 ERR("Using '/../' is not permitted in the trace path (%s)",
970 ret
= create_directory_check_exists(handle
, tmp
, mode
);
972 if (errno
!= EACCES
) {
973 PERROR("Failed to create directory \"%s\"",
983 ret
= create_directory_check_exists(handle
, tmp
, mode
);
985 PERROR("mkdirat recursive last element");
993 bool lttng_directory_handle_get(struct lttng_directory_handle
*handle
)
995 return urcu_ref_get_unless_zero(&handle
->ref
);
999 void lttng_directory_handle_put(struct lttng_directory_handle
*handle
)
1004 LTTNG_ASSERT(handle
->ref
.refcount
);
1005 urcu_ref_put(&handle
->ref
, lttng_directory_handle_release
);
1009 int lttng_directory_handle_create_subdirectory_as_user(
1010 const struct lttng_directory_handle
*handle
,
1011 const char *subdirectory
,
1012 mode_t mode
, const struct lttng_credentials
*creds
)
1017 /* Run as current user. */
1018 ret
= create_directory_check_exists(handle
,
1019 subdirectory
, mode
);
1021 ret
= _run_as_mkdir(handle
, subdirectory
, mode
,
1022 lttng_credentials_get_uid(creds
),
1023 lttng_credentials_get_gid(creds
));
1030 int lttng_directory_handle_create_subdirectory_recursive_as_user(
1031 const struct lttng_directory_handle
*handle
,
1032 const char *subdirectory_path
,
1033 mode_t mode
, const struct lttng_credentials
*creds
)
1038 /* Run as current user. */
1039 ret
= create_directory_recursive(handle
,
1040 subdirectory_path
, mode
);
1042 ret
= _run_as_mkdir_recursive(handle
, subdirectory_path
,
1043 mode
, lttng_credentials_get_uid(creds
), lttng_credentials_get_gid(creds
));
1050 int lttng_directory_handle_create_subdirectory(
1051 const struct lttng_directory_handle
*handle
,
1052 const char *subdirectory
,
1055 return lttng_directory_handle_create_subdirectory_as_user(
1056 handle
, subdirectory
, mode
, NULL
);
1060 int lttng_directory_handle_create_subdirectory_recursive(
1061 const struct lttng_directory_handle
*handle
,
1062 const char *subdirectory_path
,
1065 return lttng_directory_handle_create_subdirectory_recursive_as_user(
1066 handle
, subdirectory_path
, mode
, NULL
);
1070 int lttng_directory_handle_open_file_as_user(
1071 const struct lttng_directory_handle
*handle
,
1072 const char *filename
,
1073 int flags
, mode_t mode
,
1074 const struct lttng_credentials
*creds
)
1079 /* Run as current user. */
1080 ret
= lttng_directory_handle_open(handle
, filename
, flags
,
1083 ret
= _run_as_open(handle
, filename
, flags
, mode
,
1084 lttng_credentials_get_uid(creds
), lttng_credentials_get_gid(creds
));
1090 int lttng_directory_handle_open_file(
1091 const struct lttng_directory_handle
*handle
,
1092 const char *filename
,
1093 int flags
, mode_t mode
)
1095 return lttng_directory_handle_open_file_as_user(handle
, filename
, flags
,
1100 int lttng_directory_handle_unlink_file_as_user(
1101 const struct lttng_directory_handle
*handle
,
1102 const char *filename
,
1103 const struct lttng_credentials
*creds
)
1108 /* Run as current user. */
1109 ret
= lttng_directory_handle_unlink(handle
, filename
);
1111 ret
= _run_as_unlink(handle
, filename
, lttng_credentials_get_uid(creds
), lttng_credentials_get_gid(creds
));
1117 int lttng_directory_handle_unlink_file(
1118 const struct lttng_directory_handle
*handle
,
1119 const char *filename
)
1121 return lttng_directory_handle_unlink_file_as_user(handle
,
1126 int lttng_directory_handle_rename(
1127 const struct lttng_directory_handle
*old_handle
,
1128 const char *old_name
,
1129 const struct lttng_directory_handle
*new_handle
,
1130 const char *new_name
)
1132 return lttng_directory_handle_rename_as_user(old_handle
, old_name
,
1133 new_handle
, new_name
, NULL
);
1137 int lttng_directory_handle_rename_as_user(
1138 const struct lttng_directory_handle
*old_handle
,
1139 const char *old_name
,
1140 const struct lttng_directory_handle
*new_handle
,
1141 const char *new_name
,
1142 const struct lttng_credentials
*creds
)
1147 /* Run as current user. */
1148 ret
= _lttng_directory_handle_rename(old_handle
,
1149 old_name
, new_handle
, new_name
);
1151 ret
= _run_as_rename(old_handle
, old_name
, new_handle
,
1152 new_name
, lttng_credentials_get_uid(creds
), lttng_credentials_get_gid(creds
));
1158 int lttng_directory_handle_remove_subdirectory(
1159 const struct lttng_directory_handle
*handle
,
1162 return lttng_directory_handle_remove_subdirectory_as_user(handle
, name
,
1167 int lttng_directory_handle_remove_subdirectory_as_user(
1168 const struct lttng_directory_handle
*handle
,
1170 const struct lttng_credentials
*creds
)
1175 /* Run as current user. */
1176 ret
= lttng_directory_handle_rmdir(handle
, name
);
1178 ret
= _run_as_rmdir(handle
, name
, lttng_credentials_get_uid(creds
), lttng_credentials_get_gid(creds
));
1183 struct rmdir_frame
{
1184 ssize_t parent_frame_idx
;
1187 /* Size including '\0'. */
1192 void rmdir_frame_fini(void *data
)
1195 struct rmdir_frame
*frame
= data
;
1197 ret
= closedir(frame
->dir
);
1199 PERROR("Failed to close directory stream");
1204 int remove_directory_recursive(const struct lttng_directory_handle
*handle
,
1205 const char *path
, int flags
)
1208 struct lttng_dynamic_array frames
;
1209 size_t current_frame_idx
= 0;
1210 struct rmdir_frame initial_frame
= {
1211 .parent_frame_idx
= -1,
1212 .dir
= lttng_directory_handle_opendir(handle
, path
),
1214 .path_size
= strlen(path
) + 1,
1216 struct lttng_dynamic_buffer current_path
;
1217 const char separator
= '/';
1219 lttng_dynamic_buffer_init(¤t_path
);
1220 lttng_dynamic_array_init(&frames
, sizeof(struct rmdir_frame
),
1223 if (flags
& ~(LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
|
1224 LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG
)) {
1225 ERR("Unknown flags %d", flags
);
1230 if (!initial_frame
.dir
) {
1231 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
&&
1233 DBG("Cannot rmdir \"%s\": root does not exist", path
);
1237 PERROR("Failed to rmdir \"%s\"", path
);
1243 ret
= lttng_dynamic_array_add_element(&frames
, &initial_frame
);
1245 ERR("Failed to push context frame during recursive directory removal");
1246 rmdir_frame_fini(&initial_frame
);
1250 ret
= lttng_dynamic_buffer_append(
1251 ¤t_path
, path
, initial_frame
.path_size
);
1253 ERR("Failed to set initial path during recursive directory removal");
1258 while (lttng_dynamic_array_get_count(&frames
) > 0) {
1259 struct dirent
*entry
;
1260 struct rmdir_frame
*current_frame
=
1261 lttng_dynamic_array_get_element(
1262 &frames
, current_frame_idx
);
1264 LTTNG_ASSERT(current_frame
->dir
);
1265 ret
= lttng_dynamic_buffer_set_size(
1266 ¤t_path
, current_frame
->path_size
);
1268 current_path
.data
[current_path
.size
- 1] = '\0';
1270 while ((entry
= readdir(current_frame
->dir
))) {
1273 if (!strcmp(entry
->d_name
, ".") ||
1274 !strcmp(entry
->d_name
, "..")) {
1278 /* Set current_path to the entry's path. */
1279 ret
= lttng_dynamic_buffer_set_size(
1280 ¤t_path
, current_path
.size
- 1);
1282 ret
= lttng_dynamic_buffer_append(¤t_path
,
1283 &separator
, sizeof(separator
));
1287 ret
= lttng_dynamic_buffer_append(¤t_path
,
1289 strlen(entry
->d_name
) + 1);
1294 if (lttng_directory_handle_stat(
1295 handle
, current_path
.data
, &st
)) {
1296 if ((flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
) &&
1300 PERROR("Failed to stat \"%s\"",
1306 if (!S_ISDIR(st
.st_mode
)) {
1307 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
) {
1308 current_frame
->empty
= false;
1311 /* Not empty, abort. */
1312 DBG("Directory \"%s\" is not empty; refusing to remove directory",
1318 struct rmdir_frame new_frame
= {
1319 .path_size
= current_path
.size
,
1320 .dir
= lttng_directory_handle_opendir(
1324 .parent_frame_idx
= current_frame_idx
,
1327 if (!new_frame
.dir
) {
1328 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
&&
1330 DBG("Non-existing directory stream during recursive directory removal");
1333 PERROR("Failed to open directory stream during recursive directory removal");
1338 ret
= lttng_dynamic_array_add_element(
1339 &frames
, &new_frame
);
1341 ERR("Failed to push context frame during recursive directory removal");
1342 rmdir_frame_fini(&new_frame
);
1345 current_frame_idx
++;
1346 /* We break iteration on readdir. */
1354 /* Pop rmdir frame. */
1355 if (current_frame
->empty
) {
1356 ret
= lttng_directory_handle_rmdir(
1357 handle
, current_path
.data
);
1359 if ((flags
& LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG
) ||
1361 PERROR("Failed to remove \"%s\" during recursive directory removal",
1365 DBG("Non-existing directory stream during recursive directory removal");
1367 } else if (current_frame
->parent_frame_idx
>= 0) {
1368 struct rmdir_frame
*parent_frame
;
1370 parent_frame
= lttng_dynamic_array_get_element(&frames
,
1371 current_frame
->parent_frame_idx
);
1372 LTTNG_ASSERT(parent_frame
);
1373 parent_frame
->empty
= false;
1375 ret
= lttng_dynamic_array_remove_element(
1376 &frames
, current_frame_idx
);
1378 ERR("Failed to pop context frame during recursive directory removal");
1381 current_frame_idx
--;
1384 lttng_dynamic_array_reset(&frames
);
1385 lttng_dynamic_buffer_reset(¤t_path
);
1390 int lttng_directory_handle_remove_subdirectory_recursive(
1391 const struct lttng_directory_handle
*handle
,
1395 return lttng_directory_handle_remove_subdirectory_recursive_as_user(
1396 handle
, name
, NULL
, flags
);
1400 int lttng_directory_handle_remove_subdirectory_recursive_as_user(
1401 const struct lttng_directory_handle
*handle
,
1403 const struct lttng_credentials
*creds
,
1409 /* Run as current user. */
1410 ret
= remove_directory_recursive(handle
, name
, flags
);
1412 ret
= _run_as_rmdir_recursive(handle
, name
, lttng_credentials_get_uid(creds
),
1413 lttng_credentials_get_gid(creds
), flags
);