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 int ret
= unlinkat(handle
->dirfd
, name
, AT_REMOVEDIR
);
360 PERROR("Failed to remove directory `%s`", name
);
367 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
368 const char *name
, uid_t uid
, gid_t gid
)
370 return run_as_rmdirat(handle
->dirfd
, name
, uid
, gid
);
374 int _run_as_rmdir_recursive(
375 const struct lttng_directory_handle
*handle
, const char *name
,
376 uid_t uid
, gid_t gid
, int flags
)
378 return run_as_rmdirat_recursive(handle
->dirfd
, name
, uid
, gid
, flags
);
381 #else /* HAVE_DIRFD */
384 int get_full_path(const struct lttng_directory_handle
*handle
,
385 const char *subdirectory
, char *fullpath
, size_t size
)
388 const bool subdirectory_is_absolute
=
389 subdirectory
&& *subdirectory
== '/';
390 const char * const base
= subdirectory_is_absolute
?
391 subdirectory
: handle
->base_path
;
392 const char * const end
= subdirectory
&& !subdirectory_is_absolute
?
394 const size_t base_len
= strlen(base
);
395 const size_t end_len
= end
? strlen(end
) : 0;
396 const bool add_separator_slash
= end
&& base
[base_len
- 1] != '/';
397 const bool add_trailing_slash
= end
&& end
[end_len
- 1] != '/';
399 ret
= snprintf(fullpath
, size
, "%s%s%s%s",
401 add_separator_slash
? "/" : "",
403 add_trailing_slash
? "/" : "");
404 if (ret
== -1 || ret
>= size
) {
405 ERR("Failed to format subdirectory from directory handle");
415 struct lttng_directory_handle
*_lttng_directory_handle_create(char *path
)
417 struct lttng_directory_handle
*handle
= zmalloc(sizeof(*handle
));
422 urcu_ref_init(&handle
->ref
);
423 handle
->base_path
= path
;
429 struct lttng_directory_handle
*lttng_directory_handle_create(
433 const char *cwd
= "";
434 size_t cwd_len
, path_len
;
435 char cwd_buf
[LTTNG_PATH_MAX
] = {};
436 char handle_buf
[LTTNG_PATH_MAX
] = {};
437 struct lttng_directory_handle
*new_handle
= NULL
;
438 bool add_cwd_slash
= false, add_trailing_slash
= false;
439 const struct lttng_directory_handle cwd_handle
= {
440 .base_path
= handle_buf
,
443 path_len
= path
? strlen(path
) : 0;
444 add_trailing_slash
= path
&& path
[path_len
- 1] != '/';
445 if (!path
|| (path
&& *path
!= '/')) {
446 cwd
= getcwd(cwd_buf
, sizeof(cwd_buf
));
448 PERROR("Failed to initialize directory handle, can't get current working directory");
452 cwd_len
= strlen(cwd
);
454 ERR("Failed to initialize directory handle, current working directory path has a length of 0");
458 add_cwd_slash
= cwd
[cwd_len
- 1] != '/';
461 ret
= snprintf(handle_buf
, sizeof(handle_buf
), "%s%s%s%s",
463 add_cwd_slash
? "/" : "",
465 add_trailing_slash
? "/" : "");
466 if (ret
== -1 || ret
>= LTTNG_PATH_MAX
) {
467 ERR("Failed to initialize directory handle, failed to format directory path");
471 new_handle
= lttng_directory_handle_create_from_handle(path
, &cwd_handle
);
477 struct lttng_directory_handle
*lttng_directory_handle_create_from_handle(
479 const struct lttng_directory_handle
*ref_handle
)
482 size_t path_len
, handle_path_len
;
483 bool add_trailing_slash
;
484 struct stat stat_buf
;
485 struct lttng_directory_handle
*new_handle
= NULL
;
486 char *new_path
= NULL
;
488 assert(ref_handle
&& ref_handle
->base_path
);
490 ret
= lttng_directory_handle_stat(ref_handle
, path
, &stat_buf
);
492 PERROR("Failed to create directory handle");
494 } else if (!S_ISDIR(stat_buf
.st_mode
)) {
495 char full_path
[LTTNG_PATH_MAX
];
497 /* Best effort for logging purposes. */
498 ret
= get_full_path(ref_handle
, path
, full_path
,
504 ERR("Failed to initialize directory handle to \"%s\": not a directory",
509 new_handle
= lttng_directory_handle_copy(ref_handle
);
513 path_len
= strlen(path
);
515 ERR("Failed to initialize directory handle: provided path is an empty string");
520 new_path
= strdup(path
);
524 /* Takes ownership of new_path. */
525 new_handle
= _lttng_directory_handle_create(new_path
);
530 add_trailing_slash
= path
[path_len
- 1] != '/';
532 handle_path_len
= strlen(ref_handle
->base_path
) + path_len
+
533 !!add_trailing_slash
;
534 if (handle_path_len
>= LTTNG_PATH_MAX
) {
535 ERR("Failed to initialize directory handle as the resulting path's length (%zu bytes) exceeds the maximal allowed length (%d bytes)",
536 handle_path_len
, LTTNG_PATH_MAX
);
539 new_path
= zmalloc(handle_path_len
);
541 PERROR("Failed to initialize directory handle");
545 ret
= sprintf(new_handle
->base_path
, "%s%s%s",
546 ref_handle
->base_path
,
548 add_trailing_slash
? "/" : "");
549 if (ret
== -1 || ret
>= handle_path_len
) {
550 ERR("Failed to initialize directory handle: path formatting failed");
553 new_handle
= _lttng_directory_handle_create(new_path
);
561 struct lttng_directory_handle
*lttng_directory_handle_create_from_dirfd(
564 assert(dirfd
== AT_FDCWD
);
565 return lttng_directory_handle_create(NULL
);
569 void lttng_directory_handle_release(struct urcu_ref
*ref
)
571 struct lttng_directory_handle
*handle
=
572 container_of(ref
, struct lttng_directory_handle
, ref
);
574 free(handle
->base_path
);
575 lttng_directory_handle_invalidate(handle
);
580 struct lttng_directory_handle
*lttng_directory_handle_copy(
581 const struct lttng_directory_handle
*handle
)
583 struct lttng_directory_handle
*new_handle
= NULL
;
584 char *new_path
= NULL
;
586 if (handle
->base_path
) {
587 new_path
= strdup(handle
->base_path
);
592 new_handle
= _lttng_directory_handle_create(new_path
);
598 bool lttng_directory_handle_equals(const struct lttng_directory_handle
*lhs
,
599 const struct lttng_directory_handle
*rhs
)
601 return strcmp(lhs
->base_path
, rhs
->base_path
) == 0;
605 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
)
607 handle
->base_path
= NULL
;
611 int lttng_directory_handle_stat(const struct lttng_directory_handle
*handle
,
612 const char *subdirectory
, struct stat
*st
)
615 char fullpath
[LTTNG_PATH_MAX
];
617 ret
= get_full_path(handle
, subdirectory
, fullpath
, sizeof(fullpath
));
623 ret
= stat(fullpath
, st
);
629 bool lttng_directory_handle_uses_fd(
630 const struct lttng_directory_handle
*handle
)
636 int lttng_directory_handle_mkdir(const struct lttng_directory_handle
*handle
,
637 const char *subdirectory
, mode_t mode
)
640 char fullpath
[LTTNG_PATH_MAX
];
642 ret
= get_full_path(handle
, subdirectory
, fullpath
, sizeof(fullpath
));
648 ret
= mkdir(fullpath
, mode
);
654 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
655 const char *filename
, int flags
, mode_t mode
)
658 char fullpath
[LTTNG_PATH_MAX
];
660 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
666 ret
= open(fullpath
, flags
, mode
);
672 int lttng_directory_handle_unlink(
673 const struct lttng_directory_handle
*handle
,
674 const char *filename
)
677 char fullpath
[LTTNG_PATH_MAX
];
679 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
685 ret
= unlink(fullpath
);
691 int _run_as_mkdir(const struct lttng_directory_handle
*handle
, const char *path
,
692 mode_t mode
, uid_t uid
, gid_t gid
)
695 char fullpath
[LTTNG_PATH_MAX
];
697 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
703 ret
= run_as_mkdir(fullpath
, mode
, uid
, gid
);
709 int _run_as_open(const struct lttng_directory_handle
*handle
,
710 const char *filename
,
711 int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
714 char fullpath
[LTTNG_PATH_MAX
];
716 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
722 ret
= run_as_open(fullpath
, flags
, mode
, uid
, gid
);
728 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
729 const char *filename
, uid_t uid
, gid_t gid
)
732 char fullpath
[LTTNG_PATH_MAX
];
734 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
740 ret
= run_as_unlink(fullpath
, uid
, gid
);
746 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
747 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
750 char fullpath
[LTTNG_PATH_MAX
];
752 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
758 ret
= run_as_mkdir_recursive(fullpath
, mode
, uid
, gid
);
764 int _lttng_directory_handle_rename(
765 const struct lttng_directory_handle
*old_handle
,
766 const char *old_name
,
767 const struct lttng_directory_handle
*new_handle
,
768 const char *new_name
)
771 char old_fullpath
[LTTNG_PATH_MAX
];
772 char new_fullpath
[LTTNG_PATH_MAX
];
774 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
775 sizeof(old_fullpath
));
780 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
781 sizeof(new_fullpath
));
787 ret
= rename(old_fullpath
, new_fullpath
);
793 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
794 const char *old_name
,
795 const struct lttng_directory_handle
*new_handle
,
796 const char *new_name
, uid_t uid
, gid_t gid
)
799 char old_fullpath
[LTTNG_PATH_MAX
];
800 char new_fullpath
[LTTNG_PATH_MAX
];
802 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
803 sizeof(old_fullpath
));
808 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
809 sizeof(new_fullpath
));
815 ret
= run_as_rename(old_fullpath
, new_fullpath
, uid
, gid
);
821 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
825 DIR *dir_stream
= NULL
;
826 char fullpath
[LTTNG_PATH_MAX
];
828 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
834 dir_stream
= opendir(fullpath
);
840 int lttng_directory_handle_rmdir(
841 const struct lttng_directory_handle
*handle
, const char *name
)
844 char fullpath
[LTTNG_PATH_MAX
];
846 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
852 ret
= rmdir(fullpath
);
858 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
859 const char *name
, uid_t uid
, gid_t gid
)
862 char fullpath
[LTTNG_PATH_MAX
];
864 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
870 ret
= run_as_rmdir(fullpath
, uid
, gid
);
876 int _run_as_rmdir_recursive(
877 const struct lttng_directory_handle
*handle
, const char *name
,
878 uid_t uid
, gid_t gid
, int flags
)
881 char fullpath
[LTTNG_PATH_MAX
];
883 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
889 ret
= run_as_rmdir_recursive(fullpath
, uid
, gid
, flags
);
894 #endif /* HAVE_DIRFD */
896 /* Common implementation. */
899 * On some filesystems (e.g. nfs), mkdir will validate access rights before
900 * checking for the existence of the path element. This means that on a setup
901 * where "/home/" is a mounted NFS share, and running as an unpriviledged user,
902 * recursively creating a path of the form "/home/my_user/trace/" will fail with
903 * EACCES on mkdir("/home", ...).
905 * Checking the path for existence allows us to work around this behaviour.
908 int create_directory_check_exists(const struct lttng_directory_handle
*handle
,
909 const char *path
, mode_t mode
)
914 ret
= lttng_directory_handle_stat(handle
, path
, &st
);
916 if (S_ISDIR(st
.st_mode
)) {
917 /* Directory exists, skip. */
920 /* Exists, but is not a directory. */
925 } else if (errno
!= ENOENT
) {
930 * Let mkdir handle other errors as the caller expects mkdir
933 ret
= lttng_directory_handle_mkdir(handle
, path
, mode
);
939 int create_directory_recursive(const struct lttng_directory_handle
*handle
,
940 const char *path
, mode_t mode
)
942 char *p
, tmp
[LTTNG_PATH_MAX
];
948 ret
= lttng_strncpy(tmp
, path
, sizeof(tmp
));
950 ERR("Failed to create directory: provided path's length (%zu bytes) exceeds the maximal allowed length (%zu bytes)",
951 strlen(path
) + 1, sizeof(tmp
));
956 if (tmp
[len
- 1] == '/') {
960 for (p
= tmp
+ 1; *p
; p
++) {
963 if (tmp
[strlen(tmp
) - 1] == '.' &&
964 tmp
[strlen(tmp
) - 2] == '.' &&
965 tmp
[strlen(tmp
) - 3] == '/') {
966 ERR("Using '/../' is not permitted in the trace path (%s)",
971 ret
= create_directory_check_exists(handle
, tmp
, mode
);
973 if (errno
!= EACCES
) {
974 PERROR("Failed to create directory \"%s\"",
984 ret
= create_directory_check_exists(handle
, tmp
, mode
);
986 PERROR("mkdirat recursive last element");
994 bool lttng_directory_handle_get(struct lttng_directory_handle
*handle
)
996 return urcu_ref_get_unless_zero(&handle
->ref
);
1000 void lttng_directory_handle_put(struct lttng_directory_handle
*handle
)
1005 assert(handle
->ref
.refcount
);
1006 urcu_ref_put(&handle
->ref
, lttng_directory_handle_release
);
1010 int lttng_directory_handle_create_subdirectory_as_user(
1011 const struct lttng_directory_handle
*handle
,
1012 const char *subdirectory
,
1013 mode_t mode
, const struct lttng_credentials
*creds
)
1018 /* Run as current user. */
1019 ret
= create_directory_check_exists(handle
,
1020 subdirectory
, mode
);
1022 ret
= _run_as_mkdir(handle
, subdirectory
, mode
,
1023 lttng_credentials_get_uid(creds
),
1024 lttng_credentials_get_gid(creds
));
1031 int lttng_directory_handle_create_subdirectory_recursive_as_user(
1032 const struct lttng_directory_handle
*handle
,
1033 const char *subdirectory_path
,
1034 mode_t mode
, const struct lttng_credentials
*creds
)
1039 /* Run as current user. */
1040 ret
= create_directory_recursive(handle
,
1041 subdirectory_path
, mode
);
1043 ret
= _run_as_mkdir_recursive(handle
, subdirectory_path
,
1044 mode
, lttng_credentials_get_uid(creds
), lttng_credentials_get_gid(creds
));
1051 int lttng_directory_handle_create_subdirectory(
1052 const struct lttng_directory_handle
*handle
,
1053 const char *subdirectory
,
1056 return lttng_directory_handle_create_subdirectory_as_user(
1057 handle
, subdirectory
, mode
, NULL
);
1061 int lttng_directory_handle_create_subdirectory_recursive(
1062 const struct lttng_directory_handle
*handle
,
1063 const char *subdirectory_path
,
1066 return lttng_directory_handle_create_subdirectory_recursive_as_user(
1067 handle
, subdirectory_path
, mode
, NULL
);
1071 int lttng_directory_handle_open_file_as_user(
1072 const struct lttng_directory_handle
*handle
,
1073 const char *filename
,
1074 int flags
, mode_t mode
,
1075 const struct lttng_credentials
*creds
)
1080 /* Run as current user. */
1081 ret
= lttng_directory_handle_open(handle
, filename
, flags
,
1084 ret
= _run_as_open(handle
, filename
, flags
, mode
,
1085 lttng_credentials_get_uid(creds
), lttng_credentials_get_gid(creds
));
1091 int lttng_directory_handle_open_file(
1092 const struct lttng_directory_handle
*handle
,
1093 const char *filename
,
1094 int flags
, mode_t mode
)
1096 return lttng_directory_handle_open_file_as_user(handle
, filename
, flags
,
1101 int lttng_directory_handle_unlink_file_as_user(
1102 const struct lttng_directory_handle
*handle
,
1103 const char *filename
,
1104 const struct lttng_credentials
*creds
)
1109 /* Run as current user. */
1110 ret
= lttng_directory_handle_unlink(handle
, filename
);
1112 ret
= _run_as_unlink(handle
, filename
, lttng_credentials_get_uid(creds
), lttng_credentials_get_gid(creds
));
1118 int lttng_directory_handle_unlink_file(
1119 const struct lttng_directory_handle
*handle
,
1120 const char *filename
)
1122 return lttng_directory_handle_unlink_file_as_user(handle
,
1127 int lttng_directory_handle_rename(
1128 const struct lttng_directory_handle
*old_handle
,
1129 const char *old_name
,
1130 const struct lttng_directory_handle
*new_handle
,
1131 const char *new_name
)
1133 return lttng_directory_handle_rename_as_user(old_handle
, old_name
,
1134 new_handle
, new_name
, NULL
);
1138 int lttng_directory_handle_rename_as_user(
1139 const struct lttng_directory_handle
*old_handle
,
1140 const char *old_name
,
1141 const struct lttng_directory_handle
*new_handle
,
1142 const char *new_name
,
1143 const struct lttng_credentials
*creds
)
1148 /* Run as current user. */
1149 ret
= _lttng_directory_handle_rename(old_handle
,
1150 old_name
, new_handle
, new_name
);
1152 ret
= _run_as_rename(old_handle
, old_name
, new_handle
,
1153 new_name
, lttng_credentials_get_uid(creds
), lttng_credentials_get_gid(creds
));
1159 int lttng_directory_handle_remove_subdirectory(
1160 const struct lttng_directory_handle
*handle
,
1163 return lttng_directory_handle_remove_subdirectory_as_user(handle
, name
,
1168 int lttng_directory_handle_remove_subdirectory_as_user(
1169 const struct lttng_directory_handle
*handle
,
1171 const struct lttng_credentials
*creds
)
1176 /* Run as current user. */
1177 ret
= lttng_directory_handle_rmdir(handle
, name
);
1179 ret
= _run_as_rmdir(handle
, name
, lttng_credentials_get_uid(creds
), lttng_credentials_get_gid(creds
));
1184 struct rmdir_frame
{
1185 ssize_t parent_frame_idx
;
1188 /* Size including '\0'. */
1193 void rmdir_frame_fini(void *data
)
1196 struct rmdir_frame
*frame
= data
;
1198 ret
= closedir(frame
->dir
);
1200 PERROR("Failed to close directory stream");
1205 int remove_directory_recursive(const struct lttng_directory_handle
*handle
,
1206 const char *path
, int flags
)
1209 struct lttng_dynamic_array frames
;
1210 size_t current_frame_idx
= 0;
1211 struct rmdir_frame initial_frame
= {
1212 .parent_frame_idx
= -1,
1213 .dir
= lttng_directory_handle_opendir(handle
, path
),
1215 .path_size
= strlen(path
) + 1,
1217 struct lttng_dynamic_buffer current_path
;
1218 const char separator
= '/';
1220 lttng_dynamic_buffer_init(¤t_path
);
1221 lttng_dynamic_array_init(&frames
, sizeof(struct rmdir_frame
),
1224 if (flags
& ~(LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
|
1225 LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG
)) {
1226 ERR("Unknown flags %d", flags
);
1231 if (!initial_frame
.dir
) {
1232 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
&&
1234 DBG("Cannot rmdir \"%s\": root does not exist", path
);
1238 PERROR("Failed to rmdir \"%s\"", path
);
1244 ret
= lttng_dynamic_array_add_element(&frames
, &initial_frame
);
1246 ERR("Failed to push context frame during recursive directory removal");
1247 rmdir_frame_fini(&initial_frame
);
1251 ret
= lttng_dynamic_buffer_append(
1252 ¤t_path
, path
, initial_frame
.path_size
);
1254 ERR("Failed to set initial path during recursive directory removal");
1259 while (lttng_dynamic_array_get_count(&frames
) > 0) {
1260 struct dirent
*entry
;
1261 struct rmdir_frame
*current_frame
=
1262 lttng_dynamic_array_get_element(
1263 &frames
, current_frame_idx
);
1265 assert(current_frame
->dir
);
1266 ret
= lttng_dynamic_buffer_set_size(
1267 ¤t_path
, current_frame
->path_size
);
1269 current_path
.data
[current_path
.size
- 1] = '\0';
1271 while ((entry
= readdir(current_frame
->dir
))) {
1274 if (!strcmp(entry
->d_name
, ".") ||
1275 !strcmp(entry
->d_name
, "..")) {
1279 /* Set current_path to the entry's path. */
1280 ret
= lttng_dynamic_buffer_set_size(
1281 ¤t_path
, current_path
.size
- 1);
1283 ret
= lttng_dynamic_buffer_append(¤t_path
,
1284 &separator
, sizeof(separator
));
1288 ret
= lttng_dynamic_buffer_append(¤t_path
,
1290 strlen(entry
->d_name
) + 1);
1295 if (lttng_directory_handle_stat(
1296 handle
, current_path
.data
, &st
)) {
1297 if ((flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
) &&
1301 PERROR("Failed to stat \"%s\"",
1307 if (!S_ISDIR(st
.st_mode
)) {
1308 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
) {
1309 current_frame
->empty
= false;
1312 /* Not empty, abort. */
1313 DBG("Directory \"%s\" is not empty; refusing to remove directory",
1319 struct rmdir_frame new_frame
= {
1320 .path_size
= current_path
.size
,
1321 .dir
= lttng_directory_handle_opendir(
1325 .parent_frame_idx
= current_frame_idx
,
1328 if (!new_frame
.dir
) {
1329 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
&&
1331 DBG("Non-existing directory stream during recursive directory removal");
1334 PERROR("Failed to open directory stream during recursive directory removal");
1339 ret
= lttng_dynamic_array_add_element(
1340 &frames
, &new_frame
);
1342 ERR("Failed to push context frame during recursive directory removal");
1343 rmdir_frame_fini(&new_frame
);
1346 current_frame_idx
++;
1347 /* We break iteration on readdir. */
1355 /* Pop rmdir frame. */
1356 if (current_frame
->empty
) {
1357 ret
= lttng_directory_handle_rmdir(
1358 handle
, current_path
.data
);
1360 if ((flags
& LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG
) ||
1362 PERROR("Failed to remove \"%s\" during recursive directory removal",
1366 DBG("Non-existing directory stream during recursive directory removal");
1368 } else if (current_frame
->parent_frame_idx
>= 0) {
1369 struct rmdir_frame
*parent_frame
;
1371 parent_frame
= lttng_dynamic_array_get_element(&frames
,
1372 current_frame
->parent_frame_idx
);
1373 assert(parent_frame
);
1374 parent_frame
->empty
= false;
1376 ret
= lttng_dynamic_array_remove_element(
1377 &frames
, current_frame_idx
);
1379 ERR("Failed to pop context frame during recursive directory removal");
1382 current_frame_idx
--;
1385 lttng_dynamic_array_reset(&frames
);
1386 lttng_dynamic_buffer_reset(¤t_path
);
1391 int lttng_directory_handle_remove_subdirectory_recursive(
1392 const struct lttng_directory_handle
*handle
,
1396 return lttng_directory_handle_remove_subdirectory_recursive_as_user(
1397 handle
, name
, NULL
, flags
);
1401 int lttng_directory_handle_remove_subdirectory_recursive_as_user(
1402 const struct lttng_directory_handle
*handle
,
1404 const struct lttng_credentials
*creds
,
1410 /* Run as current user. */
1411 ret
= remove_directory_recursive(handle
, name
, flags
);
1413 ret
= _run_as_rmdir_recursive(handle
, name
, lttng_credentials_get_uid(creds
),
1414 lttng_credentials_get_gid(creds
), flags
);