source: trunk/libtransmission/file-posix.c

Last change on this file was 14640, checked in by mikedld, 5 years ago

Get rid of some more warnings

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