source: trunk/libtransmission/file-posix.c @ 14527

Last change on this file since 14527 was 14527, checked in by mikedld, 6 years ago

Fix some issues revealed by coverity

  • Property svn:keywords set to Date Rev Author Id
File size: 21.4 KB
Line 
1/*
2 * This file Copyright (C) 2013-2014 Mnemosyne LLC
3 *
4 * It may be used under the GNU GPL versions 2 or 3
5 * or any future license endorsed by Mnemosyne LLC.
6 *
7 * $Id: file-posix.c 14527 2015-05-09 14:09:05Z mikedld $
8 */
9
10#if defined (HAVE_MKDTEMP) && (!defined (_XOPEN_SOURCE) || _XOPEN_SOURCE < 700)
11 #undef _XOPEN_SOURCE
12 #define _XOPEN_SOURCE 700
13#elif (defined (HAVE_POSIX_FADVISE) || defined (HAVE_POSIX_FALLOCATE)) && (!defined (_XOPEN_SOURCE) || _XOPEN_SOURCE < 600)
14 #undef _XOPEN_SOURCE
15 #define _XOPEN_SOURCE 600
16#endif
17
18#if (defined (HAVE_FALLOCATE64) || defined (HAVE_CANONICALIZE_FILE_NAME)) && !defined (_GNU_SOURCE)
19 #define _GNU_SOURCE
20#endif
21
22#if defined (__APPLE__) && !defined (_DARWIN_C_SOURCE)
23 #define _DARWIN_C_SOURCE
24#endif
25
26#include <assert.h>
27#include <dirent.h>
28#include <errno.h>
29#include <fcntl.h> /* O_LARGEFILE, posix_fadvise (), [posix_]fallocate () */
30#include <libgen.h> /* basename (), dirname () */
31#include <limits.h> /* PATH_MAX */
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <sys/mman.h> /* mmap (), munmap () */
36#include <sys/types.h>
37#include <sys/stat.h>
38#include <unistd.h> /* lseek (), write (), ftruncate (), pread (), pwrite (), pathconf (), etc */
39
40#ifdef HAVE_XFS_XFS_H
41 #include <xfs/xfs.h>
42#endif
43
44#include "transmission.h"
45#include "error.h"
46#include "file.h"
47#include "log.h"
48#include "platform.h"
49#include "utils.h"
50
51#ifndef O_LARGEFILE
52 #define O_LARGEFILE 0
53#endif
54#ifndef O_BINARY
55 #define O_BINARY 0
56#endif
57#ifndef O_SEQUENTIAL
58 #define O_SEQUENTIAL 0
59#endif
60#ifndef O_CLOEXEC
61 #define O_CLOEXEC 0
62#endif
63
64#ifndef PATH_MAX
65 #define PATH_MAX 4096
66#endif
67
68/* don't use pread/pwrite on old versions of uClibc because they're buggy.
69 * https://trac.transmissionbt.com/ticket/3826 */
70#ifdef __UCLIBC__
71#define TR_UCLIBC_CHECK_VERSION(major,minor,micro) \
72  (__UCLIBC_MAJOR__ > (major) || \
73   (__UCLIBC_MAJOR__ == (major) && __UCLIBC_MINOR__ > (minor)) || \
74   (__UCLIBC_MAJOR__ == (major) && __UCLIBC_MINOR__ == (minor) && \
75      __UCLIBC_SUBLEVEL__ >= (micro)))
76#if !TR_UCLIBC_CHECK_VERSION (0,9,28)
77 #undef HAVE_PREAD
78 #undef HAVE_PWRITE
79#endif
80#endif
81
82#ifdef __APPLE__
83 #ifndef HAVE_PREAD
84  #define HAVE_PREAD
85 #endif
86 #ifndef HAVE_PWRITE
87  #define HAVE_PWRITE
88 #endif
89 #ifndef HAVE_MKDTEMP
90  #define HAVE_MKDTEMP
91 #endif
92#endif
93
94static void
95set_system_error (tr_error ** error,
96                  int         code)
97{
98  if (error == NULL)
99    return;
100
101  tr_error_set_literal (error, code, tr_strerror (code));
102}
103
104static void
105set_system_error_if_file_found (tr_error ** error,
106                                int         code)
107{
108  if (code != ENOENT)
109    set_system_error (error, code);
110}
111
112static void
113stat_to_sys_path_info (const struct stat * sb,
114                       tr_sys_path_info  * info)
115{
116  if (S_ISREG (sb->st_mode))
117    info->type = TR_SYS_PATH_IS_FILE;
118  else if (S_ISDIR (sb->st_mode))
119    info->type = TR_SYS_PATH_IS_DIRECTORY;
120  else
121    info->type = TR_SYS_PATH_IS_OTHER;
122
123  info->size = (uint64_t) sb->st_size;
124  info->last_modified_at = sb->st_mtime;
125}
126
127static void
128set_file_for_single_pass (tr_sys_file_t handle)
129{
130  /* Set hints about the lookahead buffer and caching. It's okay
131     for these to fail silently, so don't let them affect errno */
132
133  const int err = errno;
134
135  if (handle == TR_BAD_SYS_FILE)
136    return;
137
138#ifdef HAVE_POSIX_FADVISE
139
140  (void) posix_fadvise (handle, 0, 0, POSIX_FADV_SEQUENTIAL);
141
142#endif
143
144#ifdef __APPLE__
145
146  (void) fcntl (handle, F_RDAHEAD, 1);
147  (void) fcntl (handle, F_NOCACHE, 1);
148
149#endif
150
151  errno = err;
152}
153
154#ifndef HAVE_MKDIRP
155
156static bool
157create_path (const char  * path_in,
158             int           permissions,
159             tr_error   ** error)
160{
161  char * p;
162  char * pp;
163  bool done;
164  int tmperr;
165  int rv;
166  struct stat sb;
167  char * path;
168
169  /* make a temporary copy of path */
170  path = tr_strdup (path_in);
171
172  /* walk past the root */
173  p = path;
174  while (*p == TR_PATH_DELIMITER)
175    ++p;
176
177  pp = p;
178  done = false;
179  while ((p = strchr (pp, TR_PATH_DELIMITER)) || (p = strchr (pp, '\0')))
180    {
181      if (!*p)
182        done = true;
183      else
184        *p = '\0';
185
186      tmperr = errno;
187      rv = stat (path, &sb);
188      errno = tmperr;
189      if (rv)
190        {
191          tr_error * my_error = NULL;
192
193          /* Folder doesn't exist yet */
194          if (!tr_sys_dir_create (path, 0, permissions, &my_error))
195            {
196              tr_logAddError (_ ("Couldn't create \"%1$s\": %2$s"), path, my_error->message);
197              tr_free (path);
198              tr_error_propagate (error, &my_error);
199              return false;
200            }
201        }
202      else if ((sb.st_mode & S_IFMT) != S_IFDIR)
203        {
204          /* Node exists but isn't a folder */
205          char * const buf = tr_strdup_printf (_ ("File \"%s\" is in the way"), path);
206          tr_logAddError (_ ("Couldn't create \"%1$s\": %2$s"), path_in, buf);
207          tr_free (buf);
208          tr_free (path);
209          set_system_error (error, ENOTDIR);
210          return false;
211        }
212
213      if (done)
214        break;
215
216      *p = TR_PATH_DELIMITER;
217      p++;
218      pp = p;
219    }
220
221  tr_free (path);
222  return true;
223}
224
225#endif
226
227bool
228tr_sys_path_exists (const char  * path,
229                    tr_error   ** error)
230{
231  bool ret;
232
233  assert (path != NULL);
234
235  ret = access (path, F_OK) != -1;
236
237  if (!ret)
238    set_system_error_if_file_found (error, errno);
239
240  return ret;
241}
242
243bool
244tr_sys_path_get_info (const char        * path,
245                      int                 flags,
246                      tr_sys_path_info  * info,
247                      tr_error         ** error)
248{
249  bool ret;
250  struct stat sb;
251
252  assert (path != NULL);
253  assert (info != NULL);
254
255  if ((flags & TR_SYS_PATH_NO_FOLLOW) == 0)
256    ret = stat (path, &sb) != -1;
257  else
258    ret = lstat (path, &sb) != -1;
259
260  if (ret)
261    stat_to_sys_path_info (&sb, info);
262  else
263    set_system_error (error, errno);
264
265  return ret;
266}
267
268bool
269tr_sys_path_is_same (const char  * path1,
270                     const char  * path2,
271                     tr_error   ** error)
272{
273  bool ret = false;
274  struct stat sb1, sb2;
275
276  assert (path1 != NULL);
277  assert (path2 != NULL);
278
279  if (stat (path1, &sb1) != -1 && stat (path2, &sb2) != -1)
280    ret = sb1.st_dev == sb2.st_dev && sb1.st_ino == sb2.st_ino;
281  else
282    set_system_error_if_file_found (error, errno);
283
284  return ret;
285}
286
287char *
288tr_sys_path_resolve (const char  * path,
289                     tr_error   ** error)
290{
291  char * ret = NULL;
292  char * tmp = NULL;
293
294  assert (path != NULL);
295
296#if defined (HAVE_CANONICALIZE_FILE_NAME)
297
298  ret = canonicalize_file_name (path);
299
300#endif
301
302#if defined (_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200809L
303
304  /* Better safe than sorry: realpath () officially supports NULL as destination
305     starting off POSIX.1-2008. */
306
307  if (ret == NULL)
308    ret = realpath (path, NULL);
309
310#endif
311
312  if (ret == NULL)
313    {
314      tmp = tr_new (char, PATH_MAX);
315      ret = realpath (path, tmp);
316      if (ret != NULL)
317        ret = tr_strdup (ret);
318    }
319
320  if (ret == NULL)
321    set_system_error (error, errno);
322
323  tr_free (tmp);
324
325  return ret;
326}
327
328char *
329tr_sys_path_basename (const char  * path,
330                      tr_error   ** error)
331{
332  char * ret = NULL;
333  char * tmp;
334
335  assert (path != NULL);
336
337  tmp = tr_strdup (path);
338  ret = basename (tmp);
339  if (ret != NULL)
340    ret = tr_strdup (ret);
341  else
342    set_system_error (error, errno);
343
344  tr_free (tmp);
345
346  return ret;
347}
348
349char *
350tr_sys_path_dirname (const char  * path,
351                     tr_error   ** error)
352{
353  char * ret = NULL;
354  char * tmp;
355
356  assert (path != NULL);
357
358  tmp = tr_strdup (path);
359  ret = dirname (tmp);
360  if (ret != NULL)
361    ret = tr_strdup (ret);
362  else
363    set_system_error (error, errno);
364
365  tr_free (tmp);
366
367  return ret;
368}
369
370bool
371tr_sys_path_rename (const char  * src_path,
372                    const char  * dst_path,
373                    tr_error   ** error)
374{
375  bool ret;
376
377  assert (src_path != NULL);
378  assert (dst_path != NULL);
379
380  ret = rename (src_path, dst_path) != -1;
381
382  if (!ret)
383    set_system_error (error, errno);
384
385  return ret;
386}
387
388bool
389tr_sys_path_remove (const char  * path,
390                    tr_error   ** error)
391{
392  bool ret;
393
394  assert (path != NULL);
395
396  ret = remove (path) != -1;
397
398  if (!ret)
399    set_system_error (error, errno);
400
401  return ret;
402}
403
404tr_sys_file_t
405tr_sys_file_get_std (tr_std_sys_file_t    std_file,
406                     tr_error          ** error)
407{
408  tr_sys_file_t ret = TR_BAD_SYS_FILE;
409
410  switch (std_file)
411    {
412    case TR_STD_SYS_FILE_IN:
413      ret = STDIN_FILENO;
414      break;
415    case TR_STD_SYS_FILE_OUT:
416      ret = STDOUT_FILENO;
417      break;
418    case TR_STD_SYS_FILE_ERR:
419      ret = STDERR_FILENO;
420      break;
421    default:
422      assert (0 && "Unknown standard file");
423      set_system_error (error, EINVAL);
424    }
425
426  return ret;
427}
428
429tr_sys_file_t
430tr_sys_file_open (const char  * path,
431                  int           flags,
432                  int           permissions,
433                  tr_error   ** error)
434{
435  tr_sys_file_t ret;
436  int native_flags = 0;
437
438  assert (path != NULL);
439  assert ((flags & (TR_SYS_FILE_READ | TR_SYS_FILE_WRITE)) != 0);
440
441  if ((flags & (TR_SYS_FILE_READ | TR_SYS_FILE_WRITE)) == (TR_SYS_FILE_READ | TR_SYS_FILE_WRITE))
442    native_flags |= O_RDWR;
443  else if (flags & TR_SYS_FILE_READ)
444    native_flags |= O_RDONLY;
445  else if (flags & TR_SYS_FILE_WRITE)
446    native_flags |= O_WRONLY;
447
448  native_flags |=
449    (flags & TR_SYS_FILE_CREATE ? O_CREAT : 0) |
450    (flags & TR_SYS_FILE_CREATE_NEW ? O_CREAT | O_EXCL : 0) |
451    (flags & TR_SYS_FILE_APPEND ? O_APPEND : 0) |
452    (flags & TR_SYS_FILE_TRUNCATE ? O_TRUNC : 0) |
453    (flags & TR_SYS_FILE_SEQUENTIAL ? O_SEQUENTIAL : 0) |
454    O_BINARY | O_LARGEFILE | O_CLOEXEC;
455
456  ret = open (path, native_flags, permissions);
457
458  if (ret != TR_BAD_SYS_FILE)
459    {
460      if (flags & TR_SYS_FILE_SEQUENTIAL)
461        set_file_for_single_pass (ret);
462    }
463  else
464    {
465      set_system_error (error, errno);
466    }
467
468  return ret;
469}
470
471tr_sys_file_t
472tr_sys_file_open_temp (char      * path_template,
473                       tr_error ** error)
474{
475  tr_sys_file_t ret;
476
477  assert (path_template != NULL);
478
479  ret = mkstemp (path_template);
480
481  if (ret == TR_BAD_SYS_FILE)
482    set_system_error (error, errno);
483
484  set_file_for_single_pass (ret);
485
486  return ret;
487}
488
489bool
490tr_sys_file_close (tr_sys_file_t    handle,
491                   tr_error      ** error)
492{
493  bool ret;
494
495  assert (handle != TR_BAD_SYS_FILE);
496
497  ret = close (handle) != -1;
498
499  if (!ret)
500    set_system_error (error, errno);
501
502  return ret;
503}
504
505bool
506tr_sys_file_get_info (tr_sys_file_t       handle,
507                      tr_sys_path_info  * info,
508                      tr_error         ** error)
509{
510  bool ret;
511  struct stat sb;
512
513  assert (handle != TR_BAD_SYS_FILE);
514  assert (info != NULL);
515
516  ret = fstat (handle, &sb) != -1;
517
518  if (ret)
519    stat_to_sys_path_info (&sb, info);
520  else
521    set_system_error (error, errno);
522
523  return ret;
524}
525
526bool
527tr_sys_file_seek (tr_sys_file_t       handle,
528                  int64_t             offset,
529                  tr_seek_origin_t    origin,
530                  uint64_t          * new_offset,
531                  tr_error         ** error)
532{
533  bool ret = false;
534  off_t my_new_offset;
535
536  TR_STATIC_ASSERT (TR_SEEK_SET == SEEK_SET, "values should match");
537  TR_STATIC_ASSERT (TR_SEEK_CUR == SEEK_CUR, "values should match");
538  TR_STATIC_ASSERT (TR_SEEK_END == SEEK_END, "values should match");
539
540  TR_STATIC_ASSERT (sizeof (*new_offset) >= sizeof (my_new_offset), "");
541
542  assert (handle != TR_BAD_SYS_FILE);
543  assert (origin == TR_SEEK_SET || origin == TR_SEEK_CUR || origin == TR_SEEK_END);
544
545  my_new_offset = lseek (handle, offset, origin);
546
547  if (my_new_offset != -1)
548    {
549      if (new_offset != NULL)
550        *new_offset = my_new_offset;
551      ret = true;
552    }
553  else
554    {
555      set_system_error (error, errno);
556    }
557
558  return ret;
559}
560
561bool
562tr_sys_file_read (tr_sys_file_t    handle,
563                  void           * buffer,
564                  uint64_t         size,
565                  uint64_t       * bytes_read,
566                  tr_error      ** error)
567{
568  bool ret = false;
569  ssize_t my_bytes_read;
570
571  TR_STATIC_ASSERT (sizeof (*bytes_read) >= sizeof (my_bytes_read), "");
572
573  assert (handle != TR_BAD_SYS_FILE);
574  assert (buffer != NULL || size == 0);
575
576  my_bytes_read = read (handle, buffer, size);
577
578  if (my_bytes_read != -1)
579    {
580      if (bytes_read != NULL)
581        *bytes_read = my_bytes_read;
582      ret = true;
583    }
584  else
585    {
586      set_system_error (error, errno);
587    }
588
589  return ret;
590}
591
592bool
593tr_sys_file_read_at (tr_sys_file_t    handle,
594                     void           * buffer,
595                     uint64_t         size,
596                     uint64_t         offset,
597                     uint64_t       * bytes_read,
598                     tr_error      ** error)
599{
600  bool ret = false;
601  ssize_t my_bytes_read;
602
603  TR_STATIC_ASSERT (sizeof (*bytes_read) >= sizeof (my_bytes_read), "");
604
605  assert (handle != TR_BAD_SYS_FILE);
606  assert (buffer != NULL || size == 0);
607  /* seek requires signed offset, so it should be in mod range */
608  assert (offset < UINT64_MAX / 2);
609
610#ifdef HAVE_PREAD
611
612  my_bytes_read = pread (handle, buffer, size, offset);
613
614#else
615
616  if (lseek (handle, offset, SEEK_SET) != -1)
617    my_bytes_read = read (handle, buffer, size);
618  else
619    my_bytes_read = -1;
620
621#endif
622
623  if (my_bytes_read != -1)
624    {
625      if (bytes_read != NULL)
626        *bytes_read = my_bytes_read;
627      ret = true;
628    }
629  else
630    {
631      set_system_error (error, errno);
632    }
633
634  return ret;
635}
636
637bool
638tr_sys_file_write (tr_sys_file_t    handle,
639                   const void     * buffer,
640                   uint64_t         size,
641                   uint64_t       * bytes_written,
642                   tr_error      ** error)
643{
644  bool ret = false;
645  ssize_t my_bytes_written;
646
647  TR_STATIC_ASSERT (sizeof (*bytes_written) >= sizeof (my_bytes_written), "");
648
649  assert (handle != TR_BAD_SYS_FILE);
650  assert (buffer != NULL || size == 0);
651
652  my_bytes_written = write (handle, buffer, size);
653
654  if (my_bytes_written != -1)
655    {
656      if (bytes_written != NULL)
657        *bytes_written = my_bytes_written;
658      ret = true;
659    }
660  else
661    {
662      set_system_error (error, errno);
663    }
664
665  return ret;
666}
667
668bool
669tr_sys_file_write_at (tr_sys_file_t    handle,
670                      const void     * buffer,
671                      uint64_t         size,
672                      uint64_t         offset,
673                      uint64_t       * bytes_written,
674                      tr_error      ** error)
675{
676  bool ret = false;
677  ssize_t my_bytes_written;
678
679  TR_STATIC_ASSERT (sizeof (*bytes_written) >= sizeof (my_bytes_written), "");
680
681  assert (handle != TR_BAD_SYS_FILE);
682  assert (buffer != NULL || size == 0);
683  /* seek requires signed offset, so it should be in mod range */
684  assert (offset < UINT64_MAX / 2);
685
686#ifdef HAVE_PWRITE
687
688  my_bytes_written = pwrite (handle, buffer, size, offset);
689
690#else
691
692  if (lseek (handle, offset, SEEK_SET) != -1)
693    my_bytes_written = write (handle, buffer, size);
694  else
695    my_bytes_written = -1;
696
697#endif
698
699  if (my_bytes_written != -1)
700    {
701      if (bytes_written != NULL)
702        *bytes_written = my_bytes_written;
703      ret = true;
704    }
705  else
706    {
707      set_system_error (error, errno);
708    }
709
710  return ret;
711}
712
713bool
714tr_sys_file_flush (tr_sys_file_t    handle,
715                   tr_error      ** error)
716{
717  bool ret;
718
719  assert (handle != TR_BAD_SYS_FILE);
720
721  ret = fsync (handle) != -1;
722
723  if (!ret)
724    set_system_error (error, errno);
725
726  return ret;
727}
728
729bool
730tr_sys_file_truncate (tr_sys_file_t    handle,
731                      uint64_t         size,
732                      tr_error      ** error)
733{
734  bool ret;
735
736  assert (handle != TR_BAD_SYS_FILE);
737
738  ret = ftruncate (handle, size) != -1;
739
740  if (!ret)
741    set_system_error (error, errno);
742
743  return ret;
744}
745
746bool
747tr_sys_file_prefetch (tr_sys_file_t    handle,
748                      uint64_t         offset,
749                      uint64_t         size,
750                      tr_error      ** error)
751{
752  bool ret = false;
753
754#if defined (HAVE_POSIX_FADVISE)
755
756  int code;
757
758  assert (handle != TR_BAD_SYS_FILE);
759  assert (size > 0);
760
761  code = posix_fadvise (handle, offset, size, POSIX_FADV_WILLNEED);
762
763  if (code == 0)
764    ret = true;
765  else
766    set_system_error (error, code);
767
768#elif defined (__APPLE__)
769
770  struct radvisory radv;
771
772  assert (handle != TR_BAD_SYS_FILE);
773  assert (size > 0);
774
775  radv.ra_offset = offset;
776  radv.ra_count = size;
777
778  ret = fcntl (handle, F_RDADVISE, &radv) != -1;
779
780  if (!ret)
781    set_system_error (error, errno);
782
783#endif
784
785  return ret;
786}
787
788bool
789tr_sys_file_preallocate (tr_sys_file_t    handle,
790                         uint64_t         size,
791                         int              flags,
792                         tr_error      ** error)
793{
794  bool ret = false;
795
796  assert (handle != TR_BAD_SYS_FILE);
797
798  errno = 0;
799
800#ifdef HAVE_FALLOCATE64
801
802  /* fallocate64 is always preferred, so try it first */
803  ret = fallocate64 (handle, 0, 0, size) != -1;
804
805  if (ret || errno == ENOSPC)
806    goto out;
807
808#endif
809
810  if ((flags & TR_SYS_FILE_PREALLOC_SPARSE) == 0)
811    {
812      int code = errno;
813
814#ifdef HAVE_XFS_XFS_H
815
816      if (platform_test_xfs_fd (handle))
817        {
818          xfs_flock64_t fl;
819
820          fl.l_whence = 0;
821          fl.l_start = 0;
822          fl.l_len = size;
823
824          ret = xfsctl (NULL, handle, XFS_IOC_RESVSP64, &fl) != -1;
825
826          if (ret)
827            ret = ftruncate (handle, size) != -1;
828
829          code = errno;
830
831          if (ret || code == ENOSPC)
832            goto non_sparse_out;
833        }
834
835#endif
836
837#ifdef __APPLE__
838
839      {
840        fstore_t fst;
841
842        fst.fst_flags = F_ALLOCATEALL;
843        fst.fst_posmode = F_PEOFPOSMODE;
844        fst.fst_offset = 0;
845        fst.fst_length = size;
846        fst.fst_bytesalloc = 0;
847
848        ret = fcntl (handle, F_PREALLOCATE, &fst) != -1;
849
850        if (ret)
851          ret = ftruncate (handle, size) != -1;
852
853        code = errno;
854
855        if (ret || code == ENOSPC)
856          goto non_sparse_out;
857      }
858
859#endif
860
861#ifdef HAVE_POSIX_FALLOCATE
862
863      code = posix_fallocate (handle, 0, size);
864      ret = code == 0;
865
866#endif
867
868non_sparse_out:
869      errno = code;
870    }
871
872out:
873  if (!ret)
874    set_system_error (error, errno);
875
876  return ret;
877}
878
879void *
880tr_sys_file_map_for_reading (tr_sys_file_t    handle,
881                             uint64_t         offset,
882                             uint64_t         size,
883                             tr_error      ** error)
884{
885  void * ret;
886
887  assert (handle != TR_BAD_SYS_FILE);
888  assert (size > 0);
889
890  ret = mmap (NULL, size, PROT_READ, MAP_SHARED, handle, offset);
891
892  if (ret == MAP_FAILED)
893    {
894      set_system_error (error, errno);
895      ret = NULL;
896    }
897
898  return ret;
899}
900
901bool
902tr_sys_file_unmap (const void  * address,
903                   uint64_t      size,
904                   tr_error   ** error)
905{
906  bool ret;
907
908  assert (address != NULL);
909  assert (size > 0);
910
911  ret = munmap ((void *) address, size) != -1;
912
913  if (!ret)
914    set_system_error (error, errno);
915
916  return ret;
917}
918
919char *
920tr_sys_dir_get_current (tr_error ** error)
921{
922  char * ret;
923
924  ret = getcwd (NULL, 0);
925
926  if (ret == NULL && (errno == EINVAL || errno == ERANGE))
927    {
928      size_t size = PATH_MAX;
929      char * tmp = NULL;
930
931      do
932        {
933          tmp = tr_renew (char, tmp, size);
934          if (tmp == NULL)
935            break;
936          ret = getcwd (tmp, size);
937          size += 2048;
938        }
939      while (ret == NULL && errno == ERANGE);
940
941      if (ret == NULL)
942        {
943          const int err = errno;
944          tr_free (tmp);
945          errno = err;
946        }
947    }
948
949  if (ret == NULL)
950    set_system_error (error, errno);
951
952  return ret;
953}
954
955bool
956tr_sys_dir_create (const char  * path,
957                   int           flags,
958                   int           permissions,
959                   tr_error   ** error)
960{
961  bool ret;
962  tr_error * my_error = NULL;
963
964  assert (path != NULL);
965
966  if ((flags & TR_SYS_DIR_CREATE_PARENTS) != 0)
967#ifdef HAVE_MKDIRP
968    ret = mkdirp (path, permissions) != -1;
969#else
970    ret = create_path (path, permissions, &my_error);
971#endif
972  else
973    ret = mkdir (path, permissions) != -1;
974
975  if (!ret && errno == EEXIST)
976    {
977      struct stat sb;
978
979      if (stat (path, &sb) != -1 && S_ISDIR (sb.st_mode))
980        {
981          tr_error_clear (&my_error);
982          ret = true;
983        }
984      else
985        {
986          errno = EEXIST;
987        }
988    }
989
990  if (!ret)
991    {
992      if (my_error != NULL)
993        tr_error_propagate (error, &my_error);
994      else
995        set_system_error (error, errno);
996    }
997
998  return ret;
999}
1000
1001bool
1002tr_sys_dir_create_temp (char      * path_template,
1003                        tr_error ** error)
1004{
1005  bool ret;
1006
1007  assert (path_template != NULL);
1008
1009#ifdef HAVE_MKDTEMP
1010
1011  ret = mkdtemp (path_template) != NULL;
1012
1013#else
1014
1015  ret = mktemp (path_template) != NULL && mkdir (path_template, 0700) != -1;
1016
1017#endif
1018
1019  if (!ret)
1020    set_system_error (error, errno);
1021
1022  return ret;
1023}
1024
1025tr_sys_dir_t
1026tr_sys_dir_open (const char  * path,
1027                 tr_error   ** error)
1028{
1029  tr_sys_dir_t ret;
1030
1031#ifndef __clang__
1032  /* Clang gives "static_assert expression is not an integral constant expression" error */
1033  TR_STATIC_ASSERT (TR_BAD_SYS_DIR == NULL, "values should match");
1034#endif
1035
1036  assert (path != NULL);
1037
1038  ret = opendir (path);
1039
1040  if (ret == TR_BAD_SYS_DIR)
1041    set_system_error (error, errno);
1042
1043  return ret;
1044}
1045
1046const char *
1047tr_sys_dir_read_name (tr_sys_dir_t    handle,
1048                      tr_error     ** error)
1049{
1050  const char * ret = NULL;
1051  struct dirent * entry;
1052
1053  assert (handle != TR_BAD_SYS_DIR);
1054
1055  errno = 0;
1056  entry = readdir (handle);
1057
1058  if (entry != NULL)
1059    ret = entry->d_name;
1060  else if (errno != 0)
1061    set_system_error (error, errno);
1062
1063  return ret;
1064}
1065
1066bool
1067tr_sys_dir_close (tr_sys_dir_t    handle,
1068                  tr_error     ** error)
1069{
1070  bool ret;
1071
1072  assert (handle != TR_BAD_SYS_DIR);
1073
1074  ret = closedir (handle) != -1;
1075
1076  if (!ret)
1077    set_system_error (error, errno);
1078
1079  return ret;
1080}
Note: See TracBrowser for help on using the repository browser.