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