1 #pragma once
2 
3 
4 #include <utility>
5 #include <memory>
6 #include <string>
7 #include <chrono>
8 #include <uv.h>
9 #include "request.hpp"
10 #include "util.hpp"
11 #include "loop.hpp"
12 
13 
14 namespace uvw {
15 
16 
17 namespace details {
18 
19 
20 enum class UVFsType: std::underlying_type_t<uv_fs_type> {
21     UNKNOWN = UV_FS_UNKNOWN,
22     CUSTOM = UV_FS_CUSTOM,
23     OPEN = UV_FS_OPEN,
24     CLOSE = UV_FS_CLOSE,
25     READ = UV_FS_READ,
26     WRITE = UV_FS_WRITE,
27     SENDFILE = UV_FS_SENDFILE,
28     STAT = UV_FS_STAT,
29     LSTAT = UV_FS_LSTAT,
30     FSTAT = UV_FS_FSTAT,
31     FTRUNCATE = UV_FS_FTRUNCATE,
32     UTIME = UV_FS_UTIME,
33     FUTIME = UV_FS_FUTIME,
34     ACCESS = UV_FS_ACCESS,
35     CHMOD = UV_FS_CHMOD,
36     FCHMOD = UV_FS_FCHMOD,
37     FSYNC = UV_FS_FSYNC,
38     FDATASYNC = UV_FS_FDATASYNC,
39     UNLINK = UV_FS_UNLINK,
40     RMDIR = UV_FS_RMDIR,
41     MKDIR = UV_FS_MKDIR,
42     MKDTEMP = UV_FS_MKDTEMP,
43     RENAME = UV_FS_RENAME,
44     SCANDIR = UV_FS_SCANDIR,
45     LINK = UV_FS_LINK,
46     SYMLINK = UV_FS_SYMLINK,
47     READLINK = UV_FS_READLINK,
48     CHOWN = UV_FS_CHOWN,
49     FCHOWN = UV_FS_FCHOWN,
50     REALPATH = UV_FS_REALPATH,
51     COPYFILE = UV_FS_COPYFILE,
52     LCHOWN = UV_FS_LCHOWN
53 };
54 
55 
56 enum class UVDirentTypeT: std::underlying_type_t<uv_dirent_type_t> {
57     UNKNOWN = UV_DIRENT_UNKNOWN,
58     FILE = UV_DIRENT_FILE,
59     DIR = UV_DIRENT_DIR,
60     LINK = UV_DIRENT_LINK,
61     FIFO = UV_DIRENT_FIFO,
62     SOCKET = UV_DIRENT_SOCKET,
63     CHAR = UV_DIRENT_CHAR,
64     BLOCK = UV_DIRENT_BLOCK
65 };
66 
67 
68 enum class UVFileOpenFlags: int {
69     APPEND = UV_FS_O_APPEND,
70     CREAT = UV_FS_O_CREAT,
71     DIRECT = UV_FS_O_DIRECT,
72     DIRECTORY = UV_FS_O_DIRECTORY,
73     DSYNC = UV_FS_O_DSYNC,
74     EXCL = UV_FS_O_EXCL,
75     EXLOCK = UV_FS_O_EXLOCK,
76     NOATIME = UV_FS_O_NOATIME,
77     NOCTTY = UV_FS_O_NOCTTY,
78     NOFOLLOW = UV_FS_O_NOFOLLOW,
79     NONBLOCK = UV_FS_O_NONBLOCK,
80     RANDOM = UV_FS_O_RANDOM,
81     RDONLY = UV_FS_O_RDONLY,
82     RDWR = UV_FS_O_RDWR,
83     SEQUENTIAL = UV_FS_O_SEQUENTIAL,
84     SHORT_LIVED = UV_FS_O_SHORT_LIVED,
85     SYMLINK = UV_FS_O_SYMLINK,
86     SYNC = UV_FS_O_SYNC,
87     TEMPORARY = UV_FS_O_TEMPORARY,
88     TRUNC = UV_FS_O_TRUNC,
89     WRONLY = UV_FS_O_WRONLY
90 };
91 
92 
93 enum class UVCopyFileFlags: int {
94     EXCL = UV_FS_COPYFILE_EXCL,
95     FICLONE = UV_FS_COPYFILE_FICLONE,
96     FICLONE_FORCE = UV_FS_COPYFILE_FICLONE_FORCE
97 };
98 
99 
100 enum class UVSymLinkFlags: int {
101     DIR = UV_FS_SYMLINK_DIR,
102     JUNCTION = UV_FS_SYMLINK_JUNCTION
103 };
104 
105 
106 }
107 
108 
109 /**
110  * @brief Default FsEvent event.
111  *
112  * Available types are:
113  *
114  * * `FsRequest::Type::UNKNOWN`
115  * * `FsRequest::Type::CUSTOM`
116  * * `FsRequest::Type::OPEN`
117  * * `FsRequest::Type::CLOSE`
118  * * `FsRequest::Type::READ`
119  * * `FsRequest::Type::WRITE`
120  * * `FsRequest::Type::SENDFILE`
121  * * `FsRequest::Type::STAT`
122  * * `FsRequest::Type::LSTAT`
123  * * `FsRequest::Type::FSTAT`
124  * * `FsRequest::Type::FTRUNCATE`
125  * * `FsRequest::Type::UTIME`
126  * * `FsRequest::Type::FUTIME`
127  * * `FsRequest::Type::ACCESS`
128  * * `FsRequest::Type::CHMOD`
129  * * `FsRequest::Type::FCHMOD`
130  * * `FsRequest::Type::FSYNC`
131  * * `FsRequest::Type::FDATASYNC`
132  * * `FsRequest::Type::UNLINK`
133  * * `FsRequest::Type::RMDIR`
134  * * `FsRequest::Type::MKDIR`
135  * * `FsRequest::Type::MKDTEMP`
136  * * `FsRequest::Type::RENAME`
137  * * `FsRequest::Type::SCANDIR`
138  * * `FsRequest::Type::LINK`
139  * * `FsRequest::Type::SYMLINK`
140  * * `FsRequest::Type::READLINK`
141  * * `FsRequest::Type::CHOWN`
142  * * `FsRequest::Type::FCHOWN`
143  * * `FsRequest::Type::REALPATH`
144  * * `FsRequest::Type::COPYFILE`
145  * * `FsRequest::Type::LCHOWN`
146  *
147  * It will be emitted by FsReq and/or FileReq according with their
148  * functionalities.
149  *
150  * See the official
151  * [documentation](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_type)
152  * for further details.
153  */
154 template<details::UVFsType e>
155 struct FsEvent {
FsEventuvw::FsEvent156     FsEvent(const char *pathname) noexcept: path{pathname} {}
157 
158     const char * path; /*!< The path affecting the request. */
159 };
160 
161 
162 /**
163  * @brief FsEvent event specialization for `FsRequest::Type::READ`.
164  *
165  * It will be emitted by FsReq and/or FileReq according with their
166  * functionalities.
167  */
168 template<>
169 struct FsEvent<details::UVFsType::READ> {
FsEventuvw::FsEvent170     FsEvent(const char *pathname, std::unique_ptr<const char[]> buf, std::size_t sz) noexcept
171         : path{pathname}, data{std::move(buf)}, size{sz}
172     {}
173 
174     const char * path; /*!< The path affecting the request. */
175     std::unique_ptr<const char[]> data; /*!< A bunch of data read from the given path. */
176     std::size_t size; /*!< The amount of data read from the given path. */
177 };
178 
179 
180 /**
181  * @brief FsEvent event specialization for `FsRequest::Type::WRITE`.
182  *
183  * It will be emitted by FsReq and/or FileReq according with their
184  * functionalities.
185  */
186 template<>
187 struct FsEvent<details::UVFsType::WRITE> {
FsEventuvw::FsEvent188     FsEvent(const char *pathname, std::size_t sz) noexcept
189         : path{pathname}, size{sz}
190     {}
191 
192     const char * path; /*!< The path affecting the request. */
193     std::size_t size; /*!< The amount of data written to the given path. */
194 };
195 
196 
197 /**
198  * @brief FsEvent event specialization for `FsRequest::Type::SENDFILE`.
199  *
200  * It will be emitted by FsReq and/or FileReq according with their
201  * functionalities.
202  */
203 template<>
204 struct FsEvent<details::UVFsType::SENDFILE> {
FsEventuvw::FsEvent205     FsEvent(const char *pathname, std::size_t sz) noexcept
206         : path{pathname}, size{sz}
207     {}
208 
209     const char * path; /*!< The path affecting the request. */
210     std::size_t size; /*!< The amount of data transferred. */
211 };
212 
213 
214 /**
215  * @brief FsEvent event specialization for `FsRequest::Type::STAT`.
216  *
217  * It will be emitted by FsReq and/or FileReq according with their
218  * functionalities.
219  */
220 template<>
221 struct FsEvent<details::UVFsType::STAT> {
FsEventuvw::FsEvent222     FsEvent(const char *pathname, Stat curr) noexcept
223         : path{pathname}, stat{std::move(curr)}
224     {}
225 
226     const char * path; /*!< The path affecting the request. */
227     Stat stat; /*!< An initialized instance of Stat. */
228 };
229 
230 
231 /**
232  * @brief FsEvent event specialization for `FsRequest::Type::FSTAT`.
233  *
234  * It will be emitted by FsReq and/or FileReq according with their
235  * functionalities.
236  */
237 template<>
238 struct FsEvent<details::UVFsType::FSTAT> {
FsEventuvw::FsEvent239     FsEvent(const char *pathname, Stat curr) noexcept
240         : path{pathname}, stat{std::move(curr)}
241     {}
242 
243     const char * path; /*!< The path affecting the request. */
244     Stat stat; /*!< An initialized instance of Stat. */
245 };
246 
247 
248 /**
249  * @brief FsEvent event specialization for `FsRequest::Type::LSTAT`.
250  *
251  * It will be emitted by FsReq and/or FileReq according with their
252  * functionalities.
253  */
254 template<>
255 struct FsEvent<details::UVFsType::LSTAT> {
FsEventuvw::FsEvent256     FsEvent(const char *pathname, Stat curr) noexcept
257         : path{pathname}, stat{std::move(curr)}
258     {}
259 
260     const char * path; /*!< The path affecting the request. */
261     Stat stat; /*!< An initialized instance of Stat. */
262 };
263 
264 
265 /**
266  * @brief FsEvent event specialization for `FsRequest::Type::SCANDIR`.
267  *
268  * It will be emitted by FsReq and/or FileReq according with their
269  * functionalities.
270  */
271 template<>
272 struct FsEvent<details::UVFsType::SCANDIR> {
FsEventuvw::FsEvent273     FsEvent(const char *pathname, std::size_t sz) noexcept
274         : path{pathname}, size{sz}
275     {}
276 
277     const char * path; /*!< The path affecting the request. */
278     std::size_t size; /*!< The number of directory entries selected. */
279 };
280 
281 
282 /**
283  * @brief FsEvent event specialization for `FsRequest::Type::READLINK`.
284  *
285  * It will be emitted by FsReq and/or FileReq according with their
286  * functionalities.
287  */
288 template<>
289 struct FsEvent<details::UVFsType::READLINK> {
FsEventuvw::FsEvent290     explicit FsEvent(const char *pathname, const char *buf, std::size_t sz) noexcept
291         : path{pathname}, data{buf}, size{sz}
292     {}
293 
294     const char * path; /*!< The path affecting the request. */
295     const char * data; /*!< A bunch of data read from the given path. */
296     std::size_t size; /*!< The amount of data read from the given path. */
297 };
298 
299 
300 /**
301  * @brief Base class for FsReq and/or FileReq.
302  *
303  * Not directly instantiable, should not be used by the users of the library.
304  */
305 template<typename T>
306 class FsRequest: public Request<T, uv_fs_t> {
307 protected:
308     template<details::UVFsType e>
fsGenericCallback(uv_fs_t * req)309     static void fsGenericCallback(uv_fs_t *req) {
310         auto ptr = Request<T, uv_fs_t>::reserve(req);
311         if(req->result < 0) { ptr->publish(ErrorEvent{req->result}); }
312         else { ptr->publish(FsEvent<e>{req->path}); }
313     }
314 
315     template<details::UVFsType e>
fsResultCallback(uv_fs_t * req)316     static void fsResultCallback(uv_fs_t *req) {
317         auto ptr = Request<T, uv_fs_t>::reserve(req);
318         if(req->result < 0) { ptr->publish(ErrorEvent{req->result}); }
319         else { ptr->publish(FsEvent<e>{req->path, static_cast<std::size_t>(req->result)}); }
320     }
321 
322     template<details::UVFsType e>
fsStatCallback(uv_fs_t * req)323     static void fsStatCallback(uv_fs_t *req) {
324         auto ptr = Request<T, uv_fs_t>::reserve(req);
325         if(req->result < 0) { ptr->publish(ErrorEvent{req->result}); }
326         else { ptr->publish(FsEvent<e>{req->path, req->statbuf}); }
327     }
328 
329     template<typename... Args>
cleanupAndInvoke(Args &&...args)330     void cleanupAndInvoke(Args&&... args) {
331         uv_fs_req_cleanup(this->get());
332         this->invoke(std::forward<Args>(args)...);
333     }
334 
335     template<typename F, typename... Args>
cleanupAndInvokeSync(F && f,Args &&...args)336     void cleanupAndInvokeSync(F &&f, Args&&... args) {
337         uv_fs_req_cleanup(this->get());
338         std::forward<F>(f)(std::forward<Args>(args)..., nullptr);
339     }
340 
341 public:
342     using Time = std::chrono::duration<double>;
343     using Type = details::UVFsType;
344     using EntryType = details::UVDirentTypeT;
345     using Entry = std::pair<EntryType, std::string>;
346 
347     using Request<T, uv_fs_t>::Request;
348 };
349 
350 
351 /**
352  * @brief The FileReq request.
353  *
354  * Cross-platform sync and async filesystem operations.<br/>
355  * All file operations are run on the threadpool.
356  *
357  * To create a `FileReq` through a `Loop`, no arguments are required.
358  *
359  * See the official
360  * [documentation](http://docs.libuv.org/en/v1.x/fs.html)
361  * for further details.
362  */
363 class FileReq final: public FsRequest<FileReq> {
364     static constexpr uv_file BAD_FD = -1;
365 
fsOpenCallback(uv_fs_t * req)366     static void fsOpenCallback(uv_fs_t *req) {
367         auto ptr = reserve(req);
368 
369         if(req->result < 0) {
370             ptr->publish(ErrorEvent{req->result});
371         } else {
372             ptr->file = static_cast<uv_file>(req->result);
373             ptr->publish(FsEvent<Type::OPEN>{req->path});
374         }
375     }
376 
fsCloseCallback(uv_fs_t * req)377     static void fsCloseCallback(uv_fs_t *req) {
378         auto ptr = reserve(req);
379 
380         if(req->result < 0) {
381             ptr->publish(ErrorEvent{req->result});
382         } else {
383             ptr->file = BAD_FD;
384             ptr->publish(FsEvent<Type::CLOSE>{req->path});
385         }
386     }
387 
fsReadCallback(uv_fs_t * req)388     static void fsReadCallback(uv_fs_t *req) {
389         auto ptr = reserve(req);
390         if(req->result < 0) { ptr->publish(ErrorEvent{req->result}); }
391         else { ptr->publish(FsEvent<Type::READ>{req->path, std::move(ptr->data), static_cast<std::size_t>(req->result)}); }
392     }
393 
394 public:
395     using FileOpen = details::UVFileOpenFlags;
396 
397     using FsRequest::FsRequest;
398 
~FileReq()399     ~FileReq() noexcept {
400         uv_fs_req_cleanup(get());
401     }
402 
403     /**
404      * @brief Async [close](http://linux.die.net/man/2/close).
405      *
406      * Emit a `FsEvent<FileReq::Type::CLOSE>` event when completed.<br/>
407      * Emit an ErrorEvent event in case of errors.
408      */
close()409     void close() {
410         cleanupAndInvoke(&uv_fs_close, parent(), get(), file, &fsCloseCallback);
411     }
412 
413     /**
414      * @brief Sync [close](http://linux.die.net/man/2/close).
415      * @return True in case of success, false otherwise.
416      */
closeSync()417     bool closeSync() {
418         auto req = get();
419         cleanupAndInvokeSync(&uv_fs_close, parent(), req, file);
420         if(req->result >= 0) { file = BAD_FD; }
421         return !(req->result < 0);
422     }
423 
424     /**
425      * @brief Async [open](http://linux.die.net/man/2/open).
426      *
427      * Emit a `FsEvent<FileReq::Type::OPEN>` event when completed.<br/>
428      * Emit an ErrorEvent event in case of errors.
429      *
430      * Available flags are:
431      *
432      * * `FileReq::FileOpen::APPEND`
433      * * `FileReq::FileOpen::CREAT`
434      * * `FileReq::FileOpen::DIRECT`
435      * * `FileReq::FileOpen::DIRECTORY`
436      * * `FileReq::FileOpen::DSYNC`
437      * * `FileReq::FileOpen::EXCL`
438      * * `FileReq::FileOpen::EXLOCK`
439      * * `FileReq::FileOpen::NOATIME`
440      * * `FileReq::FileOpen::NOCTTY`
441      * * `FileReq::FileOpen::NOFOLLOW`
442      * * `FileReq::FileOpen::NONBLOCK`
443      * * `FileReq::FileOpen::RANDOM`
444      * * `FileReq::FileOpen::RDONLY`
445      * * `FileReq::FileOpen::RDWR`
446      * * `FileReq::FileOpen::SEQUENTIAL`
447      * * `FileReq::FileOpen::SHORT_LIVED`
448      * * `FileReq::FileOpen::SYMLINK`
449      * * `FileReq::FileOpen::SYNC`
450      * * `FileReq::FileOpen::TEMPORARY`
451      * * `FileReq::FileOpen::TRUNC`
452      * * `FileReq::FileOpen::WRONLY`
453      *
454      * See the official
455      * [documentation](http://docs.libuv.org/en/v1.x/fs.html#file-open-constants)
456      * for further details.
457      *
458      * @param path A valid path name for a file.
459      * @param flags Flags made out of underlying constants.
460      * @param mode Mode, as described in the official documentation.
461      */
open(std::string path,Flags<FileOpen> flags,int mode)462     void open(std::string path, Flags<FileOpen> flags, int mode) {
463         cleanupAndInvoke(&uv_fs_open, parent(), get(), path.data(), flags, mode, &fsOpenCallback);
464     }
465 
466     /**
467      * @brief Sync [open](http://linux.die.net/man/2/open).
468      *
469      * Available flags are:
470      *
471      * * `FileReq::FileOpen::APPEND`
472      * * `FileReq::FileOpen::CREAT`
473      * * `FileReq::FileOpen::DIRECT`
474      * * `FileReq::FileOpen::DIRECTORY`
475      * * `FileReq::FileOpen::DSYNC`
476      * * `FileReq::FileOpen::EXCL`
477      * * `FileReq::FileOpen::EXLOCK`
478      * * `FileReq::FileOpen::NOATIME`
479      * * `FileReq::FileOpen::NOCTTY`
480      * * `FileReq::FileOpen::NOFOLLOW`
481      * * `FileReq::FileOpen::NONBLOCK`
482      * * `FileReq::FileOpen::RANDOM`
483      * * `FileReq::FileOpen::RDONLY`
484      * * `FileReq::FileOpen::RDWR`
485      * * `FileReq::FileOpen::SEQUENTIAL`
486      * * `FileReq::FileOpen::SHORT_LIVED`
487      * * `FileReq::FileOpen::SYMLINK`
488      * * `FileReq::FileOpen::SYNC`
489      * * `FileReq::FileOpen::TEMPORARY`
490      * * `FileReq::FileOpen::TRUNC`
491      * * `FileReq::FileOpen::WRONLY`
492      *
493      * See the official
494      * [documentation](http://docs.libuv.org/en/v1.x/fs.html#file-open-constants)
495      * for further details.
496      *
497      * @param path A valid path name for a file.
498      * @param flags Flags made out of underlying constants.
499      * @param mode Mode, as described in the official documentation.
500      * @return True in case of success, false otherwise.
501      */
openSync(std::string path,Flags<FileOpen> flags,int mode)502     bool openSync(std::string path, Flags<FileOpen> flags, int mode) {
503         auto req = get();
504         cleanupAndInvokeSync(&uv_fs_open, parent(), req, path.data(), flags, mode);
505         if(req->result >= 0) { file = static_cast<uv_file>(req->result); }
506         return !(req->result < 0);
507     }
508 
509     /**
510      * @brief Async [read](http://linux.die.net/man/2/preadv).
511      *
512      * Emit a `FsEvent<FileReq::Type::READ>` event when completed.<br/>
513      * Emit an ErrorEvent event in case of errors.
514      *
515      * @param offset Offset, as described in the official documentation.
516      * @param len Length, as described in the official documentation.
517      */
read(int64_t offset,unsigned int len)518     void read(int64_t offset, unsigned int len) {
519         data = std::unique_ptr<char[]>{new char[len]};
520         buffer = uv_buf_init(data.get(), len);
521         uv_buf_t bufs[] = { buffer };
522         cleanupAndInvoke(&uv_fs_read, parent(), get(), file, bufs, 1, offset, &fsReadCallback);
523     }
524 
525     /**
526      * @brief Sync [read](http://linux.die.net/man/2/preadv).
527      *
528      * @param offset Offset, as described in the official documentation.
529      * @param len Length, as described in the official documentation.
530      *
531      * @return A `std::pair` composed as it follows:
532      * * A boolean value that is true in case of success, false otherwise.
533      * * A `std::pair` composed as it follows:
534      *   * A bunch of data read from the given path.
535      *   * The amount of data read from the given path.
536      */
537     std::pair<bool, std::pair<std::unique_ptr<const char[]>, std::size_t>>
readSync(int64_t offset,unsigned int len)538     readSync(int64_t offset, unsigned int len) {
539         data = std::unique_ptr<char[]>{new char[len]};
540         buffer = uv_buf_init(data.get(), len);
541         uv_buf_t bufs[] = { buffer };
542         auto req = get();
543         cleanupAndInvokeSync(&uv_fs_read, parent(), req, file, bufs, 1, offset);
544         bool err = req->result < 0;
545         return std::make_pair(!err, std::make_pair(std::move(data), err ? 0 : std::size_t(req->result)));
546     }
547 
548     /**
549      * @brief Async [write](http://linux.die.net/man/2/pwritev).
550      *
551      * The request takes the ownership of the data and it is in charge of delete
552      * them.
553      *
554      * Emit a `FsEvent<FileReq::Type::WRITE>` event when completed.<br/>
555      * Emit an ErrorEvent event in case of errors.
556      *
557      * @param buf The data to be written.
558      * @param len The lenght of the submitted data.
559      * @param offset Offset, as described in the official documentation.
560      */
write(std::unique_ptr<char[]> buf,unsigned int len,int64_t offset)561     void write(std::unique_ptr<char[]> buf, unsigned int len, int64_t offset) {
562         this->data = std::move(buf);
563         uv_buf_t bufs[] = { uv_buf_init(this->data.get(), len) };
564         cleanupAndInvoke(&uv_fs_write, parent(), get(), file, bufs, 1, offset, &fsResultCallback<Type::WRITE>);
565     }
566 
567     /**
568      * @brief Async [write](http://linux.die.net/man/2/pwritev).
569      *
570      * The request doesn't take the ownership of the data. Be sure that their
571      * lifetime overcome the one of the request.
572      *
573      * Emit a `FsEvent<FileReq::Type::WRITE>` event when completed.<br/>
574      * Emit an ErrorEvent event in case of errors.
575      *
576      * @param buf The data to be written.
577      * @param len The lenght of the submitted data.
578      * @param offset Offset, as described in the official documentation.
579      */
write(char * buf,unsigned int len,int64_t offset)580     void write(char *buf, unsigned int len, int64_t offset) {
581         uv_buf_t bufs[] = { uv_buf_init(buf, len) };
582         cleanupAndInvoke(&uv_fs_write, parent(), get(), file, bufs, 1, offset, &fsResultCallback<Type::WRITE>);
583     }
584 
585     /**
586      * @brief Sync [write](http://linux.die.net/man/2/pwritev).
587      *
588      * @param buf The data to be written.
589      * @param len The lenght of the submitted data.
590      * @param offset Offset, as described in the official documentation.
591      *
592      * @return A `std::pair` composed as it follows:
593      * * A boolean value that is true in case of success, false otherwise.
594      * * The amount of data written to the given path.
595      */
writeSync(std::unique_ptr<char[]> buf,unsigned int len,int64_t offset)596     std::pair<bool, std::size_t> writeSync(std::unique_ptr<char[]> buf, unsigned int len, int64_t offset) {
597         this->data = std::move(buf);
598         uv_buf_t bufs[] = { uv_buf_init(this->data.get(), len) };
599         auto req = get();
600         cleanupAndInvokeSync(&uv_fs_write, parent(), req, file, bufs, 1, offset);
601         bool err = req->result < 0;
602         return std::make_pair(!err, err ? 0 : std::size_t(req->result));
603     }
604 
605     /**
606      * @brief Async [fstat](http://linux.die.net/man/2/fstat).
607      *
608      * Emit a `FsEvent<FileReq::Type::FSTAT>` event when completed.<br/>
609      * Emit an ErrorEvent event in case of errors.
610      */
stat()611     void stat() {
612         cleanupAndInvoke(&uv_fs_fstat, parent(), get(), file, &fsStatCallback<Type::FSTAT>);
613     }
614 
615     /**
616      * @brief Sync [fstat](http://linux.die.net/man/2/fstat).
617      *
618      * @return A `std::pair` composed as it follows:
619      * * A boolean value that is true in case of success, false otherwise.
620      * * An initialized instance of Stat.
621      */
statSync()622     std::pair<bool, Stat> statSync() {
623         auto req = get();
624         cleanupAndInvokeSync(&uv_fs_fstat, parent(), req, file);
625         return std::make_pair(!(req->result < 0), req->statbuf);
626     }
627 
628     /**
629      * @brief Async [fsync](http://linux.die.net/man/2/fsync).
630      *
631      * Emit a `FsEvent<FileReq::Type::FSYNC>` event when completed.<br/>
632      * Emit an ErrorEvent event in case of errors.
633      */
sync()634     void sync() {
635         cleanupAndInvoke(&uv_fs_fsync, parent(), get(), file, &fsGenericCallback<Type::FSYNC>);
636     }
637 
638     /**
639      * @brief Sync [fsync](http://linux.die.net/man/2/fsync).
640      * @return True in case of success, false otherwise.
641      */
syncSync()642     bool syncSync() {
643         auto req = get();
644         cleanupAndInvokeSync(&uv_fs_fsync, parent(), req, file);
645         return !(req->result < 0);
646     }
647 
648     /**
649      * @brief Async [fdatasync](http://linux.die.net/man/2/fdatasync).
650      *
651      * Emit a `FsEvent<FileReq::Type::FDATASYNC>` event when completed.<br/>
652      * Emit an ErrorEvent event in case of errors.
653      */
datasync()654     void datasync() {
655         cleanupAndInvoke(&uv_fs_fdatasync, parent(), get(), file, &fsGenericCallback<Type::FDATASYNC>);
656     }
657 
658     /**
659      * @brief Sync [fdatasync](http://linux.die.net/man/2/fdatasync).
660      * @return True in case of success, false otherwise.
661      */
datasyncSync()662     bool datasyncSync() {
663         auto req = get();
664         cleanupAndInvokeSync(&uv_fs_fdatasync, parent(), req, file);
665         return !(req->result < 0);
666     }
667 
668     /**
669      * @brief Async [ftruncate](http://linux.die.net/man/2/ftruncate).
670      *
671      * Emit a `FsEvent<FileReq::Type::FTRUNCATE>` event when completed.<br/>
672      * Emit an ErrorEvent event in case of errors.
673      *
674      * @param offset Offset, as described in the official documentation.
675      */
truncate(int64_t offset)676     void truncate(int64_t offset) {
677         cleanupAndInvoke(&uv_fs_ftruncate, parent(), get(), file, offset, &fsGenericCallback<Type::FTRUNCATE>);
678     }
679 
680     /**
681      * @brief Sync [ftruncate](http://linux.die.net/man/2/ftruncate).
682      * @param offset Offset, as described in the official documentation.
683      * @return True in case of success, false otherwise.
684      */
truncateSync(int64_t offset)685     bool truncateSync(int64_t offset) {
686         auto req = get();
687         cleanupAndInvokeSync(&uv_fs_ftruncate, parent(), req, file, offset);
688         return !(req->result < 0);
689     }
690 
691     /**
692      * @brief Async [sendfile](http://linux.die.net/man/2/sendfile).
693      *
694      * Emit a `FsEvent<FileReq::Type::SENDFILE>` event when completed.<br/>
695      * Emit an ErrorEvent event in case of errors.
696      *
697      * @param out A valid instance of FileHandle.
698      * @param offset Offset, as described in the official documentation.
699      * @param length Length, as described in the official documentation.
700      */
sendfile(FileHandle out,int64_t offset,std::size_t length)701     void sendfile(FileHandle out, int64_t offset, std::size_t length) {
702         cleanupAndInvoke(&uv_fs_sendfile, parent(), get(), out, file, offset, length, &fsResultCallback<Type::SENDFILE>);
703     }
704 
705     /**
706      * @brief Sync [sendfile](http://linux.die.net/man/2/sendfile).
707      *
708      * @param out A valid instance of FileHandle.
709      * @param offset Offset, as described in the official documentation.
710      * @param length Length, as described in the official documentation.
711      *
712      * @return A `std::pair` composed as it follows:
713      * * A boolean value that is true in case of success, false otherwise.
714      * * The amount of data transferred.
715      */
sendfileSync(FileHandle out,int64_t offset,std::size_t length)716     std::pair<bool, std::size_t> sendfileSync(FileHandle out, int64_t offset, std::size_t length) {
717         auto req = get();
718         cleanupAndInvokeSync(&uv_fs_sendfile, parent(), req, out, file, offset, length);
719         bool err = req->result < 0;
720         return std::make_pair(!err, err ? 0 : std::size_t(req->result));
721     }
722 
723     /**
724      * @brief Async [fchmod](http://linux.die.net/man/2/fchmod).
725      *
726      * Emit a `FsEvent<FileReq::Type::FCHMOD>` event when completed.<br/>
727      * Emit an ErrorEvent event in case of errors.
728      *
729      * @param mode Mode, as described in the official documentation.
730      */
chmod(int mode)731     void chmod(int mode) {
732         cleanupAndInvoke(&uv_fs_fchmod, parent(), get(), file, mode, &fsGenericCallback<Type::FCHMOD>);
733     }
734 
735     /**
736      * @brief Sync [fchmod](http://linux.die.net/man/2/fchmod).
737      * @param mode Mode, as described in the official documentation.
738      * @return True in case of success, false otherwise.
739      */
chmodSync(int mode)740     bool chmodSync(int mode) {
741         auto req = get();
742         cleanupAndInvokeSync(&uv_fs_fchmod, parent(), req, file, mode);
743         return !(req->result < 0);
744     }
745 
746     /**
747      * @brief Async [futime](http://linux.die.net/man/2/futime).
748      *
749      * Emit a `FsEvent<FileReq::Type::FUTIME>` event when completed.<br/>
750      * Emit an ErrorEvent event in case of errors.
751      *
752      * @param atime `std::chrono::duration<double>`, having the same meaning as
753      * described in the official documentation.
754      * @param mtime `std::chrono::duration<double>`, having the same meaning as
755      * described in the official documentation.
756      */
utime(Time atime,Time mtime)757     void utime(Time atime, Time mtime) {
758         cleanupAndInvoke(&uv_fs_futime, parent(), get(), file, atime.count(), mtime.count(), &fsGenericCallback<Type::FUTIME>);
759     }
760 
761     /**
762      * @brief Sync [futime](http://linux.die.net/man/2/futime).
763      * @param atime `std::chrono::duration<double>`, having the same meaning as
764      * described in the official documentation.
765      * @param mtime `std::chrono::duration<double>`, having the same meaning as
766      * described in the official documentation.
767      * @return True in case of success, false otherwise.
768      */
utimeSync(Time atime,Time mtime)769     bool utimeSync(Time atime, Time mtime) {
770         auto req = get();
771         cleanupAndInvokeSync(&uv_fs_futime, parent(), req, file, atime.count(), mtime.count());
772         return !(req->result < 0);
773     }
774 
775     /**
776      * @brief Async [fchown](http://linux.die.net/man/2/fchown).
777      *
778      * Emit a `FsEvent<FileReq::Type::FCHOWN>` event when completed.<br/>
779      * Emit an ErrorEvent event in case of errors.
780      *
781      * @param uid UID, as described in the official documentation.
782      * @param gid GID, as described in the official documentation.
783      */
chown(Uid uid,Gid gid)784     void chown(Uid uid, Gid gid) {
785         cleanupAndInvoke(&uv_fs_fchown, parent(), get(), file, uid, gid, &fsGenericCallback<Type::FCHOWN>);
786     }
787 
788     /**
789      * @brief Sync [fchown](http://linux.die.net/man/2/fchown).
790      * @param uid UID, as described in the official documentation.
791      * @param gid GID, as described in the official documentation.
792      * @return True in case of success, false otherwise.
793      */
chownSync(Uid uid,Gid gid)794     bool chownSync(Uid uid, Gid gid) {
795         auto req = get();
796         cleanupAndInvokeSync(&uv_fs_fchown, parent(), req, file, uid, gid);
797         return !(req->result < 0);
798     }
799 
800     /**
801      * @brief Cast operator to FileHandle.
802      *
803      * Cast operator to an internal representation of the underlying file
804      * handle.
805      *
806      * @return A valid instance of FileHandle (the descriptor can be invalid).
807      */
operator FileHandle() const808     operator FileHandle() const noexcept { return file; }
809 
810 private:
811     std::unique_ptr<char[]> data{nullptr};
812     uv_buf_t buffer{};
813     uv_file file{BAD_FD};
814 };
815 
816 
817 /**
818  * @brief The FsReq request.
819  *
820  * Cross-platform sync and async filesystem operations.<br/>
821  * All file operations are run on the threadpool.
822  *
823  * To create a `FsReq` through a `Loop`, no arguments are required.
824  *
825  * See the official
826  * [documentation](http://docs.libuv.org/en/v1.x/fs.html)
827  * for further details.
828  */
829 class FsReq final: public FsRequest<FsReq> {
fsReadlinkCallback(uv_fs_t * req)830     static void fsReadlinkCallback(uv_fs_t *req) {
831         auto ptr = reserve(req);
832         if(req->result < 0) { ptr->publish(ErrorEvent{req->result}); }
833         else { ptr->publish(FsEvent<Type::READLINK>{req->path, static_cast<char *>(req->ptr), static_cast<std::size_t>(req->result)}); }
834     }
835 
836 public:
837     using CopyFile = details::UVCopyFileFlags;
838     using SymLink = details::UVSymLinkFlags;
839 
840     using FsRequest::FsRequest;
841 
~FsReq()842     ~FsReq() noexcept {
843         uv_fs_req_cleanup(get());
844     }
845 
846     /**
847      * @brief Async [unlink](http://linux.die.net/man/2/unlink).
848      *
849      * Emit a `FsEvent<FsReq::Type::UNLINK>` event when completed.<br/>
850      * Emit an ErrorEvent event in case of errors.
851      *
852      * @param path Path, as described in the official documentation.
853      */
unlink(std::string path)854     void unlink(std::string path) {
855         cleanupAndInvoke(&uv_fs_unlink, parent(), get(), path.data(), &fsGenericCallback<Type::UNLINK>);
856     }
857 
858     /**
859      * @brief Sync [unlink](http://linux.die.net/man/2/unlink).
860      * @param path Path, as described in the official documentation.
861      * @return True in case of success, false otherwise.
862      */
unlinkSync(std::string path)863     bool unlinkSync(std::string path) {
864         auto req = get();
865         cleanupAndInvokeSync(&uv_fs_unlink, parent(), req, path.data());
866         return !(req->result < 0);
867     }
868 
869     /**
870      * @brief Async [mkdir](http://linux.die.net/man/2/mkdir).
871      *
872      * Emit a `FsEvent<FsReq::Type::MKDIR>` event when completed.<br/>
873      * Emit an ErrorEvent event in case of errors.
874      *
875      * @param path Path, as described in the official documentation.
876      * @param mode Mode, as described in the official documentation.
877      */
mkdir(std::string path,int mode)878     void mkdir(std::string path, int mode) {
879         cleanupAndInvoke(&uv_fs_mkdir, parent(), get(), path.data(), mode, &fsGenericCallback<Type::MKDIR>);
880     }
881 
882     /**
883      * @brief Sync [mkdir](http://linux.die.net/man/2/mkdir).
884      * @param path Path, as described in the official documentation.
885      * @param mode Mode, as described in the official documentation.
886      * @return True in case of success, false otherwise.
887      */
mkdirSync(std::string path,int mode)888     bool mkdirSync(std::string path, int mode) {
889         auto req = get();
890         cleanupAndInvokeSync(&uv_fs_mkdir, parent(), req, path.data(), mode);
891         return !(req->result < 0);
892     }
893 
894     /**
895      * @brief Async [mktemp](http://linux.die.net/man/3/mkdtemp).
896      *
897      * Emit a `FsEvent<FsReq::Type::MKDTEMP>` event when completed.<br/>
898      * Emit an ErrorEvent event in case of errors.
899      *
900      * @param tpl Template, as described in the official documentation.
901      */
mkdtemp(std::string tpl)902     void mkdtemp(std::string tpl) {
903         cleanupAndInvoke(&uv_fs_mkdtemp, parent(), get(), tpl.data(), &fsGenericCallback<Type::MKDTEMP>);
904     }
905 
906     /**
907      * @brief Sync [mktemp](http://linux.die.net/man/3/mkdtemp).
908      *
909      * @param tpl Template, as described in the official documentation.
910      *
911      * @return A `std::pair` composed as it follows:
912      * * A boolean value that is true in case of success, false otherwise.
913      * * The actual path of the newly created directoy.
914      */
mkdtempSync(std::string tpl)915     std::pair<bool, const char *> mkdtempSync(std::string tpl) {
916         auto req = get();
917         cleanupAndInvokeSync(&uv_fs_mkdtemp, parent(), req, tpl.data());
918         return std::make_pair(!(req->result < 0), req->path);
919     }
920 
921     /**
922      * @brief Async [rmdir](http://linux.die.net/man/2/rmdir).
923      *
924      * Emit a `FsEvent<FsReq::Type::RMDIR>` event when completed.<br/>
925      * Emit an ErrorEvent event in case of errors.
926      *
927      * @param path Path, as described in the official documentation.
928      */
rmdir(std::string path)929     void rmdir(std::string path) {
930         cleanupAndInvoke(&uv_fs_rmdir, parent(), get(), path.data(), &fsGenericCallback<Type::RMDIR>);
931     }
932 
933     /**
934      * @brief Sync [rmdir](http://linux.die.net/man/2/rmdir).
935      * @param path Path, as described in the official documentation.
936      * @return True in case of success, false otherwise.
937      */
rmdirSync(std::string path)938     bool rmdirSync(std::string path) {
939         auto req = get();
940         cleanupAndInvokeSync(&uv_fs_rmdir, parent(), req, path.data());
941         return !(req->result < 0);
942     }
943 
944     /**
945      * @brief Async [scandir](http://linux.die.net/man/3/scandir).
946      *
947      * Emit a `FsEvent<FsReq::Type::SCANDIR>` event when completed.<br/>
948      * Emit an ErrorEvent event in case of errors.
949      *
950      * @param path Path, as described in the official documentation.
951      * @param flags Flags, as described in the official documentation.
952      */
scandir(std::string path,int flags)953     void scandir(std::string path, int flags) {
954         cleanupAndInvoke(&uv_fs_scandir, parent(), get(), path.data(), flags, &fsResultCallback<Type::SCANDIR>);
955     }
956 
957     /**
958      * @brief Sync [scandir](http://linux.die.net/man/3/scandir).
959      *
960      * @param path Path, as described in the official documentation.
961      * @param flags Flags, as described in the official documentation.
962      *
963      * @return A `std::pair` composed as it follows:
964      * * A boolean value that is true in case of success, false otherwise.
965      * * The number of directory entries selected.
966      */
scandirSync(std::string path,int flags)967     std::pair<bool, std::size_t> scandirSync(std::string path, int flags) {
968         auto req = get();
969         cleanupAndInvokeSync(&uv_fs_scandir, parent(), req, path.data(), flags);
970         bool err = req->result < 0;
971         return std::make_pair(!err, err ? 0 : std::size_t(req->result));
972     }
973 
974     /**
975      * @brief Gets entries populated with the next directory entry data.
976      *
977      * Returns instances of Entry, that is an alias for a pair where:
978      *
979      * * The first parameter indicates the entry type (see below).
980      * * The second parameter is a `std::string` that contains the actual value.
981      *
982      * Available entry types are:
983      *
984      * * `FsReq::EntryType::UNKNOWN`
985      * * `FsReq::EntryType::FILE`
986      * * `FsReq::EntryType::DIR`
987      * * `FsReq::EntryType::LINK`
988      * * `FsReq::EntryType::FIFO`
989      * * `FsReq::EntryType::SOCKET`
990      * * `FsReq::EntryType::CHAR`
991      * * `FsReq::EntryType::BLOCK`
992      *
993      * See the official
994      * [documentation](http://docs.libuv.org/en/v1.x/fs.html#c.uv_dirent_t)
995      * for further details.
996      *
997      * @return A pair where:
998      *
999      * * The first parameter is a boolean value that indicates if the current
1000      * entry is still valid.
1001      * * The second parameter is an instance of `Entry` (see above).
1002      */
scandirNext()1003     std::pair<bool, Entry> scandirNext() {
1004         uv_dirent_t dirent;
1005         std::pair<bool, Entry> ret{false, { EntryType::UNKNOWN, "" }};
1006         auto res = uv_fs_scandir_next(get(), &dirent);
1007 
1008         if(UV_EOF != res) {
1009             ret.second.first = static_cast<EntryType>(dirent.type);
1010             ret.second.second = dirent.name;
1011             ret.first = true;
1012         }
1013 
1014         return ret;
1015     }
1016 
1017     /**
1018      * @brief Async [stat](http://linux.die.net/man/2/stat).
1019      *
1020      * Emit a `FsEvent<FsReq::Type::STAT>` event when completed.<br/>
1021      * Emit an ErrorEvent event in case of errors.
1022      *
1023      * @param path Path, as described in the official documentation.
1024      */
stat(std::string path)1025     void stat(std::string path) {
1026         cleanupAndInvoke(&uv_fs_stat, parent(), get(), path.data(), &fsStatCallback<Type::STAT>);
1027     }
1028 
1029     /**
1030      * @brief Sync [stat](http://linux.die.net/man/2/stat).
1031      *
1032      * @param path Path, as described in the official documentation.
1033      *
1034      * @return A `std::pair` composed as it follows:
1035      * * A boolean value that is true in case of success, false otherwise.
1036      * * An initialized instance of Stat.
1037      */
statSync(std::string path)1038     std::pair<bool, Stat> statSync(std::string path) {
1039         auto req = get();
1040         cleanupAndInvokeSync(&uv_fs_stat, parent(), req, path.data());
1041         return std::make_pair(!(req->result < 0), req->statbuf);
1042     }
1043 
1044     /**
1045      * @brief Async [lstat](http://linux.die.net/man/2/lstat).
1046      *
1047      * Emit a `FsEvent<FsReq::Type::LSTAT>` event when completed.<br/>
1048      * Emit an ErrorEvent event in case of errors.
1049      *
1050      * @param path Path, as described in the official documentation.
1051      */
lstat(std::string path)1052     void lstat(std::string path) {
1053         cleanupAndInvoke(&uv_fs_lstat, parent(), get(), path.data(), &fsStatCallback<Type::LSTAT>);
1054     }
1055 
1056     /**
1057      * @brief Sync [lstat](http://linux.die.net/man/2/lstat).
1058      *
1059      * @param path Path, as described in the official documentation.
1060      *
1061      * @return A `std::pair` composed as it follows:
1062      * * A boolean value that is true in case of success, false otherwise.
1063      * * An initialized instance of Stat.
1064      */
lstatSync(std::string path)1065     std::pair<bool, Stat> lstatSync(std::string path) {
1066         auto req = get();
1067         cleanupAndInvokeSync(&uv_fs_lstat, parent(), req, path.data());
1068         return std::make_pair(!(req->result < 0), req->statbuf);
1069     }
1070 
1071     /**
1072      * @brief Async [rename](http://linux.die.net/man/2/rename).
1073      *
1074      * Emit a `FsEvent<FsReq::Type::RENAME>` event when completed.<br/>
1075      * Emit an ErrorEvent event in case of errors.
1076      *
1077      * @param old Old path, as described in the official documentation.
1078      * @param path New path, as described in the official documentation.
1079      */
rename(std::string old,std::string path)1080     void rename(std::string old, std::string path) {
1081         cleanupAndInvoke(&uv_fs_rename, parent(), get(), old.data(), path.data(), &fsGenericCallback<Type::RENAME>);
1082     }
1083 
1084     /**
1085      * @brief Sync [rename](http://linux.die.net/man/2/rename).
1086      * @param old Old path, as described in the official documentation.
1087      * @param path New path, as described in the official documentation.
1088      * @return True in case of success, false otherwise.
1089      */
renameSync(std::string old,std::string path)1090     bool renameSync(std::string old, std::string path) {
1091         auto req = get();
1092         cleanupAndInvokeSync(&uv_fs_rename, parent(), req, old.data(), path.data());
1093         return !(req->result < 0);
1094     }
1095 
1096     /**
1097      * @brief Copies a file asynchronously from a path to a new one.
1098      *
1099      * Emit a `FsEvent<FsReq::Type::UV_FS_COPYFILE>` event when
1100      * completed.<br/>
1101      * Emit an ErrorEvent event in case of errors.
1102      *
1103      * Available flags are:
1104      *
1105      * * `FsReq::CopyFile::EXCL`: it fails if the destination path
1106      * already exists (the default behavior is to overwrite the destination if
1107      * it exists).
1108      * * `FsReq::CopyFile::FICLONE`: If present, it will attempt to create a
1109      * copy-on-write reflink. If the underlying platform does not support
1110      * copy-on-write, then a fallback copy mechanism is used.
1111      * * `FsReq::CopyFile::FICLONE_FORCE`: If present, it will attempt to create
1112      * a copy-on-write reflink. If the underlying platform does not support
1113      * copy-on-write, then an error is returned.
1114      *
1115      * @warning
1116      * If the destination path is created, but an error occurs while copying the
1117      * data, then the destination path is removed. There is a brief window of
1118      * time between closing and removing the file where another process could
1119      * access the file.
1120      *
1121      * @param old Old path, as described in the official documentation.
1122      * @param path New path, as described in the official documentation.
1123      * @param flags Optional additional flags.
1124      */
copyfile(std::string old,std::string path,Flags<CopyFile> flags=Flags<CopyFile>{})1125     void copyfile(std::string old, std::string path, Flags<CopyFile> flags = Flags<CopyFile>{}) {
1126         cleanupAndInvoke(&uv_fs_copyfile, parent(), get(), old.data(), path.data(), flags, &fsGenericCallback<Type::COPYFILE>);
1127     }
1128 
1129     /**
1130      * @brief Copies a file synchronously from a path to a new one.
1131      *
1132      * Available flags are:
1133      *
1134      * * `FsReq::CopyFile::EXCL`: it fails if the destination path
1135      * already exists (the default behavior is to overwrite the destination if
1136      * it exists).
1137      *
1138      * If the destination path is created, but an error occurs while copying the
1139      * data, then the destination path is removed. There is a brief window of
1140      * time between closing and removing the file where another process could
1141      * access the file.
1142      *
1143      * @param old Old path, as described in the official documentation.
1144      * @param path New path, as described in the official documentation.
1145      * @param flags Optional additional flags.
1146      * @return True in case of success, false otherwise.
1147      */
copyfileSync(std::string old,std::string path,Flags<CopyFile> flags=Flags<CopyFile>{})1148     bool copyfileSync(std::string old, std::string path, Flags<CopyFile> flags = Flags<CopyFile>{}) {
1149         auto req = get();
1150         cleanupAndInvokeSync(&uv_fs_copyfile, parent(), get(), old.data(), path.data(), flags);
1151         return !(req->result < 0);
1152     }
1153 
1154     /**
1155      * @brief Async [access](http://linux.die.net/man/2/access).
1156      *
1157      * Emit a `FsEvent<FsReq::Type::ACCESS>` event when completed.<br/>
1158      * Emit an ErrorEvent event in case of errors.
1159      *
1160      * @param path Path, as described in the official documentation.
1161      * @param mode Mode, as described in the official documentation.
1162      */
access(std::string path,int mode)1163     void access(std::string path, int mode) {
1164         cleanupAndInvoke(&uv_fs_access, parent(), get(), path.data(), mode, &fsGenericCallback<Type::ACCESS>);
1165     }
1166 
1167     /**
1168      * @brief Sync [access](http://linux.die.net/man/2/access).
1169      * @param path Path, as described in the official documentation.
1170      * @param mode Mode, as described in the official documentation.
1171      * @return True in case of success, false otherwise.
1172      */
accessSync(std::string path,int mode)1173     bool accessSync(std::string path, int mode) {
1174         auto req = get();
1175         cleanupAndInvokeSync(&uv_fs_access, parent(), req, path.data(), mode);
1176         return !(req->result < 0);
1177     }
1178 
1179     /**
1180      * @brief Async [chmod](http://linux.die.net/man/2/chmod).
1181      *
1182      * Emit a `FsEvent<FsReq::Type::CHMOD>` event when completed.<br/>
1183      * Emit an ErrorEvent event in case of errors.
1184      *
1185      * @param path Path, as described in the official documentation.
1186      * @param mode Mode, as described in the official documentation.
1187      */
chmod(std::string path,int mode)1188     void chmod(std::string path, int mode) {
1189         cleanupAndInvoke(&uv_fs_chmod, parent(), get(), path.data(), mode, &fsGenericCallback<Type::CHMOD>);
1190     }
1191 
1192     /**
1193      * @brief Sync [chmod](http://linux.die.net/man/2/chmod).
1194      * @param path Path, as described in the official documentation.
1195      * @param mode Mode, as described in the official documentation.
1196      * @return True in case of success, false otherwise.
1197      */
chmodSync(std::string path,int mode)1198     bool chmodSync(std::string path, int mode) {
1199         auto req = get();
1200         cleanupAndInvokeSync(&uv_fs_chmod, parent(), req, path.data(), mode);
1201         return !(req->result < 0);
1202     }
1203 
1204     /**
1205      * @brief Async [utime](http://linux.die.net/man/2/utime).
1206      *
1207      * Emit a `FsEvent<FsReq::Type::UTIME>` event when completed.<br/>
1208      * Emit an ErrorEvent event in case of errors.
1209      *
1210      * @param path Path, as described in the official documentation.
1211      * @param atime `std::chrono::duration<double>`, having the same meaning as
1212      * described in the official documentation.
1213      * @param mtime `std::chrono::duration<double>`, having the same meaning as
1214      * described in the official documentation.
1215      */
utime(std::string path,Time atime,Time mtime)1216     void utime(std::string path, Time atime, Time mtime) {
1217         cleanupAndInvoke(&uv_fs_utime, parent(), get(), path.data(), atime.count(), mtime.count(), &fsGenericCallback<Type::UTIME>);
1218     }
1219 
1220     /**
1221      * @brief Sync [utime](http://linux.die.net/man/2/utime).
1222      * @param path Path, as described in the official documentation.
1223      * @param atime `std::chrono::duration<double>`, having the same meaning as
1224      * described in the official documentation.
1225      * @param mtime `std::chrono::duration<double>`, having the same meaning as
1226      * described in the official documentation.
1227      * @return True in case of success, false otherwise.
1228      */
utimeSync(std::string path,Time atime,Time mtime)1229     bool utimeSync(std::string path, Time atime, Time mtime) {
1230         auto req = get();
1231         cleanupAndInvokeSync(&uv_fs_utime, parent(), req, path.data(), atime.count(), mtime.count());
1232         return !(req->result < 0);
1233     }
1234 
1235     /**
1236      * @brief Async [link](http://linux.die.net/man/2/link).
1237      *
1238      * Emit a `FsEvent<FsReq::Type::LINK>` event when completed.<br/>
1239      * Emit an ErrorEvent event in case of errors.
1240      *
1241      * @param old Old path, as described in the official documentation.
1242      * @param path New path, as described in the official documentation.
1243      */
link(std::string old,std::string path)1244     void link(std::string old, std::string path) {
1245         cleanupAndInvoke(&uv_fs_link, parent(), get(), old.data(), path.data(), &fsGenericCallback<Type::LINK>);
1246     }
1247 
1248     /**
1249      * @brief Sync [link](http://linux.die.net/man/2/link).
1250      * @param old Old path, as described in the official documentation.
1251      * @param path New path, as described in the official documentation.
1252      * @return True in case of success, false otherwise.
1253      */
linkSync(std::string old,std::string path)1254     bool linkSync(std::string old, std::string path) {
1255         auto req = get();
1256         cleanupAndInvokeSync(&uv_fs_link, parent(), req, old.data(), path.data());
1257         return !(req->result < 0);
1258     }
1259 
1260     /**
1261      * @brief Async [symlink](http://linux.die.net/man/2/symlink).
1262      *
1263      * Emit a `FsEvent<FsReq::Type::SYMLINK>` event when completed.<br/>
1264      * Emit an ErrorEvent event in case of errors.
1265      *
1266      * Available flags are:
1267      *
1268      * * `FsReq::SymLink::DIR`: it indicates that the old path points to a
1269      * directory.
1270      * * `FsReq::SymLink::JUNCTION`: it requests that the symlink is created
1271      * using junction points.
1272      *
1273      * @param old Old path, as described in the official documentation.
1274      * @param path New path, as described in the official documentation.
1275      * @param flags Optional additional flags.
1276      */
symlink(std::string old,std::string path,Flags<SymLink> flags=Flags<SymLink>{})1277     void symlink(std::string old, std::string path, Flags<SymLink> flags = Flags<SymLink>{}) {
1278         cleanupAndInvoke(&uv_fs_symlink, parent(), get(), old.data(), path.data(), flags, &fsGenericCallback<Type::SYMLINK>);
1279     }
1280 
1281     /**
1282      * @brief Sync [symlink](http://linux.die.net/man/2/symlink).
1283      *
1284      * Available flags are:
1285      *
1286      * * `FsReq::SymLink::DIR`: it indicates that the old path points to a
1287      * directory.
1288      * * `FsReq::SymLink::JUNCTION`: it requests that the symlink is created
1289      * using junction points.
1290      *
1291      * @param old Old path, as described in the official documentation.
1292      * @param path New path, as described in the official documentation.
1293      * @param flags Flags, as described in the official documentation.
1294      * @return True in case of success, false otherwise.
1295      */
symlinkSync(std::string old,std::string path,Flags<SymLink> flags=Flags<SymLink>{})1296     bool symlinkSync(std::string old, std::string path, Flags<SymLink> flags = Flags<SymLink>{}) {
1297         auto req = get();
1298         cleanupAndInvokeSync(&uv_fs_symlink, parent(), req, old.data(), path.data(), flags);
1299         return !(req->result < 0);
1300     }
1301 
1302     /**
1303      * @brief Async [readlink](http://linux.die.net/man/2/readlink).
1304      *
1305      * Emit a `FsEvent<FsReq::Type::READLINK>` event when completed.<br/>
1306      * Emit an ErrorEvent event in case of errors.
1307      *
1308      * @param path Path, as described in the official documentation.
1309      */
readlink(std::string path)1310     void readlink(std::string path) {
1311         cleanupAndInvoke(&uv_fs_readlink, parent(), get(), path.data(), &fsReadlinkCallback);
1312     }
1313 
1314     /**
1315      * @brief Sync [readlink](http://linux.die.net/man/2/readlink).
1316      *
1317      * @param path Path, as described in the official documentation.
1318      *
1319      * @return A `std::pair` composed as it follows:
1320      * * A boolean value that is true in case of success, false otherwise.
1321      * * A `std::pair` composed as it follows:
1322      *   * A bunch of data read from the given path.
1323      *   * The amount of data read from the given path.
1324      */
1325     std::pair<bool, std::pair<const char *, std::size_t>>
readlinkSync(std::string path)1326     readlinkSync(std::string path) {
1327         auto req = get();
1328         cleanupAndInvokeSync(&uv_fs_readlink, parent(), req, path.data());
1329         bool err = req->result < 0;
1330         return std::make_pair(!err, std::make_pair(static_cast<char *>(req->ptr), err ? 0 : std::size_t(req->result)));
1331     }
1332 
1333     /**
1334      * @brief Async [realpath](http://linux.die.net/man/3/realpath).
1335      *
1336      * Emit a `FsEvent<FsReq::Type::REALPATH>` event when completed.<br/>
1337      * Emit an ErrorEvent event in case of errors.
1338      *
1339      * @param path Path, as described in the official documentation.
1340      */
realpath(std::string path)1341     void realpath(std::string path) {
1342         cleanupAndInvoke(&uv_fs_realpath, parent(), get(), path.data(), &fsGenericCallback<Type::REALPATH>);
1343     }
1344 
1345     /**
1346      * @brief Sync [realpath](http://linux.die.net/man/3/realpath).
1347      *
1348      * @param path Path, as described in the official documentation.
1349      *
1350      * @return A `std::pair` composed as it follows:
1351      * * A boolean value that is true in case of success, false otherwise.
1352      * * The canonicalized absolute pathname.
1353      */
realpathSync(std::string path)1354     std::pair<bool, const char *> realpathSync(std::string path) {
1355         auto req = get();
1356         cleanupAndInvokeSync(&uv_fs_realpath, parent(), req, path.data());
1357         return std::make_pair(!(req->result < 0), req->path);
1358     }
1359 
1360     /**
1361      * @brief Async [chown](http://linux.die.net/man/2/chown).
1362      *
1363      * Emit a `FsEvent<FsReq::Type::CHOWN>` event when completed.<br/>
1364      * Emit an ErrorEvent event in case of errors.
1365      *
1366      * @param path Path, as described in the official documentation.
1367      * @param uid UID, as described in the official documentation.
1368      * @param gid GID, as described in the official documentation.
1369      */
chown(std::string path,Uid uid,Gid gid)1370     void chown(std::string path, Uid uid, Gid gid) {
1371         cleanupAndInvoke(&uv_fs_chown, parent(), get(), path.data(), uid, gid, &fsGenericCallback<Type::CHOWN>);
1372     }
1373 
1374     /**
1375      * @brief Sync [chown](http://linux.die.net/man/2/chown).
1376      * @param path Path, as described in the official documentation.
1377      * @param uid UID, as described in the official documentation.
1378      * @param gid GID, as described in the official documentation.
1379      * @return True in case of success, false otherwise.
1380      */
chownSync(std::string path,Uid uid,Gid gid)1381     bool chownSync(std::string path, Uid uid, Gid gid) {
1382         auto req = get();
1383         cleanupAndInvokeSync(&uv_fs_chown, parent(), req, path.data(), uid, gid);
1384         return !(req->result < 0);
1385     }
1386 
1387     /**
1388      * @brief Async [lchown](https://linux.die.net/man/2/lchown).
1389      *
1390      * Emit a `FsEvent<FsReq::Type::LCHOWN>` event when completed.<br/>
1391      * Emit an ErrorEvent event in case of errors.
1392      *
1393      * @param path Path, as described in the official documentation.
1394      * @param uid UID, as described in the official documentation.
1395      * @param gid GID, as described in the official documentation.
1396      */
lchown(std::string path,Uid uid,Gid gid)1397     void lchown(std::string path, Uid uid, Gid gid) {
1398         cleanupAndInvoke(&uv_fs_lchown, parent(), get(), path.data(), uid, gid, &fsGenericCallback<Type::LCHOWN>);
1399     }
1400 
1401     /**
1402      * @brief Sync [lchown](https://linux.die.net/man/2/lchown).
1403      * @param path Path, as described in the official documentation.
1404      * @param uid UID, as described in the official documentation.
1405      * @param gid GID, as described in the official documentation.
1406      * @return True in case of success, false otherwise.
1407      */
lchownSync(std::string path,Uid uid,Gid gid)1408     bool lchownSync(std::string path, Uid uid, Gid gid) {
1409         auto req = get();
1410         cleanupAndInvokeSync(&uv_fs_lchown, parent(), req, path.data(), uid, gid);
1411         return !(req->result < 0);
1412     }
1413 };
1414 
1415 
1416 /*! @brief Helper functions. */
1417 struct FsHelper {
1418     /**
1419      * @brief Gets the OS dependent handle.
1420      *
1421      * For a file descriptor in the C runtime, get the OS-dependent handle. On
1422      * UNIX, returns the file descriptor as-is. On Windows, this calls a system
1423      * function.<br/>
1424      * Note that the return value is still owned by the C runtime, any attempts
1425      * to close it or to use it after closing the file descriptor may lead to
1426      * malfunction.
1427      */
handleuvw::FsHelper1428     static OSFileDescriptor handle(FileHandle file) noexcept {
1429         return uv_get_osfhandle(file);
1430     }
1431 
1432     /**
1433      * @brief Gets the file descriptor.
1434      *
1435      * For a OS-dependent handle, get the file descriptor in the C runtime. On
1436      * UNIX, returns the file descriptor as-is. On Windows, this calls a system
1437      * function.<br/>
1438      * Note that the return value is still owned by the C runtime, any attempts
1439      * to close it or to use it after closing the handle may lead to
1440      * malfunction.
1441      */
openuvw::FsHelper1442     static FileHandle open(OSFileDescriptor descriptor) noexcept {
1443         return uv_open_osfhandle(descriptor);
1444     }
1445 };
1446 
1447 
1448 }
1449