Replace explicit rcu_read_lock/unlock with lttng::urcu::read_lock_guard
[lttng-tools.git] / src / common / compat / directory-handle.cpp
CommitLineData
18710679 1/*
ab5be9fa 2 * Copyright (C) 2019 Jérémie Galarneau <jeremie.galarneau@efficios.com>
18710679 3 *
c922647d 4 * SPDX-License-Identifier: LGPL-2.1-only
18710679 5 *
18710679
JG
6 */
7
c9e313bc 8#include <common/compat/directory-handle.hpp>
28ab034a
JG
9#include <common/credentials.hpp>
10#include <common/dynamic-array.hpp>
c9e313bc
SM
11#include <common/error.hpp>
12#include <common/macros.hpp>
13#include <common/runas.hpp>
28ab034a 14
18710679
JG
15#include <lttng/constant.h>
16
28ab034a 17#include <dirent.h>
18710679 18#include <fcntl.h>
28ab034a
JG
19#include <sys/stat.h>
20#include <sys/types.h>
18710679
JG
21#include <unistd.h>
22
2912cead
JG
23/*
24 * This compatibility layer shares a common "base" that is implemented
25 * in terms of an internal API. This file contains two implementations
26 * of the internal API below.
27 */
28ab034a
JG
28static int lttng_directory_handle_mkdir(const struct lttng_directory_handle *handle,
29 const char *path,
30 mode_t mode);
31static int _run_as_mkdir(const struct lttng_directory_handle *handle,
32 const char *path,
33 mode_t mode,
34 uid_t uid,
35 gid_t gid);
36static int _run_as_mkdir_recursive(const struct lttng_directory_handle *handle,
37 const char *path,
38 mode_t mode,
39 uid_t uid,
40 gid_t gid);
41static int lttng_directory_handle_open(const struct lttng_directory_handle *handle,
42 const char *filename,
43 int flags,
44 mode_t mode);
45static int _run_as_open(const struct lttng_directory_handle *handle,
46 const char *filename,
47 int flags,
48 mode_t mode,
49 uid_t uid,
50 gid_t gid);
51static int lttng_directory_handle_unlink(const struct lttng_directory_handle *handle,
52 const char *filename);
53static int _run_as_unlink(const struct lttng_directory_handle *handle,
54 const char *filename,
55 uid_t uid,
56 gid_t gid);
57static int _lttng_directory_handle_rename(const struct lttng_directory_handle *old_handle,
58 const char *old_name,
59 const struct lttng_directory_handle *new_handle,
60 const char *new_name);
61static int _run_as_rename(const struct lttng_directory_handle *old_handle,
62 const char *old_name,
63 const struct lttng_directory_handle *new_handle,
64 const char *new_name,
65 uid_t uid,
66 gid_t gid);
67static DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle *handle,
68 const char *path);
69static int lttng_directory_handle_rmdir(const struct lttng_directory_handle *handle,
70 const char *name);
71static int
72_run_as_rmdir(const struct lttng_directory_handle *handle, const char *name, uid_t uid, gid_t gid);
73static int _run_as_rmdir_recursive(const struct lttng_directory_handle *handle,
74 const char *name,
75 uid_t uid,
76 gid_t gid,
77 int flags);
78static void lttng_directory_handle_invalidate(struct lttng_directory_handle *handle);
79static void lttng_directory_handle_release(struct urcu_ref *ref);
18710679 80
4fb28dfc 81#ifdef HAVE_DIRFD
18710679 82
0e985513
JG
83/*
84 * Special inode number reserved to represent the "current working directory".
85 * ino_t is spec'ed as being an unsigned integral type.
86 */
87#define RESERVED_AT_FDCWD_INO \
88 ({ \
89 uint64_t reserved_val; \
90 switch (sizeof(ino_t)) { \
91 case 4: \
92 reserved_val = UINT32_MAX; \
93 break; \
94 case 8: \
95 reserved_val = UINT64_MAX; \
96 break; \
97 default: \
98 abort(); \
99 } \
100 (ino_t) reserved_val; \
101 })
102
cbf53d23 103struct lttng_directory_handle *lttng_directory_handle_create(const char *path)
fd774fc6 104{
28ab034a 105 lttng_directory_handle cwd_handle{};
740da7d5 106 cwd_handle.dirfd = AT_FDCWD;
fd774fc6
JG
107
108 /* Open a handle to the CWD if NULL is passed. */
cbf53d23 109 return lttng_directory_handle_create_from_handle(path, &cwd_handle);
fd774fc6
JG
110}
111
28ab034a
JG
112struct lttng_directory_handle *
113lttng_directory_handle_create_from_handle(const char *path,
114 const struct lttng_directory_handle *ref_handle)
18710679 115{
cbf53d23 116 int dirfd;
cd9adb8b 117 struct lttng_directory_handle *handle = nullptr;
18710679
JG
118
119 if (!path) {
cbf53d23 120 handle = lttng_directory_handle_copy(ref_handle);
18710679
JG
121 goto end;
122 }
fd774fc6
JG
123 if (!*path) {
124 ERR("Failed to initialize directory handle: provided path is an empty string");
fd774fc6
JG
125 goto end;
126 }
cbf53d23
JG
127
128 dirfd = openat(ref_handle->dirfd, path, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
129 if (dirfd == -1) {
18710679
JG
130 PERROR("Failed to initialize directory handle to \"%s\"", path);
131 goto end;
132 }
cbf53d23
JG
133
134 handle = lttng_directory_handle_create_from_dirfd(dirfd);
135 if (!handle) {
136 goto error_close;
137 }
18710679 138end:
cbf53d23
JG
139 return handle;
140error_close:
141 if (close(dirfd)) {
142 PERROR("Failed to close directory file descriptor");
143 }
cd9adb8b 144 return nullptr;
18710679
JG
145}
146
28ab034a 147struct lttng_directory_handle *lttng_directory_handle_create_from_dirfd(int dirfd)
18710679 148{
0e985513 149 int ret;
64803277 150 struct lttng_directory_handle *handle = zmalloc<lttng_directory_handle>();
0e985513 151 struct stat stat_buf;
cbf53d23
JG
152
153 if (!handle) {
154 goto end;
155 }
0e985513
JG
156
157 if (dirfd != AT_FDCWD) {
158 ret = fstat(dirfd, &stat_buf);
159 if (ret) {
160 PERROR("Failed to fstat directory file descriptor %i", dirfd);
161 lttng_directory_handle_release(&handle->ref);
cd9adb8b 162 handle = nullptr;
b2081a0f 163 goto end;
0e985513
JG
164 }
165 } else {
166 handle->directory_inode = RESERVED_AT_FDCWD_INO;
167 }
18710679 168 handle->dirfd = dirfd;
cbf53d23
JG
169 urcu_ref_init(&handle->ref);
170end:
171 return handle;
18710679
JG
172}
173
28ab034a 174static void lttng_directory_handle_release(struct urcu_ref *ref)
18710679
JG
175{
176 int ret;
cbf53d23 177 struct lttng_directory_handle *handle =
28ab034a 178 lttng::utils::container_of(ref, &lttng_directory_handle::ref);
18710679 179
dd95933f
JG
180 if (handle->destroy_cb) {
181 handle->destroy_cb(handle, handle->destroy_cb_data);
182 }
183
46307ffe
JG
184 if (handle->dirfd == AT_FDCWD || handle->dirfd == -1) {
185 goto end;
18710679
JG
186 }
187 ret = close(handle->dirfd);
188 if (ret == -1) {
189 PERROR("Failed to close directory file descriptor of directory handle");
190 }
46307ffe
JG
191end:
192 lttng_directory_handle_invalidate(handle);
cbf53d23 193 free(handle);
18710679
JG
194}
195
28ab034a
JG
196struct lttng_directory_handle *
197lttng_directory_handle_copy(const struct lttng_directory_handle *handle)
578e21bd 198{
cd9adb8b 199 struct lttng_directory_handle *new_handle = nullptr;
578e21bd
JG
200
201 if (handle->dirfd == AT_FDCWD) {
cbf53d23 202 new_handle = lttng_directory_handle_create_from_dirfd(AT_FDCWD);
578e21bd 203 } else {
cbf53d23
JG
204 const int new_dirfd = dup(handle->dirfd);
205
206 if (new_dirfd == -1) {
207 PERROR("Failed to duplicate directory file descriptor of directory handle");
208 goto end;
209 }
28ab034a 210 new_handle = lttng_directory_handle_create_from_dirfd(new_dirfd);
cbf53d23
JG
211 if (!new_handle && close(new_dirfd)) {
212 PERROR("Failed to close directory file descriptor of directory handle");
578e21bd
JG
213 }
214 }
cbf53d23
JG
215end:
216 return new_handle;
578e21bd
JG
217}
218
0e985513 219bool lttng_directory_handle_equals(const struct lttng_directory_handle *lhs,
28ab034a 220 const struct lttng_directory_handle *rhs)
0e985513
JG
221{
222 return lhs->directory_inode == rhs->directory_inode;
223}
224
28ab034a 225static void lttng_directory_handle_invalidate(struct lttng_directory_handle *handle)
46307ffe
JG
226{
227 handle->dirfd = -1;
228}
229
18710679 230int lttng_directory_handle_stat(const struct lttng_directory_handle *handle,
28ab034a
JG
231 const char *path,
232 struct stat *st)
18710679
JG
233{
234 return fstatat(handle->dirfd, path, st, 0);
235}
236
28ab034a 237bool lttng_directory_handle_uses_fd(const struct lttng_directory_handle *handle)
9a1a997f
JG
238{
239 return handle->dirfd != AT_FDCWD;
240}
241
28ab034a
JG
242static int lttng_directory_handle_mkdir(const struct lttng_directory_handle *handle,
243 const char *path,
244 mode_t mode)
18710679
JG
245{
246 return mkdirat(handle->dirfd, path, mode);
247}
248
28ab034a
JG
249static int lttng_directory_handle_open(const struct lttng_directory_handle *handle,
250 const char *filename,
251 int flags,
252 mode_t mode)
2912cead
JG
253{
254 return openat(handle->dirfd, filename, flags, mode);
255}
256
28ab034a
JG
257static int _run_as_open(const struct lttng_directory_handle *handle,
258 const char *filename,
259 int flags,
260 mode_t mode,
261 uid_t uid,
262 gid_t gid)
2912cead
JG
263{
264 return run_as_openat(handle->dirfd, filename, flags, mode, uid, gid);
265}
266
28ab034a
JG
267static int _run_as_unlink(const struct lttng_directory_handle *handle,
268 const char *filename,
269 uid_t uid,
270 gid_t gid)
2912cead
JG
271{
272 return run_as_unlinkat(handle->dirfd, filename, uid, gid);
273}
274
28ab034a
JG
275static int lttng_directory_handle_unlink(const struct lttng_directory_handle *handle,
276 const char *filename)
2912cead
JG
277{
278 return unlinkat(handle->dirfd, filename, 0);
279}
280
28ab034a
JG
281static int _run_as_mkdir(const struct lttng_directory_handle *handle,
282 const char *path,
283 mode_t mode,
284 uid_t uid,
285 gid_t gid)
18710679
JG
286{
287 return run_as_mkdirat(handle->dirfd, path, mode, uid, gid);
288}
289
28ab034a
JG
290static int _run_as_mkdir_recursive(const struct lttng_directory_handle *handle,
291 const char *path,
292 mode_t mode,
293 uid_t uid,
294 gid_t gid)
18710679
JG
295{
296 return run_as_mkdirat_recursive(handle->dirfd, path, mode, uid, gid);
297}
298
28ab034a
JG
299static int _lttng_directory_handle_rename(const struct lttng_directory_handle *old_handle,
300 const char *old_name,
301 const struct lttng_directory_handle *new_handle,
302 const char *new_name)
93bed9fe 303{
28ab034a 304 return renameat(old_handle->dirfd, old_name, new_handle->dirfd, new_name);
93bed9fe
JG
305}
306
28ab034a
JG
307static int _run_as_rename(const struct lttng_directory_handle *old_handle,
308 const char *old_name,
309 const struct lttng_directory_handle *new_handle,
310 const char *new_name,
311 uid_t uid,
312 gid_t gid)
93bed9fe 313{
28ab034a 314 return run_as_renameat(old_handle->dirfd, old_name, new_handle->dirfd, new_name, uid, gid);
93bed9fe
JG
315}
316
28ab034a
JG
317static DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle *handle,
318 const char *path)
93bed9fe 319{
cd9adb8b 320 DIR *dir_stream = nullptr;
93bed9fe
JG
321 int fd = openat(handle->dirfd, path, O_RDONLY);
322
323 if (fd < 0) {
324 goto end;
325 }
326
327 dir_stream = fdopendir(fd);
328 if (!dir_stream) {
329 int ret;
330
331 PERROR("Failed to open directory stream");
332 ret = close(fd);
333 if (ret) {
334 PERROR("Failed to close file descriptor to %s", path);
335 }
336 goto end;
337 }
338
339end:
340 return dir_stream;
341}
342
28ab034a
JG
343static int lttng_directory_handle_rmdir(const struct lttng_directory_handle *handle,
344 const char *name)
93bed9fe 345{
dbc179cb
FD
346 int ret = unlinkat(handle->dirfd, name, AT_REMOVEDIR);
347 if (ret) {
348 PERROR("Failed to remove directory `%s`", name);
349 }
350
351 return ret;
93bed9fe
JG
352}
353
28ab034a
JG
354static int
355_run_as_rmdir(const struct lttng_directory_handle *handle, const char *name, uid_t uid, gid_t gid)
93bed9fe
JG
356{
357 return run_as_rmdirat(handle->dirfd, name, uid, gid);
358}
359
28ab034a
JG
360static int _run_as_rmdir_recursive(const struct lttng_directory_handle *handle,
361 const char *name,
362 uid_t uid,
363 gid_t gid,
364 int flags)
93bed9fe 365{
f75c5439 366 return run_as_rmdirat_recursive(handle->dirfd, name, uid, gid, flags);
93bed9fe
JG
367}
368
4fb28dfc 369#else /* HAVE_DIRFD */
18710679 370
28ab034a
JG
371static int get_full_path(const struct lttng_directory_handle *handle,
372 const char *subdirectory,
373 char *fullpath,
374 size_t size)
fd774fc6
JG
375{
376 int ret;
28ab034a
JG
377 const bool subdirectory_is_absolute = subdirectory && *subdirectory == '/';
378 const char *const base = subdirectory_is_absolute ? subdirectory : handle->base_path;
379 const char *const end = subdirectory && !subdirectory_is_absolute ? subdirectory : NULL;
93bed9fe
JG
380 const size_t base_len = strlen(base);
381 const size_t end_len = end ? strlen(end) : 0;
382 const bool add_separator_slash = end && base[base_len - 1] != '/';
383 const bool add_trailing_slash = end && end[end_len - 1] != '/';
384
28ab034a
JG
385 ret = snprintf(fullpath,
386 size,
387 "%s%s%s%s",
388 base,
389 add_separator_slash ? "/" : "",
390 end ? end : "",
391 add_trailing_slash ? "/" : "");
fd774fc6
JG
392 if (ret == -1 || ret >= size) {
393 ERR("Failed to format subdirectory from directory handle");
394 ret = -1;
93bed9fe 395 goto end;
fd774fc6
JG
396 }
397 ret = 0;
93bed9fe 398end:
fd774fc6
JG
399 return ret;
400}
401
28ab034a 402static struct lttng_directory_handle *_lttng_directory_handle_create(char *path)
cbf53d23 403{
64803277 404 struct lttng_directory_handle *handle = zmalloc<lttng_directory_handle>();
cbf53d23
JG
405
406 if (!handle) {
407 goto end;
408 }
409 urcu_ref_init(&handle->ref);
410 handle->base_path = path;
411end:
412 return handle;
413}
414
28ab034a 415struct lttng_directory_handle *lttng_directory_handle_create(const char *path)
18710679
JG
416{
417 int ret;
93bed9fe 418 const char *cwd = "";
fd774fc6
JG
419 size_t cwd_len, path_len;
420 char cwd_buf[LTTNG_PATH_MAX] = {};
421 char handle_buf[LTTNG_PATH_MAX] = {};
cbf53d23 422 struct lttng_directory_handle *new_handle = NULL;
93bed9fe 423 bool add_cwd_slash = false, add_trailing_slash = false;
fd774fc6
JG
424 const struct lttng_directory_handle cwd_handle = {
425 .base_path = handle_buf,
426 };
427
fd774fc6 428 path_len = path ? strlen(path) : 0;
fd774fc6 429 add_trailing_slash = path && path[path_len - 1] != '/';
93bed9fe
JG
430 if (!path || (path && *path != '/')) {
431 cwd = getcwd(cwd_buf, sizeof(cwd_buf));
432 if (!cwd) {
433 PERROR("Failed to initialize directory handle, can't get current working directory");
434 ret = -1;
435 goto end;
436 }
437 cwd_len = strlen(cwd);
438 if (cwd_len == 0) {
439 ERR("Failed to initialize directory handle, current working directory path has a length of 0");
440 ret = -1;
441 goto end;
442 }
443 add_cwd_slash = cwd[cwd_len - 1] != '/';
444 }
fd774fc6 445
28ab034a
JG
446 ret = snprintf(handle_buf,
447 sizeof(handle_buf),
448 "%s%s%s%s",
449 cwd,
450 add_cwd_slash ? "/" : "",
451 path ?: "",
452 add_trailing_slash ? "/" : "");
fd774fc6
JG
453 if (ret == -1 || ret >= LTTNG_PATH_MAX) {
454 ERR("Failed to initialize directory handle, failed to format directory path");
455 goto end;
18710679 456 }
93bed9fe 457
cbf53d23 458 new_handle = lttng_directory_handle_create_from_handle(path, &cwd_handle);
fd774fc6 459end:
cbf53d23 460 return new_handle;
fd774fc6 461}
18710679 462
28ab034a
JG
463struct lttng_directory_handle *
464lttng_directory_handle_create_from_handle(const char *path,
465 const struct lttng_directory_handle *ref_handle)
fd774fc6
JG
466{
467 int ret;
468 size_t path_len, handle_path_len;
469 bool add_trailing_slash;
470 struct stat stat_buf;
cbf53d23
JG
471 struct lttng_directory_handle *new_handle = NULL;
472 char *new_path = NULL;
18710679 473
a0377dfe 474 LTTNG_ASSERT(ref_handle && ref_handle->base_path);
fd774fc6 475
cbf53d23 476 ret = lttng_directory_handle_stat(ref_handle, path, &stat_buf);
fd774fc6
JG
477 if (ret == -1) {
478 PERROR("Failed to create directory handle");
479 goto end;
480 } else if (!S_ISDIR(stat_buf.st_mode)) {
481 char full_path[LTTNG_PATH_MAX];
482
483 /* Best effort for logging purposes. */
28ab034a 484 ret = get_full_path(ref_handle, path, full_path, sizeof(full_path));
fd774fc6
JG
485 if (ret) {
486 full_path[0] = '\0';
18710679 487 }
fd774fc6 488
28ab034a 489 ERR("Failed to initialize directory handle to \"%s\": not a directory", full_path);
fd774fc6
JG
490 goto end;
491 }
492 if (!path) {
cbf53d23 493 new_handle = lttng_directory_handle_copy(ref_handle);
fd774fc6
JG
494 goto end;
495 }
496
497 path_len = strlen(path);
498 if (path_len == 0) {
499 ERR("Failed to initialize directory handle: provided path is an empty string");
500 ret = -1;
501 goto end;
502 }
503 if (*path == '/') {
cbf53d23
JG
504 new_path = strdup(path);
505 if (!new_path) {
506 goto end;
507 }
508 /* Takes ownership of new_path. */
509 new_handle = _lttng_directory_handle_create(new_path);
510 new_path = NULL;
fd774fc6 511 goto end;
18710679
JG
512 }
513
fd774fc6
JG
514 add_trailing_slash = path[path_len - 1] != '/';
515
28ab034a 516 handle_path_len = strlen(ref_handle->base_path) + path_len + !!add_trailing_slash;
18710679
JG
517 if (handle_path_len >= LTTNG_PATH_MAX) {
518 ERR("Failed to initialize directory handle as the resulting path's length (%zu bytes) exceeds the maximal allowed length (%d bytes)",
28ab034a
JG
519 handle_path_len,
520 LTTNG_PATH_MAX);
18710679
JG
521 goto end;
522 }
64803277 523 new_path = zmalloc<char>(handle_path_len);
cbf53d23 524 if (!new_path) {
18710679 525 PERROR("Failed to initialize directory handle");
18710679
JG
526 goto end;
527 }
528
28ab034a
JG
529 ret = sprintf(new_handle->base_path,
530 "%s%s%s",
531 ref_handle->base_path,
532 path,
533 add_trailing_slash ? "/" : "");
18710679
JG
534 if (ret == -1 || ret >= handle_path_len) {
535 ERR("Failed to initialize directory handle: path formatting failed");
18710679
JG
536 goto end;
537 }
cbf53d23
JG
538 new_handle = _lttng_directory_handle_create(new_path);
539 new_path = NULL;
18710679 540end:
cbf53d23
JG
541 free(new_path);
542 return new_handle;
18710679
JG
543}
544
28ab034a 545struct lttng_directory_handle *lttng_directory_handle_create_from_dirfd(int dirfd)
18710679 546{
a0377dfe 547 LTTNG_ASSERT(dirfd == AT_FDCWD);
cbf53d23 548 return lttng_directory_handle_create(NULL);
18710679
JG
549}
550
28ab034a 551static void lttng_directory_handle_release(struct urcu_ref *ref)
18710679 552{
cbf53d23 553 struct lttng_directory_handle *handle =
28ab034a 554 lttng::utils::container_of(ref, &lttng_directory_handle::ref);
cbf53d23 555
18710679 556 free(handle->base_path);
46307ffe 557 lttng_directory_handle_invalidate(handle);
cbf53d23 558 free(handle);
18710679
JG
559}
560
28ab034a
JG
561struct lttng_directory_handle *
562lttng_directory_handle_copy(const struct lttng_directory_handle *handle)
578e21bd 563{
cbf53d23
JG
564 struct lttng_directory_handle *new_handle = NULL;
565 char *new_path = NULL;
566
567 if (handle->base_path) {
568 new_path = strdup(handle->base_path);
569 if (!new_path) {
570 goto end;
571 }
572 }
573 new_handle = _lttng_directory_handle_create(new_path);
574end:
575 return new_handle;
578e21bd
JG
576}
577
0e985513 578bool lttng_directory_handle_equals(const struct lttng_directory_handle *lhs,
28ab034a 579 const struct lttng_directory_handle *rhs)
0e985513 580{
0b1b49f9 581 return strcmp(lhs->base_path, rhs->base_path) == 0;
0e985513
JG
582}
583
28ab034a 584static void lttng_directory_handle_invalidate(struct lttng_directory_handle *handle)
46307ffe
JG
585{
586 handle->base_path = NULL;
587}
588
18710679 589int lttng_directory_handle_stat(const struct lttng_directory_handle *handle,
28ab034a
JG
590 const char *subdirectory,
591 struct stat *st)
18710679
JG
592{
593 int ret;
594 char fullpath[LTTNG_PATH_MAX];
595
596 ret = get_full_path(handle, subdirectory, fullpath, sizeof(fullpath));
597 if (ret) {
598 errno = ENOMEM;
599 goto end;
600 }
601
602 ret = stat(fullpath, st);
603end:
604 return ret;
605}
606
28ab034a 607bool lttng_directory_handle_uses_fd(const struct lttng_directory_handle *handle)
9a1a997f
JG
608{
609 return false;
610}
611
28ab034a
JG
612static int lttng_directory_handle_mkdir(const struct lttng_directory_handle *handle,
613 const char *subdirectory,
614 mode_t mode)
18710679
JG
615{
616 int ret;
617 char fullpath[LTTNG_PATH_MAX];
618
619 ret = get_full_path(handle, subdirectory, fullpath, sizeof(fullpath));
620 if (ret) {
621 errno = ENOMEM;
622 goto end;
623 }
624
625 ret = mkdir(fullpath, mode);
626end:
627 return ret;
628}
629
28ab034a
JG
630static int lttng_directory_handle_open(const struct lttng_directory_handle *handle,
631 const char *filename,
632 int flags,
633 mode_t mode)
2912cead
JG
634{
635 int ret;
636 char fullpath[LTTNG_PATH_MAX];
637
638 ret = get_full_path(handle, filename, fullpath, sizeof(fullpath));
639 if (ret) {
640 errno = ENOMEM;
641 goto end;
642 }
643
644 ret = open(fullpath, flags, mode);
645end:
646 return ret;
647}
648
28ab034a
JG
649static int lttng_directory_handle_unlink(const struct lttng_directory_handle *handle,
650 const char *filename)
2912cead
JG
651{
652 int ret;
653 char fullpath[LTTNG_PATH_MAX];
654
655 ret = get_full_path(handle, filename, fullpath, sizeof(fullpath));
656 if (ret) {
657 errno = ENOMEM;
658 goto end;
659 }
660
661 ret = unlink(fullpath);
662end:
663 return ret;
664}
665
28ab034a
JG
666static int _run_as_mkdir(const struct lttng_directory_handle *handle,
667 const char *path,
668 mode_t mode,
669 uid_t uid,
670 gid_t gid)
18710679
JG
671{
672 int ret;
673 char fullpath[LTTNG_PATH_MAX];
674
675 ret = get_full_path(handle, path, fullpath, sizeof(fullpath));
676 if (ret) {
677 errno = ENOMEM;
678 goto end;
679 }
680
681 ret = run_as_mkdir(fullpath, mode, uid, gid);
682end:
683 return ret;
684}
685
28ab034a
JG
686static int _run_as_open(const struct lttng_directory_handle *handle,
687 const char *filename,
688 int flags,
689 mode_t mode,
690 uid_t uid,
691 gid_t gid)
2912cead
JG
692{
693 int ret;
694 char fullpath[LTTNG_PATH_MAX];
695
696 ret = get_full_path(handle, filename, fullpath, sizeof(fullpath));
697 if (ret) {
698 errno = ENOMEM;
699 goto end;
700 }
701
702 ret = run_as_open(fullpath, flags, mode, uid, gid);
703end:
704 return ret;
705}
706
28ab034a
JG
707static int _run_as_unlink(const struct lttng_directory_handle *handle,
708 const char *filename,
709 uid_t uid,
710 gid_t gid)
2912cead
JG
711{
712 int ret;
713 char fullpath[LTTNG_PATH_MAX];
714
715 ret = get_full_path(handle, filename, fullpath, sizeof(fullpath));
716 if (ret) {
717 errno = ENOMEM;
718 goto end;
719 }
720
721 ret = run_as_unlink(fullpath, uid, gid);
722end:
723 return ret;
724}
725
28ab034a
JG
726static int _run_as_mkdir_recursive(const struct lttng_directory_handle *handle,
727 const char *path,
728 mode_t mode,
729 uid_t uid,
730 gid_t gid)
18710679
JG
731{
732 int ret;
733 char fullpath[LTTNG_PATH_MAX];
734
735 ret = get_full_path(handle, path, fullpath, sizeof(fullpath));
736 if (ret) {
737 errno = ENOMEM;
738 goto end;
739 }
740
741 ret = run_as_mkdir_recursive(fullpath, mode, uid, gid);
742end:
743 return ret;
744}
745
28ab034a
JG
746static int _lttng_directory_handle_rename(const struct lttng_directory_handle *old_handle,
747 const char *old_name,
748 const struct lttng_directory_handle *new_handle,
749 const char *new_name)
93bed9fe
JG
750{
751 int ret;
752 char old_fullpath[LTTNG_PATH_MAX];
753 char new_fullpath[LTTNG_PATH_MAX];
754
28ab034a 755 ret = get_full_path(old_handle, old_name, old_fullpath, sizeof(old_fullpath));
93bed9fe
JG
756 if (ret) {
757 errno = ENOMEM;
758 goto end;
759 }
28ab034a 760 ret = get_full_path(new_handle, new_name, new_fullpath, sizeof(new_fullpath));
93bed9fe
JG
761 if (ret) {
762 errno = ENOMEM;
763 goto end;
764 }
765
766 ret = rename(old_fullpath, new_fullpath);
767end:
768 return ret;
769}
770
28ab034a
JG
771static int _run_as_rename(const struct lttng_directory_handle *old_handle,
772 const char *old_name,
773 const struct lttng_directory_handle *new_handle,
774 const char *new_name,
775 uid_t uid,
776 gid_t gid)
93bed9fe
JG
777{
778 int ret;
779 char old_fullpath[LTTNG_PATH_MAX];
780 char new_fullpath[LTTNG_PATH_MAX];
781
28ab034a 782 ret = get_full_path(old_handle, old_name, old_fullpath, sizeof(old_fullpath));
93bed9fe
JG
783 if (ret) {
784 errno = ENOMEM;
785 goto end;
786 }
28ab034a 787 ret = get_full_path(new_handle, new_name, new_fullpath, sizeof(new_fullpath));
93bed9fe
JG
788 if (ret) {
789 errno = ENOMEM;
790 goto end;
791 }
792
793 ret = run_as_rename(old_fullpath, new_fullpath, uid, gid);
794end:
795 return ret;
796}
797
28ab034a
JG
798static DIR *lttng_directory_handle_opendir(const struct lttng_directory_handle *handle,
799 const char *path)
93bed9fe
JG
800{
801 int ret;
802 DIR *dir_stream = NULL;
803 char fullpath[LTTNG_PATH_MAX];
804
805 ret = get_full_path(handle, path, fullpath, sizeof(fullpath));
806 if (ret) {
807 errno = ENOMEM;
808 goto end;
809 }
810
811 dir_stream = opendir(fullpath);
812end:
813 return dir_stream;
814}
815
28ab034a
JG
816static int lttng_directory_handle_rmdir(const struct lttng_directory_handle *handle,
817 const char *name)
93bed9fe
JG
818{
819 int ret;
820 char fullpath[LTTNG_PATH_MAX];
821
822 ret = get_full_path(handle, name, fullpath, sizeof(fullpath));
823 if (ret) {
824 errno = ENOMEM;
825 goto end;
826 }
827
828 ret = rmdir(fullpath);
829end:
830 return ret;
831}
832
28ab034a
JG
833static int
834_run_as_rmdir(const struct lttng_directory_handle *handle, const char *name, uid_t uid, gid_t gid)
93bed9fe
JG
835{
836 int ret;
837 char fullpath[LTTNG_PATH_MAX];
838
839 ret = get_full_path(handle, name, fullpath, sizeof(fullpath));
840 if (ret) {
841 errno = ENOMEM;
842 goto end;
843 }
844
845 ret = run_as_rmdir(fullpath, uid, gid);
846end:
847 return ret;
848}
849
28ab034a
JG
850static int _run_as_rmdir_recursive(const struct lttng_directory_handle *handle,
851 const char *name,
852 uid_t uid,
853 gid_t gid,
854 int flags)
93bed9fe
JG
855{
856 int ret;
857 char fullpath[LTTNG_PATH_MAX];
858
859 ret = get_full_path(handle, name, fullpath, sizeof(fullpath));
860 if (ret) {
861 errno = ENOMEM;
862 goto end;
863 }
864
f75c5439 865 ret = run_as_rmdir_recursive(fullpath, uid, gid, flags);
93bed9fe
JG
866end:
867 return ret;
868}
869
4fb28dfc 870#endif /* HAVE_DIRFD */
18710679 871
93bed9fe
JG
872/* Common implementation. */
873
18710679
JG
874/*
875 * On some filesystems (e.g. nfs), mkdir will validate access rights before
876 * checking for the existence of the path element. This means that on a setup
877 * where "/home/" is a mounted NFS share, and running as an unpriviledged user,
878 * recursively creating a path of the form "/home/my_user/trace/" will fail with
879 * EACCES on mkdir("/home", ...).
880 *
881 * Checking the path for existence allows us to work around this behaviour.
882 */
28ab034a
JG
883static int create_directory_check_exists(const struct lttng_directory_handle *handle,
884 const char *path,
885 mode_t mode)
18710679
JG
886{
887 int ret = 0;
888 struct stat st;
889
890 ret = lttng_directory_handle_stat(handle, path, &st);
891 if (ret == 0) {
892 if (S_ISDIR(st.st_mode)) {
893 /* Directory exists, skip. */
894 goto end;
895 } else {
896 /* Exists, but is not a directory. */
897 errno = ENOTDIR;
898 ret = -1;
899 goto end;
900 }
93bed9fe
JG
901 } else if (errno != ENOENT) {
902 goto end;
18710679
JG
903 }
904
905 /*
906 * Let mkdir handle other errors as the caller expects mkdir
907 * semantics.
908 */
909 ret = lttng_directory_handle_mkdir(handle, path, mode);
910end:
911 return ret;
912}
913
28ab034a
JG
914static int create_directory_recursive(const struct lttng_directory_handle *handle,
915 const char *path,
916 mode_t mode)
18710679
JG
917{
918 char *p, tmp[LTTNG_PATH_MAX];
919 size_t len;
920 int ret;
921
a0377dfe 922 LTTNG_ASSERT(path);
18710679
JG
923
924 ret = lttng_strncpy(tmp, path, sizeof(tmp));
925 if (ret) {
926 ERR("Failed to create directory: provided path's length (%zu bytes) exceeds the maximal allowed length (%zu bytes)",
28ab034a
JG
927 strlen(path) + 1,
928 sizeof(tmp));
18710679
JG
929 goto error;
930 }
931
932 len = strlen(path);
933 if (tmp[len - 1] == '/') {
934 tmp[len - 1] = 0;
935 }
936
937 for (p = tmp + 1; *p; p++) {
938 if (*p == '/') {
939 *p = 0;
28ab034a
JG
940 if (tmp[strlen(tmp) - 1] == '.' && tmp[strlen(tmp) - 2] == '.' &&
941 tmp[strlen(tmp) - 3] == '/') {
942 ERR("Using '/../' is not permitted in the trace path (%s)", tmp);
18710679
JG
943 ret = -1;
944 goto error;
945 }
946 ret = create_directory_check_exists(handle, tmp, mode);
947 if (ret < 0) {
948 if (errno != EACCES) {
28ab034a 949 PERROR("Failed to create directory \"%s\"", path);
18710679
JG
950 ret = -errno;
951 goto error;
952 }
953 }
954 *p = '/';
955 }
956 }
957
958 ret = create_directory_check_exists(handle, tmp, mode);
959 if (ret < 0) {
960 PERROR("mkdirat recursive last element");
961 ret = -errno;
962 }
963error:
964 return ret;
965}
966
cbf53d23
JG
967bool lttng_directory_handle_get(struct lttng_directory_handle *handle)
968{
969 return urcu_ref_get_unless_zero(&handle->ref);
970}
971
cbf53d23
JG
972void lttng_directory_handle_put(struct lttng_directory_handle *handle)
973{
974 if (!handle) {
975 return;
976 }
a0377dfe 977 LTTNG_ASSERT(handle->ref.refcount);
cbf53d23
JG
978 urcu_ref_put(&handle->ref, lttng_directory_handle_release);
979}
980
28ab034a
JG
981int lttng_directory_handle_create_subdirectory_as_user(const struct lttng_directory_handle *handle,
982 const char *subdirectory,
983 mode_t mode,
984 const struct lttng_credentials *creds)
18710679
JG
985{
986 int ret;
987
988 if (!creds) {
989 /* Run as current user. */
28ab034a 990 ret = create_directory_check_exists(handle, subdirectory, mode);
18710679 991 } else {
28ab034a
JG
992 ret = _run_as_mkdir(handle,
993 subdirectory,
994 mode,
995 lttng_credentials_get_uid(creds),
996 lttng_credentials_get_gid(creds));
18710679
JG
997 }
998
999 return ret;
1000}
1001
18710679 1002int lttng_directory_handle_create_subdirectory_recursive_as_user(
28ab034a
JG
1003 const struct lttng_directory_handle *handle,
1004 const char *subdirectory_path,
1005 mode_t mode,
1006 const struct lttng_credentials *creds)
18710679
JG
1007{
1008 int ret;
1009
1010 if (!creds) {
1011 /* Run as current user. */
28ab034a 1012 ret = create_directory_recursive(handle, subdirectory_path, mode);
18710679 1013 } else {
28ab034a
JG
1014 ret = _run_as_mkdir_recursive(handle,
1015 subdirectory_path,
1016 mode,
1017 lttng_credentials_get_uid(creds),
1018 lttng_credentials_get_gid(creds));
18710679
JG
1019 }
1020
1021 return ret;
1022}
1023
28ab034a
JG
1024int lttng_directory_handle_create_subdirectory(const struct lttng_directory_handle *handle,
1025 const char *subdirectory,
1026 mode_t mode)
18710679 1027{
cd9adb8b
JG
1028 return lttng_directory_handle_create_subdirectory_as_user(
1029 handle, subdirectory, mode, nullptr);
18710679
JG
1030}
1031
18710679 1032int lttng_directory_handle_create_subdirectory_recursive(
28ab034a 1033 const struct lttng_directory_handle *handle, const char *subdirectory_path, mode_t mode)
18710679
JG
1034{
1035 return lttng_directory_handle_create_subdirectory_recursive_as_user(
cd9adb8b 1036 handle, subdirectory_path, mode, nullptr);
18710679 1037}
2912cead 1038
28ab034a
JG
1039int lttng_directory_handle_open_file_as_user(const struct lttng_directory_handle *handle,
1040 const char *filename,
1041 int flags,
1042 mode_t mode,
1043 const struct lttng_credentials *creds)
2912cead
JG
1044{
1045 int ret;
1046
1047 if (!creds) {
1048 /* Run as current user. */
28ab034a 1049 ret = lttng_directory_handle_open(handle, filename, flags, mode);
2912cead 1050 } else {
28ab034a
JG
1051 ret = _run_as_open(handle,
1052 filename,
1053 flags,
1054 mode,
1055 lttng_credentials_get_uid(creds),
1056 lttng_credentials_get_gid(creds));
2912cead
JG
1057 }
1058 return ret;
1059}
1060
28ab034a
JG
1061int lttng_directory_handle_open_file(const struct lttng_directory_handle *handle,
1062 const char *filename,
1063 int flags,
1064 mode_t mode)
2912cead 1065{
cd9adb8b 1066 return lttng_directory_handle_open_file_as_user(handle, filename, flags, mode, nullptr);
2912cead
JG
1067}
1068
28ab034a
JG
1069int lttng_directory_handle_unlink_file_as_user(const struct lttng_directory_handle *handle,
1070 const char *filename,
1071 const struct lttng_credentials *creds)
2912cead
JG
1072{
1073 int ret;
1074
1075 if (!creds) {
1076 /* Run as current user. */
1077 ret = lttng_directory_handle_unlink(handle, filename);
1078 } else {
28ab034a
JG
1079 ret = _run_as_unlink(handle,
1080 filename,
1081 lttng_credentials_get_uid(creds),
1082 lttng_credentials_get_gid(creds));
2912cead
JG
1083 }
1084 return ret;
1085}
1086
28ab034a
JG
1087int lttng_directory_handle_unlink_file(const struct lttng_directory_handle *handle,
1088 const char *filename)
2912cead 1089{
cd9adb8b 1090 return lttng_directory_handle_unlink_file_as_user(handle, filename, nullptr);
2912cead 1091}
93bed9fe 1092
28ab034a
JG
1093int lttng_directory_handle_rename(const struct lttng_directory_handle *old_handle,
1094 const char *old_name,
1095 const struct lttng_directory_handle *new_handle,
1096 const char *new_name)
93bed9fe 1097{
28ab034a 1098 return lttng_directory_handle_rename_as_user(
cd9adb8b 1099 old_handle, old_name, new_handle, new_name, nullptr);
93bed9fe
JG
1100}
1101
28ab034a
JG
1102int lttng_directory_handle_rename_as_user(const struct lttng_directory_handle *old_handle,
1103 const char *old_name,
1104 const struct lttng_directory_handle *new_handle,
1105 const char *new_name,
1106 const struct lttng_credentials *creds)
93bed9fe
JG
1107{
1108 int ret;
1109
1110 if (!creds) {
1111 /* Run as current user. */
28ab034a 1112 ret = _lttng_directory_handle_rename(old_handle, old_name, new_handle, new_name);
93bed9fe 1113 } else {
28ab034a
JG
1114 ret = _run_as_rename(old_handle,
1115 old_name,
1116 new_handle,
1117 new_name,
1118 lttng_credentials_get_uid(creds),
1119 lttng_credentials_get_gid(creds));
93bed9fe
JG
1120 }
1121 return ret;
1122}
1123
28ab034a
JG
1124int lttng_directory_handle_remove_subdirectory(const struct lttng_directory_handle *handle,
1125 const char *name)
93bed9fe 1126{
cd9adb8b 1127 return lttng_directory_handle_remove_subdirectory_as_user(handle, name, nullptr);
93bed9fe
JG
1128}
1129
28ab034a
JG
1130int lttng_directory_handle_remove_subdirectory_as_user(const struct lttng_directory_handle *handle,
1131 const char *name,
1132 const struct lttng_credentials *creds)
93bed9fe
JG
1133{
1134 int ret;
1135
1136 if (!creds) {
1137 /* Run as current user. */
1138 ret = lttng_directory_handle_rmdir(handle, name);
1139 } else {
28ab034a
JG
1140 ret = _run_as_rmdir(handle,
1141 name,
1142 lttng_credentials_get_uid(creds),
1143 lttng_credentials_get_gid(creds));
93bed9fe
JG
1144 }
1145 return ret;
1146}
1147
f1494934 1148namespace {
93bed9fe 1149struct rmdir_frame {
f75c5439 1150 ssize_t parent_frame_idx;
93bed9fe 1151 DIR *dir;
f75c5439 1152 bool empty;
93bed9fe
JG
1153 /* Size including '\0'. */
1154 size_t path_size;
1155};
f1494934 1156} /* namespace */
93bed9fe 1157
28ab034a 1158static void rmdir_frame_fini(void *data)
93bed9fe 1159{
41066401 1160 int ret;
740da7d5 1161 struct rmdir_frame *frame = (rmdir_frame *) data;
93bed9fe 1162
41066401
FD
1163 ret = closedir(frame->dir);
1164 if (ret == -1) {
1165 PERROR("Failed to close directory stream");
1166 }
93bed9fe
JG
1167}
1168
28ab034a
JG
1169static int
1170remove_directory_recursive(const struct lttng_directory_handle *handle, const char *path, int flags)
93bed9fe
JG
1171{
1172 int ret;
1173 struct lttng_dynamic_array frames;
1174 size_t current_frame_idx = 0;
1175 struct rmdir_frame initial_frame = {
f75c5439 1176 .parent_frame_idx = -1,
93bed9fe 1177 .dir = lttng_directory_handle_opendir(handle, path),
f75c5439 1178 .empty = true,
93bed9fe
JG
1179 .path_size = strlen(path) + 1,
1180 };
1181 struct lttng_dynamic_buffer current_path;
1182 const char separator = '/';
1183
1184 lttng_dynamic_buffer_init(&current_path);
28ab034a 1185 lttng_dynamic_array_init(&frames, sizeof(struct rmdir_frame), rmdir_frame_fini);
f75c5439 1186
28ab034a
JG
1187 if (flags &
1188 ~(LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG |
1189 LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG)) {
f75c5439
MD
1190 ERR("Unknown flags %d", flags);
1191 ret = -1;
1192 goto end;
1193 }
1194
1195 if (!initial_frame.dir) {
28ab034a 1196 if (flags & LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG && errno == ENOENT) {
f75c5439
MD
1197 DBG("Cannot rmdir \"%s\": root does not exist", path);
1198 ret = 0;
1199 goto end;
1200 } else {
1201 PERROR("Failed to rmdir \"%s\"", path);
1202 ret = -1;
1203 goto end;
1204 }
1205 }
93bed9fe
JG
1206
1207 ret = lttng_dynamic_array_add_element(&frames, &initial_frame);
1208 if (ret) {
1209 ERR("Failed to push context frame during recursive directory removal");
1210 rmdir_frame_fini(&initial_frame);
1211 goto end;
1212 }
1213
28ab034a 1214 ret = lttng_dynamic_buffer_append(&current_path, path, initial_frame.path_size);
f75c5439 1215 if (ret) {
93bed9fe
JG
1216 ERR("Failed to set initial path during recursive directory removal");
1217 ret = -1;
1218 goto end;
f75c5439 1219 }
93bed9fe 1220
f75c5439 1221 while (lttng_dynamic_array_get_count(&frames) > 0) {
93bed9fe
JG
1222 struct dirent *entry;
1223 struct rmdir_frame *current_frame =
28ab034a 1224 (rmdir_frame *) lttng_dynamic_array_get_element(&frames, current_frame_idx);
93bed9fe 1225
a0377dfe 1226 LTTNG_ASSERT(current_frame->dir);
28ab034a 1227 ret = lttng_dynamic_buffer_set_size(&current_path, current_frame->path_size);
a0377dfe 1228 LTTNG_ASSERT(!ret);
93bed9fe
JG
1229 current_path.data[current_path.size - 1] = '\0';
1230
1231 while ((entry = readdir(current_frame->dir))) {
1232 struct stat st;
93bed9fe 1233
28ab034a 1234 if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
93bed9fe
JG
1235 continue;
1236 }
1237
1238 /* Set current_path to the entry's path. */
28ab034a 1239 ret = lttng_dynamic_buffer_set_size(&current_path, current_path.size - 1);
a0377dfe 1240 LTTNG_ASSERT(!ret);
28ab034a
JG
1241 ret = lttng_dynamic_buffer_append(
1242 &current_path, &separator, sizeof(separator));
93bed9fe
JG
1243 if (ret) {
1244 goto end;
1245 }
28ab034a
JG
1246 ret = lttng_dynamic_buffer_append(
1247 &current_path, entry->d_name, strlen(entry->d_name) + 1);
93bed9fe
JG
1248 if (ret) {
1249 goto end;
1250 }
1251
28ab034a 1252 if (lttng_directory_handle_stat(handle, current_path.data, &st)) {
f75c5439 1253 if ((flags & LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG) &&
28ab034a 1254 errno == ENOENT) {
f75c5439
MD
1255 break;
1256 }
28ab034a 1257 PERROR("Failed to stat \"%s\"", current_path.data);
93bed9fe
JG
1258 ret = -1;
1259 goto end;
1260 }
1261
1262 if (!S_ISDIR(st.st_mode)) {
f75c5439
MD
1263 if (flags & LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG) {
1264 current_frame->empty = false;
1265 break;
1266 } else {
1267 /* Not empty, abort. */
1268 DBG("Directory \"%s\" is not empty; refusing to remove directory",
28ab034a 1269 current_path.data);
f75c5439
MD
1270 ret = -1;
1271 goto end;
1272 }
1273 } else {
1274 struct rmdir_frame new_frame = {
740da7d5 1275 .parent_frame_idx = (ssize_t) current_frame_idx,
28ab034a
JG
1276 .dir = lttng_directory_handle_opendir(handle,
1277 current_path.data),
f75c5439 1278 .empty = true,
740da7d5 1279 .path_size = current_path.size,
f75c5439
MD
1280 };
1281
1282 if (!new_frame.dir) {
1283 if (flags & LTTNG_DIRECTORY_HANDLE_SKIP_NON_EMPTY_FLAG &&
28ab034a 1284 errno == ENOENT) {
f75c5439
MD
1285 DBG("Non-existing directory stream during recursive directory removal");
1286 break;
1287 } else {
1288 PERROR("Failed to open directory stream during recursive directory removal");
1289 ret = -1;
1290 goto end;
1291 }
1292 }
28ab034a 1293 ret = lttng_dynamic_array_add_element(&frames, &new_frame);
f75c5439
MD
1294 if (ret) {
1295 ERR("Failed to push context frame during recursive directory removal");
1296 rmdir_frame_fini(&new_frame);
1297 goto end;
1298 }
1299 current_frame_idx++;
1300 /* We break iteration on readdir. */
1301 break;
93bed9fe 1302 }
f75c5439
MD
1303 }
1304 if (entry) {
1305 continue;
1306 }
93bed9fe 1307
f75c5439
MD
1308 /* Pop rmdir frame. */
1309 if (current_frame->empty) {
28ab034a 1310 ret = lttng_directory_handle_rmdir(handle, current_path.data);
93bed9fe 1311 if (ret) {
f75c5439 1312 if ((flags & LTTNG_DIRECTORY_HANDLE_FAIL_NON_EMPTY_FLAG) ||
28ab034a 1313 errno != ENOENT) {
f75c5439 1314 PERROR("Failed to remove \"%s\" during recursive directory removal",
28ab034a 1315 current_path.data);
f75c5439
MD
1316 goto end;
1317 }
1318 DBG("Non-existing directory stream during recursive directory removal");
93bed9fe 1319 }
f75c5439
MD
1320 } else if (current_frame->parent_frame_idx >= 0) {
1321 struct rmdir_frame *parent_frame;
1322
28ab034a
JG
1323 parent_frame = (rmdir_frame *) lttng_dynamic_array_get_element(
1324 &frames, current_frame->parent_frame_idx);
a0377dfe 1325 LTTNG_ASSERT(parent_frame);
f75c5439
MD
1326 parent_frame->empty = false;
1327 }
28ab034a 1328 ret = lttng_dynamic_array_remove_element(&frames, current_frame_idx);
f75c5439
MD
1329 if (ret) {
1330 ERR("Failed to pop context frame during recursive directory removal");
1331 goto end;
1332 }
1333 current_frame_idx--;
93bed9fe
JG
1334 }
1335end:
1336 lttng_dynamic_array_reset(&frames);
1337 lttng_dynamic_buffer_reset(&current_path);
1338 return ret;
1339}
1340
93bed9fe 1341int lttng_directory_handle_remove_subdirectory_recursive(
28ab034a 1342 const struct lttng_directory_handle *handle, const char *name, int flags)
93bed9fe
JG
1343{
1344 return lttng_directory_handle_remove_subdirectory_recursive_as_user(
cd9adb8b 1345 handle, name, nullptr, flags);
93bed9fe
JG
1346}
1347
93bed9fe 1348int lttng_directory_handle_remove_subdirectory_recursive_as_user(
28ab034a
JG
1349 const struct lttng_directory_handle *handle,
1350 const char *name,
1351 const struct lttng_credentials *creds,
1352 int flags)
93bed9fe
JG
1353{
1354 int ret;
1355
1356 if (!creds) {
1357 /* Run as current user. */
f75c5439 1358 ret = remove_directory_recursive(handle, name, flags);
93bed9fe 1359 } else {
28ab034a
JG
1360 ret = _run_as_rmdir_recursive(handle,
1361 name,
1362 lttng_credentials_get_uid(creds),
1363 lttng_credentials_get_gid(creds),
1364 flags);
93bed9fe
JG
1365 }
1366 return ret;
1367}
This page took 0.122594 seconds and 4 git commands to generate.