disk.c 34 KB

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