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 int ret
= unlinkat(handle
->dirfd
, name
, AT_REMOVEDIR
);
297 PERROR("Failed to remove directory `%s`", name
);
304 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
305 const char *name
, uid_t uid
, gid_t gid
)
307 return run_as_rmdirat(handle
->dirfd
, name
, uid
, gid
);
311 int _run_as_rmdir_recursive(
312 const struct lttng_directory_handle
*handle
, const char *name
,
313 uid_t uid
, gid_t gid
, int flags
)
315 return run_as_rmdirat_recursive(handle
->dirfd
, name
, uid
, gid
, flags
);
318 #else /* COMPAT_DIRFD */
321 int get_full_path(const struct lttng_directory_handle
*handle
,
322 const char *subdirectory
, char *fullpath
, size_t size
)
325 const bool subdirectory_is_absolute
=
326 subdirectory
&& *subdirectory
== '/';
327 const char * const base
= subdirectory_is_absolute
?
328 subdirectory
: handle
->base_path
;
329 const char * const end
= subdirectory
&& !subdirectory_is_absolute
?
331 const size_t base_len
= strlen(base
);
332 const size_t end_len
= end
? strlen(end
) : 0;
333 const bool add_separator_slash
= end
&& base
[base_len
- 1] != '/';
334 const bool add_trailing_slash
= end
&& end
[end_len
- 1] != '/';
336 ret
= snprintf(fullpath
, size
, "%s%s%s%s",
338 add_separator_slash
? "/" : "",
340 add_trailing_slash
? "/" : "");
341 if (ret
== -1 || ret
>= size
) {
342 ERR("Failed to format subdirectory from directory handle");
352 int lttng_directory_handle_init(struct lttng_directory_handle
*handle
,
356 const char *cwd
= "";
357 size_t cwd_len
, path_len
;
358 char cwd_buf
[LTTNG_PATH_MAX
] = {};
359 char handle_buf
[LTTNG_PATH_MAX
] = {};
360 bool add_cwd_slash
= false, add_trailing_slash
= false;
361 const struct lttng_directory_handle cwd_handle
= {
362 .base_path
= handle_buf
,
365 path_len
= path
? strlen(path
) : 0;
366 add_trailing_slash
= path
&& path
[path_len
- 1] != '/';
367 if (!path
|| (path
&& *path
!= '/')) {
368 cwd
= getcwd(cwd_buf
, sizeof(cwd_buf
));
370 PERROR("Failed to initialize directory handle, can't get current working directory");
374 cwd_len
= strlen(cwd
);
376 ERR("Failed to initialize directory handle, current working directory path has a length of 0");
380 add_cwd_slash
= cwd
[cwd_len
- 1] != '/';
383 ret
= snprintf(handle_buf
, sizeof(handle_buf
), "%s%s%s%s",
385 add_cwd_slash
? "/" : "",
387 add_trailing_slash
? "/" : "");
388 if (ret
== -1 || ret
>= LTTNG_PATH_MAX
) {
389 ERR("Failed to initialize directory handle, failed to format directory path");
393 ret
= lttng_directory_handle_init_from_handle(handle
, path
,
400 int lttng_directory_handle_init_from_handle(
401 struct lttng_directory_handle
*new_handle
, const char *path
,
402 const struct lttng_directory_handle
*handle
)
405 size_t path_len
, handle_path_len
;
406 bool add_trailing_slash
;
407 struct stat stat_buf
;
409 assert(handle
&& handle
->base_path
);
411 ret
= lttng_directory_handle_stat(handle
, path
, &stat_buf
);
413 PERROR("Failed to create directory handle");
415 } else if (!S_ISDIR(stat_buf
.st_mode
)) {
416 char full_path
[LTTNG_PATH_MAX
];
418 /* Best effort for logging purposes. */
419 ret
= get_full_path(handle
, path
, full_path
,
425 ERR("Failed to initialize directory handle to \"%s\": not a directory",
431 ret
= lttng_directory_handle_copy(handle
, new_handle
);
435 path_len
= strlen(path
);
437 ERR("Failed to initialize directory handle: provided path is an empty string");
442 new_handle
->base_path
= strdup(path
);
443 ret
= new_handle
->base_path
? 0 : -1;
447 add_trailing_slash
= path
[path_len
- 1] != '/';
449 handle_path_len
= strlen(handle
->base_path
) + path_len
+
450 !!add_trailing_slash
;
451 if (handle_path_len
>= LTTNG_PATH_MAX
) {
452 ERR("Failed to initialize directory handle as the resulting path's length (%zu bytes) exceeds the maximal allowed length (%d bytes)",
453 handle_path_len
, LTTNG_PATH_MAX
);
457 new_handle
->base_path
= zmalloc(handle_path_len
);
458 if (!new_handle
->base_path
) {
459 PERROR("Failed to initialize directory handle");
464 ret
= sprintf(new_handle
->base_path
, "%s%s%s",
467 add_trailing_slash
? "/" : "");
468 if (ret
== -1 || ret
>= handle_path_len
) {
469 ERR("Failed to initialize directory handle: path formatting failed");
478 int lttng_directory_handle_init_from_dirfd(
479 struct lttng_directory_handle
*handle
, int dirfd
)
481 assert(dirfd
== AT_FDCWD
);
482 return lttng_directory_handle_init(handle
, NULL
);
486 void lttng_directory_handle_fini(struct lttng_directory_handle
*handle
)
488 free(handle
->base_path
);
489 lttng_directory_handle_invalidate(handle
);
493 int lttng_directory_handle_copy(const struct lttng_directory_handle
*handle
,
494 struct lttng_directory_handle
*new_copy
)
496 new_copy
->base_path
= strdup(handle
->base_path
);
497 return new_copy
->base_path
? 0 : -1;
501 void lttng_directory_handle_invalidate(struct lttng_directory_handle
*handle
)
503 handle
->base_path
= NULL
;
507 int lttng_directory_handle_stat(const struct lttng_directory_handle
*handle
,
508 const char *subdirectory
, struct stat
*st
)
511 char fullpath
[LTTNG_PATH_MAX
];
513 ret
= get_full_path(handle
, subdirectory
, fullpath
, sizeof(fullpath
));
519 ret
= stat(fullpath
, st
);
525 int lttng_directory_handle_mkdir(const struct lttng_directory_handle
*handle
,
526 const char *subdirectory
, mode_t mode
)
529 char fullpath
[LTTNG_PATH_MAX
];
531 ret
= get_full_path(handle
, subdirectory
, fullpath
, sizeof(fullpath
));
537 ret
= mkdir(fullpath
, mode
);
543 int lttng_directory_handle_open(const struct lttng_directory_handle
*handle
,
544 const char *filename
, int flags
, mode_t mode
)
547 char fullpath
[LTTNG_PATH_MAX
];
549 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
555 ret
= open(fullpath
, flags
, mode
);
561 int lttng_directory_handle_unlink(
562 const struct lttng_directory_handle
*handle
,
563 const char *filename
)
566 char fullpath
[LTTNG_PATH_MAX
];
568 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
574 ret
= unlink(fullpath
);
580 int _run_as_mkdir(const struct lttng_directory_handle
*handle
, const char *path
,
581 mode_t mode
, uid_t uid
, gid_t gid
)
584 char fullpath
[LTTNG_PATH_MAX
];
586 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
592 ret
= run_as_mkdir(fullpath
, mode
, uid
, gid
);
598 int _run_as_open(const struct lttng_directory_handle
*handle
,
599 const char *filename
,
600 int flags
, mode_t mode
, uid_t uid
, gid_t gid
)
603 char fullpath
[LTTNG_PATH_MAX
];
605 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
611 ret
= run_as_open(fullpath
, flags
, mode
, uid
, gid
);
617 int _run_as_unlink(const struct lttng_directory_handle
*handle
,
618 const char *filename
, uid_t uid
, gid_t gid
)
621 char fullpath
[LTTNG_PATH_MAX
];
623 ret
= get_full_path(handle
, filename
, fullpath
, sizeof(fullpath
));
629 ret
= run_as_unlink(fullpath
, uid
, gid
);
635 int _run_as_mkdir_recursive(const struct lttng_directory_handle
*handle
,
636 const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
639 char fullpath
[LTTNG_PATH_MAX
];
641 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
647 ret
= run_as_mkdir_recursive(fullpath
, mode
, uid
, gid
);
653 int _lttng_directory_handle_rename(
654 const struct lttng_directory_handle
*old_handle
,
655 const char *old_name
,
656 const struct lttng_directory_handle
*new_handle
,
657 const char *new_name
)
660 char old_fullpath
[LTTNG_PATH_MAX
];
661 char new_fullpath
[LTTNG_PATH_MAX
];
663 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
664 sizeof(old_fullpath
));
669 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
670 sizeof(new_fullpath
));
676 ret
= rename(old_fullpath
, new_fullpath
);
682 int _run_as_rename(const struct lttng_directory_handle
*old_handle
,
683 const char *old_name
,
684 const struct lttng_directory_handle
*new_handle
,
685 const char *new_name
, uid_t uid
, gid_t gid
)
688 char old_fullpath
[LTTNG_PATH_MAX
];
689 char new_fullpath
[LTTNG_PATH_MAX
];
691 ret
= get_full_path(old_handle
, old_name
, old_fullpath
,
692 sizeof(old_fullpath
));
697 ret
= get_full_path(new_handle
, new_name
, new_fullpath
,
698 sizeof(new_fullpath
));
704 ret
= run_as_rename(old_fullpath
, new_fullpath
, uid
, gid
);
710 DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle
*handle
,
714 DIR *dir_stream
= NULL
;
715 char fullpath
[LTTNG_PATH_MAX
];
717 ret
= get_full_path(handle
, path
, fullpath
, sizeof(fullpath
));
723 dir_stream
= opendir(fullpath
);
729 int lttng_directory_handle_rmdir(
730 const struct lttng_directory_handle
*handle
, const char *name
)
733 char fullpath
[LTTNG_PATH_MAX
];
735 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
741 ret
= rmdir(fullpath
);
747 int _run_as_rmdir(const struct lttng_directory_handle
*handle
,
748 const char *name
, uid_t uid
, gid_t gid
)
751 char fullpath
[LTTNG_PATH_MAX
];
753 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
759 ret
= run_as_rmdir(fullpath
, uid
, gid
);
765 int _run_as_rmdir_recursive(
766 const struct lttng_directory_handle
*handle
, const char *name
,
767 uid_t uid
, gid_t gid
, int flags
)
770 char fullpath
[LTTNG_PATH_MAX
];
772 ret
= get_full_path(handle
, name
, fullpath
, sizeof(fullpath
));
778 ret
= run_as_rmdir_recursive(fullpath
, uid
, gid
, flags
);
783 #endif /* COMPAT_DIRFD */
785 /* Common implementation. */
788 * On some filesystems (e.g. nfs), mkdir will validate access rights before
789 * checking for the existence of the path element. This means that on a setup
790 * where "/home/" is a mounted NFS share, and running as an unpriviledged user,
791 * recursively creating a path of the form "/home/my_user/trace/" will fail with
792 * EACCES on mkdir("/home", ...).
794 * Checking the path for existence allows us to work around this behaviour.
797 int create_directory_check_exists(const struct lttng_directory_handle
*handle
,
798 const char *path
, mode_t mode
)
803 ret
= lttng_directory_handle_stat(handle
, path
, &st
);
805 if (S_ISDIR(st
.st_mode
)) {
806 /* Directory exists, skip. */
809 /* Exists, but is not a directory. */
814 } else if (errno
!= ENOENT
) {
819 * Let mkdir handle other errors as the caller expects mkdir
822 ret
= lttng_directory_handle_mkdir(handle
, path
, mode
);
828 struct lttng_directory_handle
829 lttng_directory_handle_move(struct lttng_directory_handle
*original
)
831 const struct lttng_directory_handle tmp
= *original
;
833 lttng_directory_handle_invalidate(original
);
838 int create_directory_recursive(const struct lttng_directory_handle
*handle
,
839 const char *path
, mode_t mode
)
841 char *p
, tmp
[LTTNG_PATH_MAX
];
847 ret
= lttng_strncpy(tmp
, path
, sizeof(tmp
));
849 ERR("Failed to create directory: provided path's length (%zu bytes) exceeds the maximal allowed length (%zu bytes)",
850 strlen(path
) + 1, sizeof(tmp
));
855 if (tmp
[len
- 1] == '/') {
859 for (p
= tmp
+ 1; *p
; p
++) {
862 if (tmp
[strlen(tmp
) - 1] == '.' &&
863 tmp
[strlen(tmp
) - 2] == '.' &&
864 tmp
[strlen(tmp
) - 3] == '/') {
865 ERR("Using '/../' is not permitted in the trace path (%s)",
870 ret
= create_directory_check_exists(handle
, tmp
, mode
);
872 if (errno
!= EACCES
) {
873 PERROR("Failed to create directory \"%s\"",
883 ret
= create_directory_check_exists(handle
, tmp
, mode
);
885 PERROR("mkdirat recursive last element");
893 int lttng_directory_handle_create_subdirectory_as_user(
894 const struct lttng_directory_handle
*handle
,
895 const char *subdirectory
,
896 mode_t mode
, const struct lttng_credentials
*creds
)
901 /* Run as current user. */
902 ret
= create_directory_check_exists(handle
,
905 ret
= _run_as_mkdir(handle
, subdirectory
,
906 mode
, creds
->uid
, creds
->gid
);
913 int lttng_directory_handle_create_subdirectory_recursive_as_user(
914 const struct lttng_directory_handle
*handle
,
915 const char *subdirectory_path
,
916 mode_t mode
, const struct lttng_credentials
*creds
)
921 /* Run as current user. */
922 ret
= create_directory_recursive(handle
,
923 subdirectory_path
, mode
);
925 ret
= _run_as_mkdir_recursive(handle
, subdirectory_path
,
926 mode
, creds
->uid
, creds
->gid
);
933 int lttng_directory_handle_create_subdirectory(
934 const struct lttng_directory_handle
*handle
,
935 const char *subdirectory
,
938 return lttng_directory_handle_create_subdirectory_as_user(
939 handle
, subdirectory
, mode
, NULL
);
943 int lttng_directory_handle_create_subdirectory_recursive(
944 const struct lttng_directory_handle
*handle
,
945 const char *subdirectory_path
,
948 return lttng_directory_handle_create_subdirectory_recursive_as_user(
949 handle
, subdirectory_path
, mode
, NULL
);
953 int lttng_directory_handle_open_file_as_user(
954 const struct lttng_directory_handle
*handle
,
955 const char *filename
,
956 int flags
, mode_t mode
,
957 const struct lttng_credentials
*creds
)
962 /* Run as current user. */
963 ret
= lttng_directory_handle_open(handle
, filename
, flags
,
966 ret
= _run_as_open(handle
, filename
, flags
, mode
,
967 creds
->uid
, creds
->gid
);
973 int lttng_directory_handle_open_file(
974 const struct lttng_directory_handle
*handle
,
975 const char *filename
,
976 int flags
, mode_t mode
)
978 return lttng_directory_handle_open_file_as_user(handle
, filename
, flags
,
983 int lttng_directory_handle_unlink_file_as_user(
984 const struct lttng_directory_handle
*handle
,
985 const char *filename
,
986 const struct lttng_credentials
*creds
)
991 /* Run as current user. */
992 ret
= lttng_directory_handle_unlink(handle
, filename
);
994 ret
= _run_as_unlink(handle
, filename
, creds
->uid
, creds
->gid
);
1000 int lttng_directory_handle_unlink_file(
1001 const struct lttng_directory_handle
*handle
,
1002 const char *filename
)
1004 return lttng_directory_handle_unlink_file_as_user(handle
,
1009 int lttng_directory_handle_rename(
1010 const struct lttng_directory_handle
*old_handle
,
1011 const char *old_name
,
1012 const struct lttng_directory_handle
*new_handle
,
1013 const char *new_name
)
1015 return lttng_directory_handle_rename_as_user(old_handle
, old_name
,
1016 new_handle
, new_name
, NULL
);
1020 int lttng_directory_handle_rename_as_user(
1021 const struct lttng_directory_handle
*old_handle
,
1022 const char *old_name
,
1023 const struct lttng_directory_handle
*new_handle
,
1024 const char *new_name
,
1025 const struct lttng_credentials
*creds
)
1030 /* Run as current user. */
1031 ret
= _lttng_directory_handle_rename(old_handle
,
1032 old_name
, new_handle
, new_name
);
1034 ret
= _run_as_rename(old_handle
, old_name
, new_handle
,
1035 new_name
, creds
->uid
, creds
->gid
);
1041 int lttng_directory_handle_remove_subdirectory(
1042 const struct lttng_directory_handle
*handle
,
1045 return lttng_directory_handle_remove_subdirectory_as_user(handle
, name
,
1050 int lttng_directory_handle_remove_subdirectory_as_user(
1051 const struct lttng_directory_handle
*handle
,
1053 const struct lttng_credentials
*creds
)
1058 /* Run as current user. */
1059 ret
= lttng_directory_handle_rmdir(handle
, name
);
1061 ret
= _run_as_rmdir(handle
, name
, creds
->uid
, creds
->gid
);
1066 struct rmdir_frame
{
1067 ssize_t parent_frame_idx
;
1070 /* Size including '\0'. */
1075 void rmdir_frame_fini(void *data
)
1078 struct rmdir_frame
*frame
= data
;
1080 ret
= closedir(frame
->dir
);
1082 PERROR("Failed to close directory stream");
1087 int remove_directory_recursive(const struct lttng_directory_handle
*handle
,
1088 const char *path
, int flags
)
1091 struct lttng_dynamic_array frames
;
1092 size_t current_frame_idx
= 0;
1093 struct rmdir_frame initial_frame
= {
1094 .parent_frame_idx
= -1,
1095 .dir
= lttng_directory_handle_opendir(handle
, path
),
1097 .path_size
= strlen(path
) + 1,
1099 struct lttng_dynamic_buffer current_path
;
1100 const char separator
= '/';
1102 lttng_dynamic_buffer_init(¤t_path
);
1103 lttng_dynamic_array_init(&frames
, sizeof(struct rmdir_frame
),
1106 if (flags
& ~(LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
|
1107 LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG
)) {
1108 ERR("Unknown flags %d", flags
);
1113 if (!initial_frame
.dir
) {
1114 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
&&
1116 DBG("Cannot rmdir \"%s\": root does not exist", path
);
1120 PERROR("Failed to rmdir \"%s\"", path
);
1126 ret
= lttng_dynamic_array_add_element(&frames
, &initial_frame
);
1128 ERR("Failed to push context frame during recursive directory removal");
1129 rmdir_frame_fini(&initial_frame
);
1133 ret
= lttng_dynamic_buffer_append(
1134 ¤t_path
, path
, initial_frame
.path_size
);
1136 ERR("Failed to set initial path during recursive directory removal");
1141 while (lttng_dynamic_array_get_count(&frames
) > 0) {
1142 struct dirent
*entry
;
1143 struct rmdir_frame
*current_frame
=
1144 lttng_dynamic_array_get_element(
1145 &frames
, current_frame_idx
);
1147 assert(current_frame
->dir
);
1148 ret
= lttng_dynamic_buffer_set_size(
1149 ¤t_path
, current_frame
->path_size
);
1151 current_path
.data
[current_path
.size
- 1] = '\0';
1153 while ((entry
= readdir(current_frame
->dir
))) {
1156 if (!strcmp(entry
->d_name
, ".") ||
1157 !strcmp(entry
->d_name
, "..")) {
1161 /* Set current_path to the entry's path. */
1162 ret
= lttng_dynamic_buffer_set_size(
1163 ¤t_path
, current_path
.size
- 1);
1165 ret
= lttng_dynamic_buffer_append(¤t_path
,
1166 &separator
, sizeof(separator
));
1170 ret
= lttng_dynamic_buffer_append(¤t_path
,
1172 strlen(entry
->d_name
) + 1);
1177 if (lttng_directory_handle_stat(
1178 handle
, current_path
.data
, &st
)) {
1179 if ((flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
) &&
1183 PERROR("Failed to stat \"%s\"",
1189 if (!S_ISDIR(st
.st_mode
)) {
1190 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
) {
1191 current_frame
->empty
= false;
1194 /* Not empty, abort. */
1195 DBG("Directory \"%s\" is not empty; refusing to remove directory",
1201 struct rmdir_frame new_frame
= {
1202 .path_size
= current_path
.size
,
1203 .dir
= lttng_directory_handle_opendir(
1207 .parent_frame_idx
= current_frame_idx
,
1210 if (!new_frame
.dir
) {
1211 if (flags
& LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG
&&
1213 DBG("Non-existing directory stream during recursive directory removal");
1216 PERROR("Failed to open directory stream during recursive directory removal");
1221 ret
= lttng_dynamic_array_add_element(
1222 &frames
, &new_frame
);
1224 ERR("Failed to push context frame during recursive directory removal");
1225 rmdir_frame_fini(&new_frame
);
1228 current_frame_idx
++;
1229 /* We break iteration on readdir. */
1237 /* Pop rmdir frame. */
1238 if (current_frame
->empty
) {
1239 ret
= lttng_directory_handle_rmdir(
1240 handle
, current_path
.data
);
1242 if ((flags
& LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG
) ||
1244 PERROR("Failed to remove \"%s\" during recursive directory removal",
1248 DBG("Non-existing directory stream during recursive directory removal");
1250 } else if (current_frame
->parent_frame_idx
>= 0) {
1251 struct rmdir_frame
*parent_frame
;
1253 parent_frame
= lttng_dynamic_array_get_element(&frames
,
1254 current_frame
->parent_frame_idx
);
1255 assert(parent_frame
);
1256 parent_frame
->empty
= false;
1258 ret
= lttng_dynamic_array_remove_element(
1259 &frames
, current_frame_idx
);
1261 ERR("Failed to pop context frame during recursive directory removal");
1264 current_frame_idx
--;
1267 lttng_dynamic_array_reset(&frames
);
1268 lttng_dynamic_buffer_reset(¤t_path
);
1273 int lttng_directory_handle_remove_subdirectory_recursive(
1274 const struct lttng_directory_handle
*handle
,
1278 return lttng_directory_handle_remove_subdirectory_recursive_as_user(
1279 handle
, name
, NULL
, flags
);
1283 int lttng_directory_handle_remove_subdirectory_recursive_as_user(
1284 const struct lttng_directory_handle
*handle
,
1286 const struct lttng_credentials
*creds
,
1292 /* Run as current user. */
1293 ret
= remove_directory_recursive(handle
, name
, flags
);
1295 ret
= _run_as_rmdir_recursive(handle
, name
, creds
->uid
,