gnunet_disk_lib.h (20995B)
1 /* 2 This file is part of GNUnet. 3 Copyright (C) 2001-2012 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 * @addtogroup libgnunetutil 22 * Multi-function utilities library for GNUnet programs 23 * @{ 24 * 25 * @author Christian Grothoff 26 * 27 * @file 28 * Disk IO APIs 29 * 30 * @defgroup disk Disk library 31 * Disk IO APIs 32 * @{ 33 */ 34 35 #if ! defined (__GNUNET_UTIL_LIB_H_INSIDE__) 36 #error "Only <gnunet_util_lib.h> can be included directly." 37 #endif 38 39 #ifndef GNUNET_DISK_LIB_H 40 #define GNUNET_DISK_LIB_H 41 42 /** 43 * Handle used to manage a pipe. 44 */ 45 struct GNUNET_DISK_PipeHandle; 46 47 /** 48 * Type of a handle. 49 */ 50 enum GNUNET_FILE_Type 51 { 52 /** 53 * Handle represents an event. 54 */ 55 GNUNET_DISK_HANLDE_TYPE_EVENT, 56 57 /** 58 * Handle represents a file. 59 */ 60 GNUNET_DISK_HANLDE_TYPE_FILE, 61 62 /** 63 * Handle represents a pipe. 64 */ 65 GNUNET_DISK_HANLDE_TYPE_PIPE 66 }; 67 68 /** 69 * Handle used to access files (and pipes). 70 */ 71 struct GNUNET_DISK_FileHandle 72 { 73 /** 74 * File handle on Unix-like systems. 75 */ 76 int fd; 77 }; 78 79 80 /* we need size_t, and since it can be both unsigned int 81 or unsigned long long, this IS platform dependent; 82 but "stdlib.h" should be portable 'enough' to be 83 unconditionally available... */ 84 85 #include <stdlib.h> 86 #include "gnunet_configuration_lib.h" 87 #include "gnunet_scheduler_lib.h" 88 89 #ifdef __cplusplus 90 extern "C" 91 { 92 #if 0 /* keep Emacsens' auto-indent happy */ 93 } 94 #endif 95 #endif 96 97 98 /** 99 * Specifies how a file should be opened. 100 */ 101 enum GNUNET_DISK_OpenFlags 102 { 103 /** 104 * Open the file for reading 105 */ 106 GNUNET_DISK_OPEN_READ = 1, 107 108 /** 109 * Open the file for writing 110 */ 111 GNUNET_DISK_OPEN_WRITE = 2, 112 113 /** 114 * Open the file for both reading and writing 115 */ 116 GNUNET_DISK_OPEN_READWRITE = 3, 117 118 /** 119 * Fail if file already exists 120 */ 121 GNUNET_DISK_OPEN_FAILIFEXISTS = 4, 122 123 /** 124 * Truncate file if it exists 125 */ 126 GNUNET_DISK_OPEN_TRUNCATE = 8, 127 128 /** 129 * Create file if it doesn't exist 130 */ 131 GNUNET_DISK_OPEN_CREATE = 16, 132 133 /** 134 * Append to the file 135 */ 136 GNUNET_DISK_OPEN_APPEND = 32 137 }; 138 139 /** 140 * Specifies what type of memory map is desired. 141 */ 142 enum GNUNET_DISK_MapType 143 { 144 /** 145 * Read-only memory map. 146 */ 147 GNUNET_DISK_MAP_TYPE_READ = 1, 148 149 /** 150 * Write-able memory map. 151 */ 152 GNUNET_DISK_MAP_TYPE_WRITE = 2, 153 154 /** 155 * Read-write memory map. 156 */ 157 GNUNET_DISK_MAP_TYPE_READWRITE = 3 158 }; 159 160 161 /** 162 * File access permissions, UNIX-style. 163 */ 164 enum GNUNET_DISK_AccessPermissions 165 { 166 /** 167 * Nobody is allowed to do anything to the file. 168 */ 169 GNUNET_DISK_PERM_NONE = 0, 170 171 /** 172 * Owner can read. 173 */ 174 GNUNET_DISK_PERM_USER_READ = 1, 175 176 /** 177 * Owner can write. 178 */ 179 GNUNET_DISK_PERM_USER_WRITE = 2, 180 181 /** 182 * Owner can execute. 183 */ 184 GNUNET_DISK_PERM_USER_EXEC = 4, 185 186 /** 187 * Group can read. 188 */ 189 GNUNET_DISK_PERM_GROUP_READ = 8, 190 191 /** 192 * Group can write. 193 */ 194 GNUNET_DISK_PERM_GROUP_WRITE = 16, 195 196 /** 197 * Group can execute. 198 */ 199 GNUNET_DISK_PERM_GROUP_EXEC = 32, 200 201 /** 202 * Everybody can read. 203 */ 204 GNUNET_DISK_PERM_OTHER_READ = 64, 205 206 /** 207 * Everybody can write. 208 */ 209 GNUNET_DISK_PERM_OTHER_WRITE = 128, 210 211 /** 212 * Everybody can execute. 213 */ 214 GNUNET_DISK_PERM_OTHER_EXEC = 256 215 }; 216 217 218 /** 219 * Constants for specifying how to seek. Do not change values or order, 220 * some of the code depends on the specific numeric values! 221 */ 222 enum GNUNET_DISK_Seek 223 { 224 /** 225 * Seek an absolute position (from the start of the file). 226 */ 227 GNUNET_DISK_SEEK_SET = 0, 228 229 /** 230 * Seek a relative position (from the current offset). 231 */ 232 GNUNET_DISK_SEEK_CUR = 1, 233 234 /** 235 * Seek an absolute position from the end of the file. 236 */ 237 GNUNET_DISK_SEEK_END = 2 238 }; 239 240 241 /** 242 * Enumeration identifying the two ends of a pipe. 243 */ 244 enum GNUNET_DISK_PipeEnd 245 { 246 /** 247 * The reading-end of a pipe. 248 */ 249 GNUNET_DISK_PIPE_END_READ = 0, 250 251 /** 252 * The writing-end of a pipe. 253 */ 254 GNUNET_DISK_PIPE_END_WRITE = 1 255 }; 256 257 258 /** 259 * Checks whether a handle is invalid 260 * 261 * @param h handle to check 262 * @return #GNUNET_YES if invalid, #GNUNET_NO if valid 263 */ 264 enum GNUNET_GenericReturnValue 265 GNUNET_DISK_handle_invalid (const struct GNUNET_DISK_FileHandle *h); 266 267 268 /** 269 * Check that fil corresponds to a filename 270 * (of a file that exists and that is not a directory). 271 * 272 * @param fil filename to check 273 * @return #GNUNET_YES if yes, #GNUNET_NO if not a file, #GNUNET_SYSERR if something 274 * else (will print an error message in that case, too). 275 */ 276 enum GNUNET_GenericReturnValue 277 GNUNET_DISK_file_test (const char *fil); 278 279 280 /** 281 * Check that fil corresponds to a filename and the file has read permissions. 282 * 283 * @param fil filename to check 284 * @return #GNUNET_YES if yes, #GNUNET_NO if file doesn't exist or 285 * has no read permissions, #GNUNET_SYSERR if something else 286 * (will print an error message in that case, too). 287 */ 288 enum GNUNET_GenericReturnValue 289 GNUNET_DISK_file_test_read (const char *fil); 290 291 292 /** 293 * Move a file out of the way (create a backup) by renaming it to "orig.NUM~" 294 * where NUM is the smallest number that is not used yet. 295 * 296 * @param fil name of the file to back up 297 * @return the backup file name (must be freed by caller) 298 */ 299 char* 300 GNUNET_DISK_file_backup (const char *fil); 301 302 303 /** 304 * Move the read/write pointer in a file 305 * @param h handle of an open file 306 * @param offset position to move to 307 * @param whence specification to which position the offset parameter relates to 308 * @return the new position on success, #GNUNET_SYSERR otherwise 309 */ 310 off_t 311 GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle *h, 312 off_t offset, 313 enum GNUNET_DISK_Seek whence); 314 315 316 /** 317 * Get the size of the file (or directory) of the given file (in 318 * bytes). 319 * 320 * @param filename name of the file or directory 321 * @param size set to the size of the file (or, 322 * in the case of directories, the sum 323 * of all sizes of files in the directory) 324 * @param include_symbolic_links should symbolic links be 325 * included? 326 * @param single_file_mode #GNUNET_YES to only get size of one file 327 * and return #GNUNET_SYSERR for directories. 328 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success 329 */ 330 enum GNUNET_GenericReturnValue 331 GNUNET_DISK_file_size (const char *filename, 332 uint64_t *size, 333 int include_symbolic_links, 334 int single_file_mode); 335 336 337 /** 338 * Obtain some unique identifiers for the given file 339 * that can be used to identify it in the local system. 340 * This function is used between GNUnet processes to 341 * quickly check if two files with the same absolute path 342 * are actually identical. The two processes represent 343 * the same peer but may communicate over the network 344 * (and the file may be on an NFS volume). This function 345 * may not be supported on all operating systems. 346 * 347 * @param filename name of the file 348 * @param dev set to the device ID 349 * @param ino set to the inode ID 350 * @return #GNUNET_OK on success 351 */ 352 enum GNUNET_GenericReturnValue 353 GNUNET_DISK_file_get_identifiers (const char *filename, 354 uint64_t *dev, 355 uint64_t *ino); 356 357 358 /** 359 * Create an (empty) temporary file on disk. If the given name is not 360 * an absolute path, the current 'TMPDIR' will be prepended. In any case, 361 * 6 random characters will be appended to the name to create a unique 362 * filename. 363 * 364 * @param pd project data to use to determine paths 365 * @param t component to use for the name; 366 * does NOT contain "XXXXXX" or "/tmp/". 367 * @return NULL on error, otherwise name of fresh 368 * file on disk in directory for temporary files 369 */ 370 char * 371 GNUNET_DISK_mktemp (const struct GNUNET_OS_ProjectData *pd, 372 const char *t); 373 374 375 /** 376 * Create an (empty) temporary directory on disk. If the given name is not an 377 * absolute path, the current 'TMPDIR' will be prepended. In any case, 6 378 * random characters will be appended to the name to create a unique name. 379 * 380 * @param pd project data to use to determine paths 381 * @param t component to use for the name; 382 * does NOT contain "XXXXXX" or "/tmp/". 383 * @return NULL on error, otherwise name of freshly created directory 384 */ 385 char * 386 GNUNET_DISK_mkdtemp (const struct GNUNET_OS_ProjectData *pd, 387 const char *t); 388 389 390 /** 391 * Open a file. Note that the access permissions will only be 392 * used if a new file is created and if the underlying operating 393 * system supports the given permissions. 394 * 395 * @param fn file name to be opened 396 * @param flags opening flags, a combination of GNUNET_DISK_OPEN_xxx bit flags 397 * @param perm permissions for the newly created file, use 398 * #GNUNET_DISK_PERM_NONE if a file could not be created by this 399 * call (because of flags) 400 * @return IO handle on success, NULL on error 401 */ 402 struct GNUNET_DISK_FileHandle * 403 GNUNET_DISK_file_open (const char *fn, 404 enum GNUNET_DISK_OpenFlags flags, 405 enum GNUNET_DISK_AccessPermissions perm); 406 407 408 /** 409 * Get the size of an open file. 410 * 411 * @param fh open file handle 412 * @param size where to write size of the file 413 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error 414 */ 415 enum GNUNET_GenericReturnValue 416 GNUNET_DISK_file_handle_size (struct GNUNET_DISK_FileHandle *fh, 417 off_t *size); 418 419 420 /** 421 * Flags for #GNUNET_DISK_pipe(). 422 */ 423 enum GNUNET_DISK_PipeFlags 424 { 425 426 /** 427 * No special options, use non-blocking read/write operations. 428 */ 429 GNUNET_DISK_PF_NONE, 430 431 /** 432 * Configure read end to block when reading if set. 433 */ 434 GNUNET_DISK_PF_BLOCKING_READ = 1, 435 436 /** 437 * Configure write end to block when writing if set. 438 */ 439 GNUNET_DISK_PF_BLOCKING_WRITE = 2, 440 441 /** 442 * Configure both pipe ends for blocking operations if set. 443 */ 444 GNUNET_DISK_PF_BLOCKING_RW = GNUNET_DISK_PF_BLOCKING_READ 445 | GNUNET_DISK_PF_BLOCKING_WRITE 446 447 }; 448 449 450 /** 451 * Creates an interprocess channel 452 * 453 * @param pf how to configure the pipe 454 * @return handle to the new pipe, NULL on error 455 */ 456 struct GNUNET_DISK_PipeHandle * 457 GNUNET_DISK_pipe (enum GNUNET_DISK_PipeFlags pf); 458 459 460 /** 461 * Creates a pipe object from a couple of file descriptors. 462 * Useful for wrapping existing pipe FDs. 463 * 464 * @param pf how to configure the pipe 465 * @param fd an array of two fd values. One of them may be -1 for read-only or write-only pipes 466 * @return handle to the new pipe, NULL on error 467 */ 468 struct GNUNET_DISK_PipeHandle * 469 GNUNET_DISK_pipe_from_fd (enum GNUNET_DISK_PipeFlags pf, 470 int fd[2]); 471 472 473 /** 474 * Closes an interprocess channel 475 * @param p pipe 476 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise 477 */ 478 enum GNUNET_GenericReturnValue 479 GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p); 480 481 482 /** 483 * Closes one half of an interprocess channel 484 * 485 * @param p pipe to close end of 486 * @param end which end of the pipe to close 487 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise 488 */ 489 enum GNUNET_GenericReturnValue 490 GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p, 491 enum GNUNET_DISK_PipeEnd end); 492 493 494 /** 495 * Detaches one of the ends from the pipe. 496 * Detached end is a fully-functional FileHandle, it will 497 * not be affected by anything you do with the pipe afterwards. 498 * Each end of a pipe can only be detched from it once (i.e. 499 * it is not duplicated). 500 * 501 * @param p pipe to detach an end from 502 * @param end which end of the pipe to detach 503 * @return Detached end on success, NULL on failure 504 * (or if that end is not present or is closed). 505 */ 506 struct GNUNET_DISK_FileHandle * 507 GNUNET_DISK_pipe_detach_end (struct GNUNET_DISK_PipeHandle *p, 508 enum GNUNET_DISK_PipeEnd end); 509 510 /** 511 * Close an open file. 512 * 513 * @param h file handle 514 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise 515 */ 516 enum GNUNET_GenericReturnValue 517 GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h); 518 519 520 /** 521 * Get the handle to a particular pipe end 522 * 523 * @param p pipe 524 * @param n end to access 525 * @return handle for the respective end 526 */ 527 const struct GNUNET_DISK_FileHandle * 528 GNUNET_DISK_pipe_handle (const struct GNUNET_DISK_PipeHandle *p, 529 enum GNUNET_DISK_PipeEnd n); 530 531 532 /** 533 * Update POSIX permissions mask of a file on disk. If both arguments 534 * are #GNUNET_NO, the file is made world-read-write-executable (777). 535 * Does nothing on W32. 536 * 537 * @param fn name of the file to update 538 * @param require_uid_match #GNUNET_YES means 700 539 * @param require_gid_match #GNUNET_YES means 770 unless @a require_uid_match is set 540 */ 541 void 542 GNUNET_DISK_fix_permissions (const char *fn, 543 int require_uid_match, 544 int require_gid_match); 545 546 547 /** 548 * Get a handle from a native integer FD. 549 * 550 * @param fno native integer file descriptor 551 * @return file handle corresponding to the descriptor 552 */ 553 struct GNUNET_DISK_FileHandle * 554 GNUNET_DISK_get_handle_from_int_fd (int fno); 555 556 557 /** 558 * Get a handle from a native FD. 559 * 560 * @param fd native file descriptor 561 * @return file handle corresponding to the descriptor 562 */ 563 struct GNUNET_DISK_FileHandle * 564 GNUNET_DISK_get_handle_from_native (FILE *fd); 565 566 567 /** 568 * Read the contents of a binary file into a buffer. 569 * 570 * @param h handle to an open file 571 * @param result the buffer to write the result to 572 * @param len the maximum number of bytes to read 573 * @return the number of bytes read on success, #GNUNET_SYSERR on failure 574 */ 575 ssize_t 576 GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle *h, 577 void *result, 578 size_t len); 579 580 581 /** 582 * Read the contents of a binary file into a buffer. 583 * 584 * @param fn file name 585 * @param result the buffer to write the result to 586 * @param len the maximum number of bytes to read 587 * @return number of bytes read, #GNUNET_SYSERR on failure 588 */ 589 ssize_t 590 GNUNET_DISK_fn_read (const char *fn, 591 void *result, 592 size_t len); 593 594 595 /** 596 * Write a buffer to a file. 597 * 598 * @param h handle to open file 599 * @param buffer the data to write 600 * @param n number of bytes to write 601 * @return number of bytes written on success, #GNUNET_SYSERR on error 602 */ 603 ssize_t 604 GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle *h, 605 const void *buffer, 606 size_t n); 607 608 609 /** 610 * Write a buffer to a file, blocking, if necessary. 611 * 612 * @param h handle to open file 613 * @param buffer the data to write 614 * @param n number of bytes to write 615 * @return number of bytes written on success, #GNUNET_SYSERR on error 616 */ 617 ssize_t 618 GNUNET_DISK_file_write_blocking (const struct GNUNET_DISK_FileHandle *h, 619 const void *buffer, 620 size_t n); 621 622 623 /** 624 * Write a buffer to a file atomically. The directory is created if 625 * necessary. Fail if @a filename already exists or if not exactly @a buf 626 * with @a buf_size bytes could be written to @a filename. 627 * 628 * @param fn file name 629 * @param buf the data to write 630 * @param buf_size number of bytes to write from @a buf 631 * @param mode file permissions 632 * @return #GNUNET_OK on success, 633 * #GNUNET_NO if a file existed under @a filename 634 * #GNUNET_SYSERR on failure 635 */ 636 enum GNUNET_GenericReturnValue 637 GNUNET_DISK_fn_write (const char *fn, 638 const void *buf, 639 size_t buf_size, 640 enum GNUNET_DISK_AccessPermissions mode); 641 642 643 /** 644 * Copy a file. 645 * 646 * @param src file to copy 647 * @param dst destination file name 648 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error 649 */ 650 enum GNUNET_GenericReturnValue 651 GNUNET_DISK_file_copy (const char *src, 652 const char *dst); 653 654 655 /** 656 * Scan a directory for files. 657 * 658 * @param dir_name the name of the directory 659 * @param callback the method to call for each file 660 * @param callback_cls closure for @a callback 661 * @return the number of files found, -1 on error 662 */ 663 int 664 GNUNET_DISK_directory_scan (const char *dir_name, 665 GNUNET_FileNameCallback callback, 666 void *callback_cls); 667 668 /** 669 * Find all files matching a glob pattern. 670 * 671 * Currently, the glob_pattern only supports asterisks in the last 672 * path component. 673 * 674 * @param glob_pattern the glob pattern to search for 675 * @param callback the method to call for each file 676 * @param callback_cls closure for @a callback 677 * @return the number of files found, -1 on error 678 */ 679 int 680 GNUNET_DISK_glob (const char *glob_pattern, 681 GNUNET_FileNameCallback callback, 682 void *callback_cls); 683 684 685 /** 686 * Create the directory structure for storing 687 * a file. 688 * 689 * @param filename name of a file in the directory 690 * @returns #GNUNET_OK on success, #GNUNET_SYSERR on failure, 691 * #GNUNET_NO if directory exists but is not writeable 692 */ 693 enum GNUNET_GenericReturnValue 694 GNUNET_DISK_directory_create_for_file (const char *filename); 695 696 697 /** 698 * Test if @a fil is a directory and listable. Optionally, also check if the 699 * directory is readable. Will not print an error message if the directory does 700 * not exist. Will log errors if #GNUNET_SYSERR is returned (i.e., a file exists 701 * with the same name). 702 * 703 * @param fil filename to test 704 * @param is_readable #GNUNET_YES to additionally check if @a fil is readable; 705 * #GNUNET_NO to disable this check 706 * @return #GNUNET_YES if yes, #GNUNET_NO if not; #GNUNET_SYSERR if it 707 * does not exist or `stat`ed 708 */ 709 enum GNUNET_GenericReturnValue 710 GNUNET_DISK_directory_test (const char *fil, 711 int is_readable); 712 713 714 /** 715 * Remove all files in a directory (rm -rf). Call with caution. 716 * 717 * @param filename the file to remove 718 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error 719 */ 720 enum GNUNET_GenericReturnValue 721 GNUNET_DISK_directory_remove (const char *filename); 722 723 724 /** 725 * Remove the directory given under @a option in 726 * section [PATHS] in configuration under @a cfg_filename 727 * 728 * @param pd project data to use to determine paths 729 * @param cfg_filename configuration file to parse 730 * @param option option with the dir name to purge 731 */ 732 void 733 GNUNET_DISK_purge_cfg_dir (const struct GNUNET_OS_ProjectData *pd, 734 const char *cfg_filename, 735 const char *option); 736 737 738 /** 739 * Implementation of "mkdir -p" 740 * 741 * @param dir the directory to create 742 * @returns #GNUNET_SYSERR on failure, #GNUNET_OK otherwise 743 */ 744 enum GNUNET_GenericReturnValue 745 GNUNET_DISK_directory_create (const char *dir); 746 747 748 /** 749 * @brief Removes special characters as ':' from a filename. 750 * @param fn the filename to canonicalize 751 */ 752 void 753 GNUNET_DISK_filename_canonicalize (char *fn); 754 755 756 /** 757 * @brief Change owner of a file 758 * @param filename file to change 759 * @param user new owner of the file 760 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure 761 */ 762 enum GNUNET_GenericReturnValue 763 GNUNET_DISK_file_change_owner (const char *filename, 764 const char *user); 765 766 767 /** 768 * Opaque handle for a memory-mapping operation. 769 */ 770 struct GNUNET_DISK_MapHandle; 771 772 773 /** 774 * Map a file into memory. 775 * 776 * @param h open file handle 777 * @param m handle to the new mapping (will be set) 778 * @param access access specification, GNUNET_DISK_MAP_TYPE_xxx 779 * @param len size of the mapping 780 * @return pointer to the mapped memory region, NULL on failure 781 */ 782 void * 783 GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h, 784 struct GNUNET_DISK_MapHandle **m, 785 enum GNUNET_DISK_MapType access, 786 size_t len); 787 788 789 /** 790 * Unmap a file 791 * 792 * @param h mapping handle 793 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise 794 */ 795 enum GNUNET_GenericReturnValue 796 GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h); 797 798 799 /** 800 * Write file changes to disk 801 * 802 * @param h handle to an open file 803 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise 804 */ 805 enum GNUNET_GenericReturnValue 806 GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h); 807 808 809 #if 0 /* keep Emacsens' auto-indent happy */ 810 { 811 #endif 812 #ifdef __cplusplus 813 } 814 #endif 815 816 /* ifndef GNUNET_DISK_LIB_H */ 817 #endif 818 819 /** @} */ /* end of group */ 820 821 /** @} */ /* end of group addition */ 822 823 /* end of gnunet_disk_lib.h */