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_mkdir(
40 const struct lttng_directory_handle
*handle
,
41 const char *path
, mode_t mode
);
43 int _run_as_mkdir(const struct lttng_directory_handle
*handle
, const char *path
,
44 mode_t mode
, uid_t uid
, gid_t gid
);
46 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
47 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
);
49 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
50 const char *filename
, int flags
, mode_t mode
);
52 int _run_as_open(const struct lttng_directory_handle
*handle
,
54 int flags
, mode_t mode
, uid_t uid
, gid_t gid
);
56 int lttng_directory_handle_unlink(
57 const struct lttng_directory_handle
*handle
,
58 const char *filename
);
60 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
61 const char *filename
, uid_t uid
, gid_t gid
);
63 int _lttng_directory_handle_rename(
64 const struct lttng_directory_handle
*old_handle
,
66 const struct lttng_directory_handle
*new_handle
,
67 const char *new_name
);
69 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
71 const struct lttng_directory_handle
*new_handle
,
72 const char *new_name
, uid_t uid
, gid_t gid
);
74 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
77 int lttng_directory_handle_rmdir(
78 const struct lttng_directory_handle
*handle
, const char *name
);
80 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
81 const char *name
, uid_t uid
, gid_t gid
);
83 int _run_as_rmdir_recursive(
84 const struct lttng_directory_handle
*handle
, const char *name
,
85 uid_t uid
, gid_t gid
, int flags
);
87 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
);
89 void lttng_directory_handle_release(struct urcu_ref
*ref
);
94 * Special inode number reserved to represent the "current working directory".
95 * ino_t is spec'ed as being an unsigned integral type.
97 #define RESERVED_AT_FDCWD_INO \
99 uint64_t reserved_val; \
100 switch (sizeof(ino_t)) { \
102 reserved_val = UINT32_MAX; \
105 reserved_val = UINT64_MAX; \
110 (ino_t) reserved_val; \
114 struct lttng_directory_handle
*lttng_directory_handle_create(const char *path
)
116 const struct lttng_directory_handle cwd_handle
= {
120 /* Open a handle to the CWD if NULL is passed. */
121 return lttng_directory_handle_create_from_handle(path
, &cwd_handle
);
125 struct lttng_directory_handle
*lttng_directory_handle_create_from_handle(
127 const struct lttng_directory_handle
*ref_handle
)
130 struct lttng_directory_handle
*handle
= NULL
;
133 handle
= lttng_directory_handle_copy(ref_handle
);
137 ERR("Failed to initialize directory handle: provided path is an empty string");
141 dirfd
= openat(ref_handle
->dirfd
, path
, O_RDONLY
| O_DIRECTORY
| O_CLOEXEC
);
143 PERROR("Failed to initialize directory handle to \"%s\"", path
);
147 handle
= lttng_directory_handle_create_from_dirfd(dirfd
);
155 PERROR("Failed to close directory file descriptor");
161 struct lttng_directory_handle
*lttng_directory_handle_create_from_dirfd(
165 struct lttng_directory_handle
*handle
= zmalloc(sizeof(*handle
));
166 struct stat stat_buf
;
172 if (dirfd
!= AT_FDCWD
) {
173 ret
= fstat(dirfd
, &stat_buf
);
175 PERROR("Failed to fstat directory file descriptor %i", dirfd
);
176 lttng_directory_handle_release(&handle
->ref
);
179 handle
->directory_inode
= RESERVED_AT_FDCWD_INO
;
181 handle
->dirfd
= dirfd
;
182 urcu_ref_init(&handle
->ref
);
188 void lttng_directory_handle_release(struct urcu_ref
*ref
)
191 struct lttng_directory_handle
*handle
=
192 container_of(ref
, struct lttng_directory_handle
, ref
);
194 if (handle
->dirfd
== AT_FDCWD
|| handle
->dirfd
== -1) {
197 ret
= close(handle
->dirfd
);
199 PERROR("Failed to close directory file descriptor of directory handle");
202 lttng_directory_handle_invalidate(handle
);
207 struct lttng_directory_handle
*lttng_directory_handle_copy(
208 const struct lttng_directory_handle
*handle
)
210 struct lttng_directory_handle
*new_handle
= NULL
;
212 if (handle
->dirfd
== AT_FDCWD
) {
213 new_handle
= lttng_directory_handle_create_from_dirfd(AT_FDCWD
);
215 const int new_dirfd
= dup(handle
->dirfd
);
217 if (new_dirfd
== -1) {
218 PERROR("Failed to duplicate directory file descriptor of directory handle");
221 new_handle
= lttng_directory_handle_create_from_dirfd(
223 if (!new_handle
&& close(new_dirfd
)) {
224 PERROR("Failed to close directory file descriptor of directory handle");
232 bool lttng_directory_handle_equals(const struct lttng_directory_handle
*lhs
,
233 const struct lttng_directory_handle
*rhs
)
235 return lhs
->directory_inode
== rhs
->directory_inode
;
239 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
)
245 int lttng_directory_handle_stat(const struct lttng_directory_handle
*handle
,
246 const char *path
, struct stat
*st
)
248 return fstatat(handle
->dirfd
, path
, st
, 0);
252 int lttng_directory_handle_mkdir(
253 const struct lttng_directory_handle
*handle
,
254 const char *path
, mode_t mode
)
256 return mkdirat(handle
->dirfd
, path
, mode
);
260 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
261 const char *filename
, int flags
, mode_t mode
)
263 return openat(handle
->dirfd
, filename
, flags
, mode
);
267 int _run_as_open(const struct lttng_directory_handle
*handle
,
268 const char *filename
,
269 int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
271 return run_as_openat(handle
->dirfd
, filename
, flags
, mode
, uid
, gid
);
275 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
276 const char *filename
, uid_t uid
, gid_t gid
)
278 return run_as_unlinkat(handle
->dirfd
, filename
, uid
, gid
);
282 int lttng_directory_handle_unlink(
283 const struct lttng_directory_handle
*handle
,
284 const char *filename
)
286 return unlinkat(handle
->dirfd
, filename
, 0);
290 int _run_as_mkdir(const struct lttng_directory_handle
*handle
,
291 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
293 return run_as_mkdirat(handle
->dirfd
, path
, mode
, uid
, gid
);
297 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
298 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
300 return run_as_mkdirat_recursive(handle
->dirfd
, path
, mode
, uid
, gid
);
304 int _lttng_directory_handle_rename(
305 const struct lttng_directory_handle
*old_handle
,
306 const char *old_name
,
307 const struct lttng_directory_handle
*new_handle
,
308 const char *new_name
)
310 return renameat(old_handle
->dirfd
, old_name
,
311 new_handle
->dirfd
, new_name
);
315 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
316 const char *old_name
,
317 const struct lttng_directory_handle
*new_handle
,
318 const char *new_name
, uid_t uid
, gid_t gid
)
320 return run_as_renameat(old_handle
->dirfd
, old_name
, new_handle
->dirfd
,
325 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
328 DIR *dir_stream
= NULL
;
329 int fd
= openat(handle
->dirfd
, path
, O_RDONLY
);
335 dir_stream
= fdopendir(fd
);
339 PERROR("Failed to open directory stream");
342 PERROR("Failed to close file descriptor to %s", path
);
352 int lttng_directory_handle_rmdir(
353 const struct lttng_directory_handle
*handle
, const char *name
)
355 return unlinkat(handle
->dirfd
, name
, AT_REMOVEDIR
);
359 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
360 const char *name
, uid_t uid
, gid_t gid
)
362 return run_as_rmdirat(handle
->dirfd
, name
, uid
, gid
);
366 int _run_as_rmdir_recursive(
367 const struct lttng_directory_handle
*handle
, const char *name
,
368 uid_t uid
, gid_t gid
, int flags
)
370 return run_as_rmdirat_recursive(handle
->dirfd
, name
, uid
, gid
, flags
);
373 #else /* COMPAT_DIRFD */
376 int get_full_path(const struct lttng_directory_handle
*handle
,
377 const char *subdirectory
, char *fullpath
, size_t size
)
380 const bool subdirectory_is_absolute
=
381 subdirectory
&& *subdirectory
== '/';
382 const char * const base
= subdirectory_is_absolute
?
383 subdirectory
: handle
->base_path
;
384 const char * const end
= subdirectory
&& !subdirectory_is_absolute
?
386 const size_t base_len
= strlen(base
);
387 const size_t end_len
= end
? strlen(end
) : 0;
388 const bool add_separator_slash
= end
&& base
[base_len
- 1] != '/';
389 const bool add_trailing_slash
= end
&& end
[end_len
- 1] != '/';
391 ret
= snprintf(fullpath
, size
, "%s%s%s%s",
393 add_separator_slash
? "/" : "",
395 add_trailing_slash
? "/" : "");
396 if (ret
== -1 || ret
>= size
) {
397 ERR("Failed to format subdirectory from directory handle");
407 struct lttng_directory_handle
*_lttng_directory_handle_create(char *path
)
409 struct lttng_directory_handle
*handle
= zmalloc(sizeof(*handle
));
414 urcu_ref_init(&handle
->ref
);
415 handle
->base_path
= path
;
421 struct lttng_directory_handle
*lttng_directory_handle_create(
425 const char *cwd
= "";
426 size_t cwd_len
, path_len
;
427 char cwd_buf
[LTTNG_PATH_MAX
] = {};
428 char handle_buf
[LTTNG_PATH_MAX
] = {};
429 struct lttng_directory_handle
*new_handle
= NULL
;
430 bool add_cwd_slash
= false, add_trailing_slash
= false;
431 const struct lttng_directory_handle cwd_handle
= {
432 .base_path
= handle_buf
,
435 path_len
= path
? strlen(path
) : 0;
436 add_trailing_slash
= path
&& path
[path_len
- 1] != '/';
437 if (!path
|| (path
&& *path
!= '/')) {
438 cwd
= getcwd(cwd_buf
, sizeof(cwd_buf
));
440 PERROR("Failed to initialize directory handle, can't get current working directory");
444 cwd_len
= strlen(cwd
);
446 ERR("Failed to initialize directory handle, current working directory path has a length of 0");
450 add_cwd_slash
= cwd
[cwd_len
- 1] != '/';
453 ret
= snprintf(handle_buf
, sizeof(handle_buf
), "%s%s%s%s",
455 add_cwd_slash
? "/" : "",
457 add_trailing_slash
? "/" : "");
458 if (ret
== -1 || ret
>= LTTNG_PATH_MAX
) {
459 ERR("Failed to initialize directory handle, failed to format directory path");
463 new_handle
= lttng_directory_handle_create_from_handle(path
, &cwd_handle
);
469 struct lttng_directory_handle
*lttng_directory_handle_create_from_handle(
471 const struct lttng_directory_handle
*ref_handle
)
474 size_t path_len
, handle_path_len
;
475 bool add_trailing_slash
;
476 struct stat stat_buf
;
477 struct lttng_directory_handle
*new_handle
= NULL
;
478 char *new_path
= NULL
;
480 assert(ref_handle
&& ref_handle
->base_path
);
482 ret
= lttng_directory_handle_stat(ref_handle
, path
, &stat_buf
);
484 PERROR("Failed to create directory handle");
486 } else if (!S_ISDIR(stat_buf
.st_mode
)) {
487 char full_path
[LTTNG_PATH_MAX
];
489 /* Best effort for logging purposes. */
490 ret
= get_full_path(ref_handle
, path
, full_path
,
496 ERR("Failed to initialize directory handle to \"%s\": not a directory",
501 new_handle
= lttng_directory_handle_copy(ref_handle
);
505 path_len
= strlen(path
);
507 ERR("Failed to initialize directory handle: provided path is an empty string");
512 new_path
= strdup(path
);
516 /* Takes ownership of new_path. */
517 new_handle
= _lttng_directory_handle_create(new_path
);
522 add_trailing_slash
= path
[path_len
- 1] != '/';
524 handle_path_len
= strlen(ref_handle
->base_path
) + path_len
+
525 !!add_trailing_slash
;
526 if (handle_path_len
>= LTTNG_PATH_MAX
) {
527 ERR("Failed to initialize directory handle as the resulting path's length (%zu bytes) exceeds the maximal allowed length (%d bytes)",
528 handle_path_len
, LTTNG_PATH_MAX
);
531 new_path
= zmalloc(handle_path_len
);
533 PERROR("Failed to initialize directory handle");
537 ret
= sprintf(new_handle
->base_path
, "%s%s%s",
538 ref_handle
->base_path
,
540 add_trailing_slash
? "/" : "");
541 if (ret
== -1 || ret
>= handle_path_len
) {
542 ERR("Failed to initialize directory handle: path formatting failed");
545 new_handle
= _lttng_directory_handle_create(new_path
);
553 struct lttng_directory_handle
*lttng_directory_handle_create_from_dirfd(
556 assert(dirfd
== AT_FDCWD
);
557 return lttng_directory_handle_create(NULL
);
561 void lttng_directory_handle_release(struct urcu_ref
*ref
)
563 struct lttng_directory_handle
*handle
=
564 container_of(ref
, struct lttng_directory_handle
, ref
);
566 free(handle
->base_path
);
567 lttng_directory_handle_invalidate(handle
);
572 struct lttng_directory_handle
*lttng_directory_handle_copy(
573 const struct lttng_directory_handle
*handle
)
575 struct lttng_directory_handle
*new_handle
= NULL
;
576 char *new_path
= NULL
;
578 if (handle
->base_path
) {
579 new_path
= strdup(handle
->base_path
);
584 new_handle
= _lttng_directory_handle_create(new_path
);
590 bool lttng_directory_handle_equals(const struct lttng_directory_handle
*lhs
,
591 const struct lttng_directory_handle
*rhs
)
593 return strcmp(lhs
->path
, rhs
->path
) == 0;
597 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
)
599 handle
->base_path
= NULL
;
603 int lttng_directory_handle_stat(const struct lttng_directory_handle
*handle
,
604 const char *subdirectory
, struct stat
*st
)
607 char fullpath
[LTTNG_PATH_MAX
];
609 ret
= get_full_path(handle
, subdirectory
, fullpath
, sizeof(fullpath
));
615 ret
= stat(fullpath
, st
);
621 int lttng_directory_handle_mkdir(const struct lttng_directory_handle
*handle
,
622 const char *subdirectory
, mode_t mode
)
625 char fullpath
[LTTNG_PATH_MAX
];
627 ret
= get_full_path(handle
, subdirectory
, fullpath
, sizeof(fullpath
));
633 ret
= mkdir(fullpath
, mode
);
639 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
640 const char *filename
, int flags
, mode_t mode
)
643 char fullpath
[LTTNG_PATH_MAX
];
645 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
651 ret
= open(fullpath
, flags
, mode
);
657 int lttng_directory_handle_unlink(
658 const struct lttng_directory_handle
*handle
,
659 const char *filename
)
662 char fullpath
[LTTNG_PATH_MAX
];
664 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
670 ret
= unlink(fullpath
);
676 int _run_as_mkdir(const struct lttng_directory_handle
*handle
, const char *path
,
677 mode_t mode
, uid_t uid
, gid_t gid
)
680 char fullpath
[LTTNG_PATH_MAX
];
682 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
688 ret
= run_as_mkdir(fullpath
, mode
, uid
, gid
);
694 int _run_as_open(const struct lttng_directory_handle
*handle
,
695 const char *filename
,
696 int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
699 char fullpath
[LTTNG_PATH_MAX
];
701 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
707 ret
= run_as_open(fullpath
, flags
, mode
, uid
, gid
);
713 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
714 const char *filename
, uid_t uid
, gid_t gid
)
717 char fullpath
[LTTNG_PATH_MAX
];
719 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
725 ret
= run_as_unlink(fullpath
, uid
, gid
);
731 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
732 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
735 char fullpath
[LTTNG_PATH_MAX
];
737 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
743 ret
= run_as_mkdir_recursive(fullpath
, mode
, uid
, gid
);
749 int _lttng_directory_handle_rename(
750 const struct lttng_directory_handle
*old_handle
,
751 const char *old_name
,
752 const struct lttng_directory_handle
*new_handle
,
753 const char *new_name
)
756 char old_fullpath
[LTTNG_PATH_MAX
];
757 char new_fullpath
[LTTNG_PATH_MAX
];
759 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
760 sizeof(old_fullpath
));
765 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
766 sizeof(new_fullpath
));
772 ret
= rename(old_fullpath
, new_fullpath
);
778 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
779 const char *old_name
,
780 const struct lttng_directory_handle
*new_handle
,
781 const char *new_name
, uid_t uid
, gid_t gid
)
784 char old_fullpath
[LTTNG_PATH_MAX
];
785 char new_fullpath
[LTTNG_PATH_MAX
];
787 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
788 sizeof(old_fullpath
));
793 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
794 sizeof(new_fullpath
));
800 ret
= run_as_rename(old_fullpath
, new_fullpath
, uid
, gid
);
806 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
810 DIR *dir_stream
= NULL
;
811 char fullpath
[LTTNG_PATH_MAX
];
813 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
819 dir_stream
= opendir(fullpath
);
825 int lttng_directory_handle_rmdir(
826 const struct lttng_directory_handle
*handle
, const char *name
)
829 char fullpath
[LTTNG_PATH_MAX
];
831 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
837 ret
= rmdir(fullpath
);
843 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
844 const char *name
, uid_t uid
, gid_t gid
)
847 char fullpath
[LTTNG_PATH_MAX
];
849 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
855 ret
= run_as_rmdir(fullpath
, uid
, gid
);
861 int _run_as_rmdir_recursive(
862 const struct lttng_directory_handle
*handle
, const char *name
,
863 uid_t uid
, gid_t gid
, int flags
)
866 char fullpath
[LTTNG_PATH_MAX
];
868 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
874 ret
= run_as_rmdir_recursive(fullpath
, uid
, gid
, flags
);
879 #endif /* COMPAT_DIRFD */
881 /* Common implementation. */
884 * On some filesystems (e.g. nfs), mkdir will validate access rights before
885 * checking for the existence of the path element. This means that on a setup
886 * where "/home/" is a mounted NFS share, and running as an unpriviledged user,
887 * recursively creating a path of the form "/home/my_user/trace/" will fail with
888 * EACCES on mkdir("/home", ...).
890 * Checking the path for existence allows us to work around this behaviour.
893 int create_directory_check_exists(const struct lttng_directory_handle
*handle
,
894 const char *path
, mode_t mode
)
899 ret
= lttng_directory_handle_stat(handle
, path
, &st
);
901 if (S_ISDIR(st
.st_mode
)) {
902 /* Directory exists, skip. */
905 /* Exists, but is not a directory. */
910 } else if (errno
!= ENOENT
) {
915 * Let mkdir handle other errors as the caller expects mkdir
918 ret
= lttng_directory_handle_mkdir(handle
, path
, mode
);
924 int create_directory_recursive(const struct lttng_directory_handle
*handle
,
925 const char *path
, mode_t mode
)
927 char *p
, tmp
[LTTNG_PATH_MAX
];
933 ret
= lttng_strncpy(tmp
, path
, sizeof(tmp
));
935 ERR("Failed to create directory: provided path's length (%zu bytes) exceeds the maximal allowed length (%zu bytes)",
936 strlen(path
) + 1, sizeof(tmp
));
941 if (tmp
[len
- 1] == '/') {
945 for (p
= tmp
+ 1; *p
; p
++) {
948 if (tmp
[strlen(tmp
) - 1] == '.' &&
949 tmp
[strlen(tmp
) - 2] == '.' &&
950 tmp
[strlen(tmp
) - 3] == '/') {
951 ERR("Using '/../' is not permitted in the trace path (%s)",
956 ret
= create_directory_check_exists(handle
, tmp
, mode
);
958 if (errno
!= EACCES
) {
959 PERROR("Failed to create directory \"%s\"",
969 ret
= create_directory_check_exists(handle
, tmp
, mode
);
971 PERROR("mkdirat recursive last element");
979 bool lttng_directory_handle_get(struct lttng_directory_handle
*handle
)
981 return urcu_ref_get_unless_zero(&handle
->ref
);
985 void lttng_directory_handle_put(struct lttng_directory_handle
*handle
)
990 assert(handle
->ref
.refcount
);
991 urcu_ref_put(&handle
->ref
, lttng_directory_handle_release
);
995 int lttng_directory_handle_create_subdirectory_as_user(
996 const struct lttng_directory_handle
*handle
,
997 const char *subdirectory
,
998 mode_t mode
, const struct lttng_credentials
*creds
)
1003 /* Run as current user. */
1004 ret
= create_directory_check_exists(handle
,
1005 subdirectory
, mode
);
1007 ret
= _run_as_mkdir(handle
, subdirectory
,
1008 mode
, creds
->uid
, creds
->gid
);
1015 int lttng_directory_handle_create_subdirectory_recursive_as_user(
1016 const struct lttng_directory_handle
*handle
,
1017 const char *subdirectory_path
,
1018 mode_t mode
, const struct lttng_credentials
*creds
)
1023 /* Run as current user. */
1024 ret
= create_directory_recursive(handle
,
1025 subdirectory_path
, mode
);
1027 ret
= _run_as_mkdir_recursive(handle
, subdirectory_path
,
1028 mode
, creds
->uid
, creds
->gid
);
1035 int lttng_directory_handle_create_subdirectory(
1036 const struct lttng_directory_handle
*handle
,
1037 const char *subdirectory
,
1040 return lttng_directory_handle_create_subdirectory_as_user(
1041 handle
, subdirectory
, mode
, NULL
);
1045 int lttng_directory_handle_create_subdirectory_recursive(
1046 const struct lttng_directory_handle
*handle
,
1047 const char *subdirectory_path
,
1050 return lttng_directory_handle_create_subdirectory_recursive_as_user(
1051 handle
, subdirectory_path
, mode
, NULL
);
1055 int lttng_directory_handle_open_file_as_user(
1056 const struct lttng_directory_handle
*handle
,
1057 const char *filename
,
1058 int flags
, mode_t mode
,
1059 const struct lttng_credentials
*creds
)
1064 /* Run as current user. */
1065 ret
= lttng_directory_handle_open(handle
, filename
, flags
,
1068 ret
= _run_as_open(handle
, filename
, flags
, mode
,
1069 creds
->uid
, creds
->gid
);
1075 int lttng_directory_handle_open_file(
1076 const struct lttng_directory_handle
*handle
,
1077 const char *filename
,
1078 int flags
, mode_t mode
)
1080 return lttng_directory_handle_open_file_as_user(handle
, filename
, flags
,
1085 int lttng_directory_handle_unlink_file_as_user(
1086 const struct lttng_directory_handle
*handle
,
1087 const char *filename
,
1088 const struct lttng_credentials
*creds
)
1093 /* Run as current user. */
1094 ret
= lttng_directory_handle_unlink(handle
, filename
);
1096 ret
= _run_as_unlink(handle
, filename
, creds
->uid
, creds
->gid
);
1102 int lttng_directory_handle_unlink_file(
1103 const struct lttng_directory_handle
*handle
,
1104 const char *filename
)
1106 return lttng_directory_handle_unlink_file_as_user(handle
,
1111 int lttng_directory_handle_rename(
1112 const struct lttng_directory_handle
*old_handle
,
1113 const char *old_name
,
1114 const struct lttng_directory_handle
*new_handle
,
1115 const char *new_name
)
1117 return lttng_directory_handle_rename_as_user(old_handle
, old_name
,
1118 new_handle
, new_name
, NULL
);
1122 int lttng_directory_handle_rename_as_user(
1123 const struct lttng_directory_handle
*old_handle
,
1124 const char *old_name
,
1125 const struct lttng_directory_handle
*new_handle
,
1126 const char *new_name
,
1127 const struct lttng_credentials
*creds
)
1132 /* Run as current user. */
1133 ret
= _lttng_directory_handle_rename(old_handle
,
1134 old_name
, new_handle
, new_name
);
1136 ret
= _run_as_rename(old_handle
, old_name
, new_handle
,
1137 new_name
, creds
->uid
, creds
->gid
);
1143 int lttng_directory_handle_remove_subdirectory(
1144 const struct lttng_directory_handle
*handle
,
1147 return lttng_directory_handle_remove_subdirectory_as_user(handle
, name
,
1152 int lttng_directory_handle_remove_subdirectory_as_user(
1153 const struct lttng_directory_handle
*handle
,
1155 const struct lttng_credentials
*creds
)
1160 /* Run as current user. */
1161 ret
= lttng_directory_handle_rmdir(handle
, name
);
1163 ret
= _run_as_rmdir(handle
, name
, creds
->uid
, creds
->gid
);
1168 struct rmdir_frame
{
1169 ssize_t parent_frame_idx
;
1172 /* Size including '\0'. */
1177 void rmdir_frame_fini(void *data
)
1180 struct rmdir_frame
*frame
= data
;
1182 ret
= closedir(frame
->dir
);
1184 PERROR("Failed to close directory stream");
1189 int remove_directory_recursive(const struct lttng_directory_handle
*handle
,
1190 const char *path
, int flags
)
1193 struct lttng_dynamic_array frames
;
1194 size_t current_frame_idx
= 0;
1195 struct rmdir_frame initial_frame
= {
1196 .parent_frame_idx
= -1,
1197 .dir
= lttng_directory_handle_opendir(handle
, path
),
1199 .path_size
= strlen(path
) + 1,
1201 struct lttng_dynamic_buffer current_path
;
1202 const char separator
= '/';
1204 lttng_dynamic_buffer_init(¤t_path
);
1205 lttng_dynamic_array_init(&frames
, sizeof(struct rmdir_frame
),
1208 if (flags
& ~(LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
|
1209 LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG
)) {
1210 ERR("Unknown flags %d", flags
);
1215 if (!initial_frame
.dir
) {
1216 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
&&
1218 DBG("Cannot rmdir \"%s\": root does not exist", path
);
1222 PERROR("Failed to rmdir \"%s\"", path
);
1228 ret
= lttng_dynamic_array_add_element(&frames
, &initial_frame
);
1230 ERR("Failed to push context frame during recursive directory removal");
1231 rmdir_frame_fini(&initial_frame
);
1235 ret
= lttng_dynamic_buffer_append(
1236 ¤t_path
, path
, initial_frame
.path_size
);
1238 ERR("Failed to set initial path during recursive directory removal");
1243 while (lttng_dynamic_array_get_count(&frames
) > 0) {
1244 struct dirent
*entry
;
1245 struct rmdir_frame
*current_frame
=
1246 lttng_dynamic_array_get_element(
1247 &frames
, current_frame_idx
);
1249 assert(current_frame
->dir
);
1250 ret
= lttng_dynamic_buffer_set_size(
1251 ¤t_path
, current_frame
->path_size
);
1253 current_path
.data
[current_path
.size
- 1] = '\0';
1255 while ((entry
= readdir(current_frame
->dir
))) {
1258 if (!strcmp(entry
->d_name
, ".") ||
1259 !strcmp(entry
->d_name
, "..")) {
1263 /* Set current_path to the entry's path. */
1264 ret
= lttng_dynamic_buffer_set_size(
1265 ¤t_path
, current_path
.size
- 1);
1267 ret
= lttng_dynamic_buffer_append(¤t_path
,
1268 &separator
, sizeof(separator
));
1272 ret
= lttng_dynamic_buffer_append(¤t_path
,
1274 strlen(entry
->d_name
) + 1);
1279 if (lttng_directory_handle_stat(
1280 handle
, current_path
.data
, &st
)) {
1281 if ((flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
) &&
1285 PERROR("Failed to stat \"%s\"",
1291 if (!S_ISDIR(st
.st_mode
)) {
1292 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
) {
1293 current_frame
->empty
= false;
1296 /* Not empty, abort. */
1297 DBG("Directory \"%s\" is not empty; refusing to remove directory",
1303 struct rmdir_frame new_frame
= {
1304 .path_size
= current_path
.size
,
1305 .dir
= lttng_directory_handle_opendir(
1309 .parent_frame_idx
= current_frame_idx
,
1312 if (!new_frame
.dir
) {
1313 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
&&
1315 DBG("Non-existing directory stream during recursive directory removal");
1318 PERROR("Failed to open directory stream during recursive directory removal");
1323 ret
= lttng_dynamic_array_add_element(
1324 &frames
, &new_frame
);
1326 ERR("Failed to push context frame during recursive directory removal");
1327 rmdir_frame_fini(&new_frame
);
1330 current_frame_idx
++;
1331 /* We break iteration on readdir. */
1339 /* Pop rmdir frame. */
1340 if (current_frame
->empty
) {
1341 ret
= lttng_directory_handle_rmdir(
1342 handle
, current_path
.data
);
1344 if ((flags
& LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG
) ||
1346 PERROR("Failed to remove \"%s\" during recursive directory removal",
1350 DBG("Non-existing directory stream during recursive directory removal");
1352 } else if (current_frame
->parent_frame_idx
>= 0) {
1353 struct rmdir_frame
*parent_frame
;
1355 parent_frame
= lttng_dynamic_array_get_element(&frames
,
1356 current_frame
->parent_frame_idx
);
1357 assert(parent_frame
);
1358 parent_frame
->empty
= false;
1360 ret
= lttng_dynamic_array_remove_element(
1361 &frames
, current_frame_idx
);
1363 ERR("Failed to pop context frame during recursive directory removal");
1366 current_frame_idx
--;
1369 lttng_dynamic_array_reset(&frames
);
1370 lttng_dynamic_buffer_reset(¤t_path
);
1375 int lttng_directory_handle_remove_subdirectory_recursive(
1376 const struct lttng_directory_handle
*handle
,
1380 return lttng_directory_handle_remove_subdirectory_recursive_as_user(
1381 handle
, name
, NULL
, flags
);
1385 int lttng_directory_handle_remove_subdirectory_recursive_as_user(
1386 const struct lttng_directory_handle
*handle
,
1388 const struct lttng_credentials
*creds
,
1394 /* Run as current user. */
1395 ret
= remove_directory_recursive(handle
, name
, flags
);
1397 ret
= _run_as_rmdir_recursive(handle
, name
, creds
->uid
,