xref: /netbsd-src/external/mit/libuv/dist/test/test-fs.c (revision d90047b5d07facf36e6c01dcc0bded8997ce9cc2)
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 #include "uv.h"
23 #include "task.h"
24 
25 #include <errno.h>
26 #include <string.h> /* memset */
27 #include <fcntl.h>
28 #include <sys/stat.h>
29 #include <limits.h> /* INT_MAX, PATH_MAX, IOV_MAX */
30 
31 /* FIXME we shouldn't need to branch in this file */
32 #if defined(__unix__) || defined(__POSIX__) || \
33     defined(__APPLE__) || defined(__sun) || \
34     defined(_AIX) || defined(__MVS__) || \
35     defined(__HAIKU__)
36 #include <unistd.h> /* unlink, rmdir, etc. */
37 #else
38 # include <winioctl.h>
39 # include <direct.h>
40 # include <io.h>
41 # ifndef ERROR_SYMLINK_NOT_SUPPORTED
42 #  define ERROR_SYMLINK_NOT_SUPPORTED 1464
43 # endif
44 # define unlink _unlink
45 # define rmdir _rmdir
46 # define open _open
47 # define write _write
48 # define close _close
49 # ifndef stat
50 #  define stat _stati64
51 # endif
52 # ifndef lseek
53 #   define lseek _lseek
54 # endif
55 #endif
56 
57 #define TOO_LONG_NAME_LENGTH 65536
58 #define PATHMAX 4096
59 
60 typedef struct {
61   const char* path;
62   double atime;
63   double mtime;
64 } utime_check_t;
65 
66 
67 static int dummy_cb_count;
68 static int close_cb_count;
69 static int create_cb_count;
70 static int open_cb_count;
71 static int read_cb_count;
72 static int write_cb_count;
73 static int unlink_cb_count;
74 static int mkdir_cb_count;
75 static int mkdtemp_cb_count;
76 static int mkstemp_cb_count;
77 static int rmdir_cb_count;
78 static int scandir_cb_count;
79 static int stat_cb_count;
80 static int rename_cb_count;
81 static int fsync_cb_count;
82 static int fdatasync_cb_count;
83 static int ftruncate_cb_count;
84 static int sendfile_cb_count;
85 static int fstat_cb_count;
86 static int access_cb_count;
87 static int chmod_cb_count;
88 static int fchmod_cb_count;
89 static int chown_cb_count;
90 static int fchown_cb_count;
91 static int lchown_cb_count;
92 static int link_cb_count;
93 static int symlink_cb_count;
94 static int readlink_cb_count;
95 static int realpath_cb_count;
96 static int utime_cb_count;
97 static int futime_cb_count;
98 static int lutime_cb_count;
99 static int statfs_cb_count;
100 
101 static uv_loop_t* loop;
102 
103 static uv_fs_t open_req1;
104 static uv_fs_t open_req2;
105 static uv_fs_t read_req;
106 static uv_fs_t write_req;
107 static uv_fs_t unlink_req;
108 static uv_fs_t close_req;
109 static uv_fs_t mkdir_req;
110 static uv_fs_t mkdtemp_req1;
111 static uv_fs_t mkdtemp_req2;
112 static uv_fs_t mkstemp_req1;
113 static uv_fs_t mkstemp_req2;
114 static uv_fs_t mkstemp_req3;
115 static uv_fs_t rmdir_req;
116 static uv_fs_t scandir_req;
117 static uv_fs_t stat_req;
118 static uv_fs_t rename_req;
119 static uv_fs_t fsync_req;
120 static uv_fs_t fdatasync_req;
121 static uv_fs_t ftruncate_req;
122 static uv_fs_t sendfile_req;
123 static uv_fs_t utime_req;
124 static uv_fs_t futime_req;
125 
126 static char buf[32];
127 static char buf2[32];
128 static char test_buf[] = "test-buffer\n";
129 static char test_buf2[] = "second-buffer\n";
130 static uv_buf_t iov;
131 
132 #ifdef _WIN32
133 int uv_test_getiovmax(void) {
134   return INT32_MAX; /* Emulated by libuv, so no real limit. */
135 }
136 #else
137 int uv_test_getiovmax(void) {
138 #if defined(IOV_MAX)
139   return IOV_MAX;
140 #elif defined(_SC_IOV_MAX)
141   static int iovmax = -1;
142   if (iovmax == -1) {
143     iovmax = sysconf(_SC_IOV_MAX);
144     /* On some embedded devices (arm-linux-uclibc based ip camera),
145      * sysconf(_SC_IOV_MAX) can not get the correct value. The return
146      * value is -1 and the errno is EINPROGRESS. Degrade the value to 1.
147      */
148     if (iovmax == -1) iovmax = 1;
149   }
150   return iovmax;
151 #else
152   return 1024;
153 #endif
154 }
155 #endif
156 
157 #ifdef _WIN32
158 /*
159  * This tag and guid have no special meaning, and don't conflict with
160  * reserved ids.
161 */
162 static unsigned REPARSE_TAG = 0x9913;
163 static GUID REPARSE_GUID = {
164   0x1bf6205f, 0x46ae, 0x4527,
165   { 0xb1, 0x0c, 0xc5, 0x09, 0xb7, 0x55, 0x22, 0x80 }};
166 #endif
167 
168 static void check_permission(const char* filename, unsigned int mode) {
169   int r;
170   uv_fs_t req;
171   uv_stat_t* s;
172 
173   r = uv_fs_stat(NULL, &req, filename, NULL);
174   ASSERT(r == 0);
175   ASSERT(req.result == 0);
176 
177   s = &req.statbuf;
178 #if defined(_WIN32) || defined(__CYGWIN__) || defined(__MSYS__)
179   /*
180    * On Windows, chmod can only modify S_IWUSR (_S_IWRITE) bit,
181    * so only testing for the specified flags.
182    */
183   ASSERT((s->st_mode & 0777) & mode);
184 #else
185   ASSERT((s->st_mode & 0777) == mode);
186 #endif
187 
188   uv_fs_req_cleanup(&req);
189 }
190 
191 
192 static void dummy_cb(uv_fs_t* req) {
193   (void) req;
194   dummy_cb_count++;
195 }
196 
197 
198 static void link_cb(uv_fs_t* req) {
199   ASSERT(req->fs_type == UV_FS_LINK);
200   ASSERT(req->result == 0);
201   link_cb_count++;
202   uv_fs_req_cleanup(req);
203 }
204 
205 
206 static void symlink_cb(uv_fs_t* req) {
207   ASSERT(req->fs_type == UV_FS_SYMLINK);
208   ASSERT(req->result == 0);
209   symlink_cb_count++;
210   uv_fs_req_cleanup(req);
211 }
212 
213 static void readlink_cb(uv_fs_t* req) {
214   ASSERT(req->fs_type == UV_FS_READLINK);
215   ASSERT(req->result == 0);
216   ASSERT(strcmp(req->ptr, "test_file_symlink2") == 0);
217   readlink_cb_count++;
218   uv_fs_req_cleanup(req);
219 }
220 
221 
222 static void realpath_cb(uv_fs_t* req) {
223   char test_file_abs_buf[PATHMAX];
224   size_t test_file_abs_size = sizeof(test_file_abs_buf);
225   ASSERT(req->fs_type == UV_FS_REALPATH);
226 #ifdef _WIN32
227   /*
228    * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW()
229    */
230   if (req->result == UV_ENOSYS) {
231     realpath_cb_count++;
232     uv_fs_req_cleanup(req);
233     return;
234   }
235 #endif
236   ASSERT(req->result == 0);
237 
238   uv_cwd(test_file_abs_buf, &test_file_abs_size);
239 #ifdef _WIN32
240   strcat(test_file_abs_buf, "\\test_file");
241   ASSERT(stricmp(req->ptr, test_file_abs_buf) == 0);
242 #else
243   strcat(test_file_abs_buf, "/test_file");
244   ASSERT(strcmp(req->ptr, test_file_abs_buf) == 0);
245 #endif
246   realpath_cb_count++;
247   uv_fs_req_cleanup(req);
248 }
249 
250 
251 static void access_cb(uv_fs_t* req) {
252   ASSERT(req->fs_type == UV_FS_ACCESS);
253   access_cb_count++;
254   uv_fs_req_cleanup(req);
255 }
256 
257 
258 static void fchmod_cb(uv_fs_t* req) {
259   ASSERT(req->fs_type == UV_FS_FCHMOD);
260   ASSERT(req->result == 0);
261   fchmod_cb_count++;
262   uv_fs_req_cleanup(req);
263   check_permission("test_file", *(int*)req->data);
264 }
265 
266 
267 static void chmod_cb(uv_fs_t* req) {
268   ASSERT(req->fs_type == UV_FS_CHMOD);
269   ASSERT(req->result == 0);
270   chmod_cb_count++;
271   uv_fs_req_cleanup(req);
272   check_permission("test_file", *(int*)req->data);
273 }
274 
275 
276 static void fchown_cb(uv_fs_t* req) {
277   ASSERT(req->fs_type == UV_FS_FCHOWN);
278   ASSERT(req->result == 0);
279   fchown_cb_count++;
280   uv_fs_req_cleanup(req);
281 }
282 
283 
284 static void chown_cb(uv_fs_t* req) {
285   ASSERT(req->fs_type == UV_FS_CHOWN);
286   ASSERT(req->result == 0);
287   chown_cb_count++;
288   uv_fs_req_cleanup(req);
289 }
290 
291 static void lchown_cb(uv_fs_t* req) {
292   ASSERT(req->fs_type == UV_FS_LCHOWN);
293   ASSERT(req->result == 0);
294   lchown_cb_count++;
295   uv_fs_req_cleanup(req);
296 }
297 
298 static void chown_root_cb(uv_fs_t* req) {
299   ASSERT(req->fs_type == UV_FS_CHOWN);
300 #if defined(_WIN32) || defined(__MSYS__)
301   /* On windows, chown is a no-op and always succeeds. */
302   ASSERT(req->result == 0);
303 #else
304   /* On unix, chown'ing the root directory is not allowed -
305    * unless you're root, of course.
306    */
307   if (geteuid() == 0)
308     ASSERT(req->result == 0);
309   else
310 #   if defined(__CYGWIN__)
311     /* On Cygwin, uid 0 is invalid (no root). */
312     ASSERT(req->result == UV_EINVAL);
313 #   elif defined(__PASE__)
314     /* On IBMi PASE, there is no root user. uid 0 is user qsecofr.
315      * User may grant qsecofr's privileges, including changing
316      * the file's ownership to uid 0.
317      */
318     ASSERT(req->result == 0 || req->result == UV_EPERM);
319 #   else
320     ASSERT(req->result == UV_EPERM);
321 #   endif
322 #endif
323   chown_cb_count++;
324   uv_fs_req_cleanup(req);
325 }
326 
327 static void unlink_cb(uv_fs_t* req) {
328   ASSERT(req == &unlink_req);
329   ASSERT(req->fs_type == UV_FS_UNLINK);
330   ASSERT(req->result == 0);
331   unlink_cb_count++;
332   uv_fs_req_cleanup(req);
333 }
334 
335 static void fstat_cb(uv_fs_t* req) {
336   uv_stat_t* s = req->ptr;
337   ASSERT(req->fs_type == UV_FS_FSTAT);
338   ASSERT(req->result == 0);
339   ASSERT(s->st_size == sizeof(test_buf));
340   uv_fs_req_cleanup(req);
341   fstat_cb_count++;
342 }
343 
344 
345 static void statfs_cb(uv_fs_t* req) {
346   uv_statfs_t* stats;
347 
348   ASSERT(req->fs_type == UV_FS_STATFS);
349   ASSERT(req->result == 0);
350   ASSERT(req->ptr != NULL);
351   stats = req->ptr;
352 
353 #if defined(_WIN32) || defined(__sun) || defined(_AIX) || defined(__MVS__) || \
354   defined(__OpenBSD__) || defined(__NetBSD__)
355   ASSERT(stats->f_type == 0);
356 #else
357   ASSERT(stats->f_type > 0);
358 #endif
359 
360   ASSERT(stats->f_bsize > 0);
361   ASSERT(stats->f_blocks > 0);
362   ASSERT(stats->f_bfree <= stats->f_blocks);
363   ASSERT(stats->f_bavail <= stats->f_bfree);
364 
365 #ifdef _WIN32
366   ASSERT(stats->f_files == 0);
367   ASSERT(stats->f_ffree == 0);
368 #else
369   /* There is no assertion for stats->f_files that makes sense, so ignore it. */
370   ASSERT(stats->f_ffree <= stats->f_files);
371 #endif
372   uv_fs_req_cleanup(req);
373   ASSERT(req->ptr == NULL);
374   statfs_cb_count++;
375 }
376 
377 
378 static void close_cb(uv_fs_t* req) {
379   int r;
380   ASSERT(req == &close_req);
381   ASSERT(req->fs_type == UV_FS_CLOSE);
382   ASSERT(req->result == 0);
383   close_cb_count++;
384   uv_fs_req_cleanup(req);
385   if (close_cb_count == 3) {
386     r = uv_fs_unlink(loop, &unlink_req, "test_file2", unlink_cb);
387     ASSERT(r == 0);
388   }
389 }
390 
391 
392 static void ftruncate_cb(uv_fs_t* req) {
393   int r;
394   ASSERT(req == &ftruncate_req);
395   ASSERT(req->fs_type == UV_FS_FTRUNCATE);
396   ASSERT(req->result == 0);
397   ftruncate_cb_count++;
398   uv_fs_req_cleanup(req);
399   r = uv_fs_close(loop, &close_req, open_req1.result, close_cb);
400   ASSERT(r == 0);
401 }
402 
403 static void fail_cb(uv_fs_t* req) {
404   FATAL("fail_cb should not have been called");
405 }
406 
407 static void read_cb(uv_fs_t* req) {
408   int r;
409   ASSERT(req == &read_req);
410   ASSERT(req->fs_type == UV_FS_READ);
411   ASSERT(req->result >= 0);  /* FIXME(bnoordhuis) Check if requested size? */
412   read_cb_count++;
413   uv_fs_req_cleanup(req);
414   if (read_cb_count == 1) {
415     ASSERT(strcmp(buf, test_buf) == 0);
416     r = uv_fs_ftruncate(loop, &ftruncate_req, open_req1.result, 7,
417         ftruncate_cb);
418   } else {
419     ASSERT(strcmp(buf, "test-bu") == 0);
420     r = uv_fs_close(loop, &close_req, open_req1.result, close_cb);
421   }
422   ASSERT(r == 0);
423 }
424 
425 
426 static void open_cb(uv_fs_t* req) {
427   int r;
428   ASSERT(req == &open_req1);
429   ASSERT(req->fs_type == UV_FS_OPEN);
430   if (req->result < 0) {
431     fprintf(stderr, "async open error: %d\n", (int) req->result);
432     ASSERT(0);
433   }
434   open_cb_count++;
435   ASSERT(req->path);
436   ASSERT(memcmp(req->path, "test_file2\0", 11) == 0);
437   uv_fs_req_cleanup(req);
438   memset(buf, 0, sizeof(buf));
439   iov = uv_buf_init(buf, sizeof(buf));
440   r = uv_fs_read(loop, &read_req, open_req1.result, &iov, 1, -1,
441       read_cb);
442   ASSERT(r == 0);
443 }
444 
445 
446 static void open_cb_simple(uv_fs_t* req) {
447   ASSERT(req->fs_type == UV_FS_OPEN);
448   if (req->result < 0) {
449     fprintf(stderr, "async open error: %d\n", (int) req->result);
450     ASSERT(0);
451   }
452   open_cb_count++;
453   ASSERT(req->path);
454   uv_fs_req_cleanup(req);
455 }
456 
457 
458 static void fsync_cb(uv_fs_t* req) {
459   int r;
460   ASSERT(req == &fsync_req);
461   ASSERT(req->fs_type == UV_FS_FSYNC);
462   ASSERT(req->result == 0);
463   fsync_cb_count++;
464   uv_fs_req_cleanup(req);
465   r = uv_fs_close(loop, &close_req, open_req1.result, close_cb);
466   ASSERT(r == 0);
467 }
468 
469 
470 static void fdatasync_cb(uv_fs_t* req) {
471   int r;
472   ASSERT(req == &fdatasync_req);
473   ASSERT(req->fs_type == UV_FS_FDATASYNC);
474   ASSERT(req->result == 0);
475   fdatasync_cb_count++;
476   uv_fs_req_cleanup(req);
477   r = uv_fs_fsync(loop, &fsync_req, open_req1.result, fsync_cb);
478   ASSERT(r == 0);
479 }
480 
481 
482 static void write_cb(uv_fs_t* req) {
483   int r;
484   ASSERT(req == &write_req);
485   ASSERT(req->fs_type == UV_FS_WRITE);
486   ASSERT(req->result >= 0);  /* FIXME(bnoordhuis) Check if requested size? */
487   write_cb_count++;
488   uv_fs_req_cleanup(req);
489   r = uv_fs_fdatasync(loop, &fdatasync_req, open_req1.result, fdatasync_cb);
490   ASSERT(r == 0);
491 }
492 
493 
494 static void create_cb(uv_fs_t* req) {
495   int r;
496   ASSERT(req == &open_req1);
497   ASSERT(req->fs_type == UV_FS_OPEN);
498   ASSERT(req->result >= 0);
499   create_cb_count++;
500   uv_fs_req_cleanup(req);
501   iov = uv_buf_init(test_buf, sizeof(test_buf));
502   r = uv_fs_write(loop, &write_req, req->result, &iov, 1, -1, write_cb);
503   ASSERT(r == 0);
504 }
505 
506 
507 static void rename_cb(uv_fs_t* req) {
508   ASSERT(req == &rename_req);
509   ASSERT(req->fs_type == UV_FS_RENAME);
510   ASSERT(req->result == 0);
511   rename_cb_count++;
512   uv_fs_req_cleanup(req);
513 }
514 
515 
516 static void mkdir_cb(uv_fs_t* req) {
517   ASSERT(req == &mkdir_req);
518   ASSERT(req->fs_type == UV_FS_MKDIR);
519   ASSERT(req->result == 0);
520   mkdir_cb_count++;
521   ASSERT(req->path);
522   ASSERT(memcmp(req->path, "test_dir\0", 9) == 0);
523   uv_fs_req_cleanup(req);
524 }
525 
526 
527 static void check_mkdtemp_result(uv_fs_t* req) {
528   int r;
529 
530   ASSERT(req->fs_type == UV_FS_MKDTEMP);
531   ASSERT(req->result == 0);
532   ASSERT(req->path);
533   ASSERT(strlen(req->path) == 15);
534   ASSERT(memcmp(req->path, "test_dir_", 9) == 0);
535   ASSERT(memcmp(req->path + 9, "XXXXXX", 6) != 0);
536   check_permission(req->path, 0700);
537 
538   /* Check if req->path is actually a directory */
539   r = uv_fs_stat(NULL, &stat_req, req->path, NULL);
540   ASSERT(r == 0);
541   ASSERT(((uv_stat_t*)stat_req.ptr)->st_mode & S_IFDIR);
542   uv_fs_req_cleanup(&stat_req);
543 }
544 
545 
546 static void mkdtemp_cb(uv_fs_t* req) {
547   ASSERT(req == &mkdtemp_req1);
548   check_mkdtemp_result(req);
549   mkdtemp_cb_count++;
550 }
551 
552 
553 static void check_mkstemp_result(uv_fs_t* req) {
554   int r;
555 
556   ASSERT(req->fs_type == UV_FS_MKSTEMP);
557   ASSERT(req->result >= 0);
558   ASSERT(req->path);
559   ASSERT(strlen(req->path) == 16);
560   ASSERT(memcmp(req->path, "test_file_", 10) == 0);
561   ASSERT(memcmp(req->path + 10, "XXXXXX", 6) != 0);
562   check_permission(req->path, 0600);
563 
564   /* Check if req->path is actually a file */
565   r = uv_fs_stat(NULL, &stat_req, req->path, NULL);
566   ASSERT(r == 0);
567   ASSERT(stat_req.statbuf.st_mode & S_IFREG);
568   uv_fs_req_cleanup(&stat_req);
569 }
570 
571 
572 static void mkstemp_cb(uv_fs_t* req) {
573   ASSERT(req == &mkstemp_req1);
574   check_mkstemp_result(req);
575   mkstemp_cb_count++;
576 }
577 
578 
579 static void rmdir_cb(uv_fs_t* req) {
580   ASSERT(req == &rmdir_req);
581   ASSERT(req->fs_type == UV_FS_RMDIR);
582   ASSERT(req->result == 0);
583   rmdir_cb_count++;
584   ASSERT(req->path);
585   ASSERT(memcmp(req->path, "test_dir\0", 9) == 0);
586   uv_fs_req_cleanup(req);
587 }
588 
589 
590 static void assert_is_file_type(uv_dirent_t dent) {
591 #ifdef HAVE_DIRENT_TYPES
592   /*
593    * For Apple and Windows, we know getdents is expected to work but for other
594    * environments, the filesystem dictates whether or not getdents supports
595    * returning the file type.
596    *
597    *   See:
598    *     http://man7.org/linux/man-pages/man2/getdents.2.html
599    *     https://github.com/libuv/libuv/issues/501
600    */
601   #if defined(__APPLE__) || defined(_WIN32)
602     ASSERT(dent.type == UV_DIRENT_FILE);
603   #else
604     ASSERT(dent.type == UV_DIRENT_FILE || dent.type == UV_DIRENT_UNKNOWN);
605   #endif
606 #else
607   ASSERT(dent.type == UV_DIRENT_UNKNOWN);
608 #endif
609 }
610 
611 
612 static void scandir_cb(uv_fs_t* req) {
613   uv_dirent_t dent;
614   ASSERT(req == &scandir_req);
615   ASSERT(req->fs_type == UV_FS_SCANDIR);
616   ASSERT(req->result == 2);
617   ASSERT(req->ptr);
618 
619   while (UV_EOF != uv_fs_scandir_next(req, &dent)) {
620     ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0);
621     assert_is_file_type(dent);
622   }
623   scandir_cb_count++;
624   ASSERT(req->path);
625   ASSERT(memcmp(req->path, "test_dir\0", 9) == 0);
626   uv_fs_req_cleanup(req);
627   ASSERT(!req->ptr);
628 }
629 
630 
631 static void empty_scandir_cb(uv_fs_t* req) {
632   uv_dirent_t dent;
633 
634   ASSERT(req == &scandir_req);
635   ASSERT(req->fs_type == UV_FS_SCANDIR);
636   ASSERT(req->result == 0);
637   ASSERT(req->ptr == NULL);
638   ASSERT(UV_EOF == uv_fs_scandir_next(req, &dent));
639   uv_fs_req_cleanup(req);
640   scandir_cb_count++;
641 }
642 
643 static void non_existent_scandir_cb(uv_fs_t* req) {
644   uv_dirent_t dent;
645 
646   ASSERT(req == &scandir_req);
647   ASSERT(req->fs_type == UV_FS_SCANDIR);
648   ASSERT(req->result == UV_ENOENT);
649   ASSERT(req->ptr == NULL);
650   ASSERT(UV_ENOENT == uv_fs_scandir_next(req, &dent));
651   uv_fs_req_cleanup(req);
652   scandir_cb_count++;
653 }
654 
655 
656 static void file_scandir_cb(uv_fs_t* req) {
657   ASSERT(req == &scandir_req);
658   ASSERT(req->fs_type == UV_FS_SCANDIR);
659   ASSERT(req->result == UV_ENOTDIR);
660   ASSERT(req->ptr == NULL);
661   uv_fs_req_cleanup(req);
662   scandir_cb_count++;
663 }
664 
665 
666 static void stat_cb(uv_fs_t* req) {
667   ASSERT(req == &stat_req);
668   ASSERT(req->fs_type == UV_FS_STAT || req->fs_type == UV_FS_LSTAT);
669   ASSERT(req->result == 0);
670   ASSERT(req->ptr);
671   stat_cb_count++;
672   uv_fs_req_cleanup(req);
673   ASSERT(!req->ptr);
674 }
675 
676 
677 static void sendfile_cb(uv_fs_t* req) {
678   ASSERT(req == &sendfile_req);
679   ASSERT(req->fs_type == UV_FS_SENDFILE);
680   ASSERT(req->result == 65546);
681   sendfile_cb_count++;
682   uv_fs_req_cleanup(req);
683 }
684 
685 
686 static void sendfile_nodata_cb(uv_fs_t* req) {
687   ASSERT(req == &sendfile_req);
688   ASSERT(req->fs_type == UV_FS_SENDFILE);
689   ASSERT(req->result == 0);
690   sendfile_cb_count++;
691   uv_fs_req_cleanup(req);
692 }
693 
694 
695 static void open_noent_cb(uv_fs_t* req) {
696   ASSERT(req->fs_type == UV_FS_OPEN);
697   ASSERT(req->result == UV_ENOENT);
698   open_cb_count++;
699   uv_fs_req_cleanup(req);
700 }
701 
702 static void open_nametoolong_cb(uv_fs_t* req) {
703   ASSERT(req->fs_type == UV_FS_OPEN);
704   ASSERT(req->result == UV_ENAMETOOLONG);
705   open_cb_count++;
706   uv_fs_req_cleanup(req);
707 }
708 
709 static void open_loop_cb(uv_fs_t* req) {
710   ASSERT(req->fs_type == UV_FS_OPEN);
711   ASSERT(req->result == UV_ELOOP);
712   open_cb_count++;
713   uv_fs_req_cleanup(req);
714 }
715 
716 
717 TEST_IMPL(fs_file_noent) {
718   uv_fs_t req;
719   int r;
720 
721   loop = uv_default_loop();
722 
723   r = uv_fs_open(NULL, &req, "does_not_exist", O_RDONLY, 0, NULL);
724   ASSERT(r == UV_ENOENT);
725   ASSERT(req.result == UV_ENOENT);
726   uv_fs_req_cleanup(&req);
727 
728   r = uv_fs_open(loop, &req, "does_not_exist", O_RDONLY, 0, open_noent_cb);
729   ASSERT(r == 0);
730 
731   ASSERT(open_cb_count == 0);
732   uv_run(loop, UV_RUN_DEFAULT);
733   ASSERT(open_cb_count == 1);
734 
735   /* TODO add EACCES test */
736 
737   MAKE_VALGRIND_HAPPY();
738   return 0;
739 }
740 
741 TEST_IMPL(fs_file_nametoolong) {
742   uv_fs_t req;
743   int r;
744   char name[TOO_LONG_NAME_LENGTH + 1];
745 
746   loop = uv_default_loop();
747 
748   memset(name, 'a', TOO_LONG_NAME_LENGTH);
749   name[TOO_LONG_NAME_LENGTH] = 0;
750 
751   r = uv_fs_open(NULL, &req, name, O_RDONLY, 0, NULL);
752   ASSERT(r == UV_ENAMETOOLONG);
753   ASSERT(req.result == UV_ENAMETOOLONG);
754   uv_fs_req_cleanup(&req);
755 
756   r = uv_fs_open(loop, &req, name, O_RDONLY, 0, open_nametoolong_cb);
757   ASSERT(r == 0);
758 
759   ASSERT(open_cb_count == 0);
760   uv_run(loop, UV_RUN_DEFAULT);
761   ASSERT(open_cb_count == 1);
762 
763   MAKE_VALGRIND_HAPPY();
764   return 0;
765 }
766 
767 TEST_IMPL(fs_file_loop) {
768   uv_fs_t req;
769   int r;
770 
771   loop = uv_default_loop();
772 
773   unlink("test_symlink");
774   r = uv_fs_symlink(NULL, &req, "test_symlink", "test_symlink", 0, NULL);
775 #ifdef _WIN32
776   /*
777    * Windows XP and Server 2003 don't support symlinks; we'll get UV_ENOTSUP.
778    * Starting with vista they are supported, but only when elevated, otherwise
779    * we'll see UV_EPERM.
780    */
781   if (r == UV_ENOTSUP || r == UV_EPERM)
782     return 0;
783 #elif defined(__MSYS__)
784   /* MSYS2's approximation of symlinks with copies does not work for broken
785      links.  */
786   if (r == UV_ENOENT)
787     return 0;
788 #endif
789   ASSERT(r == 0);
790   uv_fs_req_cleanup(&req);
791 
792   r = uv_fs_open(NULL, &req, "test_symlink", O_RDONLY, 0, NULL);
793   ASSERT(r == UV_ELOOP);
794   ASSERT(req.result == UV_ELOOP);
795   uv_fs_req_cleanup(&req);
796 
797   r = uv_fs_open(loop, &req, "test_symlink", O_RDONLY, 0, open_loop_cb);
798   ASSERT(r == 0);
799 
800   ASSERT(open_cb_count == 0);
801   uv_run(loop, UV_RUN_DEFAULT);
802   ASSERT(open_cb_count == 1);
803 
804   unlink("test_symlink");
805 
806   MAKE_VALGRIND_HAPPY();
807   return 0;
808 }
809 
810 static void check_utime(const char* path,
811                         double atime,
812                         double mtime,
813                         int test_lutime) {
814   uv_stat_t* s;
815   uv_fs_t req;
816   int r;
817 
818   if (test_lutime)
819     r = uv_fs_lstat(loop, &req, path, NULL);
820   else
821     r = uv_fs_stat(loop, &req, path, NULL);
822 
823   ASSERT(r == 0);
824 
825   ASSERT(req.result == 0);
826   s = &req.statbuf;
827 
828   ASSERT(s->st_atim.tv_sec + (s->st_atim.tv_nsec / 1000000000.0) == atime);
829   ASSERT(s->st_mtim.tv_sec + (s->st_mtim.tv_nsec / 1000000000.0) == mtime);
830 
831   uv_fs_req_cleanup(&req);
832 }
833 
834 
835 static void utime_cb(uv_fs_t* req) {
836   utime_check_t* c;
837 
838   ASSERT(req == &utime_req);
839   ASSERT(req->result == 0);
840   ASSERT(req->fs_type == UV_FS_UTIME);
841 
842   c = req->data;
843   check_utime(c->path, c->atime, c->mtime, /* test_lutime */ 0);
844 
845   uv_fs_req_cleanup(req);
846   utime_cb_count++;
847 }
848 
849 
850 static void futime_cb(uv_fs_t* req) {
851   utime_check_t* c;
852 
853   ASSERT(req == &futime_req);
854   ASSERT(req->result == 0);
855   ASSERT(req->fs_type == UV_FS_FUTIME);
856 
857   c = req->data;
858   check_utime(c->path, c->atime, c->mtime, /* test_lutime */ 0);
859 
860   uv_fs_req_cleanup(req);
861   futime_cb_count++;
862 }
863 
864 
865 static void lutime_cb(uv_fs_t* req) {
866   utime_check_t* c;
867 
868   ASSERT(req->result == 0);
869   ASSERT(req->fs_type == UV_FS_LUTIME);
870 
871   c = req->data;
872   check_utime(c->path, c->atime, c->mtime, /* test_lutime */ 1);
873 
874   uv_fs_req_cleanup(req);
875   lutime_cb_count++;
876 }
877 
878 
879 TEST_IMPL(fs_file_async) {
880   int r;
881 
882   /* Setup. */
883   unlink("test_file");
884   unlink("test_file2");
885 
886   loop = uv_default_loop();
887 
888   r = uv_fs_open(loop, &open_req1, "test_file", O_WRONLY | O_CREAT,
889       S_IRUSR | S_IWUSR, create_cb);
890   ASSERT(r == 0);
891   uv_run(loop, UV_RUN_DEFAULT);
892 
893   ASSERT(create_cb_count == 1);
894   ASSERT(write_cb_count == 1);
895   ASSERT(fsync_cb_count == 1);
896   ASSERT(fdatasync_cb_count == 1);
897   ASSERT(close_cb_count == 1);
898 
899   r = uv_fs_rename(loop, &rename_req, "test_file", "test_file2", rename_cb);
900   ASSERT(r == 0);
901 
902   uv_run(loop, UV_RUN_DEFAULT);
903   ASSERT(create_cb_count == 1);
904   ASSERT(write_cb_count == 1);
905   ASSERT(close_cb_count == 1);
906   ASSERT(rename_cb_count == 1);
907 
908   r = uv_fs_open(loop, &open_req1, "test_file2", O_RDWR, 0, open_cb);
909   ASSERT(r == 0);
910 
911   uv_run(loop, UV_RUN_DEFAULT);
912   ASSERT(open_cb_count == 1);
913   ASSERT(read_cb_count == 1);
914   ASSERT(close_cb_count == 2);
915   ASSERT(rename_cb_count == 1);
916   ASSERT(create_cb_count == 1);
917   ASSERT(write_cb_count == 1);
918   ASSERT(ftruncate_cb_count == 1);
919 
920   r = uv_fs_open(loop, &open_req1, "test_file2", O_RDONLY, 0, open_cb);
921   ASSERT(r == 0);
922 
923   uv_run(loop, UV_RUN_DEFAULT);
924   ASSERT(open_cb_count == 2);
925   ASSERT(read_cb_count == 2);
926   ASSERT(close_cb_count == 3);
927   ASSERT(rename_cb_count == 1);
928   ASSERT(unlink_cb_count == 1);
929   ASSERT(create_cb_count == 1);
930   ASSERT(write_cb_count == 1);
931   ASSERT(ftruncate_cb_count == 1);
932 
933   /* Cleanup. */
934   unlink("test_file");
935   unlink("test_file2");
936 
937   MAKE_VALGRIND_HAPPY();
938   return 0;
939 }
940 
941 
942 static void fs_file_sync(int add_flags) {
943   int r;
944 
945   /* Setup. */
946   unlink("test_file");
947   unlink("test_file2");
948 
949   loop = uv_default_loop();
950 
951   r = uv_fs_open(loop, &open_req1, "test_file",
952       O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL);
953   ASSERT(r >= 0);
954   ASSERT(open_req1.result >= 0);
955   uv_fs_req_cleanup(&open_req1);
956 
957   iov = uv_buf_init(test_buf, sizeof(test_buf));
958   r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
959   ASSERT(r >= 0);
960   ASSERT(write_req.result >= 0);
961   uv_fs_req_cleanup(&write_req);
962 
963   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
964   ASSERT(r == 0);
965   ASSERT(close_req.result == 0);
966   uv_fs_req_cleanup(&close_req);
967 
968   r = uv_fs_open(NULL, &open_req1, "test_file", O_RDWR | add_flags, 0, NULL);
969   ASSERT(r >= 0);
970   ASSERT(open_req1.result >= 0);
971   uv_fs_req_cleanup(&open_req1);
972 
973   iov = uv_buf_init(buf, sizeof(buf));
974   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
975   ASSERT(r >= 0);
976   ASSERT(read_req.result >= 0);
977   ASSERT(strcmp(buf, test_buf) == 0);
978   uv_fs_req_cleanup(&read_req);
979 
980   r = uv_fs_ftruncate(NULL, &ftruncate_req, open_req1.result, 7, NULL);
981   ASSERT(r == 0);
982   ASSERT(ftruncate_req.result == 0);
983   uv_fs_req_cleanup(&ftruncate_req);
984 
985   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
986   ASSERT(r == 0);
987   ASSERT(close_req.result == 0);
988   uv_fs_req_cleanup(&close_req);
989 
990   r = uv_fs_rename(NULL, &rename_req, "test_file", "test_file2", NULL);
991   ASSERT(r == 0);
992   ASSERT(rename_req.result == 0);
993   uv_fs_req_cleanup(&rename_req);
994 
995   r = uv_fs_open(NULL, &open_req1, "test_file2", O_RDONLY | add_flags, 0,
996       NULL);
997   ASSERT(r >= 0);
998   ASSERT(open_req1.result >= 0);
999   uv_fs_req_cleanup(&open_req1);
1000 
1001   memset(buf, 0, sizeof(buf));
1002   iov = uv_buf_init(buf, sizeof(buf));
1003   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
1004   ASSERT(r >= 0);
1005   ASSERT(read_req.result >= 0);
1006   ASSERT(strcmp(buf, "test-bu") == 0);
1007   uv_fs_req_cleanup(&read_req);
1008 
1009   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
1010   ASSERT(r == 0);
1011   ASSERT(close_req.result == 0);
1012   uv_fs_req_cleanup(&close_req);
1013 
1014   r = uv_fs_unlink(NULL, &unlink_req, "test_file2", NULL);
1015   ASSERT(r == 0);
1016   ASSERT(unlink_req.result == 0);
1017   uv_fs_req_cleanup(&unlink_req);
1018 
1019   /* Cleanup */
1020   unlink("test_file");
1021   unlink("test_file2");
1022 }
1023 TEST_IMPL(fs_file_sync) {
1024   fs_file_sync(0);
1025   fs_file_sync(UV_FS_O_FILEMAP);
1026 
1027   MAKE_VALGRIND_HAPPY();
1028   return 0;
1029 }
1030 
1031 
1032 static void fs_file_write_null_buffer(int add_flags) {
1033   int r;
1034 
1035   /* Setup. */
1036   unlink("test_file");
1037 
1038   loop = uv_default_loop();
1039 
1040   r = uv_fs_open(NULL, &open_req1, "test_file",
1041       O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL);
1042   ASSERT(r >= 0);
1043   ASSERT(open_req1.result >= 0);
1044   uv_fs_req_cleanup(&open_req1);
1045 
1046   iov = uv_buf_init(NULL, 0);
1047   r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
1048   ASSERT(r == 0);
1049   ASSERT(write_req.result == 0);
1050   uv_fs_req_cleanup(&write_req);
1051 
1052   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
1053   ASSERT(r == 0);
1054   ASSERT(close_req.result == 0);
1055   uv_fs_req_cleanup(&close_req);
1056 
1057   unlink("test_file");
1058 }
1059 TEST_IMPL(fs_file_write_null_buffer) {
1060   fs_file_write_null_buffer(0);
1061   fs_file_write_null_buffer(UV_FS_O_FILEMAP);
1062 
1063   MAKE_VALGRIND_HAPPY();
1064   return 0;
1065 }
1066 
1067 
1068 TEST_IMPL(fs_async_dir) {
1069   int r;
1070   uv_dirent_t dent;
1071 
1072   /* Setup */
1073   unlink("test_dir/file1");
1074   unlink("test_dir/file2");
1075   rmdir("test_dir");
1076 
1077   loop = uv_default_loop();
1078 
1079   r = uv_fs_mkdir(loop, &mkdir_req, "test_dir", 0755, mkdir_cb);
1080   ASSERT(r == 0);
1081 
1082   uv_run(loop, UV_RUN_DEFAULT);
1083   ASSERT(mkdir_cb_count == 1);
1084 
1085   /* Create 2 files synchronously. */
1086   r = uv_fs_open(NULL, &open_req1, "test_dir/file1", O_WRONLY | O_CREAT,
1087       S_IWUSR | S_IRUSR, NULL);
1088   ASSERT(r >= 0);
1089   uv_fs_req_cleanup(&open_req1);
1090   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
1091   ASSERT(r == 0);
1092   uv_fs_req_cleanup(&close_req);
1093 
1094   r = uv_fs_open(NULL, &open_req1, "test_dir/file2", O_WRONLY | O_CREAT,
1095       S_IWUSR | S_IRUSR, NULL);
1096   ASSERT(r >= 0);
1097   uv_fs_req_cleanup(&open_req1);
1098   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
1099   ASSERT(r == 0);
1100   uv_fs_req_cleanup(&close_req);
1101 
1102   r = uv_fs_scandir(loop, &scandir_req, "test_dir", 0, scandir_cb);
1103   ASSERT(r == 0);
1104 
1105   uv_run(loop, UV_RUN_DEFAULT);
1106   ASSERT(scandir_cb_count == 1);
1107 
1108   /* sync uv_fs_scandir */
1109   r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL);
1110   ASSERT(r == 2);
1111   ASSERT(scandir_req.result == 2);
1112   ASSERT(scandir_req.ptr);
1113   while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) {
1114     ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0);
1115     assert_is_file_type(dent);
1116   }
1117   uv_fs_req_cleanup(&scandir_req);
1118   ASSERT(!scandir_req.ptr);
1119 
1120   r = uv_fs_stat(loop, &stat_req, "test_dir", stat_cb);
1121   ASSERT(r == 0);
1122   uv_run(loop, UV_RUN_DEFAULT);
1123 
1124   r = uv_fs_stat(loop, &stat_req, "test_dir/", stat_cb);
1125   ASSERT(r == 0);
1126   uv_run(loop, UV_RUN_DEFAULT);
1127 
1128   r = uv_fs_lstat(loop, &stat_req, "test_dir", stat_cb);
1129   ASSERT(r == 0);
1130   uv_run(loop, UV_RUN_DEFAULT);
1131 
1132   r = uv_fs_lstat(loop, &stat_req, "test_dir/", stat_cb);
1133   ASSERT(r == 0);
1134   uv_run(loop, UV_RUN_DEFAULT);
1135 
1136   ASSERT(stat_cb_count == 4);
1137 
1138   r = uv_fs_unlink(loop, &unlink_req, "test_dir/file1", unlink_cb);
1139   ASSERT(r == 0);
1140   uv_run(loop, UV_RUN_DEFAULT);
1141   ASSERT(unlink_cb_count == 1);
1142 
1143   r = uv_fs_unlink(loop, &unlink_req, "test_dir/file2", unlink_cb);
1144   ASSERT(r == 0);
1145   uv_run(loop, UV_RUN_DEFAULT);
1146   ASSERT(unlink_cb_count == 2);
1147 
1148   r = uv_fs_rmdir(loop, &rmdir_req, "test_dir", rmdir_cb);
1149   ASSERT(r == 0);
1150   uv_run(loop, UV_RUN_DEFAULT);
1151   ASSERT(rmdir_cb_count == 1);
1152 
1153   /* Cleanup */
1154   unlink("test_dir/file1");
1155   unlink("test_dir/file2");
1156   rmdir("test_dir");
1157 
1158   MAKE_VALGRIND_HAPPY();
1159   return 0;
1160 }
1161 
1162 
1163 static int test_sendfile(void (*setup)(int), uv_fs_cb cb, off_t expected_size) {
1164   int f, r;
1165   struct stat s1, s2;
1166 
1167   loop = uv_default_loop();
1168 
1169   /* Setup. */
1170   unlink("test_file");
1171   unlink("test_file2");
1172 
1173   f = open("test_file", O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR);
1174   ASSERT(f != -1);
1175 
1176   if (setup != NULL)
1177     setup(f);
1178 
1179   r = close(f);
1180   ASSERT(r == 0);
1181 
1182   /* Test starts here. */
1183   r = uv_fs_open(NULL, &open_req1, "test_file", O_RDWR, 0, NULL);
1184   ASSERT(r >= 0);
1185   ASSERT(open_req1.result >= 0);
1186   uv_fs_req_cleanup(&open_req1);
1187 
1188   r = uv_fs_open(NULL, &open_req2, "test_file2", O_WRONLY | O_CREAT,
1189       S_IWUSR | S_IRUSR, NULL);
1190   ASSERT(r >= 0);
1191   ASSERT(open_req2.result >= 0);
1192   uv_fs_req_cleanup(&open_req2);
1193 
1194   r = uv_fs_sendfile(loop, &sendfile_req, open_req2.result, open_req1.result,
1195       0, 131072, cb);
1196   ASSERT(r == 0);
1197   uv_run(loop, UV_RUN_DEFAULT);
1198 
1199   ASSERT(sendfile_cb_count == 1);
1200 
1201   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
1202   ASSERT(r == 0);
1203   uv_fs_req_cleanup(&close_req);
1204   r = uv_fs_close(NULL, &close_req, open_req2.result, NULL);
1205   ASSERT(r == 0);
1206   uv_fs_req_cleanup(&close_req);
1207 
1208   ASSERT(0 == stat("test_file", &s1));
1209   ASSERT(0 == stat("test_file2", &s2));
1210   ASSERT(s1.st_size == s2.st_size);
1211   ASSERT(s2.st_size == expected_size);
1212 
1213   /* Cleanup. */
1214   unlink("test_file");
1215   unlink("test_file2");
1216 
1217   MAKE_VALGRIND_HAPPY();
1218   return 0;
1219 }
1220 
1221 
1222 static void sendfile_setup(int f) {
1223   ASSERT(6 == write(f, "begin\n", 6));
1224   ASSERT(65542 == lseek(f, 65536, SEEK_CUR));
1225   ASSERT(4 == write(f, "end\n", 4));
1226 }
1227 
1228 
1229 TEST_IMPL(fs_async_sendfile) {
1230   return test_sendfile(sendfile_setup, sendfile_cb, 65546);
1231 }
1232 
1233 
1234 TEST_IMPL(fs_async_sendfile_nodata) {
1235   return test_sendfile(NULL, sendfile_nodata_cb, 0);
1236 }
1237 
1238 
1239 TEST_IMPL(fs_mkdtemp) {
1240   int r;
1241   const char* path_template = "test_dir_XXXXXX";
1242 
1243   loop = uv_default_loop();
1244 
1245   r = uv_fs_mkdtemp(loop, &mkdtemp_req1, path_template, mkdtemp_cb);
1246   ASSERT(r == 0);
1247 
1248   uv_run(loop, UV_RUN_DEFAULT);
1249   ASSERT(mkdtemp_cb_count == 1);
1250 
1251   /* sync mkdtemp */
1252   r = uv_fs_mkdtemp(NULL, &mkdtemp_req2, path_template, NULL);
1253   ASSERT(r == 0);
1254   check_mkdtemp_result(&mkdtemp_req2);
1255 
1256   /* mkdtemp return different values on subsequent calls */
1257   ASSERT(strcmp(mkdtemp_req1.path, mkdtemp_req2.path) != 0);
1258 
1259   /* Cleanup */
1260   rmdir(mkdtemp_req1.path);
1261   rmdir(mkdtemp_req2.path);
1262   uv_fs_req_cleanup(&mkdtemp_req1);
1263   uv_fs_req_cleanup(&mkdtemp_req2);
1264 
1265   MAKE_VALGRIND_HAPPY();
1266   return 0;
1267 }
1268 
1269 
1270 TEST_IMPL(fs_mkstemp) {
1271   int r;
1272   int fd;
1273   const char path_template[] = "test_file_XXXXXX";
1274   uv_fs_t req;
1275 
1276   loop = uv_default_loop();
1277 
1278   r = uv_fs_mkstemp(loop, &mkstemp_req1, path_template, mkstemp_cb);
1279   ASSERT(r == 0);
1280 
1281   uv_run(loop, UV_RUN_DEFAULT);
1282   ASSERT(mkstemp_cb_count == 1);
1283 
1284   /* sync mkstemp */
1285   r = uv_fs_mkstemp(NULL, &mkstemp_req2, path_template, NULL);
1286   ASSERT(r >= 0);
1287   check_mkstemp_result(&mkstemp_req2);
1288 
1289   /* mkstemp return different values on subsequent calls */
1290   ASSERT(strcmp(mkstemp_req1.path, mkstemp_req2.path) != 0);
1291 
1292   /* invalid template returns EINVAL */
1293   ASSERT(uv_fs_mkstemp(NULL, &mkstemp_req3, "test_file", NULL) == UV_EINVAL);
1294 
1295   /* We can write to the opened file */
1296   iov = uv_buf_init(test_buf, sizeof(test_buf));
1297   r = uv_fs_write(NULL, &req, mkstemp_req1.result, &iov, 1, -1, NULL);
1298   ASSERT(r == sizeof(test_buf));
1299   ASSERT(req.result == sizeof(test_buf));
1300   uv_fs_req_cleanup(&req);
1301 
1302   /* Cleanup */
1303   uv_fs_close(NULL, &req, mkstemp_req1.result, NULL);
1304   uv_fs_req_cleanup(&req);
1305   uv_fs_close(NULL, &req, mkstemp_req2.result, NULL);
1306   uv_fs_req_cleanup(&req);
1307 
1308   fd = uv_fs_open(NULL, &req, mkstemp_req1.path , O_RDONLY, 0, NULL);
1309   ASSERT(fd >= 0);
1310   uv_fs_req_cleanup(&req);
1311 
1312   memset(buf, 0, sizeof(buf));
1313   iov = uv_buf_init(buf, sizeof(buf));
1314   r = uv_fs_read(NULL, &req, fd, &iov, 1, -1, NULL);
1315   ASSERT(r >= 0);
1316   ASSERT(req.result >= 0);
1317   ASSERT(strcmp(buf, test_buf) == 0);
1318   uv_fs_req_cleanup(&req);
1319 
1320   uv_fs_close(NULL, &req, fd, NULL);
1321   uv_fs_req_cleanup(&req);
1322 
1323   unlink(mkstemp_req1.path);
1324   unlink(mkstemp_req2.path);
1325   uv_fs_req_cleanup(&mkstemp_req1);
1326   uv_fs_req_cleanup(&mkstemp_req2);
1327 
1328   MAKE_VALGRIND_HAPPY();
1329   return 0;
1330 }
1331 
1332 
1333 TEST_IMPL(fs_fstat) {
1334   int r;
1335   uv_fs_t req;
1336   uv_file file;
1337   uv_stat_t* s;
1338 #ifndef _WIN32
1339   struct stat t;
1340 #endif
1341 
1342   /* Setup. */
1343   unlink("test_file");
1344 
1345   loop = uv_default_loop();
1346 
1347   r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
1348       S_IWUSR | S_IRUSR, NULL);
1349   ASSERT(r >= 0);
1350   ASSERT(req.result >= 0);
1351   file = req.result;
1352   uv_fs_req_cleanup(&req);
1353 
1354 #ifndef _WIN32
1355   ASSERT(0 == fstat(file, &t));
1356   ASSERT(0 == uv_fs_fstat(NULL, &req, file, NULL));
1357   ASSERT(req.result == 0);
1358   s = req.ptr;
1359 # if defined(__APPLE__)
1360   ASSERT(s->st_birthtim.tv_sec == t.st_birthtimespec.tv_sec);
1361   ASSERT(s->st_birthtim.tv_nsec == t.st_birthtimespec.tv_nsec);
1362 # elif defined(__linux__)
1363   /* If statx() is supported, the birth time should be equal to the change time
1364    * because we just created the file. On older kernels, it's set to zero.
1365    */
1366   ASSERT(s->st_birthtim.tv_sec == 0 ||
1367          s->st_birthtim.tv_sec == t.st_ctim.tv_sec);
1368   ASSERT(s->st_birthtim.tv_nsec == 0 ||
1369          s->st_birthtim.tv_nsec == t.st_ctim.tv_nsec);
1370 # endif
1371 #endif
1372 
1373   iov = uv_buf_init(test_buf, sizeof(test_buf));
1374   r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
1375   ASSERT(r == sizeof(test_buf));
1376   ASSERT(req.result == sizeof(test_buf));
1377   uv_fs_req_cleanup(&req);
1378 
1379   memset(&req.statbuf, 0xaa, sizeof(req.statbuf));
1380   r = uv_fs_fstat(NULL, &req, file, NULL);
1381   ASSERT(r == 0);
1382   ASSERT(req.result == 0);
1383   s = req.ptr;
1384   ASSERT(s->st_size == sizeof(test_buf));
1385 
1386 #ifndef _WIN32
1387   r = fstat(file, &t);
1388   ASSERT(r == 0);
1389 
1390   ASSERT(s->st_dev == (uint64_t) t.st_dev);
1391   ASSERT(s->st_mode == (uint64_t) t.st_mode);
1392   ASSERT(s->st_nlink == (uint64_t) t.st_nlink);
1393   ASSERT(s->st_uid == (uint64_t) t.st_uid);
1394   ASSERT(s->st_gid == (uint64_t) t.st_gid);
1395   ASSERT(s->st_rdev == (uint64_t) t.st_rdev);
1396   ASSERT(s->st_ino == (uint64_t) t.st_ino);
1397   ASSERT(s->st_size == (uint64_t) t.st_size);
1398   ASSERT(s->st_blksize == (uint64_t) t.st_blksize);
1399   ASSERT(s->st_blocks == (uint64_t) t.st_blocks);
1400 #if defined(__APPLE__)
1401   ASSERT(s->st_atim.tv_sec == t.st_atimespec.tv_sec);
1402   ASSERT(s->st_atim.tv_nsec == t.st_atimespec.tv_nsec);
1403   ASSERT(s->st_mtim.tv_sec == t.st_mtimespec.tv_sec);
1404   ASSERT(s->st_mtim.tv_nsec == t.st_mtimespec.tv_nsec);
1405   ASSERT(s->st_ctim.tv_sec == t.st_ctimespec.tv_sec);
1406   ASSERT(s->st_ctim.tv_nsec == t.st_ctimespec.tv_nsec);
1407 #elif defined(_AIX)
1408   ASSERT(s->st_atim.tv_sec == t.st_atime);
1409   ASSERT(s->st_atim.tv_nsec == 0);
1410   ASSERT(s->st_mtim.tv_sec == t.st_mtime);
1411   ASSERT(s->st_mtim.tv_nsec == 0);
1412   ASSERT(s->st_ctim.tv_sec == t.st_ctime);
1413   ASSERT(s->st_ctim.tv_nsec == 0);
1414 #elif defined(__ANDROID__)
1415   ASSERT(s->st_atim.tv_sec == t.st_atime);
1416   ASSERT(s->st_atim.tv_nsec == t.st_atimensec);
1417   ASSERT(s->st_mtim.tv_sec == t.st_mtime);
1418   ASSERT(s->st_mtim.tv_nsec == t.st_mtimensec);
1419   ASSERT(s->st_ctim.tv_sec == t.st_ctime);
1420   ASSERT(s->st_ctim.tv_nsec == t.st_ctimensec);
1421 #elif defined(__sun)           || \
1422       defined(__DragonFly__)   || \
1423       defined(__FreeBSD__)     || \
1424       defined(__OpenBSD__)     || \
1425       defined(__NetBSD__)      || \
1426       defined(_GNU_SOURCE)     || \
1427       defined(_BSD_SOURCE)     || \
1428       defined(_SVID_SOURCE)    || \
1429       defined(_XOPEN_SOURCE)   || \
1430       defined(_DEFAULT_SOURCE)
1431   ASSERT(s->st_atim.tv_sec == t.st_atim.tv_sec);
1432   ASSERT(s->st_atim.tv_nsec == t.st_atim.tv_nsec);
1433   ASSERT(s->st_mtim.tv_sec == t.st_mtim.tv_sec);
1434   ASSERT(s->st_mtim.tv_nsec == t.st_mtim.tv_nsec);
1435   ASSERT(s->st_ctim.tv_sec == t.st_ctim.tv_sec);
1436   ASSERT(s->st_ctim.tv_nsec == t.st_ctim.tv_nsec);
1437 # if defined(__FreeBSD__)    || \
1438      defined(__NetBSD__)
1439   ASSERT(s->st_birthtim.tv_sec == t.st_birthtim.tv_sec);
1440   ASSERT(s->st_birthtim.tv_nsec == t.st_birthtim.tv_nsec);
1441 # endif
1442 #else
1443   ASSERT(s->st_atim.tv_sec == t.st_atime);
1444   ASSERT(s->st_atim.tv_nsec == 0);
1445   ASSERT(s->st_mtim.tv_sec == t.st_mtime);
1446   ASSERT(s->st_mtim.tv_nsec == 0);
1447   ASSERT(s->st_ctim.tv_sec == t.st_ctime);
1448   ASSERT(s->st_ctim.tv_nsec == 0);
1449 #endif
1450 #endif
1451 
1452 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
1453   ASSERT(s->st_flags == t.st_flags);
1454   ASSERT(s->st_gen == t.st_gen);
1455 #else
1456   ASSERT(s->st_flags == 0);
1457   ASSERT(s->st_gen == 0);
1458 #endif
1459 
1460   uv_fs_req_cleanup(&req);
1461 
1462   /* Now do the uv_fs_fstat call asynchronously */
1463   r = uv_fs_fstat(loop, &req, file, fstat_cb);
1464   ASSERT(r == 0);
1465   uv_run(loop, UV_RUN_DEFAULT);
1466   ASSERT(fstat_cb_count == 1);
1467 
1468 
1469   r = uv_fs_close(NULL, &req, file, NULL);
1470   ASSERT(r == 0);
1471   ASSERT(req.result == 0);
1472   uv_fs_req_cleanup(&req);
1473 
1474   /*
1475    * Run the loop just to check we don't have make any extraneous uv_ref()
1476    * calls. This should drop out immediately.
1477    */
1478   uv_run(loop, UV_RUN_DEFAULT);
1479 
1480   /* Cleanup. */
1481   unlink("test_file");
1482 
1483   MAKE_VALGRIND_HAPPY();
1484   return 0;
1485 }
1486 
1487 
1488 TEST_IMPL(fs_access) {
1489   int r;
1490   uv_fs_t req;
1491   uv_file file;
1492 
1493   /* Setup. */
1494   unlink("test_file");
1495   rmdir("test_dir");
1496 
1497   loop = uv_default_loop();
1498 
1499   /* File should not exist */
1500   r = uv_fs_access(NULL, &req, "test_file", F_OK, NULL);
1501   ASSERT(r < 0);
1502   ASSERT(req.result < 0);
1503   uv_fs_req_cleanup(&req);
1504 
1505   /* File should not exist */
1506   r = uv_fs_access(loop, &req, "test_file", F_OK, access_cb);
1507   ASSERT(r == 0);
1508   uv_run(loop, UV_RUN_DEFAULT);
1509   ASSERT(access_cb_count == 1);
1510   access_cb_count = 0; /* reset for the next test */
1511 
1512   /* Create file */
1513   r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
1514                  S_IWUSR | S_IRUSR, NULL);
1515   ASSERT(r >= 0);
1516   ASSERT(req.result >= 0);
1517   file = req.result;
1518   uv_fs_req_cleanup(&req);
1519 
1520   /* File should exist */
1521   r = uv_fs_access(NULL, &req, "test_file", F_OK, NULL);
1522   ASSERT(r == 0);
1523   ASSERT(req.result == 0);
1524   uv_fs_req_cleanup(&req);
1525 
1526   /* File should exist */
1527   r = uv_fs_access(loop, &req, "test_file", F_OK, access_cb);
1528   ASSERT(r == 0);
1529   uv_run(loop, UV_RUN_DEFAULT);
1530   ASSERT(access_cb_count == 1);
1531   access_cb_count = 0; /* reset for the next test */
1532 
1533   /* Close file */
1534   r = uv_fs_close(NULL, &req, file, NULL);
1535   ASSERT(r == 0);
1536   ASSERT(req.result == 0);
1537   uv_fs_req_cleanup(&req);
1538 
1539   /* Directory access */
1540   r = uv_fs_mkdir(NULL, &req, "test_dir", 0777, NULL);
1541   ASSERT(r == 0);
1542   uv_fs_req_cleanup(&req);
1543 
1544   r = uv_fs_access(NULL, &req, "test_dir", W_OK, NULL);
1545   ASSERT(r == 0);
1546   ASSERT(req.result == 0);
1547   uv_fs_req_cleanup(&req);
1548 
1549   /*
1550    * Run the loop just to check we don't have make any extraneous uv_ref()
1551    * calls. This should drop out immediately.
1552    */
1553   uv_run(loop, UV_RUN_DEFAULT);
1554 
1555   /* Cleanup. */
1556   unlink("test_file");
1557   rmdir("test_dir");
1558 
1559   MAKE_VALGRIND_HAPPY();
1560   return 0;
1561 }
1562 
1563 
1564 TEST_IMPL(fs_chmod) {
1565   int r;
1566   uv_fs_t req;
1567   uv_file file;
1568 
1569   /* Setup. */
1570   unlink("test_file");
1571 
1572   loop = uv_default_loop();
1573 
1574   r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
1575       S_IWUSR | S_IRUSR, NULL);
1576   ASSERT(r >= 0);
1577   ASSERT(req.result >= 0);
1578   file = req.result;
1579   uv_fs_req_cleanup(&req);
1580 
1581   iov = uv_buf_init(test_buf, sizeof(test_buf));
1582   r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
1583   ASSERT(r == sizeof(test_buf));
1584   ASSERT(req.result == sizeof(test_buf));
1585   uv_fs_req_cleanup(&req);
1586 
1587 #ifndef _WIN32
1588   /* Make the file write-only */
1589   r = uv_fs_chmod(NULL, &req, "test_file", 0200, NULL);
1590   ASSERT(r == 0);
1591   ASSERT(req.result == 0);
1592   uv_fs_req_cleanup(&req);
1593 
1594   check_permission("test_file", 0200);
1595 #endif
1596 
1597   /* Make the file read-only */
1598   r = uv_fs_chmod(NULL, &req, "test_file", 0400, NULL);
1599   ASSERT(r == 0);
1600   ASSERT(req.result == 0);
1601   uv_fs_req_cleanup(&req);
1602 
1603   check_permission("test_file", 0400);
1604 
1605   /* Make the file read+write with sync uv_fs_fchmod */
1606   r = uv_fs_fchmod(NULL, &req, file, 0600, NULL);
1607   ASSERT(r == 0);
1608   ASSERT(req.result == 0);
1609   uv_fs_req_cleanup(&req);
1610 
1611   check_permission("test_file", 0600);
1612 
1613 #ifndef _WIN32
1614   /* async chmod */
1615   {
1616     static int mode = 0200;
1617     req.data = &mode;
1618   }
1619   r = uv_fs_chmod(loop, &req, "test_file", 0200, chmod_cb);
1620   ASSERT(r == 0);
1621   uv_run(loop, UV_RUN_DEFAULT);
1622   ASSERT(chmod_cb_count == 1);
1623   chmod_cb_count = 0; /* reset for the next test */
1624 #endif
1625 
1626   /* async chmod */
1627   {
1628     static int mode = 0400;
1629     req.data = &mode;
1630   }
1631   r = uv_fs_chmod(loop, &req, "test_file", 0400, chmod_cb);
1632   ASSERT(r == 0);
1633   uv_run(loop, UV_RUN_DEFAULT);
1634   ASSERT(chmod_cb_count == 1);
1635 
1636   /* async fchmod */
1637   {
1638     static int mode = 0600;
1639     req.data = &mode;
1640   }
1641   r = uv_fs_fchmod(loop, &req, file, 0600, fchmod_cb);
1642   ASSERT(r == 0);
1643   uv_run(loop, UV_RUN_DEFAULT);
1644   ASSERT(fchmod_cb_count == 1);
1645 
1646   uv_fs_close(loop, &req, file, NULL);
1647 
1648   /*
1649    * Run the loop just to check we don't have make any extraneous uv_ref()
1650    * calls. This should drop out immediately.
1651    */
1652   uv_run(loop, UV_RUN_DEFAULT);
1653 
1654   /* Cleanup. */
1655   unlink("test_file");
1656 
1657   MAKE_VALGRIND_HAPPY();
1658   return 0;
1659 }
1660 
1661 
1662 TEST_IMPL(fs_unlink_readonly) {
1663   int r;
1664   uv_fs_t req;
1665   uv_file file;
1666 
1667   /* Setup. */
1668   unlink("test_file");
1669 
1670   loop = uv_default_loop();
1671 
1672   r = uv_fs_open(NULL,
1673                  &req,
1674                  "test_file",
1675                  O_RDWR | O_CREAT,
1676                  S_IWUSR | S_IRUSR,
1677                  NULL);
1678   ASSERT(r >= 0);
1679   ASSERT(req.result >= 0);
1680   file = req.result;
1681   uv_fs_req_cleanup(&req);
1682 
1683   iov = uv_buf_init(test_buf, sizeof(test_buf));
1684   r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
1685   ASSERT(r == sizeof(test_buf));
1686   ASSERT(req.result == sizeof(test_buf));
1687   uv_fs_req_cleanup(&req);
1688 
1689   uv_fs_close(loop, &req, file, NULL);
1690 
1691   /* Make the file read-only */
1692   r = uv_fs_chmod(NULL, &req, "test_file", 0400, NULL);
1693   ASSERT(r == 0);
1694   ASSERT(req.result == 0);
1695   uv_fs_req_cleanup(&req);
1696 
1697   check_permission("test_file", 0400);
1698 
1699   /* Try to unlink the file */
1700   r = uv_fs_unlink(NULL, &req, "test_file", NULL);
1701   ASSERT(r == 0);
1702   ASSERT(req.result == 0);
1703   uv_fs_req_cleanup(&req);
1704 
1705   /*
1706   * Run the loop just to check we don't have make any extraneous uv_ref()
1707   * calls. This should drop out immediately.
1708   */
1709   uv_run(loop, UV_RUN_DEFAULT);
1710 
1711   /* Cleanup. */
1712   uv_fs_chmod(NULL, &req, "test_file", 0600, NULL);
1713   uv_fs_req_cleanup(&req);
1714   unlink("test_file");
1715 
1716   MAKE_VALGRIND_HAPPY();
1717   return 0;
1718 }
1719 
1720 #ifdef _WIN32
1721 TEST_IMPL(fs_unlink_archive_readonly) {
1722   int r;
1723   uv_fs_t req;
1724   uv_file file;
1725 
1726   /* Setup. */
1727   unlink("test_file");
1728 
1729   loop = uv_default_loop();
1730 
1731   r = uv_fs_open(NULL,
1732                  &req,
1733                  "test_file",
1734                  O_RDWR | O_CREAT,
1735                  S_IWUSR | S_IRUSR,
1736                  NULL);
1737   ASSERT(r >= 0);
1738   ASSERT(req.result >= 0);
1739   file = req.result;
1740   uv_fs_req_cleanup(&req);
1741 
1742   iov = uv_buf_init(test_buf, sizeof(test_buf));
1743   r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
1744   ASSERT(r == sizeof(test_buf));
1745   ASSERT(req.result == sizeof(test_buf));
1746   uv_fs_req_cleanup(&req);
1747 
1748   uv_fs_close(loop, &req, file, NULL);
1749 
1750   /* Make the file read-only and clear archive flag */
1751   r = SetFileAttributes("test_file", FILE_ATTRIBUTE_READONLY);
1752   ASSERT(r != 0);
1753   uv_fs_req_cleanup(&req);
1754 
1755   check_permission("test_file", 0400);
1756 
1757   /* Try to unlink the file */
1758   r = uv_fs_unlink(NULL, &req, "test_file", NULL);
1759   ASSERT(r == 0);
1760   ASSERT(req.result == 0);
1761   uv_fs_req_cleanup(&req);
1762 
1763   /*
1764   * Run the loop just to check we don't have make any extraneous uv_ref()
1765   * calls. This should drop out immediately.
1766   */
1767   uv_run(loop, UV_RUN_DEFAULT);
1768 
1769   /* Cleanup. */
1770   uv_fs_chmod(NULL, &req, "test_file", 0600, NULL);
1771   uv_fs_req_cleanup(&req);
1772   unlink("test_file");
1773 
1774   MAKE_VALGRIND_HAPPY();
1775   return 0;
1776 }
1777 #endif
1778 
1779 TEST_IMPL(fs_chown) {
1780   int r;
1781   uv_fs_t req;
1782   uv_file file;
1783 
1784   /* Setup. */
1785   unlink("test_file");
1786   unlink("test_file_link");
1787 
1788   loop = uv_default_loop();
1789 
1790   r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
1791       S_IWUSR | S_IRUSR, NULL);
1792   ASSERT(r >= 0);
1793   ASSERT(req.result >= 0);
1794   file = req.result;
1795   uv_fs_req_cleanup(&req);
1796 
1797   /* sync chown */
1798   r = uv_fs_chown(NULL, &req, "test_file", -1, -1, NULL);
1799   ASSERT(r == 0);
1800   ASSERT(req.result == 0);
1801   uv_fs_req_cleanup(&req);
1802 
1803   /* sync fchown */
1804   r = uv_fs_fchown(NULL, &req, file, -1, -1, NULL);
1805   ASSERT(r == 0);
1806   ASSERT(req.result == 0);
1807   uv_fs_req_cleanup(&req);
1808 
1809   /* async chown */
1810   r = uv_fs_chown(loop, &req, "test_file", -1, -1, chown_cb);
1811   ASSERT(r == 0);
1812   uv_run(loop, UV_RUN_DEFAULT);
1813   ASSERT(chown_cb_count == 1);
1814 
1815 #ifndef __MVS__
1816   /* chown to root (fail) */
1817   chown_cb_count = 0;
1818   r = uv_fs_chown(loop, &req, "test_file", 0, 0, chown_root_cb);
1819   ASSERT(r == 0);
1820   uv_run(loop, UV_RUN_DEFAULT);
1821   ASSERT(chown_cb_count == 1);
1822 #endif
1823 
1824   /* async fchown */
1825   r = uv_fs_fchown(loop, &req, file, -1, -1, fchown_cb);
1826   ASSERT(r == 0);
1827   uv_run(loop, UV_RUN_DEFAULT);
1828   ASSERT(fchown_cb_count == 1);
1829 
1830 #ifndef __HAIKU__
1831   /* Haiku doesn't support hardlink */
1832   /* sync link */
1833   r = uv_fs_link(NULL, &req, "test_file", "test_file_link", NULL);
1834   ASSERT(r == 0);
1835   ASSERT(req.result == 0);
1836   uv_fs_req_cleanup(&req);
1837 
1838   /* sync lchown */
1839   r = uv_fs_lchown(NULL, &req, "test_file_link", -1, -1, NULL);
1840   ASSERT(r == 0);
1841   ASSERT(req.result == 0);
1842   uv_fs_req_cleanup(&req);
1843 
1844   /* async lchown */
1845   r = uv_fs_lchown(loop, &req, "test_file_link", -1, -1, lchown_cb);
1846   ASSERT(r == 0);
1847   uv_run(loop, UV_RUN_DEFAULT);
1848   ASSERT(lchown_cb_count == 1);
1849 #endif
1850 
1851   /* Close file */
1852   r = uv_fs_close(NULL, &req, file, NULL);
1853   ASSERT(r == 0);
1854   ASSERT(req.result == 0);
1855   uv_fs_req_cleanup(&req);
1856 
1857   /*
1858    * Run the loop just to check we don't have make any extraneous uv_ref()
1859    * calls. This should drop out immediately.
1860    */
1861   uv_run(loop, UV_RUN_DEFAULT);
1862 
1863   /* Cleanup. */
1864   unlink("test_file");
1865   unlink("test_file_link");
1866 
1867   MAKE_VALGRIND_HAPPY();
1868   return 0;
1869 }
1870 
1871 
1872 TEST_IMPL(fs_link) {
1873   int r;
1874   uv_fs_t req;
1875   uv_file file;
1876   uv_file link;
1877 
1878   /* Setup. */
1879   unlink("test_file");
1880   unlink("test_file_link");
1881   unlink("test_file_link2");
1882 
1883   loop = uv_default_loop();
1884 
1885   r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
1886       S_IWUSR | S_IRUSR, NULL);
1887   ASSERT(r >= 0);
1888   ASSERT(req.result >= 0);
1889   file = req.result;
1890   uv_fs_req_cleanup(&req);
1891 
1892   iov = uv_buf_init(test_buf, sizeof(test_buf));
1893   r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
1894   ASSERT(r == sizeof(test_buf));
1895   ASSERT(req.result == sizeof(test_buf));
1896   uv_fs_req_cleanup(&req);
1897 
1898   uv_fs_close(loop, &req, file, NULL);
1899 
1900   /* sync link */
1901   r = uv_fs_link(NULL, &req, "test_file", "test_file_link", NULL);
1902   ASSERT(r == 0);
1903   ASSERT(req.result == 0);
1904   uv_fs_req_cleanup(&req);
1905 
1906   r = uv_fs_open(NULL, &req, "test_file_link", O_RDWR, 0, NULL);
1907   ASSERT(r >= 0);
1908   ASSERT(req.result >= 0);
1909   link = req.result;
1910   uv_fs_req_cleanup(&req);
1911 
1912   memset(buf, 0, sizeof(buf));
1913   iov = uv_buf_init(buf, sizeof(buf));
1914   r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
1915   ASSERT(r >= 0);
1916   ASSERT(req.result >= 0);
1917   ASSERT(strcmp(buf, test_buf) == 0);
1918 
1919   close(link);
1920 
1921   /* async link */
1922   r = uv_fs_link(loop, &req, "test_file", "test_file_link2", link_cb);
1923   ASSERT(r == 0);
1924   uv_run(loop, UV_RUN_DEFAULT);
1925   ASSERT(link_cb_count == 1);
1926 
1927   r = uv_fs_open(NULL, &req, "test_file_link2", O_RDWR, 0, NULL);
1928   ASSERT(r >= 0);
1929   ASSERT(req.result >= 0);
1930   link = req.result;
1931   uv_fs_req_cleanup(&req);
1932 
1933   memset(buf, 0, sizeof(buf));
1934   iov = uv_buf_init(buf, sizeof(buf));
1935   r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
1936   ASSERT(r >= 0);
1937   ASSERT(req.result >= 0);
1938   ASSERT(strcmp(buf, test_buf) == 0);
1939 
1940   uv_fs_close(loop, &req, link, NULL);
1941 
1942   /*
1943    * Run the loop just to check we don't have make any extraneous uv_ref()
1944    * calls. This should drop out immediately.
1945    */
1946   uv_run(loop, UV_RUN_DEFAULT);
1947 
1948   /* Cleanup. */
1949   unlink("test_file");
1950   unlink("test_file_link");
1951   unlink("test_file_link2");
1952 
1953   MAKE_VALGRIND_HAPPY();
1954   return 0;
1955 }
1956 
1957 
1958 TEST_IMPL(fs_readlink) {
1959   uv_fs_t req;
1960 
1961   loop = uv_default_loop();
1962   ASSERT(0 == uv_fs_readlink(loop, &req, "no_such_file", dummy_cb));
1963   ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
1964   ASSERT(dummy_cb_count == 1);
1965   ASSERT(req.ptr == NULL);
1966   ASSERT(req.result == UV_ENOENT);
1967   uv_fs_req_cleanup(&req);
1968 
1969   ASSERT(UV_ENOENT == uv_fs_readlink(NULL, &req, "no_such_file", NULL));
1970   ASSERT(req.ptr == NULL);
1971   ASSERT(req.result == UV_ENOENT);
1972   uv_fs_req_cleanup(&req);
1973 
1974   MAKE_VALGRIND_HAPPY();
1975   return 0;
1976 }
1977 
1978 
1979 TEST_IMPL(fs_realpath) {
1980   uv_fs_t req;
1981 
1982   loop = uv_default_loop();
1983   ASSERT(0 == uv_fs_realpath(loop, &req, "no_such_file", dummy_cb));
1984   ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
1985   ASSERT(dummy_cb_count == 1);
1986   ASSERT(req.ptr == NULL);
1987 #ifdef _WIN32
1988   /*
1989    * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW()
1990    */
1991   if (req.result == UV_ENOSYS) {
1992     uv_fs_req_cleanup(&req);
1993     RETURN_SKIP("realpath is not supported on Windows XP");
1994   }
1995 #endif
1996   ASSERT(req.result == UV_ENOENT);
1997   uv_fs_req_cleanup(&req);
1998 
1999   ASSERT(UV_ENOENT == uv_fs_realpath(NULL, &req, "no_such_file", NULL));
2000   ASSERT(req.ptr == NULL);
2001   ASSERT(req.result == UV_ENOENT);
2002   uv_fs_req_cleanup(&req);
2003 
2004   MAKE_VALGRIND_HAPPY();
2005   return 0;
2006 }
2007 
2008 
2009 TEST_IMPL(fs_symlink) {
2010   int r;
2011   uv_fs_t req;
2012   uv_file file;
2013   uv_file link;
2014   char test_file_abs_buf[PATHMAX];
2015   size_t test_file_abs_size;
2016 
2017   /* Setup. */
2018   unlink("test_file");
2019   unlink("test_file_symlink");
2020   unlink("test_file_symlink2");
2021   unlink("test_file_symlink_symlink");
2022   unlink("test_file_symlink2_symlink");
2023   test_file_abs_size = sizeof(test_file_abs_buf);
2024 #ifdef _WIN32
2025   uv_cwd(test_file_abs_buf, &test_file_abs_size);
2026   strcat(test_file_abs_buf, "\\test_file");
2027 #else
2028   uv_cwd(test_file_abs_buf, &test_file_abs_size);
2029   strcat(test_file_abs_buf, "/test_file");
2030 #endif
2031 
2032   loop = uv_default_loop();
2033 
2034   r = uv_fs_open(NULL, &req, "test_file", O_RDWR | O_CREAT,
2035       S_IWUSR | S_IRUSR, NULL);
2036   ASSERT(r >= 0);
2037   ASSERT(req.result >= 0);
2038   file = req.result;
2039   uv_fs_req_cleanup(&req);
2040 
2041   iov = uv_buf_init(test_buf, sizeof(test_buf));
2042   r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
2043   ASSERT(r == sizeof(test_buf));
2044   ASSERT(req.result == sizeof(test_buf));
2045   uv_fs_req_cleanup(&req);
2046 
2047   uv_fs_close(loop, &req, file, NULL);
2048 
2049   /* sync symlink */
2050   r = uv_fs_symlink(NULL, &req, "test_file", "test_file_symlink", 0, NULL);
2051 #ifdef _WIN32
2052   if (r < 0) {
2053     if (r == UV_ENOTSUP) {
2054       /*
2055        * Windows doesn't support symlinks on older versions.
2056        * We just pass the test and bail out early if we get ENOTSUP.
2057        */
2058       return 0;
2059     } else if (r == UV_EPERM) {
2060       /*
2061        * Creating a symlink is only allowed when running elevated.
2062        * We pass the test and bail out early if we get UV_EPERM.
2063        */
2064       return 0;
2065     }
2066   }
2067 #endif
2068   ASSERT(r == 0);
2069   ASSERT(req.result == 0);
2070   uv_fs_req_cleanup(&req);
2071 
2072   r = uv_fs_open(NULL, &req, "test_file_symlink", O_RDWR, 0, NULL);
2073   ASSERT(r >= 0);
2074   ASSERT(req.result >= 0);
2075   link = req.result;
2076   uv_fs_req_cleanup(&req);
2077 
2078   memset(buf, 0, sizeof(buf));
2079   iov = uv_buf_init(buf, sizeof(buf));
2080   r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
2081   ASSERT(r >= 0);
2082   ASSERT(req.result >= 0);
2083   ASSERT(strcmp(buf, test_buf) == 0);
2084 
2085   uv_fs_close(loop, &req, link, NULL);
2086 
2087   r = uv_fs_symlink(NULL,
2088                     &req,
2089                     "test_file_symlink",
2090                     "test_file_symlink_symlink",
2091                     0,
2092                     NULL);
2093   ASSERT(r == 0);
2094   uv_fs_req_cleanup(&req);
2095 
2096 #if defined(__MSYS__)
2097   RETURN_SKIP("symlink reading is not supported on MSYS2");
2098 #endif
2099 
2100   r = uv_fs_readlink(NULL, &req, "test_file_symlink_symlink", NULL);
2101   ASSERT(r == 0);
2102   ASSERT(strcmp(req.ptr, "test_file_symlink") == 0);
2103   uv_fs_req_cleanup(&req);
2104 
2105   r = uv_fs_realpath(NULL, &req, "test_file_symlink_symlink", NULL);
2106 #ifdef _WIN32
2107   /*
2108    * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW()
2109    */
2110   if (r == UV_ENOSYS) {
2111     uv_fs_req_cleanup(&req);
2112     RETURN_SKIP("realpath is not supported on Windows XP");
2113   }
2114 #endif
2115   ASSERT(r == 0);
2116 #ifdef _WIN32
2117   ASSERT(stricmp(req.ptr, test_file_abs_buf) == 0);
2118 #else
2119   ASSERT(strcmp(req.ptr, test_file_abs_buf) == 0);
2120 #endif
2121   uv_fs_req_cleanup(&req);
2122 
2123   /* async link */
2124   r = uv_fs_symlink(loop,
2125                     &req,
2126                     "test_file",
2127                     "test_file_symlink2",
2128                     0,
2129                     symlink_cb);
2130   ASSERT(r == 0);
2131   uv_run(loop, UV_RUN_DEFAULT);
2132   ASSERT(symlink_cb_count == 1);
2133 
2134   r = uv_fs_open(NULL, &req, "test_file_symlink2", O_RDWR, 0, NULL);
2135   ASSERT(r >= 0);
2136   ASSERT(req.result >= 0);
2137   link = req.result;
2138   uv_fs_req_cleanup(&req);
2139 
2140   memset(buf, 0, sizeof(buf));
2141   iov = uv_buf_init(buf, sizeof(buf));
2142   r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
2143   ASSERT(r >= 0);
2144   ASSERT(req.result >= 0);
2145   ASSERT(strcmp(buf, test_buf) == 0);
2146 
2147   uv_fs_close(loop, &req, link, NULL);
2148 
2149   r = uv_fs_symlink(NULL,
2150                     &req,
2151                     "test_file_symlink2",
2152                     "test_file_symlink2_symlink",
2153                     0,
2154                     NULL);
2155   ASSERT(r == 0);
2156   uv_fs_req_cleanup(&req);
2157 
2158   r = uv_fs_readlink(loop, &req, "test_file_symlink2_symlink", readlink_cb);
2159   ASSERT(r == 0);
2160   uv_run(loop, UV_RUN_DEFAULT);
2161   ASSERT(readlink_cb_count == 1);
2162 
2163   r = uv_fs_realpath(loop, &req, "test_file", realpath_cb);
2164 #ifdef _WIN32
2165   /*
2166    * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW()
2167    */
2168   if (r == UV_ENOSYS) {
2169     uv_fs_req_cleanup(&req);
2170     RETURN_SKIP("realpath is not supported on Windows XP");
2171   }
2172 #endif
2173   ASSERT(r == 0);
2174   uv_run(loop, UV_RUN_DEFAULT);
2175   ASSERT(realpath_cb_count == 1);
2176 
2177   /*
2178    * Run the loop just to check we don't have make any extraneous uv_ref()
2179    * calls. This should drop out immediately.
2180    */
2181   uv_run(loop, UV_RUN_DEFAULT);
2182 
2183   /* Cleanup. */
2184   unlink("test_file");
2185   unlink("test_file_symlink");
2186   unlink("test_file_symlink_symlink");
2187   unlink("test_file_symlink2");
2188   unlink("test_file_symlink2_symlink");
2189 
2190   MAKE_VALGRIND_HAPPY();
2191   return 0;
2192 }
2193 
2194 
2195 int test_symlink_dir_impl(int type) {
2196   uv_fs_t req;
2197   int r;
2198   char* test_dir;
2199   uv_dirent_t dent;
2200   static char test_dir_abs_buf[PATHMAX];
2201   size_t test_dir_abs_size;
2202 
2203   /* set-up */
2204   unlink("test_dir/file1");
2205   unlink("test_dir/file2");
2206   rmdir("test_dir");
2207   rmdir("test_dir_symlink");
2208   test_dir_abs_size = sizeof(test_dir_abs_buf);
2209 
2210   loop = uv_default_loop();
2211 
2212   uv_fs_mkdir(NULL, &req, "test_dir", 0777, NULL);
2213   uv_fs_req_cleanup(&req);
2214 
2215 #ifdef _WIN32
2216   strcpy(test_dir_abs_buf, "\\\\?\\");
2217   uv_cwd(test_dir_abs_buf + 4, &test_dir_abs_size);
2218   test_dir_abs_size += 4;
2219   strcat(test_dir_abs_buf, "\\test_dir\\");
2220   test_dir_abs_size += strlen("\\test_dir\\");
2221   test_dir = test_dir_abs_buf;
2222 #else
2223   uv_cwd(test_dir_abs_buf, &test_dir_abs_size);
2224   strcat(test_dir_abs_buf, "/test_dir");
2225   test_dir_abs_size += strlen("/test_dir");
2226   test_dir = "test_dir";
2227 #endif
2228 
2229   r = uv_fs_symlink(NULL, &req, test_dir, "test_dir_symlink", type, NULL);
2230   if (type == UV_FS_SYMLINK_DIR && (r == UV_ENOTSUP || r == UV_EPERM)) {
2231     uv_fs_req_cleanup(&req);
2232     RETURN_SKIP("this version of Windows doesn't support unprivileged "
2233                 "creation of directory symlinks");
2234   }
2235   fprintf(stderr, "r == %i\n", r);
2236   ASSERT(r == 0);
2237   ASSERT(req.result == 0);
2238   uv_fs_req_cleanup(&req);
2239 
2240   r = uv_fs_stat(NULL, &req, "test_dir_symlink", NULL);
2241   ASSERT(r == 0);
2242   ASSERT(((uv_stat_t*)req.ptr)->st_mode & S_IFDIR);
2243   uv_fs_req_cleanup(&req);
2244 
2245   r = uv_fs_lstat(NULL, &req, "test_dir_symlink", NULL);
2246   ASSERT(r == 0);
2247 #if defined(__MSYS__)
2248   RETURN_SKIP("symlink reading is not supported on MSYS2");
2249 #endif
2250   ASSERT(((uv_stat_t*)req.ptr)->st_mode & S_IFLNK);
2251 #ifdef _WIN32
2252   ASSERT(((uv_stat_t*)req.ptr)->st_size == strlen(test_dir + 4));
2253 #else
2254 # ifdef __PASE__
2255   /* On IBMi PASE, st_size returns the length of the symlink itself. */
2256   ASSERT(((uv_stat_t*)req.ptr)->st_size == strlen("test_dir_symlink"));
2257 # else
2258   ASSERT(((uv_stat_t*)req.ptr)->st_size == strlen(test_dir));
2259 # endif
2260 #endif
2261   uv_fs_req_cleanup(&req);
2262 
2263   r = uv_fs_readlink(NULL, &req, "test_dir_symlink", NULL);
2264   ASSERT(r == 0);
2265 #ifdef _WIN32
2266   ASSERT(strcmp(req.ptr, test_dir + 4) == 0);
2267 #else
2268   ASSERT(strcmp(req.ptr, test_dir) == 0);
2269 #endif
2270   uv_fs_req_cleanup(&req);
2271 
2272   r = uv_fs_realpath(NULL, &req, "test_dir_symlink", NULL);
2273 #ifdef _WIN32
2274   /*
2275    * Windows XP and Server 2003 don't support GetFinalPathNameByHandleW()
2276    */
2277   if (r == UV_ENOSYS) {
2278     uv_fs_req_cleanup(&req);
2279     RETURN_SKIP("realpath is not supported on Windows XP");
2280   }
2281 #endif
2282   ASSERT(r == 0);
2283 #ifdef _WIN32
2284   ASSERT(strlen(req.ptr) == test_dir_abs_size - 5);
2285   ASSERT(strnicmp(req.ptr, test_dir + 4, test_dir_abs_size - 5) == 0);
2286 #else
2287   ASSERT(strcmp(req.ptr, test_dir_abs_buf) == 0);
2288 #endif
2289   uv_fs_req_cleanup(&req);
2290 
2291   r = uv_fs_open(NULL, &open_req1, "test_dir/file1", O_WRONLY | O_CREAT,
2292       S_IWUSR | S_IRUSR, NULL);
2293   ASSERT(r >= 0);
2294   uv_fs_req_cleanup(&open_req1);
2295   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
2296   ASSERT(r == 0);
2297   uv_fs_req_cleanup(&close_req);
2298 
2299   r = uv_fs_open(NULL, &open_req1, "test_dir/file2", O_WRONLY | O_CREAT,
2300       S_IWUSR | S_IRUSR, NULL);
2301   ASSERT(r >= 0);
2302   uv_fs_req_cleanup(&open_req1);
2303   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
2304   ASSERT(r == 0);
2305   uv_fs_req_cleanup(&close_req);
2306 
2307   r = uv_fs_scandir(NULL, &scandir_req, "test_dir_symlink", 0, NULL);
2308   ASSERT(r == 2);
2309   ASSERT(scandir_req.result == 2);
2310   ASSERT(scandir_req.ptr);
2311   while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) {
2312     ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0);
2313     assert_is_file_type(dent);
2314   }
2315   uv_fs_req_cleanup(&scandir_req);
2316   ASSERT(!scandir_req.ptr);
2317 
2318   /* unlink will remove the directory symlink */
2319   r = uv_fs_unlink(NULL, &req, "test_dir_symlink", NULL);
2320   ASSERT(r == 0);
2321   uv_fs_req_cleanup(&req);
2322 
2323   r = uv_fs_scandir(NULL, &scandir_req, "test_dir_symlink", 0, NULL);
2324   ASSERT(r == UV_ENOENT);
2325   uv_fs_req_cleanup(&scandir_req);
2326 
2327   r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL);
2328   ASSERT(r == 2);
2329   ASSERT(scandir_req.result == 2);
2330   ASSERT(scandir_req.ptr);
2331   while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) {
2332     ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0);
2333     assert_is_file_type(dent);
2334   }
2335   uv_fs_req_cleanup(&scandir_req);
2336   ASSERT(!scandir_req.ptr);
2337 
2338   /* clean-up */
2339   unlink("test_dir/file1");
2340   unlink("test_dir/file2");
2341   rmdir("test_dir");
2342   rmdir("test_dir_symlink");
2343 
2344   MAKE_VALGRIND_HAPPY();
2345   return 0;
2346 }
2347 
2348 TEST_IMPL(fs_symlink_dir) {
2349   return test_symlink_dir_impl(UV_FS_SYMLINK_DIR);
2350 }
2351 
2352 TEST_IMPL(fs_symlink_junction) {
2353   return test_symlink_dir_impl(UV_FS_SYMLINK_JUNCTION);
2354 }
2355 
2356 #ifdef _WIN32
2357 TEST_IMPL(fs_non_symlink_reparse_point) {
2358   uv_fs_t req;
2359   int r;
2360   HANDLE file_handle;
2361   REPARSE_GUID_DATA_BUFFER reparse_buffer;
2362   DWORD bytes_returned;
2363   uv_dirent_t dent;
2364 
2365   /* set-up */
2366   unlink("test_dir/test_file");
2367   rmdir("test_dir");
2368 
2369   loop = uv_default_loop();
2370 
2371   uv_fs_mkdir(NULL, &req, "test_dir", 0777, NULL);
2372   uv_fs_req_cleanup(&req);
2373 
2374   file_handle = CreateFile("test_dir/test_file",
2375                            GENERIC_WRITE | FILE_WRITE_ATTRIBUTES,
2376                            0,
2377                            NULL,
2378                            CREATE_ALWAYS,
2379                            FILE_FLAG_OPEN_REPARSE_POINT |
2380                              FILE_FLAG_BACKUP_SEMANTICS,
2381                            NULL);
2382   ASSERT(file_handle != INVALID_HANDLE_VALUE);
2383 
2384   memset(&reparse_buffer, 0, REPARSE_GUID_DATA_BUFFER_HEADER_SIZE);
2385   reparse_buffer.ReparseTag = REPARSE_TAG;
2386   reparse_buffer.ReparseDataLength = 0;
2387   reparse_buffer.ReparseGuid = REPARSE_GUID;
2388 
2389   r = DeviceIoControl(file_handle,
2390                       FSCTL_SET_REPARSE_POINT,
2391                       &reparse_buffer,
2392                       REPARSE_GUID_DATA_BUFFER_HEADER_SIZE,
2393                       NULL,
2394                       0,
2395                       &bytes_returned,
2396                       NULL);
2397   ASSERT(r != 0);
2398 
2399   CloseHandle(file_handle);
2400 
2401   r = uv_fs_readlink(NULL, &req, "test_dir/test_file", NULL);
2402   ASSERT(r == UV_EINVAL && GetLastError() == ERROR_SYMLINK_NOT_SUPPORTED);
2403   uv_fs_req_cleanup(&req);
2404 
2405 /*
2406   Placeholder tests for exercising the behavior fixed in issue #995.
2407   To run, update the path with the IP address of a Mac with the hard drive
2408   shared via SMB as "Macintosh HD".
2409 
2410   r = uv_fs_stat(NULL, &req, "\\\\<mac_ip>\\Macintosh HD\\.DS_Store", NULL);
2411   ASSERT(r == 0);
2412   uv_fs_req_cleanup(&req);
2413 
2414   r = uv_fs_lstat(NULL, &req, "\\\\<mac_ip>\\Macintosh HD\\.DS_Store", NULL);
2415   ASSERT(r == 0);
2416   uv_fs_req_cleanup(&req);
2417 */
2418 
2419 /*
2420   uv_fs_stat and uv_fs_lstat can only work on non-symlink reparse
2421   points when a minifilter driver is registered which intercepts
2422   associated filesystem requests. Installing a driver is beyond
2423   the scope of this test.
2424 
2425   r = uv_fs_stat(NULL, &req, "test_dir/test_file", NULL);
2426   ASSERT(r == 0);
2427   uv_fs_req_cleanup(&req);
2428 
2429   r = uv_fs_lstat(NULL, &req, "test_dir/test_file", NULL);
2430   ASSERT(r == 0);
2431   uv_fs_req_cleanup(&req);
2432 */
2433 
2434   r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL);
2435   ASSERT(r == 1);
2436   ASSERT(scandir_req.result == 1);
2437   ASSERT(scandir_req.ptr);
2438   while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) {
2439     ASSERT(strcmp(dent.name, "test_file") == 0);
2440     /* uv_fs_scandir incorrectly identifies non-symlink reparse points
2441        as links because it doesn't open the file and verify the reparse
2442        point tag. The PowerShell Get-ChildItem command shares this
2443        behavior, so it's reasonable to leave it as is. */
2444     ASSERT(dent.type == UV_DIRENT_LINK);
2445   }
2446   uv_fs_req_cleanup(&scandir_req);
2447   ASSERT(!scandir_req.ptr);
2448 
2449   /* clean-up */
2450   unlink("test_dir/test_file");
2451   rmdir("test_dir");
2452 
2453   MAKE_VALGRIND_HAPPY();
2454   return 0;
2455 }
2456 
2457 TEST_IMPL(fs_lstat_windows_store_apps) {
2458   uv_loop_t* loop;
2459   char localappdata[MAX_PATH];
2460   char windowsapps_path[MAX_PATH];
2461   char file_path[MAX_PATH];
2462   size_t len;
2463   int r;
2464   uv_fs_t req;
2465   uv_fs_t stat_req;
2466   uv_dirent_t dirent;
2467 
2468   loop = uv_default_loop();
2469   ASSERT_NOT_NULL(loop);
2470   len = sizeof(localappdata);
2471   r = uv_os_getenv("LOCALAPPDATA", localappdata, &len);
2472   if (r == UV_ENOENT) {
2473     MAKE_VALGRIND_HAPPY();
2474     return TEST_SKIP;
2475   }
2476   ASSERT_EQ(r, 0);
2477   r = snprintf(windowsapps_path,
2478               sizeof(localappdata),
2479               "%s\\Microsoft\\WindowsApps",
2480               localappdata);
2481   ASSERT_GT(r, 0);
2482   if (uv_fs_opendir(loop, &req, windowsapps_path, NULL) != 0) {
2483     /* If we cannot read the directory, skip the test. */
2484     MAKE_VALGRIND_HAPPY();
2485     return TEST_SKIP;
2486   }
2487   if (uv_fs_scandir(loop, &req, windowsapps_path, 0, NULL) <= 0) {
2488     MAKE_VALGRIND_HAPPY();
2489     return TEST_SKIP;
2490   }
2491   while (uv_fs_scandir_next(&req, &dirent) != UV_EOF) {
2492     if (dirent.type != UV_DIRENT_LINK) {
2493       continue;
2494     }
2495     if (snprintf(file_path,
2496                  sizeof(file_path),
2497                  "%s\\%s",
2498                  windowsapps_path,
2499                  dirent.name) < 0) {
2500       continue;
2501     }
2502     ASSERT_EQ(uv_fs_lstat(loop, &stat_req, file_path, NULL), 0);
2503   }
2504   MAKE_VALGRIND_HAPPY();
2505   return 0;
2506 }
2507 #endif
2508 
2509 
2510 TEST_IMPL(fs_utime) {
2511   utime_check_t checkme;
2512   const char* path = "test_file";
2513   double atime;
2514   double mtime;
2515   uv_fs_t req;
2516   int r;
2517 
2518   /* Setup. */
2519   loop = uv_default_loop();
2520   unlink(path);
2521   r = uv_fs_open(NULL, &req, path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL);
2522   ASSERT(r >= 0);
2523   ASSERT(req.result >= 0);
2524   uv_fs_req_cleanup(&req);
2525   uv_fs_close(loop, &req, r, NULL);
2526 
2527   atime = mtime = 400497753; /* 1982-09-10 11:22:33 */
2528 
2529   /*
2530    * Test sub-second timestamps only on Windows (assuming NTFS). Some other
2531    * platforms support sub-second timestamps, but that support is filesystem-
2532    * dependent. Notably OS X (HFS Plus) does NOT support sub-second timestamps.
2533    */
2534 #ifdef _WIN32
2535   mtime += 0.444;            /* 1982-09-10 11:22:33.444 */
2536 #endif
2537 
2538   r = uv_fs_utime(NULL, &req, path, atime, mtime, NULL);
2539   ASSERT(r == 0);
2540   ASSERT(req.result == 0);
2541   uv_fs_req_cleanup(&req);
2542 
2543   r = uv_fs_stat(NULL, &req, path, NULL);
2544   ASSERT(r == 0);
2545   ASSERT(req.result == 0);
2546   check_utime(path, atime, mtime, /* test_lutime */ 0);
2547   uv_fs_req_cleanup(&req);
2548 
2549   atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */
2550   checkme.path = path;
2551   checkme.atime = atime;
2552   checkme.mtime = mtime;
2553 
2554   /* async utime */
2555   utime_req.data = &checkme;
2556   r = uv_fs_utime(loop, &utime_req, path, atime, mtime, utime_cb);
2557   ASSERT(r == 0);
2558   uv_run(loop, UV_RUN_DEFAULT);
2559   ASSERT(utime_cb_count == 1);
2560 
2561   /* Cleanup. */
2562   unlink(path);
2563 
2564   MAKE_VALGRIND_HAPPY();
2565   return 0;
2566 }
2567 
2568 
2569 #ifdef _WIN32
2570 TEST_IMPL(fs_stat_root) {
2571   int r;
2572 
2573   r = uv_fs_stat(NULL, &stat_req, "\\", NULL);
2574   ASSERT(r == 0);
2575 
2576   r = uv_fs_stat(NULL, &stat_req, "..\\..\\..\\..\\..\\..\\..", NULL);
2577   ASSERT(r == 0);
2578 
2579   r = uv_fs_stat(NULL, &stat_req, "..", NULL);
2580   ASSERT(r == 0);
2581 
2582   r = uv_fs_stat(NULL, &stat_req, "..\\", NULL);
2583   ASSERT(r == 0);
2584 
2585   /* stats the current directory on c: */
2586   r = uv_fs_stat(NULL, &stat_req, "c:", NULL);
2587   ASSERT(r == 0);
2588 
2589   r = uv_fs_stat(NULL, &stat_req, "c:\\", NULL);
2590   ASSERT(r == 0);
2591 
2592   r = uv_fs_stat(NULL, &stat_req, "\\\\?\\C:\\", NULL);
2593   ASSERT(r == 0);
2594 
2595   MAKE_VALGRIND_HAPPY();
2596   return 0;
2597 }
2598 #endif
2599 
2600 
2601 TEST_IMPL(fs_futime) {
2602   utime_check_t checkme;
2603   const char* path = "test_file";
2604   double atime;
2605   double mtime;
2606   uv_file file;
2607   uv_fs_t req;
2608   int r;
2609 #if defined(_AIX) && !defined(_AIX71)
2610   RETURN_SKIP("futime is not implemented for AIX versions below 7.1");
2611 #endif
2612 
2613   /* Setup. */
2614   loop = uv_default_loop();
2615   unlink(path);
2616   r = uv_fs_open(NULL, &req, path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL);
2617   ASSERT(r >= 0);
2618   ASSERT(req.result >= 0);
2619   uv_fs_req_cleanup(&req);
2620   uv_fs_close(loop, &req, r, NULL);
2621 
2622   atime = mtime = 400497753; /* 1982-09-10 11:22:33 */
2623 
2624   /*
2625    * Test sub-second timestamps only on Windows (assuming NTFS). Some other
2626    * platforms support sub-second timestamps, but that support is filesystem-
2627    * dependent. Notably OS X (HFS Plus) does NOT support sub-second timestamps.
2628    */
2629 #ifdef _WIN32
2630   mtime += 0.444;            /* 1982-09-10 11:22:33.444 */
2631 #endif
2632 
2633   r = uv_fs_open(NULL, &req, path, O_RDWR, 0, NULL);
2634   ASSERT(r >= 0);
2635   ASSERT(req.result >= 0);
2636   file = req.result; /* FIXME probably not how it's supposed to be used */
2637   uv_fs_req_cleanup(&req);
2638 
2639   r = uv_fs_futime(NULL, &req, file, atime, mtime, NULL);
2640 #if defined(__CYGWIN__) || defined(__MSYS__)
2641   ASSERT(r == UV_ENOSYS);
2642   RETURN_SKIP("futime not supported on Cygwin");
2643 #else
2644   ASSERT(r == 0);
2645   ASSERT(req.result == 0);
2646 #endif
2647   uv_fs_req_cleanup(&req);
2648 
2649   r = uv_fs_stat(NULL, &req, path, NULL);
2650   ASSERT(r == 0);
2651   ASSERT(req.result == 0);
2652   check_utime(path, atime, mtime, /* test_lutime */ 0);
2653   uv_fs_req_cleanup(&req);
2654 
2655   atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */
2656 
2657   checkme.atime = atime;
2658   checkme.mtime = mtime;
2659   checkme.path = path;
2660 
2661   /* async futime */
2662   futime_req.data = &checkme;
2663   r = uv_fs_futime(loop, &futime_req, file, atime, mtime, futime_cb);
2664   ASSERT(r == 0);
2665   uv_run(loop, UV_RUN_DEFAULT);
2666   ASSERT(futime_cb_count == 1);
2667 
2668   /* Cleanup. */
2669   unlink(path);
2670 
2671   MAKE_VALGRIND_HAPPY();
2672   return 0;
2673 }
2674 
2675 
2676 TEST_IMPL(fs_lutime) {
2677   utime_check_t checkme;
2678   const char* path = "test_file";
2679   const char* symlink_path = "test_file_symlink";
2680   double atime;
2681   double mtime;
2682   uv_fs_t req;
2683   int r, s;
2684 
2685 
2686   /* Setup */
2687   loop = uv_default_loop();
2688   unlink(path);
2689   r = uv_fs_open(NULL, &req, path, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR, NULL);
2690   ASSERT(r >= 0);
2691   ASSERT(req.result >= 0);
2692   uv_fs_req_cleanup(&req);
2693   uv_fs_close(loop, &req, r, NULL);
2694 
2695   unlink(symlink_path);
2696   s = uv_fs_symlink(NULL, &req, path, symlink_path, 0, NULL);
2697 #ifdef _WIN32
2698   if (s == UV_EPERM) {
2699     /*
2700      * Creating a symlink before Windows 10 Creators Update was only allowed
2701      * when running elevated console (with admin rights)
2702      */
2703     RETURN_SKIP(
2704         "Symlink creation requires elevated console (with admin rights)");
2705   }
2706 #endif
2707   ASSERT(s == 0);
2708   ASSERT(req.result == 0);
2709   uv_fs_req_cleanup(&req);
2710 
2711   /* Test the synchronous version. */
2712   atime = mtime = 400497753; /* 1982-09-10 11:22:33 */
2713 
2714 #ifdef _WIN32
2715   mtime += 0.444;            /* 1982-09-10 11:22:33.444 */
2716 #endif
2717 
2718   checkme.atime = atime;
2719   checkme.mtime = mtime;
2720   checkme.path = symlink_path;
2721   req.data = &checkme;
2722 
2723   r = uv_fs_lutime(NULL, &req, symlink_path, atime, mtime, NULL);
2724 #if (defined(_AIX) && !defined(_AIX71)) ||                                    \
2725      defined(__MVS__)
2726   ASSERT(r == UV_ENOSYS);
2727   RETURN_SKIP("lutime is not implemented for z/OS and AIX versions below 7.1");
2728 #endif
2729   ASSERT(r == 0);
2730   lutime_cb(&req);
2731   ASSERT(lutime_cb_count == 1);
2732 
2733   /* Test the asynchronous version. */
2734   atime = mtime = 1291404900; /* 2010-12-03 20:35:00 */
2735 
2736   checkme.atime = atime;
2737   checkme.mtime = mtime;
2738   checkme.path = symlink_path;
2739 
2740   r = uv_fs_lutime(loop, &req, symlink_path, atime, mtime, lutime_cb);
2741   ASSERT(r == 0);
2742   uv_run(loop, UV_RUN_DEFAULT);
2743   ASSERT(lutime_cb_count == 2);
2744 
2745   /* Cleanup. */
2746   unlink(path);
2747   unlink(symlink_path);
2748 
2749   MAKE_VALGRIND_HAPPY();
2750   return 0;
2751 }
2752 
2753 
2754 TEST_IMPL(fs_stat_missing_path) {
2755   uv_fs_t req;
2756   int r;
2757 
2758   loop = uv_default_loop();
2759 
2760   r = uv_fs_stat(NULL, &req, "non_existent_file", NULL);
2761   ASSERT(r == UV_ENOENT);
2762   ASSERT(req.result == UV_ENOENT);
2763   uv_fs_req_cleanup(&req);
2764 
2765   MAKE_VALGRIND_HAPPY();
2766   return 0;
2767 }
2768 
2769 
2770 TEST_IMPL(fs_scandir_empty_dir) {
2771   const char* path;
2772   uv_fs_t req;
2773   uv_dirent_t dent;
2774   int r;
2775 
2776   path = "./empty_dir/";
2777   loop = uv_default_loop();
2778 
2779   uv_fs_mkdir(NULL, &req, path, 0777, NULL);
2780   uv_fs_req_cleanup(&req);
2781 
2782   /* Fill the req to ensure that required fields are cleaned up */
2783   memset(&req, 0xdb, sizeof(req));
2784 
2785   r = uv_fs_scandir(NULL, &req, path, 0, NULL);
2786   ASSERT(r == 0);
2787   ASSERT(req.result == 0);
2788   ASSERT(req.ptr == NULL);
2789   ASSERT(UV_EOF == uv_fs_scandir_next(&req, &dent));
2790   uv_fs_req_cleanup(&req);
2791 
2792   r = uv_fs_scandir(loop, &scandir_req, path, 0, empty_scandir_cb);
2793   ASSERT(r == 0);
2794 
2795   ASSERT(scandir_cb_count == 0);
2796   uv_run(loop, UV_RUN_DEFAULT);
2797   ASSERT(scandir_cb_count == 1);
2798 
2799   uv_fs_rmdir(NULL, &req, path, NULL);
2800   uv_fs_req_cleanup(&req);
2801 
2802   MAKE_VALGRIND_HAPPY();
2803   return 0;
2804 }
2805 
2806 
2807 TEST_IMPL(fs_scandir_non_existent_dir) {
2808   const char* path;
2809   uv_fs_t req;
2810   uv_dirent_t dent;
2811   int r;
2812 
2813   path = "./non_existent_dir/";
2814   loop = uv_default_loop();
2815 
2816   uv_fs_rmdir(NULL, &req, path, NULL);
2817   uv_fs_req_cleanup(&req);
2818 
2819   /* Fill the req to ensure that required fields are cleaned up */
2820   memset(&req, 0xdb, sizeof(req));
2821 
2822   r = uv_fs_scandir(NULL, &req, path, 0, NULL);
2823   ASSERT(r == UV_ENOENT);
2824   ASSERT(req.result == UV_ENOENT);
2825   ASSERT(req.ptr == NULL);
2826   ASSERT(UV_ENOENT == uv_fs_scandir_next(&req, &dent));
2827   uv_fs_req_cleanup(&req);
2828 
2829   r = uv_fs_scandir(loop, &scandir_req, path, 0, non_existent_scandir_cb);
2830   ASSERT(r == 0);
2831 
2832   ASSERT(scandir_cb_count == 0);
2833   uv_run(loop, UV_RUN_DEFAULT);
2834   ASSERT(scandir_cb_count == 1);
2835 
2836   MAKE_VALGRIND_HAPPY();
2837   return 0;
2838 }
2839 
2840 TEST_IMPL(fs_scandir_file) {
2841   const char* path;
2842   int r;
2843 
2844   path = "test/fixtures/empty_file";
2845   loop = uv_default_loop();
2846 
2847   r = uv_fs_scandir(NULL, &scandir_req, path, 0, NULL);
2848   ASSERT(r == UV_ENOTDIR);
2849   uv_fs_req_cleanup(&scandir_req);
2850 
2851   r = uv_fs_scandir(loop, &scandir_req, path, 0, file_scandir_cb);
2852   ASSERT(r == 0);
2853 
2854   ASSERT(scandir_cb_count == 0);
2855   uv_run(loop, UV_RUN_DEFAULT);
2856   ASSERT(scandir_cb_count == 1);
2857 
2858   MAKE_VALGRIND_HAPPY();
2859   return 0;
2860 }
2861 
2862 
2863 TEST_IMPL(fs_open_dir) {
2864   const char* path;
2865   uv_fs_t req;
2866   int r, file;
2867 
2868   path = ".";
2869   loop = uv_default_loop();
2870 
2871   r = uv_fs_open(NULL, &req, path, O_RDONLY, 0, NULL);
2872   ASSERT(r >= 0);
2873   ASSERT(req.result >= 0);
2874   ASSERT(req.ptr == NULL);
2875   file = r;
2876   uv_fs_req_cleanup(&req);
2877 
2878   r = uv_fs_close(NULL, &req, file, NULL);
2879   ASSERT(r == 0);
2880 
2881   r = uv_fs_open(loop, &req, path, O_RDONLY, 0, open_cb_simple);
2882   ASSERT(r == 0);
2883 
2884   ASSERT(open_cb_count == 0);
2885   uv_run(loop, UV_RUN_DEFAULT);
2886   ASSERT(open_cb_count == 1);
2887 
2888   MAKE_VALGRIND_HAPPY();
2889   return 0;
2890 }
2891 
2892 
2893 static void fs_file_open_append(int add_flags) {
2894   int r;
2895 
2896   /* Setup. */
2897   unlink("test_file");
2898 
2899   loop = uv_default_loop();
2900 
2901   r = uv_fs_open(NULL, &open_req1, "test_file",
2902       O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL);
2903   ASSERT(r >= 0);
2904   ASSERT(open_req1.result >= 0);
2905   uv_fs_req_cleanup(&open_req1);
2906 
2907   iov = uv_buf_init(test_buf, sizeof(test_buf));
2908   r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
2909   ASSERT(r >= 0);
2910   ASSERT(write_req.result >= 0);
2911   uv_fs_req_cleanup(&write_req);
2912 
2913   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
2914   ASSERT(r == 0);
2915   ASSERT(close_req.result == 0);
2916   uv_fs_req_cleanup(&close_req);
2917 
2918   r = uv_fs_open(NULL, &open_req1, "test_file",
2919       O_RDWR | O_APPEND | add_flags, 0, NULL);
2920   ASSERT(r >= 0);
2921   ASSERT(open_req1.result >= 0);
2922   uv_fs_req_cleanup(&open_req1);
2923 
2924   iov = uv_buf_init(test_buf, sizeof(test_buf));
2925   r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
2926   ASSERT(r >= 0);
2927   ASSERT(write_req.result >= 0);
2928   uv_fs_req_cleanup(&write_req);
2929 
2930   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
2931   ASSERT(r == 0);
2932   ASSERT(close_req.result == 0);
2933   uv_fs_req_cleanup(&close_req);
2934 
2935   r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY | add_flags,
2936       S_IRUSR, NULL);
2937   ASSERT(r >= 0);
2938   ASSERT(open_req1.result >= 0);
2939   uv_fs_req_cleanup(&open_req1);
2940 
2941   iov = uv_buf_init(buf, sizeof(buf));
2942   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
2943   printf("read = %d\n", r);
2944   ASSERT(r == 26);
2945   ASSERT(read_req.result == 26);
2946   ASSERT(memcmp(buf,
2947                 "test-buffer\n\0test-buffer\n\0",
2948                 sizeof("test-buffer\n\0test-buffer\n\0") - 1) == 0);
2949   uv_fs_req_cleanup(&read_req);
2950 
2951   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
2952   ASSERT(r == 0);
2953   ASSERT(close_req.result == 0);
2954   uv_fs_req_cleanup(&close_req);
2955 
2956   /* Cleanup */
2957   unlink("test_file");
2958 }
2959 TEST_IMPL(fs_file_open_append) {
2960   fs_file_open_append(0);
2961   fs_file_open_append(UV_FS_O_FILEMAP);
2962 
2963   MAKE_VALGRIND_HAPPY();
2964   return 0;
2965 }
2966 
2967 
2968 TEST_IMPL(fs_rename_to_existing_file) {
2969   int r;
2970 
2971   /* Setup. */
2972   unlink("test_file");
2973   unlink("test_file2");
2974 
2975   loop = uv_default_loop();
2976 
2977   r = uv_fs_open(NULL, &open_req1, "test_file", O_WRONLY | O_CREAT,
2978       S_IWUSR | S_IRUSR, NULL);
2979   ASSERT(r >= 0);
2980   ASSERT(open_req1.result >= 0);
2981   uv_fs_req_cleanup(&open_req1);
2982 
2983   iov = uv_buf_init(test_buf, sizeof(test_buf));
2984   r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
2985   ASSERT(r >= 0);
2986   ASSERT(write_req.result >= 0);
2987   uv_fs_req_cleanup(&write_req);
2988 
2989   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
2990   ASSERT(r == 0);
2991   ASSERT(close_req.result == 0);
2992   uv_fs_req_cleanup(&close_req);
2993 
2994   r = uv_fs_open(NULL, &open_req1, "test_file2", O_WRONLY | O_CREAT,
2995       S_IWUSR | S_IRUSR, NULL);
2996   ASSERT(r >= 0);
2997   ASSERT(open_req1.result >= 0);
2998   uv_fs_req_cleanup(&open_req1);
2999 
3000   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3001   ASSERT(r == 0);
3002   ASSERT(close_req.result == 0);
3003   uv_fs_req_cleanup(&close_req);
3004 
3005   r = uv_fs_rename(NULL, &rename_req, "test_file", "test_file2", NULL);
3006   ASSERT(r == 0);
3007   ASSERT(rename_req.result == 0);
3008   uv_fs_req_cleanup(&rename_req);
3009 
3010   r = uv_fs_open(NULL, &open_req1, "test_file2", O_RDONLY, 0, NULL);
3011   ASSERT(r >= 0);
3012   ASSERT(open_req1.result >= 0);
3013   uv_fs_req_cleanup(&open_req1);
3014 
3015   memset(buf, 0, sizeof(buf));
3016   iov = uv_buf_init(buf, sizeof(buf));
3017   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
3018   ASSERT(r >= 0);
3019   ASSERT(read_req.result >= 0);
3020   ASSERT(strcmp(buf, test_buf) == 0);
3021   uv_fs_req_cleanup(&read_req);
3022 
3023   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3024   ASSERT(r == 0);
3025   ASSERT(close_req.result == 0);
3026   uv_fs_req_cleanup(&close_req);
3027 
3028   /* Cleanup */
3029   unlink("test_file");
3030   unlink("test_file2");
3031 
3032   MAKE_VALGRIND_HAPPY();
3033   return 0;
3034 }
3035 
3036 
3037 static void fs_read_bufs(int add_flags) {
3038   char scratch[768];
3039   uv_buf_t bufs[4];
3040 
3041   ASSERT(0 <= uv_fs_open(NULL, &open_req1,
3042                          "test/fixtures/lorem_ipsum.txt",
3043                          O_RDONLY | add_flags, 0, NULL));
3044   ASSERT(open_req1.result >= 0);
3045   uv_fs_req_cleanup(&open_req1);
3046 
3047   ASSERT(UV_EINVAL == uv_fs_read(NULL, &read_req, open_req1.result,
3048                                  NULL, 0, 0, NULL));
3049   ASSERT(UV_EINVAL == uv_fs_read(NULL, &read_req, open_req1.result,
3050                                  NULL, 1, 0, NULL));
3051   ASSERT(UV_EINVAL == uv_fs_read(NULL, &read_req, open_req1.result,
3052                                  bufs, 0, 0, NULL));
3053 
3054   bufs[0] = uv_buf_init(scratch + 0, 256);
3055   bufs[1] = uv_buf_init(scratch + 256, 256);
3056   bufs[2] = uv_buf_init(scratch + 512, 128);
3057   bufs[3] = uv_buf_init(scratch + 640, 128);
3058 
3059   ASSERT(446 == uv_fs_read(NULL,
3060                            &read_req,
3061                            open_req1.result,
3062                            bufs + 0,
3063                            2,  /* 2x 256 bytes. */
3064                            0,  /* Positional read. */
3065                            NULL));
3066   ASSERT(read_req.result == 446);
3067   uv_fs_req_cleanup(&read_req);
3068 
3069   ASSERT(190 == uv_fs_read(NULL,
3070                            &read_req,
3071                            open_req1.result,
3072                            bufs + 2,
3073                            2,  /* 2x 128 bytes. */
3074                            256,  /* Positional read. */
3075                            NULL));
3076   ASSERT(read_req.result == /* 446 - 256 */ 190);
3077   uv_fs_req_cleanup(&read_req);
3078 
3079   ASSERT(0 == memcmp(bufs[1].base + 0, bufs[2].base, 128));
3080   ASSERT(0 == memcmp(bufs[1].base + 128, bufs[3].base, 190 - 128));
3081 
3082   ASSERT(0 == uv_fs_close(NULL, &close_req, open_req1.result, NULL));
3083   ASSERT(close_req.result == 0);
3084   uv_fs_req_cleanup(&close_req);
3085 }
3086 TEST_IMPL(fs_read_bufs) {
3087   fs_read_bufs(0);
3088   fs_read_bufs(UV_FS_O_FILEMAP);
3089 
3090   MAKE_VALGRIND_HAPPY();
3091   return 0;
3092 }
3093 
3094 
3095 static void fs_read_file_eof(int add_flags) {
3096 #if defined(__CYGWIN__) || defined(__MSYS__)
3097   RETURN_SKIP("Cygwin pread at EOF may (incorrectly) return data!");
3098 #endif
3099   int r;
3100 
3101   /* Setup. */
3102   unlink("test_file");
3103 
3104   loop = uv_default_loop();
3105 
3106   r = uv_fs_open(NULL, &open_req1, "test_file",
3107       O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL);
3108   ASSERT(r >= 0);
3109   ASSERT(open_req1.result >= 0);
3110   uv_fs_req_cleanup(&open_req1);
3111 
3112   iov = uv_buf_init(test_buf, sizeof(test_buf));
3113   r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
3114   ASSERT(r >= 0);
3115   ASSERT(write_req.result >= 0);
3116   uv_fs_req_cleanup(&write_req);
3117 
3118   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3119   ASSERT(r == 0);
3120   ASSERT(close_req.result == 0);
3121   uv_fs_req_cleanup(&close_req);
3122 
3123   r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY | add_flags, 0,
3124       NULL);
3125   ASSERT(r >= 0);
3126   ASSERT(open_req1.result >= 0);
3127   uv_fs_req_cleanup(&open_req1);
3128 
3129   memset(buf, 0, sizeof(buf));
3130   iov = uv_buf_init(buf, sizeof(buf));
3131   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
3132   ASSERT(r >= 0);
3133   ASSERT(read_req.result >= 0);
3134   ASSERT(strcmp(buf, test_buf) == 0);
3135   uv_fs_req_cleanup(&read_req);
3136 
3137   iov = uv_buf_init(buf, sizeof(buf));
3138   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1,
3139                  read_req.result, NULL);
3140   ASSERT(r == 0);
3141   ASSERT(read_req.result == 0);
3142   uv_fs_req_cleanup(&read_req);
3143 
3144   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3145   ASSERT(r == 0);
3146   ASSERT(close_req.result == 0);
3147   uv_fs_req_cleanup(&close_req);
3148 
3149   /* Cleanup */
3150   unlink("test_file");
3151 }
3152 TEST_IMPL(fs_read_file_eof) {
3153   fs_read_file_eof(0);
3154   fs_read_file_eof(UV_FS_O_FILEMAP);
3155 
3156   MAKE_VALGRIND_HAPPY();
3157   return 0;
3158 }
3159 
3160 
3161 static void fs_write_multiple_bufs(int add_flags) {
3162   uv_buf_t iovs[2];
3163   int r;
3164 
3165   /* Setup. */
3166   unlink("test_file");
3167 
3168   loop = uv_default_loop();
3169 
3170   r = uv_fs_open(NULL, &open_req1, "test_file",
3171       O_WRONLY | O_CREAT | add_flags, S_IWUSR | S_IRUSR, NULL);
3172   ASSERT(r >= 0);
3173   ASSERT(open_req1.result >= 0);
3174   uv_fs_req_cleanup(&open_req1);
3175 
3176   iovs[0] = uv_buf_init(test_buf, sizeof(test_buf));
3177   iovs[1] = uv_buf_init(test_buf2, sizeof(test_buf2));
3178   r = uv_fs_write(NULL, &write_req, open_req1.result, iovs, 2, 0, NULL);
3179   ASSERT(r >= 0);
3180   ASSERT(write_req.result >= 0);
3181   uv_fs_req_cleanup(&write_req);
3182 
3183   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3184   ASSERT(r == 0);
3185   ASSERT(close_req.result == 0);
3186   uv_fs_req_cleanup(&close_req);
3187 
3188   r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY | add_flags, 0,
3189       NULL);
3190   ASSERT(r >= 0);
3191   ASSERT(open_req1.result >= 0);
3192   uv_fs_req_cleanup(&open_req1);
3193 
3194   memset(buf, 0, sizeof(buf));
3195   memset(buf2, 0, sizeof(buf2));
3196   /* Read the strings back to separate buffers. */
3197   iovs[0] = uv_buf_init(buf, sizeof(test_buf));
3198   iovs[1] = uv_buf_init(buf2, sizeof(test_buf2));
3199   ASSERT(lseek(open_req1.result, 0, SEEK_CUR) == 0);
3200   r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, 2, -1, NULL);
3201   ASSERT(r >= 0);
3202   ASSERT(read_req.result == sizeof(test_buf) + sizeof(test_buf2));
3203   ASSERT(strcmp(buf, test_buf) == 0);
3204   ASSERT(strcmp(buf2, test_buf2) == 0);
3205   uv_fs_req_cleanup(&read_req);
3206 
3207   iov = uv_buf_init(buf, sizeof(buf));
3208   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
3209   ASSERT(r == 0);
3210   ASSERT(read_req.result == 0);
3211   uv_fs_req_cleanup(&read_req);
3212 
3213   /* Read the strings back to separate buffers. */
3214   iovs[0] = uv_buf_init(buf, sizeof(test_buf));
3215   iovs[1] = uv_buf_init(buf2, sizeof(test_buf2));
3216   r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, 2, 0, NULL);
3217   ASSERT(r >= 0);
3218   if (read_req.result == sizeof(test_buf)) {
3219     /* Infer that preadv is not available. */
3220     uv_fs_req_cleanup(&read_req);
3221     r = uv_fs_read(NULL, &read_req, open_req1.result, &iovs[1], 1, read_req.result, NULL);
3222     ASSERT(r >= 0);
3223     ASSERT(read_req.result == sizeof(test_buf2));
3224   } else {
3225     ASSERT(read_req.result == sizeof(test_buf) + sizeof(test_buf2));
3226   }
3227   ASSERT(strcmp(buf, test_buf) == 0);
3228   ASSERT(strcmp(buf2, test_buf2) == 0);
3229   uv_fs_req_cleanup(&read_req);
3230 
3231   iov = uv_buf_init(buf, sizeof(buf));
3232   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1,
3233                  sizeof(test_buf) + sizeof(test_buf2), NULL);
3234   ASSERT(r == 0);
3235   ASSERT(read_req.result == 0);
3236   uv_fs_req_cleanup(&read_req);
3237 
3238   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3239   ASSERT(r == 0);
3240   ASSERT(close_req.result == 0);
3241   uv_fs_req_cleanup(&close_req);
3242 
3243   /* Cleanup */
3244   unlink("test_file");
3245 }
3246 TEST_IMPL(fs_write_multiple_bufs) {
3247   fs_write_multiple_bufs(0);
3248   fs_write_multiple_bufs(UV_FS_O_FILEMAP);
3249 
3250   MAKE_VALGRIND_HAPPY();
3251   return 0;
3252 }
3253 
3254 
3255 static void fs_write_alotof_bufs(int add_flags) {
3256   size_t iovcount;
3257   size_t iovmax;
3258   uv_buf_t* iovs;
3259   char* buffer;
3260   size_t index;
3261   int r;
3262 
3263   iovcount = 54321;
3264 
3265   /* Setup. */
3266   unlink("test_file");
3267 
3268   loop = uv_default_loop();
3269 
3270   iovs = malloc(sizeof(*iovs) * iovcount);
3271   ASSERT(iovs != NULL);
3272   iovmax = uv_test_getiovmax();
3273 
3274   r = uv_fs_open(NULL,
3275                  &open_req1,
3276                  "test_file",
3277                  O_RDWR | O_CREAT | add_flags,
3278                  S_IWUSR | S_IRUSR,
3279                  NULL);
3280   ASSERT(r >= 0);
3281   ASSERT(open_req1.result >= 0);
3282   uv_fs_req_cleanup(&open_req1);
3283 
3284   for (index = 0; index < iovcount; ++index)
3285     iovs[index] = uv_buf_init(test_buf, sizeof(test_buf));
3286 
3287   r = uv_fs_write(NULL,
3288                   &write_req,
3289                   open_req1.result,
3290                   iovs,
3291                   iovcount,
3292                   -1,
3293                   NULL);
3294   ASSERT(r >= 0);
3295   ASSERT((size_t)write_req.result == sizeof(test_buf) * iovcount);
3296   uv_fs_req_cleanup(&write_req);
3297 
3298   /* Read the strings back to separate buffers. */
3299   buffer = malloc(sizeof(test_buf) * iovcount);
3300   ASSERT(buffer != NULL);
3301 
3302   for (index = 0; index < iovcount; ++index)
3303     iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf),
3304                               sizeof(test_buf));
3305 
3306   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3307   ASSERT(r == 0);
3308   ASSERT(close_req.result == 0);
3309   uv_fs_req_cleanup(&close_req);
3310 
3311   r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY | add_flags, 0,
3312     NULL);
3313   ASSERT(r >= 0);
3314   ASSERT(open_req1.result >= 0);
3315   uv_fs_req_cleanup(&open_req1);
3316 
3317   r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, iovcount, -1, NULL);
3318   if (iovcount > iovmax)
3319     iovcount = iovmax;
3320   ASSERT(r >= 0);
3321   ASSERT((size_t)read_req.result == sizeof(test_buf) * iovcount);
3322 
3323   for (index = 0; index < iovcount; ++index)
3324     ASSERT(strncmp(buffer + index * sizeof(test_buf),
3325                    test_buf,
3326                    sizeof(test_buf)) == 0);
3327 
3328   uv_fs_req_cleanup(&read_req);
3329   free(buffer);
3330 
3331   ASSERT(lseek(open_req1.result, write_req.result, SEEK_SET) == write_req.result);
3332   iov = uv_buf_init(buf, sizeof(buf));
3333   r = uv_fs_read(NULL,
3334                  &read_req,
3335                  open_req1.result,
3336                  &iov,
3337                  1,
3338                  -1,
3339                  NULL);
3340   ASSERT(r == 0);
3341   ASSERT(read_req.result == 0);
3342   uv_fs_req_cleanup(&read_req);
3343 
3344   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3345   ASSERT(r == 0);
3346   ASSERT(close_req.result == 0);
3347   uv_fs_req_cleanup(&close_req);
3348 
3349   /* Cleanup */
3350   unlink("test_file");
3351   free(iovs);
3352 }
3353 TEST_IMPL(fs_write_alotof_bufs) {
3354   fs_write_alotof_bufs(0);
3355   fs_write_alotof_bufs(UV_FS_O_FILEMAP);
3356 
3357   MAKE_VALGRIND_HAPPY();
3358   return 0;
3359 }
3360 
3361 
3362 static void fs_write_alotof_bufs_with_offset(int add_flags) {
3363   size_t iovcount;
3364   size_t iovmax;
3365   uv_buf_t* iovs;
3366   char* buffer;
3367   size_t index;
3368   int r;
3369   int64_t offset;
3370   char* filler;
3371   int filler_len;
3372 
3373   filler = "0123456789";
3374   filler_len = strlen(filler);
3375   iovcount = 54321;
3376 
3377   /* Setup. */
3378   unlink("test_file");
3379 
3380   loop = uv_default_loop();
3381 
3382   iovs = malloc(sizeof(*iovs) * iovcount);
3383   ASSERT(iovs != NULL);
3384   iovmax = uv_test_getiovmax();
3385 
3386   r = uv_fs_open(NULL,
3387                  &open_req1,
3388                  "test_file",
3389                  O_RDWR | O_CREAT | add_flags,
3390                  S_IWUSR | S_IRUSR,
3391                  NULL);
3392   ASSERT(r >= 0);
3393   ASSERT(open_req1.result >= 0);
3394   uv_fs_req_cleanup(&open_req1);
3395 
3396   iov = uv_buf_init(filler, filler_len);
3397   r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
3398   ASSERT(r == filler_len);
3399   ASSERT(write_req.result == filler_len);
3400   uv_fs_req_cleanup(&write_req);
3401   offset = (int64_t)r;
3402 
3403   for (index = 0; index < iovcount; ++index)
3404     iovs[index] = uv_buf_init(test_buf, sizeof(test_buf));
3405 
3406   r = uv_fs_write(NULL,
3407                   &write_req,
3408                   open_req1.result,
3409                   iovs,
3410                   iovcount,
3411                   offset,
3412                   NULL);
3413   ASSERT(r >= 0);
3414   ASSERT((size_t)write_req.result == sizeof(test_buf) * iovcount);
3415   uv_fs_req_cleanup(&write_req);
3416 
3417   /* Read the strings back to separate buffers. */
3418   buffer = malloc(sizeof(test_buf) * iovcount);
3419   ASSERT(buffer != NULL);
3420 
3421   for (index = 0; index < iovcount; ++index)
3422     iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf),
3423                               sizeof(test_buf));
3424 
3425   r = uv_fs_read(NULL, &read_req, open_req1.result,
3426                  iovs, iovcount, offset, NULL);
3427   ASSERT(r >= 0);
3428   if (r == sizeof(test_buf))
3429     iovcount = 1; /* Infer that preadv is not available. */
3430   else if (iovcount > iovmax)
3431     iovcount = iovmax;
3432   ASSERT((size_t)read_req.result == sizeof(test_buf) * iovcount);
3433 
3434   for (index = 0; index < iovcount; ++index)
3435     ASSERT(strncmp(buffer + index * sizeof(test_buf),
3436                    test_buf,
3437                    sizeof(test_buf)) == 0);
3438 
3439   uv_fs_req_cleanup(&read_req);
3440   free(buffer);
3441 
3442   r = uv_fs_stat(NULL, &stat_req, "test_file", NULL);
3443   ASSERT(r == 0);
3444   ASSERT((int64_t)((uv_stat_t*)stat_req.ptr)->st_size ==
3445          offset + (int64_t)write_req.result);
3446   uv_fs_req_cleanup(&stat_req);
3447 
3448   iov = uv_buf_init(buf, sizeof(buf));
3449   r = uv_fs_read(NULL,
3450                  &read_req,
3451                  open_req1.result,
3452                  &iov,
3453                  1,
3454                  offset + write_req.result,
3455                  NULL);
3456   ASSERT(r == 0);
3457   ASSERT(read_req.result == 0);
3458   uv_fs_req_cleanup(&read_req);
3459 
3460   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3461   ASSERT(r == 0);
3462   ASSERT(close_req.result == 0);
3463   uv_fs_req_cleanup(&close_req);
3464 
3465   /* Cleanup */
3466   unlink("test_file");
3467   free(iovs);
3468 }
3469 TEST_IMPL(fs_write_alotof_bufs_with_offset) {
3470   fs_write_alotof_bufs_with_offset(0);
3471   fs_write_alotof_bufs_with_offset(UV_FS_O_FILEMAP);
3472 
3473   MAKE_VALGRIND_HAPPY();
3474   return 0;
3475 }
3476 
3477 TEST_IMPL(fs_read_dir) {
3478   int r;
3479   char buf[2];
3480   loop = uv_default_loop();
3481 
3482   /* Setup */
3483   rmdir("test_dir");
3484   r = uv_fs_mkdir(loop, &mkdir_req, "test_dir", 0755, mkdir_cb);
3485   ASSERT(r == 0);
3486   uv_run(loop, UV_RUN_DEFAULT);
3487   ASSERT(mkdir_cb_count == 1);
3488   /* Setup Done Here */
3489 
3490   /* Get a file descriptor for the directory */
3491   r = uv_fs_open(loop,
3492                  &open_req1,
3493                  "test_dir",
3494                  UV_FS_O_RDONLY | UV_FS_O_DIRECTORY,
3495                  S_IWUSR | S_IRUSR,
3496                  NULL);
3497   ASSERT(r >= 0);
3498   uv_fs_req_cleanup(&open_req1);
3499 
3500   /* Try to read data from the directory */
3501   iov = uv_buf_init(buf, sizeof(buf));
3502   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, 0, NULL);
3503 #if defined(__FreeBSD__)   || \
3504     defined(__OpenBSD__)   || \
3505     defined(__NetBSD__)    || \
3506     defined(__DragonFly__) || \
3507     defined(_AIX)          || \
3508     defined(__sun)         || \
3509     defined(__MVS__)
3510   /*
3511    * As of now, these operating systems support reading from a directory,
3512    * that too depends on the filesystem this temporary test directory is
3513    * created on. That is why this assertion is a bit lenient.
3514    */
3515   ASSERT((r >= 0) || (r == UV_EISDIR));
3516 #else
3517   ASSERT(r == UV_EISDIR);
3518 #endif
3519   uv_fs_req_cleanup(&read_req);
3520 
3521   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3522   ASSERT(r == 0);
3523   uv_fs_req_cleanup(&close_req);
3524 
3525   /* Cleanup */
3526   rmdir("test_dir");
3527 
3528   MAKE_VALGRIND_HAPPY();
3529   return 0;
3530 }
3531 
3532 #ifdef _WIN32
3533 
3534 TEST_IMPL(fs_partial_read) {
3535   RETURN_SKIP("Test not implemented on Windows.");
3536 }
3537 
3538 TEST_IMPL(fs_partial_write) {
3539   RETURN_SKIP("Test not implemented on Windows.");
3540 }
3541 
3542 #else  /* !_WIN32 */
3543 
3544 struct thread_ctx {
3545   pthread_t pid;
3546   int fd;
3547   char* data;
3548   int size;
3549   int interval;
3550   int doread;
3551 };
3552 
3553 static void thread_main(void* arg) {
3554   const struct thread_ctx* ctx;
3555   int size;
3556   char* data;
3557 
3558   ctx = (struct thread_ctx*)arg;
3559   size = ctx->size;
3560   data = ctx->data;
3561 
3562   while (size > 0) {
3563     ssize_t result;
3564     int nbytes;
3565     nbytes = size < ctx->interval ? size : ctx->interval;
3566     if (ctx->doread) {
3567       result = write(ctx->fd, data, nbytes);
3568       /* Should not see EINTR (or other errors) */
3569       ASSERT(result == nbytes);
3570     } else {
3571       result = read(ctx->fd, data, nbytes);
3572       /* Should not see EINTR (or other errors),
3573        * but might get a partial read if we are faster than the writer
3574        */
3575       ASSERT(result > 0 && result <= nbytes);
3576     }
3577 
3578     pthread_kill(ctx->pid, SIGUSR1);
3579     size -= result;
3580     data += result;
3581   }
3582 }
3583 
3584 static void sig_func(uv_signal_t* handle, int signum) {
3585   uv_signal_stop(handle);
3586 }
3587 
3588 static size_t uv_test_fs_buf_offset(uv_buf_t* bufs, size_t size) {
3589   size_t offset;
3590   /* Figure out which bufs are done */
3591   for (offset = 0; size > 0 && bufs[offset].len <= size; ++offset)
3592     size -= bufs[offset].len;
3593 
3594   /* Fix a partial read/write */
3595   if (size > 0) {
3596     bufs[offset].base += size;
3597     bufs[offset].len -= size;
3598   }
3599   return offset;
3600 }
3601 
3602 static void test_fs_partial(int doread) {
3603   struct thread_ctx ctx;
3604   uv_thread_t thread;
3605   uv_signal_t signal;
3606   int pipe_fds[2];
3607   size_t iovcount;
3608   uv_buf_t* iovs;
3609   char* buffer;
3610   size_t index;
3611 
3612   iovcount = 54321;
3613 
3614   iovs = malloc(sizeof(*iovs) * iovcount);
3615   ASSERT(iovs != NULL);
3616 
3617   ctx.pid = pthread_self();
3618   ctx.doread = doread;
3619   ctx.interval = 1000;
3620   ctx.size = sizeof(test_buf) * iovcount;
3621   ctx.data = malloc(ctx.size);
3622   ASSERT(ctx.data != NULL);
3623   buffer = malloc(ctx.size);
3624   ASSERT(buffer != NULL);
3625 
3626   for (index = 0; index < iovcount; ++index)
3627     iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf), sizeof(test_buf));
3628 
3629   loop = uv_default_loop();
3630 
3631   ASSERT(0 == uv_signal_init(loop, &signal));
3632   ASSERT(0 == uv_signal_start(&signal, sig_func, SIGUSR1));
3633 
3634   ASSERT(0 == pipe(pipe_fds));
3635 
3636   ctx.fd = pipe_fds[doread];
3637   ASSERT(0 == uv_thread_create(&thread, thread_main, &ctx));
3638 
3639   if (doread) {
3640     uv_buf_t* read_iovs;
3641     int nread;
3642     read_iovs = iovs;
3643     nread = 0;
3644     while (nread < ctx.size) {
3645       int result;
3646       result = uv_fs_read(loop, &read_req, pipe_fds[0], read_iovs, iovcount, -1, NULL);
3647       if (result > 0) {
3648         size_t read_iovcount;
3649         read_iovcount = uv_test_fs_buf_offset(read_iovs, result);
3650         read_iovs += read_iovcount;
3651         iovcount -= read_iovcount;
3652         nread += result;
3653       } else {
3654         ASSERT(result == UV_EINTR);
3655       }
3656       uv_fs_req_cleanup(&read_req);
3657     }
3658   } else {
3659     int result;
3660     result = uv_fs_write(loop, &write_req, pipe_fds[1], iovs, iovcount, -1, NULL);
3661     ASSERT(write_req.result == result);
3662     ASSERT(result == ctx.size);
3663     uv_fs_req_cleanup(&write_req);
3664   }
3665 
3666   ASSERT(0 == memcmp(buffer, ctx.data, ctx.size));
3667 
3668   ASSERT(0 == uv_thread_join(&thread));
3669   ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
3670 
3671   ASSERT(0 == close(pipe_fds[1]));
3672   uv_close((uv_handle_t*) &signal, NULL);
3673 
3674   { /* Make sure we read everything that we wrote. */
3675       int result;
3676       result = uv_fs_read(loop, &read_req, pipe_fds[0], iovs, 1, -1, NULL);
3677       ASSERT(result == 0);
3678       uv_fs_req_cleanup(&read_req);
3679   }
3680   ASSERT(0 == close(pipe_fds[0]));
3681 
3682   free(iovs);
3683   free(buffer);
3684   free(ctx.data);
3685 
3686   MAKE_VALGRIND_HAPPY();
3687 }
3688 
3689 TEST_IMPL(fs_partial_read) {
3690   test_fs_partial(1);
3691   return 0;
3692 }
3693 
3694 TEST_IMPL(fs_partial_write) {
3695   test_fs_partial(0);
3696   return 0;
3697 }
3698 
3699 #endif/* _WIN32 */
3700 
3701 TEST_IMPL(fs_read_write_null_arguments) {
3702   int r;
3703 
3704   r = uv_fs_read(NULL, &read_req, 0, NULL, 0, -1, NULL);
3705   ASSERT(r == UV_EINVAL);
3706   uv_fs_req_cleanup(&read_req);
3707 
3708   r = uv_fs_write(NULL, &write_req, 0, NULL, 0, -1, NULL);
3709   /* Validate some memory management on failed input validation before sending
3710      fs work to the thread pool. */
3711   ASSERT(r == UV_EINVAL);
3712   ASSERT(write_req.path == NULL);
3713   ASSERT(write_req.ptr == NULL);
3714 #ifdef _WIN32
3715   ASSERT(write_req.file.pathw == NULL);
3716   ASSERT(write_req.fs.info.new_pathw == NULL);
3717   ASSERT(write_req.fs.info.bufs == NULL);
3718 #else
3719   ASSERT(write_req.new_path == NULL);
3720   ASSERT(write_req.bufs == NULL);
3721 #endif
3722   uv_fs_req_cleanup(&write_req);
3723 
3724   iov = uv_buf_init(NULL, 0);
3725   r = uv_fs_read(NULL, &read_req, 0, &iov, 0, -1, NULL);
3726   ASSERT(r == UV_EINVAL);
3727   uv_fs_req_cleanup(&read_req);
3728 
3729   iov = uv_buf_init(NULL, 0);
3730   r = uv_fs_write(NULL, &write_req, 0, &iov, 0, -1, NULL);
3731   ASSERT(r == UV_EINVAL);
3732   uv_fs_req_cleanup(&write_req);
3733 
3734   /* If the arguments are invalid, the loop should not be kept open */
3735   loop = uv_default_loop();
3736 
3737   r = uv_fs_read(loop, &read_req, 0, NULL, 0, -1, fail_cb);
3738   ASSERT(r == UV_EINVAL);
3739   uv_run(loop, UV_RUN_DEFAULT);
3740   uv_fs_req_cleanup(&read_req);
3741 
3742   r = uv_fs_write(loop, &write_req, 0, NULL, 0, -1, fail_cb);
3743   ASSERT(r == UV_EINVAL);
3744   uv_run(loop, UV_RUN_DEFAULT);
3745   uv_fs_req_cleanup(&write_req);
3746 
3747   iov = uv_buf_init(NULL, 0);
3748   r = uv_fs_read(loop, &read_req, 0, &iov, 0, -1, fail_cb);
3749   ASSERT(r == UV_EINVAL);
3750   uv_run(loop, UV_RUN_DEFAULT);
3751   uv_fs_req_cleanup(&read_req);
3752 
3753   iov = uv_buf_init(NULL, 0);
3754   r = uv_fs_write(loop, &write_req, 0, &iov, 0, -1, fail_cb);
3755   ASSERT(r == UV_EINVAL);
3756   uv_run(loop, UV_RUN_DEFAULT);
3757   uv_fs_req_cleanup(&write_req);
3758 
3759   return 0;
3760 }
3761 
3762 
3763 TEST_IMPL(get_osfhandle_valid_handle) {
3764   int r;
3765   uv_os_fd_t fd;
3766 
3767   /* Setup. */
3768   unlink("test_file");
3769 
3770   loop = uv_default_loop();
3771 
3772   r = uv_fs_open(NULL,
3773                  &open_req1,
3774                  "test_file",
3775                  O_RDWR | O_CREAT,
3776                  S_IWUSR | S_IRUSR,
3777                  NULL);
3778   ASSERT(r >= 0);
3779   ASSERT(open_req1.result >= 0);
3780   uv_fs_req_cleanup(&open_req1);
3781 
3782   fd = uv_get_osfhandle(open_req1.result);
3783 #ifdef _WIN32
3784   ASSERT(fd != INVALID_HANDLE_VALUE);
3785 #else
3786   ASSERT(fd >= 0);
3787 #endif
3788 
3789   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3790   ASSERT(r == 0);
3791   ASSERT(close_req.result == 0);
3792   uv_fs_req_cleanup(&close_req);
3793 
3794   /* Cleanup. */
3795   unlink("test_file");
3796 
3797   MAKE_VALGRIND_HAPPY();
3798   return 0;
3799 }
3800 
3801 TEST_IMPL(open_osfhandle_valid_handle) {
3802   int r;
3803   uv_os_fd_t handle;
3804   int fd;
3805 
3806   /* Setup. */
3807   unlink("test_file");
3808 
3809   loop = uv_default_loop();
3810 
3811   r = uv_fs_open(NULL,
3812                  &open_req1,
3813                  "test_file",
3814                  O_RDWR | O_CREAT,
3815                  S_IWUSR | S_IRUSR,
3816                  NULL);
3817   ASSERT(r >= 0);
3818   ASSERT(open_req1.result >= 0);
3819   uv_fs_req_cleanup(&open_req1);
3820 
3821   handle = uv_get_osfhandle(open_req1.result);
3822 #ifdef _WIN32
3823   ASSERT(handle != INVALID_HANDLE_VALUE);
3824 #else
3825   ASSERT(handle >= 0);
3826 #endif
3827 
3828   fd = uv_open_osfhandle(handle);
3829 #ifdef _WIN32
3830   ASSERT(fd > 0);
3831 #else
3832   ASSERT(fd == open_req1.result);
3833 #endif
3834 
3835   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3836   ASSERT(r == 0);
3837   ASSERT(close_req.result == 0);
3838   uv_fs_req_cleanup(&close_req);
3839 
3840   /* Cleanup. */
3841   unlink("test_file");
3842 
3843   MAKE_VALGRIND_HAPPY();
3844   return 0;
3845 }
3846 
3847 TEST_IMPL(fs_file_pos_after_op_with_offset) {
3848   int r;
3849 
3850   /* Setup. */
3851   unlink("test_file");
3852   loop = uv_default_loop();
3853 
3854   r = uv_fs_open(loop,
3855                  &open_req1,
3856                  "test_file",
3857                  O_RDWR | O_CREAT,
3858                  S_IWUSR | S_IRUSR,
3859                  NULL);
3860   ASSERT(r > 0);
3861   uv_fs_req_cleanup(&open_req1);
3862 
3863   iov = uv_buf_init(test_buf, sizeof(test_buf));
3864   r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, 0, NULL);
3865   ASSERT(r == sizeof(test_buf));
3866   ASSERT(lseek(open_req1.result, 0, SEEK_CUR) == 0);
3867   uv_fs_req_cleanup(&write_req);
3868 
3869   iov = uv_buf_init(buf, sizeof(buf));
3870   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, 0, NULL);
3871   ASSERT(r == sizeof(test_buf));
3872   ASSERT(strcmp(buf, test_buf) == 0);
3873   ASSERT(lseek(open_req1.result, 0, SEEK_CUR) == 0);
3874   uv_fs_req_cleanup(&read_req);
3875 
3876   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3877   ASSERT(r == 0);
3878   uv_fs_req_cleanup(&close_req);
3879 
3880   /* Cleanup */
3881   unlink("test_file");
3882 
3883   MAKE_VALGRIND_HAPPY();
3884   return 0;
3885 }
3886 
3887 #ifdef _WIN32
3888 static void fs_file_pos_common() {
3889   int r;
3890 
3891   iov = uv_buf_init("abc", 3);
3892   r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
3893   ASSERT(r == 3);
3894   uv_fs_req_cleanup(&write_req);
3895 
3896   /* Read with offset should not change the position */
3897   iov = uv_buf_init(buf, 1);
3898   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, 1, NULL);
3899   ASSERT(r == 1);
3900   ASSERT(buf[0] == 'b');
3901   uv_fs_req_cleanup(&read_req);
3902 
3903   iov = uv_buf_init(buf, sizeof(buf));
3904   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
3905   ASSERT(r == 0);
3906   uv_fs_req_cleanup(&read_req);
3907 
3908   /* Write without offset should change the position */
3909   iov = uv_buf_init("d", 1);
3910   r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
3911   ASSERT(r == 1);
3912   uv_fs_req_cleanup(&write_req);
3913 
3914   iov = uv_buf_init(buf, sizeof(buf));
3915   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
3916   ASSERT(r == 0);
3917   uv_fs_req_cleanup(&read_req);
3918 }
3919 
3920 static void fs_file_pos_close_check(const char *contents, int size) {
3921   int r;
3922 
3923   /* Close */
3924   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3925   ASSERT(r == 0);
3926   uv_fs_req_cleanup(&close_req);
3927 
3928   /* Confirm file contents */
3929   r = uv_fs_open(NULL, &open_req1, "test_file", O_RDONLY, 0, NULL);
3930   ASSERT(r >= 0);
3931   ASSERT(open_req1.result >= 0);
3932   uv_fs_req_cleanup(&open_req1);
3933 
3934   iov = uv_buf_init(buf, sizeof(buf));
3935   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
3936   ASSERT(r == size);
3937   ASSERT(strncmp(buf, contents, size) == 0);
3938   uv_fs_req_cleanup(&read_req);
3939 
3940   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3941   ASSERT(r == 0);
3942   uv_fs_req_cleanup(&close_req);
3943 
3944   /* Cleanup */
3945   unlink("test_file");
3946 }
3947 
3948 static void fs_file_pos_write(int add_flags) {
3949   int r;
3950 
3951   /* Setup. */
3952   unlink("test_file");
3953 
3954   r = uv_fs_open(NULL,
3955                  &open_req1,
3956                  "test_file",
3957                  O_TRUNC | O_CREAT | O_RDWR | add_flags,
3958                  S_IWUSR | S_IRUSR,
3959                  NULL);
3960   ASSERT(r > 0);
3961   uv_fs_req_cleanup(&open_req1);
3962 
3963   fs_file_pos_common();
3964 
3965   /* Write with offset should not change the position */
3966   iov = uv_buf_init("e", 1);
3967   r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, 1, NULL);
3968   ASSERT(r == 1);
3969   uv_fs_req_cleanup(&write_req);
3970 
3971   iov = uv_buf_init(buf, sizeof(buf));
3972   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
3973   ASSERT(r == 0);
3974   uv_fs_req_cleanup(&read_req);
3975 
3976   fs_file_pos_close_check("aecd", 4);
3977 }
3978 TEST_IMPL(fs_file_pos_write) {
3979   fs_file_pos_write(0);
3980   fs_file_pos_write(UV_FS_O_FILEMAP);
3981 
3982   MAKE_VALGRIND_HAPPY();
3983   return 0;
3984 }
3985 
3986 static void fs_file_pos_append(int add_flags) {
3987   int r;
3988 
3989   /* Setup. */
3990   unlink("test_file");
3991 
3992   r = uv_fs_open(NULL,
3993                  &open_req1,
3994                  "test_file",
3995                  O_APPEND | O_CREAT | O_RDWR | add_flags,
3996                  S_IWUSR | S_IRUSR,
3997                  NULL);
3998   ASSERT(r > 0);
3999   uv_fs_req_cleanup(&open_req1);
4000 
4001   fs_file_pos_common();
4002 
4003   /* Write with offset appends (ignoring offset)
4004    * but does not change the position */
4005   iov = uv_buf_init("e", 1);
4006   r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, 1, NULL);
4007   ASSERT(r == 1);
4008   uv_fs_req_cleanup(&write_req);
4009 
4010   iov = uv_buf_init(buf, sizeof(buf));
4011   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
4012   ASSERT(r == 1);
4013   ASSERT(buf[0] == 'e');
4014   uv_fs_req_cleanup(&read_req);
4015 
4016   fs_file_pos_close_check("abcde", 5);
4017 }
4018 TEST_IMPL(fs_file_pos_append) {
4019   fs_file_pos_append(0);
4020   fs_file_pos_append(UV_FS_O_FILEMAP);
4021 
4022   MAKE_VALGRIND_HAPPY();
4023   return 0;
4024 }
4025 #endif
4026 
4027 TEST_IMPL(fs_null_req) {
4028   /* Verify that all fs functions return UV_EINVAL when the request is NULL. */
4029   int r;
4030 
4031   r = uv_fs_open(NULL, NULL, NULL, 0, 0, NULL);
4032   ASSERT(r == UV_EINVAL);
4033 
4034   r = uv_fs_close(NULL, NULL, 0, NULL);
4035   ASSERT(r == UV_EINVAL);
4036 
4037   r = uv_fs_read(NULL, NULL, 0, NULL, 0, -1, NULL);
4038   ASSERT(r == UV_EINVAL);
4039 
4040   r = uv_fs_write(NULL, NULL, 0, NULL, 0, -1, NULL);
4041   ASSERT(r == UV_EINVAL);
4042 
4043   r = uv_fs_unlink(NULL, NULL, NULL, NULL);
4044   ASSERT(r == UV_EINVAL);
4045 
4046   r = uv_fs_mkdir(NULL, NULL, NULL, 0, NULL);
4047   ASSERT(r == UV_EINVAL);
4048 
4049   r = uv_fs_mkdtemp(NULL, NULL, NULL, NULL);
4050   ASSERT(r == UV_EINVAL);
4051 
4052   r = uv_fs_mkstemp(NULL, NULL, NULL, NULL);
4053   ASSERT(r == UV_EINVAL);
4054 
4055   r = uv_fs_rmdir(NULL, NULL, NULL, NULL);
4056   ASSERT(r == UV_EINVAL);
4057 
4058   r = uv_fs_scandir(NULL, NULL, NULL, 0, NULL);
4059   ASSERT(r == UV_EINVAL);
4060 
4061   r = uv_fs_link(NULL, NULL, NULL, NULL, NULL);
4062   ASSERT(r == UV_EINVAL);
4063 
4064   r = uv_fs_symlink(NULL, NULL, NULL, NULL, 0, NULL);
4065   ASSERT(r == UV_EINVAL);
4066 
4067   r = uv_fs_readlink(NULL, NULL, NULL, NULL);
4068   ASSERT(r == UV_EINVAL);
4069 
4070   r = uv_fs_realpath(NULL, NULL, NULL, NULL);
4071   ASSERT(r == UV_EINVAL);
4072 
4073   r = uv_fs_chown(NULL, NULL, NULL, 0, 0, NULL);
4074   ASSERT(r == UV_EINVAL);
4075 
4076   r = uv_fs_fchown(NULL, NULL, 0, 0, 0, NULL);
4077   ASSERT(r == UV_EINVAL);
4078 
4079   r = uv_fs_stat(NULL, NULL, NULL, NULL);
4080   ASSERT(r == UV_EINVAL);
4081 
4082   r = uv_fs_lstat(NULL, NULL, NULL, NULL);
4083   ASSERT(r == UV_EINVAL);
4084 
4085   r = uv_fs_fstat(NULL, NULL, 0, NULL);
4086   ASSERT(r == UV_EINVAL);
4087 
4088   r = uv_fs_rename(NULL, NULL, NULL, NULL, NULL);
4089   ASSERT(r == UV_EINVAL);
4090 
4091   r = uv_fs_fsync(NULL, NULL, 0, NULL);
4092   ASSERT(r == UV_EINVAL);
4093 
4094   r = uv_fs_fdatasync(NULL, NULL, 0, NULL);
4095   ASSERT(r == UV_EINVAL);
4096 
4097   r = uv_fs_ftruncate(NULL, NULL, 0, 0, NULL);
4098   ASSERT(r == UV_EINVAL);
4099 
4100   r = uv_fs_copyfile(NULL, NULL, NULL, NULL, 0, NULL);
4101   ASSERT(r == UV_EINVAL);
4102 
4103   r = uv_fs_sendfile(NULL, NULL, 0, 0, 0, 0, NULL);
4104   ASSERT(r == UV_EINVAL);
4105 
4106   r = uv_fs_access(NULL, NULL, NULL, 0, NULL);
4107   ASSERT(r == UV_EINVAL);
4108 
4109   r = uv_fs_chmod(NULL, NULL, NULL, 0, NULL);
4110   ASSERT(r == UV_EINVAL);
4111 
4112   r = uv_fs_fchmod(NULL, NULL, 0, 0, NULL);
4113   ASSERT(r == UV_EINVAL);
4114 
4115   r = uv_fs_utime(NULL, NULL, NULL, 0.0, 0.0, NULL);
4116   ASSERT(r == UV_EINVAL);
4117 
4118   r = uv_fs_futime(NULL, NULL, 0, 0.0, 0.0, NULL);
4119   ASSERT(r == UV_EINVAL);
4120 
4121   r = uv_fs_statfs(NULL, NULL, NULL, NULL);
4122   ASSERT(r == UV_EINVAL);
4123 
4124   /* This should be a no-op. */
4125   uv_fs_req_cleanup(NULL);
4126 
4127   return 0;
4128 }
4129 
4130 #ifdef _WIN32
4131 TEST_IMPL(fs_exclusive_sharing_mode) {
4132   int r;
4133 
4134   /* Setup. */
4135   unlink("test_file");
4136 
4137   ASSERT(UV_FS_O_EXLOCK > 0);
4138 
4139   r = uv_fs_open(NULL,
4140                  &open_req1,
4141                  "test_file",
4142                  O_RDWR | O_CREAT | UV_FS_O_EXLOCK,
4143                  S_IWUSR | S_IRUSR,
4144                  NULL);
4145   ASSERT(r >= 0);
4146   ASSERT(open_req1.result >= 0);
4147   uv_fs_req_cleanup(&open_req1);
4148 
4149   r = uv_fs_open(NULL,
4150                  &open_req2,
4151                  "test_file",
4152                  O_RDONLY | UV_FS_O_EXLOCK,
4153                  S_IWUSR | S_IRUSR,
4154                  NULL);
4155   ASSERT(r < 0);
4156   ASSERT(open_req2.result < 0);
4157   uv_fs_req_cleanup(&open_req2);
4158 
4159   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
4160   ASSERT(r == 0);
4161   ASSERT(close_req.result == 0);
4162   uv_fs_req_cleanup(&close_req);
4163 
4164   r = uv_fs_open(NULL,
4165                  &open_req2,
4166                  "test_file",
4167                  O_RDONLY | UV_FS_O_EXLOCK,
4168                  S_IWUSR | S_IRUSR,
4169                  NULL);
4170   ASSERT(r >= 0);
4171   ASSERT(open_req2.result >= 0);
4172   uv_fs_req_cleanup(&open_req2);
4173 
4174   r = uv_fs_close(NULL, &close_req, open_req2.result, NULL);
4175   ASSERT(r == 0);
4176   ASSERT(close_req.result == 0);
4177   uv_fs_req_cleanup(&close_req);
4178 
4179   /* Cleanup */
4180   unlink("test_file");
4181 
4182   MAKE_VALGRIND_HAPPY();
4183   return 0;
4184 }
4185 #endif
4186 
4187 #ifdef _WIN32
4188 TEST_IMPL(fs_file_flag_no_buffering) {
4189   int r;
4190 
4191   /* Setup. */
4192   unlink("test_file");
4193 
4194   ASSERT(UV_FS_O_APPEND > 0);
4195   ASSERT(UV_FS_O_CREAT > 0);
4196   ASSERT(UV_FS_O_DIRECT > 0);
4197   ASSERT(UV_FS_O_RDWR > 0);
4198 
4199   /* FILE_APPEND_DATA must be excluded from FILE_GENERIC_WRITE: */
4200   r = uv_fs_open(NULL,
4201                  &open_req1,
4202                  "test_file",
4203                  UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_DIRECT,
4204                  S_IWUSR | S_IRUSR,
4205                  NULL);
4206   ASSERT(r >= 0);
4207   ASSERT(open_req1.result >= 0);
4208   uv_fs_req_cleanup(&open_req1);
4209 
4210   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
4211   ASSERT(r == 0);
4212   ASSERT(close_req.result == 0);
4213   uv_fs_req_cleanup(&close_req);
4214 
4215   /* FILE_APPEND_DATA and FILE_FLAG_NO_BUFFERING are mutually exclusive: */
4216   r = uv_fs_open(NULL,
4217                  &open_req2,
4218                  "test_file",
4219                  UV_FS_O_APPEND | UV_FS_O_DIRECT,
4220                  S_IWUSR | S_IRUSR,
4221                  NULL);
4222   ASSERT(r == UV_EINVAL);
4223   ASSERT(open_req2.result == UV_EINVAL);
4224   uv_fs_req_cleanup(&open_req2);
4225 
4226   /* Cleanup */
4227   unlink("test_file");
4228 
4229   MAKE_VALGRIND_HAPPY();
4230   return 0;
4231 }
4232 #endif
4233 
4234 #ifdef _WIN32
4235 int call_icacls(const char* command, ...) {
4236     char icacls_command[1024];
4237     va_list args;
4238 
4239     va_start(args, command);
4240     vsnprintf(icacls_command, ARRAYSIZE(icacls_command), command, args);
4241     va_end(args);
4242     return system(icacls_command);
4243 }
4244 
4245 TEST_IMPL(fs_open_readonly_acl) {
4246     uv_passwd_t pwd;
4247     uv_fs_t req;
4248     int r;
4249 
4250     /*
4251         Based on Node.js test from
4252         https://github.com/nodejs/node/commit/3ba81e34e86a5c32658e218cb6e65b13e8326bc5
4253 
4254         If anything goes wrong, you can delte the test_fle_icacls with:
4255 
4256             icacls test_file_icacls /remove "%USERNAME%" /inheritance:e
4257             attrib -r test_file_icacls
4258             del test_file_icacls
4259     */
4260 
4261     /* Setup - clear the ACL and remove the file */
4262     loop = uv_default_loop();
4263     r = uv_os_get_passwd(&pwd);
4264     ASSERT(r == 0);
4265     call_icacls("icacls test_file_icacls /remove \"%s\" /inheritance:e",
4266                 pwd.username);
4267     uv_fs_chmod(loop, &req, "test_file_icacls", S_IWUSR, NULL);
4268     unlink("test_file_icacls");
4269 
4270     /* Create the file */
4271     r = uv_fs_open(loop,
4272                    &open_req1,
4273                    "test_file_icacls",
4274                    O_RDONLY | O_CREAT,
4275                    S_IRUSR,
4276                    NULL);
4277     ASSERT(r >= 0);
4278     ASSERT(open_req1.result >= 0);
4279     uv_fs_req_cleanup(&open_req1);
4280     r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
4281     ASSERT(r == 0);
4282     ASSERT(close_req.result == 0);
4283     uv_fs_req_cleanup(&close_req);
4284 
4285     /* Set up ACL */
4286     r = call_icacls("icacls test_file_icacls /inheritance:r /remove \"%s\"",
4287                     pwd.username);
4288     if (r != 0) {
4289         goto acl_cleanup;
4290     }
4291     r = call_icacls("icacls test_file_icacls /grant \"%s\":RX", pwd.username);
4292     if (r != 0) {
4293         goto acl_cleanup;
4294     }
4295 
4296     /* Try opening the file */
4297     r = uv_fs_open(NULL, &open_req1, "test_file_icacls", O_RDONLY, 0, NULL);
4298     if (r < 0) {
4299         goto acl_cleanup;
4300     }
4301     uv_fs_req_cleanup(&open_req1);
4302     r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
4303     if (r != 0) {
4304         goto acl_cleanup;
4305     }
4306     uv_fs_req_cleanup(&close_req);
4307 
4308  acl_cleanup:
4309     /* Cleanup */
4310     call_icacls("icacls test_file_icacls /remove \"%s\" /inheritance:e",
4311                 pwd.username);
4312     unlink("test_file_icacls");
4313     uv_os_free_passwd(&pwd);
4314     ASSERT(r == 0);
4315     MAKE_VALGRIND_HAPPY();
4316     return 0;
4317 }
4318 #endif
4319 
4320 #ifdef _WIN32
4321 TEST_IMPL(fs_fchmod_archive_readonly) {
4322     uv_fs_t req;
4323     uv_file file;
4324     int r;
4325     /* Test clearing read-only flag from files with Archive flag cleared */
4326 
4327     /* Setup*/
4328     unlink("test_file");
4329     r = uv_fs_open(NULL,
4330                    &req,
4331                    "test_file",
4332                    O_WRONLY | O_CREAT,
4333                    S_IWUSR | S_IRUSR,
4334                    NULL);
4335     ASSERT(r >= 0);
4336     ASSERT(req.result >= 0);
4337     file = req.result;
4338     uv_fs_req_cleanup(&req);
4339     r = uv_fs_close(NULL, &req, file, NULL);
4340     ASSERT(r == 0);
4341     uv_fs_req_cleanup(&req);
4342     /* Make the file read-only and clear archive flag */
4343     r = SetFileAttributes("test_file", FILE_ATTRIBUTE_READONLY);
4344     ASSERT(r != 0);
4345     check_permission("test_file", 0400);
4346     /* Try fchmod */
4347     r = uv_fs_open(NULL, &req, "test_file", O_RDONLY, 0, NULL);
4348     ASSERT(r >= 0);
4349     ASSERT(req.result >= 0);
4350     file = req.result;
4351     uv_fs_req_cleanup(&req);
4352     r = uv_fs_fchmod(NULL, &req, file, S_IWUSR, NULL);
4353     ASSERT(r == 0);
4354     ASSERT(req.result == 0);
4355     uv_fs_req_cleanup(&req);
4356     r = uv_fs_close(NULL, &req, file, NULL);
4357     ASSERT(r == 0);
4358     uv_fs_req_cleanup(&req);
4359     check_permission("test_file", S_IWUSR);
4360 
4361     /* Restore Archive flag for rest of the tests */
4362     r = SetFileAttributes("test_file", FILE_ATTRIBUTE_ARCHIVE);
4363     ASSERT(r != 0);
4364 
4365     return 0;
4366 }
4367 
4368 TEST_IMPL(fs_invalid_mkdir_name) {
4369   uv_loop_t* loop;
4370   uv_fs_t req;
4371   int r;
4372 
4373   loop = uv_default_loop();
4374   r = uv_fs_mkdir(loop, &req, "invalid>", 0, NULL);
4375   ASSERT(r == UV_EINVAL);
4376 
4377   return 0;
4378 }
4379 #endif
4380 
4381 TEST_IMPL(fs_statfs) {
4382   uv_fs_t req;
4383   int r;
4384 
4385   loop = uv_default_loop();
4386 
4387   /* Test the synchronous version. */
4388   r = uv_fs_statfs(NULL, &req, ".", NULL);
4389   ASSERT(r == 0);
4390   statfs_cb(&req);
4391   ASSERT(statfs_cb_count == 1);
4392 
4393   /* Test the asynchronous version. */
4394   r = uv_fs_statfs(loop, &req, ".", statfs_cb);
4395   ASSERT(r == 0);
4396   uv_run(loop, UV_RUN_DEFAULT);
4397   ASSERT(statfs_cb_count == 2);
4398 
4399   return 0;
4400 }
4401 
4402 TEST_IMPL(fs_get_system_error) {
4403   uv_fs_t req;
4404   int r;
4405   int system_error;
4406 
4407   r = uv_fs_statfs(NULL, &req, "non_existing_file", NULL);
4408   ASSERT(r != 0);
4409 
4410   system_error = uv_fs_get_system_error(&req);
4411 #ifdef _WIN32
4412   ASSERT(system_error == ERROR_FILE_NOT_FOUND);
4413 #else
4414   ASSERT(system_error == ENOENT);
4415 #endif
4416 
4417   return 0;
4418 }
4419