uvcc
libuv C++ bindings
request-fs.hpp
1 
2 #ifndef UVCC_REQUEST_FS__HPP
3 #define UVCC_REQUEST_FS__HPP
4 
5 #include "uvcc/utility.hpp"
6 #include "uvcc/request-base.hpp"
7 #include "uvcc/handle-fs.hpp"
8 #include "uvcc/handle-io.hpp"
9 #include "uvcc/buffer.hpp"
10 #include "uvcc/loop.hpp"
11 
12 #include <uv.h>
13 
14 #ifdef _WIN32
15 #include <io.h> // _telli64()
16 #else
17 #include <unistd.h> // lseek64()
18 #endif
19 
20 #include <functional> // function
21 #include <type_traits> // enable_if_t is_convertible
22 
23 
24 namespace uv
25 {
26 
27 
28 /*! \ingroup doxy_group__request
29  \brief The base calss for filesystem requests.
30  \sa libuv API documentation: [Filesystem operations](http://docs.libuv.org/en/v1.x/fs.html#filesystem-operations).
31 
32  \warning As far as all _asynchronous_ file operations in libuv are run on the threadpool, i.e. in separate threads,
33  pay attention when running _asynchronous_ requests for sequential reading/writing from/to a file with the `_offset`
34  value specified as of < 0 which means using of the "current file position". When the next read/write request on
35  a file is scheduled after the previous one has completed and its callback has been called, everything will be OK.
36  If several _asynchronous_ requests intended for performing sequential input/output are scheduled as unchained
37  operations, some or all of them can be actually preformed simultaneously in parallel threads and the result will
38  most probably turn out to be not what was expected. Don't use the "current file position" dummy value in such a case,
39  always designate a real effective file offset for each request run. */
40 class fs : public request
41 {
42  //! \cond
43  friend class request::instance< fs >;
44  //! \endcond
45 
46 public: /*types*/
47  using uv_t = ::uv_fs_t;
48 
49  class close;
50  class read;
51  class write;
52  class sync;
53  class truncate;
54  class sendfile;
55 
56  class stat;
57  class chmod;
58  class chown;
59  class utime;
60 
61  class unlink;
62  class mkdir;
63  class mkdtemp;
64  class rmdir;
65  class scandir;
66  class rename;
67  class access;
68  class link;
69  class readlink;
70  class realpath;
71 
72 protected: /*types*/
73  //! \cond internals
74  //! \addtogroup doxy_group__internals
75  //! \{
76  struct properties : request::properties
77  {
78  uv_t *uv_req = nullptr;
79  ~properties() { if (uv_req) ::uv_fs_req_cleanup(uv_req); }
80  };
81  //! \}
82  //! \endcond
83 
84 private: /*types*/
85  using instance = request::instance< fs >;
86 
87 protected: /*constructors*/
88  //! \cond
89  fs() noexcept = default;
90 
91  explicit fs(uv_t *_uv_req) : request(reinterpret_cast< request::uv_t* >(_uv_req)) {}
92  //! \endcond
93 
94 public: /*constructors*/
95  ~fs() = default;
96 
97  fs(const fs&) = default;
98  fs& operator =(const fs&) = default;
99 
100  fs(fs&&) noexcept = default;
101  fs& operator =(fs&&) noexcept = default;
102 
103 protected: /*interface*/
104  //! \cond
105  template< ::uv_fs_type _UV_FS_TYPE_ > void init()
106  {
107  static_cast< uv_t* >(uv_req)->type = UV_FS;
108  static_cast< uv_t* >(uv_req)->fs_type = _UV_FS_TYPE_;
109  instance::from(uv_req)->properties().uv_req = static_cast< uv_t* >(uv_req);
110  }
111  //! \endcond
112 
113 public: /*interface*/
114  /*! \brief The tag indicating a subtype of the filesystem request.
115  \sa libuv API documentation: [`uv_fs_type`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_type). */
116  ::uv_fs_type fs_type() const noexcept { return static_cast< uv_t* >(uv_req)->fs_type; }
117 
118  /*! \brief The libuv loop that started this filesystem request and where completion will be reported. */
119  uv::loop loop() const noexcept { return uv::loop(static_cast< uv_t* >(uv_req)->loop); }
120 
121 public: /*conversion operators*/
122  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
123  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
124 };
125 
126 
127 
128 /*! \brief Close a file handle. */
129 class fs::close : public fs
130 {
131  //! \cond
132  friend class request::instance< close >;
133  //! \endcond
134 
135 public: /*types*/
136  using on_request_t = std::function< void(close _request) >;
137  /*!< \brief The function type of the callback called when the `close` request has completed. */
138 
139 protected: /*types*/
140  //! \cond internals
141  //! \addtogroup doxy_group__internals
142  //! \{
143  struct properties : fs::properties
144  {
145  file::uv_t *uv_handle = nullptr;
146  };
147  //! \}
148  //! \endcond
149 
150 private: /*types*/
151  using instance = request::instance< close >;
152 
153 protected: /*constructors*/
154  //! \cond
155  explicit close(uv_t *_uv_req) : fs(_uv_req) {}
156  //! \endcond
157 
158 public: /*constructors*/
159  ~close() = default;
160  close()
161  {
162  uv_req = instance::create();
163  init< UV_FS_CLOSE >();
164  }
165 
166  close(const close&) = default;
167  close& operator =(const close&) = default;
168 
169  close(close&&) noexcept = default;
170  close& operator =(close&&) noexcept = default;
171 
172 private: /*functions*/
173  template< typename = void > static void close_cb(::uv_fs_t*);
174 
175 public: /*interface*/
176  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
177 
178  /*! \brief The file which this close request has been running on.
179  \details It is guaranteed that it will be a valid instance at least within the request callback. */
180  file handle() const noexcept { return file(instance::from(uv_req)->properties().uv_handle); }
181 
182  /*! \brief Run the request. Close a `_file` handle.
183  \details If the `_file` is in reading state being put in by `io::read_start()` function,
184  the request calls `io::read_stop()` for the `_file`.
185  \sa libuv API documentation: [`uv_fs_close()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_close).
186  \sa Linux: [`close()`](http://man7.org/linux/man-pages/man2/close.2.html).
187  \note If the request callback is empty (has not been set), the request runs _synchronously_. */
188  int run(file &_file)
189  {
190  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
191 
192  file::instance::from(_file.uv_handle)->properties().is_closing = 1;
193 
194  auto instance_ptr = instance::from(uv_req);
195 
196  if (!instance_ptr->request_cb_storage.value())
197  {
198  instance_ptr->properties().uv_handle = static_cast< file::uv_t* >(_file);
199 
200  _file.read_stop();
201 
202  return uv_status(::uv_fs_close(
203  static_cast< file::uv_t* >(_file)->loop, static_cast< uv_t* >(uv_req),
204  _file.fd(),
205  nullptr
206  ));
207  }
208  else
209  {
210  file::instance::from(_file.uv_handle)->ref();
211  instance_ptr->ref();
212 
213  // instance_ptr->properties() = { static_cast< file::uv_t* >(_file) };
214  {
215  auto &properties = instance_ptr->properties();
216  properties.uv_handle = static_cast< file::uv_t* >(_file);
217  }
218 
219  _file.read_stop(); // it shall be after adding the extra reference to the handle
220 
221  uv_status(0);
222  auto uv_ret = ::uv_fs_close(
223  static_cast< file::uv_t* >(_file)->loop, static_cast< uv_t* >(uv_req),
224  _file.fd(),
225  close_cb
226  );
227  if (uv_ret < 0)
228  {
229  uv_status(uv_ret);
230  file::instance::from(_file.uv_handle)->unref();
231  instance_ptr->unref();
232  }
233 
234  return uv_ret;
235  }
236  }
237 
238 public: /*conversion operators*/
239  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
240  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
241 };
242 
243 template< typename >
244 void fs::close::close_cb(::uv_fs_t *_uv_req)
245 {
246  auto instance_ptr = instance::from(_uv_req);
247  instance_ptr->uv_error = _uv_req->result;
248 
249  auto &properties = instance_ptr->properties();
250 
251  ref_guard< file::instance > unref_file(*file::instance::from(properties.uv_handle), adopt_ref);
252  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
253 
254  auto &close_cb = instance_ptr->request_cb_storage.value();
255  if (close_cb) close_cb(close(_uv_req));
256 }
257 
258 
259 
260 /*! \brief Read data from a file. */
261 class fs::read : public fs
262 {
263  //! \cond
264  friend class request::instance< read >;
265  //! \endcond
266 
267 public: /*types*/
268  using on_request_t = std::function< void(read _request, buffer _buffer) >;
269  /*!< \brief The function type of the callback called when data was read from the file. */
270 
271 protected: /*types*/
272  //! \cond internals
273  //! \addtogroup doxy_group__internals
274  //! \{
275  struct properties : fs::properties
276  {
277  file::uv_t *uv_handle = nullptr;
278  buffer::uv_t *uv_buf = nullptr;
279  int64_t offset = 0;
280  };
281  //! \}
282  //! \endcond
283 
284 private: /*types*/
285  using instance = request::instance< read >;
286 
287 protected: /*constructors*/
288  //! \cond
289  explicit read(uv_t *_uv_req) : fs(_uv_req) {}
290  //! \endcond
291 
292 public: /*constructors*/
293  ~read() = default;
294  read()
295  {
296  uv_req = instance::create();
297  init< UV_FS_READ >();
298  }
299 
300  read(const read&) = default;
301  read& operator =(const read&) = default;
302 
303  read(read&&) noexcept = default;
304  read& operator =(read&&) noexcept = default;
305 
306 private: /*functions*/
307  template< typename = void > static void read_cb(::uv_fs_t*);
308 
309 public: /*interface*/
310  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
311 
312  /*! \brief The file which this read request has been running on.
313  \details It is guaranteed that it will be a valid instance at least within the request callback. */
314  file handle() const noexcept { return file(instance::from(uv_req)->properties().uv_handle); }
315 
316  /*! \brief The offset this read request has been performed at. */
317  int64_t offset() const noexcept { return instance::from(uv_req)->properties().offset; }
318 
319  /*! \brief Run the request. Read data from the `_file` into the buffers described by `_buf` object.
320  \sa libuv API documentation: [`uv_fs_read()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_read).
321  \sa Linux: [`preadv()`](http://man7.org/linux/man-pages/man2/preadv.2.html).
322  \note If the request callback is empty (has not been set), the request runs _synchronously_.
323  In this case the function returns a number of bytes read or relevant libuv error code.
324 
325  The `_offset` value of < 0 means using of the current file position. */
326  int run(file &_file, buffer &_buf, int64_t _offset)
327  {
328  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
329 
330  if (_offset < 0)
331  {
332 #ifdef _WIN32
333  /*! \sa Windows: [`_tell()`, `_telli64()`](https://msdn.microsoft.com/en-us/library/c3kc5e7a.aspx). */
334  _offset = _telli64(_file.fd());
335 #else
336  _offset = lseek64(_file.fd(), 0, SEEK_CUR);
337 #endif
338  }
339 
340  auto instance_ptr = instance::from(uv_req);
341 
342  if (!instance_ptr->request_cb_storage.value())
343  {
344  auto &properties = instance_ptr->properties();
345  properties.uv_handle = static_cast< file::uv_t* >(_file);
346  properties.offset = _offset;
347 
348  return uv_status(::uv_fs_read(
349  static_cast< file::uv_t* >(_file)->loop, static_cast< uv_t* >(uv_req),
350  _file.fd(),
351  static_cast< const buffer::uv_t* >(_buf), _buf.count(),
352  _offset,
353  nullptr
354  ));
355  }
356  else
357  {
358  file::instance::from(_file.uv_handle)->ref();
359  buffer::instance::from(_buf.uv_buf)->ref();
360  instance_ptr->ref();
361 
362  // instance_ptr->properties() = { static_cast< file::uv_t* >(_file), _buf.uv_buf, _offset };
363  {
364  auto &properties = instance_ptr->properties();
365  properties.uv_handle = static_cast< file::uv_t* >(_file);
366  properties.uv_buf = _buf.uv_buf;
367  properties.offset = _offset;
368  }
369 
370  uv_status(0);
371  auto uv_ret = ::uv_fs_read(
372  static_cast< file::uv_t* >(_file)->loop, static_cast< uv_t* >(uv_req),
373  _file.fd(),
374  static_cast< const buffer::uv_t* >(_buf), _buf.count(),
375  _offset,
376  read_cb
377  );
378  if (uv_ret < 0)
379  {
380  uv_status(uv_ret);
381  file::instance::from(_file.uv_handle)->unref();
382  buffer::instance::from(_buf.uv_buf)->unref();
383  instance_ptr->unref();
384  }
385 
386  return uv_ret;
387  }
388  }
389 
390 public: /*conversion operators*/
391  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
392  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
393 };
394 
395 template< typename >
396 void fs::read::read_cb(::uv_fs_t *_uv_req)
397 {
398  auto instance_ptr = instance::from(_uv_req);
399  instance_ptr->uv_error = _uv_req->result;
400 
401  auto &properties = instance_ptr->properties();
402 
403  ref_guard< file::instance > unref_file(*file::instance::from(properties.uv_handle), adopt_ref);
404  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
405 
406  auto &read_cb = instance_ptr->request_cb_storage.value();
407  if (read_cb)
408  read_cb(read(_uv_req), buffer(properties.uv_buf, adopt_ref));
409  else
410  buffer::instance::from(properties.uv_buf)->unref();
411 }
412 
413 
414 
415 /*! \brief Write data to a file. */
416 class fs::write : public fs
417 {
418  //! \cond
419  friend class request::instance< write >;
420  friend class output;
421  //! \endcond
422 
423 public: /*types*/
424  using on_request_t = std::function< void(write _request, buffer _buffer) >;
425  /*!< \brief The function type of the callback called when data was written to the file. */
426 
427 protected: /*types*/
428  //! \cond internals
429  //! \addtogroup doxy_group__internals
430  //! \{
431  struct properties : fs::properties
432  {
433  file::uv_t *uv_handle = nullptr;
434  buffer::uv_t *uv_buf = nullptr;
435  int64_t offset = 0;
436  std::size_t pending_size = 0;
437  };
438  //! \}
439  //! \endcond
440 
441 private: /*types*/
442  using instance = request::instance< write >;
443 
444 protected: /*constructors*/
445  //! \cond
446  explicit write(uv_t *_uv_req) : fs(_uv_req) {}
447  //! \endcond
448 
449 public: /*constructors*/
450  ~write() = default;
451  write()
452  {
453  uv_req = instance::create();
454  init< UV_FS_WRITE >();
455  }
456 
457  write(const write&) = default;
458  write& operator =(const write&) = default;
459 
460  write(write&&) noexcept = default;
461  write& operator =(write&&) noexcept = default;
462 
463 private: /*functions*/
464  template< typename = void > static void write_cb(::uv_fs_t*);
465 
466 public: /*interface*/
467  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
468 
469  /*! \brief The file which this write request has been running on.
470  \details It is guaranteed that it will be a valid instance at least within the request callback. */
471  file handle() const noexcept { return file(instance::from(uv_req)->properties().uv_handle); }
472 
473  /*! \brief The offset this write request has been performed at. */
474  int64_t offset() const noexcept { return instance::from(uv_req)->properties().offset; }
475 
476  /*! \brief Run the request. Write data to the `_file` from the buffers described by `_buf` object.
477  \sa libuv API documentation: [`uv_fs_write()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_write).
478  \sa Linux: [`pwritev()`](http://man7.org/linux/man-pages/man2/pwritev.2.html).
479  \note If the request callback is empty (has not been set), the request runs _synchronously_.
480  In this case the function returns a number of bytes written or relevant libuv error code.
481 
482  The `_offset` value of < 0 means using of the current file position. */
483  int run(file &_file, const buffer &_buf, int64_t _offset)
484  {
485  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
486 
487  if (_offset < 0)
488  {
489 #ifdef _WIN32
490  /*! \sa Windows: [`_tell()`, `_telli64()`](https://msdn.microsoft.com/en-us/library/c3kc5e7a.aspx). */
491  _offset = _telli64(_file.fd());
492 #else
493  _offset = lseek64(_file.fd(), 0, SEEK_CUR);
494 #endif
495  }
496 
497  auto instance_ptr = instance::from(uv_req);
498 
499  if (!instance_ptr->request_cb_storage.value())
500  {
501  auto &properties = instance_ptr->properties();
502  properties.uv_handle = static_cast< file::uv_t* >(_file);
503  properties.offset = _offset;
504 
505  return uv_status(::uv_fs_write(
506  static_cast< file::uv_t* >(_file)->loop, static_cast< uv_t* >(uv_req),
507  _file.fd(),
508  static_cast< const buffer::uv_t* >(_buf), _buf.count(),
509  _offset,
510  nullptr
511  ));
512  }
513  else
514  {
515  file::instance::from(_file.uv_handle)->ref();
516  buffer::instance::from(_buf.uv_buf)->ref();
517  instance_ptr->ref();
518 
519  std::size_t wr_size = 0;
520  for (std::size_t i = 0, buf_count = _buf.count(); i < buf_count; ++i) wr_size += _buf.len(i);
521 
522  // instance_ptr->properties() = { static_cast< file::uv_t* >(_file), _buf.uv_buf, _offset, wr_size };
523  {
524  auto &properties = instance_ptr->properties();
525  properties.uv_handle = static_cast< file::uv_t* >(_file);
526  properties.uv_buf = _buf.uv_buf;
527  properties.offset = _offset;
528  properties.pending_size = wr_size;
529  }
530 
531  file::instance::from(_file.uv_handle)->properties().write_queue_size += wr_size;
532 
533  uv_status(0);
534  auto uv_ret = ::uv_fs_write(
535  static_cast< file::uv_t* >(_file)->loop, static_cast< uv_t* >(uv_req),
536  _file.fd(),
537  static_cast< const buffer::uv_t* >(_buf), _buf.count(),
538  _offset,
539  write_cb
540  );
541  if (uv_ret < 0)
542  {
543  uv_status(uv_ret);
544 
545  file::instance::from(_file.uv_handle)->properties().write_queue_size -= wr_size;
546 
547  file::instance::from(_file.uv_handle)->unref();
548  buffer::instance::from(_buf.uv_buf)->unref();
549  instance_ptr->unref();
550  }
551 
552  return uv_ret;
553  }
554  }
555 
556  /*! \brief Try to execute the request _synchronously_ if it can be completed immediately...
557  \details ...i.e. if `(_file.write_queue_size() == 0)` and without calling the request callback.\n
558  The `_offset` value of < 0 means using of the current file position.
559  \returns A number of bytes written, or relevant libuv error code, or `UV_EAGAIN` error code when
560  the data can’t be written immediately. */
561  int try_write(file &_file, const buffer &_buf, int64_t _offset)
562  {
563  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
564 
565  if (_file.write_queue_size() != 0) return uv_status(UV_EAGAIN);
566 
567  if (_offset < 0)
568  {
569 #ifdef _WIN32
570  /*! \sa Windows: [`_tell()`, `_telli64()`](https://msdn.microsoft.com/en-us/library/c3kc5e7a.aspx). */
571  _offset = _telli64(_file.fd());
572 #else
573  _offset = lseek64(_file.fd(), 0, SEEK_CUR);
574 #endif
575  }
576 
577  auto &properties = instance::from(uv_req)->properties();
578  properties.uv_handle = static_cast< file::uv_t* >(_file);
579  properties.offset = _offset;
580 
581  auto uv_ret = uv_status(::uv_fs_write(
582  static_cast< file::uv_t* >(_file)->loop, static_cast< uv_t* >(uv_req),
583  _file.fd(),
584  static_cast< const buffer::uv_t* >(_buf), _buf.count(),
585  _offset,
586  nullptr
587  ));
588 
589  return uv_ret;
590  }
591 
592 public: /*conversion operators*/
593  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
594  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
595 };
596 
597 template< typename >
598 void fs::write::write_cb(::uv_fs_t *_uv_req)
599 {
600  auto instance_ptr = instance::from(_uv_req);
601  instance_ptr->uv_error = _uv_req->result;
602 
603  auto &properties = instance_ptr->properties();
604  auto file_instance_ptr = file::instance::from(properties.uv_handle);
605 
606  ref_guard< file::instance > unref_file(*file_instance_ptr, adopt_ref);
607  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
608 
609  // if (_uv_req->result > 0) file_instance_ptr->properties().write_queue_size -= _uv_req->result; // don't mistakenly use the actual written bytes amount
610  file_instance_ptr->properties().write_queue_size -= properties.pending_size;
611 
612  auto &write_cb = instance_ptr->request_cb_storage.value();
613  if (write_cb)
614  write_cb(write(_uv_req), buffer(properties.uv_buf, adopt_ref));
615  else
616  buffer::instance::from(properties.uv_buf)->unref();
617 }
618 
619 
620 
621 /*! \brief Synchronize a file's state with storage device. */
622 class fs::sync : public fs
623 {
624  //! \cond
625  friend class request::instance< sync >;
626  //! \endcond
627 
628 public: /*types*/
629  using on_request_t = std::function< void(sync _request) >;
630  /*!< \brief The function type of the callback called when the `sync` request has completed. */
631 
632 protected: /*types*/
633  //! \cond internals
634  //! \addtogroup doxy_group__internals
635  //! \{
636  struct properties : fs::properties
637  {
638  file::uv_t *uv_handle = nullptr;
639  };
640  //! \}
641  //! \endcond
642 
643 private: /*types*/
644  using instance = request::instance< sync >;
645 
646 protected: /*constructors*/
647  //! \cond
648  explicit sync(uv_t *_uv_req) : fs(_uv_req) {}
649  //! \endcond
650 
651 public: /*constructors*/
652  ~sync() = default;
653  sync()
654  {
655  uv_req = instance::create();
656  init< UV_FS_FSYNC >();
657  }
658 
659  sync(const sync&) = default;
660  sync& operator =(const sync&) = default;
661 
662  sync(sync&&) noexcept = default;
663  sync& operator =(sync&&) noexcept = default;
664 
665 private: /*functions*/
666  template< typename = void > static void sync_cb(::uv_fs_t*);
667 
668 public: /*interface*/
669  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
670 
671  /*! \brief The file which this sync request has been running on.
672  \details It is guaranteed that it will be a valid instance at least within the request callback. */
673  file handle() const noexcept { return file(instance::from(uv_req)->properties().uv_handle); }
674 
675  /*! \brief Run the request. Flush the data of the `_file` to the storage device.
676  \sa libuv API documentation: [`uv_fs_fsync()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_fsync),
677  [`uv_fs_fdatasync()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_fdatasync).
678  \sa Linux: [`fsync()`](http://man7.org/linux/man-pages/man2/fsync.2.html),
679  [`fdatasync()`](http://man7.org/linux/man-pages/man2/fdatasync.2.html).
680 
681  By default [`uv_fs_fdatasync()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_fdatasync) libuv API function is used.
682  \note If the request callback is empty (has not been set), the request runs _synchronously_. */
683  int run(file &_file, bool _flush_all_metadata = false)
684  {
685  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
686 
687  auto uv_fs_sync_func_ptr = _flush_all_metadata ? ::uv_fs_fsync : ::uv_fs_fdatasync;
688  auto instance_ptr = instance::from(uv_req);
689 
690  if (!instance_ptr->request_cb_storage.value())
691  {
692  instance_ptr->properties().uv_handle = static_cast< file::uv_t* >(_file);
693 
694  return uv_status(uv_fs_sync_func_ptr(
695  static_cast< file::uv_t* >(_file)->loop, static_cast< uv_t* >(uv_req),
696  _file.fd(),
697  nullptr
698  ));
699  }
700  else
701  {
702  file::instance::from(_file.uv_handle)->ref();
703  instance_ptr->ref();
704 
705  // instance_ptr->properties() = { static_cast< file::uv_t* >(_file) };
706  {
707  auto &properties = instance_ptr->properties();
708  properties.uv_handle = static_cast< file::uv_t* >(_file);
709  }
710 
711  uv_status(0);
712  auto uv_ret = uv_fs_sync_func_ptr(
713  static_cast< file::uv_t* >(_file)->loop, static_cast< uv_t* >(uv_req),
714  _file.fd(),
715  sync_cb
716  );
717  if (uv_ret < 0)
718  {
719  uv_status(uv_ret);
720  file::instance::from(_file.uv_handle)->unref();
721  instance_ptr->unref();
722  }
723 
724  return uv_ret;
725  }
726  }
727 
728 public: /*conversion operators*/
729  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
730  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
731 };
732 
733 template< typename >
734 void fs::sync::sync_cb(::uv_fs_t *_uv_req)
735 {
736  auto instance_ptr = instance::from(_uv_req);
737  instance_ptr->uv_error = _uv_req->result;
738 
739  auto &properties = instance_ptr->properties();
740 
741  ref_guard< file::instance > unref_file(*file::instance::from(properties.uv_handle), adopt_ref);
742  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
743 
744  auto &sync_cb = instance_ptr->request_cb_storage.value();
745  if (sync_cb) sync_cb(sync(_uv_req));
746 }
747 
748 
749 
750 /*! \brief Truncate a file to a specified length. */
751 class fs::truncate : public fs
752 {
753  //! \cond
754  friend class request::instance< truncate >;
755  //! \endcond
756 
757 public: /*types*/
758  using on_request_t = std::function< void(truncate _request) >;
759  /*!< \brief The function type of the callback called when the `truncate` request has completed. */
760 
761 protected: /*types*/
762  //! \cond internals
763  //! \addtogroup doxy_group__internals
764  //! \{
765  struct properties : fs::properties
766  {
767  file::uv_t *uv_handle = nullptr;
768  int64_t offset = 0;
769  };
770  //! \}
771  //! \endcond
772 
773 private: /*types*/
774  using instance = request::instance< truncate >;
775 
776 protected: /*constructors*/
777  //! \cond
778  explicit truncate(uv_t *_uv_req) : fs(_uv_req) {}
779  //! \endcond
780 
781 public: /*constructors*/
782  ~truncate() = default;
783  truncate()
784  {
785  uv_req = instance::create();
786  init< UV_FS_FTRUNCATE >();
787  }
788 
789  truncate(const truncate&) = default;
790  truncate& operator =(const truncate&) = default;
791 
792  truncate(truncate&&) noexcept = default;
793  truncate& operator =(truncate&&) noexcept = default;
794 
795 private: /*functions*/
796  template< typename = void > static void truncate_cb(::uv_fs_t*);
797 
798 public: /*interface*/
799  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
800 
801  /*! \brief The file which this truncate request has been running on.
802  \details It is guaranteed that it will be a valid instance at least within the request callback. */
803  file handle() const noexcept { return file(instance::from(uv_req)->properties().uv_handle); }
804 
805  /*! \brief The offset this trucate request has been performed at. */
806  int64_t offset() const noexcept { return instance::from(uv_req)->properties().offset; }
807 
808  /*! \brief Run the request. Truncate the `_file` to a size of `_offset` bytes.
809  \sa libuv API documentation: [`uv_fs_ftruncate()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_ftruncate).
810  \sa Linux: [`ftruncate()`](http://man7.org/linux/man-pages/man2/ftruncate.2.html).
811  \note If the request callback is empty (has not been set), the request runs _synchronously_.
812 
813  The `_offset` value of < 0 means using of the current file position. */
814  int run(file &_file, int64_t _offset)
815  {
816  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
817 
818  if (_offset < 0)
819  {
820 #ifdef _WIN32
821  /*! \sa Windows: [`_tell()`, `_telli64()`](https://msdn.microsoft.com/en-us/library/c3kc5e7a.aspx). */
822  _offset = _telli64(_file.fd());
823 #else
824  _offset = lseek64(_file.fd(), 0, SEEK_CUR);
825 #endif
826  }
827 
828  auto instance_ptr = instance::from(uv_req);
829 
830  if (!instance_ptr->request_cb_storage.value())
831  {
832  auto &properties = instance_ptr->properties();
833  properties.uv_handle = static_cast< file::uv_t* >(_file);
834  properties.offset = _offset;
835 
836  return uv_status(::uv_fs_ftruncate(
837  static_cast< file::uv_t* >(_file)->loop, static_cast< uv_t* >(uv_req),
838  _file.fd(),
839  _offset,
840  nullptr
841  ));
842  }
843  else
844  {
845  file::instance::from(_file.uv_handle)->ref();
846  instance_ptr->ref();
847 
848  // instance_ptr->properties() = { static_cast< file::uv_t* >(_file), _offset };
849  {
850  auto &properties = instance_ptr->properties();
851  properties.uv_handle = static_cast< file::uv_t* >(_file);
852  properties.offset = _offset;
853  }
854 
855  uv_status(0);
856  auto uv_ret = ::uv_fs_ftruncate(
857  static_cast< file::uv_t* >(_file)->loop, static_cast< uv_t* >(uv_req),
858  _file.fd(),
859  _offset,
860  truncate_cb
861  );
862  if (uv_ret < 0)
863  {
864  uv_status(uv_ret);
865  file::instance::from(_file.uv_handle)->unref();
866  instance_ptr->unref();
867  }
868 
869  return uv_ret;
870  }
871  }
872 
873 public: /*conversion operators*/
874  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
875  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
876 };
877 
878 template< typename >
879 void fs::truncate::truncate_cb(::uv_fs_t *_uv_req)
880 {
881  auto instance_ptr = instance::from(_uv_req);
882  instance_ptr->uv_error = _uv_req->result;
883 
884  auto &properties = instance_ptr->properties();
885 
886  ref_guard< file::instance > unref_file(*file::instance::from(properties.uv_handle), adopt_ref);
887  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
888 
889  auto &truncate_cb = instance_ptr->request_cb_storage.value();
890  if (truncate_cb) truncate_cb(truncate(_uv_req));
891 }
892 
893 
894 
895 /*! \brief Transfer data between file descriptors. */
896 class fs::sendfile : public fs
897 {
898  //! \cond
899  friend class request::instance< sendfile >;
900  friend class output;
901  //! \endcond
902 
903 public: /*types*/
904  using on_request_t = std::function< void(sendfile _request) >;
905  /*!< \brief The function type of the callback called when the `sendfile` request has completed. */
906 
907 protected: /*types*/
908  //! \cond internals
909  //! \addtogroup doxy_group__internals
910  //! \{
911  struct properties : fs::properties
912  {
913  io::uv_t *uv_handle_out = nullptr;
914  file::uv_t *uv_handle_in = nullptr;
915  int64_t offset = 0;
916  std::size_t pending_size = 0;
917  };
918  //! \}
919  //! \endcond
920 
921 private: /*types*/
922  using instance = request::instance< sendfile >;
923 
924  struct fd
925  {
926  static constexpr const bool is_convertible_v = std::is_convertible< ::uv_os_fd_t, ::uv_file >::value;
927 
928  template< bool _is_convertible_ = is_convertible_v >
929  static std::enable_if_t< !_is_convertible_, ::uv_file > try_convert(::uv_os_fd_t) { return -1; }
930  template< bool _is_convertible_ = is_convertible_v >
931  static std::enable_if_t< _is_convertible_, ::uv_file > try_convert(::uv_os_fd_t _os_fd) { return _os_fd; }
932  };
933 
934 protected: /*constructors*/
935  //! \cond
936  explicit sendfile(uv_t *_uv_req) : fs(_uv_req) {}
937  //! \endcond
938 
939 public: /*constructors*/
940  ~sendfile() = default;
941  sendfile()
942  {
943  uv_req = instance::create();
944  init< UV_FS_SENDFILE >();
945  }
946 
947  sendfile(const sendfile&) = default;
948  sendfile& operator =(const sendfile&) = default;
949 
950  sendfile(sendfile&&) noexcept = default;
951  sendfile& operator =(sendfile&&) noexcept = default;
952 
953 private: /*functions*/
954  template< typename = void > static void sendfile_cb(::uv_fs_t*);
955 
956 public: /*interface*/
957  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
958 
959  /*! \brief The I/O endpoint which this sendfile request has been writing data to.
960  \details It is guaranteed that it will be a valid instance at least within the request callback. */
961  io handle_out() const noexcept { return io(instance::from(uv_req)->properties().uv_handle_out); }
962  /*! \brief The file which this sendfile request has been reading data from.
963  \details It is guaranteed that it will be a valid instance at least within the request callback. */
964  file handle_in() const noexcept { return file(instance::from(uv_req)->properties().uv_handle_in); }
965 
966  /*! \brief The offset this sendfile request has been started to read data at from input file. */
967  int64_t offset() const noexcept { return instance::from(uv_req)->properties().offset; }
968 
969  /*! \brief Run the request. Read data from the `_in` file starting from the `_offset` and copy it to the `_out` endpoint.
970  \details `_length` is the number of bytes to be transferred.
971  \sa libuv API documentation: [`uv_fs_sendfile()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_sendfile).
972  \sa Linux: [`sendfile()`](http://man7.org/linux/man-pages/man2/sendfile.2.html).
973  \note If the request callback is empty (has not been set), the request runs _synchronously_.
974  In this case the function returns a number of bytes copied or relevant libuv error code.
975 
976  The `_offset` value of < 0 means using of the current file position. */
977  int run(io &_out, file &_in, int64_t _offset, std::size_t _length)
978  {
979  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
980 
981  ::uv_file out = _out.type() == UV_FILE ? static_cast< file& >(_out).fd() : fd::try_convert(_out.fileno());
982  if (out == -1) return UV_EBADF;
983 
984  if (_offset < 0)
985  {
986 #ifdef _WIN32
987  /*! \sa Windows: [`_tell()`, `_telli64()`](https://msdn.microsoft.com/en-us/library/c3kc5e7a.aspx). */
988  _offset = _telli64(_in.fd());
989 #else
990  _offset = lseek64(_in.fd(), 0, SEEK_CUR);
991 #endif
992  }
993 
994  auto instance_ptr = instance::from(uv_req);
995 
996  if (!instance_ptr->request_cb_storage.value())
997  {
998  auto &properties = instance_ptr->properties();
999  properties.uv_handle_out = static_cast< io::uv_t* >(_out);
1000  properties.uv_handle_in = static_cast< file::uv_t* >(_in);
1001  properties.offset = _offset;
1002 
1003  return uv_status(::uv_fs_sendfile(
1004  static_cast< file::uv_t* >(_in)->loop, static_cast< uv_t* >(uv_req),
1005  out, _in.fd(),
1006  _offset, _length,
1007  nullptr
1008  ));
1009  }
1010  else
1011  {
1012  io::instance::from(_out.uv_handle)->ref();
1013  file::instance::from(_in.uv_handle)->ref();
1014  instance_ptr->ref();
1015 
1016  // instance_ptr->properties() = { static_cast< io::uv_t* >(_out), static_cast< file::uv_t* >(_in), _offset, _length };
1017  {
1018  auto &properties = instance_ptr->properties();
1019  properties.uv_handle_out = static_cast< io::uv_t* >(_out);
1020  properties.uv_handle_in = static_cast< file::uv_t* >(_in);
1021  properties.offset = _offset;
1022  properties.pending_size = _length;
1023  }
1024 
1025  if (_out.type() == UV_FILE) file::instance::from(_out.uv_handle)->properties().write_queue_size += _length;
1026 
1027  uv_status(0);
1028  int uv_ret = ::uv_fs_sendfile(
1029  static_cast< file::uv_t* >(_in)->loop, static_cast< uv_t* >(uv_req),
1030  out, _in.fd(),
1031  _offset, _length,
1032  sendfile_cb
1033  );
1034  if (uv_ret < 0)
1035  {
1036  uv_status(uv_ret);
1037 
1038  if (_out.type() == UV_FILE) file::instance::from(_out.uv_handle)->properties().write_queue_size -= _length;
1039 
1040  io::instance::from(_out.uv_handle)->unref();
1041  file::instance::from(_in.uv_handle)->unref();
1042  instance_ptr->unref();
1043  }
1044 
1045  return uv_ret;
1046  }
1047  }
1048 
1049 public: /*conversion operators*/
1050  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
1051  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
1052 };
1053 
1054 template< typename >
1055 void fs::sendfile::sendfile_cb(::uv_fs_t *_uv_req)
1056 {
1057  auto instance_ptr = instance::from(_uv_req);
1058  instance_ptr->uv_error = _uv_req->result;
1059 
1060  auto &properties = instance_ptr->properties();
1061  auto handle_out_instance_ptr = io::instance::from(properties.uv_handle_out);
1062  auto handle_in_instance_ptr = file::instance::from(properties.uv_handle_in);
1063 
1064  ref_guard< io::instance > unref_out(*handle_out_instance_ptr, adopt_ref);
1065  ref_guard< file::instance > unref_in(*handle_in_instance_ptr, adopt_ref);
1066  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
1067 
1068  if (handle_out_instance_ptr->uv_interface()->type(properties.uv_handle_out) == UV_FILE)
1069  reinterpret_cast< file::instance* >(handle_out_instance_ptr)->properties().write_queue_size -= properties.pending_size;
1070 
1071  auto &sendfile_cb = instance_ptr->request_cb_storage.value();
1072  if (sendfile_cb) sendfile_cb(sendfile(_uv_req));
1073 }
1074 
1075 
1076 
1077 /*! \brief Get information about a file. */
1078 class fs::stat : public fs
1079 {
1080  //! \cond
1081  friend class request::instance< stat >;
1082  //! \endcond
1083 
1084 public: /*types*/
1085  using on_request_t = std::function< void(stat _request) >;
1086  /*!< \brief The function type of the callback called when the `stat` request has completed. */
1087 
1088 protected: /*types*/
1089  //! \cond internals
1090  //! \addtogroup doxy_group__internals
1091  //! \{
1092  struct properties : fs::properties
1093  {
1094  file::uv_t *uv_handle = nullptr;
1095  };
1096  //! \}
1097  //! \endcond
1098 
1099 private: /*types*/
1100  using instance = request::instance< stat >;
1101 
1102 protected: /*constructors*/
1103  //! \cond
1104  explicit stat(uv_t *_uv_req) : fs(_uv_req) {}
1105  //! \endcond
1106 
1107 public: /*constructors*/
1108  ~stat() = default;
1109  stat()
1110  {
1111  uv_req = instance::create();
1112  init< UV_FS_STAT >();
1113  }
1114 
1115  stat(const stat&) = default;
1116  stat& operator =(const stat&) = default;
1117 
1118  stat(stat&&) noexcept = default;
1119  stat& operator =(stat&&) noexcept = default;
1120 
1121 private: /*functions*/
1122  template< typename = void > static void stat_cb(::uv_fs_t*);
1123 
1124 public: /*interface*/
1125  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
1126 
1127  /*! \brief The file which this stat request has been running on.
1128  \details It is guaranteed that it will be a valid instance at least within the request callback.\n\n
1129  If the request was applied to a file path then the handle of the returned file is closed (i.e. `uv::file::is_closing() == 1`). */
1130  file handle() const noexcept
1131  {
1132  auto uv_handle = instance::from(uv_req)->properties().uv_handle;
1133  return uv_handle ? file(uv_handle) : file(static_cast< uv_t* >(uv_req)->loop, -1, static_cast< uv_t* >(uv_req)->path);
1134  }
1135 
1136  /*! \brief The file path affected by request.
1137  \sa libuv API documentation: [`uv_fs_t.path`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_t.path). */
1138  const char* path() const noexcept
1139  {
1140  auto uv_handle = instance::from(uv_req)->properties().uv_handle;
1141  return uv_handle ? uv_handle->path : static_cast< uv_t* >(uv_req)->path;
1142  }
1143 
1144  /*! \brief The result of the stat request.
1145  \sa libuv API documentation: [`uv_stat_t`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_stat_t),
1146  [`uv_timespec_t`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_timespec_t),
1147  [`uv_fs_t.statbuf`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_t.statbuf).
1148  \sa Linux: [`stat()`](http://man7.org/linux/man-pages/man2/stat.2.html),
1149  [`fstat()`](http://man7.org/linux/man-pages/man2/fstat.2.html),
1150  [`lstat()`](http://man7.org/linux/man-pages/man2/lstat.2.html). */
1151  const ::uv_stat_t& result() const noexcept { return static_cast< uv_t* >(uv_req)->statbuf; }
1152 
1153  /*! \brief Run the request. Get status information on a file or directory specified by `_path`.
1154  \sa libuv API documentation: [`uv_fs_stat()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_stat),
1155  [`uv_fs_lstat()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_lstat).
1156  \sa Linux: [`stat()`](http://man7.org/linux/man-pages/man2/stat.2.html),
1157  [`lstat()`](http://man7.org/linux/man-pages/man2/lstat.2.html).
1158  \note If the request callback is empty (has not been set), the request runs _synchronously_. */
1159  int run(uv::loop &_loop, const char* _path, bool _follow_symlinks = false)
1160  {
1161  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
1162 
1163  auto uv_fs_stat_func_ptr = _follow_symlinks ? ::uv_fs_stat : ::uv_fs_lstat;
1164  auto instance_ptr = instance::from(uv_req);
1165 
1166  if (!instance_ptr->request_cb_storage.value())
1167  {
1168  instance_ptr->properties().uv_handle = nullptr;
1169 
1170  return uv_status(uv_fs_stat_func_ptr(
1171  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
1172  _path,
1173  nullptr
1174  ));
1175  }
1176  else
1177  {
1178  instance_ptr->ref();
1179 
1180  // instance_ptr->properties() = { nullptr };
1181  {
1182  auto &properties = instance_ptr->properties();
1183  properties.uv_handle = nullptr;
1184  }
1185 
1186  uv_status(0);
1187  auto uv_ret = uv_fs_stat_func_ptr(
1188  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
1189  _path,
1190  stat_cb
1191  );
1192  if (uv_ret < 0)
1193  {
1194  uv_status(uv_ret);
1195  instance_ptr->unref();
1196  }
1197 
1198  return uv_ret;
1199  }
1200  }
1201 
1202  /*! \brief Run the request. Get status information about the open `_file`.
1203  \sa libuv API documentation: [`uv_fs_fstat()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_fstat).
1204  \sa Linux: [`fstat()`](http://man7.org/linux/man-pages/man2/fstat.2.html).
1205  \note If the request callback is empty (has not been set), the request runs _synchronously_. */
1206  int run(file &_file)
1207  {
1208  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
1209 
1210  auto instance_ptr = instance::from(uv_req);
1211 
1212  if (!instance_ptr->request_cb_storage.value())
1213  {
1214  instance_ptr->properties().uv_handle = static_cast< file::uv_t* >(_file);
1215 
1216  return uv_status(::uv_fs_fstat(
1217  static_cast< file::uv_t* >(_file)->loop, static_cast< uv_t* >(uv_req),
1218  _file.fd(),
1219  nullptr
1220  ));
1221  }
1222  else
1223  {
1224  file::instance::from(_file.uv_handle)->ref();
1225  instance_ptr->ref();
1226 
1227  // instance_ptr->properties() = { static_cast< file::uv_t* >(_file) };
1228  {
1229  auto &properties = instance_ptr->properties();
1230  properties.uv_handle = static_cast< file::uv_t* >(_file);
1231  }
1232 
1233  uv_status(0);
1234  auto uv_ret = ::uv_fs_fstat(
1235  static_cast< file::uv_t* >(_file)->loop, static_cast< uv_t* >(uv_req),
1236  _file.fd(),
1237  stat_cb
1238  );
1239  if (uv_ret < 0)
1240  {
1241  uv_status(uv_ret);
1242  file::instance::from(_file.uv_handle)->unref();
1243  instance_ptr->unref();
1244  }
1245 
1246  return uv_ret;
1247  }
1248  }
1249 
1250 public: /*conversion operators*/
1251  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
1252  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
1253 };
1254 
1255 template< typename >
1256 void fs::stat::stat_cb(::uv_fs_t *_uv_req)
1257 {
1258  auto instance_ptr = instance::from(_uv_req);
1259  instance_ptr->uv_error = _uv_req->result;
1260 
1261  auto &properties = instance_ptr->properties();
1262 
1263  if (properties.uv_handle)
1264  {
1265  ref_guard< file::instance > unref_file(*file::instance::from(properties.uv_handle), adopt_ref);
1266  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
1267 
1268  auto &stat_cb = instance_ptr->request_cb_storage.value();
1269  if (stat_cb) stat_cb(stat(_uv_req));
1270  }
1271  else
1272  {
1273  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
1274 
1275  auto &stat_cb = instance_ptr->request_cb_storage.value();
1276  if (stat_cb) stat_cb(stat(_uv_req));
1277  }
1278 }
1279 
1280 
1281 
1282 /*! \brief Change a file mode bits. */
1283 class fs::chmod : public fs
1284 {
1285  //! \cond
1286  friend class request::instance< chmod >;
1287  //! \endcond
1288 
1289 public: /*types*/
1290  using on_request_t = std::function< void(chmod _request) >;
1291  /*!< \brief The function type of the callback called when the `chmod` request has completed. */
1292 
1293 protected: /*types*/
1294  //! \cond internals
1295  //! \addtogroup doxy_group__internals
1296  //! \{
1297  struct properties : fs::properties
1298  {
1299  file::uv_t *uv_handle = nullptr;
1300  };
1301  //! \}
1302  //! \endcond
1303 
1304 private: /*types*/
1305  using instance = request::instance< chmod >;
1306 
1307 protected: /*constructors*/
1308  //! \cond
1309  explicit chmod(uv_t *_uv_req) : fs(_uv_req) {}
1310  //! \endcond
1311 
1312 public: /*constructors*/
1313  ~chmod() = default;
1314  chmod()
1315  {
1316  uv_req = instance::create();
1317  init< UV_FS_CHMOD >();
1318  }
1319 
1320  chmod(const chmod&) = default;
1321  chmod& operator =(const chmod&) = default;
1322 
1323  chmod(chmod&&) noexcept = default;
1324  chmod& operator =(chmod&&) noexcept = default;
1325 
1326 private: /*functions*/
1327  template< typename = void > static void chmod_cb(::uv_fs_t*);
1328 
1329 public: /*interface*/
1330  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
1331 
1332  /*! \brief The file which this chmod request has been running on.
1333  \details It is guaranteed that it will be a valid instance at least within the request callback.\n\n
1334  If the request was applied to a file path then the handle of the returned file is closed (i.e. `uv::file::is_closing() == 1`). */
1335  file handle() const noexcept
1336  {
1337  auto uv_handle = instance::from(uv_req)->properties().uv_handle;
1338  return uv_handle ? file(uv_handle) : file(static_cast< uv_t* >(uv_req)->loop, -1, static_cast< uv_t* >(uv_req)->path);
1339  }
1340 
1341  /*! \brief The file path affected by request.
1342  \sa libuv API documentation: [`uv_fs_t.path`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_t.path). */
1343  const char* path() const noexcept
1344  {
1345  auto uv_handle = instance::from(uv_req)->properties().uv_handle;
1346  return uv_handle ? uv_handle->path : static_cast< uv_t* >(uv_req)->path;
1347  }
1348 
1349  /*! \brief Run the request. Change permissions of a file or directory specified by `_path`.
1350  \sa libuv API documentation: [`uv_fs_chmod()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_chmod).
1351  \sa Linux: [`chmod()`](http://man7.org/linux/man-pages/man2/chmod.2.html),\n
1352  Windows: [`_chmod()`](https://msdn.microsoft.com/en-us/library/1z319a54.aspx).
1353  \note If the request callback is empty (has not been set), the request runs _synchronously_. */
1354  int run(uv::loop &_loop, const char* _path, int _mode)
1355  {
1356  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
1357 
1358  auto instance_ptr = instance::from(uv_req);
1359 
1360  if (!instance_ptr->request_cb_storage.value())
1361  {
1362  instance_ptr->properties().uv_handle = nullptr;
1363 
1364  return uv_status(::uv_fs_chmod(
1365  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
1366  _path, _mode,
1367  nullptr
1368  ));
1369  }
1370  else
1371  {
1372  instance_ptr->ref();
1373 
1374  // instance_ptr->properties() = { nullptr };
1375  {
1376  auto &properties = instance_ptr->properties();
1377  properties.uv_handle = nullptr;
1378  }
1379 
1380  uv_status(0);
1381  auto uv_ret = ::uv_fs_chmod(
1382  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
1383  _path, _mode,
1384  chmod_cb
1385  );
1386  if (uv_ret < 0)
1387  {
1388  uv_status(uv_ret);
1389  instance_ptr->unref();
1390  }
1391 
1392  return uv_ret;
1393  }
1394  }
1395 
1396  /*! \brief Run the request. Change permissions of the open `_file`.
1397  \sa libuv API documentation: [`uv_fs_fchmod()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_fchmod).
1398  \sa Linux: [`fchmod()`](http://man7.org/linux/man-pages/man2/fchmod.2.html).
1399  \note If the request callback is empty (has not been set), the request runs _synchronously_. */
1400  int run(file &_file, int _mode)
1401  {
1402  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
1403 
1404  auto instance_ptr = instance::from(uv_req);
1405 
1406  if (!instance_ptr->request_cb_storage.value())
1407  {
1408  instance_ptr->properties().uv_handle = static_cast< file::uv_t* >(_file);
1409 
1410  return uv_status(::uv_fs_fchmod(
1411  static_cast< file::uv_t* >(_file)->loop, static_cast< uv_t* >(uv_req),
1412  _file.fd(), _mode,
1413  nullptr
1414  ));
1415  }
1416  else
1417  {
1418  file::instance::from(_file.uv_handle)->ref();
1419  instance_ptr->ref();
1420 
1421  // instance_ptr->properties() = { static_cast< file::uv_t* >(_file) };
1422  {
1423  auto &properties = instance_ptr->properties();
1424  properties.uv_handle = static_cast< file::uv_t* >(_file);
1425  }
1426 
1427  uv_status(0);
1428  auto uv_ret = ::uv_fs_fchmod(
1429  static_cast< file::uv_t* >(_file)->loop, static_cast< uv_t* >(uv_req),
1430  _file.fd(), _mode,
1431  chmod_cb
1432  );
1433  if (uv_ret < 0)
1434  {
1435  uv_status(uv_ret);
1436  file::instance::from(_file.uv_handle)->unref();
1437  instance_ptr->unref();
1438  }
1439 
1440  return uv_ret;
1441  }
1442  }
1443 
1444 public: /*conversion operators*/
1445  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
1446  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
1447 };
1448 
1449 template< typename >
1450 void fs::chmod::chmod_cb(::uv_fs_t *_uv_req)
1451 {
1452  auto instance_ptr = instance::from(_uv_req);
1453  instance_ptr->uv_error = _uv_req->result;
1454 
1455  auto &properties = instance_ptr->properties();
1456 
1457  if (properties.uv_handle)
1458  {
1459  ref_guard< file::instance > unref_file(*file::instance::from(properties.uv_handle), adopt_ref);
1460  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
1461 
1462  auto &chmod_cb = instance_ptr->request_cb_storage.value();
1463  if (chmod_cb) chmod_cb(chmod(_uv_req));
1464  }
1465  else
1466  {
1467  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
1468 
1469  auto &chmod_cb = instance_ptr->request_cb_storage.value();
1470  if (chmod_cb) chmod_cb(chmod(_uv_req));
1471  }
1472 }
1473 
1474 
1475 
1476 /*! \brief Change ownership of a file. (_Not implemented on Windows._) */
1477 class fs::chown : public fs
1478 {
1479  //! \cond
1480  friend class request::instance< chown >;
1481  //! \endcond
1482 
1483 public: /*types*/
1484  using on_request_t = std::function< void(chown _request) >;
1485  /*!< \brief The function type of the callback called when the `chown` request has completed. */
1486 
1487 protected: /*types*/
1488  //! \cond internals
1489  //! \addtogroup doxy_group__internals
1490  //! \{
1491  struct properties : fs::properties
1492  {
1493  file::uv_t *uv_handle = nullptr;
1494  };
1495  //! \}
1496  //! \endcond
1497 
1498 private: /*types*/
1499  using instance = request::instance< chown >;
1500 
1501 protected: /*constructors*/
1502  //! \cond
1503  explicit chown(uv_t *_uv_req) : fs(_uv_req) {}
1504  //! \endcond
1505 
1506 public: /*constructors*/
1507  ~chown() = default;
1508  chown()
1509  {
1510  uv_req = instance::create();
1511  init< UV_FS_CHOWN >();
1512  }
1513 
1514  chown(const chown&) = default;
1515  chown& operator =(const chown&) = default;
1516 
1517  chown(chown&&) noexcept = default;
1518  chown& operator =(chown&&) noexcept = default;
1519 
1520 private: /*functions*/
1521  template< typename = void > static void chown_cb(::uv_fs_t*);
1522 
1523 public: /*interface*/
1524  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
1525 
1526  /*! \brief The file which this chown request has been running on.
1527  \details It is guaranteed that it will be a valid instance at least within the request callback.\n\n
1528  If the request was applied to a file path then the handle of the returned file is closed (i.e. `uv::file::is_closing() == 1`). */
1529  file handle() const noexcept
1530  {
1531  auto uv_handle = instance::from(uv_req)->properties().uv_handle;
1532  return uv_handle ? file(uv_handle) : file(static_cast< uv_t* >(uv_req)->loop, -1, static_cast< uv_t* >(uv_req)->path);
1533  }
1534 
1535  /*! \brief The file path affected by request.
1536  \sa libuv API documentation: [`uv_fs_t.path`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_t.path). */
1537  const char* path() const noexcept
1538  {
1539  auto uv_handle = instance::from(uv_req)->properties().uv_handle;
1540  return uv_handle ? uv_handle->path : static_cast< uv_t* >(uv_req)->path;
1541  }
1542 
1543  /*! \brief Run the request. Change the owner and group of a file or directory specified by `_path`.
1544  \sa libuv API documentation: [`uv_fs_chown()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_chown).
1545  \sa Linux: [`chown()`](http://man7.org/linux/man-pages/man2/chown.2.html).
1546  \note If the request callback is empty (has not been set), the request runs _synchronously_. */
1547  int run(uv::loop &_loop, const char* _path, ::uv_uid_t _uid, ::uv_gid_t _gid)
1548  {
1549  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
1550 
1551  auto instance_ptr = instance::from(uv_req);
1552 
1553  if (!instance_ptr->request_cb_storage.value())
1554  {
1555  instance_ptr->properties().uv_handle = nullptr;
1556 
1557  return uv_status(::uv_fs_chown(
1558  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
1559  _path, _uid, _gid,
1560  nullptr
1561  ));
1562  }
1563  else
1564  {
1565  instance_ptr->ref();
1566 
1567  // instance_ptr->properties() = { nullptr };
1568  {
1569  auto &properties = instance_ptr->properties();
1570  properties.uv_handle = nullptr;
1571  }
1572 
1573  uv_status(0);
1574  auto uv_ret = ::uv_fs_chown(
1575  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
1576  _path, _uid, _gid,
1577  chown_cb
1578  );
1579  if (uv_ret < 0)
1580  {
1581  uv_status(uv_ret);
1582  instance_ptr->unref();
1583  }
1584 
1585  return uv_ret;
1586  }
1587  }
1588 
1589  /*! \brief Run the request. Change the owner and group of the open `_file`.
1590  \sa libuv API documentation: [`uv_fs_fchown()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_fchown).
1591  \sa Linux: [`fchown()`](http://man7.org/linux/man-pages/man2/fchown.2.html).
1592  \note If the request callback is empty (has not been set), the request runs _synchronously_. */
1593  int run(file &_file, ::uv_uid_t _uid, ::uv_gid_t _gid)
1594  {
1595  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
1596 
1597  auto instance_ptr = instance::from(uv_req);
1598 
1599  if (!instance_ptr->request_cb_storage.value())
1600  {
1601  instance_ptr->properties().uv_handle = static_cast< file::uv_t* >(_file);
1602 
1603  return uv_status(::uv_fs_fchown(
1604  static_cast< file::uv_t* >(_file)->loop, static_cast< uv_t* >(uv_req),
1605  _file.fd(), _uid, _gid,
1606  nullptr
1607  ));
1608  }
1609  else
1610  {
1611  file::instance::from(_file.uv_handle)->ref();
1612  instance_ptr->ref();
1613 
1614  // instance_ptr->properties() = { static_cast< file::uv_t* >(_file) };
1615  {
1616  auto &properties = instance_ptr->properties();
1617  properties.uv_handle = static_cast< file::uv_t* >(_file);
1618  }
1619 
1620  uv_status(0);
1621  auto uv_ret = ::uv_fs_fchown(
1622  static_cast< file::uv_t* >(_file)->loop, static_cast< uv_t* >(uv_req),
1623  _file.fd(), _uid, _gid,
1624  chown_cb
1625  );
1626  if (uv_ret < 0)
1627  {
1628  uv_status(uv_ret);
1629  file::instance::from(_file.uv_handle)->unref();
1630  instance_ptr->unref();
1631  }
1632 
1633  return uv_ret;
1634  }
1635  }
1636 
1637 public: /*conversion operators*/
1638  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
1639  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
1640 };
1641 
1642 template< typename >
1643 void fs::chown::chown_cb(::uv_fs_t *_uv_req)
1644 {
1645  auto instance_ptr = instance::from(_uv_req);
1646  instance_ptr->uv_error = _uv_req->result;
1647 
1648  auto &properties = instance_ptr->properties();
1649 
1650  if (properties.uv_handle)
1651  {
1652  ref_guard< file::instance > unref_file(*file::instance::from(properties.uv_handle), adopt_ref);
1653  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
1654 
1655  auto &chown_cb = instance_ptr->request_cb_storage.value();
1656  if (chown_cb) chown_cb(chown(_uv_req));
1657  }
1658  else
1659  {
1660  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
1661 
1662  auto &chown_cb = instance_ptr->request_cb_storage.value();
1663  if (chown_cb) chown_cb(chown(_uv_req));
1664  }
1665 }
1666 
1667 
1668 
1669 /*! \brief Change file timestamps. */
1670 class fs::utime : public fs
1671 {
1672  //! \cond
1673  friend class request::instance< utime >;
1674  //! \endcond
1675 
1676 public: /*types*/
1677  using on_request_t = std::function< void(utime _request) >;
1678  /*!< \brief The function type of the callback called when the `utime` request has completed. */
1679 
1680 protected: /*types*/
1681  //! \cond internals
1682  //! \addtogroup doxy_group__internals
1683  //! \{
1684  struct properties : fs::properties
1685  {
1686  file::uv_t *uv_handle = nullptr;
1687  };
1688  //! \}
1689  //! \endcond
1690 
1691 private: /*types*/
1692  using instance = request::instance< utime >;
1693 
1694 protected: /*constructors*/
1695  //! \cond
1696  explicit utime(uv_t *_uv_req) : fs(_uv_req) {}
1697  //! \endcond
1698 
1699 public: /*constructors*/
1700  ~utime() = default;
1701  utime()
1702  {
1703  uv_req = instance::create();
1704  init< UV_FS_UTIME >();
1705  }
1706 
1707  utime(const utime&) = default;
1708  utime& operator =(const utime&) = default;
1709 
1710  utime(utime&&) noexcept = default;
1711  utime& operator =(utime&&) noexcept = default;
1712 
1713 private: /*functions*/
1714  template< typename = void > static void utime_cb(::uv_fs_t*);
1715 
1716 public: /*interface*/
1717  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
1718 
1719  /*! \brief The file which this utime request has been running on.
1720  \details It is guaranteed that it will be a valid instance at least within the request callback.\n\n
1721  If the request was applied to a file path then the handle of the returned file is closed (i.e. `uv::file::is_closing() == 1`). */
1722  file handle() const noexcept
1723  {
1724  auto uv_handle = instance::from(uv_req)->properties().uv_handle;
1725  return uv_handle ? file(uv_handle) : file(static_cast< uv_t* >(uv_req)->loop, -1, static_cast< uv_t* >(uv_req)->path);
1726  }
1727 
1728  /*! \brief The file path affected by request.
1729  \sa libuv API documentation: [`uv_fs_t.path`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_t.path). */
1730  const char* path() const noexcept
1731  {
1732  auto uv_handle = instance::from(uv_req)->properties().uv_handle;
1733  return uv_handle ? uv_handle->path : static_cast< uv_t* >(uv_req)->path;
1734  }
1735 
1736  /*! \brief Run the request. Change last access and modification times for a file or directory specified by `_path`.
1737  \sa libuv API documentation: [`uv_fs_utime()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_utime).
1738  \sa Linux: [`utime()`](http://man7.org/linux/man-pages/man2/utime.2.html),
1739  [`utimensat()`](http://man7.org/linux/man-pages/man2/utimensat.2.html).
1740  \note If the request callback is empty (has not been set), the request runs _synchronously_. */
1741  int run(uv::loop &_loop, const char* _path, double _atime, double _mtime)
1742  {
1743  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
1744 
1745  auto instance_ptr = instance::from(uv_req);
1746 
1747  if (!instance_ptr->request_cb_storage.value())
1748  {
1749  instance_ptr->properties().uv_handle = nullptr;
1750 
1751  return uv_status(::uv_fs_utime(
1752  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
1753  _path, _atime, _mtime,
1754  nullptr
1755  ));
1756  }
1757  else
1758  {
1759  instance_ptr->ref();
1760 
1761  // instance_ptr->properties() = { nullptr };
1762  {
1763  auto &properties = instance_ptr->properties();
1764  properties.uv_handle = nullptr;
1765  }
1766 
1767  uv_status(0);
1768  auto uv_ret = ::uv_fs_utime(
1769  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
1770  _path, _atime, _mtime,
1771  utime_cb
1772  );
1773  if (uv_ret < 0)
1774  {
1775  uv_status(uv_ret);
1776  instance_ptr->unref();
1777  }
1778 
1779  return uv_ret;
1780  }
1781  }
1782 
1783  /*! \brief Run the request. Change last access and modification times for the open `_file`.
1784  \sa libuv API documentation: [`uv_fs_futime()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_futime).
1785  \sa Linux: [`utimensat()`](http://man7.org/linux/man-pages/man2/utimensat.2.html).
1786  \note If the request callback is empty (has not been set), the request runs _synchronously_. */
1787  int run(file &_file, double _atime, double _mtime)
1788  {
1789  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
1790 
1791  auto instance_ptr = instance::from(uv_req);
1792 
1793  if (!instance_ptr->request_cb_storage.value())
1794  {
1795  instance_ptr->properties().uv_handle = static_cast< file::uv_t* >(_file);
1796 
1797  return uv_status(::uv_fs_futime(
1798  static_cast< file::uv_t* >(_file)->loop, static_cast< uv_t* >(uv_req),
1799  _file.fd(), _atime, _mtime,
1800  nullptr
1801  ));
1802  }
1803  else
1804  {
1805  file::instance::from(_file.uv_handle)->ref();
1806  instance_ptr->ref();
1807 
1808  // instance_ptr->properties() = { static_cast< file::uv_t* >(_file) };
1809  {
1810  auto &properties = instance_ptr->properties();
1811  properties.uv_handle = static_cast< file::uv_t* >(_file);
1812  }
1813 
1814  uv_status(0);
1815  auto uv_ret = ::uv_fs_futime(
1816  static_cast< file::uv_t* >(_file)->loop, static_cast< uv_t* >(uv_req),
1817  _file.fd(), _atime, _mtime,
1818  utime_cb
1819  );
1820  if (uv_ret < 0)
1821  {
1822  uv_status(uv_ret);
1823  file::instance::from(_file.uv_handle)->unref();
1824  instance_ptr->unref();
1825  }
1826 
1827  return uv_ret;
1828  }
1829  }
1830 
1831 public: /*conversion operators*/
1832  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
1833  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
1834 };
1835 
1836 template< typename >
1837 void fs::utime::utime_cb(::uv_fs_t *_uv_req)
1838 {
1839  auto instance_ptr = instance::from(_uv_req);
1840  instance_ptr->uv_error = _uv_req->result;
1841 
1842  auto &properties = instance_ptr->properties();
1843 
1844  if (properties.uv_handle)
1845  {
1846  ref_guard< file::instance > unref_file(*file::instance::from(properties.uv_handle), adopt_ref);
1847  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
1848 
1849  auto &utime_cb = instance_ptr->request_cb_storage.value();
1850  if (utime_cb) utime_cb(utime(_uv_req));
1851  }
1852  else
1853  {
1854  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
1855 
1856  auto &utime_cb = instance_ptr->request_cb_storage.value();
1857  if (utime_cb) utime_cb(utime(_uv_req));
1858  }
1859 }
1860 
1861 
1862 
1863 /*! \brief Delete a file name and possibly the file itself that the name refers to. */
1864 class fs::unlink : public fs
1865 {
1866  //! \cond
1867  friend class request::instance< unlink >;
1868  //! \endcond
1869 
1870 public: /*types*/
1871  using on_request_t = std::function< void(unlink _request) >;
1872  /*!< \brief The function type of the callback called when the `unlink` request has completed. */
1873 
1874 private: /*types*/
1875  using instance = request::instance< unlink >;
1876 
1877 protected: /*constructors*/
1878  //! \cond
1879  explicit unlink(uv_t *_uv_req) : fs(_uv_req) {}
1880  //! \endcond
1881 
1882 public: /*constructors*/
1883  ~unlink() = default;
1884  unlink()
1885  {
1886  uv_req = instance::create();
1887  init< UV_FS_UNLINK >();
1888  }
1889 
1890  unlink(const unlink&) = default;
1891  unlink& operator =(const unlink&) = default;
1892 
1893  unlink(unlink&&) noexcept = default;
1894  unlink& operator =(unlink&&) noexcept = default;
1895 
1896 private: /*functions*/
1897  template< typename = void > static void unlink_cb(::uv_fs_t*);
1898 
1899 public: /*interface*/
1900  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
1901 
1902  /*! \brief The file path affected by request.
1903  \sa libuv API documentation: [`uv_fs_t.path`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_t.path). */
1904  const char* path() const noexcept { return static_cast< uv_t* >(uv_req)->path; }
1905 
1906  /*! \brief Run the request. Delete a file name specified by `_path`.
1907  \sa libuv API documentation: [`uv_fs_unlink()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_unlink).
1908  \sa Linux: [`unlink()`](http://man7.org/linux/man-pages/man2/unlink.2.html).
1909  \note If the request callback is empty (has not been set), the request runs _synchronously_. */
1910  int run(uv::loop &_loop, const char* _path)
1911  {
1912  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
1913 
1914  auto instance_ptr = instance::from(uv_req);
1915 
1916  if (!instance_ptr->request_cb_storage.value())
1917  {
1918  return uv_status(::uv_fs_unlink(
1919  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
1920  _path,
1921  nullptr
1922  ));
1923  }
1924  else
1925  {
1926  instance_ptr->ref();
1927 
1928  uv_status(0);
1929  auto uv_ret = ::uv_fs_unlink(
1930  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
1931  _path,
1932  unlink_cb
1933  );
1934  if (uv_ret < 0)
1935  {
1936  uv_status(uv_ret);
1937  instance_ptr->unref();
1938  }
1939 
1940  return uv_ret;
1941  }
1942  }
1943 
1944 public: /*conversion operators*/
1945  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
1946  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
1947 };
1948 
1949 template< typename >
1950 void fs::unlink::unlink_cb(::uv_fs_t *_uv_req)
1951 {
1952  auto instance_ptr = instance::from(_uv_req);
1953  instance_ptr->uv_error = _uv_req->result;
1954 
1955  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
1956 
1957  auto &unlink_cb = instance_ptr->request_cb_storage.value();
1958  if (unlink_cb) unlink_cb(unlink(_uv_req));
1959 }
1960 
1961 
1962 
1963 /*! \brief Create a directory. */
1964 class fs::mkdir : public fs
1965 {
1966  //! \cond
1967  friend class request::instance< mkdir >;
1968  //! \endcond
1969 
1970 public: /*types*/
1971  using on_request_t = std::function< void(mkdir _request) >;
1972  /*!< \brief The function type of the callback called when the `mkdir` request has completed. */
1973 
1974 private: /*types*/
1975  using instance = request::instance< mkdir >;
1976 
1977 protected: /*constructors*/
1978  //! \cond
1979  explicit mkdir(uv_t *_uv_req) : fs(_uv_req) {}
1980  //! \endcond
1981 
1982 public: /*constructors*/
1983  ~mkdir() = default;
1984  mkdir()
1985  {
1986  uv_req = instance::create();
1987  init< UV_FS_MKDIR >();
1988  }
1989 
1990  mkdir(const mkdir&) = default;
1991  mkdir& operator =(const mkdir&) = default;
1992 
1993  mkdir(mkdir&&) noexcept = default;
1994  mkdir& operator =(mkdir&&) noexcept = default;
1995 
1996 private: /*functions*/
1997  template< typename = void > static void mkdir_cb(::uv_fs_t*);
1998 
1999 public: /*interface*/
2000  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
2001 
2002  /*! \brief The file path affected by request.
2003  \sa libuv API documentation: [`uv_fs_t.path`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_t.path). */
2004  const char* path() const noexcept { return static_cast< uv_t* >(uv_req)->path; }
2005 
2006  /*! \brief Run the request. Create a directory specified by `_path`.
2007  \sa libuv API documentation: [`uv_fs_mkdir()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_mkdir).
2008  \sa Linux: [`mkdir()`](http://man7.org/linux/man-pages/man2/mkdir.2.html).
2009  \note If the request callback is empty (has not been set), the request runs _synchronously_. */
2010  int run(uv::loop &_loop, const char* _path, int _mode)
2011  {
2012  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
2013 
2014  auto instance_ptr = instance::from(uv_req);
2015 
2016  if (!instance_ptr->request_cb_storage.value())
2017  {
2018  return uv_status(::uv_fs_mkdir(
2019  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
2020  _path, _mode,
2021  nullptr
2022  ));
2023  }
2024  else
2025  {
2026  instance_ptr->ref();
2027 
2028  uv_status(0);
2029  auto uv_ret = ::uv_fs_mkdir(
2030  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
2031  _path, _mode,
2032  mkdir_cb
2033  );
2034  if (uv_ret < 0)
2035  {
2036  uv_status(uv_ret);
2037  instance_ptr->unref();
2038  }
2039 
2040  return uv_ret;
2041  }
2042  }
2043 
2044 public: /*conversion operators*/
2045  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
2046  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
2047 };
2048 
2049 template< typename >
2050 void fs::mkdir::mkdir_cb(::uv_fs_t *_uv_req)
2051 {
2052  auto instance_ptr = instance::from(_uv_req);
2053  instance_ptr->uv_error = _uv_req->result;
2054 
2055  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
2056 
2057  auto &mkdir_cb = instance_ptr->request_cb_storage.value();
2058  if (mkdir_cb) mkdir_cb(mkdir(_uv_req));
2059 }
2060 
2061 
2062 
2063 /*! \brief Create a uniquely named temporary directory. */
2064 class fs::mkdtemp : public fs
2065 {
2066  //! \cond
2067  friend class request::instance< mkdtemp >;
2068  //! \endcond
2069 
2070 public: /*types*/
2071  using on_request_t = std::function< void(mkdtemp _request) >;
2072  /*!< \brief The function type of the callback called when the `mkdtemp` request has completed. */
2073 
2074 private: /*types*/
2075  using instance = request::instance< mkdtemp >;
2076 
2077 protected: /*constructors*/
2078  //! \cond
2079  explicit mkdtemp(uv_t *_uv_req) : fs(_uv_req) {}
2080  //! \endcond
2081 
2082 public: /*constructors*/
2083  ~mkdtemp() = default;
2084  mkdtemp()
2085  {
2086  uv_req = instance::create();
2087  init< UV_FS_MKDTEMP >();
2088  }
2089 
2090  mkdtemp(const mkdtemp&) = default;
2091  mkdtemp& operator =(const mkdtemp&) = default;
2092 
2093  mkdtemp(mkdtemp&&) noexcept = default;
2094  mkdtemp& operator =(mkdtemp&&) noexcept = default;
2095 
2096 private: /*functions*/
2097  template< typename = void > static void mkdtemp_cb(::uv_fs_t*);
2098 
2099 public: /*interface*/
2100  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
2101 
2102  /*! \brief The path of the directory created by request.
2103  \sa libuv API documentation: [`uv_fs_t.path`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_t.path). */
2104  const char* path() const noexcept { return static_cast< uv_t* >(uv_req)->path; }
2105 
2106  /*! \brief Run the request. Create a temporary directory with unique name generated from `_template` string.
2107  \sa libuv API documentation: [`uv_fs_mkdtemp()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_mkdtemp).
2108  \sa Linux: [`mkdtemp()`](http://man7.org/linux/man-pages/man3/mkdtemp.3.html).
2109  \note If the request callback is empty (has not been set), the request runs _synchronously_. */
2110  int run(uv::loop &_loop, const char* _template)
2111  {
2112  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
2113 
2114  auto instance_ptr = instance::from(uv_req);
2115 
2116  if (!instance_ptr->request_cb_storage.value())
2117  {
2118  return uv_status(::uv_fs_mkdtemp(
2119  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
2120  _template,
2121  nullptr
2122  ));
2123  }
2124  else
2125  {
2126  instance_ptr->ref();
2127 
2128  uv_status(0);
2129  auto uv_ret = ::uv_fs_mkdtemp(
2130  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
2131  _template,
2132  mkdtemp_cb
2133  );
2134  if (uv_ret < 0)
2135  {
2136  uv_status(uv_ret);
2137  instance_ptr->unref();
2138  }
2139 
2140  return uv_ret;
2141  }
2142  }
2143 
2144 public: /*conversion operators*/
2145  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
2146  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
2147 };
2148 
2149 template< typename >
2150 void fs::mkdtemp::mkdtemp_cb(::uv_fs_t *_uv_req)
2151 {
2152  auto instance_ptr = instance::from(_uv_req);
2153  instance_ptr->uv_error = _uv_req->result;
2154 
2155  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
2156 
2157  auto &mkdtemp_cb = instance_ptr->request_cb_storage.value();
2158  if (mkdtemp_cb) mkdtemp_cb(mkdtemp(_uv_req));
2159 }
2160 
2161 
2162 
2163 /*! \brief Delete a directory. */
2164 class fs::rmdir : public fs
2165 {
2166  //! \cond
2167  friend class request::instance< rmdir >;
2168  //! \endcond
2169 
2170 public: /*types*/
2171  using on_request_t = std::function< void(rmdir _request) >;
2172  /*!< \brief The function type of the callback called when the `rmdir` request has completed. */
2173 
2174 private: /*types*/
2175  using instance = request::instance< rmdir >;
2176 
2177 protected: /*constructors*/
2178  //! \cond
2179  explicit rmdir(uv_t *_uv_req) : fs(_uv_req) {}
2180  //! \endcond
2181 
2182 public: /*constructors*/
2183  ~rmdir() = default;
2184  rmdir()
2185  {
2186  uv_req = instance::create();
2187  init< UV_FS_RMDIR >();
2188  }
2189 
2190  rmdir(const rmdir&) = default;
2191  rmdir& operator =(const rmdir&) = default;
2192 
2193  rmdir(rmdir&&) noexcept = default;
2194  rmdir& operator =(rmdir&&) noexcept = default;
2195 
2196 private: /*functions*/
2197  template< typename = void > static void rmdir_cb(::uv_fs_t*);
2198 
2199 public: /*interface*/
2200  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
2201 
2202  /*! \brief The file path affected by request.
2203  \sa libuv API documentation: [`uv_fs_t.path`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_t.path). */
2204  const char* path() const noexcept { return static_cast< uv_t* >(uv_req)->path; }
2205 
2206  /*! \brief Run the request. Delete a directory (which must be empty) specified by `_path`.
2207  \sa libuv API documentation: [`uv_fs_rmdir()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_rmdir).
2208  \sa Linux: [`rmdir()`](http://man7.org/linux/man-pages/man2/rmdir.2.html).
2209  \note If the request callback is empty (has not been set), the request runs _synchronously_. */
2210  int run(uv::loop &_loop, const char* _path)
2211  {
2212  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
2213 
2214  auto instance_ptr = instance::from(uv_req);
2215 
2216  if (!instance_ptr->request_cb_storage.value())
2217  {
2218  return uv_status(::uv_fs_rmdir(
2219  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
2220  _path,
2221  nullptr
2222  ));
2223  }
2224  else
2225  {
2226  instance_ptr->ref();
2227 
2228  uv_status(0);
2229  auto uv_ret = ::uv_fs_rmdir(
2230  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
2231  _path,
2232  rmdir_cb
2233  );
2234  if (uv_ret < 0)
2235  {
2236  uv_status(uv_ret);
2237  instance_ptr->unref();
2238  }
2239 
2240  return uv_ret;
2241  }
2242  }
2243 
2244 public: /*conversion operators*/
2245  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
2246  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
2247 };
2248 
2249 template< typename >
2250 void fs::rmdir::rmdir_cb(::uv_fs_t *_uv_req)
2251 {
2252  auto instance_ptr = instance::from(_uv_req);
2253  instance_ptr->uv_error = _uv_req->result;
2254 
2255  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
2256 
2257  auto &rmdir_cb = instance_ptr->request_cb_storage.value();
2258  if (rmdir_cb) rmdir_cb(rmdir(_uv_req));
2259 }
2260 
2261 
2262 
2263 /*! \brief Scan a directory. */
2264 class fs::scandir : public fs
2265 {
2266  //! \cond
2267  friend class request::instance< scandir >;
2268  //! \endcond
2269 
2270 public: /*types*/
2271  using on_request_t = std::function< void(scandir _request) >;
2272  /*!< \brief The function type of the callback called when the `scandir` request has completed. */
2273 
2274 private: /*types*/
2275  using instance = request::instance< scandir >;
2276 
2277 protected: /*constructors*/
2278  //! \cond
2279  explicit scandir(uv_t *_uv_req) : fs(_uv_req) {}
2280  //! \endcond
2281 
2282 public: /*constructors*/
2283  ~scandir() = default;
2284  scandir()
2285  {
2286  uv_req = instance::create();
2287  init< UV_FS_SCANDIR >();
2288  }
2289 
2290  scandir(const scandir&) = default;
2291  scandir& operator =(const scandir&) = default;
2292 
2293  scandir(scandir&&) noexcept = default;
2294  scandir& operator =(scandir&&) noexcept = default;
2295 
2296 private: /*functions*/
2297  template< typename = void > static void scandir_cb(::uv_fs_t*);
2298 
2299 public: /*interface*/
2300  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
2301 
2302  /*! \brief The file path affected by request.
2303  \sa libuv API documentation: [`uv_fs_t.path`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_t.path). */
2304  const char* path() const noexcept { return static_cast< uv_t* >(uv_req)->path; }
2305 
2306  /*! \brief Get the results of the scandir request.
2307  \details It is simply a wrapper around `uv_fs_scandir_next()` libuv API function.
2308  \sa libuv API documentation: [`uv_dirent_t`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_dirent_t),
2309  [`uv_fs_scandir()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_scandir),
2310  [`uv_fs_scandir_next()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_scandir_next). */
2311  int scandir_next(::uv_dirent_t &_entry) const noexcept
2312  { return uv_status(uv_fs_scandir_next(static_cast< uv_t* >(uv_req), &_entry)); }
2313 
2314  /*! \brief Run the request. Scan a directory specified by `_path`.
2315  \sa libuv API documentation: [`uv_fs_scandir()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_scandir),
2316  [`uv_fs_scandir_next()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_scandir_next).
2317  \sa Linux: [`scandir()`](http://man7.org/linux/man-pages/man3/scandir.3.html).
2318  \note If the request callback is empty (has not been set), the request runs _synchronously_.
2319  In this case the function returns the number of directory entries or relevant libuv error code. */
2320  int run(uv::loop &_loop, const char* _path)
2321  {
2322  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
2323 
2324  auto instance_ptr = instance::from(uv_req);
2325 
2326  if (!instance_ptr->request_cb_storage.value())
2327  {
2328  return uv_status(::uv_fs_scandir(
2329  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
2330  _path, 0,
2331  nullptr
2332  ));
2333  }
2334  else
2335  {
2336  instance_ptr->ref();
2337 
2338  uv_status(0);
2339  auto uv_ret = ::uv_fs_scandir(
2340  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
2341  _path, 0,
2342  scandir_cb
2343  );
2344  if (uv_ret < 0)
2345  {
2346  uv_status(uv_ret);
2347  instance_ptr->unref();
2348  }
2349 
2350  return uv_ret;
2351  }
2352  }
2353 
2354 public: /*conversion operators*/
2355  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
2356  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
2357 };
2358 
2359 template< typename >
2360 void fs::scandir::scandir_cb(::uv_fs_t *_uv_req)
2361 {
2362  auto instance_ptr = instance::from(_uv_req);
2363  instance_ptr->uv_error = _uv_req->result;
2364 
2365  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
2366 
2367  auto &scandir_cb = instance_ptr->request_cb_storage.value();
2368  if (scandir_cb) scandir_cb(scandir(_uv_req));
2369 }
2370 
2371 
2372 
2373 /*! \brief Change the name or location of a file. */
2374 class fs::rename : public fs
2375 {
2376  //! \cond
2377  friend class request::instance< rename >;
2378  //! \endcond
2379 
2380 public: /*types*/
2381  using on_request_t = std::function< void(rename _request) >;
2382  /*!< \brief The function type of the callback called when the `rename` request has completed. */
2383 
2384 private: /*types*/
2385  using instance = request::instance< rename >;
2386 
2387 protected: /*constructors*/
2388  //! \cond
2389  explicit rename(uv_t *_uv_req) : fs(_uv_req) {}
2390  //! \endcond
2391 
2392 public: /*constructors*/
2393  ~rename() = default;
2394  rename()
2395  {
2396  uv_req = instance::create();
2397  init< UV_FS_RENAME >();
2398  }
2399 
2400  rename(const rename&) = default;
2401  rename& operator =(const rename&) = default;
2402 
2403  rename(rename&&) noexcept = default;
2404  rename& operator =(rename&&) noexcept = default;
2405 
2406 private: /*functions*/
2407  template< typename = void > static void rename_cb(::uv_fs_t*);
2408 
2409 public: /*interface*/
2410  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
2411 
2412  /*! \brief The file path affected by request.
2413  \warning On Windows the pointer actually refers to `WCHAR` string.
2414  \sa libuv API documentation: [`uv_fs_t.path`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_t.path). */
2415  const char* path() const noexcept
2416  {
2417 #ifdef _WIN32
2418  return reinterpret_cast< const char* >(static_cast< uv_t* >(uv_req)->file.pathw);
2419 #else
2420  return static_cast< uv_t* >(uv_req)->path;
2421 #endif
2422  }
2423  /*! \brief The file path affected by request.
2424  \warning On Windows the pointer actually refers to `WCHAR` string. */
2425  const char* new_path() const noexcept
2426  {
2427 #ifdef _WIN32
2428  return reinterpret_cast< const char* >(static_cast< uv_t* >(uv_req)->fs.info.new_pathw);
2429 #else
2430  return static_cast< uv_t* >(uv_req)->new_path;
2431 #endif
2432  }
2433 
2434  /*! \brief Run the request. Renames a file, moving it between directories if required.
2435  \sa libuv API documentation: [`uv_fs_rename()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_rename).
2436  \sa Linux: [`rename()`](http://man7.org/linux/man-pages/man2/rename.2.html).
2437  \note If the request callback is empty (has not been set), the request runs _synchronously_. */
2438  int run(uv::loop &_loop, const char* _path, const char* _new_path)
2439  {
2440  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
2441 
2442  auto instance_ptr = instance::from(uv_req);
2443 
2444  if (!instance_ptr->request_cb_storage.value())
2445  {
2446  return uv_status(::uv_fs_rename(
2447  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
2448  _path, _new_path,
2449  nullptr
2450  ));
2451  }
2452  else
2453  {
2454  instance_ptr->ref();
2455 
2456  uv_status(0);
2457  auto uv_ret = ::uv_fs_rename(
2458  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
2459  _path, _new_path,
2460  rename_cb
2461  );
2462  if (uv_ret < 0)
2463  {
2464  uv_status(uv_ret);
2465  instance_ptr->unref();
2466  }
2467 
2468  return uv_ret;
2469  }
2470  }
2471 
2472 public: /*conversion operators*/
2473  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
2474  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
2475 };
2476 
2477 template< typename >
2478 void fs::rename::rename_cb(::uv_fs_t *_uv_req)
2479 {
2480  auto instance_ptr = instance::from(_uv_req);
2481  instance_ptr->uv_error = _uv_req->result;
2482 
2483  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
2484 
2485  auto &rename_cb = instance_ptr->request_cb_storage.value();
2486  if (rename_cb) rename_cb(rename(_uv_req));
2487 }
2488 
2489 
2490 
2491 /*! \brief Check user's permissions for a file. */
2492 class fs::access : public fs
2493 {
2494  //! \cond
2495  friend class request::instance< access >;
2496  //! \endcond
2497 
2498 public: /*types*/
2499  using on_request_t = std::function< void(access _request) >;
2500  /*!< \brief The function type of the callback called when the `access` request has completed. */
2501 
2502 private: /*types*/
2503  using instance = request::instance< access >;
2504 
2505 protected: /*constructors*/
2506  //! \cond
2507  explicit access(uv_t *_uv_req) : fs(_uv_req) {}
2508  //! \endcond
2509 
2510 public: /*constructors*/
2511  ~access() = default;
2512  access()
2513  {
2514  uv_req = instance::create();
2515  init< UV_FS_ACCESS >();
2516  }
2517 
2518  access(const access&) = default;
2519  access& operator =(const access&) = default;
2520 
2521  access(access&&) noexcept = default;
2522  access& operator =(access&&) noexcept = default;
2523 
2524 private: /*functions*/
2525  template< typename = void > static void access_cb(::uv_fs_t*);
2526 
2527 public: /*interface*/
2528  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
2529 
2530  /*! \brief The file path affected by request.
2531  \sa libuv API documentation: [`uv_fs_t.path`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_t.path). */
2532  const char* path() const noexcept { return static_cast< uv_t* >(uv_req)->path; }
2533 
2534  /*! \brief Run the request. Check if the calling process can access the file specified by `_path` using the access `_mode`.
2535  \sa libuv API documentation: [`uv_fs_access()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_access).
2536  \sa Linux: [`access()`](http://man7.org/linux/man-pages/man2/access.2.html).
2537  \note If the request callback is empty (has not been set), the request runs _synchronously_. */
2538  int run(uv::loop &_loop, const char* _path, int _mode)
2539  {
2540  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
2541 
2542  auto instance_ptr = instance::from(uv_req);
2543 
2544  if (!instance_ptr->request_cb_storage.value())
2545  {
2546  return uv_status(::uv_fs_access(
2547  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
2548  _path, _mode,
2549  nullptr
2550  ));
2551  }
2552  else
2553  {
2554  instance_ptr->ref();
2555 
2556  uv_status(0);
2557  auto uv_ret = ::uv_fs_access(
2558  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
2559  _path, _mode,
2560  access_cb
2561  );
2562  if (uv_ret < 0)
2563  {
2564  uv_status(uv_ret);
2565  instance_ptr->unref();
2566  }
2567 
2568  return uv_ret;
2569  }
2570  }
2571 
2572 public: /*conversion operators*/
2573  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
2574  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
2575 };
2576 
2577 template< typename >
2578 void fs::access::access_cb(::uv_fs_t *_uv_req)
2579 {
2580  auto instance_ptr = instance::from(_uv_req);
2581  instance_ptr->uv_error = _uv_req->result;
2582 
2583  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
2584 
2585  auto &access_cb = instance_ptr->request_cb_storage.value();
2586  if (access_cb) access_cb(access(_uv_req));
2587 }
2588 
2589 
2590 
2591 /*! \brief Create a new link to a file. */
2592 class fs::link : public fs
2593 {
2594  //! \cond
2595  friend class request::instance< link >;
2596  //! \endcond
2597 
2598 public: /*types*/
2599  using on_request_t = std::function< void(link _request) >;
2600  /*!< \brief The function type of the callback called when the `link` request has completed. */
2601 
2602 private: /*types*/
2603  using instance = request::instance< link >;
2604 
2605 protected: /*constructors*/
2606  //! \cond
2607  explicit link(uv_t *_uv_req) : fs(_uv_req) {}
2608  //! \endcond
2609 
2610 public: /*constructors*/
2611  ~link() = default;
2612  link()
2613  {
2614  uv_req = instance::create();
2615  init< UV_FS_LINK >();
2616  }
2617 
2618  link(const link&) = default;
2619  link& operator =(const link&) = default;
2620 
2621  link(link&&) noexcept = default;
2622  link& operator =(link&&) noexcept = default;
2623 
2624 private: /*functions*/
2625  template< typename = void > static void link_cb(::uv_fs_t*);
2626 
2627 public: /*interface*/
2628  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
2629 
2630  /*! \brief The file path affected by request.
2631  \warning On Windows the pointer actually refers to `WCHAR` string.
2632  \sa libuv API documentation: [`uv_fs_t.path`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_t.path). */
2633  const char* path() const noexcept
2634  {
2635 #ifdef _WIN32
2636  return reinterpret_cast< const char* >(static_cast< uv_t* >(uv_req)->file.pathw);
2637 #else
2638  return static_cast< uv_t* >(uv_req)->path;
2639 #endif
2640  }
2641  /*! \brief The new name for the path affected by request.
2642  \warning On Windows the pointer actually refers to `WCHAR` string. */
2643  const char* link_path() const noexcept
2644  {
2645 #ifdef _WIN32
2646  return reinterpret_cast< const char* >(static_cast< uv_t* >(uv_req)->fs.info.new_pathw);
2647 #else
2648  return static_cast< uv_t* >(uv_req)->new_path;
2649 #endif
2650  }
2651 
2652  /*! \brief Run the request. Make a new name for a target specified by `_path`.
2653  \details
2654  \arg If `(_symlink == false)`, create a new hard link to an existing `_path`.
2655  \arg If `(_symlink == true)`, create a symbolic link which contains the string from `_path`
2656  as a link target.
2657 
2658  On _Windows_ the `_symlink_flags` parameter can be specified to control how the _link to a directory_
2659  will be created:
2660  \arg `UV_FS_SYMLINK_DIR` - request to create a symbolic link;
2661  \arg `UV_FS_SYMLINK_JUNCTION` - request to create a junction point.
2662 
2663  \sa libuv API documentation: [`uv_fs_link()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_link),
2664  [`uv_fs_symlink()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_symlink).
2665  \sa Linux: [`link()`](http://man7.org/linux/man-pages/man2/link.2.html),
2666  [`symlink()`](http://man7.org/linux/man-pages/man2/symlink.2.html).
2667  \note If the request callback is empty (has not been set), the request runs _synchronously_. */
2668  int run(uv::loop &_loop, const char* _path, const char* _link_path, bool _symlink, int _symlink_flags = 0)
2669  {
2670  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
2671 
2672  auto instance_ptr = instance::from(uv_req);
2673 
2674  if (!instance_ptr->request_cb_storage.value())
2675  {
2676  if (_symlink) return uv_status(::uv_fs_symlink(
2677  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
2678  _path, _link_path, _symlink_flags,
2679  nullptr
2680  ));
2681  else return uv_status(::uv_fs_link(
2682  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
2683  _path, _link_path,
2684  nullptr
2685  ));
2686  }
2687  else
2688  {
2689  instance_ptr->ref();
2690 
2691  uv_status(0);
2692  int uv_ret = 0;
2693  if (_symlink) uv_ret = ::uv_fs_symlink(
2694  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
2695  _path, _link_path, _symlink_flags,
2696  link_cb
2697  );
2698  else uv_ret = ::uv_fs_link(
2699  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
2700  _path, _link_path,
2701  link_cb
2702  );
2703  if (uv_ret < 0)
2704  {
2705  uv_status(uv_ret);
2706  instance_ptr->unref();
2707  }
2708 
2709  return uv_ret;
2710  }
2711  }
2712 
2713 public: /*conversion operators*/
2714  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
2715  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
2716 };
2717 
2718 template< typename >
2719 void fs::link::link_cb(::uv_fs_t *_uv_req)
2720 {
2721  auto instance_ptr = instance::from(_uv_req);
2722  instance_ptr->uv_error = _uv_req->result;
2723 
2724  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
2725 
2726  auto &link_cb = instance_ptr->request_cb_storage.value();
2727  if (link_cb) link_cb(link(_uv_req));
2728 }
2729 
2730 
2731 
2732 /*! \brief Read value of a symbolic link. */
2733 class fs::readlink : public fs
2734 {
2735  //! \cond
2736  friend class request::instance< readlink >;
2737  //! \endcond
2738 
2739 public: /*types*/
2740  using on_request_t = std::function< void(readlink _request) >;
2741  /*!< \brief The function type of the callback called when the `readlink` request has completed. */
2742 
2743 private: /*types*/
2744  using instance = request::instance< readlink >;
2745 
2746 protected: /*constructors*/
2747  //! \cond
2748  explicit readlink(uv_t *_uv_req) : fs(_uv_req) {}
2749  //! \endcond
2750 
2751 public: /*constructors*/
2752  ~readlink() = default;
2753  readlink()
2754  {
2755  uv_req = instance::create();
2756  init< UV_FS_READLINK >();
2757  }
2758 
2759  readlink(const readlink&) = default;
2760  readlink& operator =(const readlink&) = default;
2761 
2762  readlink(readlink&&) noexcept = default;
2763  readlink& operator =(readlink&&) noexcept = default;
2764 
2765 private: /*functions*/
2766  template< typename = void > static void readlink_cb(::uv_fs_t*);
2767 
2768 public: /*interface*/
2769  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
2770 
2771  /*! \brief The file path affected by request.
2772  \sa libuv API documentation: [`uv_fs_t.path`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_t.path). */
2773  const char* path() const noexcept { return static_cast< uv_t* >(uv_req)->path; }
2774 
2775  /*! \brief The result of the readlink request. */
2776  const char* result() const noexcept { return static_cast< const char* >(static_cast< uv_t* >(uv_req)->ptr); }
2777 
2778  /*! \brief Run the request. Read value of a symbolic link specified by `_path`.
2779  \sa libuv API documentation: [`uv_fs_readlink()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_readlink).
2780  \sa Linux: [`readlink()`](http://man7.org/linux/man-pages/man2/readlink.2.html).
2781  \note If the request callback is empty (has not been set), the request runs _synchronously_. */
2782  int run(uv::loop &_loop, const char* _path)
2783  {
2784  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
2785 
2786  auto instance_ptr = instance::from(uv_req);
2787 
2788  if (!instance_ptr->request_cb_storage.value())
2789  {
2790  return uv_status(::uv_fs_readlink(
2791  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
2792  _path,
2793  nullptr
2794  ));
2795  }
2796  else
2797  {
2798  instance_ptr->ref();
2799 
2800  uv_status(0);
2801  auto uv_ret = ::uv_fs_readlink(
2802  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
2803  _path,
2804  readlink_cb
2805  );
2806  if (uv_ret < 0)
2807  {
2808  uv_status(uv_ret);
2809  instance_ptr->unref();
2810  }
2811 
2812  return uv_ret;
2813  }
2814  }
2815 
2816 public: /*conversion operators*/
2817  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
2818  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
2819 };
2820 
2821 template< typename >
2822 void fs::readlink::readlink_cb(::uv_fs_t *_uv_req)
2823 {
2824  auto instance_ptr = instance::from(_uv_req);
2825  instance_ptr->uv_error = _uv_req->result;
2826 
2827  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
2828 
2829  auto &readlink_cb = instance_ptr->request_cb_storage.value();
2830  if (readlink_cb) readlink_cb(readlink(_uv_req));
2831 }
2832 
2833 
2834 
2835 /*! \brief Get canonicalized absolute pathname. */
2836 class fs::realpath : public fs
2837 {
2838  //! \cond
2839  friend class request::instance< realpath >;
2840  //! \endcond
2841 
2842 public: /*types*/
2843  using on_request_t = std::function< void(realpath _request) >;
2844  /*!< \brief The function type of the callback called when the `realpath` request has completed. */
2845 
2846 private: /*types*/
2847  using instance = request::instance< realpath >;
2848 
2849 protected: /*constructors*/
2850  //! \cond
2851  explicit realpath(uv_t *_uv_req) : fs(_uv_req) {}
2852  //! \endcond
2853 
2854 public: /*constructors*/
2855  ~realpath() = default;
2856  realpath()
2857  {
2858  uv_req = instance::create();
2859  init< UV_FS_REALPATH >();
2860  }
2861 
2862  realpath(const realpath&) = default;
2863  realpath& operator =(const realpath&) = default;
2864 
2865  realpath(realpath&&) noexcept = default;
2866  realpath& operator =(realpath&&) noexcept = default;
2867 
2868 private: /*functions*/
2869  template< typename = void > static void realpath_cb(::uv_fs_t*);
2870 
2871 public: /*interface*/
2872  on_request_t& on_request() const noexcept { return instance::from(uv_req)->request_cb_storage.value(); }
2873 
2874  /*! \brief The file path affected by request.
2875  \sa libuv API documentation: [`uv_fs_t.path`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_t.path). */
2876  const char* path() const noexcept { return static_cast< uv_t* >(uv_req)->path; }
2877 
2878  /*! \brief The result of the realpath request. */
2879  const char* result() const noexcept { return static_cast< const char* >(static_cast< uv_t* >(uv_req)->ptr); }
2880 
2881  /*! \brief Run the request. Get canonicalized absolute pathname.
2882  \sa libuv API documentation: [`uv_fs_realpath()`](http://docs.libuv.org/en/v1.x/fs.html#c.uv_fs_realpath).
2883  \sa Linux: [`realpath()`](http://man7.org/linux/man-pages/man3/realpath.3.html).
2884  \note If the request callback is empty (has not been set), the request runs _synchronously_. */
2885  int run(uv::loop &_loop, const char* _path)
2886  {
2887  ::uv_fs_req_cleanup(static_cast< uv_t* >(uv_req)); // assuming that *uv_req has initially been nulled
2888 
2889  auto instance_ptr = instance::from(uv_req);
2890 
2891  if (!instance_ptr->request_cb_storage.value())
2892  {
2893  return uv_status(::uv_fs_realpath(
2894  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
2895  _path,
2896  nullptr
2897  ));
2898  }
2899  else
2900  {
2901  instance_ptr->ref();
2902 
2903  uv_status(0);
2904  auto uv_ret = ::uv_fs_realpath(
2905  static_cast< uv::loop::uv_t* >(_loop), static_cast< uv_t* >(uv_req),
2906  _path,
2907  realpath_cb
2908  );
2909  if (uv_ret < 0)
2910  {
2911  uv_status(uv_ret);
2912  instance_ptr->unref();
2913  }
2914 
2915  return uv_ret;
2916  }
2917  }
2918 
2919 public: /*conversion operators*/
2920  explicit operator const uv_t*() const noexcept { return static_cast< const uv_t* >(uv_req); }
2921  explicit operator uv_t*() noexcept { return static_cast< uv_t* >(uv_req); }
2922 };
2923 
2924 template< typename >
2925 void fs::realpath::realpath_cb(::uv_fs_t *_uv_req)
2926 {
2927  auto instance_ptr = instance::from(_uv_req);
2928  instance_ptr->uv_error = _uv_req->result;
2929 
2930  ref_guard< instance > unref_req(*instance_ptr, adopt_ref);
2931 
2932  auto &realpath_cb = instance_ptr->request_cb_storage.value();
2933  if (realpath_cb) realpath_cb(realpath(_uv_req));
2934 }
2935 
2936 
2937 }
2938 
2939 
2940 #endif
io handle_out() const noexcept
The I/O endpoint which this sendfile request has been writing data to.
Definition: request-fs.hpp:961
Namespace for all uvcc definitions.
Definition: buffer.hpp:17
int run(uv::loop &_loop, const char *_path, ::uv_uid_t _uid, ::uv_gid_t _gid)
Run the request. Change the owner and group of a file or directory specified by _path.
Get canonicalized absolute pathname.
const char * path() const noexcept
The file path affected by request.
int run(file &_file, int _mode)
Run the request. Change permissions of the open _file.
Change the name or location of a file.
operator bool() const noexcept
Equivalent to (base() != nullptr).
Definition: buffer.hpp:248
file handle() const noexcept
The file which this stat request has been running on.
int run(uv::loop &_loop, const char *_path, int _mode)
Run the request. Change permissions of a file or directory specified by _path.
The base class for the libuv requests.
The open file handle.
Definition: handle-fs.hpp:29
Transfer data between file descriptors.
Definition: request-fs.hpp:896
file handle() const noexcept
The file which this write request has been running on.
Definition: request-fs.hpp:471
int run(uv::loop &_loop, const char *_path, bool _follow_symlinks=false)
Run the request. Get status information on a file or directory specified by _path.
Get information about a file.
const char * new_path() const noexcept
The file path affected by request.
int run(uv::loop &_loop, const char *_path, const char *_new_path)
Run the request. Renames a file, moving it between directories if required.
Synchronize a file&#39;s state with storage device.
Definition: request-fs.hpp:622
const char * path() const noexcept
The file path affected by request.
Change ownership of a file. (Not implemented on Windows.)
int run(uv::loop &_loop, const char *_path)
Run the request. Get canonicalized absolute pathname.
file handle() const noexcept
The file which this read request has been running on.
Definition: request-fs.hpp:314
Scan a directory.
int64_t offset() const noexcept
The offset this write request has been performed at.
Definition: request-fs.hpp:474
Truncate a file to a specified length.
Definition: request-fs.hpp:751
Create a directory.
int run(file &_file, buffer &_buf, int64_t _offset)
Run the request. Read data from the _file into the buffers described by _buf object.
Definition: request-fs.hpp:326
The base calss for filesystem requests.
Definition: request-fs.hpp:40
int64_t offset() const noexcept
The offset this read request has been performed at.
Definition: request-fs.hpp:317
Change a file mode bits.
const char * path() const noexcept
The file path affected by request.
Delete a directory.
int scandir_next(::uv_dirent_t &_entry) const noexcept
Get the results of the scandir request.
int run(uv::loop &_loop, const char *_template)
Run the request. Create a temporary directory with unique name generated from _template string...
Read data from a file.
Definition: request-fs.hpp:261
int read_stop() const
Stop reading data from the I/O endpoint.
Definition: handle-io.hpp:254
int run(file &_file)
Run the request. Close a _file handle.
Definition: request-fs.hpp:188
const char * path() const noexcept
The file path affected by request.
const char * path() const noexcept
The file path affected by request.
int64_t offset() const noexcept
The offset this sendfile request has been started to read data at from input file.
Definition: request-fs.hpp:967
const ::uv_stat_t & result() const noexcept
The result of the stat request.
int run(file &_file, ::uv_uid_t _uid, ::uv_gid_t _gid)
Run the request. Change the owner and group of the open _file.
int run(file &_file, int64_t _offset)
Run the request. Truncate the _file to a size of _offset bytes.
Definition: request-fs.hpp:814
const char * path() const noexcept
The file path affected by request.
Check user&#39;s permissions for a file.
const char * path() const noexcept
The path of the directory created by request.
const char * path() const noexcept
The file path affected by request.
file handle() const noexcept
The file which this truncate request has been running on.
Definition: request-fs.hpp:803
file handle() const noexcept
The file which this utime request has been running on.
file handle() const noexcept
The file which this chown request has been running on.
int try_write(file &_file, const buffer &_buf, int64_t _offset)
Try to execute the request synchronously if it can be completed immediately...
Definition: request-fs.hpp:561
The I/O event loop class.
Definition: loop.hpp:33
int run(uv::loop &_loop, const char *_path, int _mode)
Run the request. Check if the calling process can access the file specified by _path using the access...
The base class for handles representing I/O endpoints: a file, TCP/UDP socket, pipe, TTY.
Definition: handle-io.hpp:25
A scoped reference counting guard.
Definition: utility.hpp:280
Write data to a file.
Definition: request-fs.hpp:416
int64_t offset() const noexcept
The offset this trucate request has been performed at.
Definition: request-fs.hpp:806
const char * path() const noexcept
The file path affected by request.
int run(file &_file, const buffer &_buf, int64_t _offset)
Run the request. Write data to the _file from the buffers described by _buf object.
Definition: request-fs.hpp:483
int run(uv::loop &_loop, const char *_path)
Run the request. Scan a directory specified by _path.
Change file timestamps.
Close a file handle.
Definition: request-fs.hpp:129
int run(io &_out, file &_in, int64_t _offset, std::size_t _length)
Run the request. Read data from the _in file starting from the _offset and copy it to the _out endpoi...
Definition: request-fs.hpp:977
int run(file &_file, bool _flush_all_metadata=false)
Run the request. Flush the data of the _file to the storage device.
Definition: request-fs.hpp:683
file handle() const noexcept
The file which this chmod request has been running on.
const char * result() const noexcept
The result of the realpath request.
int run(uv::loop &_loop, const char *_path)
Run the request. Delete a directory (which must be empty) specified by _path.
file handle() const noexcept
The file which this sync request has been running on.
Definition: request-fs.hpp:673
std::size_t write_queue_size() const noexcept
The amount of bytes waiting to be written to the file.
Definition: handle-fs.hpp:196
const char * path() const noexcept
The file path affected by request.
int run(uv::loop &_loop, const char *_path, int _mode)
Run the request. Create a directory specified by _path.
file handle_in() const noexcept
The file which this sendfile request has been reading data from.
Definition: request-fs.hpp:964
int run(uv::loop &_loop, const char *_path, double _atime, double _mtime)
Run the request. Change last access and modification times for a file or directory specified by _path...
int run(file &_file)
Run the request. Get status information about the open _file.
const char * path() const noexcept
The file path affected by request.
::uv_fs_type fs_type() const noexcept
The tag indicating a subtype of the filesystem request.
Definition: request-fs.hpp:116
file handle() const noexcept
The file which this close request has been running on.
Definition: request-fs.hpp:180
Create a uniquely named temporary directory.
int run(file &_file, double _atime, double _mtime)
Run the request. Change last access and modification times for the open _file.