1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to
5 * deal in the Software without restriction, including without limitation the
6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 * sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 /* Caveat emptor: this file deviates from the libuv convention of returning
23 * negated errno codes. Most uv_fs_*() functions map directly to the system
24 * call of the same name. For more complex wrappers, it's easier to just
25 * return -1 with errno set. The dispatcher in uv__fs_work() takes care of
26 * getting the errno to the right place (req->result or as the return value.)
37 #include <sys/types.h>
47 #if defined(__linux__) || defined(__sun)
48 # include <sys/sendfile.h>
49 #elif defined(__APPLE__) || defined(__FreeBSD__)
50 # include <sys/socket.h>
56 uv__req_init((loop), (req), UV_FS); \
57 (req)->fs_type = UV_FS_ ## type; \
62 (req)->new_path = NULL; \
69 (req)->path = strdup(path); \
70 if ((req)->path == NULL) \
78 size_t new_path_len; \
79 path_len = strlen((path)) + 1; \
80 new_path_len = strlen((new_path)) + 1; \
81 (req)->path = malloc(path_len + new_path_len); \
82 if ((req)->path == NULL) \
84 (req)->new_path = (req)->path + path_len; \
85 memcpy((void*) (req)->path, (path), path_len); \
86 memcpy((void*) (req)->new_path, (new_path), new_path_len); \
93 uv__work_submit((loop), &(req)->work_req, uv__fs_work, uv__fs_done); \
97 uv__fs_work(&(req)->work_req); \
98 uv__fs_done(&(req)->work_req, 0); \
99 return (req)->result; \
105 static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
106 #if defined(__linux__) || defined(__sun) || defined(__NetBSD__)
107 return fdatasync(req->file);
108 #elif defined(__APPLE__) && defined(F_FULLFSYNC)
109 return fcntl(req->file, F_FULLFSYNC);
111 return fsync(req->file);
116 static ssize_t uv__fs_futime(uv_fs_t* req) {
117 #if defined(__linux__)
118 /* utimesat() has nanosecond resolution but we stick to microseconds
119 * for the sake of consistency with other platforms.
121 static int no_utimesat;
122 struct timespec ts[2];
123 struct timeval tv[2];
124 char path[sizeof("/proc/self/fd/") + 3 * sizeof(int)];
130 ts[0].tv_sec = req->atime;
131 ts[0].tv_nsec = (unsigned long)(req->atime * 1000000) % 1000000 * 1000;
132 ts[1].tv_sec = req->mtime;
133 ts[1].tv_nsec = (unsigned long)(req->mtime * 1000000) % 1000000 * 1000;
135 r = uv__utimesat(req->file, NULL, ts, 0);
146 tv[0].tv_sec = req->atime;
147 tv[0].tv_usec = (unsigned long)(req->atime * 1000000) % 1000000;
148 tv[1].tv_sec = req->mtime;
149 tv[1].tv_usec = (unsigned long)(req->mtime * 1000000) % 1000000;
150 snprintf(path, sizeof(path), "/proc/self/fd/%d", (int) req->file);
152 r = utimes(path, tv);
158 if (fcntl(req->file, F_GETFL) == -1 && errno == EBADF)
170 #elif defined(__APPLE__) \
171 || defined(__DragonFly__) \
172 || defined(__FreeBSD__) \
173 || defined(__NetBSD__) \
174 || defined(__OpenBSD__) \
176 struct timeval tv[2];
177 tv[0].tv_sec = req->atime;
178 tv[0].tv_usec = (unsigned long)(req->atime * 1000000) % 1000000;
179 tv[1].tv_sec = req->mtime;
180 tv[1].tv_usec = (unsigned long)(req->mtime * 1000000) % 1000000;
182 return futimesat(req->file, NULL, tv);
184 return futimes(req->file, tv);
193 static ssize_t uv__fs_read(uv_fs_t* req) {
195 return read(req->file, req->buf, req->len);
197 return pread(req->file, req->buf, req->len, req->off);
201 static int uv__fs_readdir_filter(const struct dirent* dent) {
202 return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0;
206 /* This should have been called uv__fs_scandir(). */
207 static ssize_t uv__fs_readdir(uv_fs_t* req) {
208 struct dirent **dents;
216 n = scandir(req->path, &dents, uv__fs_readdir_filter, alphasort);
218 if (n == -1 || n == 0)
223 for (i = 0; i < n; i++)
224 len += strlen(dents[i]->d_name) + 1;
236 for (i = 0; i < n; i++) {
237 len = strlen(dents[i]->d_name) + 1;
238 memcpy(buf + off, dents[i]->d_name, len);
247 for (i = 0; i < n; i++)
257 static ssize_t uv__fs_readlink(uv_fs_t* req) {
261 len = pathconf(req->path, _PC_PATH_MAX);
264 #if defined(PATH_MAX)
271 buf = malloc(len + 1);
278 len = readlink(req->path, buf, len);
292 static ssize_t uv__fs_sendfile_emul(uv_fs_t* req) {
312 /* Here are the rules regarding errors:
314 * 1. Read errors are reported only if nsent==0, otherwise we return nsent.
315 * The user needs to know that some data has already been sent, to stop
316 * them from sending it twice.
318 * 2. Write errors are always reported. Write errors are bad because they
319 * mean data loss: we've read data but now we can't write it out.
321 * We try to use pread() and fall back to regular read() if the source fd
322 * doesn't support positional reads, for example when it's a pipe fd.
324 * If we get EAGAIN when writing to the target fd, we poll() on it until
325 * it becomes writable again.
327 * FIXME: If we get a write error when use_pread==1, it should be safe to
328 * return the number of sent bytes instead of an error because pread()
329 * is, in theory, idempotent. However, special files in /dev or /proc
330 * may support pread() but not necessarily return the same data on
333 * FIXME: There is no way now to signal that we managed to send *some* data
334 * before a write error.
336 for (nsent = 0; (size_t) nsent < len; ) {
337 buflen = len - nsent;
339 if (buflen > sizeof(buf))
340 buflen = sizeof(buf);
344 nread = pread(in_fd, buf, buflen, offset);
346 nread = read(in_fd, buf, buflen);
347 while (nread == -1 && errno == EINTR);
353 if (use_pread && nsent == 0 && (errno == EIO || errno == ESPIPE)) {
364 for (nwritten = 0; nwritten < nread; ) {
366 n = write(out_fd, buf + nwritten, nread - nwritten);
367 while (n == -1 && errno == EINTR);
374 if (errno != EAGAIN && errno != EWOULDBLOCK) {
380 pfd.events = POLLOUT;
384 n = poll(&pfd, 1, -1);
385 while (n == -1 && errno == EINTR);
387 if (n == -1 || (pfd.revents & ~POLLOUT) != 0) {
406 static ssize_t uv__fs_sendfile(uv_fs_t* req) {
413 #if defined(__linux__) || defined(__sun)
419 r = sendfile(out_fd, in_fd, &off, req->len);
421 /* sendfile() on SunOS returns EINVAL if the target fd is not a socket but
422 * it still writes out data. Fortunately, we can detect it by checking if
423 * the offset has been updated.
425 if (r != -1 || off > req->off) {
431 if (errno == EINVAL ||
436 return uv__fs_sendfile_emul(req);
441 #elif defined(__FreeBSD__) || defined(__APPLE__)
446 /* sendfile() on FreeBSD and Darwin returns EAGAIN if the target fd is in
447 * non-blocking mode and not all data could be written. If a non-zero
448 * number of bytes have been sent, we don't consider it an error.
451 #if defined(__FreeBSD__)
453 r = sendfile(in_fd, out_fd, req->off, req->len, NULL, &len, 0);
455 /* The darwin sendfile takes len as an input for the length to send,
456 * so make sure to initialize it with the caller's value. */
458 r = sendfile(in_fd, out_fd, req->off, &len, NULL, 0);
461 if (r != -1 || len != 0) {
463 return (ssize_t) len;
466 if (errno == EINVAL ||
471 return uv__fs_sendfile_emul(req);
477 /* Squelch compiler warnings. */
481 return uv__fs_sendfile_emul(req);
486 static ssize_t uv__fs_utime(uv_fs_t* req) {
488 buf.actime = req->atime;
489 buf.modtime = req->mtime;
490 return utime(req->path, &buf); /* TODO use utimes() where available */
494 static ssize_t uv__fs_write(uv_fs_t* req) {
497 /* Serialize writes on OS X, concurrent write() and pwrite() calls result in
498 * data loss. We can't use a per-file descriptor lock, the descriptor may be
501 #if defined(__APPLE__)
502 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
503 pthread_mutex_lock(&lock);
507 r = write(req->file, req->buf, req->len);
509 r = pwrite(req->file, req->buf, req->len, req->off);
511 #if defined(__APPLE__)
512 pthread_mutex_unlock(&lock);
518 static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
519 dst->st_dev = src->st_dev;
520 dst->st_mode = src->st_mode;
521 dst->st_nlink = src->st_nlink;
522 dst->st_uid = src->st_uid;
523 dst->st_gid = src->st_gid;
524 dst->st_rdev = src->st_rdev;
525 dst->st_ino = src->st_ino;
526 dst->st_size = src->st_size;
527 dst->st_blksize = src->st_blksize;
528 dst->st_blocks = src->st_blocks;
530 #if defined(__APPLE__)
531 dst->st_atim.tv_sec = src->st_atimespec.tv_sec;
532 dst->st_atim.tv_nsec = src->st_atimespec.tv_nsec;
533 dst->st_mtim.tv_sec = src->st_mtimespec.tv_sec;
534 dst->st_mtim.tv_nsec = src->st_mtimespec.tv_nsec;
535 dst->st_ctim.tv_sec = src->st_ctimespec.tv_sec;
536 dst->st_ctim.tv_nsec = src->st_ctimespec.tv_nsec;
537 dst->st_birthtim.tv_sec = src->st_birthtimespec.tv_sec;
538 dst->st_birthtim.tv_nsec = src->st_birthtimespec.tv_nsec;
539 dst->st_flags = src->st_flags;
540 dst->st_gen = src->st_gen;
541 #elif defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_XOPEN_SOURCE)
542 dst->st_atim.tv_sec = src->st_atim.tv_sec;
543 dst->st_atim.tv_nsec = src->st_atim.tv_nsec;
544 dst->st_mtim.tv_sec = src->st_mtim.tv_sec;
545 dst->st_mtim.tv_nsec = src->st_mtim.tv_nsec;
546 dst->st_ctim.tv_sec = src->st_ctim.tv_sec;
547 dst->st_ctim.tv_nsec = src->st_ctim.tv_nsec;
548 # if defined(__DragonFly__) || \
549 defined(__FreeBSD__) || \
550 defined(__OpenBSD__) || \
552 dst->st_birthtim.tv_sec = src->st_birthtim.tv_sec;
553 dst->st_birthtim.tv_nsec = src->st_birthtim.tv_nsec;
554 dst->st_flags = src->st_flags;
555 dst->st_gen = src->st_gen;
557 dst->st_birthtim.tv_sec = src->st_ctim.tv_sec;
558 dst->st_birthtim.tv_nsec = src->st_ctim.tv_nsec;
563 dst->st_atim.tv_sec = src->st_atime;
564 dst->st_atim.tv_nsec = 0;
565 dst->st_mtim.tv_sec = src->st_mtime;
566 dst->st_mtim.tv_nsec = 0;
567 dst->st_ctim.tv_sec = src->st_ctime;
568 dst->st_ctim.tv_nsec = 0;
569 dst->st_birthtim.tv_sec = src->st_ctime;
570 dst->st_birthtim.tv_nsec = 0;
577 static int uv__fs_stat(const char *path, uv_stat_t *buf) {
580 ret = stat(path, &pbuf);
581 uv__to_stat(&pbuf, buf);
586 static int uv__fs_lstat(const char *path, uv_stat_t *buf) {
589 ret = lstat(path, &pbuf);
590 uv__to_stat(&pbuf, buf);
595 static int uv__fs_fstat(int fd, uv_stat_t *buf) {
598 ret = fstat(fd, &pbuf);
599 uv__to_stat(&pbuf, buf);
604 static void uv__fs_work(struct uv__work* w) {
609 req = container_of(w, uv_fs_t, work_req);
610 retry_on_eintr = !(req->fs_type == UV_FS_CLOSE);
615 #define X(type, action) \
616 case UV_FS_ ## type: \
620 switch (req->fs_type) {
621 X(CHMOD, chmod(req->path, req->mode));
622 X(CHOWN, chown(req->path, req->uid, req->gid));
623 X(CLOSE, close(req->file));
624 X(FCHMOD, fchmod(req->file, req->mode));
625 X(FCHOWN, fchown(req->file, req->uid, req->gid));
626 X(FDATASYNC, uv__fs_fdatasync(req));
627 X(FSTAT, uv__fs_fstat(req->file, &req->statbuf));
628 X(FSYNC, fsync(req->file));
629 X(FTRUNCATE, ftruncate(req->file, req->off));
630 X(FUTIME, uv__fs_futime(req));
631 X(LSTAT, uv__fs_lstat(req->path, &req->statbuf));
632 X(LINK, link(req->path, req->new_path));
633 X(MKDIR, mkdir(req->path, req->mode));
634 X(OPEN, open(req->path, req->flags, req->mode));
635 X(READ, uv__fs_read(req));
636 X(READDIR, uv__fs_readdir(req));
637 X(READLINK, uv__fs_readlink(req));
638 X(RENAME, rename(req->path, req->new_path));
639 X(RMDIR, rmdir(req->path));
640 X(SENDFILE, uv__fs_sendfile(req));
641 X(STAT, uv__fs_stat(req->path, &req->statbuf));
642 X(SYMLINK, symlink(req->path, req->new_path));
643 X(UNLINK, unlink(req->path));
644 X(UTIME, uv__fs_utime(req));
645 X(WRITE, uv__fs_write(req));
651 while (r == -1 && errno == EINTR && retry_on_eintr);
654 req->result = -errno;
658 if (r == 0 && (req->fs_type == UV_FS_STAT ||
659 req->fs_type == UV_FS_FSTAT ||
660 req->fs_type == UV_FS_LSTAT)) {
661 req->ptr = &req->statbuf;
666 static void uv__fs_done(struct uv__work* w, int status) {
669 req = container_of(w, uv_fs_t, work_req);
670 uv__req_unregister(req->loop, req);
672 if (status == -ECANCELED) {
673 assert(req->result == 0);
674 req->result = -ECANCELED;
682 int uv_fs_chmod(uv_loop_t* loop,
694 int uv_fs_chown(uv_loop_t* loop,
708 int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
715 int uv_fs_fchmod(uv_loop_t* loop,
727 int uv_fs_fchown(uv_loop_t* loop,
741 int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
748 int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
755 int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
762 int uv_fs_ftruncate(uv_loop_t* loop,
774 int uv_fs_futime(uv_loop_t* loop,
788 int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
795 int uv_fs_link(uv_loop_t* loop,
798 const char* new_path,
806 int uv_fs_mkdir(uv_loop_t* loop,
818 int uv_fs_open(uv_loop_t* loop,
832 int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
847 int uv_fs_readdir(uv_loop_t* loop,
859 int uv_fs_readlink(uv_loop_t* loop,
869 int uv_fs_rename(uv_loop_t* loop,
872 const char* new_path,
880 int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
887 int uv_fs_sendfile(uv_loop_t* loop,
895 req->flags = in_fd; /* hack */
903 int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
910 int uv_fs_symlink(uv_loop_t* loop,
913 const char* new_path,
923 int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
930 int uv_fs_utime(uv_loop_t* loop,
944 int uv_fs_write(uv_loop_t* loop,
953 req->buf = (void*) buf;
960 void uv_fs_req_cleanup(uv_fs_t* req) {
961 free((void*) req->path);
963 req->new_path = NULL;
965 if (req->ptr != &req->statbuf)