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
);
171 handle
->directory_inode
= RESERVED_AT_FDCWD_INO
;
173 handle
->dirfd
= dirfd
;
174 urcu_ref_init(&handle
->ref
);
180 void lttng_directory_handle_release(struct urcu_ref
*ref
)
183 struct lttng_directory_handle
*handle
=
184 container_of(ref
, struct lttng_directory_handle
, ref
);
186 if (handle
->destroy_cb
) {
187 handle
->destroy_cb(handle
, handle
->destroy_cb_data
);
190 if (handle
->dirfd
== AT_FDCWD
|| handle
->dirfd
== -1) {
193 ret
= close(handle
->dirfd
);
195 PERROR("Failed to close directory file descriptor of directory handle");
198 lttng_directory_handle_invalidate(handle
);
203 struct lttng_directory_handle
*lttng_directory_handle_copy(
204 const struct lttng_directory_handle
*handle
)
206 struct lttng_directory_handle
*new_handle
= NULL
;
208 if (handle
->dirfd
== AT_FDCWD
) {
209 new_handle
= lttng_directory_handle_create_from_dirfd(AT_FDCWD
);
211 const int new_dirfd
= dup(handle
->dirfd
);
213 if (new_dirfd
== -1) {
214 PERROR("Failed to duplicate directory file descriptor of directory handle");
217 new_handle
= lttng_directory_handle_create_from_dirfd(
219 if (!new_handle
&& close(new_dirfd
)) {
220 PERROR("Failed to close directory file descriptor of directory handle");
228 bool lttng_directory_handle_equals(const struct lttng_directory_handle
*lhs
,
229 const struct lttng_directory_handle
*rhs
)
231 return lhs
->directory_inode
== rhs
->directory_inode
;
235 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
)
241 int lttng_directory_handle_stat(const struct lttng_directory_handle
*handle
,
242 const char *path
, struct stat
*st
)
244 return fstatat(handle
->dirfd
, path
, st
, 0);
248 bool lttng_directory_handle_uses_fd(
249 const struct lttng_directory_handle
*handle
)
251 return handle
->dirfd
!= AT_FDCWD
;
255 int lttng_directory_handle_mkdir(
256 const struct lttng_directory_handle
*handle
,
257 const char *path
, mode_t mode
)
259 return mkdirat(handle
->dirfd
, path
, mode
);
263 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
264 const char *filename
, int flags
, mode_t mode
)
266 return openat(handle
->dirfd
, filename
, flags
, mode
);
270 int _run_as_open(const struct lttng_directory_handle
*handle
,
271 const char *filename
,
272 int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
274 return run_as_openat(handle
->dirfd
, filename
, flags
, mode
, uid
, gid
);
278 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
279 const char *filename
, uid_t uid
, gid_t gid
)
281 return run_as_unlinkat(handle
->dirfd
, filename
, uid
, gid
);
285 int lttng_directory_handle_unlink(
286 const struct lttng_directory_handle
*handle
,
287 const char *filename
)
289 return unlinkat(handle
->dirfd
, filename
, 0);
293 int _run_as_mkdir(const struct lttng_directory_handle
*handle
,
294 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
296 return run_as_mkdirat(handle
->dirfd
, path
, mode
, uid
, gid
);
300 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
301 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
303 return run_as_mkdirat_recursive(handle
->dirfd
, path
, mode
, uid
, gid
);
307 int _lttng_directory_handle_rename(
308 const struct lttng_directory_handle
*old_handle
,
309 const char *old_name
,
310 const struct lttng_directory_handle
*new_handle
,
311 const char *new_name
)
313 return renameat(old_handle
->dirfd
, old_name
,
314 new_handle
->dirfd
, new_name
);
318 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
319 const char *old_name
,
320 const struct lttng_directory_handle
*new_handle
,
321 const char *new_name
, uid_t uid
, gid_t gid
)
323 return run_as_renameat(old_handle
->dirfd
, old_name
, new_handle
->dirfd
,
328 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
331 DIR *dir_stream
= NULL
;
332 int fd
= openat(handle
->dirfd
, path
, O_RDONLY
);
338 dir_stream
= fdopendir(fd
);
342 PERROR("Failed to open directory stream");
345 PERROR("Failed to close file descriptor to %s", path
);
355 int lttng_directory_handle_rmdir(
356 const struct lttng_directory_handle
*handle
, const char *name
)
358 return unlinkat(handle
->dirfd
, name
, AT_REMOVEDIR
);
362 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
363 const char *name
, uid_t uid
, gid_t gid
)
365 return run_as_rmdirat(handle
->dirfd
, name
, uid
, gid
);
369 int _run_as_rmdir_recursive(
370 const struct lttng_directory_handle
*handle
, const char *name
,
371 uid_t uid
, gid_t gid
, int flags
)
373 return run_as_rmdirat_recursive(handle
->dirfd
, name
, uid
, gid
, flags
);
376 #else /* COMPAT_DIRFD */
379 int get_full_path(const struct lttng_directory_handle
*handle
,
380 const char *subdirectory
, char *fullpath
, size_t size
)
383 const bool subdirectory_is_absolute
=
384 subdirectory
&& *subdirectory
== '/';
385 const char * const base
= subdirectory_is_absolute
?
386 subdirectory
: handle
->base_path
;
387 const char * const end
= subdirectory
&& !subdirectory_is_absolute
?
389 const size_t base_len
= strlen(base
);
390 const size_t end_len
= end
? strlen(end
) : 0;
391 const bool add_separator_slash
= end
&& base
[base_len
- 1] != '/';
392 const bool add_trailing_slash
= end
&& end
[end_len
- 1] != '/';
394 ret
= snprintf(fullpath
, size
, "%s%s%s%s",
396 add_separator_slash
? "/" : "",
398 add_trailing_slash
? "/" : "");
399 if (ret
== -1 || ret
>= size
) {
400 ERR("Failed to format subdirectory from directory handle");
410 struct lttng_directory_handle
*_lttng_directory_handle_create(char *path
)
412 struct lttng_directory_handle
*handle
= zmalloc(sizeof(*handle
));
417 urcu_ref_init(&handle
->ref
);
418 handle
->base_path
= path
;
424 struct lttng_directory_handle
*lttng_directory_handle_create(
428 const char *cwd
= "";
429 size_t cwd_len
, path_len
;
430 char cwd_buf
[LTTNG_PATH_MAX
] = {};
431 char handle_buf
[LTTNG_PATH_MAX
] = {};
432 struct lttng_directory_handle
*new_handle
= NULL
;
433 bool add_cwd_slash
= false, add_trailing_slash
= false;
434 const struct lttng_directory_handle cwd_handle
= {
435 .base_path
= handle_buf
,
438 path_len
= path
? strlen(path
) : 0;
439 add_trailing_slash
= path
&& path
[path_len
- 1] != '/';
440 if (!path
|| (path
&& *path
!= '/')) {
441 cwd
= getcwd(cwd_buf
, sizeof(cwd_buf
));
443 PERROR("Failed to initialize directory handle, can't get current working directory");
447 cwd_len
= strlen(cwd
);
449 ERR("Failed to initialize directory handle, current working directory path has a length of 0");
453 add_cwd_slash
= cwd
[cwd_len
- 1] != '/';
456 ret
= snprintf(handle_buf
, sizeof(handle_buf
), "%s%s%s%s",
458 add_cwd_slash
? "/" : "",
460 add_trailing_slash
? "/" : "");
461 if (ret
== -1 || ret
>= LTTNG_PATH_MAX
) {
462 ERR("Failed to initialize directory handle, failed to format directory path");
466 new_handle
= lttng_directory_handle_create_from_handle(path
, &cwd_handle
);
472 struct lttng_directory_handle
*lttng_directory_handle_create_from_handle(
474 const struct lttng_directory_handle
*ref_handle
)
477 size_t path_len
, handle_path_len
;
478 bool add_trailing_slash
;
479 struct stat stat_buf
;
480 struct lttng_directory_handle
*new_handle
= NULL
;
481 char *new_path
= NULL
;
483 assert(ref_handle
&& ref_handle
->base_path
);
485 ret
= lttng_directory_handle_stat(ref_handle
, path
, &stat_buf
);
487 PERROR("Failed to create directory handle");
489 } else if (!S_ISDIR(stat_buf
.st_mode
)) {
490 char full_path
[LTTNG_PATH_MAX
];
492 /* Best effort for logging purposes. */
493 ret
= get_full_path(ref_handle
, path
, full_path
,
499 ERR("Failed to initialize directory handle to \"%s\": not a directory",
504 new_handle
= lttng_directory_handle_copy(ref_handle
);
508 path_len
= strlen(path
);
510 ERR("Failed to initialize directory handle: provided path is an empty string");
515 new_path
= strdup(path
);
519 /* Takes ownership of new_path. */
520 new_handle
= _lttng_directory_handle_create(new_path
);
525 add_trailing_slash
= path
[path_len
- 1] != '/';
527 handle_path_len
= strlen(ref_handle
->base_path
) + path_len
+
528 !!add_trailing_slash
;
529 if (handle_path_len
>= LTTNG_PATH_MAX
) {
530 ERR("Failed to initialize directory handle as the resulting path's length (%zu bytes) exceeds the maximal allowed length (%d bytes)",
531 handle_path_len
, LTTNG_PATH_MAX
);
534 new_path
= zmalloc(handle_path_len
);
536 PERROR("Failed to initialize directory handle");
540 ret
= sprintf(new_handle
->base_path
, "%s%s%s",
541 ref_handle
->base_path
,
543 add_trailing_slash
? "/" : "");
544 if (ret
== -1 || ret
>= handle_path_len
) {
545 ERR("Failed to initialize directory handle: path formatting failed");
548 new_handle
= _lttng_directory_handle_create(new_path
);
556 struct lttng_directory_handle
*lttng_directory_handle_create_from_dirfd(
559 assert(dirfd
== AT_FDCWD
);
560 return lttng_directory_handle_create(NULL
);
564 void lttng_directory_handle_release(struct urcu_ref
*ref
)
566 struct lttng_directory_handle
*handle
=
567 container_of(ref
, struct lttng_directory_handle
, ref
);
569 free(handle
->base_path
);
570 lttng_directory_handle_invalidate(handle
);
575 struct lttng_directory_handle
*lttng_directory_handle_copy(
576 const struct lttng_directory_handle
*handle
)
578 struct lttng_directory_handle
*new_handle
= NULL
;
579 char *new_path
= NULL
;
581 if (handle
->base_path
) {
582 new_path
= strdup(handle
->base_path
);
587 new_handle
= _lttng_directory_handle_create(new_path
);
593 bool lttng_directory_handle_equals(const struct lttng_directory_handle
*lhs
,
594 const struct lttng_directory_handle
*rhs
)
596 return strcmp(lhs
->base_path
, rhs
->base_path
) == 0;
600 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
)
602 handle
->base_path
= NULL
;
606 int lttng_directory_handle_stat(const struct lttng_directory_handle
*handle
,
607 const char *subdirectory
, struct stat
*st
)
610 char fullpath
[LTTNG_PATH_MAX
];
612 ret
= get_full_path(handle
, subdirectory
, fullpath
, sizeof(fullpath
));
618 ret
= stat(fullpath
, st
);
624 bool lttng_directory_handle_uses_fd(
625 const struct lttng_directory_handle
*handle
)
631 int lttng_directory_handle_mkdir(const struct lttng_directory_handle
*handle
,
632 const char *subdirectory
, mode_t mode
)
635 char fullpath
[LTTNG_PATH_MAX
];
637 ret
= get_full_path(handle
, subdirectory
, fullpath
, sizeof(fullpath
));
643 ret
= mkdir(fullpath
, mode
);
649 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
650 const char *filename
, int flags
, mode_t mode
)
653 char fullpath
[LTTNG_PATH_MAX
];
655 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
661 ret
= open(fullpath
, flags
, mode
);
667 int lttng_directory_handle_unlink(
668 const struct lttng_directory_handle
*handle
,
669 const char *filename
)
672 char fullpath
[LTTNG_PATH_MAX
];
674 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
680 ret
= unlink(fullpath
);
686 int _run_as_mkdir(const struct lttng_directory_handle
*handle
, const char *path
,
687 mode_t mode
, uid_t uid
, gid_t gid
)
690 char fullpath
[LTTNG_PATH_MAX
];
692 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
698 ret
= run_as_mkdir(fullpath
, mode
, uid
, gid
);
704 int _run_as_open(const struct lttng_directory_handle
*handle
,
705 const char *filename
,
706 int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
709 char fullpath
[LTTNG_PATH_MAX
];
711 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
717 ret
= run_as_open(fullpath
, flags
, mode
, uid
, gid
);
723 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
724 const char *filename
, uid_t uid
, gid_t gid
)
727 char fullpath
[LTTNG_PATH_MAX
];
729 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
735 ret
= run_as_unlink(fullpath
, uid
, gid
);
741 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
742 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
745 char fullpath
[LTTNG_PATH_MAX
];
747 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
753 ret
= run_as_mkdir_recursive(fullpath
, mode
, uid
, gid
);
759 int _lttng_directory_handle_rename(
760 const struct lttng_directory_handle
*old_handle
,
761 const char *old_name
,
762 const struct lttng_directory_handle
*new_handle
,
763 const char *new_name
)
766 char old_fullpath
[LTTNG_PATH_MAX
];
767 char new_fullpath
[LTTNG_PATH_MAX
];
769 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
770 sizeof(old_fullpath
));
775 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
776 sizeof(new_fullpath
));
782 ret
= rename(old_fullpath
, new_fullpath
);
788 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
789 const char *old_name
,
790 const struct lttng_directory_handle
*new_handle
,
791 const char *new_name
, uid_t uid
, gid_t gid
)
794 char old_fullpath
[LTTNG_PATH_MAX
];
795 char new_fullpath
[LTTNG_PATH_MAX
];
797 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
798 sizeof(old_fullpath
));
803 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
804 sizeof(new_fullpath
));
810 ret
= run_as_rename(old_fullpath
, new_fullpath
, uid
, gid
);
816 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
820 DIR *dir_stream
= NULL
;
821 char fullpath
[LTTNG_PATH_MAX
];
823 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
829 dir_stream
= opendir(fullpath
);
835 int lttng_directory_handle_rmdir(
836 const struct lttng_directory_handle
*handle
, const char *name
)
839 char fullpath
[LTTNG_PATH_MAX
];
841 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
847 ret
= rmdir(fullpath
);
853 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
854 const char *name
, uid_t uid
, gid_t gid
)
857 char fullpath
[LTTNG_PATH_MAX
];
859 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
865 ret
= run_as_rmdir(fullpath
, uid
, gid
);
871 int _run_as_rmdir_recursive(
872 const struct lttng_directory_handle
*handle
, const char *name
,
873 uid_t uid
, gid_t gid
, int flags
)
876 char fullpath
[LTTNG_PATH_MAX
];
878 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
884 ret
= run_as_rmdir_recursive(fullpath
, uid
, gid
, flags
);
889 #endif /* COMPAT_DIRFD */
891 /* Common implementation. */
894 * On some filesystems (e.g. nfs), mkdir will validate access rights before
895 * checking for the existence of the path element. This means that on a setup
896 * where "/home/" is a mounted NFS share, and running as an unpriviledged user,
897 * recursively creating a path of the form "/home/my_user/trace/" will fail with
898 * EACCES on mkdir("/home", ...).
900 * Checking the path for existence allows us to work around this behaviour.
903 int create_directory_check_exists(const struct lttng_directory_handle
*handle
,
904 const char *path
, mode_t mode
)
909 ret
= lttng_directory_handle_stat(handle
, path
, &st
);
911 if (S_ISDIR(st
.st_mode
)) {
912 /* Directory exists, skip. */
915 /* Exists, but is not a directory. */
920 } else if (errno
!= ENOENT
) {
925 * Let mkdir handle other errors as the caller expects mkdir
928 ret
= lttng_directory_handle_mkdir(handle
, path
, mode
);
934 int create_directory_recursive(const struct lttng_directory_handle
*handle
,
935 const char *path
, mode_t mode
)
937 char *p
, tmp
[LTTNG_PATH_MAX
];
943 ret
= lttng_strncpy(tmp
, path
, sizeof(tmp
));
945 ERR("Failed to create directory: provided path's length (%zu bytes) exceeds the maximal allowed length (%zu bytes)",
946 strlen(path
) + 1, sizeof(tmp
));
951 if (tmp
[len
- 1] == '/') {
955 for (p
= tmp
+ 1; *p
; p
++) {
958 if (tmp
[strlen(tmp
) - 1] == '.' &&
959 tmp
[strlen(tmp
) - 2] == '.' &&
960 tmp
[strlen(tmp
) - 3] == '/') {
961 ERR("Using '/../' is not permitted in the trace path (%s)",
966 ret
= create_directory_check_exists(handle
, tmp
, mode
);
968 if (errno
!= EACCES
) {
969 PERROR("Failed to create directory \"%s\"",
979 ret
= create_directory_check_exists(handle
, tmp
, mode
);
981 PERROR("mkdirat recursive last element");
989 bool lttng_directory_handle_get(struct lttng_directory_handle
*handle
)
991 return urcu_ref_get_unless_zero(&handle
->ref
);
995 void lttng_directory_handle_put(struct lttng_directory_handle
*handle
)
1000 assert(handle
->ref
.refcount
);
1001 urcu_ref_put(&handle
->ref
, lttng_directory_handle_release
);
1005 int lttng_directory_handle_create_subdirectory_as_user(
1006 const struct lttng_directory_handle
*handle
,
1007 const char *subdirectory
,
1008 mode_t mode
, const struct lttng_credentials
*creds
)
1013 /* Run as current user. */
1014 ret
= create_directory_check_exists(handle
,
1015 subdirectory
, mode
);
1017 ret
= _run_as_mkdir(handle
, subdirectory
,
1018 mode
, creds
->uid
, creds
->gid
);
1025 int lttng_directory_handle_create_subdirectory_recursive_as_user(
1026 const struct lttng_directory_handle
*handle
,
1027 const char *subdirectory_path
,
1028 mode_t mode
, const struct lttng_credentials
*creds
)
1033 /* Run as current user. */
1034 ret
= create_directory_recursive(handle
,
1035 subdirectory_path
, mode
);
1037 ret
= _run_as_mkdir_recursive(handle
, subdirectory_path
,
1038 mode
, creds
->uid
, creds
->gid
);
1045 int lttng_directory_handle_create_subdirectory(
1046 const struct lttng_directory_handle
*handle
,
1047 const char *subdirectory
,
1050 return lttng_directory_handle_create_subdirectory_as_user(
1051 handle
, subdirectory
, mode
, NULL
);
1055 int lttng_directory_handle_create_subdirectory_recursive(
1056 const struct lttng_directory_handle
*handle
,
1057 const char *subdirectory_path
,
1060 return lttng_directory_handle_create_subdirectory_recursive_as_user(
1061 handle
, subdirectory_path
, mode
, NULL
);
1065 int lttng_directory_handle_open_file_as_user(
1066 const struct lttng_directory_handle
*handle
,
1067 const char *filename
,
1068 int flags
, mode_t mode
,
1069 const struct lttng_credentials
*creds
)
1074 /* Run as current user. */
1075 ret
= lttng_directory_handle_open(handle
, filename
, flags
,
1078 ret
= _run_as_open(handle
, filename
, flags
, mode
,
1079 creds
->uid
, creds
->gid
);
1085 int lttng_directory_handle_open_file(
1086 const struct lttng_directory_handle
*handle
,
1087 const char *filename
,
1088 int flags
, mode_t mode
)
1090 return lttng_directory_handle_open_file_as_user(handle
, filename
, flags
,
1095 int lttng_directory_handle_unlink_file_as_user(
1096 const struct lttng_directory_handle
*handle
,
1097 const char *filename
,
1098 const struct lttng_credentials
*creds
)
1103 /* Run as current user. */
1104 ret
= lttng_directory_handle_unlink(handle
, filename
);
1106 ret
= _run_as_unlink(handle
, filename
, creds
->uid
, creds
->gid
);
1112 int lttng_directory_handle_unlink_file(
1113 const struct lttng_directory_handle
*handle
,
1114 const char *filename
)
1116 return lttng_directory_handle_unlink_file_as_user(handle
,
1121 int lttng_directory_handle_rename(
1122 const struct lttng_directory_handle
*old_handle
,
1123 const char *old_name
,
1124 const struct lttng_directory_handle
*new_handle
,
1125 const char *new_name
)
1127 return lttng_directory_handle_rename_as_user(old_handle
, old_name
,
1128 new_handle
, new_name
, NULL
);
1132 int lttng_directory_handle_rename_as_user(
1133 const struct lttng_directory_handle
*old_handle
,
1134 const char *old_name
,
1135 const struct lttng_directory_handle
*new_handle
,
1136 const char *new_name
,
1137 const struct lttng_credentials
*creds
)
1142 /* Run as current user. */
1143 ret
= _lttng_directory_handle_rename(old_handle
,
1144 old_name
, new_handle
, new_name
);
1146 ret
= _run_as_rename(old_handle
, old_name
, new_handle
,
1147 new_name
, creds
->uid
, creds
->gid
);
1153 int lttng_directory_handle_remove_subdirectory(
1154 const struct lttng_directory_handle
*handle
,
1157 return lttng_directory_handle_remove_subdirectory_as_user(handle
, name
,
1162 int lttng_directory_handle_remove_subdirectory_as_user(
1163 const struct lttng_directory_handle
*handle
,
1165 const struct lttng_credentials
*creds
)
1170 /* Run as current user. */
1171 ret
= lttng_directory_handle_rmdir(handle
, name
);
1173 ret
= _run_as_rmdir(handle
, name
, creds
->uid
, creds
->gid
);
1178 struct rmdir_frame
{
1179 ssize_t parent_frame_idx
;
1182 /* Size including '\0'. */
1187 void rmdir_frame_fini(void *data
)
1190 struct rmdir_frame
*frame
= data
;
1192 ret
= closedir(frame
->dir
);
1194 PERROR("Failed to close directory stream");
1199 int remove_directory_recursive(const struct lttng_directory_handle
*handle
,
1200 const char *path
, int flags
)
1203 struct lttng_dynamic_array frames
;
1204 size_t current_frame_idx
= 0;
1205 struct rmdir_frame initial_frame
= {
1206 .parent_frame_idx
= -1,
1207 .dir
= lttng_directory_handle_opendir(handle
, path
),
1209 .path_size
= strlen(path
) + 1,
1211 struct lttng_dynamic_buffer current_path
;
1212 const char separator
= '/';
1214 lttng_dynamic_buffer_init(¤t_path
);
1215 lttng_dynamic_array_init(&frames
, sizeof(struct rmdir_frame
),
1218 if (flags
& ~(LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
|
1219 LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG
)) {
1220 ERR("Unknown flags %d", flags
);
1225 if (!initial_frame
.dir
) {
1226 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
&&
1228 DBG("Cannot rmdir \"%s\": root does not exist", path
);
1232 PERROR("Failed to rmdir \"%s\"", path
);
1238 ret
= lttng_dynamic_array_add_element(&frames
, &initial_frame
);
1240 ERR("Failed to push context frame during recursive directory removal");
1241 rmdir_frame_fini(&initial_frame
);
1245 ret
= lttng_dynamic_buffer_append(
1246 ¤t_path
, path
, initial_frame
.path_size
);
1248 ERR("Failed to set initial path during recursive directory removal");
1253 while (lttng_dynamic_array_get_count(&frames
) > 0) {
1254 struct dirent
*entry
;
1255 struct rmdir_frame
*current_frame
=
1256 lttng_dynamic_array_get_element(
1257 &frames
, current_frame_idx
);
1259 assert(current_frame
->dir
);
1260 ret
= lttng_dynamic_buffer_set_size(
1261 ¤t_path
, current_frame
->path_size
);
1263 current_path
.data
[current_path
.size
- 1] = '\0';
1265 while ((entry
= readdir(current_frame
->dir
))) {
1268 if (!strcmp(entry
->d_name
, ".") ||
1269 !strcmp(entry
->d_name
, "..")) {
1273 /* Set current_path to the entry's path. */
1274 ret
= lttng_dynamic_buffer_set_size(
1275 ¤t_path
, current_path
.size
- 1);
1277 ret
= lttng_dynamic_buffer_append(¤t_path
,
1278 &separator
, sizeof(separator
));
1282 ret
= lttng_dynamic_buffer_append(¤t_path
,
1284 strlen(entry
->d_name
) + 1);
1289 if (lttng_directory_handle_stat(
1290 handle
, current_path
.data
, &st
)) {
1291 if ((flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
) &&
1295 PERROR("Failed to stat \"%s\"",
1301 if (!S_ISDIR(st
.st_mode
)) {
1302 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
) {
1303 current_frame
->empty
= false;
1306 /* Not empty, abort. */
1307 DBG("Directory \"%s\" is not empty; refusing to remove directory",
1313 struct rmdir_frame new_frame
= {
1314 .path_size
= current_path
.size
,
1315 .dir
= lttng_directory_handle_opendir(
1319 .parent_frame_idx
= current_frame_idx
,
1322 if (!new_frame
.dir
) {
1323 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
&&
1325 DBG("Non-existing directory stream during recursive directory removal");
1328 PERROR("Failed to open directory stream during recursive directory removal");
1333 ret
= lttng_dynamic_array_add_element(
1334 &frames
, &new_frame
);
1336 ERR("Failed to push context frame during recursive directory removal");
1337 rmdir_frame_fini(&new_frame
);
1340 current_frame_idx
++;
1341 /* We break iteration on readdir. */
1349 /* Pop rmdir frame. */
1350 if (current_frame
->empty
) {
1351 ret
= lttng_directory_handle_rmdir(
1352 handle
, current_path
.data
);
1354 if ((flags
& LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG
) ||
1356 PERROR("Failed to remove \"%s\" during recursive directory removal",
1360 DBG("Non-existing directory stream during recursive directory removal");
1362 } else if (current_frame
->parent_frame_idx
>= 0) {
1363 struct rmdir_frame
*parent_frame
;
1365 parent_frame
= lttng_dynamic_array_get_element(&frames
,
1366 current_frame
->parent_frame_idx
);
1367 assert(parent_frame
);
1368 parent_frame
->empty
= false;
1370 ret
= lttng_dynamic_array_remove_element(
1371 &frames
, current_frame_idx
);
1373 ERR("Failed to pop context frame during recursive directory removal");
1376 current_frame_idx
--;
1379 lttng_dynamic_array_reset(&frames
);
1380 lttng_dynamic_buffer_reset(¤t_path
);
1385 int lttng_directory_handle_remove_subdirectory_recursive(
1386 const struct lttng_directory_handle
*handle
,
1390 return lttng_directory_handle_remove_subdirectory_recursive_as_user(
1391 handle
, name
, NULL
, flags
);
1395 int lttng_directory_handle_remove_subdirectory_recursive_as_user(
1396 const struct lttng_directory_handle
*handle
,
1398 const struct lttng_credentials
*creds
,
1404 /* Run as current user. */
1405 ret
= remove_directory_recursive(handle
, name
, flags
);
1407 ret
= _run_as_rmdir_recursive(handle
, name
, creds
->uid
,