2 * Copyright (C) 2019 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2 only,
6 * as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 #include <common/compat/directory-handle.h>
19 #include <common/error.h>
20 #include <common/macros.h>
21 #include <common/runas.h>
22 #include <common/credentials.h>
23 #include <lttng/constant.h>
24 #include <common/dynamic-array.h>
27 #include <sys/types.h>
34 * This compatibility layer shares a common "base" that is implemented
35 * in terms of an internal API. This file contains two implementations
36 * of the internal API below.
39 int lttng_directory_handle_stat(const struct lttng_directory_handle
*handle
,
40 const char *path
, struct stat
*st
);
42 int lttng_directory_handle_mkdir(
43 const struct lttng_directory_handle
*handle
,
44 const char *path
, mode_t mode
);
46 int _run_as_mkdir(const struct lttng_directory_handle
*handle
, const char *path
,
47 mode_t mode
, uid_t uid
, gid_t gid
);
49 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
50 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
);
52 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
53 const char *filename
, int flags
, mode_t mode
);
55 int _run_as_open(const struct lttng_directory_handle
*handle
,
57 int flags
, mode_t mode
, uid_t uid
, gid_t gid
);
59 int lttng_directory_handle_unlink(
60 const struct lttng_directory_handle
*handle
,
61 const char *filename
);
63 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
64 const char *filename
, uid_t uid
, gid_t gid
);
66 int _lttng_directory_handle_rename(
67 const struct lttng_directory_handle
*old_handle
,
69 const struct lttng_directory_handle
*new_handle
,
70 const char *new_name
);
72 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
74 const struct lttng_directory_handle
*new_handle
,
75 const char *new_name
, uid_t uid
, gid_t gid
);
77 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
80 int lttng_directory_handle_rmdir(
81 const struct lttng_directory_handle
*handle
, const char *name
);
83 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
84 const char *name
, uid_t uid
, gid_t gid
);
86 int _run_as_rmdir_recursive(
87 const struct lttng_directory_handle
*handle
, const char *name
,
88 uid_t uid
, gid_t gid
, int flags
);
90 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
);
92 void lttng_directory_handle_release(struct urcu_ref
*ref
);
97 * Special inode number reserved to represent the "current working directory".
98 * ino_t is spec'ed as being an unsigned integral type.
100 #define RESERVED_AT_FDCWD_INO \
102 uint64_t reserved_val; \
103 switch (sizeof(ino_t)) { \
105 reserved_val = UINT32_MAX; \
108 reserved_val = UINT64_MAX; \
113 (ino_t) reserved_val; \
117 struct lttng_directory_handle
*lttng_directory_handle_create(const char *path
)
119 const struct lttng_directory_handle cwd_handle
= {
123 /* Open a handle to the CWD if NULL is passed. */
124 return lttng_directory_handle_create_from_handle(path
, &cwd_handle
);
128 struct lttng_directory_handle
*lttng_directory_handle_create_from_handle(
130 const struct lttng_directory_handle
*ref_handle
)
133 struct lttng_directory_handle
*handle
= NULL
;
136 handle
= lttng_directory_handle_copy(ref_handle
);
140 ERR("Failed to initialize directory handle: provided path is an empty string");
144 dirfd
= openat(ref_handle
->dirfd
, path
, O_RDONLY
| O_DIRECTORY
| O_CLOEXEC
);
146 PERROR("Failed to initialize directory handle to \"%s\"", path
);
150 handle
= lttng_directory_handle_create_from_dirfd(dirfd
);
158 PERROR("Failed to close directory file descriptor");
164 struct lttng_directory_handle
*lttng_directory_handle_create_from_dirfd(
168 struct lttng_directory_handle
*handle
= zmalloc(sizeof(*handle
));
169 struct stat stat_buf
;
175 if (dirfd
!= AT_FDCWD
) {
176 ret
= fstat(dirfd
, &stat_buf
);
178 PERROR("Failed to fstat directory file descriptor %i", dirfd
);
179 lttng_directory_handle_release(&handle
->ref
);
182 handle
->directory_inode
= RESERVED_AT_FDCWD_INO
;
184 handle
->dirfd
= dirfd
;
185 urcu_ref_init(&handle
->ref
);
191 void lttng_directory_handle_release(struct urcu_ref
*ref
)
194 struct lttng_directory_handle
*handle
=
195 container_of(ref
, struct lttng_directory_handle
, ref
);
197 if (handle
->dirfd
== AT_FDCWD
|| handle
->dirfd
== -1) {
200 ret
= close(handle
->dirfd
);
202 PERROR("Failed to close directory file descriptor of directory handle");
205 lttng_directory_handle_invalidate(handle
);
210 struct lttng_directory_handle
*lttng_directory_handle_copy(
211 const struct lttng_directory_handle
*handle
)
213 struct lttng_directory_handle
*new_handle
= NULL
;
215 if (handle
->dirfd
== AT_FDCWD
) {
216 new_handle
= lttng_directory_handle_create_from_dirfd(AT_FDCWD
);
218 const int new_dirfd
= dup(handle
->dirfd
);
220 if (new_dirfd
== -1) {
221 PERROR("Failed to duplicate directory file descriptor of directory handle");
224 new_handle
= lttng_directory_handle_create_from_dirfd(
226 if (!new_handle
&& close(new_dirfd
)) {
227 PERROR("Failed to close directory file descriptor of directory handle");
235 bool lttng_directory_handle_equals(const struct lttng_directory_handle
*lhs
,
236 const struct lttng_directory_handle
*rhs
)
238 return lhs
->directory_inode
== rhs
->directory_inode
;
242 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
)
248 int lttng_directory_handle_stat(const struct lttng_directory_handle
*handle
,
249 const char *path
, struct stat
*st
)
251 return fstatat(handle
->dirfd
, path
, st
, 0);
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
->path
, rhs
->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 int lttng_directory_handle_mkdir(const struct lttng_directory_handle
*handle
,
625 const char *subdirectory
, mode_t mode
)
628 char fullpath
[LTTNG_PATH_MAX
];
630 ret
= get_full_path(handle
, subdirectory
, fullpath
, sizeof(fullpath
));
636 ret
= mkdir(fullpath
, mode
);
642 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
643 const char *filename
, int flags
, mode_t mode
)
646 char fullpath
[LTTNG_PATH_MAX
];
648 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
654 ret
= open(fullpath
, flags
, mode
);
660 int lttng_directory_handle_unlink(
661 const struct lttng_directory_handle
*handle
,
662 const char *filename
)
665 char fullpath
[LTTNG_PATH_MAX
];
667 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
673 ret
= unlink(fullpath
);
679 int _run_as_mkdir(const struct lttng_directory_handle
*handle
, const char *path
,
680 mode_t mode
, uid_t uid
, gid_t gid
)
683 char fullpath
[LTTNG_PATH_MAX
];
685 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
691 ret
= run_as_mkdir(fullpath
, mode
, uid
, gid
);
697 int _run_as_open(const struct lttng_directory_handle
*handle
,
698 const char *filename
,
699 int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
702 char fullpath
[LTTNG_PATH_MAX
];
704 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
710 ret
= run_as_open(fullpath
, flags
, mode
, uid
, gid
);
716 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
717 const char *filename
, uid_t uid
, gid_t gid
)
720 char fullpath
[LTTNG_PATH_MAX
];
722 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
728 ret
= run_as_unlink(fullpath
, uid
, gid
);
734 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
735 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
738 char fullpath
[LTTNG_PATH_MAX
];
740 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
746 ret
= run_as_mkdir_recursive(fullpath
, mode
, uid
, gid
);
752 int _lttng_directory_handle_rename(
753 const struct lttng_directory_handle
*old_handle
,
754 const char *old_name
,
755 const struct lttng_directory_handle
*new_handle
,
756 const char *new_name
)
759 char old_fullpath
[LTTNG_PATH_MAX
];
760 char new_fullpath
[LTTNG_PATH_MAX
];
762 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
763 sizeof(old_fullpath
));
768 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
769 sizeof(new_fullpath
));
775 ret
= rename(old_fullpath
, new_fullpath
);
781 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
782 const char *old_name
,
783 const struct lttng_directory_handle
*new_handle
,
784 const char *new_name
, uid_t uid
, gid_t gid
)
787 char old_fullpath
[LTTNG_PATH_MAX
];
788 char new_fullpath
[LTTNG_PATH_MAX
];
790 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
791 sizeof(old_fullpath
));
796 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
797 sizeof(new_fullpath
));
803 ret
= run_as_rename(old_fullpath
, new_fullpath
, uid
, gid
);
809 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
813 DIR *dir_stream
= NULL
;
814 char fullpath
[LTTNG_PATH_MAX
];
816 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
822 dir_stream
= opendir(fullpath
);
828 int lttng_directory_handle_rmdir(
829 const struct lttng_directory_handle
*handle
, const char *name
)
832 char fullpath
[LTTNG_PATH_MAX
];
834 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
840 ret
= rmdir(fullpath
);
846 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
847 const char *name
, uid_t uid
, gid_t gid
)
850 char fullpath
[LTTNG_PATH_MAX
];
852 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
858 ret
= run_as_rmdir(fullpath
, uid
, gid
);
864 int _run_as_rmdir_recursive(
865 const struct lttng_directory_handle
*handle
, const char *name
,
866 uid_t uid
, gid_t gid
, int flags
)
869 char fullpath
[LTTNG_PATH_MAX
];
871 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
877 ret
= run_as_rmdir_recursive(fullpath
, uid
, gid
, flags
);
882 #endif /* COMPAT_DIRFD */
884 /* Common implementation. */
887 * On some filesystems (e.g. nfs), mkdir will validate access rights before
888 * checking for the existence of the path element. This means that on a setup
889 * where "/home/" is a mounted NFS share, and running as an unpriviledged user,
890 * recursively creating a path of the form "/home/my_user/trace/" will fail with
891 * EACCES on mkdir("/home", ...).
893 * Checking the path for existence allows us to work around this behaviour.
896 int create_directory_check_exists(const struct lttng_directory_handle
*handle
,
897 const char *path
, mode_t mode
)
902 ret
= lttng_directory_handle_stat(handle
, path
, &st
);
904 if (S_ISDIR(st
.st_mode
)) {
905 /* Directory exists, skip. */
908 /* Exists, but is not a directory. */
913 } else if (errno
!= ENOENT
) {
918 * Let mkdir handle other errors as the caller expects mkdir
921 ret
= lttng_directory_handle_mkdir(handle
, path
, mode
);
927 int create_directory_recursive(const struct lttng_directory_handle
*handle
,
928 const char *path
, mode_t mode
)
930 char *p
, tmp
[LTTNG_PATH_MAX
];
936 ret
= lttng_strncpy(tmp
, path
, sizeof(tmp
));
938 ERR("Failed to create directory: provided path's length (%zu bytes) exceeds the maximal allowed length (%zu bytes)",
939 strlen(path
) + 1, sizeof(tmp
));
944 if (tmp
[len
- 1] == '/') {
948 for (p
= tmp
+ 1; *p
; p
++) {
951 if (tmp
[strlen(tmp
) - 1] == '.' &&
952 tmp
[strlen(tmp
) - 2] == '.' &&
953 tmp
[strlen(tmp
) - 3] == '/') {
954 ERR("Using '/../' is not permitted in the trace path (%s)",
959 ret
= create_directory_check_exists(handle
, tmp
, mode
);
961 if (errno
!= EACCES
) {
962 PERROR("Failed to create directory \"%s\"",
972 ret
= create_directory_check_exists(handle
, tmp
, mode
);
974 PERROR("mkdirat recursive last element");
982 bool lttng_directory_handle_get(struct lttng_directory_handle
*handle
)
984 return urcu_ref_get_unless_zero(&handle
->ref
);
988 void lttng_directory_handle_put(struct lttng_directory_handle
*handle
)
993 assert(handle
->ref
.refcount
);
994 urcu_ref_put(&handle
->ref
, lttng_directory_handle_release
);
998 int lttng_directory_handle_create_subdirectory_as_user(
999 const struct lttng_directory_handle
*handle
,
1000 const char *subdirectory
,
1001 mode_t mode
, const struct lttng_credentials
*creds
)
1006 /* Run as current user. */
1007 ret
= create_directory_check_exists(handle
,
1008 subdirectory
, mode
);
1010 ret
= _run_as_mkdir(handle
, subdirectory
,
1011 mode
, creds
->uid
, creds
->gid
);
1018 int lttng_directory_handle_create_subdirectory_recursive_as_user(
1019 const struct lttng_directory_handle
*handle
,
1020 const char *subdirectory_path
,
1021 mode_t mode
, const struct lttng_credentials
*creds
)
1026 /* Run as current user. */
1027 ret
= create_directory_recursive(handle
,
1028 subdirectory_path
, mode
);
1030 ret
= _run_as_mkdir_recursive(handle
, subdirectory_path
,
1031 mode
, creds
->uid
, creds
->gid
);
1038 int lttng_directory_handle_create_subdirectory(
1039 const struct lttng_directory_handle
*handle
,
1040 const char *subdirectory
,
1043 return lttng_directory_handle_create_subdirectory_as_user(
1044 handle
, subdirectory
, mode
, NULL
);
1048 int lttng_directory_handle_create_subdirectory_recursive(
1049 const struct lttng_directory_handle
*handle
,
1050 const char *subdirectory_path
,
1053 return lttng_directory_handle_create_subdirectory_recursive_as_user(
1054 handle
, subdirectory_path
, mode
, NULL
);
1058 int lttng_directory_handle_open_file_as_user(
1059 const struct lttng_directory_handle
*handle
,
1060 const char *filename
,
1061 int flags
, mode_t mode
,
1062 const struct lttng_credentials
*creds
)
1067 /* Run as current user. */
1068 ret
= lttng_directory_handle_open(handle
, filename
, flags
,
1071 ret
= _run_as_open(handle
, filename
, flags
, mode
,
1072 creds
->uid
, creds
->gid
);
1078 int lttng_directory_handle_open_file(
1079 const struct lttng_directory_handle
*handle
,
1080 const char *filename
,
1081 int flags
, mode_t mode
)
1083 return lttng_directory_handle_open_file_as_user(handle
, filename
, flags
,
1088 int lttng_directory_handle_unlink_file_as_user(
1089 const struct lttng_directory_handle
*handle
,
1090 const char *filename
,
1091 const struct lttng_credentials
*creds
)
1096 /* Run as current user. */
1097 ret
= lttng_directory_handle_unlink(handle
, filename
);
1099 ret
= _run_as_unlink(handle
, filename
, creds
->uid
, creds
->gid
);
1105 int lttng_directory_handle_unlink_file(
1106 const struct lttng_directory_handle
*handle
,
1107 const char *filename
)
1109 return lttng_directory_handle_unlink_file_as_user(handle
,
1114 int lttng_directory_handle_rename(
1115 const struct lttng_directory_handle
*old_handle
,
1116 const char *old_name
,
1117 const struct lttng_directory_handle
*new_handle
,
1118 const char *new_name
)
1120 return lttng_directory_handle_rename_as_user(old_handle
, old_name
,
1121 new_handle
, new_name
, NULL
);
1125 int lttng_directory_handle_rename_as_user(
1126 const struct lttng_directory_handle
*old_handle
,
1127 const char *old_name
,
1128 const struct lttng_directory_handle
*new_handle
,
1129 const char *new_name
,
1130 const struct lttng_credentials
*creds
)
1135 /* Run as current user. */
1136 ret
= _lttng_directory_handle_rename(old_handle
,
1137 old_name
, new_handle
, new_name
);
1139 ret
= _run_as_rename(old_handle
, old_name
, new_handle
,
1140 new_name
, creds
->uid
, creds
->gid
);
1146 int lttng_directory_handle_remove_subdirectory(
1147 const struct lttng_directory_handle
*handle
,
1150 return lttng_directory_handle_remove_subdirectory_as_user(handle
, name
,
1155 int lttng_directory_handle_remove_subdirectory_as_user(
1156 const struct lttng_directory_handle
*handle
,
1158 const struct lttng_credentials
*creds
)
1163 /* Run as current user. */
1164 ret
= lttng_directory_handle_rmdir(handle
, name
);
1166 ret
= _run_as_rmdir(handle
, name
, creds
->uid
, creds
->gid
);
1171 struct rmdir_frame
{
1172 ssize_t parent_frame_idx
;
1175 /* Size including '\0'. */
1180 void rmdir_frame_fini(void *data
)
1183 struct rmdir_frame
*frame
= data
;
1185 ret
= closedir(frame
->dir
);
1187 PERROR("Failed to close directory stream");
1192 int remove_directory_recursive(const struct lttng_directory_handle
*handle
,
1193 const char *path
, int flags
)
1196 struct lttng_dynamic_array frames
;
1197 size_t current_frame_idx
= 0;
1198 struct rmdir_frame initial_frame
= {
1199 .parent_frame_idx
= -1,
1200 .dir
= lttng_directory_handle_opendir(handle
, path
),
1202 .path_size
= strlen(path
) + 1,
1204 struct lttng_dynamic_buffer current_path
;
1205 const char separator
= '/';
1207 lttng_dynamic_buffer_init(¤t_path
);
1208 lttng_dynamic_array_init(&frames
, sizeof(struct rmdir_frame
),
1211 if (flags
& ~(LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
|
1212 LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG
)) {
1213 ERR("Unknown flags %d", flags
);
1218 if (!initial_frame
.dir
) {
1219 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
&&
1221 DBG("Cannot rmdir \"%s\": root does not exist", path
);
1225 PERROR("Failed to rmdir \"%s\"", path
);
1231 ret
= lttng_dynamic_array_add_element(&frames
, &initial_frame
);
1233 ERR("Failed to push context frame during recursive directory removal");
1234 rmdir_frame_fini(&initial_frame
);
1238 ret
= lttng_dynamic_buffer_append(
1239 ¤t_path
, path
, initial_frame
.path_size
);
1241 ERR("Failed to set initial path during recursive directory removal");
1246 while (lttng_dynamic_array_get_count(&frames
) > 0) {
1247 struct dirent
*entry
;
1248 struct rmdir_frame
*current_frame
=
1249 lttng_dynamic_array_get_element(
1250 &frames
, current_frame_idx
);
1252 assert(current_frame
->dir
);
1253 ret
= lttng_dynamic_buffer_set_size(
1254 ¤t_path
, current_frame
->path_size
);
1256 current_path
.data
[current_path
.size
- 1] = '\0';
1258 while ((entry
= readdir(current_frame
->dir
))) {
1261 if (!strcmp(entry
->d_name
, ".") ||
1262 !strcmp(entry
->d_name
, "..")) {
1266 /* Set current_path to the entry's path. */
1267 ret
= lttng_dynamic_buffer_set_size(
1268 ¤t_path
, current_path
.size
- 1);
1270 ret
= lttng_dynamic_buffer_append(¤t_path
,
1271 &separator
, sizeof(separator
));
1275 ret
= lttng_dynamic_buffer_append(¤t_path
,
1277 strlen(entry
->d_name
) + 1);
1282 if (lttng_directory_handle_stat(
1283 handle
, current_path
.data
, &st
)) {
1284 if ((flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
) &&
1288 PERROR("Failed to stat \"%s\"",
1294 if (!S_ISDIR(st
.st_mode
)) {
1295 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
) {
1296 current_frame
->empty
= false;
1299 /* Not empty, abort. */
1300 DBG("Directory \"%s\" is not empty; refusing to remove directory",
1306 struct rmdir_frame new_frame
= {
1307 .path_size
= current_path
.size
,
1308 .dir
= lttng_directory_handle_opendir(
1312 .parent_frame_idx
= current_frame_idx
,
1315 if (!new_frame
.dir
) {
1316 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
&&
1318 DBG("Non-existing directory stream during recursive directory removal");
1321 PERROR("Failed to open directory stream during recursive directory removal");
1326 ret
= lttng_dynamic_array_add_element(
1327 &frames
, &new_frame
);
1329 ERR("Failed to push context frame during recursive directory removal");
1330 rmdir_frame_fini(&new_frame
);
1333 current_frame_idx
++;
1334 /* We break iteration on readdir. */
1342 /* Pop rmdir frame. */
1343 if (current_frame
->empty
) {
1344 ret
= lttng_directory_handle_rmdir(
1345 handle
, current_path
.data
);
1347 if ((flags
& LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG
) ||
1349 PERROR("Failed to remove \"%s\" during recursive directory removal",
1353 DBG("Non-existing directory stream during recursive directory removal");
1355 } else if (current_frame
->parent_frame_idx
>= 0) {
1356 struct rmdir_frame
*parent_frame
;
1358 parent_frame
= lttng_dynamic_array_get_element(&frames
,
1359 current_frame
->parent_frame_idx
);
1360 assert(parent_frame
);
1361 parent_frame
->empty
= false;
1363 ret
= lttng_dynamic_array_remove_element(
1364 &frames
, current_frame_idx
);
1366 ERR("Failed to pop context frame during recursive directory removal");
1369 current_frame_idx
--;
1372 lttng_dynamic_array_reset(&frames
);
1373 lttng_dynamic_buffer_reset(¤t_path
);
1378 int lttng_directory_handle_remove_subdirectory_recursive(
1379 const struct lttng_directory_handle
*handle
,
1383 return lttng_directory_handle_remove_subdirectory_recursive_as_user(
1384 handle
, name
, NULL
, flags
);
1388 int lttng_directory_handle_remove_subdirectory_recursive_as_user(
1389 const struct lttng_directory_handle
*handle
,
1391 const struct lttng_credentials
*creds
,
1397 /* Run as current user. */
1398 ret
= remove_directory_recursive(handle
, name
, flags
);
1400 ret
= _run_as_rmdir_recursive(handle
, name
, creds
->uid
,