4e572b7d96ba6ed872c0c8c7265d4c5adc1575d9
[platform/upstream/nodejs.git] / deps / uv / src / unix / fs.c
1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2  *
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:
9  *
10  * The above copyright notice and this permission notice shall be included in
11  * all copies or substantial portions of the Software.
12  *
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
19  * IN THE SOFTWARE.
20  */
21
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.)
27  */
28
29 #include "uv.h"
30 #include "internal.h"
31
32 #include <errno.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <sys/time.h>
40 #include <pthread.h>
41 #include <dirent.h>
42 #include <unistd.h>
43 #include <fcntl.h>
44 #include <utime.h>
45 #include <poll.h>
46
47 #if defined(__linux__) || defined(__sun)
48 # include <sys/sendfile.h>
49 #elif defined(__APPLE__) || defined(__FreeBSD__)
50 # include <sys/socket.h>
51 # include <sys/uio.h>
52 #endif
53
54 #define INIT(type)                                                            \
55   do {                                                                        \
56     uv__req_init((loop), (req), UV_FS);                                       \
57     (req)->fs_type = UV_FS_ ## type;                                          \
58     (req)->result = 0;                                                        \
59     (req)->ptr = NULL;                                                        \
60     (req)->loop = loop;                                                       \
61     (req)->path = NULL;                                                       \
62     (req)->new_path = NULL;                                                   \
63     (req)->cb = (cb);                                                         \
64   }                                                                           \
65   while (0)
66
67 #define PATH                                                                  \
68   do {                                                                        \
69     (req)->path = strdup(path);                                               \
70     if ((req)->path == NULL)                                                  \
71       return -ENOMEM;                                                         \
72   }                                                                           \
73   while (0)
74
75 #define PATH2                                                                 \
76   do {                                                                        \
77     size_t path_len;                                                          \
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)                                                  \
83       return -ENOMEM;                                                         \
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);                \
87   }                                                                           \
88   while (0)
89
90 #define POST                                                                  \
91   do {                                                                        \
92     if ((cb) != NULL) {                                                       \
93       uv__work_submit((loop), &(req)->work_req, uv__fs_work, uv__fs_done);    \
94       return 0;                                                               \
95     }                                                                         \
96     else {                                                                    \
97       uv__fs_work(&(req)->work_req);                                          \
98       uv__fs_done(&(req)->work_req, 0);                                       \
99       return (req)->result;                                                   \
100     }                                                                         \
101   }                                                                           \
102   while (0)
103
104
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);
110 #else
111   return fsync(req->file);
112 #endif
113 }
114
115
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.
120    */
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)];
125   int r;
126
127   if (no_utimesat)
128     goto skip;
129
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;
134
135   r = uv__utimesat(req->file, NULL, ts, 0);
136   if (r == 0)
137     return r;
138
139   if (errno != ENOSYS)
140     return r;
141
142   no_utimesat = 1;
143
144 skip:
145
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);
151
152   r = utimes(path, tv);
153   if (r == 0)
154     return r;
155
156   switch (errno) {
157   case ENOENT:
158     if (fcntl(req->file, F_GETFL) == -1 && errno == EBADF)
159       break;
160     /* Fall through. */
161
162   case EACCES:
163   case ENOTDIR:
164     errno = ENOSYS;
165     break;
166   }
167
168   return r;
169
170 #elif defined(__APPLE__)                                                      \
171     || defined(__DragonFly__)                                                 \
172     || defined(__FreeBSD__)                                                   \
173     || defined(__NetBSD__)                                                    \
174     || defined(__OpenBSD__)                                                   \
175     || defined(__sun)
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;
181 # if defined(__sun)
182   return futimesat(req->file, NULL, tv);
183 # else
184   return futimes(req->file, tv);
185 # endif
186 #else
187   errno = ENOSYS;
188   return -1;
189 #endif
190 }
191
192
193 static ssize_t uv__fs_read(uv_fs_t* req) {
194   if (req->off < 0)
195     return read(req->file, req->buf, req->len);
196   else
197     return pread(req->file, req->buf, req->len, req->off);
198 }
199
200
201 static int uv__fs_readdir_filter(const struct dirent* dent) {
202   return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0;
203 }
204
205
206 /* This should have been called uv__fs_scandir(). */
207 static ssize_t uv__fs_readdir(uv_fs_t* req) {
208   struct dirent **dents;
209   int saved_errno;
210   size_t off;
211   size_t len;
212   char *buf;
213   int i;
214   int n;
215
216   n = scandir(req->path, &dents, uv__fs_readdir_filter, alphasort);
217
218   if (n == -1 || n == 0)
219     return n;
220
221   len = 0;
222
223   for (i = 0; i < n; i++)
224     len += strlen(dents[i]->d_name) + 1;
225
226   buf = malloc(len);
227
228   if (buf == NULL) {
229     errno = ENOMEM;
230     n = -1;
231     goto out;
232   }
233
234   off = 0;
235
236   for (i = 0; i < n; i++) {
237     len = strlen(dents[i]->d_name) + 1;
238     memcpy(buf + off, dents[i]->d_name, len);
239     off += len;
240   }
241
242   req->ptr = buf;
243
244 out:
245   saved_errno = errno;
246   {
247     for (i = 0; i < n; i++)
248       free(dents[i]);
249     free(dents);
250   }
251   errno = saved_errno;
252
253   return n;
254 }
255
256
257 static ssize_t uv__fs_readlink(uv_fs_t* req) {
258   ssize_t len;
259   char* buf;
260
261   len = pathconf(req->path, _PC_PATH_MAX);
262
263   if (len == -1) {
264 #if defined(PATH_MAX)
265     len = PATH_MAX;
266 #else
267     len = 4096;
268 #endif
269   }
270
271   buf = malloc(len + 1);
272
273   if (buf == NULL) {
274     errno = ENOMEM;
275     return -1;
276   }
277
278   len = readlink(req->path, buf, len);
279
280   if (len == -1) {
281     free(buf);
282     return -1;
283   }
284
285   buf[len] = '\0';
286   req->ptr = buf;
287
288   return 0;
289 }
290
291
292 static ssize_t uv__fs_sendfile_emul(uv_fs_t* req) {
293   struct pollfd pfd;
294   int use_pread;
295   off_t offset;
296   ssize_t nsent;
297   ssize_t nread;
298   ssize_t nwritten;
299   size_t buflen;
300   size_t len;
301   ssize_t n;
302   int in_fd;
303   int out_fd;
304   char buf[8192];
305
306   len = req->len;
307   in_fd = req->flags;
308   out_fd = req->file;
309   offset = req->off;
310   use_pread = 1;
311
312   /* Here are the rules regarding errors:
313    *
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.
317    *
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.
320    *
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.
323    *
324    * If we get EAGAIN when writing to the target fd, we poll() on it until
325    * it becomes writable again.
326    *
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
331    *        successive reads.
332    *
333    * FIXME: There is no way now to signal that we managed to send *some* data
334    *        before a write error.
335    */
336   for (nsent = 0; (size_t) nsent < len; ) {
337     buflen = len - nsent;
338
339     if (buflen > sizeof(buf))
340       buflen = sizeof(buf);
341
342     do
343       if (use_pread)
344         nread = pread(in_fd, buf, buflen, offset);
345       else
346         nread = read(in_fd, buf, buflen);
347     while (nread == -1 && errno == EINTR);
348
349     if (nread == 0)
350       goto out;
351
352     if (nread == -1) {
353       if (use_pread && nsent == 0 && (errno == EIO || errno == ESPIPE)) {
354         use_pread = 0;
355         continue;
356       }
357
358       if (nsent == 0)
359         nsent = -1;
360
361       goto out;
362     }
363
364     for (nwritten = 0; nwritten < nread; ) {
365       do
366         n = write(out_fd, buf + nwritten, nread - nwritten);
367       while (n == -1 && errno == EINTR);
368
369       if (n != -1) {
370         nwritten += n;
371         continue;
372       }
373
374       if (errno != EAGAIN && errno != EWOULDBLOCK) {
375         nsent = -1;
376         goto out;
377       }
378
379       pfd.fd = out_fd;
380       pfd.events = POLLOUT;
381       pfd.revents = 0;
382
383       do
384         n = poll(&pfd, 1, -1);
385       while (n == -1 && errno == EINTR);
386
387       if (n == -1 || (pfd.revents & ~POLLOUT) != 0) {
388         errno = EIO;
389         nsent = -1;
390         goto out;
391       }
392     }
393
394     offset += nread;
395     nsent += nread;
396   }
397
398 out:
399   if (nsent != -1)
400     req->off = offset;
401
402   return nsent;
403 }
404
405
406 static ssize_t uv__fs_sendfile(uv_fs_t* req) {
407   int in_fd;
408   int out_fd;
409
410   in_fd = req->flags;
411   out_fd = req->file;
412
413 #if defined(__linux__) || defined(__sun)
414   {
415     off_t off;
416     ssize_t r;
417
418     off = req->off;
419     r = sendfile(out_fd, in_fd, &off, req->len);
420
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.
424      */
425     if (r != -1 || off > req->off) {
426       r = off - req->off;
427       req->off = off;
428       return r;
429     }
430
431     if (errno == EINVAL ||
432         errno == EIO ||
433         errno == ENOTSOCK ||
434         errno == EXDEV) {
435       errno = 0;
436       return uv__fs_sendfile_emul(req);
437     }
438
439     return -1;
440   }
441 #elif defined(__FreeBSD__) || defined(__APPLE__)
442   {
443     off_t len;
444     ssize_t r;
445
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.
449      */
450
451 #if defined(__FreeBSD__)
452     len = 0;
453     r = sendfile(in_fd, out_fd, req->off, req->len, NULL, &len, 0);
454 #else
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. */
457     len = req->len;
458     r = sendfile(in_fd, out_fd, req->off, &len, NULL, 0);
459 #endif
460
461     if (r != -1 || len != 0) {
462       req->off += len;
463       return (ssize_t) len;
464     }
465
466     if (errno == EINVAL ||
467         errno == EIO ||
468         errno == ENOTSOCK ||
469         errno == EXDEV) {
470       errno = 0;
471       return uv__fs_sendfile_emul(req);
472     }
473
474     return -1;
475   }
476 #else
477   /* Squelch compiler warnings. */
478   (void) &in_fd;
479   (void) &out_fd;
480
481   return uv__fs_sendfile_emul(req);
482 #endif
483 }
484
485
486 static ssize_t uv__fs_utime(uv_fs_t* req) {
487   struct utimbuf buf;
488   buf.actime = req->atime;
489   buf.modtime = req->mtime;
490   return utime(req->path, &buf); /* TODO use utimes() where available */
491 }
492
493
494 static ssize_t uv__fs_write(uv_fs_t* req) {
495   ssize_t r;
496
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
499    * a dup().
500    */
501 #if defined(__APPLE__)
502   static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
503   pthread_mutex_lock(&lock);
504 #endif
505
506   if (req->off < 0)
507     r = write(req->file, req->buf, req->len);
508   else
509     r = pwrite(req->file, req->buf, req->len, req->off);
510
511 #if defined(__APPLE__)
512   pthread_mutex_unlock(&lock);
513 #endif
514
515   return r;
516 }
517
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;
529
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__)    || \
551      defined(__NetBSD__)
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;
556 # else
557   dst->st_birthtim.tv_sec = src->st_ctim.tv_sec;
558   dst->st_birthtim.tv_nsec = src->st_ctim.tv_nsec;
559   dst->st_flags = 0;
560   dst->st_gen = 0;
561 # endif
562 #else
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;
571   dst->st_flags = 0;
572   dst->st_gen = 0;
573 #endif
574 }
575
576
577 static int uv__fs_stat(const char *path, uv_stat_t *buf) {
578   struct stat pbuf;
579   int ret;
580   ret = stat(path, &pbuf);
581   uv__to_stat(&pbuf, buf);
582   return ret;
583 }
584
585
586 static int uv__fs_lstat(const char *path, uv_stat_t *buf) {
587   struct stat pbuf;
588   int ret;
589   ret = lstat(path, &pbuf);
590   uv__to_stat(&pbuf, buf);
591   return ret;
592 }
593
594
595 static int uv__fs_fstat(int fd, uv_stat_t *buf) {
596   struct stat pbuf;
597   int ret;
598   ret = fstat(fd, &pbuf);
599   uv__to_stat(&pbuf, buf);
600   return ret;
601 }
602
603
604 static void uv__fs_work(struct uv__work* w) {
605   int retry_on_eintr;
606   uv_fs_t* req;
607   ssize_t r;
608
609   req = container_of(w, uv_fs_t, work_req);
610   retry_on_eintr = !(req->fs_type == UV_FS_CLOSE);
611
612   do {
613     errno = 0;
614
615 #define X(type, action)                                                       \
616   case UV_FS_ ## type:                                                        \
617     r = action;                                                               \
618     break;
619
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));
646     default: abort();
647     }
648
649 #undef X
650   }
651   while (r == -1 && errno == EINTR && retry_on_eintr);
652
653   if (r == -1)
654     req->result = -errno;
655   else
656     req->result = r;
657
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;
662   }
663 }
664
665
666 static void uv__fs_done(struct uv__work* w, int status) {
667   uv_fs_t* req;
668
669   req = container_of(w, uv_fs_t, work_req);
670   uv__req_unregister(req->loop, req);
671
672   if (status == -ECANCELED) {
673     assert(req->result == 0);
674     req->result = -ECANCELED;
675   }
676
677   if (req->cb != NULL)
678     req->cb(req);
679 }
680
681
682 int uv_fs_chmod(uv_loop_t* loop,
683                 uv_fs_t* req,
684                 const char* path,
685                 int mode,
686                 uv_fs_cb cb) {
687   INIT(CHMOD);
688   PATH;
689   req->mode = mode;
690   POST;
691 }
692
693
694 int uv_fs_chown(uv_loop_t* loop,
695                 uv_fs_t* req,
696                 const char* path,
697                 uv_uid_t uid,
698                 uv_gid_t gid,
699                 uv_fs_cb cb) {
700   INIT(CHOWN);
701   PATH;
702   req->uid = uid;
703   req->gid = gid;
704   POST;
705 }
706
707
708 int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
709   INIT(CLOSE);
710   req->file = file;
711   POST;
712 }
713
714
715 int uv_fs_fchmod(uv_loop_t* loop,
716                  uv_fs_t* req,
717                  uv_file file,
718                  int mode,
719                  uv_fs_cb cb) {
720   INIT(FCHMOD);
721   req->file = file;
722   req->mode = mode;
723   POST;
724 }
725
726
727 int uv_fs_fchown(uv_loop_t* loop,
728                  uv_fs_t* req,
729                  uv_file file,
730                  uv_uid_t uid,
731                  uv_gid_t gid,
732                  uv_fs_cb cb) {
733   INIT(FCHOWN);
734   req->file = file;
735   req->uid = uid;
736   req->gid = gid;
737   POST;
738 }
739
740
741 int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
742   INIT(FDATASYNC);
743   req->file = file;
744   POST;
745 }
746
747
748 int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
749   INIT(FSTAT);
750   req->file = file;
751   POST;
752 }
753
754
755 int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
756   INIT(FSYNC);
757   req->file = file;
758   POST;
759 }
760
761
762 int uv_fs_ftruncate(uv_loop_t* loop,
763                     uv_fs_t* req,
764                     uv_file file,
765                     int64_t off,
766                     uv_fs_cb cb) {
767   INIT(FTRUNCATE);
768   req->file = file;
769   req->off = off;
770   POST;
771 }
772
773
774 int uv_fs_futime(uv_loop_t* loop,
775                  uv_fs_t* req,
776                  uv_file file,
777                  double atime,
778                  double mtime,
779                  uv_fs_cb cb) {
780   INIT(FUTIME);
781   req->file = file;
782   req->atime = atime;
783   req->mtime = mtime;
784   POST;
785 }
786
787
788 int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
789   INIT(LSTAT);
790   PATH;
791   POST;
792 }
793
794
795 int uv_fs_link(uv_loop_t* loop,
796                uv_fs_t* req,
797                const char* path,
798                const char* new_path,
799                uv_fs_cb cb) {
800   INIT(LINK);
801   PATH2;
802   POST;
803 }
804
805
806 int uv_fs_mkdir(uv_loop_t* loop,
807                 uv_fs_t* req,
808                 const char* path,
809                 int mode,
810                 uv_fs_cb cb) {
811   INIT(MKDIR);
812   PATH;
813   req->mode = mode;
814   POST;
815 }
816
817
818 int uv_fs_open(uv_loop_t* loop,
819                uv_fs_t* req,
820                const char* path,
821                int flags,
822                int mode,
823                uv_fs_cb cb) {
824   INIT(OPEN);
825   PATH;
826   req->flags = flags;
827   req->mode = mode;
828   POST;
829 }
830
831
832 int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
833                uv_file file,
834                void* buf,
835                size_t len,
836                int64_t off,
837                uv_fs_cb cb) {
838   INIT(READ);
839   req->file = file;
840   req->buf = buf;
841   req->len = len;
842   req->off = off;
843   POST;
844 }
845
846
847 int uv_fs_readdir(uv_loop_t* loop,
848                   uv_fs_t* req,
849                   const char* path,
850                   int flags,
851                   uv_fs_cb cb) {
852   INIT(READDIR);
853   PATH;
854   req->flags = flags;
855   POST;
856 }
857
858
859 int uv_fs_readlink(uv_loop_t* loop,
860                    uv_fs_t* req,
861                    const char* path,
862                    uv_fs_cb cb) {
863   INIT(READLINK);
864   PATH;
865   POST;
866 }
867
868
869 int uv_fs_rename(uv_loop_t* loop,
870                  uv_fs_t* req,
871                  const char* path,
872                  const char* new_path,
873                  uv_fs_cb cb) {
874   INIT(RENAME);
875   PATH2;
876   POST;
877 }
878
879
880 int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
881   INIT(RMDIR);
882   PATH;
883   POST;
884 }
885
886
887 int uv_fs_sendfile(uv_loop_t* loop,
888                    uv_fs_t* req,
889                    uv_file out_fd,
890                    uv_file in_fd,
891                    int64_t off,
892                    size_t len,
893                    uv_fs_cb cb) {
894   INIT(SENDFILE);
895   req->flags = in_fd; /* hack */
896   req->file = out_fd;
897   req->off = off;
898   req->len = len;
899   POST;
900 }
901
902
903 int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
904   INIT(STAT);
905   PATH;
906   POST;
907 }
908
909
910 int uv_fs_symlink(uv_loop_t* loop,
911                   uv_fs_t* req,
912                   const char* path,
913                   const char* new_path,
914                   int flags,
915                   uv_fs_cb cb) {
916   INIT(SYMLINK);
917   PATH2;
918   req->flags = flags;
919   POST;
920 }
921
922
923 int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
924   INIT(UNLINK);
925   PATH;
926   POST;
927 }
928
929
930 int uv_fs_utime(uv_loop_t* loop,
931                 uv_fs_t* req,
932                 const char* path,
933                 double atime,
934                 double mtime,
935                 uv_fs_cb cb) {
936   INIT(UTIME);
937   PATH;
938   req->atime = atime;
939   req->mtime = mtime;
940   POST;
941 }
942
943
944 int uv_fs_write(uv_loop_t* loop,
945                 uv_fs_t* req,
946                 uv_file file,
947                 const void* buf,
948                 size_t len,
949                 int64_t off,
950                 uv_fs_cb cb) {
951   INIT(WRITE);
952   req->file = file;
953   req->buf = (void*) buf;
954   req->len = len;
955   req->off = off;
956   POST;
957 }
958
959
960 void uv_fs_req_cleanup(uv_fs_t* req) {
961   free((void*) req->path);
962   req->path = NULL;
963   req->new_path = NULL;
964
965   if (req->ptr != &req->statbuf)
966     free(req->ptr);
967   req->ptr = NULL;
968 }