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
);
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");
156 lttng_directory_handle_invalidate(handle
);
160 int lttng_directory_handle_copy(const struct lttng_directory_handle
*handle
,
161 struct lttng_directory_handle
*new_copy
)
165 if (handle
->dirfd
== AT_FDCWD
) {
166 new_copy
->dirfd
= handle
->dirfd
;
168 new_copy
->dirfd
= dup(handle
->dirfd
);
169 if (new_copy
->dirfd
== -1) {
170 PERROR("Failed to duplicate directory fd of directory handle");
178 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
)
184 int lttng_directory_handle_stat(const struct lttng_directory_handle
*handle
,
185 const char *path
, struct stat
*st
)
187 return fstatat(handle
->dirfd
, path
, st
, 0);
191 int lttng_directory_handle_mkdir(
192 const struct lttng_directory_handle
*handle
,
193 const char *path
, mode_t mode
)
195 return mkdirat(handle
->dirfd
, path
, mode
);
199 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
200 const char *filename
, int flags
, mode_t mode
)
202 return openat(handle
->dirfd
, filename
, flags
, mode
);
206 int _run_as_open(const struct lttng_directory_handle
*handle
,
207 const char *filename
,
208 int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
210 return run_as_openat(handle
->dirfd
, filename
, flags
, mode
, uid
, gid
);
214 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
215 const char *filename
, uid_t uid
, gid_t gid
)
217 return run_as_unlinkat(handle
->dirfd
, filename
, uid
, gid
);
221 int lttng_directory_handle_unlink(
222 const struct lttng_directory_handle
*handle
,
223 const char *filename
)
225 return unlinkat(handle
->dirfd
, filename
, 0);
229 int _run_as_mkdir(const struct lttng_directory_handle
*handle
,
230 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
232 return run_as_mkdirat(handle
->dirfd
, path
, mode
, uid
, gid
);
236 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
237 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
239 return run_as_mkdirat_recursive(handle
->dirfd
, path
, mode
, uid
, gid
);
243 int _lttng_directory_handle_rename(
244 const struct lttng_directory_handle
*old_handle
,
245 const char *old_name
,
246 const struct lttng_directory_handle
*new_handle
,
247 const char *new_name
)
249 return renameat(old_handle
->dirfd
, old_name
,
250 new_handle
->dirfd
, new_name
);
254 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
255 const char *old_name
,
256 const struct lttng_directory_handle
*new_handle
,
257 const char *new_name
, uid_t uid
, gid_t gid
)
259 return run_as_renameat(old_handle
->dirfd
, old_name
, new_handle
->dirfd
,
264 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
267 DIR *dir_stream
= NULL
;
268 int fd
= openat(handle
->dirfd
, path
, O_RDONLY
);
274 dir_stream
= fdopendir(fd
);
278 PERROR("Failed to open directory stream");
281 PERROR("Failed to close file descriptor to %s", path
);
291 int lttng_directory_handle_rmdir(
292 const struct lttng_directory_handle
*handle
, const char *name
)
294 return unlinkat(handle
->dirfd
, name
, AT_REMOVEDIR
);
298 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
299 const char *name
, uid_t uid
, gid_t gid
)
301 return run_as_rmdirat(handle
->dirfd
, name
, uid
, gid
);
305 int _run_as_rmdir_recursive(
306 const struct lttng_directory_handle
*handle
, const char *name
,
307 uid_t uid
, gid_t gid
)
309 return run_as_rmdirat_recursive(handle
->dirfd
, name
, uid
, gid
);
312 #else /* COMPAT_DIRFD */
315 int get_full_path(const struct lttng_directory_handle
*handle
,
316 const char *subdirectory
, char *fullpath
, size_t size
)
319 const bool subdirectory_is_absolute
=
320 subdirectory
&& *subdirectory
== '/';
321 const char * const base
= subdirectory_is_absolute
?
322 subdirectory
: handle
->base_path
;
323 const char * const end
= subdirectory
&& !subdirectory_is_absolute
?
325 const size_t base_len
= strlen(base
);
326 const size_t end_len
= end
? strlen(end
) : 0;
327 const bool add_separator_slash
= end
&& base
[base_len
- 1] != '/';
328 const bool add_trailing_slash
= end
&& end
[end_len
- 1] != '/';
330 ret
= snprintf(fullpath
, size
, "%s%s%s%s",
332 add_separator_slash
? "/" : "",
334 add_trailing_slash
? "/" : "");
335 if (ret
== -1 || ret
>= size
) {
336 ERR("Failed to format subdirectory from directory handle");
346 int lttng_directory_handle_init(struct lttng_directory_handle
*handle
,
350 const char *cwd
= "";
351 size_t cwd_len
, path_len
;
352 char cwd_buf
[LTTNG_PATH_MAX
] = {};
353 char handle_buf
[LTTNG_PATH_MAX
] = {};
354 bool add_cwd_slash
= false, add_trailing_slash
= false;
355 const struct lttng_directory_handle cwd_handle
= {
356 .base_path
= handle_buf
,
359 path_len
= path
? strlen(path
) : 0;
360 add_trailing_slash
= path
&& path
[path_len
- 1] != '/';
361 if (!path
|| (path
&& *path
!= '/')) {
362 cwd
= getcwd(cwd_buf
, sizeof(cwd_buf
));
364 PERROR("Failed to initialize directory handle, can't get current working directory");
368 cwd_len
= strlen(cwd
);
370 ERR("Failed to initialize directory handle, current working directory path has a length of 0");
374 add_cwd_slash
= cwd
[cwd_len
- 1] != '/';
377 ret
= snprintf(handle_buf
, sizeof(handle_buf
), "%s%s%s%s",
379 add_cwd_slash
? "/" : "",
381 add_trailing_slash
? "/" : "");
382 if (ret
== -1 || ret
>= LTTNG_PATH_MAX
) {
383 ERR("Failed to initialize directory handle, failed to format directory path");
387 ret
= lttng_directory_handle_init_from_handle(handle
, path
,
394 int lttng_directory_handle_init_from_handle(
395 struct lttng_directory_handle
*new_handle
, const char *path
,
396 const struct lttng_directory_handle
*handle
)
399 size_t path_len
, handle_path_len
;
400 bool add_trailing_slash
;
401 struct stat stat_buf
;
403 assert(handle
&& handle
->base_path
);
405 ret
= lttng_directory_handle_stat(handle
, path
, &stat_buf
);
407 PERROR("Failed to create directory handle");
409 } else if (!S_ISDIR(stat_buf
.st_mode
)) {
410 char full_path
[LTTNG_PATH_MAX
];
412 /* Best effort for logging purposes. */
413 ret
= get_full_path(handle
, path
, full_path
,
419 ERR("Failed to initialize directory handle to \"%s\": not a directory",
425 ret
= lttng_directory_handle_copy(handle
, new_handle
);
429 path_len
= strlen(path
);
431 ERR("Failed to initialize directory handle: provided path is an empty string");
436 new_handle
->base_path
= strdup(path
);
437 ret
= new_handle
->base_path
? 0 : -1;
441 add_trailing_slash
= path
[path_len
- 1] != '/';
443 handle_path_len
= strlen(handle
->base_path
) + path_len
+
444 !!add_trailing_slash
;
445 if (handle_path_len
>= LTTNG_PATH_MAX
) {
446 ERR("Failed to initialize directory handle as the resulting path's length (%zu bytes) exceeds the maximal allowed length (%d bytes)",
447 handle_path_len
, LTTNG_PATH_MAX
);
451 new_handle
->base_path
= zmalloc(handle_path_len
);
452 if (!new_handle
->base_path
) {
453 PERROR("Failed to initialize directory handle");
458 ret
= sprintf(new_handle
->base_path
, "%s%s%s",
461 add_trailing_slash
? "/" : "");
462 if (ret
== -1 || ret
>= handle_path_len
) {
463 ERR("Failed to initialize directory handle: path formatting failed");
472 int lttng_directory_handle_init_from_dirfd(
473 struct lttng_directory_handle
*handle
, int dirfd
)
475 assert(dirfd
== AT_FDCWD
);
476 return lttng_directory_handle_init(handle
, NULL
);
480 void lttng_directory_handle_fini(struct lttng_directory_handle
*handle
)
482 free(handle
->base_path
);
483 lttng_directory_handle_invalidate(handle
);
487 int lttng_directory_handle_copy(const struct lttng_directory_handle
*handle
,
488 struct lttng_directory_handle
*new_copy
)
490 new_copy
->base_path
= strdup(handle
->base_path
);
491 return new_copy
->base_path
? 0 : -1;
495 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
)
497 handle
->base_path
= NULL
;
501 int lttng_directory_handle_stat(const struct lttng_directory_handle
*handle
,
502 const char *subdirectory
, struct stat
*st
)
505 char fullpath
[LTTNG_PATH_MAX
];
507 ret
= get_full_path(handle
, subdirectory
, fullpath
, sizeof(fullpath
));
513 ret
= stat(fullpath
, st
);
519 int lttng_directory_handle_mkdir(const struct lttng_directory_handle
*handle
,
520 const char *subdirectory
, mode_t mode
)
523 char fullpath
[LTTNG_PATH_MAX
];
525 ret
= get_full_path(handle
, subdirectory
, fullpath
, sizeof(fullpath
));
531 ret
= mkdir(fullpath
, mode
);
537 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
538 const char *filename
, int flags
, mode_t mode
)
541 char fullpath
[LTTNG_PATH_MAX
];
543 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
549 ret
= open(fullpath
, flags
, mode
);
555 int lttng_directory_handle_unlink(
556 const struct lttng_directory_handle
*handle
,
557 const char *filename
)
560 char fullpath
[LTTNG_PATH_MAX
];
562 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
568 ret
= unlink(fullpath
);
574 int _run_as_mkdir(const struct lttng_directory_handle
*handle
, const char *path
,
575 mode_t mode
, uid_t uid
, gid_t gid
)
578 char fullpath
[LTTNG_PATH_MAX
];
580 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
586 ret
= run_as_mkdir(fullpath
, mode
, uid
, gid
);
592 int _run_as_open(const struct lttng_directory_handle
*handle
,
593 const char *filename
,
594 int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
597 char fullpath
[LTTNG_PATH_MAX
];
599 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
605 ret
= run_as_open(fullpath
, flags
, mode
, uid
, gid
);
611 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
612 const char *filename
, uid_t uid
, gid_t gid
)
615 char fullpath
[LTTNG_PATH_MAX
];
617 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
623 ret
= run_as_unlink(fullpath
, uid
, gid
);
629 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
630 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
633 char fullpath
[LTTNG_PATH_MAX
];
635 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
641 ret
= run_as_mkdir_recursive(fullpath
, mode
, uid
, gid
);
647 int _lttng_directory_handle_rename(
648 const struct lttng_directory_handle
*old_handle
,
649 const char *old_name
,
650 const struct lttng_directory_handle
*new_handle
,
651 const char *new_name
)
654 char old_fullpath
[LTTNG_PATH_MAX
];
655 char new_fullpath
[LTTNG_PATH_MAX
];
657 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
658 sizeof(old_fullpath
));
663 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
664 sizeof(new_fullpath
));
670 ret
= rename(old_fullpath
, new_fullpath
);
676 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
677 const char *old_name
,
678 const struct lttng_directory_handle
*new_handle
,
679 const char *new_name
, uid_t uid
, gid_t gid
)
682 char old_fullpath
[LTTNG_PATH_MAX
];
683 char new_fullpath
[LTTNG_PATH_MAX
];
685 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
686 sizeof(old_fullpath
));
691 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
692 sizeof(new_fullpath
));
698 ret
= run_as_rename(old_fullpath
, new_fullpath
, uid
, gid
);
704 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
708 DIR *dir_stream
= NULL
;
709 char fullpath
[LTTNG_PATH_MAX
];
711 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
717 dir_stream
= opendir(fullpath
);
723 int lttng_directory_handle_rmdir(
724 const struct lttng_directory_handle
*handle
, const char *name
)
727 char fullpath
[LTTNG_PATH_MAX
];
729 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
735 ret
= rmdir(fullpath
);
741 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
742 const char *name
, uid_t uid
, gid_t gid
)
745 char fullpath
[LTTNG_PATH_MAX
];
747 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
753 ret
= run_as_rmdir(fullpath
, uid
, gid
);
759 int _run_as_rmdir_recursive(
760 const struct lttng_directory_handle
*handle
, const char *name
,
761 uid_t uid
, gid_t gid
)
764 char fullpath
[LTTNG_PATH_MAX
];
766 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
772 ret
= run_as_rmdir_recursive(fullpath
, uid
, gid
);
777 #endif /* COMPAT_DIRFD */
779 /* Common implementation. */
782 * On some filesystems (e.g. nfs), mkdir will validate access rights before
783 * checking for the existence of the path element. This means that on a setup
784 * where "/home/" is a mounted NFS share, and running as an unpriviledged user,
785 * recursively creating a path of the form "/home/my_user/trace/" will fail with
786 * EACCES on mkdir("/home", ...).
788 * Checking the path for existence allows us to work around this behaviour.
791 int create_directory_check_exists(const struct lttng_directory_handle
*handle
,
792 const char *path
, mode_t mode
)
797 ret
= lttng_directory_handle_stat(handle
, path
, &st
);
799 if (S_ISDIR(st
.st_mode
)) {
800 /* Directory exists, skip. */
803 /* Exists, but is not a directory. */
808 } else if (errno
!= ENOENT
) {
813 * Let mkdir handle other errors as the caller expects mkdir
816 ret
= lttng_directory_handle_mkdir(handle
, path
, mode
);
822 struct lttng_directory_handle
823 lttng_directory_handle_move(struct lttng_directory_handle
*original
)
825 const struct lttng_directory_handle tmp
= *original
;
827 lttng_directory_handle_invalidate(original
);
832 int create_directory_recursive(const struct lttng_directory_handle
*handle
,
833 const char *path
, mode_t mode
)
835 char *p
, tmp
[LTTNG_PATH_MAX
];
841 ret
= lttng_strncpy(tmp
, path
, sizeof(tmp
));
843 ERR("Failed to create directory: provided path's length (%zu bytes) exceeds the maximal allowed length (%zu bytes)",
844 strlen(path
) + 1, sizeof(tmp
));
849 if (tmp
[len
- 1] == '/') {
853 for (p
= tmp
+ 1; *p
; p
++) {
856 if (tmp
[strlen(tmp
) - 1] == '.' &&
857 tmp
[strlen(tmp
) - 2] == '.' &&
858 tmp
[strlen(tmp
) - 3] == '/') {
859 ERR("Using '/../' is not permitted in the trace path (%s)",
864 ret
= create_directory_check_exists(handle
, tmp
, mode
);
866 if (errno
!= EACCES
) {
867 PERROR("Failed to create directory \"%s\"",
877 ret
= create_directory_check_exists(handle
, tmp
, mode
);
879 PERROR("mkdirat recursive last element");
887 int lttng_directory_handle_create_subdirectory_as_user(
888 const struct lttng_directory_handle
*handle
,
889 const char *subdirectory
,
890 mode_t mode
, const struct lttng_credentials
*creds
)
895 /* Run as current user. */
896 ret
= create_directory_check_exists(handle
,
899 ret
= _run_as_mkdir(handle
, subdirectory
,
900 mode
, creds
->uid
, creds
->gid
);
907 int lttng_directory_handle_create_subdirectory_recursive_as_user(
908 const struct lttng_directory_handle
*handle
,
909 const char *subdirectory_path
,
910 mode_t mode
, const struct lttng_credentials
*creds
)
915 /* Run as current user. */
916 ret
= create_directory_recursive(handle
,
917 subdirectory_path
, mode
);
919 ret
= _run_as_mkdir_recursive(handle
, subdirectory_path
,
920 mode
, creds
->uid
, creds
->gid
);
927 int lttng_directory_handle_create_subdirectory(
928 const struct lttng_directory_handle
*handle
,
929 const char *subdirectory
,
932 return lttng_directory_handle_create_subdirectory_as_user(
933 handle
, subdirectory
, mode
, NULL
);
937 int lttng_directory_handle_create_subdirectory_recursive(
938 const struct lttng_directory_handle
*handle
,
939 const char *subdirectory_path
,
942 return lttng_directory_handle_create_subdirectory_recursive_as_user(
943 handle
, subdirectory_path
, mode
, NULL
);
947 int lttng_directory_handle_open_file_as_user(
948 const struct lttng_directory_handle
*handle
,
949 const char *filename
,
950 int flags
, mode_t mode
,
951 const struct lttng_credentials
*creds
)
956 /* Run as current user. */
957 ret
= lttng_directory_handle_open(handle
, filename
, flags
,
960 ret
= _run_as_open(handle
, filename
, flags
, mode
,
961 creds
->uid
, creds
->gid
);
967 int lttng_directory_handle_open_file(
968 const struct lttng_directory_handle
*handle
,
969 const char *filename
,
970 int flags
, mode_t mode
)
972 return lttng_directory_handle_open_file_as_user(handle
, filename
, flags
,
977 int lttng_directory_handle_unlink_file_as_user(
978 const struct lttng_directory_handle
*handle
,
979 const char *filename
,
980 const struct lttng_credentials
*creds
)
985 /* Run as current user. */
986 ret
= lttng_directory_handle_unlink(handle
, filename
);
988 ret
= _run_as_unlink(handle
, filename
, creds
->uid
, creds
->gid
);
994 int lttng_directory_handle_unlink_file(
995 const struct lttng_directory_handle
*handle
,
996 const char *filename
)
998 return lttng_directory_handle_unlink_file_as_user(handle
,
1003 int lttng_directory_handle_rename(
1004 const struct lttng_directory_handle
*old_handle
,
1005 const char *old_name
,
1006 const struct lttng_directory_handle
*new_handle
,
1007 const char *new_name
)
1009 return lttng_directory_handle_rename_as_user(old_handle
, old_name
,
1010 new_handle
, new_name
, NULL
);
1014 int lttng_directory_handle_rename_as_user(
1015 const struct lttng_directory_handle
*old_handle
,
1016 const char *old_name
,
1017 const struct lttng_directory_handle
*new_handle
,
1018 const char *new_name
,
1019 const struct lttng_credentials
*creds
)
1024 /* Run as current user. */
1025 ret
= _lttng_directory_handle_rename(old_handle
,
1026 old_name
, new_handle
, new_name
);
1028 ret
= _run_as_rename(old_handle
, old_name
, new_handle
,
1029 new_name
, creds
->uid
, creds
->gid
);
1035 int lttng_directory_handle_remove_subdirectory(
1036 const struct lttng_directory_handle
*handle
,
1039 return lttng_directory_handle_remove_subdirectory_as_user(handle
, name
,
1044 int lttng_directory_handle_remove_subdirectory_as_user(
1045 const struct lttng_directory_handle
*handle
,
1047 const struct lttng_credentials
*creds
)
1052 /* Run as current user. */
1053 ret
= lttng_directory_handle_rmdir(handle
, name
);
1055 ret
= _run_as_rmdir(handle
, name
, creds
->uid
, creds
->gid
);
1060 struct rmdir_frame
{
1062 /* Size including '\0'. */
1067 void rmdir_frame_fini(void *data
)
1069 struct rmdir_frame
*frame
= data
;
1071 closedir(frame
->dir
);
1075 int remove_directory_recursive(const struct lttng_directory_handle
*handle
,
1079 struct lttng_dynamic_array frames
;
1080 size_t current_frame_idx
= 0;
1081 struct rmdir_frame initial_frame
= {
1082 .dir
= lttng_directory_handle_opendir(handle
, path
),
1083 .path_size
= strlen(path
) + 1,
1085 struct lttng_dynamic_buffer current_path
;
1086 const char separator
= '/';
1088 lttng_dynamic_buffer_init(¤t_path
);
1089 lttng_dynamic_array_init(&frames
, sizeof(struct rmdir_frame
),
1092 ret
= lttng_dynamic_array_add_element(&frames
, &initial_frame
);
1094 ERR("Failed to push context frame during recursive directory removal");
1095 rmdir_frame_fini(&initial_frame
);
1099 ret
= lttng_dynamic_buffer_append(¤t_path
, path
,
1100 initial_frame
.path_size
);
1102 ERR("Failed to set initial path during recursive directory removal");
1107 while (lttng_dynamic_array_get_count(&frames
) > 0) {
1108 struct dirent
*entry
;
1109 struct rmdir_frame
*current_frame
=
1110 lttng_dynamic_array_get_element(&frames
,
1113 if (!current_frame
->dir
) {
1114 PERROR("Failed to open directory stream during recursive directory removal");
1118 ret
= lttng_dynamic_buffer_set_size(¤t_path
,
1119 current_frame
->path_size
);
1121 current_path
.data
[current_path
.size
- 1] = '\0';
1123 while ((entry
= readdir(current_frame
->dir
))) {
1125 struct rmdir_frame new_frame
;
1127 if (!strcmp(entry
->d_name
, ".")
1128 || !strcmp(entry
->d_name
, "..")) {
1132 /* Set current_path to the entry's path. */
1133 ret
= lttng_dynamic_buffer_set_size(¤t_path
,
1134 current_path
.size
- 1);
1136 ret
= lttng_dynamic_buffer_append(¤t_path
,
1137 &separator
, sizeof(separator
));
1141 ret
= lttng_dynamic_buffer_append(¤t_path
,
1143 strlen(entry
->d_name
) + 1);
1148 if (lttng_directory_handle_stat(handle
,
1149 current_path
.data
, &st
)) {
1150 PERROR("Failed to stat \"%s\"",
1156 if (!S_ISDIR(st
.st_mode
)) {
1157 /* Not empty, abort. */
1158 DBG("Directory \"%s\" is not empty; refusing to remove directory",
1164 new_frame
.path_size
= current_path
.size
;
1165 new_frame
.dir
= lttng_directory_handle_opendir(handle
,
1167 ret
= lttng_dynamic_array_add_element(&frames
,
1170 ERR("Failed to push context frame during recursive directory removal");
1171 rmdir_frame_fini(&new_frame
);
1174 current_frame_idx
++;
1178 ret
= lttng_directory_handle_rmdir(handle
,
1181 PERROR("Failed to remove \"%s\" during recursive directory removal",
1185 ret
= lttng_dynamic_array_remove_element(&frames
,
1188 ERR("Failed to pop context frame during recursive directory removal");
1191 current_frame_idx
--;
1195 lttng_dynamic_array_reset(&frames
);
1196 lttng_dynamic_buffer_reset(¤t_path
);
1201 int lttng_directory_handle_remove_subdirectory_recursive(
1202 const struct lttng_directory_handle
*handle
,
1205 return lttng_directory_handle_remove_subdirectory_recursive_as_user(
1206 handle
, name
, NULL
);
1210 int lttng_directory_handle_remove_subdirectory_recursive_as_user(
1211 const struct lttng_directory_handle
*handle
,
1213 const struct lttng_credentials
*creds
)
1218 /* Run as current user. */
1219 ret
= remove_directory_recursive(handle
, name
);
1221 ret
= _run_as_rmdir_recursive(handle
, name
, creds
->uid
,