1 /*
2  * This file Copyright (C) 2013-2017 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  */
8 
9 #pragma once
10 
11 #include <inttypes.h>
12 #include <time.h>
13 
14 #ifdef _WIN32
15 #include <windows.h>
16 #endif
17 
18 #ifdef __cplusplus
19 extern "C"
20 {
21 #endif
22 
23 struct tr_error;
24 
25 /**
26  * @addtogroup file_io File IO
27  * @{
28  */
29 
30 #ifndef _WIN32
31 
32 /** @brief Platform-specific file descriptor type. */
33 typedef int tr_sys_file_t;
34 /** @brief Platform-specific invalid file descriptor constant. */
35 #define TR_BAD_SYS_FILE (-1)
36 /** @brief Platform-specific directory descriptor type. */
37 typedef void* tr_sys_dir_t;
38 /** @brief Platform-specific end-of-line sequence. */
39 #define TR_NATIVE_EOL_STR "\n"
40 /** @brief Platform-specific end-of-line sequence length. */
41 #define TR_NATIVE_EOL_STR_SIZE 1
42 
43 #else
44 
45 typedef HANDLE tr_sys_file_t;
46 #define TR_BAD_SYS_FILE INVALID_HANDLE_VALUE
47 typedef struct tr_sys_dir_win32* tr_sys_dir_t;
48 #define TR_NATIVE_EOL_STR "\r\n"
49 #define TR_NATIVE_EOL_STR_SIZE 2
50 
51 #endif
52 
53 /** @brief Platform-specific invalid directory descriptor constant. */
54 #define TR_BAD_SYS_DIR ((tr_sys_dir_t)NULL)
55 
56 typedef enum
57 {
58     TR_STD_SYS_FILE_IN,
59     TR_STD_SYS_FILE_OUT,
60     TR_STD_SYS_FILE_ERR
61 }
62 tr_std_sys_file_t;
63 
64 typedef enum
65 {
66     TR_SYS_FILE_READ = (1 << 0),
67     TR_SYS_FILE_WRITE = (1 << 1),
68     TR_SYS_FILE_CREATE = (1 << 2),
69     TR_SYS_FILE_CREATE_NEW = (1 << 3),
70     TR_SYS_FILE_APPEND = (1 << 4),
71     TR_SYS_FILE_TRUNCATE = (1 << 5),
72     TR_SYS_FILE_SEQUENTIAL = (1 << 6)
73 }
74 tr_sys_file_open_flags_t;
75 
76 typedef enum
77 {
78     TR_SEEK_SET,
79     TR_SEEK_CUR,
80     TR_SEEK_END
81 }
82 tr_seek_origin_t;
83 
84 typedef enum
85 {
86     TR_SYS_FILE_LOCK_SH = (1 << 0),
87     TR_SYS_FILE_LOCK_EX = (1 << 1),
88     TR_SYS_FILE_LOCK_NB = (1 << 2),
89     TR_SYS_FILE_LOCK_UN = (1 << 3)
90 }
91 tr_sys_file_lock_flags_t;
92 
93 typedef enum
94 {
95     TR_SYS_PATH_NO_FOLLOW = (1 << 0)
96 }
97 tr_sys_path_get_info_flags_t;
98 
99 typedef enum
100 {
101     TR_SYS_FILE_ADVICE_WILL_NEED,
102     TR_SYS_FILE_ADVICE_DONT_NEED
103 }
104 tr_sys_file_advice_t;
105 
106 typedef enum
107 {
108     TR_SYS_FILE_PREALLOC_SPARSE = (1 << 0)
109 }
110 tr_sys_file_preallocate_flags_t;
111 
112 typedef enum
113 {
114     TR_SYS_DIR_CREATE_PARENTS = (1 << 0)
115 }
116 tr_sys_dir_create_flags_t;
117 
118 typedef enum
119 {
120     TR_SYS_PATH_IS_FILE,
121     TR_SYS_PATH_IS_DIRECTORY,
122     TR_SYS_PATH_IS_OTHER
123 }
124 tr_sys_path_type_t;
125 
126 typedef struct tr_sys_path_info
127 {
128     tr_sys_path_type_t type;
129     uint64_t size;
130     time_t last_modified_at;
131 }
132 tr_sys_path_info;
133 
134 /**
135  * @name Platform-specific wrapper functions
136  *
137  * Following functions accept paths in UTF-8 encoding and convert them to native
138  * encoding internally if needed.
139  * Descriptors returned (@ref tr_sys_file_t and @ref tr_sys_dir_t) may have
140  * different type depending on platform and should generally not be passed to
141  * native functions, but to wrapper functions instead.
142  *
143  * @{
144  */
145 
146 /* Path-related wrappers */
147 
148 /**
149  * @brief Portability wrapper for `stat()`.
150  *
151  * @param[in]  path  Path to file or directory.
152  * @param[in]  flags Combination of @ref tr_sys_path_get_info_flags_t values.
153  * @param[out] info  Result buffer.
154  * @param[out] error Pointer to error object. Optional, pass `NULL` if you are
155  *                   not interested in error details.
156  *
157  * @return `True` on success, `false` otherwise (with `error` set accordingly).
158  */
159 bool tr_sys_path_get_info(char const* path, int flags, tr_sys_path_info* info, struct tr_error** error);
160 
161 /**
162  * @brief Portability wrapper for `access()`.
163  *
164  * @param[in]  path  Path to file or directory.
165  * @param[out] error Pointer to error object. Optional, pass `NULL` if you are
166  *                   not interested in error details.
167  *
168  * @return `True` if path exists, `false` otherwise. Note that `false` will also
169  *         be returned in case of error; if you need to distinguish the two,
170  *         check if `error` is `NULL` afterwards.
171  */
172 bool tr_sys_path_exists(char const* path, struct tr_error** error);
173 
174 /**
175  * @brief Check whether path is relative.
176  *
177  * This function only analyzes the string, so no error reporting is needed.
178  *
179  * @param[in] path Path to file or directory.
180  *
181  * @return `True` if path is relative, `false` otherwise
182  */
183 bool tr_sys_path_is_relative(char const* path);
184 
185 /**
186  * @brief Test to see if the two filenames point to the same file.
187  *
188  * @param[in]  path1  Path to first file or directory.
189  * @param[in]  path2  Path to second file or directory.
190  * @param[out] error Pointer to error object. Optional, pass `NULL` if you are
191  *                   not interested in error details.
192  *
193  * @return `True` if two paths point to the same file or directory, `false`
194  *         otherwise. Note that `false` will also be returned in case of error;
195  *         if you need to distinguish the two, check if `error` is `NULL`
196  *         afterwards.
197  */
198 bool tr_sys_path_is_same(char const* path1, char const* path2, struct tr_error** error);
199 
200 /**
201  * @brief Portability wrapper for `realpath()`.
202  *
203  * @param[in]  path  Path to file or directory.
204  * @param[out] error Pointer to error object. Optional, pass `NULL` if you are
205  *                   not interested in error details.
206  *
207  * @return Pointer to newly allocated buffer containing full path (with symbolic
208  *         links, `.` and `..` resolved) on success (use @ref tr_free to free it
209  *         when no longer needed), `NULL` otherwise (with `error` set
210  *         accordingly).
211  */
212 char* tr_sys_path_resolve(char const* path, struct tr_error** error);
213 
214 /**
215  * @brief Portability wrapper for `basename()`.
216  *
217  * @param[in]  path  Path to file or directory.
218  * @param[out] error Pointer to error object. Optional, pass `NULL` if you are
219  *                   not interested in error details.
220  *
221  * @return Pointer to newly allocated buffer containing base name (last path
222  *         component; parent path removed) on success (use @ref tr_free to free
223  *         it when no longer needed), `NULL` otherwise (with `error` set
224  *         accordingly).
225  */
226 char* tr_sys_path_basename(char const* path, struct tr_error** error);
227 
228 /**
229  * @brief Portability wrapper for `dirname()`.
230  *
231  * @param[in]  path  Path to file or directory.
232  * @param[out] error Pointer to error object. Optional, pass `NULL` if you are
233  *                   not interested in error details.
234  *
235  * @return Pointer to newly allocated buffer containing directory (parent path;
236  *         last path component removed) on success (use @ref tr_free to free it
237  *         when no longer needed), `NULL` otherwise (with `error` set
238  *         accordingly).
239  */
240 char* tr_sys_path_dirname(char const* path, struct tr_error** error);
241 
242 /**
243  * @brief Portability wrapper for `rename()`.
244  *
245  * @param[in]  src_path Path to source file or directory.
246  * @param[in]  dst_path Path to destination file or directory.
247  * @param[out] error    Pointer to error object. Optional, pass `NULL` if you
248  *                      are not interested in error details.
249  *
250  * @return `True` on success, `false` otherwise (with `error` set accordingly).
251  *         Rename will generally only succeed if both source and destination are
252  *         on the same partition.
253  */
254 bool tr_sys_path_rename(char const* src_path, char const* dst_path, struct tr_error** error);
255 
256 /**
257  * @brief Portability wrapper for `remove()`.
258  *
259  * @param[in]  path  Path to file or directory.
260  * @param[out] error Pointer to error object. Optional, pass `NULL` if you are
261  *                   not interested in error details.
262  *
263  * @return `True` on success, `false` otherwise (with `error` set accordingly).
264  *         Directory removal will only succeed if it is empty (contains no other
265  *         files and directories).
266  */
267 bool tr_sys_path_remove(char const* path, struct tr_error** error);
268 
269 /**
270  * @brief Transform path separators to native ones, in-place.
271  *
272  * @param[in,out] path Path to transform.
273  *
274  * @return Same path but with native (and uniform) separators.
275  */
276 char* tr_sys_path_native_separators(char* path);
277 
278 /* File-related wrappers */
279 
280 /**
281  * @brief Get handle to one of standard I/O files.
282  *
283  * @param[in]  std_file Standard file identifier.
284  * @param[out] error    Pointer to error object. Optional, pass `NULL` if you
285  *                      are not interested in error details.
286  *
287  * @return Opened file descriptor on success, `TR_BAD_SYS_FILE` otherwise (with
288  *         `error` set accordingly). DO NOT pass this descriptor to
289  *         @ref tr_sys_file_close (unless you know what you are doing).
290  */
291 tr_sys_file_t tr_sys_file_get_std(tr_std_sys_file_t std_file, struct tr_error** error);
292 
293 /**
294  * @brief Portability wrapper for `open()`.
295  *
296  * @param[in]  path        Path to file.
297  * @param[in]  flags       Combination of @ref tr_sys_file_open_flags_t values.
298  * @param[in]  permissions Permissions to create file with (in case
299                            @ref TR_SYS_FILE_CREATE is used). Not used on Windows.
300  * @param[out] error       Pointer to error object. Optional, pass `NULL` if you
301  *                         are not interested in error details.
302  *
303  * @return Opened file descriptor on success, `TR_BAD_SYS_FILE` otherwise (with
304  *         `error` set accordingly).
305  */
306 tr_sys_file_t tr_sys_file_open(char const* path, int flags, int permissions, struct tr_error** error);
307 
308 /**
309  * @brief Portability wrapper for `mkstemp()`.
310  *
311  * @param[in,out] path_template Template path to file. Should end with at least
312  *                              six 'X' characters. Upon success, trailing 'X'
313  *                              characters are replaced with actual random
314  *                              characters used to form a unique path to
315  *                              temporary file.
316  * @param[out]    error         Pointer to error object. Optional, pass `NULL`
317  *                              if you are not interested in error details.
318  *
319  * @return Opened file descriptor on success, `TR_BAD_SYS_FILE` otherwise (with
320  *         `error` set accordingly).
321  */
322 tr_sys_file_t tr_sys_file_open_temp(char* path_template, struct tr_error** error);
323 
324 /**
325  * @brief Portability wrapper for `close()`.
326  *
327  * @param[in]  handle Valid file descriptor.
328  * @param[out] error  Pointer to error object. Optional, pass `NULL` if you are
329  *                    not interested in error details.
330  *
331  * @return `True` on success, `false` otherwise (with `error` set accordingly).
332  */
333 bool tr_sys_file_close(tr_sys_file_t handle, struct tr_error** error);
334 
335 /**
336  * @brief Portability wrapper for `fstat()`.
337  *
338  * @param[in]  handle Valid file descriptor.
339  * @param[out] info   Result buffer.
340  * @param[out] error  Pointer to error object. Optional, pass `NULL` if you are
341  *                    not interested in error details.
342  *
343  * @return `True` on success, `false` otherwise (with `error` set accordingly).
344  */
345 bool tr_sys_file_get_info(tr_sys_file_t handle, tr_sys_path_info* info, struct tr_error** error);
346 
347 /**
348  * @brief Portability wrapper for `lseek()`.
349  *
350  * @param[in]  handle     Valid file descriptor.
351  * @param[in]  offset     Relative file offset in bytes to seek to.
352  * @param[in]  origin     Offset origin.
353  * @param[out] new_offset New offset in bytes from beginning of file. Optional,
354  *                        pass `NULL` if you are not interested.
355  * @param[out] error      Pointer to error object. Optional, pass `NULL` if you
356  *                        are not interested in error details.
357  *
358  * @return `True` on success, `false` otherwise (with `error` set accordingly).
359  */
360 bool tr_sys_file_seek(tr_sys_file_t handle, int64_t offset, tr_seek_origin_t origin, uint64_t* new_offset,
361     struct tr_error** error);
362 
363 /**
364  * @brief Portability wrapper for `read()`.
365  *
366  * @param[in]  handle     Valid file descriptor.
367  * @param[out] buffer     Buffer to store read data to.
368  * @param[in]  size       Number of bytes to read.
369  * @param[out] bytes_read Number of bytes actually read. Optional, pass `NULL`
370  *                        if you are not interested.
371  * @param[out] error      Pointer to error object. Optional, pass `NULL` if you
372  *                        are not interested in error details.
373  *
374  * @return `True` on success, `false` otherwise (with `error` set accordingly).
375  */
376 bool tr_sys_file_read(tr_sys_file_t handle, void* buffer, uint64_t size, uint64_t* bytes_read, struct tr_error** error);
377 
378 /**
379  * @brief Like `pread()`, except that the position is undefined afterwards.
380  *        Not thread-safe.
381  *
382  * @param[in]  handle     Valid file descriptor.
383  * @param[out] buffer     Buffer to store read data to.
384  * @param[in]  size       Number of bytes to read.
385  * @param[in]  offset     File offset in bytes to start reading from.
386  * @param[out] bytes_read Number of bytes actually read. Optional, pass `NULL`
387  *                        if you are not interested.
388  * @param[out] error      Pointer to error object. Optional, pass `NULL` if you
389  *                        are not interested in error details.
390  *
391  * @return `True` on success, `false` otherwise (with `error` set accordingly).
392  */
393 bool tr_sys_file_read_at(tr_sys_file_t handle, void* buffer, uint64_t size, uint64_t offset, uint64_t* bytes_read,
394     struct tr_error** error);
395 
396 /**
397  * @brief Portability wrapper for `write()`.
398  *
399  * @param[in]  handle        Valid file descriptor.
400  * @param[in]  buffer        Buffer to get data being written from.
401  * @param[in]  size          Number of bytes to write.
402  * @param[out] bytes_written Number of bytes actually written. Optional, pass
403  *                           `NULL` if you are not interested.
404  * @param[out] error         Pointer to error object. Optional, pass `NULL` if
405  *                           you are not interested in error details.
406  *
407  * @return `True` on success, `false` otherwise (with `error` set accordingly).
408  */
409 bool tr_sys_file_write(tr_sys_file_t handle, void const* buffer, uint64_t size, uint64_t* bytes_written,
410     struct tr_error** error);
411 
412 /**
413  * @brief Like `pwrite()`, except that the position is undefined afterwards.
414  *        Not thread-safe.
415  *
416  * @param[in]  handle        Valid file descriptor.
417  * @param[in]  buffer        Buffer to get data being written from.
418  * @param[in]  size          Number of bytes to write.
419  * @param[in]  offset        File offset in bytes to start writing from.
420  * @param[out] bytes_written Number of bytes actually written. Optional, pass
421  *                           `NULL` if you are not interested.
422  * @param[out] error         Pointer to error object. Optional, pass `NULL` if you
423  *                           are not interested in error details.
424  *
425  * @return `True` on success, `false` otherwise (with `error` set accordingly).
426  */
427 bool tr_sys_file_write_at(tr_sys_file_t handle, void const* buffer, uint64_t size, uint64_t offset, uint64_t* bytes_written,
428     struct tr_error** error);
429 
430 /**
431  * @brief Portability wrapper for `fsync()`.
432  *
433  * @param[in]  handle Valid file descriptor.
434  * @param[out] error  Pointer to error object. Optional, pass `NULL` if you are
435  *                    not interested in error details.
436  *
437  * @return `True` on success, `false` otherwise (with `error` set accordingly).
438  */
439 bool tr_sys_file_flush(tr_sys_file_t handle, struct tr_error** error);
440 
441 /**
442  * @brief Portability wrapper for `ftruncate()`.
443  *
444  * @param[in]  handle Valid file descriptor.
445  * @param[in]  size   Number of bytes to truncate (or extend) file to.
446  * @param[out] error  Pointer to error object. Optional, pass `NULL` if you are
447  *                    not interested in error details.
448  *
449  * @return `True` on success, `false` otherwise (with `error` set accordingly).
450  */
451 bool tr_sys_file_truncate(tr_sys_file_t handle, uint64_t size, struct tr_error** error);
452 
453 /**
454  * @brief Tell system to prefetch or discard some part of file which is [not] to be read soon.
455  *
456  * @param[in]  handle Valid file descriptor.
457  * @param[in]  offset Offset in file to prefetch from.
458  * @param[in]  size   Number of bytes to prefetch.
459  * @param[out] error  Pointer to error object. Optional, pass `NULL` if you are
460  *                    not interested in error details.
461  *
462  * @return `True` on success, `false` otherwise (with `error` set accordingly).
463  */
464 bool tr_sys_file_advise(tr_sys_file_t handle, uint64_t offset, uint64_t size, tr_sys_file_advice_t advice,
465     struct tr_error** error);
466 
467 /**
468  * @brief Preallocate file to specified size in full or sparse mode.
469  *
470  * @param[in]  handle Valid file descriptor.
471  * @param[in]  size   Number of bytes to preallocate file to.
472  * @param[in]  flags  Combination of @ref tr_sys_file_preallocate_flags_t values.
473  * @param[out] error  Pointer to error object. Optional, pass `NULL` if you are
474  *                    not interested in error details.
475  *
476  * @return `True` on success, `false` otherwise (with `error` set accordingly).
477  */
478 bool tr_sys_file_preallocate(tr_sys_file_t handle, uint64_t size, int flags, struct tr_error** error);
479 
480 /**
481  * @brief Portability wrapper for `mmap()` for files.
482  *
483  * @param[in]  handle Valid file descriptor.
484  * @param[in]  offset Offset in file to map from.
485  * @param[in]  size   Number of bytes to map.
486  * @param[out] error  Pointer to error object. Optional, pass `NULL` if you are
487  *                    not interested in error details.
488  *
489  * @return Pointer to mapped file data on success, `NULL` otherwise (with
490  *         `error` set accordingly).
491  */
492 void* tr_sys_file_map_for_reading(tr_sys_file_t handle, uint64_t offset, uint64_t size, struct tr_error** error);
493 
494 /**
495  * @brief Portability wrapper for `munmap()` for files.
496  *
497  * @param[in]  address Pointer to mapped file data.
498  * @param[in]  size    Size of mapped data in bytes.
499  * @param[out] error   Pointer to error object. Optional, pass `NULL` if you are
500  *                     not interested in error details.
501  *
502  * @return `True` on success, `false` otherwise (with `error` set accordingly).
503  */
504 bool tr_sys_file_unmap(void const* address, uint64_t size, struct tr_error** error);
505 
506 /**
507  * @brief Portability wrapper for `flock()`.
508  *
509  * Don't try to upgrade or downgrade the lock unless you know what you are
510  * doing, as behavior varies a bit between platforms.
511  *
512  * @param[in]  handle    Valid file descriptor.
513  * @param[in]  operation Combination of @ref tr_sys_file_lock_flags_t values.
514  * @param[out] error     Pointer to error object. Optional, pass `NULL` if you
515  *                       are not interested in error details.
516  *
517  * @return `True` on success, `false` otherwise (with `error` set accordingly).
518  */
519 bool tr_sys_file_lock(tr_sys_file_t handle, int operation, struct tr_error** error);
520 
521 /* File-related wrappers (utility) */
522 
523 /**
524  * @brief Portability wrapper for `fgets()`, removing EOL internally.
525  *
526  * Special care should be taken when reading from one of standard input streams
527  * (@ref tr_std_sys_file_t) since no UTF-8 conversion is currently being made.
528  *
529  * Reading from other streams (files, pipes) also leaves data untouched, so it
530  * should already be in UTF-8 encoding, or whichever else you expect.
531  *
532  * @param[in]  handle      Valid file descriptor.
533  * @param[out] buffer      Buffer to store read zero-terminated string to.
534  * @param[in]  buffer_size Buffer size in bytes, taking '\0' character into
535  *                         account.
536  * @param[out] error       Pointer to error object. Optional, pass `NULL` if you
537  *                         are not interested in error details.
538  *
539  * @return `True` on success, `false` otherwise (with `error` set accordingly).
540  *         Note that `false` will also be returned in case of end of file; if
541  *         you need to distinguish the two, check if `error` is `NULL`
542  *         afterwards.
543  */
544 bool tr_sys_file_read_line(tr_sys_file_t handle, char* buffer, size_t buffer_size, struct tr_error** error);
545 
546 /**
547  * @brief Portability wrapper for `fputs()`, appending EOL internally.
548  *
549  * Special care should be taken when writing to one of standard output streams
550  * (@ref tr_std_sys_file_t) since no UTF-8 conversion is currently being made.
551  *
552  * Writing to other streams (files, pipes) also leaves data untouched, so it
553  * should already be in UTF-8 encoding, or whichever else you expect.
554  *
555  * @param[in]  handle Valid file descriptor.
556  * @param[in]  buffer Zero-terminated string to write.
557  * @param[out] error  Pointer to error object. Optional, pass `NULL` if you are
558  *                    not interested in error details.
559  *
560  * @return `True` on success, `false` otherwise (with `error` set accordingly).
561  */
562 bool tr_sys_file_write_line(tr_sys_file_t handle, char const* buffer, struct tr_error** error);
563 
564 /**
565  * @brief Portability wrapper for `fprintf()`.
566  *
567  * Special care should be taken when writing to one of standard output streams
568  * (@ref tr_std_sys_file_t) since no UTF-8 conversion is currently being made.
569  *
570  * Writing to other streams (files, pipes) also leaves data untouched, so it
571  * should already be in UTF-8 encoding, or whichever else you expect.
572  *
573  * @param[in]  handle Valid file descriptor.
574  * @param[in]  format String format to write.
575  * @param[out] error  Pointer to error object. Optional, pass `NULL` if you are
576  *                    not interested in error details.
577  * @param[in]  ...    Format arguments.
578  *
579  * @return `True` on success, `false` otherwise (with `error` set accordingly).
580  */
581 bool tr_sys_file_write_fmt(tr_sys_file_t handle, char const* format, struct tr_error** error, ...) TR_GNUC_PRINTF(2, 4);
582 
583 /* Directory-related wrappers */
584 
585 /**
586  * @brief Portability wrapper for `getcwd()`.
587  *
588  * @param[out] error Pointer to error object. Optional, pass `NULL` if you are
589  *                   not interested in error details.
590  *
591  * @return Pointer to newly allocated buffer containing path to current
592  *         directory (use @ref tr_free to free it when no longer needed) on
593  *         success, `NULL` otherwise (with `error` set accordingly).
594  */
595 char* tr_sys_dir_get_current(struct tr_error** error);
596 
597 /**
598  * @brief Like `mkdir()`, but makes parent directories if needed.
599  *
600  * @param[in]  path        Path to directory.
601  * @param[in]  flags       Combination of @ref tr_sys_dir_create_flags_t values.
602  * @param[in]  permissions Permissions to create directory with. Not used on
603                            Windows.
604  * @param[out] error       Pointer to error object. Optional, pass `NULL` if you
605  *                         are not interested in error details.
606  *
607  * @return `True` on success, `false` otherwise (with `error` set accordingly).
608  */
609 bool tr_sys_dir_create(char const* path, int flags, int permissions, struct tr_error** error);
610 
611 /**
612  * @brief Portability wrapper for `mkdtemp()`.
613  *
614  * @param[in,out] path_template Template path to directory. Should end with at
615  *                              least six 'X' characters. Upon success, trailing
616  *                              'X' characters are replaced with actual random
617  *                              characters used to form a unique path to
618  *                              temporary directory.
619  * @param[out]    error         Pointer to error object. Optional, pass `NULL`
620  *                              if you are not interested in error details.
621  *
622  * @return `True` on success, `false` otherwise (with `error` set accordingly).
623  */
624 bool tr_sys_dir_create_temp(char* path_template, struct tr_error** error);
625 
626 /**
627  * @brief Portability wrapper for `opendir()`.
628  *
629  * @param[in]  path  Path to directory.
630  * @param[out] error Pointer to error object. Optional, pass `NULL` if you are
631  *                   not interested in error details.
632  *
633  * @return Opened directory descriptor on success, `TR_BAD_SYS_DIR` otherwise
634  *         (with `error` set accordingly).
635  */
636 tr_sys_dir_t tr_sys_dir_open(char const* path, struct tr_error** error);
637 
638 /**
639  * @brief Portability wrapper for `readdir()`.
640  *
641  * @param[in]  handle Valid directory descriptor.
642  * @param[out] error  Pointer to error object. Optional, pass `NULL` if you are
643  *                    not interested in error details.
644  *
645  * @return Pointer to next directory entry name (stored internally, DO NOT pass
646  *         it to @ref tr_free) on success, `NULL` otherwise (with `error` set
647  *         accordingly). Note that `NULL` will also be returned in case of end
648  *         of directory; if you need to distinguish the two, check if `error`
649  *         is `NULL` afterwards.
650  */
651 char const* tr_sys_dir_read_name(tr_sys_dir_t handle, struct tr_error** error);
652 
653 /**
654  * @brief Portability wrapper for `closedir()`.
655  *
656  * @param[in]  handle Valid directory descriptor.
657  * @param[out] error  Pointer to error object. Optional, pass `NULL` if you are
658  *                    not interested in error details.
659  *
660  * @return `True` on success, `false` otherwise (with `error` set accordingly).
661  */
662 bool tr_sys_dir_close(tr_sys_dir_t handle, struct tr_error** error);
663 
664 /** @} */
665 /** @} */
666 
667 #ifdef __cplusplus
668 }
669 #endif
670