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 struct lttng_directory_handle
*lttng_directory_handle_create(const char *path
)
99 const struct lttng_directory_handle cwd_handle
= {
103 /* Open a handle to the CWD if NULL is passed. */
104 return lttng_directory_handle_create_from_handle(path
, &cwd_handle
);
108 struct lttng_directory_handle
*lttng_directory_handle_create_from_handle(
110 const struct lttng_directory_handle
*ref_handle
)
113 struct lttng_directory_handle
*handle
= NULL
;
116 handle
= lttng_directory_handle_copy(ref_handle
);
120 ERR("Failed to initialize directory handle: provided path is an empty string");
124 dirfd
= openat(ref_handle
->dirfd
, path
, O_RDONLY
| O_DIRECTORY
| O_CLOEXEC
);
126 PERROR("Failed to initialize directory handle to \"%s\"", path
);
130 handle
= lttng_directory_handle_create_from_dirfd(dirfd
);
138 PERROR("Failed to close directory file descriptor");
144 struct lttng_directory_handle
*lttng_directory_handle_create_from_dirfd(
147 struct lttng_directory_handle
*handle
= zmalloc(sizeof(*handle
));
152 handle
->dirfd
= dirfd
;
153 urcu_ref_init(&handle
->ref
);
159 void lttng_directory_handle_release(struct urcu_ref
*ref
)
162 struct lttng_directory_handle
*handle
=
163 container_of(ref
, struct lttng_directory_handle
, ref
);
165 if (handle
->dirfd
== AT_FDCWD
|| handle
->dirfd
== -1) {
168 ret
= close(handle
->dirfd
);
170 PERROR("Failed to close directory file descriptor of directory handle");
173 lttng_directory_handle_invalidate(handle
);
178 struct lttng_directory_handle
*lttng_directory_handle_copy(
179 const struct lttng_directory_handle
*handle
)
181 struct lttng_directory_handle
*new_handle
= NULL
;
183 if (handle
->dirfd
== AT_FDCWD
) {
184 new_handle
= lttng_directory_handle_create_from_dirfd(AT_FDCWD
);
186 const int new_dirfd
= dup(handle
->dirfd
);
188 if (new_dirfd
== -1) {
189 PERROR("Failed to duplicate directory file descriptor of directory handle");
192 new_handle
= lttng_directory_handle_create_from_dirfd(
194 if (!new_handle
&& close(new_dirfd
)) {
195 PERROR("Failed to close directory file descriptor of directory handle");
203 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
)
209 int lttng_directory_handle_stat(const struct lttng_directory_handle
*handle
,
210 const char *path
, struct stat
*st
)
212 return fstatat(handle
->dirfd
, path
, st
, 0);
216 int lttng_directory_handle_mkdir(
217 const struct lttng_directory_handle
*handle
,
218 const char *path
, mode_t mode
)
220 return mkdirat(handle
->dirfd
, path
, mode
);
224 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
225 const char *filename
, int flags
, mode_t mode
)
227 return openat(handle
->dirfd
, filename
, flags
, mode
);
231 int _run_as_open(const struct lttng_directory_handle
*handle
,
232 const char *filename
,
233 int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
235 return run_as_openat(handle
->dirfd
, filename
, flags
, mode
, uid
, gid
);
239 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
240 const char *filename
, uid_t uid
, gid_t gid
)
242 return run_as_unlinkat(handle
->dirfd
, filename
, uid
, gid
);
246 int lttng_directory_handle_unlink(
247 const struct lttng_directory_handle
*handle
,
248 const char *filename
)
250 return unlinkat(handle
->dirfd
, filename
, 0);
254 int _run_as_mkdir(const struct lttng_directory_handle
*handle
,
255 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
257 return run_as_mkdirat(handle
->dirfd
, path
, mode
, uid
, gid
);
261 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
262 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
264 return run_as_mkdirat_recursive(handle
->dirfd
, path
, mode
, uid
, gid
);
268 int _lttng_directory_handle_rename(
269 const struct lttng_directory_handle
*old_handle
,
270 const char *old_name
,
271 const struct lttng_directory_handle
*new_handle
,
272 const char *new_name
)
274 return renameat(old_handle
->dirfd
, old_name
,
275 new_handle
->dirfd
, new_name
);
279 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
280 const char *old_name
,
281 const struct lttng_directory_handle
*new_handle
,
282 const char *new_name
, uid_t uid
, gid_t gid
)
284 return run_as_renameat(old_handle
->dirfd
, old_name
, new_handle
->dirfd
,
289 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
292 DIR *dir_stream
= NULL
;
293 int fd
= openat(handle
->dirfd
, path
, O_RDONLY
);
299 dir_stream
= fdopendir(fd
);
303 PERROR("Failed to open directory stream");
306 PERROR("Failed to close file descriptor to %s", path
);
316 int lttng_directory_handle_rmdir(
317 const struct lttng_directory_handle
*handle
, const char *name
)
319 return unlinkat(handle
->dirfd
, name
, AT_REMOVEDIR
);
323 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
324 const char *name
, uid_t uid
, gid_t gid
)
326 return run_as_rmdirat(handle
->dirfd
, name
, uid
, gid
);
330 int _run_as_rmdir_recursive(
331 const struct lttng_directory_handle
*handle
, const char *name
,
332 uid_t uid
, gid_t gid
, int flags
)
334 return run_as_rmdirat_recursive(handle
->dirfd
, name
, uid
, gid
, flags
);
337 #else /* COMPAT_DIRFD */
340 int get_full_path(const struct lttng_directory_handle
*handle
,
341 const char *subdirectory
, char *fullpath
, size_t size
)
344 const bool subdirectory_is_absolute
=
345 subdirectory
&& *subdirectory
== '/';
346 const char * const base
= subdirectory_is_absolute
?
347 subdirectory
: handle
->base_path
;
348 const char * const end
= subdirectory
&& !subdirectory_is_absolute
?
350 const size_t base_len
= strlen(base
);
351 const size_t end_len
= end
? strlen(end
) : 0;
352 const bool add_separator_slash
= end
&& base
[base_len
- 1] != '/';
353 const bool add_trailing_slash
= end
&& end
[end_len
- 1] != '/';
355 ret
= snprintf(fullpath
, size
, "%s%s%s%s",
357 add_separator_slash
? "/" : "",
359 add_trailing_slash
? "/" : "");
360 if (ret
== -1 || ret
>= size
) {
361 ERR("Failed to format subdirectory from directory handle");
371 struct lttng_directory_handle
*_lttng_directory_handle_create(char *path
)
373 struct lttng_directory_handle
*handle
= zmalloc(sizeof(*handle
));
378 urcu_ref_init(&handle
->ref
);
379 handle
->base_path
= path
;
385 struct lttng_directory_handle
*lttng_directory_handle_create(
389 const char *cwd
= "";
390 size_t cwd_len
, path_len
;
391 char cwd_buf
[LTTNG_PATH_MAX
] = {};
392 char handle_buf
[LTTNG_PATH_MAX
] = {};
393 struct lttng_directory_handle
*new_handle
= NULL
;
394 bool add_cwd_slash
= false, add_trailing_slash
= false;
395 const struct lttng_directory_handle cwd_handle
= {
396 .base_path
= handle_buf
,
399 path_len
= path
? strlen(path
) : 0;
400 add_trailing_slash
= path
&& path
[path_len
- 1] != '/';
401 if (!path
|| (path
&& *path
!= '/')) {
402 cwd
= getcwd(cwd_buf
, sizeof(cwd_buf
));
404 PERROR("Failed to initialize directory handle, can't get current working directory");
408 cwd_len
= strlen(cwd
);
410 ERR("Failed to initialize directory handle, current working directory path has a length of 0");
414 add_cwd_slash
= cwd
[cwd_len
- 1] != '/';
417 ret
= snprintf(handle_buf
, sizeof(handle_buf
), "%s%s%s%s",
419 add_cwd_slash
? "/" : "",
421 add_trailing_slash
? "/" : "");
422 if (ret
== -1 || ret
>= LTTNG_PATH_MAX
) {
423 ERR("Failed to initialize directory handle, failed to format directory path");
427 new_handle
= lttng_directory_handle_create_from_handle(path
, &cwd_handle
);
433 struct lttng_directory_handle
*lttng_directory_handle_create_from_handle(
435 const struct lttng_directory_handle
*ref_handle
)
438 size_t path_len
, handle_path_len
;
439 bool add_trailing_slash
;
440 struct stat stat_buf
;
441 struct lttng_directory_handle
*new_handle
= NULL
;
442 char *new_path
= NULL
;
444 assert(ref_handle
&& ref_handle
->base_path
);
446 ret
= lttng_directory_handle_stat(ref_handle
, path
, &stat_buf
);
448 PERROR("Failed to create directory handle");
450 } else if (!S_ISDIR(stat_buf
.st_mode
)) {
451 char full_path
[LTTNG_PATH_MAX
];
453 /* Best effort for logging purposes. */
454 ret
= get_full_path(ref_handle
, path
, full_path
,
460 ERR("Failed to initialize directory handle to \"%s\": not a directory",
465 new_handle
= lttng_directory_handle_copy(ref_handle
);
469 path_len
= strlen(path
);
471 ERR("Failed to initialize directory handle: provided path is an empty string");
476 new_path
= strdup(path
);
480 /* Takes ownership of new_path. */
481 new_handle
= _lttng_directory_handle_create(new_path
);
486 add_trailing_slash
= path
[path_len
- 1] != '/';
488 handle_path_len
= strlen(ref_handle
->base_path
) + path_len
+
489 !!add_trailing_slash
;
490 if (handle_path_len
>= LTTNG_PATH_MAX
) {
491 ERR("Failed to initialize directory handle as the resulting path's length (%zu bytes) exceeds the maximal allowed length (%d bytes)",
492 handle_path_len
, LTTNG_PATH_MAX
);
495 new_path
= zmalloc(handle_path_len
);
497 PERROR("Failed to initialize directory handle");
501 ret
= sprintf(new_handle
->base_path
, "%s%s%s",
502 ref_handle
->base_path
,
504 add_trailing_slash
? "/" : "");
505 if (ret
== -1 || ret
>= handle_path_len
) {
506 ERR("Failed to initialize directory handle: path formatting failed");
509 new_handle
= _lttng_directory_handle_create(new_path
);
517 struct lttng_directory_handle
*lttng_directory_handle_create_from_dirfd(
520 assert(dirfd
== AT_FDCWD
);
521 return lttng_directory_handle_create(NULL
);
525 void lttng_directory_handle_release(struct urcu_ref
*ref
)
527 struct lttng_directory_handle
*handle
=
528 container_of(ref
, struct lttng_directory_handle
, ref
);
530 free(handle
->base_path
);
531 lttng_directory_handle_invalidate(handle
);
536 struct lttng_directory_handle
*lttng_directory_handle_copy(
537 const struct lttng_directory_handle
*handle
)
539 struct lttng_directory_handle
*new_handle
= NULL
;
540 char *new_path
= NULL
;
542 if (handle
->base_path
) {
543 new_path
= strdup(handle
->base_path
);
548 new_handle
= _lttng_directory_handle_create(new_path
);
554 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
)
556 handle
->base_path
= NULL
;
560 int lttng_directory_handle_stat(const struct lttng_directory_handle
*handle
,
561 const char *subdirectory
, struct stat
*st
)
564 char fullpath
[LTTNG_PATH_MAX
];
566 ret
= get_full_path(handle
, subdirectory
, fullpath
, sizeof(fullpath
));
572 ret
= stat(fullpath
, st
);
578 int lttng_directory_handle_mkdir(const struct lttng_directory_handle
*handle
,
579 const char *subdirectory
, mode_t mode
)
582 char fullpath
[LTTNG_PATH_MAX
];
584 ret
= get_full_path(handle
, subdirectory
, fullpath
, sizeof(fullpath
));
590 ret
= mkdir(fullpath
, mode
);
596 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
597 const char *filename
, int flags
, mode_t mode
)
600 char fullpath
[LTTNG_PATH_MAX
];
602 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
608 ret
= open(fullpath
, flags
, mode
);
614 int lttng_directory_handle_unlink(
615 const struct lttng_directory_handle
*handle
,
616 const char *filename
)
619 char fullpath
[LTTNG_PATH_MAX
];
621 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
627 ret
= unlink(fullpath
);
633 int _run_as_mkdir(const struct lttng_directory_handle
*handle
, const char *path
,
634 mode_t mode
, uid_t uid
, gid_t gid
)
637 char fullpath
[LTTNG_PATH_MAX
];
639 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
645 ret
= run_as_mkdir(fullpath
, mode
, uid
, gid
);
651 int _run_as_open(const struct lttng_directory_handle
*handle
,
652 const char *filename
,
653 int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
656 char fullpath
[LTTNG_PATH_MAX
];
658 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
664 ret
= run_as_open(fullpath
, flags
, mode
, uid
, gid
);
670 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
671 const char *filename
, uid_t uid
, gid_t gid
)
674 char fullpath
[LTTNG_PATH_MAX
];
676 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
682 ret
= run_as_unlink(fullpath
, uid
, gid
);
688 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
689 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
692 char fullpath
[LTTNG_PATH_MAX
];
694 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
700 ret
= run_as_mkdir_recursive(fullpath
, mode
, uid
, gid
);
706 int _lttng_directory_handle_rename(
707 const struct lttng_directory_handle
*old_handle
,
708 const char *old_name
,
709 const struct lttng_directory_handle
*new_handle
,
710 const char *new_name
)
713 char old_fullpath
[LTTNG_PATH_MAX
];
714 char new_fullpath
[LTTNG_PATH_MAX
];
716 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
717 sizeof(old_fullpath
));
722 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
723 sizeof(new_fullpath
));
729 ret
= rename(old_fullpath
, new_fullpath
);
735 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
736 const char *old_name
,
737 const struct lttng_directory_handle
*new_handle
,
738 const char *new_name
, uid_t uid
, gid_t gid
)
741 char old_fullpath
[LTTNG_PATH_MAX
];
742 char new_fullpath
[LTTNG_PATH_MAX
];
744 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
745 sizeof(old_fullpath
));
750 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
751 sizeof(new_fullpath
));
757 ret
= run_as_rename(old_fullpath
, new_fullpath
, uid
, gid
);
763 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
767 DIR *dir_stream
= NULL
;
768 char fullpath
[LTTNG_PATH_MAX
];
770 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
776 dir_stream
= opendir(fullpath
);
782 int lttng_directory_handle_rmdir(
783 const struct lttng_directory_handle
*handle
, const char *name
)
786 char fullpath
[LTTNG_PATH_MAX
];
788 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
794 ret
= rmdir(fullpath
);
800 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
801 const char *name
, uid_t uid
, gid_t gid
)
804 char fullpath
[LTTNG_PATH_MAX
];
806 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
812 ret
= run_as_rmdir(fullpath
, uid
, gid
);
818 int _run_as_rmdir_recursive(
819 const struct lttng_directory_handle
*handle
, const char *name
,
820 uid_t uid
, gid_t gid
, int flags
)
823 char fullpath
[LTTNG_PATH_MAX
];
825 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
831 ret
= run_as_rmdir_recursive(fullpath
, uid
, gid
, flags
);
836 #endif /* COMPAT_DIRFD */
838 /* Common implementation. */
841 * On some filesystems (e.g. nfs), mkdir will validate access rights before
842 * checking for the existence of the path element. This means that on a setup
843 * where "/home/" is a mounted NFS share, and running as an unpriviledged user,
844 * recursively creating a path of the form "/home/my_user/trace/" will fail with
845 * EACCES on mkdir("/home", ...).
847 * Checking the path for existence allows us to work around this behaviour.
850 int create_directory_check_exists(const struct lttng_directory_handle
*handle
,
851 const char *path
, mode_t mode
)
856 ret
= lttng_directory_handle_stat(handle
, path
, &st
);
858 if (S_ISDIR(st
.st_mode
)) {
859 /* Directory exists, skip. */
862 /* Exists, but is not a directory. */
867 } else if (errno
!= ENOENT
) {
872 * Let mkdir handle other errors as the caller expects mkdir
875 ret
= lttng_directory_handle_mkdir(handle
, path
, mode
);
881 int create_directory_recursive(const struct lttng_directory_handle
*handle
,
882 const char *path
, mode_t mode
)
884 char *p
, tmp
[LTTNG_PATH_MAX
];
890 ret
= lttng_strncpy(tmp
, path
, sizeof(tmp
));
892 ERR("Failed to create directory: provided path's length (%zu bytes) exceeds the maximal allowed length (%zu bytes)",
893 strlen(path
) + 1, sizeof(tmp
));
898 if (tmp
[len
- 1] == '/') {
902 for (p
= tmp
+ 1; *p
; p
++) {
905 if (tmp
[strlen(tmp
) - 1] == '.' &&
906 tmp
[strlen(tmp
) - 2] == '.' &&
907 tmp
[strlen(tmp
) - 3] == '/') {
908 ERR("Using '/../' is not permitted in the trace path (%s)",
913 ret
= create_directory_check_exists(handle
, tmp
, mode
);
915 if (errno
!= EACCES
) {
916 PERROR("Failed to create directory \"%s\"",
926 ret
= create_directory_check_exists(handle
, tmp
, mode
);
928 PERROR("mkdirat recursive last element");
936 bool lttng_directory_handle_get(struct lttng_directory_handle
*handle
)
938 return urcu_ref_get_unless_zero(&handle
->ref
);
942 void lttng_directory_handle_put(struct lttng_directory_handle
*handle
)
947 assert(handle
->ref
.refcount
);
948 urcu_ref_put(&handle
->ref
, lttng_directory_handle_release
);
952 int lttng_directory_handle_create_subdirectory_as_user(
953 const struct lttng_directory_handle
*handle
,
954 const char *subdirectory
,
955 mode_t mode
, const struct lttng_credentials
*creds
)
960 /* Run as current user. */
961 ret
= create_directory_check_exists(handle
,
964 ret
= _run_as_mkdir(handle
, subdirectory
,
965 mode
, creds
->uid
, creds
->gid
);
972 int lttng_directory_handle_create_subdirectory_recursive_as_user(
973 const struct lttng_directory_handle
*handle
,
974 const char *subdirectory_path
,
975 mode_t mode
, const struct lttng_credentials
*creds
)
980 /* Run as current user. */
981 ret
= create_directory_recursive(handle
,
982 subdirectory_path
, mode
);
984 ret
= _run_as_mkdir_recursive(handle
, subdirectory_path
,
985 mode
, creds
->uid
, creds
->gid
);
992 int lttng_directory_handle_create_subdirectory(
993 const struct lttng_directory_handle
*handle
,
994 const char *subdirectory
,
997 return lttng_directory_handle_create_subdirectory_as_user(
998 handle
, subdirectory
, mode
, NULL
);
1002 int lttng_directory_handle_create_subdirectory_recursive(
1003 const struct lttng_directory_handle
*handle
,
1004 const char *subdirectory_path
,
1007 return lttng_directory_handle_create_subdirectory_recursive_as_user(
1008 handle
, subdirectory_path
, mode
, NULL
);
1012 int lttng_directory_handle_open_file_as_user(
1013 const struct lttng_directory_handle
*handle
,
1014 const char *filename
,
1015 int flags
, mode_t mode
,
1016 const struct lttng_credentials
*creds
)
1021 /* Run as current user. */
1022 ret
= lttng_directory_handle_open(handle
, filename
, flags
,
1025 ret
= _run_as_open(handle
, filename
, flags
, mode
,
1026 creds
->uid
, creds
->gid
);
1032 int lttng_directory_handle_open_file(
1033 const struct lttng_directory_handle
*handle
,
1034 const char *filename
,
1035 int flags
, mode_t mode
)
1037 return lttng_directory_handle_open_file_as_user(handle
, filename
, flags
,
1042 int lttng_directory_handle_unlink_file_as_user(
1043 const struct lttng_directory_handle
*handle
,
1044 const char *filename
,
1045 const struct lttng_credentials
*creds
)
1050 /* Run as current user. */
1051 ret
= lttng_directory_handle_unlink(handle
, filename
);
1053 ret
= _run_as_unlink(handle
, filename
, creds
->uid
, creds
->gid
);
1059 int lttng_directory_handle_unlink_file(
1060 const struct lttng_directory_handle
*handle
,
1061 const char *filename
)
1063 return lttng_directory_handle_unlink_file_as_user(handle
,
1068 int lttng_directory_handle_rename(
1069 const struct lttng_directory_handle
*old_handle
,
1070 const char *old_name
,
1071 const struct lttng_directory_handle
*new_handle
,
1072 const char *new_name
)
1074 return lttng_directory_handle_rename_as_user(old_handle
, old_name
,
1075 new_handle
, new_name
, NULL
);
1079 int lttng_directory_handle_rename_as_user(
1080 const struct lttng_directory_handle
*old_handle
,
1081 const char *old_name
,
1082 const struct lttng_directory_handle
*new_handle
,
1083 const char *new_name
,
1084 const struct lttng_credentials
*creds
)
1089 /* Run as current user. */
1090 ret
= _lttng_directory_handle_rename(old_handle
,
1091 old_name
, new_handle
, new_name
);
1093 ret
= _run_as_rename(old_handle
, old_name
, new_handle
,
1094 new_name
, creds
->uid
, creds
->gid
);
1100 int lttng_directory_handle_remove_subdirectory(
1101 const struct lttng_directory_handle
*handle
,
1104 return lttng_directory_handle_remove_subdirectory_as_user(handle
, name
,
1109 int lttng_directory_handle_remove_subdirectory_as_user(
1110 const struct lttng_directory_handle
*handle
,
1112 const struct lttng_credentials
*creds
)
1117 /* Run as current user. */
1118 ret
= lttng_directory_handle_rmdir(handle
, name
);
1120 ret
= _run_as_rmdir(handle
, name
, creds
->uid
, creds
->gid
);
1125 struct rmdir_frame
{
1126 ssize_t parent_frame_idx
;
1129 /* Size including '\0'. */
1134 void rmdir_frame_fini(void *data
)
1137 struct rmdir_frame
*frame
= data
;
1139 ret
= closedir(frame
->dir
);
1141 PERROR("Failed to close directory stream");
1146 int remove_directory_recursive(const struct lttng_directory_handle
*handle
,
1147 const char *path
, int flags
)
1150 struct lttng_dynamic_array frames
;
1151 size_t current_frame_idx
= 0;
1152 struct rmdir_frame initial_frame
= {
1153 .parent_frame_idx
= -1,
1154 .dir
= lttng_directory_handle_opendir(handle
, path
),
1156 .path_size
= strlen(path
) + 1,
1158 struct lttng_dynamic_buffer current_path
;
1159 const char separator
= '/';
1161 lttng_dynamic_buffer_init(¤t_path
);
1162 lttng_dynamic_array_init(&frames
, sizeof(struct rmdir_frame
),
1165 if (flags
& ~(LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
|
1166 LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG
)) {
1167 ERR("Unknown flags %d", flags
);
1172 if (!initial_frame
.dir
) {
1173 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
&&
1175 DBG("Cannot rmdir \"%s\": root does not exist", path
);
1179 PERROR("Failed to rmdir \"%s\"", path
);
1185 ret
= lttng_dynamic_array_add_element(&frames
, &initial_frame
);
1187 ERR("Failed to push context frame during recursive directory removal");
1188 rmdir_frame_fini(&initial_frame
);
1192 ret
= lttng_dynamic_buffer_append(
1193 ¤t_path
, path
, initial_frame
.path_size
);
1195 ERR("Failed to set initial path during recursive directory removal");
1200 while (lttng_dynamic_array_get_count(&frames
) > 0) {
1201 struct dirent
*entry
;
1202 struct rmdir_frame
*current_frame
=
1203 lttng_dynamic_array_get_element(
1204 &frames
, current_frame_idx
);
1206 assert(current_frame
->dir
);
1207 ret
= lttng_dynamic_buffer_set_size(
1208 ¤t_path
, current_frame
->path_size
);
1210 current_path
.data
[current_path
.size
- 1] = '\0';
1212 while ((entry
= readdir(current_frame
->dir
))) {
1215 if (!strcmp(entry
->d_name
, ".") ||
1216 !strcmp(entry
->d_name
, "..")) {
1220 /* Set current_path to the entry's path. */
1221 ret
= lttng_dynamic_buffer_set_size(
1222 ¤t_path
, current_path
.size
- 1);
1224 ret
= lttng_dynamic_buffer_append(¤t_path
,
1225 &separator
, sizeof(separator
));
1229 ret
= lttng_dynamic_buffer_append(¤t_path
,
1231 strlen(entry
->d_name
) + 1);
1236 if (lttng_directory_handle_stat(
1237 handle
, current_path
.data
, &st
)) {
1238 if ((flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
) &&
1242 PERROR("Failed to stat \"%s\"",
1248 if (!S_ISDIR(st
.st_mode
)) {
1249 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
) {
1250 current_frame
->empty
= false;
1253 /* Not empty, abort. */
1254 DBG("Directory \"%s\" is not empty; refusing to remove directory",
1260 struct rmdir_frame new_frame
= {
1261 .path_size
= current_path
.size
,
1262 .dir
= lttng_directory_handle_opendir(
1266 .parent_frame_idx
= current_frame_idx
,
1269 if (!new_frame
.dir
) {
1270 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
&&
1272 DBG("Non-existing directory stream during recursive directory removal");
1275 PERROR("Failed to open directory stream during recursive directory removal");
1280 ret
= lttng_dynamic_array_add_element(
1281 &frames
, &new_frame
);
1283 ERR("Failed to push context frame during recursive directory removal");
1284 rmdir_frame_fini(&new_frame
);
1287 current_frame_idx
++;
1288 /* We break iteration on readdir. */
1296 /* Pop rmdir frame. */
1297 if (current_frame
->empty
) {
1298 ret
= lttng_directory_handle_rmdir(
1299 handle
, current_path
.data
);
1301 if ((flags
& LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG
) ||
1303 PERROR("Failed to remove \"%s\" during recursive directory removal",
1307 DBG("Non-existing directory stream during recursive directory removal");
1309 } else if (current_frame
->parent_frame_idx
>= 0) {
1310 struct rmdir_frame
*parent_frame
;
1312 parent_frame
= lttng_dynamic_array_get_element(&frames
,
1313 current_frame
->parent_frame_idx
);
1314 assert(parent_frame
);
1315 parent_frame
->empty
= false;
1317 ret
= lttng_dynamic_array_remove_element(
1318 &frames
, current_frame_idx
);
1320 ERR("Failed to pop context frame during recursive directory removal");
1323 current_frame_idx
--;
1326 lttng_dynamic_array_reset(&frames
);
1327 lttng_dynamic_buffer_reset(¤t_path
);
1332 int lttng_directory_handle_remove_subdirectory_recursive(
1333 const struct lttng_directory_handle
*handle
,
1337 return lttng_directory_handle_remove_subdirectory_recursive_as_user(
1338 handle
, name
, NULL
, flags
);
1342 int lttng_directory_handle_remove_subdirectory_recursive_as_user(
1343 const struct lttng_directory_handle
*handle
,
1345 const struct lttng_credentials
*creds
,
1351 /* Run as current user. */
1352 ret
= remove_directory_recursive(handle
, name
, flags
);
1354 ret
= _run_as_rmdir_recursive(handle
, name
, creds
->uid
,