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
);
95 int lttng_directory_handle_init(struct lttng_directory_handle
*new_handle
,
98 const struct lttng_directory_handle cwd_handle
= {
102 /* Open a handle to the CWD if NULL is passed. */
103 return lttng_directory_handle_init_from_handle(new_handle
,
109 int lttng_directory_handle_init_from_handle(
110 struct lttng_directory_handle
*new_handle
, const char *path
,
111 const struct lttng_directory_handle
*handle
)
116 ret
= lttng_directory_handle_copy(handle
, new_handle
);
120 ERR("Failed to initialize directory handle: provided path is an empty string");
124 ret
= openat(handle
->dirfd
, path
, O_RDONLY
| O_DIRECTORY
| O_CLOEXEC
);
126 PERROR("Failed to initialize directory handle to \"%s\"", path
);
129 new_handle
->dirfd
= ret
;
136 int lttng_directory_handle_init_from_dirfd(
137 struct lttng_directory_handle
*handle
, int dirfd
)
139 handle
->dirfd
= dirfd
;
144 void lttng_directory_handle_fini(struct lttng_directory_handle
*handle
)
148 if (handle
->dirfd
== AT_FDCWD
|| handle
->dirfd
== -1) {
151 ret
= close(handle
->dirfd
);
153 PERROR("Failed to close directory file descriptor of directory handle");
157 lttng_directory_handle_invalidate(handle
);
161 int lttng_directory_handle_copy(const struct lttng_directory_handle
*handle
,
162 struct lttng_directory_handle
*new_copy
)
166 if (handle
->dirfd
== AT_FDCWD
) {
167 new_copy
->dirfd
= handle
->dirfd
;
169 new_copy
->dirfd
= dup(handle
->dirfd
);
170 if (new_copy
->dirfd
== -1) {
171 PERROR("Failed to duplicate directory fd of directory handle");
179 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
)
185 int lttng_directory_handle_stat(const struct lttng_directory_handle
*handle
,
186 const char *path
, struct stat
*st
)
188 return fstatat(handle
->dirfd
, path
, st
, 0);
192 int lttng_directory_handle_mkdir(
193 const struct lttng_directory_handle
*handle
,
194 const char *path
, mode_t mode
)
196 return mkdirat(handle
->dirfd
, path
, mode
);
200 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
201 const char *filename
, int flags
, mode_t mode
)
203 return openat(handle
->dirfd
, filename
, flags
, mode
);
207 int _run_as_open(const struct lttng_directory_handle
*handle
,
208 const char *filename
,
209 int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
211 return run_as_openat(handle
->dirfd
, filename
, flags
, mode
, uid
, gid
);
215 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
216 const char *filename
, uid_t uid
, gid_t gid
)
218 return run_as_unlinkat(handle
->dirfd
, filename
, uid
, gid
);
222 int lttng_directory_handle_unlink(
223 const struct lttng_directory_handle
*handle
,
224 const char *filename
)
226 return unlinkat(handle
->dirfd
, filename
, 0);
230 int _run_as_mkdir(const struct lttng_directory_handle
*handle
,
231 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
233 return run_as_mkdirat(handle
->dirfd
, path
, mode
, uid
, gid
);
237 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
238 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
240 return run_as_mkdirat_recursive(handle
->dirfd
, path
, mode
, uid
, gid
);
244 int _lttng_directory_handle_rename(
245 const struct lttng_directory_handle
*old_handle
,
246 const char *old_name
,
247 const struct lttng_directory_handle
*new_handle
,
248 const char *new_name
)
250 return renameat(old_handle
->dirfd
, old_name
,
251 new_handle
->dirfd
, new_name
);
255 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
256 const char *old_name
,
257 const struct lttng_directory_handle
*new_handle
,
258 const char *new_name
, uid_t uid
, gid_t gid
)
260 return run_as_renameat(old_handle
->dirfd
, old_name
, new_handle
->dirfd
,
265 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
268 DIR *dir_stream
= NULL
;
269 int fd
= openat(handle
->dirfd
, path
, O_RDONLY
);
275 dir_stream
= fdopendir(fd
);
279 PERROR("Failed to open directory stream");
282 PERROR("Failed to close file descriptor to %s", path
);
292 int lttng_directory_handle_rmdir(
293 const struct lttng_directory_handle
*handle
, const char *name
)
295 return unlinkat(handle
->dirfd
, name
, AT_REMOVEDIR
);
299 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
300 const char *name
, uid_t uid
, gid_t gid
)
302 return run_as_rmdirat(handle
->dirfd
, name
, uid
, gid
);
306 int _run_as_rmdir_recursive(
307 const struct lttng_directory_handle
*handle
, const char *name
,
308 uid_t uid
, gid_t gid
, int flags
)
310 return run_as_rmdirat_recursive(handle
->dirfd
, name
, uid
, gid
, flags
);
313 #else /* COMPAT_DIRFD */
316 int get_full_path(const struct lttng_directory_handle
*handle
,
317 const char *subdirectory
, char *fullpath
, size_t size
)
320 const bool subdirectory_is_absolute
=
321 subdirectory
&& *subdirectory
== '/';
322 const char * const base
= subdirectory_is_absolute
?
323 subdirectory
: handle
->base_path
;
324 const char * const end
= subdirectory
&& !subdirectory_is_absolute
?
326 const size_t base_len
= strlen(base
);
327 const size_t end_len
= end
? strlen(end
) : 0;
328 const bool add_separator_slash
= end
&& base
[base_len
- 1] != '/';
329 const bool add_trailing_slash
= end
&& end
[end_len
- 1] != '/';
331 ret
= snprintf(fullpath
, size
, "%s%s%s%s",
333 add_separator_slash
? "/" : "",
335 add_trailing_slash
? "/" : "");
336 if (ret
== -1 || ret
>= size
) {
337 ERR("Failed to format subdirectory from directory handle");
347 int lttng_directory_handle_init(struct lttng_directory_handle
*handle
,
351 const char *cwd
= "";
352 size_t cwd_len
, path_len
;
353 char cwd_buf
[LTTNG_PATH_MAX
] = {};
354 char handle_buf
[LTTNG_PATH_MAX
] = {};
355 bool add_cwd_slash
= false, add_trailing_slash
= false;
356 const struct lttng_directory_handle cwd_handle
= {
357 .base_path
= handle_buf
,
360 path_len
= path
? strlen(path
) : 0;
361 add_trailing_slash
= path
&& path
[path_len
- 1] != '/';
362 if (!path
|| (path
&& *path
!= '/')) {
363 cwd
= getcwd(cwd_buf
, sizeof(cwd_buf
));
365 PERROR("Failed to initialize directory handle, can't get current working directory");
369 cwd_len
= strlen(cwd
);
371 ERR("Failed to initialize directory handle, current working directory path has a length of 0");
375 add_cwd_slash
= cwd
[cwd_len
- 1] != '/';
378 ret
= snprintf(handle_buf
, sizeof(handle_buf
), "%s%s%s%s",
380 add_cwd_slash
? "/" : "",
382 add_trailing_slash
? "/" : "");
383 if (ret
== -1 || ret
>= LTTNG_PATH_MAX
) {
384 ERR("Failed to initialize directory handle, failed to format directory path");
388 ret
= lttng_directory_handle_init_from_handle(handle
, path
,
395 int lttng_directory_handle_init_from_handle(
396 struct lttng_directory_handle
*new_handle
, const char *path
,
397 const struct lttng_directory_handle
*handle
)
400 size_t path_len
, handle_path_len
;
401 bool add_trailing_slash
;
402 struct stat stat_buf
;
404 assert(handle
&& handle
->base_path
);
406 ret
= lttng_directory_handle_stat(handle
, path
, &stat_buf
);
408 PERROR("Failed to create directory handle");
410 } else if (!S_ISDIR(stat_buf
.st_mode
)) {
411 char full_path
[LTTNG_PATH_MAX
];
413 /* Best effort for logging purposes. */
414 ret
= get_full_path(handle
, path
, full_path
,
420 ERR("Failed to initialize directory handle to \"%s\": not a directory",
426 ret
= lttng_directory_handle_copy(handle
, new_handle
);
430 path_len
= strlen(path
);
432 ERR("Failed to initialize directory handle: provided path is an empty string");
437 new_handle
->base_path
= strdup(path
);
438 ret
= new_handle
->base_path
? 0 : -1;
442 add_trailing_slash
= path
[path_len
- 1] != '/';
444 handle_path_len
= strlen(handle
->base_path
) + path_len
+
445 !!add_trailing_slash
;
446 if (handle_path_len
>= LTTNG_PATH_MAX
) {
447 ERR("Failed to initialize directory handle as the resulting path's length (%zu bytes) exceeds the maximal allowed length (%d bytes)",
448 handle_path_len
, LTTNG_PATH_MAX
);
452 new_handle
->base_path
= zmalloc(handle_path_len
);
453 if (!new_handle
->base_path
) {
454 PERROR("Failed to initialize directory handle");
459 ret
= sprintf(new_handle
->base_path
, "%s%s%s",
462 add_trailing_slash
? "/" : "");
463 if (ret
== -1 || ret
>= handle_path_len
) {
464 ERR("Failed to initialize directory handle: path formatting failed");
473 int lttng_directory_handle_init_from_dirfd(
474 struct lttng_directory_handle
*handle
, int dirfd
)
476 assert(dirfd
== AT_FDCWD
);
477 return lttng_directory_handle_init(handle
, NULL
);
481 void lttng_directory_handle_fini(struct lttng_directory_handle
*handle
)
483 free(handle
->base_path
);
484 lttng_directory_handle_invalidate(handle
);
488 int lttng_directory_handle_copy(const struct lttng_directory_handle
*handle
,
489 struct lttng_directory_handle
*new_copy
)
491 new_copy
->base_path
= strdup(handle
->base_path
);
492 return new_copy
->base_path
? 0 : -1;
496 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
)
498 handle
->base_path
= NULL
;
502 int lttng_directory_handle_stat(const struct lttng_directory_handle
*handle
,
503 const char *subdirectory
, struct stat
*st
)
506 char fullpath
[LTTNG_PATH_MAX
];
508 ret
= get_full_path(handle
, subdirectory
, fullpath
, sizeof(fullpath
));
514 ret
= stat(fullpath
, st
);
520 int lttng_directory_handle_mkdir(const struct lttng_directory_handle
*handle
,
521 const char *subdirectory
, mode_t mode
)
524 char fullpath
[LTTNG_PATH_MAX
];
526 ret
= get_full_path(handle
, subdirectory
, fullpath
, sizeof(fullpath
));
532 ret
= mkdir(fullpath
, mode
);
538 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
539 const char *filename
, int flags
, mode_t mode
)
542 char fullpath
[LTTNG_PATH_MAX
];
544 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
550 ret
= open(fullpath
, flags
, mode
);
556 int lttng_directory_handle_unlink(
557 const struct lttng_directory_handle
*handle
,
558 const char *filename
)
561 char fullpath
[LTTNG_PATH_MAX
];
563 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
569 ret
= unlink(fullpath
);
575 int _run_as_mkdir(const struct lttng_directory_handle
*handle
, const char *path
,
576 mode_t mode
, uid_t uid
, gid_t gid
)
579 char fullpath
[LTTNG_PATH_MAX
];
581 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
587 ret
= run_as_mkdir(fullpath
, mode
, uid
, gid
);
593 int _run_as_open(const struct lttng_directory_handle
*handle
,
594 const char *filename
,
595 int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
598 char fullpath
[LTTNG_PATH_MAX
];
600 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
606 ret
= run_as_open(fullpath
, flags
, mode
, uid
, gid
);
612 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
613 const char *filename
, uid_t uid
, gid_t gid
)
616 char fullpath
[LTTNG_PATH_MAX
];
618 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
624 ret
= run_as_unlink(fullpath
, uid
, gid
);
630 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
631 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
634 char fullpath
[LTTNG_PATH_MAX
];
636 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
642 ret
= run_as_mkdir_recursive(fullpath
, mode
, uid
, gid
);
648 int _lttng_directory_handle_rename(
649 const struct lttng_directory_handle
*old_handle
,
650 const char *old_name
,
651 const struct lttng_directory_handle
*new_handle
,
652 const char *new_name
)
655 char old_fullpath
[LTTNG_PATH_MAX
];
656 char new_fullpath
[LTTNG_PATH_MAX
];
658 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
659 sizeof(old_fullpath
));
664 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
665 sizeof(new_fullpath
));
671 ret
= rename(old_fullpath
, new_fullpath
);
677 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
678 const char *old_name
,
679 const struct lttng_directory_handle
*new_handle
,
680 const char *new_name
, uid_t uid
, gid_t gid
)
683 char old_fullpath
[LTTNG_PATH_MAX
];
684 char new_fullpath
[LTTNG_PATH_MAX
];
686 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
687 sizeof(old_fullpath
));
692 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
693 sizeof(new_fullpath
));
699 ret
= run_as_rename(old_fullpath
, new_fullpath
, uid
, gid
);
705 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
709 DIR *dir_stream
= NULL
;
710 char fullpath
[LTTNG_PATH_MAX
];
712 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
718 dir_stream
= opendir(fullpath
);
724 int lttng_directory_handle_rmdir(
725 const struct lttng_directory_handle
*handle
, const char *name
)
728 char fullpath
[LTTNG_PATH_MAX
];
730 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
736 ret
= rmdir(fullpath
);
742 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
743 const char *name
, uid_t uid
, gid_t gid
)
746 char fullpath
[LTTNG_PATH_MAX
];
748 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
754 ret
= run_as_rmdir(fullpath
, uid
, gid
);
760 int _run_as_rmdir_recursive(
761 const struct lttng_directory_handle
*handle
, const char *name
,
762 uid_t uid
, gid_t gid
, int flags
)
765 char fullpath
[LTTNG_PATH_MAX
];
767 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
773 ret
= run_as_rmdir_recursive(fullpath
, uid
, gid
, flags
);
778 #endif /* COMPAT_DIRFD */
780 /* Common implementation. */
783 * On some filesystems (e.g. nfs), mkdir will validate access rights before
784 * checking for the existence of the path element. This means that on a setup
785 * where "/home/" is a mounted NFS share, and running as an unpriviledged user,
786 * recursively creating a path of the form "/home/my_user/trace/" will fail with
787 * EACCES on mkdir("/home", ...).
789 * Checking the path for existence allows us to work around this behaviour.
792 int create_directory_check_exists(const struct lttng_directory_handle
*handle
,
793 const char *path
, mode_t mode
)
798 ret
= lttng_directory_handle_stat(handle
, path
, &st
);
800 if (S_ISDIR(st
.st_mode
)) {
801 /* Directory exists, skip. */
804 /* Exists, but is not a directory. */
809 } else if (errno
!= ENOENT
) {
814 * Let mkdir handle other errors as the caller expects mkdir
817 ret
= lttng_directory_handle_mkdir(handle
, path
, mode
);
823 struct lttng_directory_handle
824 lttng_directory_handle_move(struct lttng_directory_handle
*original
)
826 const struct lttng_directory_handle tmp
= *original
;
828 lttng_directory_handle_invalidate(original
);
833 int create_directory_recursive(const struct lttng_directory_handle
*handle
,
834 const char *path
, mode_t mode
)
836 char *p
, tmp
[LTTNG_PATH_MAX
];
842 ret
= lttng_strncpy(tmp
, path
, sizeof(tmp
));
844 ERR("Failed to create directory: provided path's length (%zu bytes) exceeds the maximal allowed length (%zu bytes)",
845 strlen(path
) + 1, sizeof(tmp
));
850 if (tmp
[len
- 1] == '/') {
854 for (p
= tmp
+ 1; *p
; p
++) {
857 if (tmp
[strlen(tmp
) - 1] == '.' &&
858 tmp
[strlen(tmp
) - 2] == '.' &&
859 tmp
[strlen(tmp
) - 3] == '/') {
860 ERR("Using '/../' is not permitted in the trace path (%s)",
865 ret
= create_directory_check_exists(handle
, tmp
, mode
);
867 if (errno
!= EACCES
) {
868 PERROR("Failed to create directory \"%s\"",
878 ret
= create_directory_check_exists(handle
, tmp
, mode
);
880 PERROR("mkdirat recursive last element");
888 int lttng_directory_handle_create_subdirectory_as_user(
889 const struct lttng_directory_handle
*handle
,
890 const char *subdirectory
,
891 mode_t mode
, const struct lttng_credentials
*creds
)
896 /* Run as current user. */
897 ret
= create_directory_check_exists(handle
,
900 ret
= _run_as_mkdir(handle
, subdirectory
,
901 mode
, creds
->uid
, creds
->gid
);
908 int lttng_directory_handle_create_subdirectory_recursive_as_user(
909 const struct lttng_directory_handle
*handle
,
910 const char *subdirectory_path
,
911 mode_t mode
, const struct lttng_credentials
*creds
)
916 /* Run as current user. */
917 ret
= create_directory_recursive(handle
,
918 subdirectory_path
, mode
);
920 ret
= _run_as_mkdir_recursive(handle
, subdirectory_path
,
921 mode
, creds
->uid
, creds
->gid
);
928 int lttng_directory_handle_create_subdirectory(
929 const struct lttng_directory_handle
*handle
,
930 const char *subdirectory
,
933 return lttng_directory_handle_create_subdirectory_as_user(
934 handle
, subdirectory
, mode
, NULL
);
938 int lttng_directory_handle_create_subdirectory_recursive(
939 const struct lttng_directory_handle
*handle
,
940 const char *subdirectory_path
,
943 return lttng_directory_handle_create_subdirectory_recursive_as_user(
944 handle
, subdirectory_path
, mode
, NULL
);
948 int lttng_directory_handle_open_file_as_user(
949 const struct lttng_directory_handle
*handle
,
950 const char *filename
,
951 int flags
, mode_t mode
,
952 const struct lttng_credentials
*creds
)
957 /* Run as current user. */
958 ret
= lttng_directory_handle_open(handle
, filename
, flags
,
961 ret
= _run_as_open(handle
, filename
, flags
, mode
,
962 creds
->uid
, creds
->gid
);
968 int lttng_directory_handle_open_file(
969 const struct lttng_directory_handle
*handle
,
970 const char *filename
,
971 int flags
, mode_t mode
)
973 return lttng_directory_handle_open_file_as_user(handle
, filename
, flags
,
978 int lttng_directory_handle_unlink_file_as_user(
979 const struct lttng_directory_handle
*handle
,
980 const char *filename
,
981 const struct lttng_credentials
*creds
)
986 /* Run as current user. */
987 ret
= lttng_directory_handle_unlink(handle
, filename
);
989 ret
= _run_as_unlink(handle
, filename
, creds
->uid
, creds
->gid
);
995 int lttng_directory_handle_unlink_file(
996 const struct lttng_directory_handle
*handle
,
997 const char *filename
)
999 return lttng_directory_handle_unlink_file_as_user(handle
,
1004 int lttng_directory_handle_rename(
1005 const struct lttng_directory_handle
*old_handle
,
1006 const char *old_name
,
1007 const struct lttng_directory_handle
*new_handle
,
1008 const char *new_name
)
1010 return lttng_directory_handle_rename_as_user(old_handle
, old_name
,
1011 new_handle
, new_name
, NULL
);
1015 int lttng_directory_handle_rename_as_user(
1016 const struct lttng_directory_handle
*old_handle
,
1017 const char *old_name
,
1018 const struct lttng_directory_handle
*new_handle
,
1019 const char *new_name
,
1020 const struct lttng_credentials
*creds
)
1025 /* Run as current user. */
1026 ret
= _lttng_directory_handle_rename(old_handle
,
1027 old_name
, new_handle
, new_name
);
1029 ret
= _run_as_rename(old_handle
, old_name
, new_handle
,
1030 new_name
, creds
->uid
, creds
->gid
);
1036 int lttng_directory_handle_remove_subdirectory(
1037 const struct lttng_directory_handle
*handle
,
1040 return lttng_directory_handle_remove_subdirectory_as_user(handle
, name
,
1045 int lttng_directory_handle_remove_subdirectory_as_user(
1046 const struct lttng_directory_handle
*handle
,
1048 const struct lttng_credentials
*creds
)
1053 /* Run as current user. */
1054 ret
= lttng_directory_handle_rmdir(handle
, name
);
1056 ret
= _run_as_rmdir(handle
, name
, creds
->uid
, creds
->gid
);
1061 struct rmdir_frame
{
1062 ssize_t parent_frame_idx
;
1065 /* Size including '\0'. */
1070 void rmdir_frame_fini(void *data
)
1073 struct rmdir_frame
*frame
= data
;
1075 ret
= closedir(frame
->dir
);
1077 PERROR("Failed to close directory stream");
1082 int remove_directory_recursive(const struct lttng_directory_handle
*handle
,
1083 const char *path
, int flags
)
1086 struct lttng_dynamic_array frames
;
1087 size_t current_frame_idx
= 0;
1088 struct rmdir_frame initial_frame
= {
1089 .parent_frame_idx
= -1,
1090 .dir
= lttng_directory_handle_opendir(handle
, path
),
1092 .path_size
= strlen(path
) + 1,
1094 struct lttng_dynamic_buffer current_path
;
1095 const char separator
= '/';
1097 lttng_dynamic_buffer_init(¤t_path
);
1098 lttng_dynamic_array_init(&frames
, sizeof(struct rmdir_frame
),
1101 if (flags
& ~(LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
|
1102 LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG
)) {
1103 ERR("Unknown flags %d", flags
);
1108 if (!initial_frame
.dir
) {
1109 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
&&
1111 DBG("Cannot rmdir \"%s\": root does not exist", path
);
1115 PERROR("Failed to rmdir \"%s\"", path
);
1121 ret
= lttng_dynamic_array_add_element(&frames
, &initial_frame
);
1123 ERR("Failed to push context frame during recursive directory removal");
1124 rmdir_frame_fini(&initial_frame
);
1128 ret
= lttng_dynamic_buffer_append(
1129 ¤t_path
, path
, initial_frame
.path_size
);
1131 ERR("Failed to set initial path during recursive directory removal");
1136 while (lttng_dynamic_array_get_count(&frames
) > 0) {
1137 struct dirent
*entry
;
1138 struct rmdir_frame
*current_frame
=
1139 lttng_dynamic_array_get_element(
1140 &frames
, current_frame_idx
);
1142 assert(current_frame
->dir
);
1143 ret
= lttng_dynamic_buffer_set_size(
1144 ¤t_path
, current_frame
->path_size
);
1146 current_path
.data
[current_path
.size
- 1] = '\0';
1148 while ((entry
= readdir(current_frame
->dir
))) {
1151 if (!strcmp(entry
->d_name
, ".") ||
1152 !strcmp(entry
->d_name
, "..")) {
1156 /* Set current_path to the entry's path. */
1157 ret
= lttng_dynamic_buffer_set_size(
1158 ¤t_path
, current_path
.size
- 1);
1160 ret
= lttng_dynamic_buffer_append(¤t_path
,
1161 &separator
, sizeof(separator
));
1165 ret
= lttng_dynamic_buffer_append(¤t_path
,
1167 strlen(entry
->d_name
) + 1);
1172 if (lttng_directory_handle_stat(
1173 handle
, current_path
.data
, &st
)) {
1174 if ((flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
) &&
1178 PERROR("Failed to stat \"%s\"",
1184 if (!S_ISDIR(st
.st_mode
)) {
1185 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
) {
1186 current_frame
->empty
= false;
1189 /* Not empty, abort. */
1190 DBG("Directory \"%s\" is not empty; refusing to remove directory",
1196 struct rmdir_frame new_frame
= {
1197 .path_size
= current_path
.size
,
1198 .dir
= lttng_directory_handle_opendir(
1202 .parent_frame_idx
= current_frame_idx
,
1205 if (!new_frame
.dir
) {
1206 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
&&
1208 DBG("Non-existing directory stream during recursive directory removal");
1211 PERROR("Failed to open directory stream during recursive directory removal");
1216 ret
= lttng_dynamic_array_add_element(
1217 &frames
, &new_frame
);
1219 ERR("Failed to push context frame during recursive directory removal");
1220 rmdir_frame_fini(&new_frame
);
1223 current_frame_idx
++;
1224 /* We break iteration on readdir. */
1232 /* Pop rmdir frame. */
1233 if (current_frame
->empty
) {
1234 ret
= lttng_directory_handle_rmdir(
1235 handle
, current_path
.data
);
1237 if ((flags
& LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG
) ||
1239 PERROR("Failed to remove \"%s\" during recursive directory removal",
1243 DBG("Non-existing directory stream during recursive directory removal");
1245 } else if (current_frame
->parent_frame_idx
>= 0) {
1246 struct rmdir_frame
*parent_frame
;
1248 parent_frame
= lttng_dynamic_array_get_element(&frames
,
1249 current_frame
->parent_frame_idx
);
1250 assert(parent_frame
);
1251 parent_frame
->empty
= false;
1253 ret
= lttng_dynamic_array_remove_element(
1254 &frames
, current_frame_idx
);
1256 ERR("Failed to pop context frame during recursive directory removal");
1259 current_frame_idx
--;
1262 lttng_dynamic_array_reset(&frames
);
1263 lttng_dynamic_buffer_reset(¤t_path
);
1268 int lttng_directory_handle_remove_subdirectory_recursive(
1269 const struct lttng_directory_handle
*handle
,
1273 return lttng_directory_handle_remove_subdirectory_recursive_as_user(
1274 handle
, name
, NULL
, flags
);
1278 int lttng_directory_handle_remove_subdirectory_recursive_as_user(
1279 const struct lttng_directory_handle
*handle
,
1281 const struct lttng_credentials
*creds
,
1287 /* Run as current user. */
1288 ret
= remove_directory_recursive(handle
, name
, flags
);
1290 ret
= _run_as_rmdir_recursive(handle
, name
, creds
->uid
,