GNUnet  0.10.x
disk.c
Go to the documentation of this file.
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 */
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) GNUNET_log_from_strerror (kind, "util-disk", syscall)
34 
35 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-disk", syscall, filename)
36 
40 #define COPY_BLK_SIZE 65536
41 
42 #include <sys/types.h>
43 #if HAVE_SYS_VFS_H
44 #include <sys/vfs.h>
45 #endif
46 #if HAVE_SYS_PARAM_H
47 #include <sys/param.h>
48 #endif
49 #if HAVE_SYS_MOUNT_H
50 #include <sys/mount.h>
51 #endif
52 #if HAVE_SYS_STATVFS_H
53 #include <sys/statvfs.h>
54 #endif
55 
56 #ifndef S_ISLNK
57 #define _IFMT 0170000 /* type of file */
58 #define _IFLNK 0120000 /* symbolic link */
59 #define S_ISLNK(m) (((m)&_IFMT) == _IFLNK)
60 #endif
61 
62 
67 {
73 };
74 
75 
81 {
85  uint64_t total;
86 
91 
96 };
97 
98 
99 #ifndef MINGW
100 
107 static int
109 {
110  int mode;
111 
112  mode = 0;
113  if (perm & GNUNET_DISK_PERM_USER_READ)
114  mode |= S_IRUSR;
115  if (perm & GNUNET_DISK_PERM_USER_WRITE)
116  mode |= S_IWUSR;
117  if (perm & GNUNET_DISK_PERM_USER_EXEC)
118  mode |= S_IXUSR;
119  if (perm & GNUNET_DISK_PERM_GROUP_READ)
120  mode |= S_IRGRP;
121  if (perm & GNUNET_DISK_PERM_GROUP_WRITE)
122  mode |= S_IWGRP;
123  if (perm & GNUNET_DISK_PERM_GROUP_EXEC)
124  mode |= S_IXGRP;
125  if (perm & GNUNET_DISK_PERM_OTHER_READ)
126  mode |= S_IROTH;
127  if (perm & GNUNET_DISK_PERM_OTHER_WRITE)
128  mode |= S_IWOTH;
129  if (perm & GNUNET_DISK_PERM_OTHER_EXEC)
130  mode |= S_IXOTH;
131 
132  return mode;
133 }
134 #endif
135 
136 
145 static int
146 getSizeRec (void *cls, const char *fn)
147 {
148  struct GetFileSizeData *gfsd = cls;
149 
150 #if defined (HAVE_STAT64) && !(defined (_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64)
152 
153  if (0 != STAT64 (fn, &buf))
154  {
156  return GNUNET_SYSERR;
157  }
158 #else
159  struct stat buf;
160 
161  if (0 != STAT (fn, &buf))
162  {
164  return GNUNET_SYSERR;
165  }
166 #endif
167  if ((S_ISDIR (buf.st_mode)) && (gfsd->single_file_mode == GNUNET_YES))
168  {
169  errno = EISDIR;
170  return GNUNET_SYSERR;
171  }
172  if ((!S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES))
173  gfsd->total += buf.st_size;
174  if ((S_ISDIR (buf.st_mode)) && (0 == ACCESS (fn, X_OK)) &&
175  ((!S_ISLNK (buf.st_mode)) || (gfsd->include_sym_links == GNUNET_YES)))
176  {
178  return GNUNET_SYSERR;
179  }
180  return GNUNET_OK;
181 }
182 
183 
190 int
192 {
193 #ifdef MINGW
194  return ((!h) || (h->h == INVALID_HANDLE_VALUE)) ? GNUNET_YES : GNUNET_NO;
195 #else
196  return ((!h) || (h->fd == -1)) ? GNUNET_YES : GNUNET_NO;
197 #endif
198 }
199 
207 int
209  off_t *size)
210 {
211 #if WINDOWS
212  BOOL b;
213  LARGE_INTEGER li;
214  b = GetFileSizeEx (fh->h, &li);
215  if (!b)
216  {
217  SetErrnoFromWinError (GetLastError ());
218  return GNUNET_SYSERR;
219  }
220  *size = (off_t) li.QuadPart;
221 #else
222  struct stat sbuf;
223 
224  if (0 != FSTAT (fh->fd, &sbuf))
225  return GNUNET_SYSERR;
226  *size = sbuf.st_size;
227 #endif
228  return GNUNET_OK;
229 }
230 
231 
240 off_t
242  off_t offset,
243  enum GNUNET_DISK_Seek whence)
244 {
245  if (h == NULL)
246  {
247  errno = EINVAL;
248  return GNUNET_SYSERR;
249  }
250 
251 #ifdef MINGW
252  LARGE_INTEGER li;
253  LARGE_INTEGER new_pos;
254  BOOL b;
255 
256  static DWORD t[] = { FILE_BEGIN, FILE_CURRENT, FILE_END };
257  li.QuadPart = offset;
258 
259  b = SetFilePointerEx (h->h, li, &new_pos, t[whence]);
260  if (b == 0)
261  {
262  SetErrnoFromWinError (GetLastError ());
263  return GNUNET_SYSERR;
264  }
265  return (off_t) new_pos.QuadPart;
266 #else
267  static int t[] = { SEEK_SET, SEEK_CUR, SEEK_END };
268 
269  return lseek (h->fd, offset, t[whence]);
270 #endif
271 }
272 
273 
288 int
290  uint64_t * size,
291  int include_symbolic_links,
292  int single_file_mode)
293 {
294  struct GetFileSizeData gfsd;
295  int ret;
296 
297  GNUNET_assert (size != NULL);
298  gfsd.total = 0;
299  gfsd.include_sym_links = include_symbolic_links;
301  ret = getSizeRec (&gfsd, filename);
302  *size = gfsd.total;
303  return ret;
304 }
305 
306 
322 int
323 GNUNET_DISK_file_get_identifiers (const char *filename, uint64_t * dev,
324  uint64_t * ino)
325 {
326 #if WINDOWS
327  {
328  // FIXME NILS: test this
329  struct GNUNET_DISK_FileHandle *fh;
330  BY_HANDLE_FILE_INFORMATION info;
331  int succ;
332 
333  fh = GNUNET_DISK_file_open (filename,
336  if (NULL == fh)
337  return GNUNET_SYSERR;
338  succ = GetFileInformationByHandle (fh->h, &info);
340  if (!succ)
341  {
342  return GNUNET_SYSERR;
343  }
344  *dev = info.dwVolumeSerialNumber;
345  *ino = ((((uint64_t) info.nFileIndexHigh) << (sizeof (DWORD) * 8)) | info.nFileIndexLow);
346  }
347 #else /* !WINDOWS */
348 #if HAVE_STAT
349  {
350  struct stat sbuf;
351 
352  if (0 != stat (filename, &sbuf))
353  {
354  return GNUNET_SYSERR;
355  }
356  *ino = (uint64_t) sbuf.st_ino;
357  }
358 #else
359  *ino = 0;
360 #endif
361 #if HAVE_STATVFS
362  {
363  struct statvfs fbuf;
364 
365  if (0 != statvfs (filename, &fbuf))
366  {
367  return GNUNET_SYSERR;
368  }
369  *dev = (uint64_t) fbuf.f_fsid;
370  }
371 #elif HAVE_STATFS
372  {
373  struct statfs fbuf;
374 
375  if (0 != statfs (filename, &fbuf))
376  {
377  return GNUNET_SYSERR;
378  }
379  *dev = ((uint64_t) fbuf.f_fsid.val[0]) << 32 ||
380  ((uint64_t) fbuf.f_fsid.val[1]);
381  }
382 #else
383  *dev = 0;
384 #endif
385 #endif /* !WINDOWS */
386  return GNUNET_OK;
387 }
388 
389 
396 static char *
397 mktemp_name (const char *t)
398 {
399  const char *tmpdir;
400  char *tmpl;
401  char *fn;
402 
403  if ((t[0] != '/') && (t[0] != '\\')
404 #if WINDOWS
405  && !(isalpha ((int) t[0]) && (t[0] != '\0') && (t[1] == ':'))
406 #endif
407  )
408  {
409  /* FIXME: This uses system codepage on W32, not UTF-8 */
410  tmpdir = getenv ("TMPDIR");
411  if (NULL == tmpdir)
412  tmpdir = getenv ("TMP");
413  if (NULL == tmpdir)
414  tmpdir = getenv ("TEMP");
415  if (NULL == tmpdir)
416  tmpdir = "/tmp";
417  GNUNET_asprintf (&tmpl, "%s/%s%s", tmpdir, t, "XXXXXX");
418  }
419  else
420  {
421  GNUNET_asprintf (&tmpl, "%s%s", t, "XXXXXX");
422  }
423 #ifdef MINGW
424  fn = (char *) GNUNET_malloc (MAX_PATH + 1);
425  if (ERROR_SUCCESS != plibc_conv_to_win_path (tmpl, fn))
426  {
427  GNUNET_free (fn);
428  GNUNET_free (tmpl);
429  return NULL;
430  }
431  GNUNET_free (tmpl);
432 #else
433  fn = tmpl;
434 #endif
435  return fn;
436 }
437 
438 
439 #if WINDOWS
440 static char *
441 mkdtemp (char *fn)
442 {
443  char *random_fn;
444  char *tfn;
445 
446  while (1)
447  {
448  tfn = GNUNET_strdup (fn);
449  random_fn = _mktemp (tfn);
450  if (NULL == random_fn)
451  {
452  GNUNET_free (tfn);
453  return NULL;
454  }
455  /* FIXME: assume fn to be UTF-8-encoded and do the right thing */
456  if (0 == CreateDirectoryA (tfn, NULL))
457  {
458  DWORD error = GetLastError ();
459  GNUNET_free (tfn);
460  if (ERROR_ALREADY_EXISTS == error)
461  continue;
462  return NULL;
463  }
464  break;
465  }
466  strcpy (fn, tfn);
467  return fn;
468 }
469 
479 void
480 GNUNET_DISK_fix_permissions (const char *fn,
481  int require_uid_match,
482  int require_gid_match)
483 {
484  /* nothing on W32 */
485 }
486 
487 #else
488 
497 void
499  int require_uid_match,
500  int require_gid_match)
501 {
502  mode_t mode;
503 
504  if (GNUNET_YES == require_uid_match)
505  mode = S_IRUSR | S_IWUSR | S_IXUSR;
506  else if (GNUNET_YES == require_gid_match)
507  mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP;
508  else
509  mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH;
510  if (0 != chmod (fn, mode))
512  "chmod",
513  fn);
514 }
515 
516 #endif
517 
529 char *
530 GNUNET_DISK_mkdtemp (const char *t)
531 {
532  char *fn;
533  mode_t omask;
534 
535  omask = umask (S_IWGRP | S_IWOTH | S_IRGRP | S_IROTH);
536  fn = mktemp_name (t);
537  if (fn != mkdtemp (fn))
538  {
540  GNUNET_free (fn);
541  umask (omask);
542  return NULL;
543  }
544  umask (omask);
545  return fn;
546 }
547 
548 
556 void
557 GNUNET_DISK_file_backup (const char *fil)
558 {
559  size_t slen;
560  char *target;
561  unsigned int num;
562 
563  slen = strlen (fil) + 20;
564  target = GNUNET_malloc (slen);
565  num = 0;
566  do
567  {
568  GNUNET_snprintf (target, slen,
569  "%s.%u~",
570  fil,
571  num++);
572  } while (0 == access (target, F_OK));
573  if (0 != rename (fil, target))
575  "rename",
576  fil);
577  GNUNET_free (target);
578 }
579 
580 
592 char *
593 GNUNET_DISK_mktemp (const char *t)
594 {
595  int fd;
596  char *fn;
597  mode_t omask;
598 
599  omask = umask (S_IWGRP | S_IWOTH | S_IRGRP | S_IROTH);
600  fn = mktemp_name (t);
601  if (-1 == (fd = mkstemp (fn)))
602  {
604  GNUNET_free (fn);
605  umask (omask);
606  return NULL;
607  }
608  umask (omask);
609  if (0 != CLOSE (fd))
611  return fn;
612 }
613 
614 
627 int
628 GNUNET_DISK_directory_test (const char *fil,
629  int is_readable)
630 {
631  struct stat filestat;
632  int ret;
633 
634  ret = STAT (fil, &filestat);
635  if (ret != 0)
636  {
637  if (errno != ENOENT)
639  return GNUNET_SYSERR;
640  }
641  if (!S_ISDIR (filestat.st_mode))
642  {
644  "A file already exits with the same name %s\n", fil);
645  return GNUNET_NO;
646  }
647  if (GNUNET_YES == is_readable)
648  ret = ACCESS (fil, R_OK | X_OK);
649  else
650  ret = ACCESS (fil, X_OK);
651  if (ret < 0)
652  {
654  return GNUNET_NO;
655  }
656  return GNUNET_YES;
657 }
658 
659 
668 int
669 GNUNET_DISK_file_test (const char *fil)
670 {
671  struct stat filestat;
672  int ret;
673  char *rdir;
674 
675  rdir = GNUNET_STRINGS_filename_expand (fil);
676  if (rdir == NULL)
677  return GNUNET_SYSERR;
678 
679  ret = STAT (rdir, &filestat);
680  if (ret != 0)
681  {
682  if (errno != ENOENT)
683  {
685  GNUNET_free (rdir);
686  return GNUNET_SYSERR;
687  }
688  GNUNET_free (rdir);
689  return GNUNET_NO;
690  }
691  if (!S_ISREG (filestat.st_mode))
692  {
693  GNUNET_free (rdir);
694  return GNUNET_NO;
695  }
696  if (ACCESS (rdir, F_OK) < 0)
697  {
699  GNUNET_free (rdir);
700  return GNUNET_SYSERR;
701  }
702  GNUNET_free (rdir);
703  return GNUNET_YES;
704 }
705 
706 
713 int
715 {
716  char *rdir;
717  unsigned int len;
718  unsigned int pos;
719  unsigned int pos2;
720  int ret = GNUNET_OK;
721 
722  rdir = GNUNET_STRINGS_filename_expand (dir);
723  if (rdir == NULL)
724  {
725  GNUNET_break (0);
726  return GNUNET_SYSERR;
727  }
728 
729  len = strlen (rdir);
730 #ifndef MINGW
731  pos = 1; /* skip heading '/' */
732 #else
733  /* Local or Network path? */
734  if (strncmp (rdir, "\\\\", 2) == 0)
735  {
736  pos = 2;
737  while (rdir[pos])
738  {
739  if (rdir[pos] == '\\')
740  {
741  pos++;
742  break;
743  }
744  pos++;
745  }
746  }
747  else
748  {
749  pos = 3; /* strlen("C:\\") */
750  }
751 #endif
752  /* Check which low level directories already exist */
753  pos2 = len;
754  rdir[len] = DIR_SEPARATOR;
755  while (pos <= pos2)
756  {
757  if (DIR_SEPARATOR == rdir[pos2])
758  {
759  rdir[pos2] = '\0';
761  if (GNUNET_NO == ret)
762  {
764  "Creating directory `%s' failed",
765  rdir);
766  GNUNET_free (rdir);
767  return GNUNET_SYSERR;
768  }
769  rdir[pos2] = DIR_SEPARATOR;
770  if (GNUNET_YES == ret)
771  {
772  pos2++;
773  break;
774  }
775  }
776  pos2--;
777  }
778  rdir[len] = '\0';
779  if (pos < pos2)
780  pos = pos2;
781  /* Start creating directories */
782  while (pos <= len)
783  {
784  if ((rdir[pos] == DIR_SEPARATOR) || (pos == len))
785  {
786  rdir[pos] = '\0';
788  if (GNUNET_NO == ret)
789  {
791  "Creating directory `%s' failed",
792  rdir);
793  GNUNET_free (rdir);
794  return GNUNET_SYSERR;
795  }
796  if (GNUNET_SYSERR == ret)
797  {
798 #ifndef MINGW
799  ret = mkdir (rdir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); /* 755 */
800 #else
801  wchar_t wrdir[MAX_PATH + 1];
802  if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(rdir, wrdir))
803  ret = !CreateDirectoryW (wrdir, NULL);
804  else
805  ret = 1;
806 #endif
807  if ((ret != 0) && (errno != EEXIST))
808  {
810  GNUNET_free (rdir);
811  return GNUNET_SYSERR;
812  }
813  }
814  rdir[pos] = DIR_SEPARATOR;
815  }
816  pos++;
817  }
818  GNUNET_free (rdir);
819  return GNUNET_OK;
820 }
821 
822 
832 int
834 {
835  char *rdir;
836  size_t len;
837  int ret;
838  int eno;
839 
840  rdir = GNUNET_STRINGS_filename_expand (filename);
841  if (NULL == rdir)
842  {
843  errno = EINVAL;
844  return GNUNET_SYSERR;
845  }
846  if (0 == ACCESS (rdir, W_OK))
847  {
848  GNUNET_free (rdir);
849  return GNUNET_OK;
850  }
851 
852  len = strlen (rdir);
853  while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
854  len--;
855  rdir[len] = '\0';
856  /* The empty path is invalid and in this case refers to / */
857  if (0 == len)
858  {
859  GNUNET_free (rdir);
860  rdir = GNUNET_strdup ("/");
861  }
862  ret = GNUNET_DISK_directory_create (rdir);
863  if ((GNUNET_OK == ret) && (0 != ACCESS (rdir, W_OK)))
864  ret = GNUNET_NO;
865  eno = errno;
866  GNUNET_free (rdir);
867  errno = eno;
868  return ret;
869 }
870 
871 
880 ssize_t
882  void *result,
883  size_t len)
884 {
885  if (NULL == h)
886  {
887  errno = EINVAL;
888  return GNUNET_SYSERR;
889  }
890 
891 #ifdef MINGW
892  DWORD bytes_read;
893 
894  if (h->type == GNUNET_DISK_HANLDE_TYPE_FILE)
895  {
896  if (!ReadFile (h->h, result, len, &bytes_read, NULL))
897  {
898  SetErrnoFromWinError (GetLastError ());
899  return GNUNET_SYSERR;
900  }
901  }
902  else if (h->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
903  {
904  if (!ReadFile (h->h, result, len, &bytes_read, h->oOverlapRead))
905  {
906  if (GetLastError () != ERROR_IO_PENDING)
907  {
909  "Error reading from pipe: %u\n",
910  GetLastError ());
911  SetErrnoFromWinError (GetLastError ());
912  return GNUNET_SYSERR;
913  }
914  LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n");
915  GetOverlappedResult (h->h, h->oOverlapRead, &bytes_read, TRUE);
916  }
917  LOG (GNUNET_ERROR_TYPE_DEBUG, "Read %u bytes from pipe\n", bytes_read);
918  }
919  else
920  {
921  bytes_read = 0;
922  }
923  return bytes_read;
924 #else
925  return read (h->fd, result, len);
926 #endif
927 }
928 
929 
940 ssize_t
942  void *result,
943  size_t len)
944 {
945  if (NULL == h)
946  {
947  errno = EINVAL;
948  return GNUNET_SYSERR;
949  }
950 
951 #ifdef MINGW
952  DWORD bytes_read;
953 
954  if (h->type == GNUNET_DISK_HANLDE_TYPE_FILE)
955  {
956  if (!ReadFile (h->h, result, len, &bytes_read, NULL))
957  {
958  SetErrnoFromWinError (GetLastError ());
959  return GNUNET_SYSERR;
960  }
961  }
962  else if (h->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
963  {
964  if (!ReadFile (h->h, result, len, &bytes_read, h->oOverlapRead))
965  {
966  if (GetLastError () != ERROR_IO_PENDING)
967  {
968  LOG (GNUNET_ERROR_TYPE_DEBUG, "Error reading from pipe: %u\n", GetLastError ());
969  SetErrnoFromWinError (GetLastError ());
970  return GNUNET_SYSERR;
971  }
972  else
973  {
975  "ReadFile() queued a read, cancelling\n");
976  CancelIo (h->h);
977  errno = EAGAIN;
978  return GNUNET_SYSERR;
979  }
980  }
982  "Read %u bytes\n",
983  bytes_read);
984  }
985  else
986  {
987  bytes_read = 0;
988  }
989  return bytes_read;
990 #else
991  int flags;
992  ssize_t ret;
993 
994  /* set to non-blocking, read, then set back */
995  flags = fcntl (h->fd, F_GETFL);
996  if (0 == (flags & O_NONBLOCK))
997  (void) fcntl (h->fd, F_SETFL, flags | O_NONBLOCK);
998  ret = read (h->fd, result, len);
999  if (0 == (flags & O_NONBLOCK))
1000  {
1001  int eno = errno;
1002  (void) fcntl (h->fd, F_SETFL, flags);
1003  errno = eno;
1004  }
1005  return ret;
1006 #endif
1007 }
1008 
1009 
1018 ssize_t
1020  void *result,
1021  size_t len)
1022 {
1023  struct GNUNET_DISK_FileHandle *fh;
1024  ssize_t ret;
1025  int eno;
1026 
1027  fh = GNUNET_DISK_file_open (fn,
1030  if (NULL == fh)
1031  return GNUNET_SYSERR;
1032  ret = GNUNET_DISK_file_read (fh, result, len);
1033  eno = errno;
1035  errno = eno;
1036  return ret;
1037 }
1038 
1039 
1048 ssize_t
1050  const void *buffer,
1051  size_t n)
1052 {
1053  if (NULL == h)
1054  {
1055  errno = EINVAL;
1056  return GNUNET_SYSERR;
1057  }
1058 
1059 #ifdef MINGW
1060  DWORD bytes_written;
1061 
1062  if (h->type == GNUNET_DISK_HANLDE_TYPE_FILE)
1063  {
1064  if (!WriteFile (h->h, buffer, n, &bytes_written, NULL))
1065  {
1066  SetErrnoFromWinError (GetLastError ());
1067  return GNUNET_SYSERR;
1068  }
1069  }
1070  else if (h->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
1071  {
1072  LOG (GNUNET_ERROR_TYPE_DEBUG, "It is a pipe trying to write %u bytes\n", n);
1073  if (!WriteFile (h->h, buffer, n, &bytes_written, h->oOverlapWrite))
1074  {
1075  if (GetLastError () != ERROR_IO_PENDING)
1076  {
1077  SetErrnoFromWinError (GetLastError ());
1078  LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1079  GetLastError ());
1080  return GNUNET_SYSERR;
1081  }
1082  LOG (GNUNET_ERROR_TYPE_DEBUG, "Will get overlapped result\n");
1083  if (!GetOverlappedResult (h->h, h->oOverlapWrite, &bytes_written, TRUE))
1084  {
1085  SetErrnoFromWinError (GetLastError ());
1087  "Error getting overlapped result while writing to pipe: %u\n",
1088  GetLastError ());
1089  return GNUNET_SYSERR;
1090  }
1091  }
1092  else
1093  {
1094  DWORD ovr;
1095  if (!GetOverlappedResult (h->h, h->oOverlapWrite, &ovr, TRUE))
1096  {
1098  "Error getting control overlapped result while writing to pipe: %u\n",
1099  GetLastError ());
1100  }
1101  else
1102  {
1104  "Wrote %u bytes (ovr says %u), picking the greatest\n",
1105  bytes_written, ovr);
1106  }
1107  }
1108  if (bytes_written == 0)
1109  {
1110  if (n > 0)
1111  {
1112  LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes, returning -1 with EAGAIN\n", bytes_written);
1113  errno = EAGAIN;
1114  return GNUNET_SYSERR;
1115  }
1116  }
1117  LOG (GNUNET_ERROR_TYPE_DEBUG, "Wrote %u bytes\n", bytes_written);
1118  }
1119  else
1120  {
1121  bytes_written = 0;
1122  }
1123  return bytes_written;
1124 #else
1125  return write (h->fd, buffer, n);
1126 #endif
1127 }
1128 
1129 
1138 ssize_t
1140  const void *buffer,
1141  size_t n)
1142 {
1143  if (NULL == h)
1144  {
1145  errno = EINVAL;
1146  return GNUNET_SYSERR;
1147  }
1148 
1149 #ifdef MINGW
1150  DWORD bytes_written;
1151  /* We do a non-overlapped write, which is as blocking as it gets */
1152  LOG (GNUNET_ERROR_TYPE_DEBUG, "Writing %u bytes\n", n);
1153  if (!WriteFile (h->h, buffer, n, &bytes_written, NULL))
1154  {
1155  SetErrnoFromWinError (GetLastError ());
1156  LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1157  GetLastError ());
1158  return GNUNET_SYSERR;
1159  }
1160  if (bytes_written == 0 && n > 0)
1161  {
1162  LOG (GNUNET_ERROR_TYPE_DEBUG, "Waiting for pipe to clean\n");
1163  WaitForSingleObject (h->h, INFINITE);
1164  if (!WriteFile (h->h, buffer, n, &bytes_written, NULL))
1165  {
1166  SetErrnoFromWinError (GetLastError ());
1167  LOG (GNUNET_ERROR_TYPE_DEBUG, "Error writing to pipe: %u\n",
1168  GetLastError ());
1169  return GNUNET_SYSERR;
1170  }
1171  }
1173  "Wrote %u bytes\n",
1174  bytes_written);
1175  return bytes_written;
1176 #else
1177  int flags;
1178  ssize_t ret;
1179 
1180  /* set to blocking, write, then set back */
1181  flags = fcntl (h->fd, F_GETFL);
1182  if (0 != (flags & O_NONBLOCK))
1183  (void) fcntl (h->fd, F_SETFL, flags - O_NONBLOCK);
1184  ret = write (h->fd, buffer, n);
1185  if (0 == (flags & O_NONBLOCK))
1186  (void) fcntl (h->fd, F_SETFL, flags);
1187  return ret;
1188 #endif
1189 }
1190 
1191 
1202 ssize_t
1204  const void *buffer,
1205  size_t n,
1207 {
1208  struct GNUNET_DISK_FileHandle *fh;
1209  ssize_t ret;
1210 
1211  fh = GNUNET_DISK_file_open (fn,
1213  | GNUNET_DISK_OPEN_CREATE, mode);
1214  if (! fh)
1215  return GNUNET_SYSERR;
1216  ret = GNUNET_DISK_file_write (fh, buffer, n);
1218  return ret;
1219 }
1220 
1221 
1232 int
1234  GNUNET_FileNameCallback callback,
1235  void *callback_cls)
1236 {
1237  DIR *dinfo;
1238  struct dirent *finfo;
1239  struct stat istat;
1240  int count = 0;
1241  int ret;
1242  char *name;
1243  char *dname;
1244  unsigned int name_len;
1245  unsigned int n_size;
1246 
1247  GNUNET_assert (NULL != dir_name);
1248  dname = GNUNET_STRINGS_filename_expand (dir_name);
1249  if (NULL == dname)
1250  return GNUNET_SYSERR;
1251  while ( (strlen (dname) > 0) &&
1252  (dname[strlen (dname) - 1] == DIR_SEPARATOR) )
1253  dname[strlen (dname) - 1] = '\0';
1254  if (0 != STAT (dname, &istat))
1255  {
1257  "stat",
1258  dname);
1259  GNUNET_free (dname);
1260  return GNUNET_SYSERR;
1261  }
1262  if (! S_ISDIR (istat.st_mode))
1263  {
1265  _("Expected `%s' to be a directory!\n"),
1266  dir_name);
1267  GNUNET_free (dname);
1268  return GNUNET_SYSERR;
1269  }
1270  errno = 0;
1271  dinfo = OPENDIR (dname);
1272  if ( (EACCES == errno) ||
1273  (NULL == dinfo) )
1274  {
1276  "opendir",
1277  dname);
1278  if (NULL != dinfo)
1279  CLOSEDIR (dinfo);
1280  GNUNET_free (dname);
1281  return GNUNET_SYSERR;
1282  }
1283  name_len = 256;
1284  n_size = strlen (dname) + name_len + strlen (DIR_SEPARATOR_STR) + 1;
1285  name = GNUNET_malloc (n_size);
1286  while (NULL != (finfo = READDIR (dinfo)))
1287  {
1288  if ( (0 == strcmp (finfo->d_name, ".")) ||
1289  (0 == strcmp (finfo->d_name, "..")) )
1290  continue;
1291  if (NULL != callback)
1292  {
1293  if (name_len < strlen (finfo->d_name))
1294  {
1295  GNUNET_free (name);
1296  name_len = strlen (finfo->d_name);
1297  n_size = strlen (dname) + name_len + strlen (DIR_SEPARATOR_STR) + 1;
1298  name = GNUNET_malloc (n_size);
1299  }
1300  /* dname can end in "/" only if dname == "/";
1301  * if dname does not end in "/", we need to add
1302  * a "/" (otherwise, we must not!) */
1303  GNUNET_snprintf (name,
1304  n_size,
1305  "%s%s%s",
1306  dname,
1307  (0 == strcmp (dname,
1309  ? ""
1311  finfo->d_name);
1312  ret = callback (callback_cls,
1313  name);
1314  if (GNUNET_OK != ret)
1315  {
1316  CLOSEDIR (dinfo);
1317  GNUNET_free (name);
1318  GNUNET_free (dname);
1319  if (GNUNET_NO == ret)
1320  return count;
1321  return GNUNET_SYSERR;
1322  }
1323  }
1324  count++;
1325  }
1326  CLOSEDIR (dinfo);
1327  GNUNET_free (name);
1328  GNUNET_free (dname);
1329  return count;
1330 }
1331 
1332 
1341 static int
1342 remove_helper (void *unused,
1343  const char *fn)
1344 {
1345  (void) unused;
1346  (void) GNUNET_DISK_directory_remove (fn);
1347  return GNUNET_OK;
1348 }
1349 
1350 
1358 int
1360 {
1361  struct stat istat;
1362 
1363  if (NULL == filename)
1364  {
1365  GNUNET_break (0);
1366  return GNUNET_SYSERR;
1367  }
1368  if (0 != LSTAT (filename, &istat))
1369  return GNUNET_NO; /* file may not exist... */
1370  (void) CHMOD (filename,
1371  S_IWUSR | S_IRUSR | S_IXUSR);
1372  if (0 == UNLINK (filename))
1373  return GNUNET_OK;
1374  if ( (errno != EISDIR) &&
1375  /* EISDIR is not sufficient in all cases, e.g.
1376  * sticky /tmp directory may result in EPERM on BSD.
1377  * So we also explicitly check "isDirectory" */
1378  (GNUNET_YES !=
1379  GNUNET_DISK_directory_test (filename,
1380  GNUNET_YES)) )
1381  {
1383  "rmdir",
1384  filename);
1385  return GNUNET_SYSERR;
1386  }
1387  if (GNUNET_SYSERR ==
1388  GNUNET_DISK_directory_scan (filename,
1389  &remove_helper,
1390  NULL))
1391  return GNUNET_SYSERR;
1392  if (0 != RMDIR (filename))
1393  {
1395  "rmdir",
1396  filename);
1397  return GNUNET_SYSERR;
1398  }
1399  return GNUNET_OK;
1400 }
1401 
1402 
1410 int
1411 GNUNET_DISK_file_copy (const char *src,
1412  const char *dst)
1413 {
1414  char *buf;
1415  uint64_t pos;
1416  uint64_t size;
1417  size_t len;
1418  ssize_t sret;
1419  struct GNUNET_DISK_FileHandle *in;
1420  struct GNUNET_DISK_FileHandle *out;
1421 
1422  if (GNUNET_OK !=
1423  GNUNET_DISK_file_size (src,
1424  &size,
1425  GNUNET_YES,
1426  GNUNET_YES))
1427  {
1429  "stat",
1430  src);
1431  return GNUNET_SYSERR;
1432  }
1433  pos = 0;
1434  in = GNUNET_DISK_file_open (src,
1437  if (! in)
1438  {
1440  "open",
1441  src);
1442  return GNUNET_SYSERR;
1443  }
1444  out =
1445  GNUNET_DISK_file_open (dst,
1452  if (!out)
1453  {
1455  "open",
1456  dst);
1458  return GNUNET_SYSERR;
1459  }
1460  buf = GNUNET_malloc (COPY_BLK_SIZE);
1461  while (pos < size)
1462  {
1463  len = COPY_BLK_SIZE;
1464  if (len > size - pos)
1465  len = size - pos;
1466  sret = GNUNET_DISK_file_read (in,
1467  buf,
1468  len);
1469  if ( (sret < 0) ||
1470  (len != (size_t) sret) )
1471  goto FAIL;
1472  sret = GNUNET_DISK_file_write (out,
1473  buf,
1474  len);
1475  if ( (sret < 0) ||
1476  (len != (size_t) sret) )
1477  goto FAIL;
1478  pos += len;
1479  }
1480  GNUNET_free (buf);
1482  GNUNET_DISK_file_close (out);
1483  return GNUNET_OK;
1484 FAIL:
1485  GNUNET_free (buf);
1487  GNUNET_DISK_file_close (out);
1488  return GNUNET_SYSERR;
1489 }
1490 
1491 
1496 void
1498 {
1499  char *idx;
1500  char c;
1501 
1502  for (idx = fn; *idx; idx++)
1503  {
1504  c = *idx;
1505 
1506  if (c == '/' || c == '\\' || c == ':' ||
1507  c == '*' || c == '?' || c == '"' ||
1508  c == '<' || c == '>' || c == '|')
1509  {
1510  *idx = '_';
1511  }
1512  }
1513 }
1514 
1515 
1516 
1524 int
1526  const char *user)
1527 {
1528 #ifndef MINGW
1529  struct passwd *pws;
1530 
1531  pws = getpwnam (user);
1532  if (NULL == pws)
1533  {
1535  _("Cannot obtain information about user `%s': %s\n"),
1536  user,
1537  STRERROR (errno));
1538  return GNUNET_SYSERR;
1539  }
1540  if (0 != chown (filename,
1541  pws->pw_uid,
1542  pws->pw_gid))
1543  {
1545  "chown",
1546  filename);
1547  return GNUNET_SYSERR;
1548  }
1549 #endif
1550  return GNUNET_OK;
1551 }
1552 
1553 
1563 int
1565  off_t lock_start,
1566  off_t lock_end,
1567  int excl)
1568 {
1569  if (fh == NULL)
1570  {
1571  errno = EINVAL;
1572  return GNUNET_SYSERR;
1573  }
1574 
1575 #ifndef MINGW
1576  struct flock fl;
1577 
1578  memset (&fl, 0, sizeof (struct flock));
1579  fl.l_type = excl ? F_WRLCK : F_RDLCK;
1580  fl.l_whence = SEEK_SET;
1581  fl.l_start = lock_start;
1582  fl.l_len = lock_end;
1583 
1584  return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1585 #else
1586  OVERLAPPED o;
1587  off_t diff = lock_end - lock_start;
1588  DWORD diff_low, diff_high;
1589  diff_low = (DWORD) (diff & 0xFFFFFFFF);
1590  diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1591 
1592  memset (&o, 0, sizeof (OVERLAPPED));
1593  o.Offset = (DWORD) (lock_start & 0xFFFFFFFF);;
1594  o.OffsetHigh = (DWORD) (((lock_start & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1595 
1596  if (!LockFileEx
1597  (fh->h, (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0) | LOCKFILE_FAIL_IMMEDIATELY,
1598  0, diff_low, diff_high, &o))
1599  {
1600  SetErrnoFromWinError (GetLastError ());
1601  return GNUNET_SYSERR;
1602  }
1603 
1604  return GNUNET_OK;
1605 #endif
1606 }
1607 
1608 
1617 int
1619  off_t unlock_start,
1620  off_t unlock_end)
1621 {
1622  if (fh == NULL)
1623  {
1624  errno = EINVAL;
1625  return GNUNET_SYSERR;
1626  }
1627 
1628 #ifndef MINGW
1629  struct flock fl;
1630 
1631  memset (&fl, 0, sizeof (struct flock));
1632  fl.l_type = F_UNLCK;
1633  fl.l_whence = SEEK_SET;
1634  fl.l_start = unlock_start;
1635  fl.l_len = unlock_end;
1636 
1637  return fcntl (fh->fd, F_SETLK, &fl) != 0 ? GNUNET_SYSERR : GNUNET_OK;
1638 #else
1639  OVERLAPPED o;
1640  off_t diff = unlock_end - unlock_start;
1641  DWORD diff_low, diff_high;
1642  diff_low = (DWORD) (diff & 0xFFFFFFFF);
1643  diff_high = (DWORD) ((diff >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1644 
1645  memset (&o, 0, sizeof (OVERLAPPED));
1646  o.Offset = (DWORD) (unlock_start & 0xFFFFFFFF);;
1647  o.OffsetHigh = (DWORD) (((unlock_start & ~0xFFFFFFFF) >> (sizeof (DWORD) * 8)) & 0xFFFFFFFF);
1648 
1649  if (!UnlockFileEx (fh->h, 0, diff_low, diff_high, &o))
1650  {
1651  SetErrnoFromWinError (GetLastError ());
1652  return GNUNET_SYSERR;
1653  }
1654 
1655  return GNUNET_OK;
1656 #endif
1657 }
1658 
1659 
1672 struct GNUNET_DISK_FileHandle *
1674  enum GNUNET_DISK_OpenFlags flags,
1676 {
1677  char *expfn;
1678  struct GNUNET_DISK_FileHandle *ret;
1679 
1680 #ifdef MINGW
1681  DWORD access;
1682  DWORD disp;
1683  HANDLE h;
1684  wchar_t wexpfn[MAX_PATH + 1];
1685 #else
1686  int oflags;
1687  int mode;
1688  int fd;
1689 #endif
1690 
1691  expfn = GNUNET_STRINGS_filename_expand (fn);
1692  if (NULL == expfn)
1693  return NULL;
1694 #ifndef MINGW
1695  mode = 0;
1697  oflags = O_RDWR; /* note: O_RDWR is NOT always O_RDONLY | O_WRONLY */
1698  else if (flags & GNUNET_DISK_OPEN_READ)
1699  oflags = O_RDONLY;
1700  else if (flags & GNUNET_DISK_OPEN_WRITE)
1701  oflags = O_WRONLY;
1702  else
1703  {
1704  GNUNET_break (0);
1705  GNUNET_free (expfn);
1706  return NULL;
1707  }
1708  if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1709  oflags |= (O_CREAT | O_EXCL);
1710  if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1711  oflags |= O_TRUNC;
1712  if (flags & GNUNET_DISK_OPEN_APPEND)
1713  oflags |= O_APPEND;
1714  if(GNUNET_NO == GNUNET_DISK_file_test(fn))
1715  {
1716  if (flags & GNUNET_DISK_OPEN_CREATE )
1717  {
1719  oflags |= O_CREAT;
1720  mode = translate_unix_perms (perm);
1721  }
1722  }
1723 
1724  fd = open (expfn, oflags
1725 #if O_CLOEXEC
1726  | O_CLOEXEC
1727 #endif
1728  | O_LARGEFILE, mode);
1729  if (fd == -1)
1730  {
1731  if (0 == (flags & GNUNET_DISK_OPEN_FAILIFEXISTS))
1733  else
1734  LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_DEBUG, "open", expfn);
1735  GNUNET_free (expfn);
1736  return NULL;
1737  }
1738 #else
1739  access = 0;
1740  disp = OPEN_ALWAYS;
1741 
1742  if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
1743  access = FILE_READ_DATA | FILE_WRITE_DATA;
1744  else if (flags & GNUNET_DISK_OPEN_READ)
1745  access = FILE_READ_DATA;
1746  else if (flags & GNUNET_DISK_OPEN_WRITE)
1747  access = FILE_WRITE_DATA;
1748 
1749  if (flags & GNUNET_DISK_OPEN_FAILIFEXISTS)
1750  {
1751  disp = CREATE_NEW;
1752  }
1753  else if (flags & GNUNET_DISK_OPEN_CREATE)
1754  {
1756  if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1757  disp = CREATE_ALWAYS;
1758  else
1759  disp = OPEN_ALWAYS;
1760  }
1761  else if (flags & GNUNET_DISK_OPEN_TRUNCATE)
1762  {
1763  disp = TRUNCATE_EXISTING;
1764  }
1765  else
1766  {
1767  disp = OPEN_EXISTING;
1768  }
1769 
1770  if (ERROR_SUCCESS == plibc_conv_to_win_pathwconv(expfn, wexpfn))
1771  h = CreateFileW (wexpfn, access,
1772  FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1773  disp, FILE_ATTRIBUTE_NORMAL, NULL);
1774  else
1775  h = INVALID_HANDLE_VALUE;
1776  if (h == INVALID_HANDLE_VALUE)
1777  {
1778  int err;
1779  SetErrnoFromWinError (GetLastError ());
1780  err = errno;
1781  LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_INFO, "open", expfn);
1782  GNUNET_free (expfn);
1783  errno = err;
1784  return NULL;
1785  }
1786 
1787  if (flags & GNUNET_DISK_OPEN_APPEND)
1788  if (SetFilePointer (h, 0, 0, FILE_END) == INVALID_SET_FILE_POINTER)
1789  {
1790  SetErrnoFromWinError (GetLastError ());
1791  LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "SetFilePointer", expfn);
1792  CloseHandle (h);
1793  GNUNET_free (expfn);
1794  return NULL;
1795  }
1796 #endif
1797 
1798  ret = GNUNET_new (struct GNUNET_DISK_FileHandle);
1799 #ifdef MINGW
1800  ret->h = h;
1801  ret->type = GNUNET_DISK_HANLDE_TYPE_FILE;
1802 #else
1803  ret->fd = fd;
1804 #endif
1805  GNUNET_free (expfn);
1806  return ret;
1807 }
1808 
1809 
1816 int
1818 {
1819  int ret;
1820  if (h == NULL)
1821  {
1822  errno = EINVAL;
1823  return GNUNET_SYSERR;
1824  }
1825 
1826  ret = GNUNET_OK;
1827 
1828 #if MINGW
1829  if (! CloseHandle (h->h))
1830  {
1831  SetErrnoFromWinError (GetLastError ());
1833  ret = GNUNET_SYSERR;
1834  }
1835  if (h->oOverlapRead)
1836  {
1837  if (! CloseHandle (h->oOverlapRead->hEvent))
1838  {
1839  SetErrnoFromWinError (GetLastError ());
1841  ret = GNUNET_SYSERR;
1842  }
1843  GNUNET_free (h->oOverlapRead);
1844  }
1845  if (h->oOverlapWrite)
1846  {
1847  if (!CloseHandle (h->oOverlapWrite->hEvent))
1848  {
1849  SetErrnoFromWinError (GetLastError ());
1851  ret = GNUNET_SYSERR;
1852  }
1853  GNUNET_free (h->oOverlapWrite);
1854  }
1855 #else
1856  if (close (h->fd) != 0)
1857  {
1859  ret = GNUNET_SYSERR;
1860  }
1861 #endif
1862  GNUNET_free (h);
1863  return ret;
1864 }
1865 
1866 
1867 #ifdef WINDOWS
1868 
1874 struct GNUNET_DISK_FileHandle *
1875 GNUNET_DISK_get_handle_from_w32_handle (HANDLE osfh)
1876 {
1877  struct GNUNET_DISK_FileHandle *fh;
1878  DWORD dwret;
1879  enum GNUNET_FILE_Type ftype;
1880 
1881  dwret = GetFileType (osfh);
1882  switch (dwret)
1883  {
1884  case FILE_TYPE_DISK:
1886  break;
1887  case FILE_TYPE_PIPE:
1889  break;
1890  case FILE_TYPE_UNKNOWN:
1891  if ( (GetLastError () == NO_ERROR) ||
1892  (GetLastError () == ERROR_INVALID_HANDLE) )
1893  {
1894  if (0 != ResetEvent (osfh))
1896  else
1897  return NULL;
1898  }
1899  else
1900  return NULL;
1901  break;
1902  default:
1903  return NULL;
1904  }
1905 
1906  fh = GNUNET_new (struct GNUNET_DISK_FileHandle);
1907 
1908  fh->h = osfh;
1909  fh->type = ftype;
1910  if (ftype == GNUNET_DISK_HANLDE_TYPE_PIPE)
1911  {
1920  fh->oOverlapRead = GNUNET_new (OVERLAPPED);
1921  fh->oOverlapWrite = GNUNET_new (OVERLAPPED);
1922  fh->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
1923  fh->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
1924  }
1925 
1926  return fh;
1927 }
1928 #endif
1929 
1936 struct GNUNET_DISK_FileHandle *
1938 {
1939  struct GNUNET_DISK_FileHandle *fh;
1940 
1941  if ( (((off_t) -1) == lseek (fno, 0, SEEK_CUR)) &&
1942  (EBADF == errno) )
1943  return NULL; /* invalid FD */
1944 
1945 #ifndef WINDOWS
1946  fh = GNUNET_new (struct GNUNET_DISK_FileHandle);
1947 
1948  fh->fd = fno;
1949 #else
1950  intptr_t osfh;
1951 
1952  osfh = _get_osfhandle (fno);
1953  if (INVALID_HANDLE_VALUE == (HANDLE) osfh)
1954  return NULL;
1955 
1956  fh = GNUNET_DISK_get_handle_from_w32_handle ((HANDLE) osfh);
1957 #endif
1958 
1959  return fh;
1960 }
1961 
1962 
1969 struct GNUNET_DISK_FileHandle *
1971 {
1972  int fno;
1973 
1974  fno = fileno (fd);
1975  if (-1 == fno)
1976  return NULL;
1977 
1979 }
1980 
1981 
1986 {
1990  void *addr;
1991 
1992 #ifdef MINGW
1993 
1996  HANDLE h;
1997 #else
1998 
2001  size_t len;
2002 #endif
2003 };
2004 
2005 
2006 #ifndef MAP_FAILED
2007 #define MAP_FAILED ((void *) -1)
2008 #endif
2009 
2019 void *
2021  struct GNUNET_DISK_MapHandle **m,
2022  enum GNUNET_DISK_MapType access, size_t len)
2023 {
2024  if (NULL == h)
2025  {
2026  errno = EINVAL;
2027  return NULL;
2028  }
2029 
2030 #ifdef MINGW
2031  DWORD mapAccess, protect;
2032 
2033  if ((access & GNUNET_DISK_MAP_TYPE_READ) &&
2034  (access & GNUNET_DISK_MAP_TYPE_WRITE))
2035  {
2036  protect = PAGE_READWRITE;
2037  mapAccess = FILE_MAP_ALL_ACCESS;
2038  }
2039  else if (access & GNUNET_DISK_MAP_TYPE_READ)
2040  {
2041  protect = PAGE_READONLY;
2042  mapAccess = FILE_MAP_READ;
2043  }
2044  else if (access & GNUNET_DISK_MAP_TYPE_WRITE)
2045  {
2046  protect = PAGE_READWRITE;
2047  mapAccess = FILE_MAP_WRITE;
2048  }
2049  else
2050  {
2051  GNUNET_break (0);
2052  return NULL;
2053  }
2054 
2055  *m = GNUNET_new (struct GNUNET_DISK_MapHandle);
2056  (*m)->h = CreateFileMapping (h->h, NULL, protect, 0, 0, NULL);
2057  if ((*m)->h == INVALID_HANDLE_VALUE)
2058  {
2059  SetErrnoFromWinError (GetLastError ());
2060  GNUNET_free (*m);
2061  return NULL;
2062  }
2063 
2064  (*m)->addr = MapViewOfFile ((*m)->h, mapAccess, 0, 0, len);
2065  if (!(*m)->addr)
2066  {
2067  SetErrnoFromWinError (GetLastError ());
2068  CloseHandle ((*m)->h);
2069  GNUNET_free (*m);
2070  }
2071 
2072  return (*m)->addr;
2073 #else
2074  int prot;
2075 
2076  prot = 0;
2077  if (access & GNUNET_DISK_MAP_TYPE_READ)
2078  prot = PROT_READ;
2079  if (access & GNUNET_DISK_MAP_TYPE_WRITE)
2080  prot |= PROT_WRITE;
2081  *m = GNUNET_new (struct GNUNET_DISK_MapHandle);
2082  (*m)->addr = mmap (NULL, len, prot, MAP_SHARED, h->fd, 0);
2083  GNUNET_assert (NULL != (*m)->addr);
2084  if (MAP_FAILED == (*m)->addr)
2085  {
2086  GNUNET_free (*m);
2087  return NULL;
2088  }
2089  (*m)->len = len;
2090  return (*m)->addr;
2091 #endif
2092 }
2093 
2099 int
2101 {
2102  int ret;
2103 
2104  if (h == NULL)
2105  {
2106  errno = EINVAL;
2107  return GNUNET_SYSERR;
2108  }
2109 
2110 #ifdef MINGW
2111  ret = UnmapViewOfFile (h->addr) ? GNUNET_OK : GNUNET_SYSERR;
2112  if (ret != GNUNET_OK)
2113  SetErrnoFromWinError (GetLastError ());
2114  if (!CloseHandle (h->h) && (ret == GNUNET_OK))
2115  {
2116  ret = GNUNET_SYSERR;
2117  SetErrnoFromWinError (GetLastError ());
2118  }
2119 #else
2120  ret = munmap (h->addr, h->len) != -1 ? GNUNET_OK : GNUNET_SYSERR;
2121 #endif
2122  GNUNET_free (h);
2123  return ret;
2124 }
2125 
2126 
2132 int
2134 {
2135  if (h == NULL)
2136  {
2137  errno = EINVAL;
2138  return GNUNET_SYSERR;
2139  }
2140 
2141 #ifdef MINGW
2142  int ret;
2143 
2144  ret = FlushFileBuffers (h->h) ? GNUNET_OK : GNUNET_SYSERR;
2145  if (ret != GNUNET_OK)
2146  SetErrnoFromWinError (GetLastError ());
2147  return ret;
2148 #elif defined(FREEBSD) || defined(OPENBSD) || defined(DARWIN)
2149  return fsync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
2150 #else
2151  return fdatasync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
2152 #endif
2153 }
2154 
2155 
2156 #if WINDOWS
2157 #ifndef PIPE_BUF
2158 #define PIPE_BUF 512
2159 #endif
2160 /* Copyright Bob Byrnes <byrnes <at> curl.com>
2161  http://permalink.gmane.org/gmane.os.cygwin.patches/2121
2162 */
2163 /* Create a pipe, and return handles to the read and write ends,
2164  just like CreatePipe, but ensure that the write end permits
2165  FILE_READ_ATTRIBUTES access, on later versions of win32 where
2166  this is supported. This access is needed by NtQueryInformationFile,
2167  which is used to implement select and nonblocking writes.
2168  Note that the return value is either NO_ERROR or GetLastError,
2169  unlike CreatePipe, which returns a bool for success or failure. */
2170 static int
2171 create_selectable_pipe (PHANDLE read_pipe_ptr, PHANDLE write_pipe_ptr,
2172  LPSECURITY_ATTRIBUTES sa_ptr, DWORD psize,
2173  DWORD dwReadMode, DWORD dwWriteMode)
2174 {
2175  /* Default to error. */
2176  *read_pipe_ptr = *write_pipe_ptr = INVALID_HANDLE_VALUE;
2177 
2178  HANDLE read_pipe;
2179  HANDLE write_pipe;
2180 
2181  /* Ensure that there is enough pipe buffer space for atomic writes. */
2182  if (psize < PIPE_BUF)
2183  psize = PIPE_BUF;
2184 
2185  char pipename[MAX_PATH];
2186 
2187  /* Retry CreateNamedPipe as long as the pipe name is in use.
2188  * Retrying will probably never be necessary, but we want
2189  * to be as robust as possible. */
2190  while (1)
2191  {
2192  static volatile LONG pipe_unique_id;
2193 
2194  snprintf (pipename, sizeof pipename, "\\\\.\\pipe\\gnunet-%d-%ld",
2195  getpid (), InterlockedIncrement ((LONG *) & pipe_unique_id));
2196  LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateNamedPipe: name = %s, size = %lu\n",
2197  pipename, psize);
2198  /* Use CreateNamedPipe instead of CreatePipe, because the latter
2199  * returns a write handle that does not permit FILE_READ_ATTRIBUTES
2200  * access, on versions of win32 earlier than WinXP SP2.
2201  * CreatePipe also stupidly creates a full duplex pipe, which is
2202  * a waste, since only a single direction is actually used.
2203  * It's important to only allow a single instance, to ensure that
2204  * the pipe was not created earlier by some other process, even if
2205  * the pid has been reused. */
2206  read_pipe = CreateNamedPipeA (pipename, PIPE_ACCESS_INBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE | dwReadMode, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, /* max instances */
2207  psize, /* output buffer size */
2208  psize, /* input buffer size */
2209  NMPWAIT_USE_DEFAULT_WAIT, sa_ptr);
2210 
2211  if (read_pipe != INVALID_HANDLE_VALUE)
2212  {
2213  LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p\n", read_pipe);
2214  break;
2215  }
2216 
2217  DWORD err = GetLastError ();
2218 
2219  switch (err)
2220  {
2221  case ERROR_PIPE_BUSY:
2222  /* The pipe is already open with compatible parameters.
2223  * Pick a new name and retry. */
2224  LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe busy, retrying\n");
2225  continue;
2226  case ERROR_ACCESS_DENIED:
2227  /* The pipe is already open with incompatible parameters.
2228  * Pick a new name and retry. */
2229  LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe access denied, retrying\n");
2230  continue;
2231  case ERROR_CALL_NOT_IMPLEMENTED:
2232  /* We are on an older Win9x platform without named pipes.
2233  * Return an anonymous pipe as the best approximation. */
2235  "CreateNamedPipe not implemented, resorting to "
2236  "CreatePipe: size = %lu\n", psize);
2237  if (CreatePipe (read_pipe_ptr, write_pipe_ptr, sa_ptr, psize))
2238  {
2239  LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe read handle = %p, write handle = %p\n",
2240  *read_pipe_ptr,
2241  *write_pipe_ptr);
2242  return GNUNET_OK;
2243  }
2244  err = GetLastError ();
2245  LOG (GNUNET_ERROR_TYPE_ERROR, "CreatePipe failed: %d\n", err);
2246  return err;
2247  default:
2248  LOG (GNUNET_ERROR_TYPE_ERROR, "CreateNamedPipe failed: %d\n", err);
2249  return err;
2250  }
2251  /* NOTREACHED */
2252  }
2253  LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile: name = %s\n", pipename);
2254 
2255  /* Open the named pipe for writing.
2256  * Be sure to permit FILE_READ_ATTRIBUTES access. */
2257  write_pipe = CreateFileA (pipename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0, /* share mode */
2258  sa_ptr, OPEN_EXISTING, dwWriteMode, /* flags and attributes */
2259  0); /* handle to template file */
2260 
2261  if (write_pipe == INVALID_HANDLE_VALUE)
2262  {
2263  /* Failure. */
2264  DWORD err = GetLastError ();
2265 
2266  LOG (GNUNET_ERROR_TYPE_DEBUG, "CreateFile failed: %d\n", err);
2267  CloseHandle (read_pipe);
2268  return err;
2269  }
2270  LOG (GNUNET_ERROR_TYPE_DEBUG, "pipe write handle = %p\n", write_pipe);
2271  /* Success. */
2272  *read_pipe_ptr = read_pipe;
2273  *write_pipe_ptr = write_pipe;
2274  return GNUNET_OK;
2275 }
2276 #endif
2277 
2278 
2288 struct GNUNET_DISK_PipeHandle *
2289 GNUNET_DISK_pipe (int blocking_read,
2290  int blocking_write,
2291  int inherit_read,
2292  int inherit_write)
2293 {
2294 #ifndef MINGW
2295  int fd[2];
2296  int ret;
2297  int eno;
2298 
2299  (void) inherit_read;
2300  (void) inherit_write;
2301  ret = pipe (fd);
2302  if (ret == -1)
2303  {
2304  eno = errno;
2306  "pipe");
2307  errno = eno;
2308  return NULL;
2309  }
2310  return GNUNET_DISK_pipe_from_fd (blocking_read,
2311  blocking_write,
2312  fd);
2313 #else
2314  struct GNUNET_DISK_PipeHandle *p;
2315  BOOL ret;
2316  HANDLE tmp_handle;
2317  int save_errno;
2318 
2319  p = GNUNET_new (struct GNUNET_DISK_PipeHandle);
2320  p->fd[0] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2321  p->fd[1] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2322 
2323  /* All pipes are overlapped. If you want them to block - just
2324  * call WriteFile() and ReadFile() with NULL overlapped pointer.
2325  * NOTE: calling with NULL overlapped pointer works only
2326  * for pipes, and doesn't seem to be a documented feature.
2327  * It will NOT work for files, because overlapped files need
2328  * to read offsets from the overlapped structure, regardless.
2329  * Pipes are not seekable, and need no offsets, which is
2330  * probably why it works for them.
2331  */
2332  ret =
2333  create_selectable_pipe (&p->fd[0]->h, &p->fd[1]->h, NULL, 0,
2334  FILE_FLAG_OVERLAPPED,
2335  FILE_FLAG_OVERLAPPED);
2336  if (!ret)
2337  {
2338  SetErrnoFromWinError (GetLastError ());
2339  save_errno = errno;
2340  GNUNET_free (p->fd[0]);
2341  GNUNET_free (p->fd[1]);
2342  GNUNET_free (p);
2343  errno = save_errno;
2344  return NULL;
2345  }
2346  if (!DuplicateHandle
2347  (GetCurrentProcess (), p->fd[0]->h, GetCurrentProcess (), &tmp_handle, 0,
2348  inherit_read == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2349  {
2350  SetErrnoFromWinError (GetLastError ());
2351  save_errno = errno;
2352  CloseHandle (p->fd[0]->h);
2353  CloseHandle (p->fd[1]->h);
2354  GNUNET_free (p->fd[0]);
2355  GNUNET_free (p->fd[1]);
2356  GNUNET_free (p);
2357  errno = save_errno;
2358  return NULL;
2359  }
2360  CloseHandle (p->fd[0]->h);
2361  p->fd[0]->h = tmp_handle;
2362 
2363  if (!DuplicateHandle
2364  (GetCurrentProcess (), p->fd[1]->h, GetCurrentProcess (), &tmp_handle, 0,
2365  inherit_write == GNUNET_YES ? TRUE : FALSE, DUPLICATE_SAME_ACCESS))
2366  {
2367  SetErrnoFromWinError (GetLastError ());
2368  save_errno = errno;
2369  CloseHandle (p->fd[0]->h);
2370  CloseHandle (p->fd[1]->h);
2371  GNUNET_free (p->fd[0]);
2372  GNUNET_free (p->fd[1]);
2373  GNUNET_free (p);
2374  errno = save_errno;
2375  return NULL;
2376  }
2377  CloseHandle (p->fd[1]->h);
2378  p->fd[1]->h = tmp_handle;
2379 
2380  p->fd[0]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2381  p->fd[1]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2382 
2383  p->fd[0]->oOverlapRead = GNUNET_new (OVERLAPPED);
2384  p->fd[0]->oOverlapWrite = GNUNET_new (OVERLAPPED);
2385  p->fd[1]->oOverlapRead = GNUNET_new (OVERLAPPED);
2386  p->fd[1]->oOverlapWrite = GNUNET_new (OVERLAPPED);
2387 
2388  p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2389  p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2390 
2391  p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2392  p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2393 
2394  return p;
2395 #endif
2396 }
2397 
2398 
2409 struct GNUNET_DISK_PipeHandle *
2410 GNUNET_DISK_pipe_from_fd (int blocking_read, int blocking_write, int fd[2])
2411 {
2412  struct GNUNET_DISK_PipeHandle *p;
2413 
2414  p = GNUNET_new (struct GNUNET_DISK_PipeHandle);
2415 
2416 #ifndef MINGW
2417  int ret;
2418  int flags;
2419  int eno = 0; /* make gcc happy */
2420 
2421  ret = 0;
2422  if (fd[0] >= 0)
2423  {
2424  p->fd[0] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2425  p->fd[0]->fd = fd[0];
2426  if (!blocking_read)
2427  {
2428  flags = fcntl (fd[0], F_GETFL);
2429  flags |= O_NONBLOCK;
2430  if (0 > fcntl (fd[0], F_SETFL, flags))
2431  {
2432  ret = -1;
2433  eno = errno;
2434  }
2435  }
2436  flags = fcntl (fd[0], F_GETFD);
2437  flags |= FD_CLOEXEC;
2438  if (0 > fcntl (fd[0], F_SETFD, flags))
2439  {
2440  ret = -1;
2441  eno = errno;
2442  }
2443  }
2444 
2445  if (fd[1] >= 0)
2446  {
2447  p->fd[1] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2448  p->fd[1]->fd = fd[1];
2449  if (!blocking_write)
2450  {
2451  flags = fcntl (fd[1], F_GETFL);
2452  flags |= O_NONBLOCK;
2453  if (0 > fcntl (fd[1], F_SETFL, flags))
2454  {
2455  ret = -1;
2456  eno = errno;
2457  }
2458  }
2459  flags = fcntl (fd[1], F_GETFD);
2460  flags |= FD_CLOEXEC;
2461  if (0 > fcntl (fd[1], F_SETFD, flags))
2462  {
2463  ret = -1;
2464  eno = errno;
2465  }
2466  }
2467  if (ret == -1)
2468  {
2469  errno = eno;
2471  if (p->fd[0]->fd >= 0)
2472  GNUNET_break (0 == close (p->fd[0]->fd));
2473  if (p->fd[1]->fd >= 0)
2474  GNUNET_break (0 == close (p->fd[1]->fd));
2475  GNUNET_free_non_null (p->fd[0]);
2476  GNUNET_free_non_null (p->fd[1]);
2477  GNUNET_free (p);
2478  errno = eno;
2479  return NULL;
2480  }
2481 #else
2482  if (fd[0] >= 0)
2483  {
2484  p->fd[0] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2485  p->fd[0]->h = (HANDLE) _get_osfhandle (fd[0]);
2486  if (p->fd[0]->h != INVALID_HANDLE_VALUE)
2487  {
2488  p->fd[0]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2489  p->fd[0]->oOverlapRead = GNUNET_new (OVERLAPPED);
2490  p->fd[0]->oOverlapWrite = GNUNET_new (OVERLAPPED);
2491  p->fd[0]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2492  p->fd[0]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2493  }
2494  else
2495  {
2496  GNUNET_free (p->fd[0]);
2497  p->fd[0] = NULL;
2498  }
2499  }
2500  if (fd[1] >= 0)
2501  {
2502  p->fd[1] = GNUNET_new (struct GNUNET_DISK_FileHandle);
2503  p->fd[1]->h = (HANDLE) _get_osfhandle (fd[1]);
2504  if (p->fd[1]->h != INVALID_HANDLE_VALUE)
2505  {
2506  p->fd[1]->type = GNUNET_DISK_HANLDE_TYPE_PIPE;
2507  p->fd[1]->oOverlapRead = GNUNET_new (OVERLAPPED);
2508  p->fd[1]->oOverlapWrite = GNUNET_new (OVERLAPPED);
2509  p->fd[1]->oOverlapRead->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2510  p->fd[1]->oOverlapWrite->hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
2511  }
2512  else
2513  {
2514  GNUNET_free (p->fd[1]);
2515  p->fd[1] = NULL;
2516  }
2517  }
2518 
2519 #endif
2520  return p;
2521 }
2522 
2523 
2531 int
2533  enum GNUNET_DISK_PipeEnd end)
2534 {
2535  int ret = GNUNET_OK;
2536 
2537  if (end == GNUNET_DISK_PIPE_END_READ)
2538  {
2539  if (p->fd[0])
2540  {
2541  ret = GNUNET_DISK_file_close (p->fd[0]);
2542  p->fd[0] = NULL;
2543  }
2544  }
2545  else if (end == GNUNET_DISK_PIPE_END_WRITE)
2546  {
2547  if (p->fd[1])
2548  {
2549  ret = GNUNET_DISK_file_close (p->fd[1]);
2550  p->fd[1] = NULL;
2551  }
2552  }
2553 
2554  return ret;
2555 }
2556 
2569 struct GNUNET_DISK_FileHandle *
2571  enum GNUNET_DISK_PipeEnd end)
2572 {
2573  struct GNUNET_DISK_FileHandle *ret = NULL;
2574 
2575  if (end == GNUNET_DISK_PIPE_END_READ)
2576  {
2577  if (p->fd[0])
2578  {
2579  ret = p->fd[0];
2580  p->fd[0] = NULL;
2581  }
2582  }
2583  else if (end == GNUNET_DISK_PIPE_END_WRITE)
2584  {
2585  if (p->fd[1])
2586  {
2587  ret = p->fd[1];
2588  p->fd[1] = NULL;
2589  }
2590  }
2591 
2592  return ret;
2593 }
2594 
2595 
2602 int
2604 {
2605  int ret = GNUNET_OK;
2606 
2607  int read_end_close;
2608  int write_end_close;
2609  int read_end_close_errno;
2610  int write_end_close_errno;
2611 
2613  read_end_close_errno = errno;
2615  write_end_close_errno = errno;
2616  GNUNET_free (p);
2617 
2618  if (GNUNET_OK != read_end_close)
2619  {
2620  errno = read_end_close_errno;
2621  ret = read_end_close;
2622  }
2623  else if (GNUNET_OK != write_end_close)
2624  {
2625  errno = write_end_close_errno;
2626  ret = write_end_close;
2627  }
2628 
2629  return ret;
2630 }
2631 
2632 
2640 const struct GNUNET_DISK_FileHandle *
2642  enum GNUNET_DISK_PipeEnd n)
2643 {
2644  switch (n)
2645  {
2648  return p->fd[n];
2649  default:
2650  GNUNET_break (0);
2651  return NULL;
2652  }
2653 }
2654 
2655 
2664 int
2666  void *dst, size_t dst_len)
2667 {
2668  if (NULL == fh)
2669  return GNUNET_SYSERR;
2670 #ifdef MINGW
2671  if (dst_len < sizeof (HANDLE))
2672  return GNUNET_SYSERR;
2673  *((HANDLE *) dst) = fh->h;
2674 #else
2675  if (dst_len < sizeof (int))
2676  return GNUNET_SYSERR;
2677  *((int *) dst) = fh->fd;
2678 #endif
2679 
2680  return GNUNET_OK;
2681 }
2682 
2683 
2691 static int
2692 purge_cfg_dir (void *cls,
2693  const struct GNUNET_CONFIGURATION_Handle *cfg)
2694 {
2695  const char *option = cls;
2696  char *tmpname;
2697 
2698  if (GNUNET_OK !=
2700  "PATHS",
2701  option,
2702  &tmpname))
2703  {
2705  "PATHS",
2706  option);
2707  return GNUNET_NO;
2708  }
2709  if (GNUNET_SYSERR ==
2710  GNUNET_DISK_directory_remove (tmpname))
2711  {
2713  "remove",
2714  tmpname);
2715  GNUNET_free (tmpname);
2716  return GNUNET_OK;
2717  }
2718  GNUNET_free (tmpname);
2719  return GNUNET_OK;
2720 }
2721 
2722 
2730 void
2732  const char *option)
2733 {
2735  GNUNET_CONFIGURATION_parse_and_run (cfg_filename,
2736  &purge_cfg_dir,
2737  (void *) option));
2738 }
2739 
2740 
2741 /* end of disk.c */
void GNUNET_DISK_purge_cfg_dir(const char *cfg_filename, const char *option)
Remove the directory given under option in section [PATHS] in configuration under cfg_filename...
Definition: disk.c:2731
int GNUNET_DISK_file_test(const char *fil)
Check that fil corresponds to a filename (of a file that exists and that is not a directory)...
Definition: disk.c:669
Open the file for reading.
int GNUNET_DISK_file_sync(const struct GNUNET_DISK_FileHandle *h)
Write file changes to disk.
Definition: disk.c:2133
static char * cfg_filename
Name of the configuration file.
static char * dir
Set to the directory where runtime files are stored.
Definition: gnunet-arm.c:84
#define WINDOWS
Definition: w32nsp.c:44
#define CHMOD(f, p)
Definition: plibc.h:657
Create file if it doesn&#39;t exist.
GNUNET_DISK_MapType
Specifies what type of memory map is desired.
static char * pipename
void * addr
Address where the map is in memory.
Definition: disk.c:1990
static const char * dir_name
Top-level directory we monitor to auto-publish.
#define RMDIR(f)
Definition: plibc.h:655
int GNUNET_DISK_file_close(struct GNUNET_DISK_FileHandle *h)
Close an open file.
Definition: disk.c:1817
int GNUNET_DISK_file_copy(const char *src, const char *dst)
Copy a file.
Definition: disk.c:1411
#define LSTAT(p, b)
Definition: plibc.h:680
static int end
Set if we are to shutdown all services (including ARM).
Definition: gnunet-arm.c:34
uint64_t total
Set to the total file size.
Definition: disk.c:85
int GNUNET_DISK_file_unlock(struct GNUNET_DISK_FileHandle *fh, off_t unlock_start, off_t unlock_end)
Unlock a part of a file.
Definition: disk.c:1618
int single_file_mode
GNUNET_YES if mode is file-only (return total == -1 for directories).
Definition: disk.c:95
Closure for the recursion to determine the file size of a directory.
Definition: disk.c:80
int GNUNET_snprintf(char *buf, size_t size, const char *format,...)
Like snprintf, just aborts if the buffer is of insufficient size.
#define MAP_FAILED
Definition: disk.c:2007
ssize_t GNUNET_DISK_file_read(const struct GNUNET_DISK_FileHandle *h, void *result, size_t len)
Read the contents of a binary file into a buffer.
Definition: disk.c:881
int GNUNET_DISK_directory_create(const char *dir)
Implementation of "mkdir -p".
Definition: disk.c:714
#define CLOSEDIR(d)
Definition: plibc.h:649
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define STRERROR(i)
Definition: plibc.h:676
GNUNET_FILE_Type
Type of a handle.
void * GNUNET_DISK_file_map(const struct GNUNET_DISK_FileHandle *h, struct GNUNET_DISK_MapHandle **m, enum GNUNET_DISK_MapType access, size_t len)
Map a file into memory.
Definition: disk.c:2020
Handle represents a file.
Everybody can execute.
int GNUNET_DISK_directory_test(const char *fil, int is_readable)
Test if fil is a directory and listable.
Definition: disk.c:628
Nobody is allowed to do anything to the file.
GNUNET_DISK_Seek
Constants for specifying how to seek.
int GNUNET_DISK_directory_create_for_file(const char *filename)
Create the directory structure for storing a file.
Definition: disk.c:833
Append to the file.
#define GNUNET_NO
Definition: gnunet_common.h:81
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
int GNUNET_DISK_file_get_identifiers(const char *filename, uint64_t *dev, uint64_t *ino)
Obtain some unique identifiers for the given file that can be used to identify it in the local system...
Definition: disk.c:323
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define STAT(p, b)
Definition: plibc.h:663
int GNUNET_DISK_directory_scan(const char *dir_name, GNUNET_FileNameCallback callback, void *callback_cls)
Scan a directory for files.
Definition: disk.c:1233
static struct GNUNET_SCHEDULER_Task * t
Main task.
off_t GNUNET_DISK_file_seek(const struct GNUNET_DISK_FileHandle *h, off_t offset, enum GNUNET_DISK_Seek whence)
Move the read/write pointer in a file.
Definition: disk.c:241
static int ret
Final status code.
Definition: gnunet-arm.c:89
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define LOG_STRERROR(kind, syscall)
Definition: disk.c:33
#define FSTAT(h, b)
Definition: plibc.h:658
ssize_t GNUNET_DISK_fn_write(const char *fn, const void *buffer, size_t n, enum GNUNET_DISK_AccessPermissions mode)
Write a buffer to a file.
Definition: disk.c:1203
static int translate_unix_perms(enum GNUNET_DISK_AccessPermissions perm)
Translate GNUnet-internal permission bitmap to UNIX file access permission bitmap.
Definition: disk.c:108
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
int GNUNET_DISK_handle_invalid(const struct GNUNET_DISK_FileHandle *h)
Checks whether a handle is invalid.
Definition: disk.c:191
const struct GNUNET_DISK_FileHandle * GNUNET_DISK_pipe_handle(const struct GNUNET_DISK_PipeHandle *p, enum GNUNET_DISK_PipeEnd n)
Get the handle to a particular pipe end.
Definition: disk.c:2641
static struct GNUNET_ARM_Handle * h
Connection with ARM.
Definition: gnunet-arm.c:94
#define UNLINK(f)
Definition: plibc.h:666
#define O_LARGEFILE
Definition: platform.h:254
#define _(String)
GNU gettext support macro.
Definition: platform.h:208
static struct GNUNET_ARM_MonitorHandle * m
Monitor connection with ARM.
Definition: gnunet-arm.c:99
int GNUNET_asprintf(char **buf, const char *format,...)
Like asprintf, just portable.
struct GNUNET_DISK_FileHandle * fd[2]
File descriptors for the pipe.
Definition: disk.c:72
char * GNUNET_DISK_mktemp(const char *t)
Create an (empty) temporary file on disk.
Definition: disk.c:593
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-qr.c:59
void GNUNET_log_config_missing(enum GNUNET_ErrorType kind, const char *section, const char *option)
Log error message about missing configuration option.
size_t len
Number of bytes mapped.
Definition: disk.c:2001
struct GNUNET_DISK_FileHandle * GNUNET_DISK_pipe_detach_end(struct GNUNET_DISK_PipeHandle *p, enum GNUNET_DISK_PipeEnd end)
Detaches one of the ends from the pipe.
Definition: disk.c:2570
#define GNUNET_log_strerror_file(level, cmd, filename)
Log an error message at log-level &#39;level&#39; that indicates a failure of the command &#39;cmd&#39; with the mess...
static char * fn
Filename of the unique file.
static int remove_helper(void *unused, const char *fn)
Function that removes the given directory by calling GNUNET_DISK_directory_remove().
Definition: disk.c:1342
#define COPY_BLK_SIZE
Block size for IO for copying files.
Definition: disk.c:40
Truncate file if it exists.
ssize_t GNUNET_DISK_file_write(const struct GNUNET_DISK_FileHandle *h, const void *buffer, size_t n)
Write a buffer to a file.
Definition: disk.c:1049
int GNUNET_DISK_directory_remove(const char *filename)
Remove all files in a directory (rm -r).
Definition: disk.c:1359
Read-only memory map.
#define CLOSE(f)
Definition: plibc.h:653
static char * option
Name of the option.
Definition: gnunet-config.c:38
static char buf[2048]
static char * filename
static int result
Global testing status.
GNUNET_DISK_AccessPermissions
File access permissions, UNIX-style.
The writing-end of a pipe.
int include_sym_links
GNUNET_YES if symbolic links should be included.
Definition: disk.c:90
The reading-end of a pipe.
static int fh
Handle to the unique file.
void GNUNET_DISK_file_backup(const char *fil)
Move a file out of the way (create a backup) by renaming it to "orig.NUM~" where NUM is the smallest ...
Definition: disk.c:557
int(* GNUNET_FileNameCallback)(void *cls, const char *filename)
Function called with a filename.
#define LOG(kind,...)
Definition: disk.c:31
#define DIR_SEPARATOR
Definition: plibc.h:631
int plibc_conv_to_win_path(const char *pszUnix, char *pszWindows)
ssize_t GNUNET_DISK_file_write_blocking(const struct GNUNET_DISK_FileHandle *h, const void *buffer, size_t n)
Write a buffer to a file, blocking, if necessary.
Definition: disk.c:1139
#define OPENDIR(d)
Definition: plibc.h:648
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe(int blocking_read, int blocking_write, int inherit_read, int inherit_write)
Creates an interprocess channel.
Definition: disk.c:2289
Handle represents a pipe.
static struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Definition: gnunet-arm.c:104
static int getSizeRec(void *cls, const char *fn)
Iterate over all files in the given directory and accumulate their size.
Definition: disk.c:146
#define READDIR(d)
Definition: plibc.h:650
int GNUNET_DISK_file_lock(struct GNUNET_DISK_FileHandle *fh, off_t lock_start, off_t lock_end, int excl)
Lock a part of a file.
Definition: disk.c:1564
#define GNUNET_SYSERR
Definition: gnunet_common.h:79
static unsigned int size
Size of the "table".
Definition: peer.c:67
int GNUNET_DISK_internal_file_handle_(const struct GNUNET_DISK_FileHandle *fh, void *dst, size_t dst_len)
Retrieve OS file handle.
Definition: disk.c:2665
Everybody can write.
int GNUNET_DISK_file_unmap(struct GNUNET_DISK_MapHandle *h)
Unmap a file.
Definition: disk.c:2100
Open the file for writing.
char * GNUNET_DISK_mkdtemp(const char *t)
Create an (empty) temporary directory on disk.
Definition: disk.c:530
char * GNUNET_STRINGS_filename_expand(const char *fil)
Complete filename (a la shell) from abbrevition.
Definition: strings.c:602
const char * name
char * getenv()
int GNUNET_DISK_file_size(const char *filename, uint64_t *size, int include_symbolic_links, int single_file_mode)
Get the size of the file (or directory) of the given file (in bytes).
Definition: disk.c:289
#define S_ISLNK(m)
Definition: disk.c:59
int GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
Definition: disk.c:2603
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe_from_fd(int blocking_read, int blocking_write, int fd[2])
Creates a pipe object from a couple of file descriptors.
Definition: disk.c:2410
#define LOG_STRERROR_FILE(kind, syscall, filename)
Definition: disk.c:35
Everybody can read.
int GNUNET_DISK_pipe_close_end(struct GNUNET_DISK_PipeHandle *p, enum GNUNET_DISK_PipeEnd end)
Closes an interprocess channel.
Definition: disk.c:2532
static int purge_cfg_dir(void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg)
Helper function for GNUNET_DISK_purge_cfg_dir.
Definition: disk.c:2692
#define STRUCT_STAT64
Definition: plibc.h:731
struct GNUNET_DISK_FileHandle * GNUNET_DISK_get_handle_from_int_fd(int fno)
Get a handle from a native integer FD.
Definition: disk.c:1937
configuration data
Definition: configuration.c:85
int GNUNET_DISK_file_handle_size(struct GNUNET_DISK_FileHandle *fh, off_t *size)
Get the size of an open file.
Definition: disk.c:208
#define GNUNET_log(kind,...)
GNUNET_DISK_OpenFlags
Specifies how a file should be opened.
Handle represents an event.
Open the file for both reading and writing.
int GNUNET_DISK_file_change_owner(const char *filename, const char *user)
Change owner of a file.
Definition: disk.c:1525
int GNUNET_CONFIGURATION_get_value_filename(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be the name of a file or directory.
Write-able memory map.
void GNUNET_DISK_fix_permissions(const char *fn, int require_uid_match, int require_gid_match)
Update POSIX permissions mask of a file on disk.
Definition: disk.c:498
#define STAT64(p, b)
Definition: plibc.h:664
static char * mktemp_name(const char *t)
Create the name for a temporary file or directory from a template.
Definition: disk.c:397
#define GNUNET_YES
Definition: gnunet_common.h:80
int fd
File handle on other OSes.
Fail if file already exists.
ssize_t GNUNET_DISK_file_read_non_blocking(const struct GNUNET_DISK_FileHandle *h, void *result, size_t len)
Read the contents of a binary file into a buffer.
Definition: disk.c:941
struct GNUNET_DISK_FileHandle * GNUNET_DISK_get_handle_from_native(FILE *fd)
Get a handle from a native streaming FD.
Definition: disk.c:1970
#define DIR_SEPARATOR_STR
Definition: plibc.h:632
struct GNUNET_DISK_FileHandle * GNUNET_DISK_file_open(const char *fn, enum GNUNET_DISK_OpenFlags flags, enum GNUNET_DISK_AccessPermissions perm)
Open a file.
Definition: disk.c:1673
GNUNET_DISK_PipeEnd
Enumeration identifying the two ends of a pipe.
#define ACCESS(p, m)
Definition: plibc.h:656
Handle used to access files (and pipes).
Handle used to manage a pipe.
Definition: disk.c:66
int GNUNET_CONFIGURATION_parse_and_run(const char *filename, GNUNET_CONFIGURATION_Callback cb, void *cb_cls)
Parse a configuration file filename and run the function cb with the resulting configuration object...
#define GNUNET_malloc(size)
Wrapper around malloc.
ssize_t GNUNET_DISK_fn_read(const char *fn, void *result, size_t len)
Read the contents of a binary file into a buffer.
Definition: disk.c:1019
void GNUNET_DISK_filename_canonicalize(char *fn)
Removes special characters as &#39;:&#39; from a filename.
Definition: disk.c:1497
static enum @11 mode
Should we do a PUT (mode = 0) or GET (mode = 1);.
Handle for a memory-mapping operation.
Definition: disk.c:1985
Internal DISK related helper functions.
#define GNUNET_free(ptr)
Wrapper around free.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...