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