aboutsummaryrefslogtreecommitdiff
path: root/src/util/disk.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/disk.c')
-rw-r--r--src/util/disk.c1688
1 files changed, 0 insertions, 1688 deletions
diff --git a/src/util/disk.c b/src/util/disk.c
deleted file mode 100644
index 2efb52d46..000000000
--- a/src/util/disk.c
+++ /dev/null
@@ -1,1688 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001--2013, 2016, 2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file util/disk.c
22 * @brief disk IO convenience methods
23 * @author Christian Grothoff
24 * @author Nils Durner
25 */
26#include "platform.h"
27#include "disk.h"
28#include "gnunet_strings_lib.h"
29#include "gnunet_disk_lib.h"
30
31#define LOG(kind, ...) GNUNET_log_from (kind, "util-disk", __VA_ARGS__)
32
33#define LOG_STRERROR(kind, syscall) \
34 GNUNET_log_from_strerror (kind, "util-disk", syscall)
35
36#define LOG_STRERROR_FILE(kind, syscall, filename) \
37 GNUNET_log_from_strerror_file (kind, "util-disk", syscall, filename)
38
39/**
40 * Block size for IO for copying files.
41 */
42#define COPY_BLK_SIZE 65536
43
44#include <sys/types.h>
45#if HAVE_SYS_VFS_H
46#include <sys/vfs.h>
47#endif
48#if HAVE_SYS_PARAM_H
49#include <sys/param.h>
50#endif
51#if HAVE_SYS_MOUNT_H
52#include <sys/mount.h>
53#endif
54#if HAVE_SYS_STATVFS_H
55#include <sys/statvfs.h>
56#endif
57
58#ifndef S_ISLNK
59#define _IFMT 0170000 /* type of file */
60#define _IFLNK 0120000 /* symbolic link */
61#define S_ISLNK(m) (((m) & _IFMT) == _IFLNK)
62#endif
63
64
65/**
66 * Handle used to manage a pipe.
67 */
68struct GNUNET_DISK_PipeHandle
69{
70 /**
71 * File descriptors for the pipe.
72 * One or both of them could be NULL.
73 */
74 struct GNUNET_DISK_FileHandle *fd[2];
75};
76
77
78/**
79 * Closure for the recursion to determine the file size
80 * of a directory.
81 */
82struct GetFileSizeData
83{
84 /**
85 * Set to the total file size.
86 */
87 uint64_t total;
88
89 /**
90 * GNUNET_YES if symbolic links should be included.
91 */
92 int include_sym_links;
93
94 /**
95 * #GNUNET_YES if mode is file-only (return total == -1 for directories).
96 */
97 int single_file_mode;
98};
99
100
101/**
102 * Translate GNUnet-internal permission bitmap to UNIX file
103 * access permission bitmap.
104 *
105 * @param perm file permissions, GNUnet style
106 * @return file permissions, UNIX style
107 */
108static int
109translate_unix_perms (enum GNUNET_DISK_AccessPermissions perm)
110{
111 int mode;
112
113 mode = 0;
114 if (perm & GNUNET_DISK_PERM_USER_READ)
115 mode |= S_IRUSR;
116 if (perm & GNUNET_DISK_PERM_USER_WRITE)
117 mode |= S_IWUSR;
118 if (perm & GNUNET_DISK_PERM_USER_EXEC)
119 mode |= S_IXUSR;
120 if (perm & GNUNET_DISK_PERM_GROUP_READ)
121 mode |= S_IRGRP;
122 if (perm & GNUNET_DISK_PERM_GROUP_WRITE)
123 mode |= S_IWGRP;
124 if (perm & GNUNET_DISK_PERM_GROUP_EXEC)
125 mode |= S_IXGRP;
126 if (perm & GNUNET_DISK_PERM_OTHER_READ)
127 mode |= S_IROTH;
128 if (perm & GNUNET_DISK_PERM_OTHER_WRITE)
129 mode |= S_IWOTH;
130 if (perm & GNUNET_DISK_PERM_OTHER_EXEC)
131 mode |= S_IXOTH;
132
133 return mode;
134}
135
136
137/**
138 * Iterate over all files in the given directory and
139 * accumulate their size.
140 *
141 * @param cls closure of type `struct GetFileSizeData`
142 * @param fn current filename we are looking at
143 * @return #GNUNET_SYSERR on serious errors, otherwise #GNUNET_OK
144 */
145static enum GNUNET_GenericReturnValue
146get_size_rec (void *cls, const char *fn)
147{
148 struct GetFileSizeData *gfsd = cls;
149
150#if defined(HAVE_STAT64) && \
151 ! (defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64)
152 struct stat64 buf;
153
154 if (0 != stat64 (fn, &buf))
155 {
156 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "stat64", fn);
157 return GNUNET_SYSERR;
158 }
159#else
160 struct stat buf;
161
162 if (0 != stat (fn, &buf))
163 {
164 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "stat", fn);
165 return GNUNET_SYSERR;
166 }
167#endif
168 if ((S_ISDIR (buf.st_mode)) && (gfsd->single_file_mode == GNUNET_YES))
169 {
170 errno = EISDIR;
171 return GNUNET_SYSERR;
172 }
173 if ((! S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES))
174 gfsd->total += buf.st_size;
175 if ((S_ISDIR (buf.st_mode)) && (0 == access (fn, X_OK)) &&
176 ((! S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES)))
177 {
178 if (GNUNET_SYSERR == GNUNET_DISK_directory_scan (fn, &get_size_rec, gfsd))
179 return GNUNET_SYSERR;
180 }
181 return GNUNET_OK;
182}
183
184
185enum GNUNET_GenericReturnValue
186GNUNET_DISK_handle_invalid (const struct GNUNET_DISK_FileHandle *h)
187{
188 return ((! h) || (h->fd == -1)) ? GNUNET_YES : GNUNET_NO;
189}
190
191
192enum GNUNET_GenericReturnValue
193GNUNET_DISK_file_handle_size (struct GNUNET_DISK_FileHandle *fh,
194 off_t *size)
195{
196 struct stat sbuf;
197
198 if (0 != fstat (fh->fd, &sbuf))
199 return GNUNET_SYSERR;
200 *size = sbuf.st_size;
201 return GNUNET_OK;
202}
203
204
205off_t
206GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle *h,
207 off_t offset,
208 enum GNUNET_DISK_Seek whence)
209{
210 static int t[] = { SEEK_SET, SEEK_CUR, SEEK_END };
211
212 if (h == NULL)
213 {
214 errno = EINVAL;
215 return GNUNET_SYSERR;
216 }
217 return lseek (h->fd, offset, t[whence]);
218}
219
220
221enum GNUNET_GenericReturnValue
222GNUNET_DISK_file_size (const char *filename,
223 uint64_t *size,
224 int include_symbolic_links,
225 int single_file_mode)
226{
227 struct GetFileSizeData gfsd;
228 enum GNUNET_GenericReturnValue ret;
229
230 GNUNET_assert (size != NULL);
231 gfsd.total = 0;
232 gfsd.include_sym_links = include_symbolic_links;
233 gfsd.single_file_mode = single_file_mode;
234 ret = get_size_rec (&gfsd, filename);
235 *size = gfsd.total;
236 return ret;
237}
238
239
240enum GNUNET_GenericReturnValue
241GNUNET_DISK_file_get_identifiers (const char *filename,
242 uint64_t *dev,
243 uint64_t *ino)
244{
245#if HAVE_STAT
246 {
247 struct stat sbuf;
248
249 if (0 != stat (filename, &sbuf))
250 {
251 return GNUNET_SYSERR;
252 }
253 *ino = (uint64_t) sbuf.st_ino;
254 }
255#else
256 *ino = 0;
257#endif
258#if HAVE_STATVFS
259 {
260 struct statvfs fbuf;
261
262 if (0 != statvfs (filename, &fbuf))
263 {
264 return GNUNET_SYSERR;
265 }
266 *dev = (uint64_t) fbuf.f_fsid;
267 }
268#elif HAVE_STATFS
269 {
270 struct statfs fbuf;
271
272 if (0 != statfs (filename, &fbuf))
273 {
274 return GNUNET_SYSERR;
275 }
276 *dev =
277 ((uint64_t) fbuf.f_fsid.val[0]) << 32 || ((uint64_t) fbuf.f_fsid.val[1]);
278 }
279#else
280 *dev = 0;
281#endif
282 return GNUNET_OK;
283}
284
285
286/**
287 * Create the name for a temporary file or directory from a template.
288 *
289 * @param t template (without XXXXX or "/tmp/")
290 * @return name ready for passing to 'mktemp' or 'mkdtemp', NULL on error
291 */
292static char *
293mktemp_name (const char *t)
294{
295 const char *tmpdir;
296 char *tmpl;
297 char *fn;
298
299 if ((t[0] != '/') && (t[0] != '\\'))
300 {
301 /* FIXME: This uses system codepage on W32, not UTF-8 */
302 tmpdir = getenv ("TMPDIR");
303 if (NULL == tmpdir)
304 tmpdir = getenv ("TMP");
305 if (NULL == tmpdir)
306 tmpdir = getenv ("TEMP");
307 if (NULL == tmpdir)
308 tmpdir = "/tmp";
309 GNUNET_asprintf (&tmpl, "%s/%s%s", tmpdir, t, "XXXXXX");
310 }
311 else
312 {
313 GNUNET_asprintf (&tmpl, "%s%s", t, "XXXXXX");
314 }
315 fn = tmpl;
316 return fn;
317}
318
319
320void
321GNUNET_DISK_fix_permissions (const char *fn,
322 int require_uid_match,
323 int require_gid_match)
324{
325 mode_t mode;
326
327 if (GNUNET_YES == require_uid_match)
328 mode = S_IRUSR | S_IWUSR | S_IXUSR;
329 else if (GNUNET_YES == require_gid_match)
330 mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP;
331 else
332 mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH
333 | S_IWOTH | S_IXOTH;
334 if (0 != chmod (fn, mode))
335 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "chmod", fn);
336}
337
338
339char *
340GNUNET_DISK_mkdtemp (const char *t)
341{
342 char *fn;
343 mode_t omask;
344
345 omask = umask (S_IWGRP | S_IWOTH | S_IRGRP | S_IROTH);
346 fn = mktemp_name (t);
347 if (fn != mkdtemp (fn))
348 {
349 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkdtemp", fn);
350 GNUNET_free (fn);
351 umask (omask);
352 return NULL;
353 }
354 umask (omask);
355 return fn;
356}
357
358
359void
360GNUNET_DISK_file_backup (const char *fil)
361{
362 size_t slen;
363 char *target;
364 unsigned int num;
365
366 slen = strlen (fil) + 20;
367 target = GNUNET_malloc (slen);
368 num = 0;
369 do
370 {
371 GNUNET_snprintf (target, slen, "%s.%u~", fil, num++);
372 }
373 while (0 == access (target, F_OK));
374 if (0 != rename (fil, target))
375 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "rename", fil);
376 GNUNET_free (target);
377}
378
379
380char *
381GNUNET_DISK_mktemp (const char *t)
382{
383 int fd;
384 char *fn;
385 mode_t omask;
386
387 omask = umask (S_IWGRP | S_IWOTH | S_IRGRP | S_IROTH);
388 fn = mktemp_name (t);
389 if (-1 == (fd = mkstemp (fn)))
390 {
391 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkstemp", fn);
392 GNUNET_free (fn);
393 umask (omask);
394 return NULL;
395 }
396 umask (omask);
397 if (0 != close (fd))
398 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "close", fn);
399 return fn;
400}
401
402
403enum GNUNET_GenericReturnValue
404GNUNET_DISK_directory_test (const char *fil, int is_readable)
405{
406 struct stat filestat;
407 int ret;
408
409 ret = stat (fil, &filestat);
410 if (ret != 0)
411 {
412 if (errno != ENOENT)
413 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", fil);
414 return GNUNET_SYSERR;
415 }
416 if (! S_ISDIR (filestat.st_mode))
417 {
418 LOG (GNUNET_ERROR_TYPE_INFO,
419 "A file already exits with the same name %s\n",
420 fil);
421 return GNUNET_NO;
422 }
423 if (GNUNET_YES == is_readable)
424 ret = access (fil, R_OK | X_OK);
425 else
426 ret = access (fil, X_OK);
427 if (ret < 0)
428 {
429 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "access", fil);
430 return GNUNET_NO;
431 }
432 return GNUNET_YES;
433}
434
435/**
436 * Check if fil can be accessed using amode.
437 *
438 * @param fil file to check for
439 * @param amode access mode
440 * @returns GNUnet error code
441 */
442static enum GNUNET_GenericReturnValue
443file_test_internal (const char *fil, int amode)
444{
445 struct stat filestat;
446 int ret;
447 char *rdir;
448
449 rdir = GNUNET_STRINGS_filename_expand (fil);
450 if (rdir == NULL)
451 return GNUNET_SYSERR;
452
453 ret = stat (rdir, &filestat);
454 if (0 != ret)
455 {
456 if (errno != ENOENT)
457 {
458 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "stat", rdir);
459 GNUNET_free (rdir);
460 return GNUNET_SYSERR;
461 }
462 GNUNET_free (rdir);
463 return GNUNET_NO;
464 }
465 if (! S_ISREG (filestat.st_mode))
466 {
467 GNUNET_free (rdir);
468 return GNUNET_NO;
469 }
470 if (access (rdir, amode) < 0)
471 {
472 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "access", rdir);
473 GNUNET_free (rdir);
474 return GNUNET_SYSERR;
475 }
476 GNUNET_free (rdir);
477 return GNUNET_YES;
478}
479
480
481enum GNUNET_GenericReturnValue
482GNUNET_DISK_file_test (const char *fil)
483{
484 return file_test_internal (fil, F_OK);
485}
486
487
488enum GNUNET_GenericReturnValue
489GNUNET_DISK_file_test_read (const char *fil)
490{
491 return file_test_internal (fil, R_OK);
492}
493
494
495enum GNUNET_GenericReturnValue
496GNUNET_DISK_directory_create (const char *dir)
497{
498 char *rdir;
499 unsigned int len;
500 unsigned int pos;
501 unsigned int pos2;
502 int ret = GNUNET_OK;
503
504 rdir = GNUNET_STRINGS_filename_expand (dir);
505 if (rdir == NULL)
506 {
507 GNUNET_break (0);
508 return GNUNET_SYSERR;
509 }
510
511 len = strlen (rdir);
512
513 pos = 1; /* skip heading '/' */
514
515 /* Check which low level directories already exist */
516 pos2 = len;
517 rdir[len] = DIR_SEPARATOR;
518 while (pos <= pos2)
519 {
520 if (DIR_SEPARATOR == rdir[pos2])
521 {
522 rdir[pos2] = '\0';
523 ret = GNUNET_DISK_directory_test (rdir, GNUNET_NO);
524 if (GNUNET_NO == ret)
525 {
526 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
527 "Creating directory `%s' failed",
528 rdir);
529 GNUNET_free (rdir);
530 return GNUNET_SYSERR;
531 }
532 rdir[pos2] = DIR_SEPARATOR;
533 if (GNUNET_YES == ret)
534 {
535 pos2++;
536 break;
537 }
538 }
539 pos2--;
540 }
541 rdir[len] = '\0';
542 if (pos < pos2)
543 pos = pos2;
544 /* Start creating directories */
545 while (pos <= len)
546 {
547 if ((rdir[pos] == DIR_SEPARATOR) || (pos == len))
548 {
549 rdir[pos] = '\0';
550 ret = GNUNET_DISK_directory_test (rdir, GNUNET_NO);
551 if (GNUNET_NO == ret)
552 {
553 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
554 "Creating directory `%s' failed",
555 rdir);
556 GNUNET_free (rdir);
557 return GNUNET_SYSERR;
558 }
559 if (GNUNET_SYSERR == ret)
560 {
561 ret = mkdir (rdir,
562 S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH
563 | S_IXOTH); /* 755 */
564
565 if ((ret != 0) && (errno != EEXIST))
566 {
567 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "mkdir", rdir);
568 GNUNET_free (rdir);
569 return GNUNET_SYSERR;
570 }
571 }
572 rdir[pos] = DIR_SEPARATOR;
573 }
574 pos++;
575 }
576 GNUNET_free (rdir);
577 return GNUNET_OK;
578}
579
580
581enum GNUNET_GenericReturnValue
582GNUNET_DISK_directory_create_for_file (const char *filename)
583{
584 char *rdir;
585 size_t len;
586 int eno;
587 enum GNUNET_GenericReturnValue res;
588
589 rdir = GNUNET_STRINGS_filename_expand (filename);
590 if (NULL == rdir)
591 {
592 errno = EINVAL;
593 return GNUNET_SYSERR;
594 }
595 if (0 == access (rdir, W_OK))
596 {
597 GNUNET_free (rdir);
598 return GNUNET_OK;
599 }
600 len = strlen (rdir);
601 while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
602 len--;
603 rdir[len] = '\0';
604 /* The empty path is invalid and in this case refers to / */
605 if (0 == len)
606 {
607 GNUNET_free (rdir);
608 rdir = GNUNET_strdup ("/");
609 }
610 res = GNUNET_DISK_directory_create (rdir);
611 if ( (GNUNET_OK == res) &&
612 (0 != access (rdir, W_OK)) )
613 res = GNUNET_NO;
614 eno = errno;
615 GNUNET_free (rdir);
616 errno = eno;
617 return res;
618}
619
620
621ssize_t
622GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle *h,
623 void *result,
624 size_t len)
625{
626 if (NULL == h)
627 {
628 errno = EINVAL;
629 return GNUNET_SYSERR;
630 }
631 return read (h->fd, result, len);
632}
633
634
635ssize_t
636GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle *h,
637 void *result,
638 size_t len)
639{
640 int flags;
641 ssize_t ret;
642
643 if (NULL == h)
644 {
645 errno = EINVAL;
646 return GNUNET_SYSERR;
647 }
648 /* set to non-blocking, read, then set back */
649 flags = fcntl (h->fd, F_GETFL);
650 if (0 == (flags & O_NONBLOCK))
651 (void) fcntl (h->fd, F_SETFL, flags | O_NONBLOCK);
652 ret = read (h->fd, result, len);
653 if (0 == (flags & O_NONBLOCK))
654 {
655 int eno = errno;
656 (void) fcntl (h->fd, F_SETFL, flags);
657 errno = eno;
658 }
659 return ret;
660}
661
662
663ssize_t
664GNUNET_DISK_fn_read (const char *fn,
665 void *result,
666 size_t len)
667{
668 struct GNUNET_DISK_FileHandle *fh;
669 ssize_t ret;
670 int eno;
671
672 fh = GNUNET_DISK_file_open (fn,
673 GNUNET_DISK_OPEN_READ,
674 GNUNET_DISK_PERM_NONE);
675 if (NULL == fh)
676 return GNUNET_SYSERR;
677 ret = GNUNET_DISK_file_read (fh, result, len);
678 eno = errno;
679 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh));
680 errno = eno;
681 return ret;
682}
683
684
685ssize_t
686GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle *h,
687 const void *buffer,
688 size_t n)
689{
690 if (NULL == h)
691 {
692 errno = EINVAL;
693 return GNUNET_SYSERR;
694 }
695
696 return write (h->fd, buffer, n);
697}
698
699
700ssize_t
701GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle *h,
702 const void *buffer,
703 size_t n)
704{
705 int flags;
706 ssize_t ret;
707
708 if (NULL == h)
709 {
710 errno = EINVAL;
711 return GNUNET_SYSERR;
712 }
713 /* set to blocking, write, then set back */
714 flags = fcntl (h->fd, F_GETFL);
715 if (0 != (flags & O_NONBLOCK))
716 (void) fcntl (h->fd, F_SETFL, flags - O_NONBLOCK);
717 ret = write (h->fd, buffer, n);
718 if (0 == (flags & O_NONBLOCK))
719 (void) fcntl (h->fd, F_SETFL, flags);
720 return ret;
721}
722
723
724enum GNUNET_GenericReturnValue
725GNUNET_DISK_fn_write (const char *fn,
726 const void *buf,
727 size_t buf_size,
728 enum GNUNET_DISK_AccessPermissions mode)
729{
730 char *tmpl;
731 int fd;
732
733 if (GNUNET_OK !=
734 GNUNET_DISK_directory_create_for_file (fn))
735 {
736 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
737 "mkstemp",
738 fn);
739 return GNUNET_SYSERR;
740 }
741 {
742 char *dname;
743
744 dname = GNUNET_strdup (fn);
745 GNUNET_asprintf (&tmpl,
746 "%s/XXXXXX",
747 dirname (dname));
748 GNUNET_free (dname);
749 }
750 fd = mkstemp (tmpl);
751 if (-1 == fd)
752 {
753 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
754 "mkstemp",
755 tmpl);
756 GNUNET_free (tmpl);
757 return GNUNET_SYSERR;
758 }
759
760 if (0 != fchmod (fd,
761 translate_unix_perms (mode)))
762 {
763 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
764 "chmod",
765 tmpl);
766 GNUNET_assert (0 == close (fd));
767 if (0 != unlink (tmpl))
768 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
769 "unlink",
770 tmpl);
771 GNUNET_free (tmpl);
772 return GNUNET_SYSERR;
773 }
774 if (buf_size !=
775 write (fd,
776 buf,
777 buf_size))
778 {
779 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
780 "write",
781 tmpl);
782 GNUNET_assert (0 == close (fd));
783 if (0 != unlink (tmpl))
784 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
785 "unlink",
786 tmpl);
787 GNUNET_free (tmpl);
788 return GNUNET_SYSERR;
789 }
790 GNUNET_assert (0 == close (fd));
791
792 if (0 != link (tmpl,
793 fn))
794 {
795 if (0 != unlink (tmpl))
796 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
797 "unlink",
798 tmpl);
799 GNUNET_free (tmpl);
800 return GNUNET_NO;
801 }
802 if (0 != unlink (tmpl))
803 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
804 "unlink",
805 tmpl);
806 GNUNET_free (tmpl);
807 return GNUNET_OK;
808
809
810}
811
812
813int
814GNUNET_DISK_directory_scan (const char *dir_name,
815 GNUNET_FileNameCallback callback,
816 void *callback_cls)
817{
818 DIR *dinfo;
819 struct dirent *finfo;
820 struct stat istat;
821 int count = 0;
822 enum GNUNET_GenericReturnValue ret;
823 char *name;
824 char *dname;
825 unsigned int name_len;
826 unsigned int n_size;
827
828 GNUNET_assert (NULL != dir_name);
829 dname = GNUNET_STRINGS_filename_expand (dir_name);
830 if (NULL == dname)
831 return GNUNET_SYSERR;
832 while ((strlen (dname) > 0) && (dname[strlen (dname) - 1] == DIR_SEPARATOR))
833 dname[strlen (dname) - 1] = '\0';
834 if (0 != stat (dname, &istat))
835 {
836 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", dname);
837 GNUNET_free (dname);
838 return GNUNET_SYSERR;
839 }
840 if (! S_ISDIR (istat.st_mode))
841 {
842 LOG (GNUNET_ERROR_TYPE_WARNING,
843 _ ("Expected `%s' to be a directory!\n"),
844 dir_name);
845 GNUNET_free (dname);
846 return GNUNET_SYSERR;
847 }
848 errno = 0;
849 dinfo = opendir (dname);
850 if ((EACCES == errno) || (NULL == dinfo))
851 {
852 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "opendir", dname);
853 if (NULL != dinfo)
854 closedir (dinfo);
855 GNUNET_free (dname);
856 return GNUNET_SYSERR;
857 }
858 name_len = 256;
859 n_size = strlen (dname) + name_len + strlen (DIR_SEPARATOR_STR) + 1;
860 name = GNUNET_malloc (n_size);
861 while (NULL != (finfo = readdir (dinfo)))
862 {
863 if ((0 == strcmp (finfo->d_name, ".")) ||
864 (0 == strcmp (finfo->d_name, "..")))
865 continue;
866 if (NULL != callback)
867 {
868 if (name_len < strlen (finfo->d_name))
869 {
870 GNUNET_free (name);
871 name_len = strlen (finfo->d_name);
872 n_size = strlen (dname) + name_len + strlen (DIR_SEPARATOR_STR) + 1;
873 name = GNUNET_malloc (n_size);
874 }
875 /* dname can end in "/" only if dname == "/";
876 * if dname does not end in "/", we need to add
877 * a "/" (otherwise, we must not!) */
878 GNUNET_snprintf (name,
879 n_size,
880 "%s%s%s",
881 dname,
882 (0 == strcmp (dname, DIR_SEPARATOR_STR))
883 ? ""
884 : DIR_SEPARATOR_STR,
885 finfo->d_name);
886 ret = callback (callback_cls, name);
887 if (GNUNET_OK != ret)
888 {
889 closedir (dinfo);
890 GNUNET_free (name);
891 GNUNET_free (dname);
892 if (GNUNET_NO == ret)
893 return count;
894 return GNUNET_SYSERR;
895 }
896 }
897 count++;
898 }
899 closedir (dinfo);
900 GNUNET_free (name);
901 GNUNET_free (dname);
902 return count;
903}
904
905/**
906 * Check for a simple wildcard match.
907 * Only asterisks are allowed.
908 * Asterisks match everything, including slashes.
909 *
910 * @param pattern pattern with wildcards
911 * @param str string to match against
912 * @returns true on match, false otherwise
913 */
914static bool
915glob_match (const char *pattern, const char *str)
916{
917 /* Position in the input string */
918 const char *str_pos = str;
919 /* Position in the pattern */
920 const char *pat_pos = pattern;
921 /* Backtrack position in string */
922 const char *str_bt = NULL;
923 /* Backtrack position in pattern */
924 const char *pat_bt = NULL;
925
926 for (;;)
927 {
928 if (*pat_pos == '*')
929 {
930 str_bt = str_pos;
931 pat_bt = pat_pos++;
932 }
933 else if (*pat_pos == *str_pos)
934 {
935 if ('\0' == *pat_pos)
936 return true;
937 str_pos++;
938 pat_pos++;
939 }
940 else
941 {
942 if (NULL == str_bt)
943 return false;
944 /* Backtrack to match one more
945 character as part of the asterisk. */
946 str_pos = str_bt + 1;
947 if ('\0' == *str_pos)
948 return false;
949 pat_pos = pat_bt;
950 }
951 }
952}
953
954struct GlobClosure
955{
956 const char *glob;
957 GNUNET_FileNameCallback cb;
958 void *cls;
959
960 /**
961 * Number of files that actually matched the glob pattern.
962 */
963 int nres;
964};
965
966/**
967 * Function called with a filename.
968 *
969 * @param cls closure
970 * @param filename complete filename (absolute path)
971 * @return #GNUNET_OK to continue to iterate,
972 * #GNUNET_NO to stop iteration with no error,
973 * #GNUNET_SYSERR to abort iteration with error!
974 */
975static enum GNUNET_GenericReturnValue
976glob_cb (void *cls,
977 const char *filename)
978{
979 struct GlobClosure *gc = cls;
980 const char *fn;
981
982 fn = strrchr (filename, DIR_SEPARATOR);
983 fn = (NULL == fn) ? filename : (fn + 1);
984
985 LOG (GNUNET_ERROR_TYPE_DEBUG,
986 "checking glob '%s' against '%s'\n",
987 gc->glob,
988 fn);
989
990 if (glob_match (gc->glob, fn))
991 {
992 enum GNUNET_GenericReturnValue cbret;
993
994 LOG (GNUNET_ERROR_TYPE_DEBUG,
995 "found glob match '%s'\n",
996 filename);
997 gc->nres++;
998 cbret = gc->cb (gc->cls, filename);
999 if (GNUNET_OK != cbret)
1000 return cbret;
1001 }
1002 return GNUNET_OK;
1003}
1004
1005
1006int
1007GNUNET_DISK_glob (const char *glob_pattern,
1008 GNUNET_FileNameCallback callback,
1009 void *callback_cls)
1010{
1011 char *mypat = GNUNET_strdup (glob_pattern);
1012 char *sep;
1013 int ret;
1014
1015 if ( (NULL != strrchr (glob_pattern, '+')) ||
1016 (NULL != strrchr (glob_pattern, '[')) ||
1017 (NULL != strrchr (glob_pattern, '+')) ||
1018 (NULL != strrchr (glob_pattern, '~')) )
1019 {
1020 LOG (GNUNET_ERROR_TYPE_ERROR,
1021 "unsupported glob pattern: '%s'\n",
1022 glob_pattern);
1023 GNUNET_free (mypat);
1024 return -1;
1025 }
1026
1027 sep = strrchr (mypat, DIR_SEPARATOR);
1028 if (NULL == sep)
1029 {
1030 GNUNET_free (mypat);
1031 return -1;
1032 }
1033
1034 *sep = '\0';
1035
1036 if (NULL != strchr (mypat, '*'))
1037 {
1038 GNUNET_free (mypat);
1039 GNUNET_break (0);
1040 LOG (GNUNET_ERROR_TYPE_ERROR,
1041 "glob pattern may only contain '*' in the final path component\n");
1042 return -1;
1043 }
1044
1045 {
1046 struct GlobClosure gc = {
1047 .glob = sep + 1,
1048 .cb = callback,
1049 .cls = callback_cls,
1050 .nres = 0,
1051 };
1052 LOG (GNUNET_ERROR_TYPE_DEBUG,
1053 "scanning directory '%s' for glob matches on '%s'\n",
1054 mypat,
1055 gc.glob);
1056 ret = GNUNET_DISK_directory_scan (mypat,
1057 glob_cb,
1058 &gc
1059 );
1060 GNUNET_free (mypat);
1061 return (ret < 0) ? ret : gc.nres;
1062 }
1063}
1064
1065
1066/**
1067 * Function that removes the given directory by calling
1068 * #GNUNET_DISK_directory_remove().
1069 *
1070 * @param unused not used
1071 * @param fn directory to remove
1072 * @return #GNUNET_OK
1073 */
1074static enum GNUNET_GenericReturnValue
1075remove_helper (void *unused,
1076 const char *fn)
1077{
1078 (void) unused;
1079 (void) GNUNET_DISK_directory_remove (fn);
1080 return GNUNET_OK;
1081}
1082
1083
1084enum GNUNET_GenericReturnValue
1085GNUNET_DISK_directory_remove (const char *filename)
1086{
1087 struct stat istat;
1088
1089 if (NULL == filename)
1090 {
1091 GNUNET_break (0);
1092 return GNUNET_SYSERR;
1093 }
1094 if (0 != lstat (filename, &istat))
1095 return GNUNET_NO; /* file may not exist... */
1096 (void) chmod (filename,
1097 S_IWUSR | S_IRUSR | S_IXUSR);
1098 if (0 == unlink (filename))
1099 return GNUNET_OK;
1100 if ( (errno != EISDIR) &&
1101 /* EISDIR is not sufficient in all cases, e.g.
1102 * sticky /tmp directory may result in EPERM on BSD.
1103 * So we also explicitly check "isDirectory" */
1104 (GNUNET_YES !=
1105 GNUNET_DISK_directory_test (filename,
1106 GNUNET_YES)) )
1107 {
1108 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename);
1109 return GNUNET_SYSERR;
1110 }
1111 if (GNUNET_SYSERR ==
1112 GNUNET_DISK_directory_scan (filename, &remove_helper, NULL))
1113 return GNUNET_SYSERR;
1114 if (0 != rmdir (filename))
1115 {
1116 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename);
1117 return GNUNET_SYSERR;
1118 }
1119 return GNUNET_OK;
1120}
1121
1122
1123enum GNUNET_GenericReturnValue
1124GNUNET_DISK_file_copy (const char *src,
1125 const char *dst)
1126{
1127 char *buf;
1128 uint64_t pos;
1129 uint64_t size;
1130 size_t len;
1131 ssize_t sret;
1132 struct GNUNET_DISK_FileHandle *in;
1133 struct GNUNET_DISK_FileHandle *out;
1134
1135 if (GNUNET_OK != GNUNET_DISK_file_size (src, &size, GNUNET_YES, GNUNET_YES))
1136 {
1137 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "stat", src);
1138 return GNUNET_SYSERR;
1139 }
1140 pos = 0;
1141 in =
1142 GNUNET_DISK_file_open (src, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE);
1143 if (! in)
1144 {
1145 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", src);
1146 return GNUNET_SYSERR;
1147 }
1148 out =
1149 GNUNET_DISK_file_open (dst,
1150 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE
1151 | GNUNET_DISK_OPEN_FAILIFEXISTS,
1152 GNUNET_DISK_PERM_USER_READ
1153 | GNUNET_DISK_PERM_USER_WRITE
1154 | GNUNET_DISK_PERM_GROUP_READ
1155 | GNUNET_DISK_PERM_GROUP_WRITE);
1156 if (! out)
1157 {
1158 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", dst);
1159 GNUNET_DISK_file_close (in);
1160 return GNUNET_SYSERR;
1161 }
1162 buf = GNUNET_malloc (COPY_BLK_SIZE);
1163 while (pos < size)
1164 {
1165 len = COPY_BLK_SIZE;
1166 if (len > size - pos)
1167 len = size - pos;
1168 sret = GNUNET_DISK_file_read (in, buf, len);
1169 if ((sret < 0) || (len != (size_t) sret))
1170 goto FAIL;
1171 sret = GNUNET_DISK_file_write (out, buf, len);
1172 if ((sret < 0) || (len != (size_t) sret))
1173 goto FAIL;
1174 pos += len;
1175 }
1176 GNUNET_free (buf);
1177 GNUNET_DISK_file_close (in);
1178 GNUNET_DISK_file_close (out);
1179 return GNUNET_OK;
1180 FAIL:
1181 GNUNET_free (buf);
1182 GNUNET_DISK_file_close (in);
1183 GNUNET_DISK_file_close (out);
1184 return GNUNET_SYSERR;
1185}
1186
1187
1188void
1189GNUNET_DISK_filename_canonicalize (char *fn)
1190{
1191 char *idx;
1192 char c;
1193
1194 for (idx = fn; *idx; idx++)
1195 {
1196 c = *idx;
1197
1198 if ((c == '/') || (c == '\\') || (c == ':') || (c == '*') || (c == '?') ||
1199 (c ==
1200 '"')
1201 ||
1202 (c == '<') || (c == '>') || (c == '|') )
1203 {
1204 *idx = '_';
1205 }
1206 }
1207}
1208
1209
1210enum GNUNET_GenericReturnValue
1211GNUNET_DISK_file_change_owner (const char *filename,
1212 const char *user)
1213{
1214 struct passwd *pws;
1215
1216 pws = getpwnam (user);
1217 if (NULL == pws)
1218 {
1219 LOG (GNUNET_ERROR_TYPE_ERROR,
1220 _ ("Cannot obtain information about user `%s': %s\n"),
1221 user,
1222 strerror (errno));
1223 return GNUNET_SYSERR;
1224 }
1225 if (0 != chown (filename, pws->pw_uid, pws->pw_gid))
1226 {
1227 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "chown", filename);
1228 return GNUNET_SYSERR;
1229 }
1230 return GNUNET_OK;
1231}
1232
1233
1234struct GNUNET_DISK_FileHandle *
1235GNUNET_DISK_file_open (const char *fn,
1236 enum GNUNET_DISK_OpenFlags flags,
1237 enum GNUNET_DISK_AccessPermissions perm)
1238{
1239 char *expfn;
1240 struct GNUNET_DISK_FileHandle *ret;
1241
1242 int oflags;
1243 int mode;
1244 int fd;
1245
1246 expfn = GNUNET_STRINGS_filename_expand (fn);
1247 if (NULL == expfn)
1248 return NULL;
1249
1250 mode = 0;
1251 if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1252 oflags = O_RDWR; /* note: O_RDWR is NOT always O_RDONLY | O_WRONLY */
1253 else if (flags & GNUNET_DISK_OPEN_READ)
1254 oflags = O_RDONLY;
1255 else if (flags & GNUNET_DISK_OPEN_WRITE)
1256 oflags = O_WRONLY;
1257 else
1258 {
1259 GNUNET_break (0);
1260 GNUNET_free (expfn);
1261 return NULL;
1262 }
1263 if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1264 oflags |= (O_CREAT | O_EXCL);
1265 if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1266 oflags |= O_TRUNC;
1267 if (flags & GNUNET_DISK_OPEN_APPEND)
1268 oflags |= O_APPEND;
1269 if (GNUNET_NO == GNUNET_DISK_file_test (fn))
1270 {
1271 if (flags & GNUNET_DISK_OPEN_CREATE)
1272 {
1273 (void) GNUNET_DISK_directory_create_for_file (expfn);
1274 oflags |= O_CREAT;
1275 mode = translate_unix_perms (perm);
1276 }
1277 }
1278
1279 fd = open (expfn,
1280 oflags
1281#if O_CLOEXEC
1282 | O_CLOEXEC
1283#endif
1284 | O_LARGEFILE,
1285 mode);
1286 if (fd == -1)
1287 {
1288 if (0 == (flags & GNUNET_DISK_OPEN_FAILIFEXISTS))
1289 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "open", expfn);
1290 else
1291 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "open", expfn);
1292 GNUNET_free (expfn);
1293 return NULL;
1294 }
1295
1296 ret = GNUNET_new (struct GNUNET_DISK_FileHandle);
1297
1298 ret->fd = fd;
1299
1300 GNUNET_free (expfn);
1301 return ret;
1302}
1303
1304
1305enum GNUNET_GenericReturnValue
1306GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
1307{
1308 enum GNUNET_GenericReturnValue ret;
1309
1310 if (NULL == h)
1311 {
1312 errno = EINVAL;
1313 return GNUNET_SYSERR;
1314 }
1315
1316 ret = GNUNET_OK;
1317 if (0 != close (h->fd))
1318 {
1319 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1320 ret = GNUNET_SYSERR;
1321 }
1322 GNUNET_free (h);
1323 return ret;
1324}
1325
1326
1327struct GNUNET_DISK_FileHandle *
1328GNUNET_DISK_get_handle_from_int_fd (int fno)
1329{
1330 struct GNUNET_DISK_FileHandle *fh;
1331
1332 if ((((off_t) -1) == lseek (fno, 0, SEEK_CUR)) && (EBADF == errno))
1333 return NULL; /* invalid FD */
1334
1335 fh = GNUNET_new (struct GNUNET_DISK_FileHandle);
1336
1337 fh->fd = fno;
1338
1339 return fh;
1340}
1341
1342
1343struct GNUNET_DISK_FileHandle *
1344GNUNET_DISK_get_handle_from_native (FILE *fd)
1345{
1346 int fno;
1347
1348 fno = fileno (fd);
1349 if (-1 == fno)
1350 return NULL;
1351 return GNUNET_DISK_get_handle_from_int_fd (fno);
1352}
1353
1354
1355/**
1356 * Handle for a memory-mapping operation.
1357 */
1358struct GNUNET_DISK_MapHandle
1359{
1360 /**
1361 * Address where the map is in memory.
1362 */
1363 void *addr;
1364
1365 /**
1366 * Number of bytes mapped.
1367 */
1368 size_t len;
1369};
1370
1371
1372#ifndef MAP_FAILED
1373#define MAP_FAILED ((void *) -1)
1374#endif
1375
1376
1377void *
1378GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h,
1379 struct GNUNET_DISK_MapHandle **m,
1380 enum GNUNET_DISK_MapType access,
1381 size_t len)
1382{
1383 int prot;
1384
1385 if (NULL == h)
1386 {
1387 errno = EINVAL;
1388 return NULL;
1389 }
1390 prot = 0;
1391 if (access & GNUNET_DISK_MAP_TYPE_READ)
1392 prot = PROT_READ;
1393 if (access & GNUNET_DISK_MAP_TYPE_WRITE)
1394 prot |= PROT_WRITE;
1395 *m = GNUNET_new (struct GNUNET_DISK_MapHandle);
1396 (*m)->addr = mmap (NULL, len, prot, MAP_SHARED, h->fd, 0);
1397 GNUNET_assert (NULL != (*m)->addr);
1398 if (MAP_FAILED == (*m)->addr)
1399 {
1400 GNUNET_free (*m);
1401 return NULL;
1402 }
1403 (*m)->len = len;
1404 return (*m)->addr;
1405}
1406
1407
1408enum GNUNET_GenericReturnValue
1409GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h)
1410{
1411 enum GNUNET_GenericReturnValue ret;
1412
1413 if (NULL == h)
1414 {
1415 errno = EINVAL;
1416 return GNUNET_SYSERR;
1417 }
1418 ret = munmap (h->addr, h->len) != -1 ? GNUNET_OK : GNUNET_SYSERR;
1419 GNUNET_free (h);
1420 return ret;
1421}
1422
1423
1424enum GNUNET_GenericReturnValue
1425GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h)
1426{
1427 if (h == NULL)
1428 {
1429 errno = EINVAL;
1430 return GNUNET_SYSERR;
1431 }
1432
1433#if ! defined(__linux__) || ! defined(GNU)
1434 return fsync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
1435#else
1436 return fdatasync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
1437#endif
1438}
1439
1440
1441struct GNUNET_DISK_PipeHandle *
1442GNUNET_DISK_pipe (enum GNUNET_DISK_PipeFlags pf)
1443{
1444 int fd[2];
1445
1446 if (-1 == pipe (fd))
1447 {
1448 int eno = errno;
1449
1450 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
1451 errno = eno;
1452 return NULL;
1453 }
1454 return GNUNET_DISK_pipe_from_fd (pf, fd);
1455}
1456
1457
1458struct GNUNET_DISK_PipeHandle *
1459GNUNET_DISK_pipe_from_fd (enum GNUNET_DISK_PipeFlags pf,
1460 int fd[2])
1461{
1462 struct GNUNET_DISK_PipeHandle *p;
1463 int ret = 0;
1464 int flags;
1465 int eno = 0; /* make gcc happy */
1466
1467 p = GNUNET_new (struct GNUNET_DISK_PipeHandle);
1468 if (fd[0] >= 0)
1469 {
1470 p->fd[0] = GNUNET_new (struct GNUNET_DISK_FileHandle);
1471 p->fd[0]->fd = fd[0];
1472 if (0 == (GNUNET_DISK_PF_BLOCKING_READ & pf))
1473 {
1474 flags = fcntl (fd[0], F_GETFL);
1475 flags |= O_NONBLOCK;
1476 if (0 > fcntl (fd[0], F_SETFL, flags))
1477 {
1478 ret = -1;
1479 eno = errno;
1480 }
1481 }
1482 flags = fcntl (fd[0], F_GETFD);
1483 flags |= FD_CLOEXEC;
1484 if (0 > fcntl (fd[0], F_SETFD, flags))
1485 {
1486 ret = -1;
1487 eno = errno;
1488 }
1489 }
1490
1491 if (fd[1] >= 0)
1492 {
1493 p->fd[1] = GNUNET_new (struct GNUNET_DISK_FileHandle);
1494 p->fd[1]->fd = fd[1];
1495 if (0 == (GNUNET_DISK_PF_BLOCKING_WRITE & pf))
1496 {
1497 flags = fcntl (fd[1], F_GETFL);
1498 flags |= O_NONBLOCK;
1499 if (0 > fcntl (fd[1], F_SETFL, flags))
1500 {
1501 ret = -1;
1502 eno = errno;
1503 }
1504 }
1505 flags = fcntl (fd[1], F_GETFD);
1506 flags |= FD_CLOEXEC;
1507 if (0 > fcntl (fd[1], F_SETFD, flags))
1508 {
1509 ret = -1;
1510 eno = errno;
1511 }
1512 }
1513 if (ret == -1)
1514 {
1515 errno = eno;
1516 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fcntl");
1517 if (p->fd[0]->fd >= 0)
1518 GNUNET_break (0 == close (p->fd[0]->fd));
1519 if (p->fd[1]->fd >= 0)
1520 GNUNET_break (0 == close (p->fd[1]->fd));
1521 GNUNET_free (p->fd[0]);
1522 GNUNET_free (p->fd[1]);
1523 GNUNET_free (p);
1524 errno = eno;
1525 return NULL;
1526 }
1527 return p;
1528}
1529
1530
1531enum GNUNET_GenericReturnValue
1532GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p,
1533 enum GNUNET_DISK_PipeEnd end)
1534{
1535 enum GNUNET_GenericReturnValue ret = GNUNET_OK;
1536
1537 if (end == GNUNET_DISK_PIPE_END_READ)
1538 {
1539 if (p->fd[0])
1540 {
1541 ret = GNUNET_DISK_file_close (p->fd[0]);
1542 p->fd[0] = NULL;
1543 }
1544 }
1545 else if (end == GNUNET_DISK_PIPE_END_WRITE)
1546 {
1547 if (p->fd[1])
1548 {
1549 ret = GNUNET_DISK_file_close (p->fd[1]);
1550 p->fd[1] = NULL;
1551 }
1552 }
1553 return ret;
1554}
1555
1556
1557struct GNUNET_DISK_FileHandle *
1558GNUNET_DISK_pipe_detach_end (struct GNUNET_DISK_PipeHandle *p,
1559 enum GNUNET_DISK_PipeEnd end)
1560{
1561 struct GNUNET_DISK_FileHandle *ret = NULL;
1562
1563 if (end == GNUNET_DISK_PIPE_END_READ)
1564 {
1565 if (p->fd[0])
1566 {
1567 ret = p->fd[0];
1568 p->fd[0] = NULL;
1569 }
1570 }
1571 else if (end == GNUNET_DISK_PIPE_END_WRITE)
1572 {
1573 if (p->fd[1])
1574 {
1575 ret = p->fd[1];
1576 p->fd[1] = NULL;
1577 }
1578 }
1579
1580 return ret;
1581}
1582
1583
1584enum GNUNET_GenericReturnValue
1585GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p)
1586{
1587 int ret = GNUNET_OK;
1588
1589 int read_end_close;
1590 int write_end_close;
1591 int read_end_close_errno;
1592 int write_end_close_errno;
1593
1594 read_end_close = GNUNET_DISK_pipe_close_end (p, GNUNET_DISK_PIPE_END_READ);
1595 read_end_close_errno = errno;
1596 write_end_close = GNUNET_DISK_pipe_close_end (p, GNUNET_DISK_PIPE_END_WRITE);
1597 write_end_close_errno = errno;
1598 GNUNET_free (p);
1599
1600 if (GNUNET_OK != read_end_close)
1601 {
1602 errno = read_end_close_errno;
1603 ret = read_end_close;
1604 }
1605 else if (GNUNET_OK != write_end_close)
1606 {
1607 errno = write_end_close_errno;
1608 ret = write_end_close;
1609 }
1610
1611 return ret;
1612}
1613
1614
1615const struct GNUNET_DISK_FileHandle *
1616GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p,
1617 enum GNUNET_DISK_PipeEnd n)
1618{
1619 switch (n)
1620 {
1621 case GNUNET_DISK_PIPE_END_READ:
1622 case GNUNET_DISK_PIPE_END_WRITE:
1623 return p->fd[n];
1624
1625 default:
1626 GNUNET_break (0);
1627 return NULL;
1628 }
1629}
1630
1631
1632enum GNUNET_GenericReturnValue
1633GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh,
1634 void *dst,
1635 size_t dst_len)
1636{
1637 if (NULL == fh)
1638 return GNUNET_SYSERR;
1639 if (dst_len < sizeof(int))
1640 return GNUNET_SYSERR;
1641 *((int *) dst) = fh->fd;
1642 return GNUNET_OK;
1643}
1644
1645
1646/**
1647 * Helper function for #GNUNET_DISK_purge_cfg_dir.
1648 *
1649 * @param cls a `const char *` with the option to purge
1650 * @param cfg our configuration
1651 * @return #GNUNET_OK on success
1652 */
1653static enum GNUNET_GenericReturnValue
1654purge_cfg_dir (void *cls,
1655 const struct GNUNET_CONFIGURATION_Handle *cfg)
1656{
1657 const char *option = cls;
1658 char *tmpname;
1659
1660 if (GNUNET_OK !=
1661 GNUNET_CONFIGURATION_get_value_filename (cfg, "PATHS", option, &tmpname))
1662 {
1663 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "PATHS", option);
1664 return GNUNET_NO;
1665 }
1666 if (GNUNET_SYSERR == GNUNET_DISK_directory_remove (tmpname))
1667 {
1668 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "remove", tmpname);
1669 GNUNET_free (tmpname);
1670 return GNUNET_OK;
1671 }
1672 GNUNET_free (tmpname);
1673 return GNUNET_OK;
1674}
1675
1676
1677void
1678GNUNET_DISK_purge_cfg_dir (const char *cfg_filename,
1679 const char *option)
1680{
1681 GNUNET_break (GNUNET_OK ==
1682 GNUNET_CONFIGURATION_parse_and_run (cfg_filename,
1683 &purge_cfg_dir,
1684 (void *) option));
1685}
1686
1687
1688/* end of disk.c */