aboutsummaryrefslogtreecommitdiff
path: root/src/util/disk.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2020-12-19 18:43:38 +0100
committerChristian Grothoff <christian@grothoff.org>2020-12-19 18:43:38 +0100
commit3636ea628d051cf2ba7a9038c50528c561d0aeaa (patch)
tree87664b904950052e8b6997a371ed5ecb1ea4b310 /src/util/disk.c
parent74d7528e6bd53cf5acc939c63a5be74a001e5ce1 (diff)
downloadgnunet-3636ea628d051cf2ba7a9038c50528c561d0aeaa.tar.gz
gnunet-3636ea628d051cf2ba7a9038c50528c561d0aeaa.zip
change GNUNET_DISK_fn_write() to always do atomic writes and to NOT overwrite existing files; also change the return value to not return the size of the written file but GNUNET_OK on success, and integrate creating the directory if needed; breaks API, hence bumping libgnunetutil version
Diffstat (limited to 'src/util/disk.c')
-rw-r--r--src/util/disk.c561
1 files changed, 155 insertions, 406 deletions
diff --git a/src/util/disk.c b/src/util/disk.c
index c95e9753c..3bafe311d 100644
--- a/src/util/disk.c
+++ b/src/util/disk.c
@@ -92,7 +92,7 @@ struct GetFileSizeData
92 int include_sym_links; 92 int include_sym_links;
93 93
94 /** 94 /**
95 * GNUNET_YES if mode is file-only (return total == -1 for directories). 95 * #GNUNET_YES if mode is file-only (return total == -1 for directories).
96 */ 96 */
97 int single_file_mode; 97 int single_file_mode;
98}; 98};
@@ -142,8 +142,8 @@ translate_unix_perms (enum GNUNET_DISK_AccessPermissions perm)
142 * @param fn current filename we are looking at 142 * @param fn current filename we are looking at
143 * @return #GNUNET_SYSERR on serious errors, otherwise #GNUNET_OK 143 * @return #GNUNET_SYSERR on serious errors, otherwise #GNUNET_OK
144 */ 144 */
145static int 145static enum GNUNET_GenericReturnValue
146getSizeRec (void *cls, const char *fn) 146get_size_rec (void *cls, const char *fn)
147{ 147{
148 struct GetFileSizeData *gfsd = cls; 148 struct GetFileSizeData *gfsd = cls;
149 149
@@ -175,35 +175,23 @@ getSizeRec (void *cls, const char *fn)
175 if ((S_ISDIR (buf.st_mode)) && (0 == access (fn, X_OK)) && 175 if ((S_ISDIR (buf.st_mode)) && (0 == access (fn, X_OK)) &&
176 ((! S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES))) 176 ((! S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES)))
177 { 177 {
178 if (GNUNET_SYSERR == GNUNET_DISK_directory_scan (fn, &getSizeRec, gfsd)) 178 if (GNUNET_SYSERR == GNUNET_DISK_directory_scan (fn, &get_size_rec, gfsd))
179 return GNUNET_SYSERR; 179 return GNUNET_SYSERR;
180 } 180 }
181 return GNUNET_OK; 181 return GNUNET_OK;
182} 182}
183 183
184 184
185/** 185enum GNUNET_GenericReturnValue
186 * Checks whether a handle is invalid
187 *
188 * @param h handle to check
189 * @return #GNUNET_YES if invalid, #GNUNET_NO if valid
190 */
191int
192GNUNET_DISK_handle_invalid (const struct GNUNET_DISK_FileHandle *h) 186GNUNET_DISK_handle_invalid (const struct GNUNET_DISK_FileHandle *h)
193{ 187{
194 return ((! h) || (h->fd == -1)) ? GNUNET_YES : GNUNET_NO; 188 return ((! h) || (h->fd == -1)) ? GNUNET_YES : GNUNET_NO;
195} 189}
196 190
197 191
198/** 192enum GNUNET_GenericReturnValue
199 * Get the size of an open file. 193GNUNET_DISK_file_handle_size (struct GNUNET_DISK_FileHandle *fh,
200 * 194 off_t *size)
201 * @param fh open file handle
202 * @param size where to write size of the file
203 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
204 */
205int
206GNUNET_DISK_file_handle_size (struct GNUNET_DISK_FileHandle *fh, off_t *size)
207{ 195{
208 struct stat sbuf; 196 struct stat sbuf;
209 197
@@ -214,80 +202,42 @@ GNUNET_DISK_file_handle_size (struct GNUNET_DISK_FileHandle *fh, off_t *size)
214} 202}
215 203
216 204
217/**
218 * Move the read/write pointer in a file
219 *
220 * @param h handle of an open file
221 * @param offset position to move to
222 * @param whence specification to which position the offset parameter relates to
223 * @return the new position on success, #GNUNET_SYSERR otherwise
224 */
225off_t 205off_t
226GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle *h, 206GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle *h,
227 off_t offset, 207 off_t offset,
228 enum GNUNET_DISK_Seek whence) 208 enum GNUNET_DISK_Seek whence)
229{ 209{
210 static int t[] = { SEEK_SET, SEEK_CUR, SEEK_END };
211
230 if (h == NULL) 212 if (h == NULL)
231 { 213 {
232 errno = EINVAL; 214 errno = EINVAL;
233 return GNUNET_SYSERR; 215 return GNUNET_SYSERR;
234 } 216 }
235
236 static int t[] = { SEEK_SET, SEEK_CUR, SEEK_END };
237
238 return lseek (h->fd, offset, t[whence]); 217 return lseek (h->fd, offset, t[whence]);
239} 218}
240 219
241 220
242/** 221enum GNUNET_GenericReturnValue
243 * Get the size of the file (or directory) of the given file (in
244 * bytes).
245 *
246 * @param filename name of the file or directory
247 * @param size set to the size of the file (or,
248 * in the case of directories, the sum
249 * of all sizes of files in the directory)
250 * @param include_symbolic_links should symbolic links be
251 * included?
252 * @param single_file_mode #GNUNET_YES to only get size of one file
253 * and return #GNUNET_SYSERR for directories.
254 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
255 */
256int
257GNUNET_DISK_file_size (const char *filename, 222GNUNET_DISK_file_size (const char *filename,
258 uint64_t *size, 223 uint64_t *size,
259 int include_symbolic_links, 224 int include_symbolic_links,
260 int single_file_mode) 225 int single_file_mode)
261{ 226{
262 struct GetFileSizeData gfsd; 227 struct GetFileSizeData gfsd;
263 int ret; 228 enum GNUNET_GenericReturnValue ret;
264 229
265 GNUNET_assert (size != NULL); 230 GNUNET_assert (size != NULL);
266 gfsd.total = 0; 231 gfsd.total = 0;
267 gfsd.include_sym_links = include_symbolic_links; 232 gfsd.include_sym_links = include_symbolic_links;
268 gfsd.single_file_mode = single_file_mode; 233 gfsd.single_file_mode = single_file_mode;
269 ret = getSizeRec (&gfsd, filename); 234 ret = get_size_rec (&gfsd, filename);
270 *size = gfsd.total; 235 *size = gfsd.total;
271 return ret; 236 return ret;
272} 237}
273 238
274 239
275/** 240enum GNUNET_GenericReturnValue
276 * Obtain some unique identifiers for the given file
277 * that can be used to identify it in the local system.
278 * This function is used between GNUnet processes to
279 * quickly check if two files with the same absolute path
280 * are actually identical. The two processes represent
281 * the same peer but may communicate over the network
282 * (and the file may be on an NFS volume). This function
283 * may not be supported on all operating systems.
284 *
285 * @param filename name of the file
286 * @param dev set to the device ID
287 * @param ino set to the inode ID
288 * @return #GNUNET_OK on success
289 */
290int
291GNUNET_DISK_file_get_identifiers (const char *filename, 241GNUNET_DISK_file_get_identifiers (const char *filename,
292 uint64_t *dev, 242 uint64_t *dev,
293 uint64_t *ino) 243 uint64_t *ino)
@@ -367,14 +317,6 @@ mktemp_name (const char *t)
367} 317}
368 318
369 319
370/**
371 * Update POSIX permissions mask of a file on disk. If both argumets
372 * are #GNUNET_NO, the file is made world-read-write-executable (777).
373 *
374 * @param fn name of the file to update
375 * @param require_uid_match #GNUNET_YES means 700
376 * @param require_gid_match #GNUNET_YES means 770 unless @a require_uid_match is set
377 */
378void 320void
379GNUNET_DISK_fix_permissions (const char *fn, 321GNUNET_DISK_fix_permissions (const char *fn,
380 int require_uid_match, 322 int require_uid_match,
@@ -394,17 +336,6 @@ GNUNET_DISK_fix_permissions (const char *fn,
394} 336}
395 337
396 338
397/**
398 * Create an (empty) temporary directory on disk. If the given name is not
399 * an absolute path, the current 'TMPDIR' will be prepended. In any case,
400 * 6 random characters will be appended to the name to create a unique
401 * filename.
402 *
403 * @param t component to use for the name;
404 * does NOT contain "XXXXXX" or "/tmp/".
405 * @return NULL on error, otherwise name of fresh
406 * file on disk in directory for temporary files
407 */
408char * 339char *
409GNUNET_DISK_mkdtemp (const char *t) 340GNUNET_DISK_mkdtemp (const char *t)
410{ 341{
@@ -425,13 +356,6 @@ GNUNET_DISK_mkdtemp (const char *t)
425} 356}
426 357
427 358
428/**
429 * Move a file out of the way (create a backup) by
430 * renaming it to "orig.NUM~" where NUM is the smallest
431 * number that is not used yet.
432 *
433 * @param fil name of the file to back up
434 */
435void 359void
436GNUNET_DISK_file_backup (const char *fil) 360GNUNET_DISK_file_backup (const char *fil)
437{ 361{
@@ -453,17 +377,6 @@ GNUNET_DISK_file_backup (const char *fil)
453} 377}
454 378
455 379
456/**
457 * Create an (empty) temporary file on disk. If the given name is not
458 * an absolute path, the current 'TMPDIR' will be prepended. In any case,
459 * 6 random characters will be appended to the name to create a unique
460 * filename.
461 *
462 * @param t component to use for the name;
463 * does NOT contain "XXXXXX" or "/tmp/".
464 * @return NULL on error, otherwise name of fresh
465 * file on disk in directory for temporary files
466 */
467char * 380char *
468GNUNET_DISK_mktemp (const char *t) 381GNUNET_DISK_mktemp (const char *t)
469{ 382{
@@ -487,19 +400,7 @@ GNUNET_DISK_mktemp (const char *t)
487} 400}
488 401
489 402
490/** 403enum GNUNET_GenericReturnValue
491 * Test if @a fil is a directory and listable. Optionally, also check if the
492 * directory is readable. Will not print an error message if the directory does
493 * not exist. Will log errors if #GNUNET_SYSERR is returned (i.e., a file exists
494 * with the same name).
495 *
496 * @param fil filename to test
497 * @param is_readable #GNUNET_YES to additionally check if @a fil is readable;
498 * #GNUNET_NO to disable this check
499 * @return #GNUNET_YES if yes, #GNUNET_NO if not; #GNUNET_SYSERR if it
500 * does not exist or stat'ed
501 */
502int
503GNUNET_DISK_directory_test (const char *fil, int is_readable) 404GNUNET_DISK_directory_test (const char *fil, int is_readable)
504{ 405{
505 struct stat filestat; 406 struct stat filestat;
@@ -532,15 +433,7 @@ GNUNET_DISK_directory_test (const char *fil, int is_readable)
532} 433}
533 434
534 435
535/** 436enum GNUNET_GenericReturnValue
536 * Check that fil corresponds to a filename
537 * (of a file that exists and that is not a directory).
538 *
539 * @param fil filename to check
540 * @return #GNUNET_YES if yes, #GNUNET_NO if not a file, #GNUNET_SYSERR if something
541 * else (will print an error message in that case, too).
542 */
543int
544GNUNET_DISK_file_test (const char *fil) 437GNUNET_DISK_file_test (const char *fil)
545{ 438{
546 struct stat filestat; 439 struct stat filestat;
@@ -552,7 +445,7 @@ GNUNET_DISK_file_test (const char *fil)
552 return GNUNET_SYSERR; 445 return GNUNET_SYSERR;
553 446
554 ret = stat (rdir, &filestat); 447 ret = stat (rdir, &filestat);
555 if (ret != 0) 448 if (0 != ret)
556 { 449 {
557 if (errno != ENOENT) 450 if (errno != ENOENT)
558 { 451 {
@@ -579,13 +472,7 @@ GNUNET_DISK_file_test (const char *fil)
579} 472}
580 473
581 474
582/** 475enum GNUNET_GenericReturnValue
583 * Implementation of "mkdir -p"
584 *
585 * @param dir the directory to create
586 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
587 */
588int
589GNUNET_DISK_directory_create (const char *dir) 476GNUNET_DISK_directory_create (const char *dir)
590{ 477{
591 char *rdir; 478 char *rdir;
@@ -671,22 +558,13 @@ GNUNET_DISK_directory_create (const char *dir)
671} 558}
672 559
673 560
674/** 561enum GNUNET_GenericReturnValue
675 * Create the directory structure for storing a file.
676 *
677 * @param filename name of a file in the directory
678 * @returns #GNUNET_OK on success,
679 * #GNUNET_SYSERR on failure,
680 * #GNUNET_NO if the directory
681 * exists but is not writeable for us
682 */
683int
684GNUNET_DISK_directory_create_for_file (const char *filename) 562GNUNET_DISK_directory_create_for_file (const char *filename)
685{ 563{
686 char *rdir; 564 char *rdir;
687 size_t len; 565 size_t len;
688 int ret;
689 int eno; 566 int eno;
567 enum GNUNET_GenericReturnValue res;
690 568
691 rdir = GNUNET_STRINGS_filename_expand (filename); 569 rdir = GNUNET_STRINGS_filename_expand (filename);
692 if (NULL == rdir) 570 if (NULL == rdir)
@@ -699,7 +577,6 @@ GNUNET_DISK_directory_create_for_file (const char *filename)
699 GNUNET_free (rdir); 577 GNUNET_free (rdir);
700 return GNUNET_OK; 578 return GNUNET_OK;
701 } 579 }
702
703 len = strlen (rdir); 580 len = strlen (rdir);
704 while ((len > 0) && (rdir[len] != DIR_SEPARATOR)) 581 while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
705 len--; 582 len--;
@@ -710,24 +587,17 @@ GNUNET_DISK_directory_create_for_file (const char *filename)
710 GNUNET_free (rdir); 587 GNUNET_free (rdir);
711 rdir = GNUNET_strdup ("/"); 588 rdir = GNUNET_strdup ("/");
712 } 589 }
713 ret = GNUNET_DISK_directory_create (rdir); 590 res = GNUNET_DISK_directory_create (rdir);
714 if ((GNUNET_OK == ret) && (0 != access (rdir, W_OK))) 591 if ( (GNUNET_OK == res) &&
715 ret = GNUNET_NO; 592 (0 != access (rdir, W_OK)) )
593 res = GNUNET_NO;
716 eno = errno; 594 eno = errno;
717 GNUNET_free (rdir); 595 GNUNET_free (rdir);
718 errno = eno; 596 errno = eno;
719 return ret; 597 return res;
720} 598}
721 599
722 600
723/**
724 * Read the contents of a binary file into a buffer.
725 *
726 * @param h handle to an open file
727 * @param result the buffer to write the result to
728 * @param len the maximum number of bytes to read
729 * @return the number of bytes read on success, #GNUNET_SYSERR on failure
730 */
731ssize_t 601ssize_t
732GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle *h, 602GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle *h,
733 void *result, 603 void *result,
@@ -738,35 +608,23 @@ GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle *h,
738 errno = EINVAL; 608 errno = EINVAL;
739 return GNUNET_SYSERR; 609 return GNUNET_SYSERR;
740 } 610 }
741
742 return read (h->fd, result, len); 611 return read (h->fd, result, len);
743} 612}
744 613
745 614
746/**
747 * Read the contents of a binary file into a buffer.
748 * Guarantees not to block (returns GNUNET_SYSERR and sets errno to EAGAIN
749 * when no data can be read).
750 *
751 * @param h handle to an open file
752 * @param result the buffer to write the result to
753 * @param len the maximum number of bytes to read
754 * @return the number of bytes read on success, #GNUNET_SYSERR on failure
755 */
756ssize_t 615ssize_t
757GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle *h, 616GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle *h,
758 void *result, 617 void *result,
759 size_t len) 618 size_t len)
760{ 619{
620 int flags;
621 ssize_t ret;
622
761 if (NULL == h) 623 if (NULL == h)
762 { 624 {
763 errno = EINVAL; 625 errno = EINVAL;
764 return GNUNET_SYSERR; 626 return GNUNET_SYSERR;
765 } 627 }
766
767 int flags;
768 ssize_t ret;
769
770 /* set to non-blocking, read, then set back */ 628 /* set to non-blocking, read, then set back */
771 flags = fcntl (h->fd, F_GETFL); 629 flags = fcntl (h->fd, F_GETFL);
772 if (0 == (flags & O_NONBLOCK)) 630 if (0 == (flags & O_NONBLOCK))
@@ -782,22 +640,18 @@ GNUNET_DISK_file_read_non_blocking (const struct GNUNET_DISK_FileHandle *h,
782} 640}
783 641
784 642
785/**
786 * Read the contents of a binary file into a buffer.
787 *
788 * @param fn file name
789 * @param result the buffer to write the result to
790 * @param len the maximum number of bytes to read
791 * @return number of bytes read, #GNUNET_SYSERR on failure
792 */
793ssize_t 643ssize_t
794GNUNET_DISK_fn_read (const char *fn, void *result, size_t len) 644GNUNET_DISK_fn_read (const char *fn,
645 void *result,
646 size_t len)
795{ 647{
796 struct GNUNET_DISK_FileHandle *fh; 648 struct GNUNET_DISK_FileHandle *fh;
797 ssize_t ret; 649 ssize_t ret;
798 int eno; 650 int eno;
799 651
800 fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); 652 fh = GNUNET_DISK_file_open (fn,
653 GNUNET_DISK_OPEN_READ,
654 GNUNET_DISK_PERM_NONE);
801 if (NULL == fh) 655 if (NULL == fh)
802 return GNUNET_SYSERR; 656 return GNUNET_SYSERR;
803 ret = GNUNET_DISK_file_read (fh, result, len); 657 ret = GNUNET_DISK_file_read (fh, result, len);
@@ -808,14 +662,6 @@ GNUNET_DISK_fn_read (const char *fn, void *result, size_t len)
808} 662}
809 663
810 664
811/**
812 * Write a buffer to a file.
813 *
814 * @param h handle to open file
815 * @param buffer the data to write
816 * @param n number of bytes to write
817 * @return number of bytes written on success, #GNUNET_SYSERR on error
818 */
819ssize_t 665ssize_t
820GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle *h, 666GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle *h,
821 const void *buffer, 667 const void *buffer,
@@ -831,29 +677,19 @@ GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle *h,
831} 677}
832 678
833 679
834/**
835 * Write a buffer to a file, blocking, if necessary.
836 *
837 * @param h handle to open file
838 * @param buffer the data to write
839 * @param n number of bytes to write
840 * @return number of bytes written on success, #GNUNET_SYSERR on error
841 */
842ssize_t 680ssize_t
843GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle *h, 681GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle *h,
844 const void *buffer, 682 const void *buffer,
845 size_t n) 683 size_t n)
846{ 684{
685 int flags;
686 ssize_t ret;
687
847 if (NULL == h) 688 if (NULL == h)
848 { 689 {
849 errno = EINVAL; 690 errno = EINVAL;
850 return GNUNET_SYSERR; 691 return GNUNET_SYSERR;
851 } 692 }
852
853
854 int flags;
855 ssize_t ret;
856
857 /* set to blocking, write, then set back */ 693 /* set to blocking, write, then set back */
858 flags = fcntl (h->fd, F_GETFL); 694 flags = fcntl (h->fd, F_GETFL);
859 if (0 != (flags & O_NONBLOCK)) 695 if (0 != (flags & O_NONBLOCK))
@@ -865,48 +701,95 @@ GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle *h,
865} 701}
866 702
867 703
868/** 704enum GNUNET_GenericReturnValue
869 * Write a buffer to a file. If the file is longer than the
870 * number of bytes that will be written, it will be truncated.
871 *
872 * @param fn file name
873 * @param buffer the data to write
874 * @param n number of bytes to write
875 * @param mode file permissions
876 * @return number of bytes written on success, #GNUNET_SYSERR on error
877 */
878ssize_t
879GNUNET_DISK_fn_write (const char *fn, 705GNUNET_DISK_fn_write (const char *fn,
880 const void *buffer, 706 const void *buf,
881 size_t n, 707 size_t buf_size,
882 enum GNUNET_DISK_AccessPermissions mode) 708 enum GNUNET_DISK_AccessPermissions mode)
883{ 709{
884 struct GNUNET_DISK_FileHandle *fh; 710 char *tmpl;
885 ssize_t ret; 711 int fd;
886 712
887 fh = 713 if (GNUNET_OK !=
888 GNUNET_DISK_file_open (fn, 714 GNUNET_DISK_directory_create_for_file (fn))
889 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE 715 {
890 | GNUNET_DISK_OPEN_CREATE, 716 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
891 mode); 717 "mkstemp",
892 if (! fh) 718 fn);
893 return GNUNET_SYSERR; 719 return GNUNET_SYSERR;
894 ret = GNUNET_DISK_file_write (fh, buffer, n); 720 }
895 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh)); 721 {
896 return ret; 722 char *dname;
723
724 dname = GNUNET_strdup (fn);
725 GNUNET_asprintf (&tmpl,
726 "%s/XXXXXX",
727 dirname (dname));
728 GNUNET_free (dname);
729 }
730 fd = mkstemp (tmpl);
731 if (-1 == fd)
732 {
733 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
734 "mkstemp",
735 tmpl);
736 GNUNET_free (tmpl);
737 return GNUNET_SYSERR;
738 }
739
740 if (0 != fchmod (fd,
741 translate_unix_perms (mode)))
742 {
743 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
744 "chmod",
745 tmpl);
746 GNUNET_assert (0 == close (fd));
747 if (0 != unlink (tmpl))
748 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
749 "unlink",
750 tmpl);
751 GNUNET_free (tmpl);
752 return GNUNET_SYSERR;
753 }
754 if (buf_size !=
755 write (fd,
756 buf,
757 buf_size))
758 {
759 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
760 "write",
761 tmpl);
762 GNUNET_assert (0 == close (fd));
763 if (0 != unlink (tmpl))
764 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
765 "unlink",
766 tmpl);
767 GNUNET_free (tmpl);
768 return GNUNET_SYSERR;
769 }
770 GNUNET_assert (0 == close (fd));
771
772 if (0 != link (tmpl,
773 fn))
774 {
775 if (0 != unlink (tmpl))
776 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
777 "unlink",
778 tmpl);
779 GNUNET_free (tmpl);
780 return GNUNET_NO;
781 }
782 if (0 != unlink (tmpl))
783 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
784 "unlink",
785 tmpl);
786 GNUNET_free (tmpl);
787 return GNUNET_OK;
788
789
897} 790}
898 791
899 792
900/**
901 * Scan a directory for files.
902 *
903 * @param dir_name the name of the directory
904 * @param callback the method to call for each file,
905 * can be NULL, in that case, we only count
906 * @param callback_cls closure for @a callback
907 * @return the number of files found, #GNUNET_SYSERR on error or
908 * ieration aborted by callback returning #GNUNET_SYSERR
909 */
910int 793int
911GNUNET_DISK_directory_scan (const char *dir_name, 794GNUNET_DISK_directory_scan (const char *dir_name,
912 GNUNET_FileNameCallback callback, 795 GNUNET_FileNameCallback callback,
@@ -916,7 +799,7 @@ GNUNET_DISK_directory_scan (const char *dir_name,
916 struct dirent *finfo; 799 struct dirent *finfo;
917 struct stat istat; 800 struct stat istat;
918 int count = 0; 801 int count = 0;
919 int ret; 802 enum GNUNET_GenericReturnValue ret;
920 char *name; 803 char *name;
921 char *dname; 804 char *dname;
922 unsigned int name_len; 805 unsigned int name_len;
@@ -1008,8 +891,9 @@ GNUNET_DISK_directory_scan (const char *dir_name,
1008 * @param fn directory to remove 891 * @param fn directory to remove
1009 * @return #GNUNET_OK 892 * @return #GNUNET_OK
1010 */ 893 */
1011static int 894static enum GNUNET_GenericReturnValue
1012remove_helper (void *unused, const char *fn) 895remove_helper (void *unused,
896 const char *fn)
1013{ 897{
1014 (void) unused; 898 (void) unused;
1015 (void) GNUNET_DISK_directory_remove (fn); 899 (void) GNUNET_DISK_directory_remove (fn);
@@ -1017,14 +901,7 @@ remove_helper (void *unused, const char *fn)
1017} 901}
1018 902
1019 903
1020/** 904enum GNUNET_GenericReturnValue
1021 * Remove all files in a directory (rm -r). Call with
1022 * caution.
1023 *
1024 * @param filename the file to remove
1025 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1026 */
1027int
1028GNUNET_DISK_directory_remove (const char *filename) 905GNUNET_DISK_directory_remove (const char *filename)
1029{ 906{
1030 struct stat istat; 907 struct stat istat;
@@ -1036,14 +913,17 @@ GNUNET_DISK_directory_remove (const char *filename)
1036 } 913 }
1037 if (0 != lstat (filename, &istat)) 914 if (0 != lstat (filename, &istat))
1038 return GNUNET_NO; /* file may not exist... */ 915 return GNUNET_NO; /* file may not exist... */
1039 (void) chmod (filename, S_IWUSR | S_IRUSR | S_IXUSR); 916 (void) chmod (filename,
917 S_IWUSR | S_IRUSR | S_IXUSR);
1040 if (0 == unlink (filename)) 918 if (0 == unlink (filename))
1041 return GNUNET_OK; 919 return GNUNET_OK;
1042 if ((errno != EISDIR) && 920 if ( (errno != EISDIR) &&
1043 /* EISDIR is not sufficient in all cases, e.g. 921 /* EISDIR is not sufficient in all cases, e.g.
1044 * sticky /tmp directory may result in EPERM on BSD. 922 * sticky /tmp directory may result in EPERM on BSD.
1045 * So we also explicitly check "isDirectory" */ 923 * So we also explicitly check "isDirectory" */
1046 (GNUNET_YES != GNUNET_DISK_directory_test (filename, GNUNET_YES))) 924 (GNUNET_YES !=
925 GNUNET_DISK_directory_test (filename,
926 GNUNET_YES)) )
1047 { 927 {
1048 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename); 928 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "rmdir", filename);
1049 return GNUNET_SYSERR; 929 return GNUNET_SYSERR;
@@ -1060,15 +940,9 @@ GNUNET_DISK_directory_remove (const char *filename)
1060} 940}
1061 941
1062 942
1063/** 943enum GNUNET_GenericReturnValue
1064 * Copy a file. 944GNUNET_DISK_file_copy (const char *src,
1065 * 945 const char *dst)
1066 * @param src file to copy
1067 * @param dst destination file name
1068 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1069 */
1070int
1071GNUNET_DISK_file_copy (const char *src, const char *dst)
1072{ 946{
1073 char *buf; 947 char *buf;
1074 uint64_t pos; 948 uint64_t pos;
@@ -1131,10 +1005,6 @@ FAIL:
1131} 1005}
1132 1006
1133 1007
1134/**
1135 * @brief Removes special characters as ':' from a filename.
1136 * @param fn the filename to canonicalize
1137 */
1138void 1008void
1139GNUNET_DISK_filename_canonicalize (char *fn) 1009GNUNET_DISK_filename_canonicalize (char *fn)
1140{ 1010{
@@ -1157,15 +1027,9 @@ GNUNET_DISK_filename_canonicalize (char *fn)
1157} 1027}
1158 1028
1159 1029
1160/** 1030enum GNUNET_GenericReturnValue
1161 * @brief Change owner of a file 1031GNUNET_DISK_file_change_owner (const char *filename,
1162 * 1032 const char *user)
1163 * @param filename name of file to change the owner of
1164 * @param user name of the new owner
1165 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1166 */
1167int
1168GNUNET_DISK_file_change_owner (const char *filename, const char *user)
1169{ 1033{
1170 struct passwd *pws; 1034 struct passwd *pws;
1171 1035
@@ -1187,18 +1051,6 @@ GNUNET_DISK_file_change_owner (const char *filename, const char *user)
1187} 1051}
1188 1052
1189 1053
1190/**
1191 * Open a file. Note that the access permissions will only be
1192 * used if a new file is created and if the underlying operating
1193 * system supports the given permissions.
1194 *
1195 * @param fn file name to be opened
1196 * @param flags opening flags, a combination of GNUNET_DISK_OPEN_xxx bit flags
1197 * @param perm permissions for the newly created file, use
1198 * #GNUNET_DISK_PERM_NONE if a file could not be created by this
1199 * call (because of flags)
1200 * @return IO handle on success, NULL on error
1201 */
1202struct GNUNET_DISK_FileHandle * 1054struct GNUNET_DISK_FileHandle *
1203GNUNET_DISK_file_open (const char *fn, 1055GNUNET_DISK_file_open (const char *fn,
1204 enum GNUNET_DISK_OpenFlags flags, 1056 enum GNUNET_DISK_OpenFlags flags,
@@ -1270,42 +1122,28 @@ GNUNET_DISK_file_open (const char *fn,
1270} 1122}
1271 1123
1272 1124
1273/** 1125enum GNUNET_GenericReturnValue
1274 * Close an open file.
1275 *
1276 * @param h file handle
1277 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
1278 */
1279int
1280GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h) 1126GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
1281{ 1127{
1282 int ret; 1128 enum GNUNET_GenericReturnValue ret;
1283 1129
1284 if (h == NULL) 1130 if (NULL == h)
1285 { 1131 {
1286 errno = EINVAL; 1132 errno = EINVAL;
1287 return GNUNET_SYSERR; 1133 return GNUNET_SYSERR;
1288 } 1134 }
1289 1135
1290 ret = GNUNET_OK; 1136 ret = GNUNET_OK;
1291 1137 if (0 != close (h->fd))
1292 if (close (h->fd) != 0)
1293 { 1138 {
1294 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close"); 1139 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close");
1295 ret = GNUNET_SYSERR; 1140 ret = GNUNET_SYSERR;
1296 } 1141 }
1297
1298 GNUNET_free (h); 1142 GNUNET_free (h);
1299 return ret; 1143 return ret;
1300} 1144}
1301 1145
1302 1146
1303/**
1304 * Get a handle from a native integer FD.
1305 *
1306 * @param fno native integer file descriptor
1307 * @return file handle corresponding to the descriptor, NULL on error
1308 */
1309struct GNUNET_DISK_FileHandle * 1147struct GNUNET_DISK_FileHandle *
1310GNUNET_DISK_get_handle_from_int_fd (int fno) 1148GNUNET_DISK_get_handle_from_int_fd (int fno)
1311{ 1149{
@@ -1322,12 +1160,6 @@ GNUNET_DISK_get_handle_from_int_fd (int fno)
1322} 1160}
1323 1161
1324 1162
1325/**
1326 * Get a handle from a native streaming FD.
1327 *
1328 * @param fd native streaming file descriptor
1329 * @return file handle corresponding to the descriptor
1330 */
1331struct GNUNET_DISK_FileHandle * 1163struct GNUNET_DISK_FileHandle *
1332GNUNET_DISK_get_handle_from_native (FILE *fd) 1164GNUNET_DISK_get_handle_from_native (FILE *fd)
1333{ 1165{
@@ -1336,7 +1168,6 @@ GNUNET_DISK_get_handle_from_native (FILE *fd)
1336 fno = fileno (fd); 1168 fno = fileno (fd);
1337 if (-1 == fno) 1169 if (-1 == fno)
1338 return NULL; 1170 return NULL;
1339
1340 return GNUNET_DISK_get_handle_from_int_fd (fno); 1171 return GNUNET_DISK_get_handle_from_int_fd (fno);
1341} 1172}
1342 1173
@@ -1362,15 +1193,7 @@ struct GNUNET_DISK_MapHandle
1362#define MAP_FAILED ((void *) -1) 1193#define MAP_FAILED ((void *) -1)
1363#endif 1194#endif
1364 1195
1365/** 1196
1366 * Map a file into memory
1367 *
1368 * @param h open file handle
1369 * @param m handle to the new mapping
1370 * @param access access specification, GNUNET_DISK_MAP_TYPE_xxx
1371 * @param len size of the mapping
1372 * @return pointer to the mapped memory region, NULL on failure
1373 */
1374void * 1197void *
1375GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h, 1198GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h,
1376 struct GNUNET_DISK_MapHandle **m, 1199 struct GNUNET_DISK_MapHandle **m,
@@ -1402,16 +1225,10 @@ GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h,
1402} 1225}
1403 1226
1404 1227
1405/** 1228enum GNUNET_GenericReturnValue
1406 * Unmap a file
1407 *
1408 * @param h mapping handle
1409 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
1410 */
1411int
1412GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h) 1229GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h)
1413{ 1230{
1414 int ret; 1231 enum GNUNET_GenericReturnValue ret;
1415 1232
1416 if (NULL == h) 1233 if (NULL == h)
1417 { 1234 {
@@ -1424,12 +1241,7 @@ GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h)
1424} 1241}
1425 1242
1426 1243
1427/** 1244enum GNUNET_GenericReturnValue
1428 * Write file changes to disk
1429 * @param h handle to an open file
1430 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
1431 */
1432int
1433GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h) 1245GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h)
1434{ 1246{
1435 if (h == NULL) 1247 if (h == NULL)
@@ -1446,12 +1258,6 @@ GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h)
1446} 1258}
1447 1259
1448 1260
1449/**
1450 * Creates an interprocess channel
1451 *
1452 * @param pf how to configure the pipe
1453 * @return handle to the new pipe, NULL on error
1454 */
1455struct GNUNET_DISK_PipeHandle * 1261struct GNUNET_DISK_PipeHandle *
1456GNUNET_DISK_pipe (enum GNUNET_DISK_PipeFlags pf) 1262GNUNET_DISK_pipe (enum GNUNET_DISK_PipeFlags pf)
1457{ 1263{
@@ -1469,15 +1275,6 @@ GNUNET_DISK_pipe (enum GNUNET_DISK_PipeFlags pf)
1469} 1275}
1470 1276
1471 1277
1472/**
1473 * Creates a pipe object from a couple of file descriptors.
1474 * Useful for wrapping existing pipe FDs.
1475 *
1476 * @param pf how to configure the pipe
1477 * @param fd an array of two fd values. One of them may be -1 for read-only or write-only pipes
1478 *
1479 * @return handle to the new pipe, NULL on error
1480 */
1481struct GNUNET_DISK_PipeHandle * 1278struct GNUNET_DISK_PipeHandle *
1482GNUNET_DISK_pipe_from_fd (enum GNUNET_DISK_PipeFlags pf, 1279GNUNET_DISK_pipe_from_fd (enum GNUNET_DISK_PipeFlags pf,
1483 int fd[2]) 1280 int fd[2])
@@ -1551,18 +1348,11 @@ GNUNET_DISK_pipe_from_fd (enum GNUNET_DISK_PipeFlags pf,
1551} 1348}
1552 1349
1553 1350
1554/** 1351enum GNUNET_GenericReturnValue
1555 * Closes an interprocess channel
1556 *
1557 * @param p pipe to close
1558 * @param end which end of the pipe to close
1559 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
1560 */
1561int
1562GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p, 1352GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p,
1563 enum GNUNET_DISK_PipeEnd end) 1353 enum GNUNET_DISK_PipeEnd end)
1564{ 1354{
1565 int ret = GNUNET_OK; 1355 enum GNUNET_GenericReturnValue ret = GNUNET_OK;
1566 1356
1567 if (end == GNUNET_DISK_PIPE_END_READ) 1357 if (end == GNUNET_DISK_PIPE_END_READ)
1568 { 1358 {
@@ -1580,23 +1370,10 @@ GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p,
1580 p->fd[1] = NULL; 1370 p->fd[1] = NULL;
1581 } 1371 }
1582 } 1372 }
1583
1584 return ret; 1373 return ret;
1585} 1374}
1586 1375
1587 1376
1588/**
1589 * Detaches one of the ends from the pipe.
1590 * Detached end is a fully-functional FileHandle, it will
1591 * not be affected by anything you do with the pipe afterwards.
1592 * Each end of a pipe can only be detched from it once (i.e.
1593 * it is not duplicated).
1594 *
1595 * @param p pipe to detach an end from
1596 * @param end which end of the pipe to detach
1597 * @return Detached end on success, NULL on failure
1598 * (or if that end is not present or is closed).
1599 */
1600struct GNUNET_DISK_FileHandle * 1377struct GNUNET_DISK_FileHandle *
1601GNUNET_DISK_pipe_detach_end (struct GNUNET_DISK_PipeHandle *p, 1378GNUNET_DISK_pipe_detach_end (struct GNUNET_DISK_PipeHandle *p,
1602 enum GNUNET_DISK_PipeEnd end) 1379 enum GNUNET_DISK_PipeEnd end)
@@ -1624,13 +1401,7 @@ GNUNET_DISK_pipe_detach_end (struct GNUNET_DISK_PipeHandle *p,
1624} 1401}
1625 1402
1626 1403
1627/** 1404enum GNUNET_GenericReturnValue
1628 * Closes an interprocess channel
1629 *
1630 * @param p pipe to close
1631 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
1632 */
1633int
1634GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p) 1405GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p)
1635{ 1406{
1636 int ret = GNUNET_OK; 1407 int ret = GNUNET_OK;
@@ -1661,13 +1432,6 @@ GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p)
1661} 1432}
1662 1433
1663 1434
1664/**
1665 * Get the handle to a particular pipe end
1666 *
1667 * @param p pipe
1668 * @param n end to access
1669 * @return handle for the respective end
1670 */
1671const struct GNUNET_DISK_FileHandle * 1435const struct GNUNET_DISK_FileHandle *
1672GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p, 1436GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p,
1673 enum GNUNET_DISK_PipeEnd n) 1437 enum GNUNET_DISK_PipeEnd n)
@@ -1685,26 +1449,16 @@ GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p,
1685} 1449}
1686 1450
1687 1451
1688/** 1452enum GNUNET_GenericReturnValue
1689 * Retrieve OS file handle
1690 * @internal
1691 * @param fh GNUnet file descriptor
1692 * @param dst destination buffer
1693 * @param dst_len length of dst
1694 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
1695 */
1696int
1697GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh, 1453GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh,
1698 void *dst, 1454 void *dst,
1699 size_t dst_len) 1455 size_t dst_len)
1700{ 1456{
1701 if (NULL == fh) 1457 if (NULL == fh)
1702 return GNUNET_SYSERR; 1458 return GNUNET_SYSERR;
1703
1704 if (dst_len < sizeof(int)) 1459 if (dst_len < sizeof(int))
1705 return GNUNET_SYSERR; 1460 return GNUNET_SYSERR;
1706 *((int *) dst) = fh->fd; 1461 *((int *) dst) = fh->fd;
1707
1708 return GNUNET_OK; 1462 return GNUNET_OK;
1709} 1463}
1710 1464
@@ -1716,8 +1470,9 @@ GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh,
1716 * @param cfg our configuration 1470 * @param cfg our configuration
1717 * @return #GNUNET_OK on success 1471 * @return #GNUNET_OK on success
1718 */ 1472 */
1719static int 1473static enum GNUNET_GenericReturnValue
1720purge_cfg_dir (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg) 1474purge_cfg_dir (void *cls,
1475 const struct GNUNET_CONFIGURATION_Handle *cfg)
1721{ 1476{
1722 const char *option = cls; 1477 const char *option = cls;
1723 char *tmpname; 1478 char *tmpname;
@@ -1739,15 +1494,9 @@ purge_cfg_dir (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
1739} 1494}
1740 1495
1741 1496
1742/**
1743 * Remove the directory given under @a option in
1744 * section [PATHS] in configuration under @a cfg_filename
1745 *
1746 * @param cfg_filename configuration file to parse
1747 * @param option option with the dir name to purge
1748 */
1749void 1497void
1750GNUNET_DISK_purge_cfg_dir (const char *cfg_filename, const char *option) 1498GNUNET_DISK_purge_cfg_dir (const char *cfg_filename,
1499 const char *option)
1751{ 1500{
1752 GNUNET_break (GNUNET_OK == 1501 GNUNET_break (GNUNET_OK ==
1753 GNUNET_CONFIGURATION_parse_and_run (cfg_filename, 1502 GNUNET_CONFIGURATION_parse_and_run (cfg_filename,