xref: /libuv/test/test-fs.c (revision fbe2d85b)
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_rmdir(NULL, &rmdir_req, "test_dir/file", NULL);
1092   ASSERT((r == UV_ENOTDIR) || (r == UV_ENOENT));
1093   ASSERT_EQ(r, rmdir_req.result);
1094   uv_fs_req_cleanup(&rmdir_req);
1095 
1096   r = uv_fs_unlink(NULL, &unlink_req, "test_dir/file", NULL);
1097   ASSERT_OK(r);
1098   ASSERT_OK(unlink_req.result);
1099   uv_fs_req_cleanup(&unlink_req);
1100 
1101   /* delete the dir while the file is still open, which should succeed on posix */
1102   r = uv_fs_rmdir(NULL, &rmdir_req, "test_dir", NULL);
1103   ASSERT_OK(r);
1104   ASSERT_OK(rmdir_req.result);
1105   uv_fs_req_cleanup(&rmdir_req);
1106 
1107   /* Cleanup */
1108   r = uv_fs_close(NULL, &close_req, open_req_noclose.result, NULL);
1109   ASSERT_OK(r);
1110   uv_fs_req_cleanup(&close_req);
1111 
1112   MAKE_VALGRIND_HAPPY(uv_default_loop());
1113   return 0;
1114 }
1115 
fs_file_write_null_buffer(int add_flags)1116 static void fs_file_write_null_buffer(int add_flags) {
1117   int r;
1118 
1119   /* Setup. */
1120   unlink("test_file");
1121 
1122   loop = uv_default_loop();
1123 
1124   r = uv_fs_open(NULL, &open_req1, "test_file",
1125                  UV_FS_O_WRONLY | UV_FS_O_CREAT | add_flags, S_IWUSR | S_IRUSR,
1126                  NULL);
1127   ASSERT_GE(r, 0);
1128   ASSERT_GE(open_req1.result, 0);
1129   uv_fs_req_cleanup(&open_req1);
1130 
1131   iov = uv_buf_init(NULL, 0);
1132   r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
1133   ASSERT_OK(r);
1134   ASSERT_OK(write_req.result);
1135   uv_fs_req_cleanup(&write_req);
1136 
1137   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
1138   ASSERT_OK(r);
1139   ASSERT_OK(close_req.result);
1140   uv_fs_req_cleanup(&close_req);
1141 
1142   unlink("test_file");
1143 }
TEST_IMPL(fs_file_write_null_buffer)1144 TEST_IMPL(fs_file_write_null_buffer) {
1145   fs_file_write_null_buffer(0);
1146   fs_file_write_null_buffer(UV_FS_O_FILEMAP);
1147 
1148   MAKE_VALGRIND_HAPPY(loop);
1149   return 0;
1150 }
1151 
1152 
TEST_IMPL(fs_async_dir)1153 TEST_IMPL(fs_async_dir) {
1154   int r;
1155   uv_dirent_t dent;
1156 
1157   /* Setup */
1158   unlink("test_dir/file1");
1159   unlink("test_dir/file2");
1160   rmdir("test_dir");
1161 
1162   loop = uv_default_loop();
1163 
1164   r = uv_fs_mkdir(loop, &mkdir_req, "test_dir", 0755, mkdir_cb);
1165   ASSERT_OK(r);
1166 
1167   uv_run(loop, UV_RUN_DEFAULT);
1168   ASSERT_EQ(1, mkdir_cb_count);
1169 
1170   /* Create 2 files synchronously. */
1171   r = uv_fs_open(NULL, &open_req1, "test_dir/file1",
1172                  UV_FS_O_WRONLY | UV_FS_O_CREAT,
1173       S_IWUSR | S_IRUSR, NULL);
1174   ASSERT_GE(r, 0);
1175   uv_fs_req_cleanup(&open_req1);
1176   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
1177   ASSERT_OK(r);
1178   uv_fs_req_cleanup(&close_req);
1179 
1180   r = uv_fs_open(NULL, &open_req1, "test_dir/file2",
1181                  UV_FS_O_WRONLY | UV_FS_O_CREAT,
1182       S_IWUSR | S_IRUSR, NULL);
1183   ASSERT_GE(r, 0);
1184   uv_fs_req_cleanup(&open_req1);
1185   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
1186   ASSERT_OK(r);
1187   uv_fs_req_cleanup(&close_req);
1188 
1189   r = uv_fs_scandir(loop, &scandir_req, "test_dir", 0, scandir_cb);
1190   ASSERT_OK(r);
1191 
1192   uv_run(loop, UV_RUN_DEFAULT);
1193   ASSERT_EQ(1, scandir_cb_count);
1194 
1195   /* sync uv_fs_scandir */
1196   r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL);
1197   ASSERT_EQ(2, r);
1198   ASSERT_EQ(2, scandir_req.result);
1199   ASSERT(scandir_req.ptr);
1200   while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) {
1201     ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0);
1202     assert_is_file_type(dent);
1203   }
1204   uv_fs_req_cleanup(&scandir_req);
1205   ASSERT(!scandir_req.ptr);
1206 
1207   r = uv_fs_stat(loop, &stat_req, "test_dir", stat_cb);
1208   ASSERT_OK(r);
1209   uv_run(loop, UV_RUN_DEFAULT);
1210 
1211   r = uv_fs_stat(loop, &stat_req, "test_dir/", stat_cb);
1212   ASSERT_OK(r);
1213   uv_run(loop, UV_RUN_DEFAULT);
1214 
1215   r = uv_fs_lstat(loop, &stat_req, "test_dir", stat_cb);
1216   ASSERT_OK(r);
1217   uv_run(loop, UV_RUN_DEFAULT);
1218 
1219   r = uv_fs_lstat(loop, &stat_req, "test_dir/", stat_cb);
1220   ASSERT_OK(r);
1221   uv_run(loop, UV_RUN_DEFAULT);
1222 
1223   ASSERT_EQ(4, stat_cb_count);
1224 
1225   r = uv_fs_unlink(loop, &unlink_req, "test_dir/file1", unlink_cb);
1226   ASSERT_OK(r);
1227   uv_run(loop, UV_RUN_DEFAULT);
1228   ASSERT_EQ(1, unlink_cb_count);
1229 
1230   r = uv_fs_unlink(loop, &unlink_req, "test_dir/file2", unlink_cb);
1231   ASSERT_OK(r);
1232   uv_run(loop, UV_RUN_DEFAULT);
1233   ASSERT_EQ(2, unlink_cb_count);
1234 
1235   r = uv_fs_rmdir(loop, &rmdir_req, "test_dir", rmdir_cb);
1236   ASSERT_OK(r);
1237   uv_run(loop, UV_RUN_DEFAULT);
1238   ASSERT_EQ(1, rmdir_cb_count);
1239 
1240   /* Cleanup */
1241   unlink("test_dir/file1");
1242   unlink("test_dir/file2");
1243   rmdir("test_dir");
1244 
1245   MAKE_VALGRIND_HAPPY(loop);
1246   return 0;
1247 }
1248 
1249 
test_sendfile(void (* setup)(int),uv_fs_cb cb,size_t expected_size)1250 static int test_sendfile(void (*setup)(int), uv_fs_cb cb, size_t expected_size) {
1251   int f, r;
1252   struct stat s1, s2;
1253   uv_fs_t req;
1254   char buf1[1];
1255 
1256   loop = uv_default_loop();
1257 
1258   /* Setup. */
1259   unlink("test_file");
1260   unlink("test_file2");
1261 
1262   f = open("test_file", UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR);
1263   ASSERT_NE(f, -1);
1264 
1265   if (setup != NULL)
1266     setup(f);
1267 
1268   r = close(f);
1269   ASSERT_OK(r);
1270 
1271   /* Test starts here. */
1272   r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDWR, 0, NULL);
1273   ASSERT_GE(r, 0);
1274   ASSERT_GE(open_req1.result, 0);
1275   uv_fs_req_cleanup(&open_req1);
1276 
1277   r = uv_fs_open(NULL, &open_req2, "test_file2", UV_FS_O_WRONLY | UV_FS_O_CREAT,
1278       S_IWUSR | S_IRUSR, NULL);
1279   ASSERT_GE(r, 0);
1280   ASSERT_GE(open_req2.result, 0);
1281   uv_fs_req_cleanup(&open_req2);
1282 
1283   r = uv_fs_sendfile(loop, &sendfile_req, open_req2.result, open_req1.result,
1284       1, 131072, cb);
1285   ASSERT_OK(r);
1286   uv_run(loop, UV_RUN_DEFAULT);
1287 
1288   ASSERT_EQ(1, sendfile_cb_count);
1289 
1290   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
1291   ASSERT_OK(r);
1292   uv_fs_req_cleanup(&close_req);
1293   r = uv_fs_close(NULL, &close_req, open_req2.result, NULL);
1294   ASSERT_OK(r);
1295   uv_fs_req_cleanup(&close_req);
1296 
1297   memset(&s1, 0, sizeof(s1));
1298   memset(&s2, 0, sizeof(s2));
1299   ASSERT_OK(stat("test_file", &s1));
1300   ASSERT_OK(stat("test_file2", &s2));
1301   ASSERT_EQ(s2.st_size, expected_size);
1302 
1303   if (expected_size > 0) {
1304     ASSERT_UINT64_EQ(s1.st_size, s2.st_size + 1);
1305     r = uv_fs_open(NULL, &open_req1, "test_file2", UV_FS_O_RDWR, 0, NULL);
1306     ASSERT_GE(r, 0);
1307     ASSERT_GE(open_req1.result, 0);
1308     uv_fs_req_cleanup(&open_req1);
1309 
1310     memset(buf1, 0, sizeof(buf1));
1311     iov = uv_buf_init(buf1, sizeof(buf1));
1312     r = uv_fs_read(NULL, &req, open_req1.result, &iov, 1, -1, NULL);
1313     ASSERT_GE(r, 0);
1314     ASSERT_GE(req.result, 0);
1315     ASSERT_EQ(buf1[0], 'e'); /* 'e' from begin */
1316     uv_fs_req_cleanup(&req);
1317   } else {
1318     ASSERT_UINT64_EQ(s1.st_size, s2.st_size);
1319   }
1320 
1321   /* Cleanup. */
1322   unlink("test_file");
1323   unlink("test_file2");
1324 
1325   MAKE_VALGRIND_HAPPY(loop);
1326   return 0;
1327 }
1328 
1329 
sendfile_setup(int f)1330 static void sendfile_setup(int f) {
1331   ASSERT_EQ(6, write(f, "begin\n", 6));
1332   ASSERT_EQ(65542, lseek(f, 65536, SEEK_CUR));
1333   ASSERT_EQ(4, write(f, "end\n", 4));
1334 }
1335 
1336 
TEST_IMPL(fs_async_sendfile)1337 TEST_IMPL(fs_async_sendfile) {
1338   return test_sendfile(sendfile_setup, sendfile_cb, 65545);
1339 }
1340 
1341 
TEST_IMPL(fs_async_sendfile_nodata)1342 TEST_IMPL(fs_async_sendfile_nodata) {
1343   return test_sendfile(NULL, sendfile_nodata_cb, 0);
1344 }
1345 
1346 
TEST_IMPL(fs_mkdtemp)1347 TEST_IMPL(fs_mkdtemp) {
1348   int r;
1349   const char* path_template = "test_dir_XXXXXX";
1350 
1351   loop = uv_default_loop();
1352 
1353   r = uv_fs_mkdtemp(loop, &mkdtemp_req1, path_template, mkdtemp_cb);
1354   ASSERT_OK(r);
1355 
1356   uv_run(loop, UV_RUN_DEFAULT);
1357   ASSERT_EQ(1, mkdtemp_cb_count);
1358 
1359   /* sync mkdtemp */
1360   r = uv_fs_mkdtemp(NULL, &mkdtemp_req2, path_template, NULL);
1361   ASSERT_OK(r);
1362   check_mkdtemp_result(&mkdtemp_req2);
1363 
1364   /* mkdtemp return different values on subsequent calls */
1365   ASSERT_NE(0, strcmp(mkdtemp_req1.path, mkdtemp_req2.path));
1366 
1367   /* Cleanup */
1368   rmdir(mkdtemp_req1.path);
1369   rmdir(mkdtemp_req2.path);
1370   uv_fs_req_cleanup(&mkdtemp_req1);
1371   uv_fs_req_cleanup(&mkdtemp_req2);
1372 
1373   MAKE_VALGRIND_HAPPY(loop);
1374   return 0;
1375 }
1376 
1377 
TEST_IMPL(fs_mkstemp)1378 TEST_IMPL(fs_mkstemp) {
1379   int r;
1380   int fd;
1381   const char path_template[] = "test_file_XXXXXX";
1382   uv_fs_t req;
1383 
1384   loop = uv_default_loop();
1385 
1386   r = uv_fs_mkstemp(loop, &mkstemp_req1, path_template, mkstemp_cb);
1387   ASSERT_OK(r);
1388 
1389   uv_run(loop, UV_RUN_DEFAULT);
1390   ASSERT_EQ(1, mkstemp_cb_count);
1391 
1392   /* sync mkstemp */
1393   r = uv_fs_mkstemp(NULL, &mkstemp_req2, path_template, NULL);
1394   ASSERT_GE(r, 0);
1395   check_mkstemp_result(&mkstemp_req2);
1396 
1397   /* mkstemp return different values on subsequent calls */
1398   ASSERT_NE(0, strcmp(mkstemp_req1.path, mkstemp_req2.path));
1399 
1400   /* invalid template returns EINVAL */
1401   ASSERT_EQ(UV_EINVAL, uv_fs_mkstemp(NULL, &mkstemp_req3, "test_file", NULL));
1402 
1403   /* Make sure that path is empty string */
1404   ASSERT_OK(strlen(mkstemp_req3.path));
1405 
1406   uv_fs_req_cleanup(&mkstemp_req3);
1407 
1408   /* We can write to the opened file */
1409   iov = uv_buf_init(test_buf, sizeof(test_buf));
1410   r = uv_fs_write(NULL, &req, mkstemp_req1.result, &iov, 1, -1, NULL);
1411   ASSERT_EQ(r, sizeof(test_buf));
1412   ASSERT_EQ(req.result, sizeof(test_buf));
1413   uv_fs_req_cleanup(&req);
1414 
1415   /* Cleanup */
1416   uv_fs_close(NULL, &req, mkstemp_req1.result, NULL);
1417   uv_fs_req_cleanup(&req);
1418   uv_fs_close(NULL, &req, mkstemp_req2.result, NULL);
1419   uv_fs_req_cleanup(&req);
1420 
1421   fd = uv_fs_open(NULL, &req, mkstemp_req1.path, UV_FS_O_RDONLY, 0, NULL);
1422   ASSERT_GE(fd, 0);
1423   uv_fs_req_cleanup(&req);
1424 
1425   memset(buf, 0, sizeof(buf));
1426   iov = uv_buf_init(buf, sizeof(buf));
1427   r = uv_fs_read(NULL, &req, fd, &iov, 1, -1, NULL);
1428   ASSERT_GE(r, 0);
1429   ASSERT_GE(req.result, 0);
1430   ASSERT_OK(strcmp(buf, test_buf));
1431   uv_fs_req_cleanup(&req);
1432 
1433   uv_fs_close(NULL, &req, fd, NULL);
1434   uv_fs_req_cleanup(&req);
1435 
1436   unlink(mkstemp_req1.path);
1437   unlink(mkstemp_req2.path);
1438   uv_fs_req_cleanup(&mkstemp_req1);
1439   uv_fs_req_cleanup(&mkstemp_req2);
1440 
1441   MAKE_VALGRIND_HAPPY(loop);
1442   return 0;
1443 }
1444 
1445 
TEST_IMPL(fs_fstat)1446 TEST_IMPL(fs_fstat) {
1447   int r;
1448   uv_fs_t req;
1449   uv_file file;
1450   uv_stat_t* s;
1451 #ifndef _WIN32
1452   struct stat t;
1453 #endif
1454 
1455 #if defined(__s390__) && defined(__QEMU__)
1456   /* qemu-user-s390x has this weird bug where statx() reports nanoseconds
1457    * but plain fstat() does not.
1458    */
1459   RETURN_SKIP("Test does not currently work in QEMU");
1460 #endif
1461 
1462   /* Setup. */
1463   unlink("test_file");
1464 
1465   loop = uv_default_loop();
1466 
1467   r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT,
1468       S_IWUSR | S_IRUSR, NULL);
1469   ASSERT_GE(r, 0);
1470   ASSERT_GE(req.result, 0);
1471   file = req.result;
1472   uv_fs_req_cleanup(&req);
1473 
1474 #ifndef _WIN32
1475   memset(&t, 0, sizeof(t));
1476   ASSERT_OK(fstat(file, &t));
1477   ASSERT_OK(uv_fs_fstat(NULL, &req, file, NULL));
1478   ASSERT_OK(req.result);
1479   s = req.ptr;
1480 # if defined(__APPLE__)
1481   ASSERT_EQ(s->st_birthtim.tv_sec, t.st_birthtimespec.tv_sec);
1482   ASSERT_EQ(s->st_birthtim.tv_nsec, t.st_birthtimespec.tv_nsec);
1483 # elif defined(__linux__)
1484   /* If statx() is supported, the birth time should be equal to the change time
1485    * because we just created the file. On older kernels, it's set to zero.
1486    */
1487   ASSERT(s->st_birthtim.tv_sec == 0 ||
1488          s->st_birthtim.tv_sec == t.st_ctim.tv_sec);
1489   ASSERT(s->st_birthtim.tv_nsec == 0 ||
1490          s->st_birthtim.tv_nsec == t.st_ctim.tv_nsec);
1491 # endif
1492 #endif
1493 
1494   iov = uv_buf_init(test_buf, sizeof(test_buf));
1495   r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
1496   ASSERT_EQ(r, sizeof(test_buf));
1497   ASSERT_EQ(req.result, sizeof(test_buf));
1498   uv_fs_req_cleanup(&req);
1499 
1500   memset(&req.statbuf, 0xaa, sizeof(req.statbuf));
1501   r = uv_fs_fstat(NULL, &req, file, NULL);
1502   ASSERT_OK(r);
1503   ASSERT_OK(req.result);
1504   s = req.ptr;
1505   ASSERT_EQ(s->st_size, sizeof(test_buf));
1506 
1507 #ifndef _WIN32
1508   r = fstat(file, &t);
1509   ASSERT_OK(r);
1510 
1511   ASSERT_EQ(s->st_dev, (uint64_t) t.st_dev);
1512   ASSERT_EQ(s->st_mode, (uint64_t) t.st_mode);
1513   ASSERT_EQ(s->st_nlink, (uint64_t) t.st_nlink);
1514   ASSERT_EQ(s->st_uid, (uint64_t) t.st_uid);
1515   ASSERT_EQ(s->st_gid, (uint64_t) t.st_gid);
1516   ASSERT_EQ(s->st_rdev, (uint64_t) t.st_rdev);
1517   ASSERT_EQ(s->st_ino, (uint64_t) t.st_ino);
1518   ASSERT_EQ(s->st_size, (uint64_t) t.st_size);
1519   ASSERT_EQ(s->st_blksize, (uint64_t) t.st_blksize);
1520   ASSERT_EQ(s->st_blocks, (uint64_t) t.st_blocks);
1521 #if defined(__APPLE__)
1522   ASSERT_EQ(s->st_atim.tv_sec, t.st_atimespec.tv_sec);
1523   ASSERT_EQ(s->st_atim.tv_nsec, t.st_atimespec.tv_nsec);
1524   ASSERT_EQ(s->st_mtim.tv_sec, t.st_mtimespec.tv_sec);
1525   ASSERT_EQ(s->st_mtim.tv_nsec, t.st_mtimespec.tv_nsec);
1526   ASSERT_EQ(s->st_ctim.tv_sec, t.st_ctimespec.tv_sec);
1527   ASSERT_EQ(s->st_ctim.tv_nsec, t.st_ctimespec.tv_nsec);
1528 #elif defined(_AIX)    || \
1529       defined(__MVS__)
1530   ASSERT_EQ(s->st_atim.tv_sec, t.st_atime);
1531   ASSERT_OK(s->st_atim.tv_nsec);
1532   ASSERT_EQ(s->st_mtim.tv_sec, t.st_mtime);
1533   ASSERT_OK(s->st_mtim.tv_nsec);
1534   ASSERT_EQ(s->st_ctim.tv_sec, t.st_ctime);
1535   ASSERT_OK(s->st_ctim.tv_nsec);
1536 #elif defined(__ANDROID__)
1537   ASSERT_EQ(s->st_atim.tv_sec, t.st_atime);
1538   ASSERT_EQ(s->st_atim.tv_nsec, t.st_atimensec);
1539   ASSERT_EQ(s->st_mtim.tv_sec, t.st_mtime);
1540   ASSERT_EQ(s->st_mtim.tv_nsec, t.st_mtimensec);
1541   ASSERT_EQ(s->st_ctim.tv_sec, t.st_ctime);
1542   ASSERT_EQ(s->st_ctim.tv_nsec, t.st_ctimensec);
1543 #elif defined(__sun)           || \
1544       defined(__DragonFly__)   || \
1545       defined(__FreeBSD__)     || \
1546       defined(__OpenBSD__)     || \
1547       defined(__NetBSD__)      || \
1548       defined(_GNU_SOURCE)     || \
1549       defined(_BSD_SOURCE)     || \
1550       defined(_SVID_SOURCE)    || \
1551       defined(_XOPEN_SOURCE)   || \
1552       defined(_DEFAULT_SOURCE)
1553   ASSERT_EQ(s->st_atim.tv_sec, t.st_atim.tv_sec);
1554   ASSERT_EQ(s->st_atim.tv_nsec, t.st_atim.tv_nsec);
1555   ASSERT_EQ(s->st_mtim.tv_sec, t.st_mtim.tv_sec);
1556   ASSERT_EQ(s->st_mtim.tv_nsec, t.st_mtim.tv_nsec);
1557   ASSERT_EQ(s->st_ctim.tv_sec, t.st_ctim.tv_sec);
1558   ASSERT_EQ(s->st_ctim.tv_nsec, t.st_ctim.tv_nsec);
1559 # if defined(__FreeBSD__)    || \
1560      defined(__NetBSD__)
1561   ASSERT_EQ(s->st_birthtim.tv_sec, t.st_birthtim.tv_sec);
1562   ASSERT_EQ(s->st_birthtim.tv_nsec, t.st_birthtim.tv_nsec);
1563 # endif
1564 #else
1565   ASSERT_EQ(s->st_atim.tv_sec, t.st_atime);
1566   ASSERT_OK(s->st_atim.tv_nsec);
1567   ASSERT_EQ(s->st_mtim.tv_sec, t.st_mtime);
1568   ASSERT_OK(s->st_mtim.tv_nsec);
1569   ASSERT_EQ(s->st_ctim.tv_sec, t.st_ctime);
1570   ASSERT_OK(s->st_ctim.tv_nsec);
1571 #endif
1572 #endif
1573 
1574 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
1575   ASSERT_EQ(s->st_flags, t.st_flags);
1576   ASSERT_EQ(s->st_gen, t.st_gen);
1577 #else
1578   ASSERT_OK(s->st_flags);
1579   ASSERT_OK(s->st_gen);
1580 #endif
1581 
1582   uv_fs_req_cleanup(&req);
1583 
1584   /* Now do the uv_fs_fstat call asynchronously */
1585   r = uv_fs_fstat(loop, &req, file, fstat_cb);
1586   ASSERT_OK(r);
1587   uv_run(loop, UV_RUN_DEFAULT);
1588   ASSERT_EQ(1, fstat_cb_count);
1589 
1590 
1591   r = uv_fs_close(NULL, &req, file, NULL);
1592   ASSERT_OK(r);
1593   ASSERT_OK(req.result);
1594   uv_fs_req_cleanup(&req);
1595 
1596   /*
1597    * Run the loop just to check we don't have make any extraneous uv_ref()
1598    * calls. This should drop out immediately.
1599    */
1600   uv_run(loop, UV_RUN_DEFAULT);
1601 
1602   /* Cleanup. */
1603   unlink("test_file");
1604 
1605   MAKE_VALGRIND_HAPPY(loop);
1606   return 0;
1607 }
1608 
1609 
TEST_IMPL(fs_fstat_stdio)1610 TEST_IMPL(fs_fstat_stdio) {
1611   int fd;
1612   int res;
1613   uv_fs_t req;
1614 #ifdef _WIN32
1615   uv_stat_t* st;
1616   DWORD ft;
1617 #endif
1618 
1619   for (fd = 0; fd <= 2; ++fd) {
1620     res = uv_fs_fstat(NULL, &req, fd, NULL);
1621     ASSERT_OK(res);
1622     ASSERT_OK(req.result);
1623 
1624 #ifdef _WIN32
1625     st = req.ptr;
1626     ft = uv_guess_handle(fd);
1627     switch (ft) {
1628     case UV_TTY:
1629     case UV_NAMED_PIPE:
1630       ASSERT_EQ(st->st_mode, (ft == UV_TTY ? S_IFCHR : S_IFIFO));
1631       ASSERT_EQ(1, st->st_nlink);
1632       ASSERT_EQ(st->st_rdev,
1633                 (ft == UV_TTY ? FILE_DEVICE_CONSOLE : FILE_DEVICE_NAMED_PIPE)
1634                 << 16);
1635       break;
1636     default:
1637       break;
1638     }
1639 #endif
1640 
1641     uv_fs_req_cleanup(&req);
1642   }
1643 
1644   MAKE_VALGRIND_HAPPY(uv_default_loop());
1645   return 0;
1646 }
1647 
1648 
TEST_IMPL(fs_access)1649 TEST_IMPL(fs_access) {
1650   int r;
1651   uv_fs_t req;
1652   uv_file file;
1653 
1654   /* Setup. */
1655   unlink("test_file");
1656   rmdir("test_dir");
1657 
1658   loop = uv_default_loop();
1659 
1660   /* File should not exist */
1661   r = uv_fs_access(NULL, &req, "test_file", F_OK, NULL);
1662   ASSERT_LT(r, 0);
1663   ASSERT_LT(req.result, 0);
1664   uv_fs_req_cleanup(&req);
1665 
1666   /* File should not exist */
1667   r = uv_fs_access(loop, &req, "test_file", F_OK, access_cb);
1668   ASSERT_OK(r);
1669   uv_run(loop, UV_RUN_DEFAULT);
1670   ASSERT_EQ(1, access_cb_count);
1671   access_cb_count = 0; /* reset for the next test */
1672 
1673   /* Create file */
1674   r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT,
1675                  S_IWUSR | S_IRUSR, NULL);
1676   ASSERT_GE(r, 0);
1677   ASSERT_GE(req.result, 0);
1678   file = req.result;
1679   uv_fs_req_cleanup(&req);
1680 
1681   /* File should exist */
1682   r = uv_fs_access(NULL, &req, "test_file", F_OK, NULL);
1683   ASSERT_OK(r);
1684   ASSERT_OK(req.result);
1685   uv_fs_req_cleanup(&req);
1686 
1687   /* File should exist */
1688   r = uv_fs_access(loop, &req, "test_file", F_OK, access_cb);
1689   ASSERT_OK(r);
1690   uv_run(loop, UV_RUN_DEFAULT);
1691   ASSERT_EQ(1, access_cb_count);
1692   access_cb_count = 0; /* reset for the next test */
1693 
1694   /* Close file */
1695   r = uv_fs_close(NULL, &req, file, NULL);
1696   ASSERT_OK(r);
1697   ASSERT_OK(req.result);
1698   uv_fs_req_cleanup(&req);
1699 
1700   /* Directory access */
1701   r = uv_fs_mkdir(NULL, &req, "test_dir", 0777, NULL);
1702   ASSERT_OK(r);
1703   uv_fs_req_cleanup(&req);
1704 
1705   r = uv_fs_access(NULL, &req, "test_dir", W_OK, NULL);
1706   ASSERT_OK(r);
1707   ASSERT_OK(req.result);
1708   uv_fs_req_cleanup(&req);
1709 
1710   /*
1711    * Run the loop just to check we don't have make any extraneous uv_ref()
1712    * calls. This should drop out immediately.
1713    */
1714   uv_run(loop, UV_RUN_DEFAULT);
1715 
1716   /* Cleanup. */
1717   unlink("test_file");
1718   rmdir("test_dir");
1719 
1720   MAKE_VALGRIND_HAPPY(loop);
1721   return 0;
1722 }
1723 
1724 
TEST_IMPL(fs_chmod)1725 TEST_IMPL(fs_chmod) {
1726   int r;
1727   uv_fs_t req;
1728   uv_file file;
1729 
1730   /* Setup. */
1731   unlink("test_file");
1732 
1733   loop = uv_default_loop();
1734 
1735   r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT,
1736       S_IWUSR | S_IRUSR, NULL);
1737   ASSERT_GE(r, 0);
1738   ASSERT_GE(req.result, 0);
1739   file = req.result;
1740   uv_fs_req_cleanup(&req);
1741 
1742   iov = uv_buf_init(test_buf, sizeof(test_buf));
1743   r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
1744   ASSERT_EQ(r, sizeof(test_buf));
1745   ASSERT_EQ(req.result, sizeof(test_buf));
1746   uv_fs_req_cleanup(&req);
1747 
1748 #ifndef _WIN32
1749   /* Make the file write-only */
1750   r = uv_fs_chmod(NULL, &req, "test_file", 0200, NULL);
1751   ASSERT_OK(r);
1752   ASSERT_OK(req.result);
1753   uv_fs_req_cleanup(&req);
1754 
1755   check_permission("test_file", 0200);
1756 #endif
1757 
1758   /* Make the file read-only */
1759   r = uv_fs_chmod(NULL, &req, "test_file", 0400, NULL);
1760   ASSERT_OK(r);
1761   ASSERT_OK(req.result);
1762   uv_fs_req_cleanup(&req);
1763 
1764   check_permission("test_file", 0400);
1765 
1766   /* Make the file read+write with sync uv_fs_fchmod */
1767   r = uv_fs_fchmod(NULL, &req, file, 0600, NULL);
1768   ASSERT_OK(r);
1769   ASSERT_OK(req.result);
1770   uv_fs_req_cleanup(&req);
1771 
1772   check_permission("test_file", 0600);
1773 
1774 #ifndef _WIN32
1775   /* async chmod */
1776   {
1777     static int mode = 0200;
1778     req.data = &mode;
1779   }
1780   r = uv_fs_chmod(loop, &req, "test_file", 0200, chmod_cb);
1781   ASSERT_OK(r);
1782   uv_run(loop, UV_RUN_DEFAULT);
1783   ASSERT_EQ(1, chmod_cb_count);
1784   chmod_cb_count = 0; /* reset for the next test */
1785 #endif
1786 
1787   /* async chmod */
1788   {
1789     static int mode = 0400;
1790     req.data = &mode;
1791   }
1792   r = uv_fs_chmod(loop, &req, "test_file", 0400, chmod_cb);
1793   ASSERT_OK(r);
1794   uv_run(loop, UV_RUN_DEFAULT);
1795   ASSERT_EQ(1, chmod_cb_count);
1796 
1797   /* async fchmod */
1798   {
1799     static int mode = 0600;
1800     req.data = &mode;
1801   }
1802   r = uv_fs_fchmod(loop, &req, file, 0600, fchmod_cb);
1803   ASSERT_OK(r);
1804   uv_run(loop, UV_RUN_DEFAULT);
1805   ASSERT_EQ(1, fchmod_cb_count);
1806 
1807   uv_fs_close(loop, &req, file, NULL);
1808 
1809   /*
1810    * Run the loop just to check we don't have make any extraneous uv_ref()
1811    * calls. This should drop out immediately.
1812    */
1813   uv_run(loop, UV_RUN_DEFAULT);
1814 
1815   /* Cleanup. */
1816   unlink("test_file");
1817 
1818   MAKE_VALGRIND_HAPPY(loop);
1819   return 0;
1820 }
1821 
1822 
TEST_IMPL(fs_unlink_readonly)1823 TEST_IMPL(fs_unlink_readonly) {
1824   int r;
1825   uv_fs_t req;
1826   uv_file file;
1827 
1828   /* Setup. */
1829   unlink("test_file");
1830 
1831   loop = uv_default_loop();
1832 
1833   r = uv_fs_open(NULL,
1834                  &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT,
1835                  S_IWUSR | S_IRUSR,
1836                  NULL);
1837   ASSERT_GE(r, 0);
1838   ASSERT_GE(req.result, 0);
1839   file = req.result;
1840   uv_fs_req_cleanup(&req);
1841 
1842   iov = uv_buf_init(test_buf, sizeof(test_buf));
1843   r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
1844   ASSERT_EQ(r, sizeof(test_buf));
1845   ASSERT_EQ(req.result, sizeof(test_buf));
1846   uv_fs_req_cleanup(&req);
1847 
1848   uv_fs_close(loop, &req, file, NULL);
1849 
1850   /* Make the file read-only */
1851   r = uv_fs_chmod(NULL, &req, "test_file", 0400, NULL);
1852   ASSERT_OK(r);
1853   ASSERT_OK(req.result);
1854   uv_fs_req_cleanup(&req);
1855 
1856   check_permission("test_file", 0400);
1857 
1858   /* Try to unlink the file */
1859   r = uv_fs_unlink(NULL, &req, "test_file", NULL);
1860   ASSERT_OK(r);
1861   ASSERT_OK(req.result);
1862   uv_fs_req_cleanup(&req);
1863 
1864   /*
1865   * Run the loop just to check we don't have make any extraneous uv_ref()
1866   * calls. This should drop out immediately.
1867   */
1868   uv_run(loop, UV_RUN_DEFAULT);
1869 
1870   /* Cleanup. */
1871   uv_fs_chmod(NULL, &req, "test_file", 0600, NULL);
1872   uv_fs_req_cleanup(&req);
1873   unlink("test_file");
1874 
1875   MAKE_VALGRIND_HAPPY(loop);
1876   return 0;
1877 }
1878 
1879 #ifdef _WIN32
TEST_IMPL(fs_unlink_archive_readonly)1880 TEST_IMPL(fs_unlink_archive_readonly) {
1881   int r;
1882   uv_fs_t req;
1883   uv_file file;
1884 
1885   /* Setup. */
1886   unlink("test_file");
1887 
1888   loop = uv_default_loop();
1889 
1890   r = uv_fs_open(NULL,
1891                  &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT,
1892                  S_IWUSR | S_IRUSR,
1893                  NULL);
1894   ASSERT_GE(r, 0);
1895   ASSERT_GE(req.result, 0);
1896   file = req.result;
1897   uv_fs_req_cleanup(&req);
1898 
1899   iov = uv_buf_init(test_buf, sizeof(test_buf));
1900   r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
1901   ASSERT_EQ(r, sizeof(test_buf));
1902   ASSERT_EQ(req.result, sizeof(test_buf));
1903   uv_fs_req_cleanup(&req);
1904 
1905   uv_fs_close(loop, &req, file, NULL);
1906 
1907   /* Make the file read-only and clear archive flag */
1908   r = SetFileAttributes("test_file", FILE_ATTRIBUTE_READONLY);
1909   ASSERT(r);
1910   uv_fs_req_cleanup(&req);
1911 
1912   check_permission("test_file", 0400);
1913 
1914   /* Try to unlink the file */
1915   r = uv_fs_unlink(NULL, &req, "test_file", NULL);
1916   ASSERT_OK(r);
1917   ASSERT_OK(req.result);
1918   uv_fs_req_cleanup(&req);
1919 
1920   /*
1921   * Run the loop just to check we don't have make any extraneous uv_ref()
1922   * calls. This should drop out immediately.
1923   */
1924   uv_run(loop, UV_RUN_DEFAULT);
1925 
1926   /* Cleanup. */
1927   uv_fs_chmod(NULL, &req, "test_file", 0600, NULL);
1928   uv_fs_req_cleanup(&req);
1929   unlink("test_file");
1930 
1931   MAKE_VALGRIND_HAPPY(loop);
1932   return 0;
1933 }
1934 #endif
1935 
TEST_IMPL(fs_chown)1936 TEST_IMPL(fs_chown) {
1937   int r;
1938   uv_fs_t req;
1939   uv_file file;
1940 
1941   /* Setup. */
1942   unlink("test_file");
1943   unlink("test_file_link");
1944 
1945   loop = uv_default_loop();
1946 
1947   r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT,
1948       S_IWUSR | S_IRUSR, NULL);
1949   ASSERT_GE(r, 0);
1950   ASSERT_GE(req.result, 0);
1951   file = req.result;
1952   uv_fs_req_cleanup(&req);
1953 
1954   /* sync chown */
1955   r = uv_fs_chown(NULL, &req, "test_file", -1, -1, NULL);
1956   ASSERT_OK(r);
1957   ASSERT_OK(req.result);
1958   uv_fs_req_cleanup(&req);
1959 
1960   /* sync fchown */
1961   r = uv_fs_fchown(NULL, &req, file, -1, -1, NULL);
1962   ASSERT_OK(r);
1963   ASSERT_OK(req.result);
1964   uv_fs_req_cleanup(&req);
1965 
1966   /* async chown */
1967   r = uv_fs_chown(loop, &req, "test_file", -1, -1, chown_cb);
1968   ASSERT_OK(r);
1969   uv_run(loop, UV_RUN_DEFAULT);
1970   ASSERT_EQ(1, chown_cb_count);
1971 
1972 #ifndef __MVS__
1973   /* chown to root (fail) */
1974   chown_cb_count = 0;
1975   r = uv_fs_chown(loop, &req, "test_file", 0, 0, chown_root_cb);
1976   ASSERT_OK(r);
1977   uv_run(loop, UV_RUN_DEFAULT);
1978   ASSERT_EQ(1, chown_cb_count);
1979 #endif
1980 
1981   /* async fchown */
1982   r = uv_fs_fchown(loop, &req, file, -1, -1, fchown_cb);
1983   ASSERT_OK(r);
1984   uv_run(loop, UV_RUN_DEFAULT);
1985   ASSERT_EQ(1, fchown_cb_count);
1986 
1987 #ifndef __HAIKU__
1988   /* Haiku doesn't support hardlink */
1989   /* sync link */
1990   r = uv_fs_link(NULL, &req, "test_file", "test_file_link", NULL);
1991   ASSERT_OK(r);
1992   ASSERT_OK(req.result);
1993   uv_fs_req_cleanup(&req);
1994 
1995   /* sync lchown */
1996   r = uv_fs_lchown(NULL, &req, "test_file_link", -1, -1, NULL);
1997   ASSERT_OK(r);
1998   ASSERT_OK(req.result);
1999   uv_fs_req_cleanup(&req);
2000 
2001   /* async lchown */
2002   r = uv_fs_lchown(loop, &req, "test_file_link", -1, -1, lchown_cb);
2003   ASSERT_OK(r);
2004   uv_run(loop, UV_RUN_DEFAULT);
2005   ASSERT_EQ(1, lchown_cb_count);
2006 #endif
2007 
2008   /* Close file */
2009   r = uv_fs_close(NULL, &req, file, NULL);
2010   ASSERT_OK(r);
2011   ASSERT_OK(req.result);
2012   uv_fs_req_cleanup(&req);
2013 
2014   /*
2015    * Run the loop just to check we don't have make any extraneous uv_ref()
2016    * calls. This should drop out immediately.
2017    */
2018   uv_run(loop, UV_RUN_DEFAULT);
2019 
2020   /* Cleanup. */
2021   unlink("test_file");
2022   unlink("test_file_link");
2023 
2024   MAKE_VALGRIND_HAPPY(loop);
2025   return 0;
2026 }
2027 
2028 
TEST_IMPL(fs_link)2029 TEST_IMPL(fs_link) {
2030   int r;
2031   uv_fs_t req;
2032   uv_file file;
2033   uv_file link;
2034 
2035   /* Setup. */
2036   unlink("test_file");
2037   unlink("test_file_link");
2038   unlink("test_file_link2");
2039 
2040   loop = uv_default_loop();
2041 
2042   r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT,
2043       S_IWUSR | S_IRUSR, NULL);
2044   ASSERT_GE(r, 0);
2045   ASSERT_GE(req.result, 0);
2046   file = req.result;
2047   uv_fs_req_cleanup(&req);
2048 
2049   iov = uv_buf_init(test_buf, sizeof(test_buf));
2050   r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
2051   ASSERT_EQ(r, sizeof(test_buf));
2052   ASSERT_EQ(req.result, sizeof(test_buf));
2053   uv_fs_req_cleanup(&req);
2054 
2055   uv_fs_close(loop, &req, file, NULL);
2056 
2057   /* sync link */
2058   r = uv_fs_link(NULL, &req, "test_file", "test_file_link", NULL);
2059   ASSERT_OK(r);
2060   ASSERT_OK(req.result);
2061   uv_fs_req_cleanup(&req);
2062 
2063   r = uv_fs_open(NULL, &req, "test_file_link", UV_FS_O_RDWR, 0, NULL);
2064   ASSERT_GE(r, 0);
2065   ASSERT_GE(req.result, 0);
2066   link = req.result;
2067   uv_fs_req_cleanup(&req);
2068 
2069   memset(buf, 0, sizeof(buf));
2070   iov = uv_buf_init(buf, sizeof(buf));
2071   r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
2072   ASSERT_GE(r, 0);
2073   ASSERT_GE(req.result, 0);
2074   ASSERT_OK(strcmp(buf, test_buf));
2075 
2076   close(link);
2077 
2078   /* async link */
2079   r = uv_fs_link(loop, &req, "test_file", "test_file_link2", link_cb);
2080   ASSERT_OK(r);
2081   uv_run(loop, UV_RUN_DEFAULT);
2082   ASSERT_EQ(1, link_cb_count);
2083 
2084   r = uv_fs_open(NULL, &req, "test_file_link2", UV_FS_O_RDWR, 0, NULL);
2085   ASSERT_GE(r, 0);
2086   ASSERT_GE(req.result, 0);
2087   link = req.result;
2088   uv_fs_req_cleanup(&req);
2089 
2090   memset(buf, 0, sizeof(buf));
2091   iov = uv_buf_init(buf, sizeof(buf));
2092   r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
2093   ASSERT_GE(r, 0);
2094   ASSERT_GE(req.result, 0);
2095   ASSERT_OK(strcmp(buf, test_buf));
2096 
2097   uv_fs_close(loop, &req, link, NULL);
2098 
2099   /*
2100    * Run the loop just to check we don't have make any extraneous uv_ref()
2101    * calls. This should drop out immediately.
2102    */
2103   uv_run(loop, UV_RUN_DEFAULT);
2104 
2105   /* Cleanup. */
2106   unlink("test_file");
2107   unlink("test_file_link");
2108   unlink("test_file_link2");
2109 
2110   MAKE_VALGRIND_HAPPY(loop);
2111   return 0;
2112 }
2113 
2114 
TEST_IMPL(fs_readlink)2115 TEST_IMPL(fs_readlink) {
2116   /* Must return UV_ENOENT on an inexistent file */
2117   {
2118     uv_fs_t req;
2119 
2120     loop = uv_default_loop();
2121     ASSERT_OK(uv_fs_readlink(loop, &req, "no_such_file", dummy_cb));
2122     ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT));
2123     ASSERT_EQ(1, dummy_cb_count);
2124     ASSERT_NULL(req.ptr);
2125     ASSERT_EQ(req.result, UV_ENOENT);
2126     uv_fs_req_cleanup(&req);
2127 
2128     ASSERT_EQ(UV_ENOENT, uv_fs_readlink(NULL, &req, "no_such_file", NULL));
2129     ASSERT_NULL(req.ptr);
2130     ASSERT_EQ(req.result, UV_ENOENT);
2131     uv_fs_req_cleanup(&req);
2132   }
2133 
2134   /* Must return UV_EINVAL on a non-symlink file */
2135   {
2136     int r;
2137     uv_fs_t req;
2138     uv_file file;
2139 
2140     /* Setup */
2141 
2142     /* Create a non-symlink file */
2143     r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT,
2144                    S_IWUSR | S_IRUSR, NULL);
2145     ASSERT_GE(r, 0);
2146     ASSERT_GE(req.result, 0);
2147     file = req.result;
2148     uv_fs_req_cleanup(&req);
2149 
2150     r = uv_fs_close(NULL, &req, file, NULL);
2151     ASSERT_OK(r);
2152     ASSERT_OK(req.result);
2153     uv_fs_req_cleanup(&req);
2154 
2155     /* Test */
2156     r = uv_fs_readlink(NULL, &req, "test_file", NULL);
2157     ASSERT_EQ(r, UV_EINVAL);
2158     uv_fs_req_cleanup(&req);
2159 
2160     /* Cleanup */
2161     unlink("test_file");
2162   }
2163 
2164   MAKE_VALGRIND_HAPPY(loop);
2165   return 0;
2166 }
2167 
2168 
TEST_IMPL(fs_realpath)2169 TEST_IMPL(fs_realpath) {
2170   uv_fs_t req;
2171 
2172   loop = uv_default_loop();
2173   ASSERT_OK(uv_fs_realpath(loop, &req, "no_such_file", dummy_cb));
2174   ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT));
2175   ASSERT_EQ(1, dummy_cb_count);
2176   ASSERT_NULL(req.ptr);
2177   ASSERT_EQ(req.result, UV_ENOENT);
2178   uv_fs_req_cleanup(&req);
2179 
2180   ASSERT_EQ(UV_ENOENT, uv_fs_realpath(NULL, &req, "no_such_file", NULL));
2181   ASSERT_NULL(req.ptr);
2182   ASSERT_EQ(req.result, UV_ENOENT);
2183   uv_fs_req_cleanup(&req);
2184 
2185   MAKE_VALGRIND_HAPPY(loop);
2186   return 0;
2187 }
2188 
2189 
TEST_IMPL(fs_symlink)2190 TEST_IMPL(fs_symlink) {
2191   int r;
2192   uv_fs_t req;
2193   uv_file file;
2194   uv_file link;
2195   char test_file_abs_buf[PATHMAX];
2196   size_t test_file_abs_size;
2197 
2198   /* Setup. */
2199   unlink("test_file");
2200   unlink("test_file_symlink");
2201   unlink("test_file_symlink2");
2202   unlink("test_file_symlink_symlink");
2203   unlink("test_file_symlink2_symlink");
2204   test_file_abs_size = sizeof(test_file_abs_buf);
2205 #ifdef _WIN32
2206   uv_cwd(test_file_abs_buf, &test_file_abs_size);
2207   strcat(test_file_abs_buf, "\\test_file");
2208 #else
2209   uv_cwd(test_file_abs_buf, &test_file_abs_size);
2210   strcat(test_file_abs_buf, "/test_file");
2211 #endif
2212 
2213   loop = uv_default_loop();
2214 
2215   r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT,
2216       S_IWUSR | S_IRUSR, NULL);
2217   ASSERT_GE(r, 0);
2218   ASSERT_GE(req.result, 0);
2219   file = req.result;
2220   uv_fs_req_cleanup(&req);
2221 
2222   iov = uv_buf_init(test_buf, sizeof(test_buf));
2223   r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
2224   ASSERT_EQ(r, sizeof(test_buf));
2225   ASSERT_EQ(req.result, sizeof(test_buf));
2226   uv_fs_req_cleanup(&req);
2227 
2228   uv_fs_close(loop, &req, file, NULL);
2229 
2230   /* sync symlink */
2231   r = uv_fs_symlink(NULL, &req, "test_file", "test_file_symlink", 0, NULL);
2232 #ifdef _WIN32
2233   if (r < 0) {
2234     if (r == UV_ENOTSUP) {
2235       /*
2236        * Windows doesn't support symlinks on older versions.
2237        * We just pass the test and bail out early if we get ENOTSUP.
2238        */
2239       return 0;
2240     } else if (r == UV_EPERM) {
2241       /*
2242        * Creating a symlink is only allowed when running elevated.
2243        * We pass the test and bail out early if we get UV_EPERM.
2244        */
2245       return 0;
2246     }
2247   }
2248 #endif
2249   ASSERT_OK(r);
2250   ASSERT_OK(req.result);
2251   uv_fs_req_cleanup(&req);
2252 
2253   r = uv_fs_open(NULL, &req, "test_file_symlink", UV_FS_O_RDWR, 0, NULL);
2254   ASSERT_GE(r, 0);
2255   ASSERT_GE(req.result, 0);
2256   link = req.result;
2257   uv_fs_req_cleanup(&req);
2258 
2259   memset(buf, 0, sizeof(buf));
2260   iov = uv_buf_init(buf, sizeof(buf));
2261   r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
2262   ASSERT_GE(r, 0);
2263   ASSERT_GE(req.result, 0);
2264   ASSERT_OK(strcmp(buf, test_buf));
2265 
2266   uv_fs_close(loop, &req, link, NULL);
2267 
2268   r = uv_fs_symlink(NULL,
2269                     &req,
2270                     "test_file_symlink",
2271                     "test_file_symlink_symlink",
2272                     0,
2273                     NULL);
2274   ASSERT_OK(r);
2275   uv_fs_req_cleanup(&req);
2276 
2277 #if defined(__MSYS__)
2278   RETURN_SKIP("symlink reading is not supported on MSYS2");
2279 #endif
2280 
2281   r = uv_fs_readlink(NULL, &req, "test_file_symlink_symlink", NULL);
2282   ASSERT_OK(r);
2283   ASSERT_OK(strcmp(req.ptr, "test_file_symlink"));
2284   uv_fs_req_cleanup(&req);
2285 
2286   r = uv_fs_realpath(NULL, &req, "test_file_symlink_symlink", NULL);
2287   ASSERT_OK(r);
2288 #ifdef _WIN32
2289   ASSERT_OK(_stricmp(req.ptr, test_file_abs_buf));
2290 #else
2291   ASSERT_OK(strcmp(req.ptr, test_file_abs_buf));
2292 #endif
2293   uv_fs_req_cleanup(&req);
2294 
2295   /* async link */
2296   r = uv_fs_symlink(loop,
2297                     &req,
2298                     "test_file",
2299                     "test_file_symlink2",
2300                     0,
2301                     symlink_cb);
2302   ASSERT_OK(r);
2303   uv_run(loop, UV_RUN_DEFAULT);
2304   ASSERT_EQ(1, symlink_cb_count);
2305 
2306   r = uv_fs_open(NULL, &req, "test_file_symlink2", UV_FS_O_RDWR, 0, NULL);
2307   ASSERT_GE(r, 0);
2308   ASSERT_GE(req.result, 0);
2309   link = req.result;
2310   uv_fs_req_cleanup(&req);
2311 
2312   memset(buf, 0, sizeof(buf));
2313   iov = uv_buf_init(buf, sizeof(buf));
2314   r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
2315   ASSERT_GE(r, 0);
2316   ASSERT_GE(req.result, 0);
2317   ASSERT_OK(strcmp(buf, test_buf));
2318 
2319   uv_fs_close(loop, &req, link, NULL);
2320 
2321   r = uv_fs_symlink(NULL,
2322                     &req,
2323                     "test_file_symlink2",
2324                     "test_file_symlink2_symlink",
2325                     0,
2326                     NULL);
2327   ASSERT_OK(r);
2328   uv_fs_req_cleanup(&req);
2329 
2330   r = uv_fs_readlink(loop, &req, "test_file_symlink2_symlink", readlink_cb);
2331   ASSERT_OK(r);
2332   uv_run(loop, UV_RUN_DEFAULT);
2333   ASSERT_EQ(1, readlink_cb_count);
2334 
2335   r = uv_fs_realpath(loop, &req, "test_file", realpath_cb);
2336   ASSERT_OK(r);
2337   uv_run(loop, UV_RUN_DEFAULT);
2338   ASSERT_EQ(1, realpath_cb_count);
2339 
2340   /*
2341    * Run the loop just to check we don't have make any extraneous uv_ref()
2342    * calls. This should drop out immediately.
2343    */
2344   uv_run(loop, UV_RUN_DEFAULT);
2345 
2346   /* Cleanup. */
2347   unlink("test_file");
2348   unlink("test_file_symlink");
2349   unlink("test_file_symlink_symlink");
2350   unlink("test_file_symlink2");
2351   unlink("test_file_symlink2_symlink");
2352 
2353   MAKE_VALGRIND_HAPPY(loop);
2354   return 0;
2355 }
2356 
2357 
test_symlink_dir_impl(int type)2358 int test_symlink_dir_impl(int type) {
2359   uv_fs_t req;
2360   int r;
2361   char* test_dir;
2362   uv_dirent_t dent;
2363   static char test_dir_abs_buf[PATHMAX];
2364   size_t test_dir_abs_size;
2365 
2366   /* set-up */
2367   unlink("test_dir/file1");
2368   unlink("test_dir/file2");
2369   rmdir("test_dir");
2370   rmdir("test_dir_symlink");
2371   test_dir_abs_size = sizeof(test_dir_abs_buf);
2372 
2373   loop = uv_default_loop();
2374 
2375   uv_fs_mkdir(NULL, &req, "test_dir", 0777, NULL);
2376   uv_fs_req_cleanup(&req);
2377 
2378 #ifdef _WIN32
2379   strcpy(test_dir_abs_buf, "\\\\?\\");
2380   uv_cwd(test_dir_abs_buf + 4, &test_dir_abs_size);
2381   test_dir_abs_size += 4;
2382   strcat(test_dir_abs_buf, "\\test_dir");
2383   test_dir_abs_size += strlen("\\test_dir");
2384   test_dir = test_dir_abs_buf;
2385 #else
2386   uv_cwd(test_dir_abs_buf, &test_dir_abs_size);
2387   strcat(test_dir_abs_buf, "/test_dir");
2388   test_dir_abs_size += strlen("/test_dir");
2389   test_dir = "test_dir";
2390 #endif
2391 
2392   r = uv_fs_symlink(NULL, &req, test_dir, "test_dir_symlink", type, NULL);
2393   if (type == UV_FS_SYMLINK_DIR && (r == UV_ENOTSUP || r == UV_EPERM)) {
2394     uv_fs_req_cleanup(&req);
2395     RETURN_SKIP("this version of Windows doesn't support unprivileged "
2396                 "creation of directory symlinks");
2397   }
2398   fprintf(stderr, "r == %i\n", r);
2399   ASSERT_OK(r);
2400   ASSERT_OK(req.result);
2401   uv_fs_req_cleanup(&req);
2402 
2403   r = uv_fs_stat(NULL, &req, "test_dir_symlink", NULL);
2404   ASSERT_OK(r);
2405   ASSERT(((uv_stat_t*)req.ptr)->st_mode & S_IFDIR);
2406   uv_fs_req_cleanup(&req);
2407 
2408   r = uv_fs_lstat(NULL, &req, "test_dir_symlink", NULL);
2409   ASSERT_OK(r);
2410 #if defined(__MSYS__)
2411   RETURN_SKIP("symlink reading is not supported on MSYS2");
2412 #endif
2413   ASSERT(((uv_stat_t*)req.ptr)->st_mode & S_IFLNK);
2414 #ifdef _WIN32
2415   ASSERT_EQ(((uv_stat_t*)req.ptr)->st_size, strlen(test_dir + 4));
2416 #else
2417 # ifdef __PASE__
2418   /* On IBMi PASE, st_size returns the length of the symlink itself. */
2419   ASSERT_EQ(((uv_stat_t*)req.ptr)->st_size, strlen("test_dir_symlink"));
2420 # else
2421   ASSERT_EQ(((uv_stat_t*)req.ptr)->st_size, strlen(test_dir));
2422 # endif
2423 #endif
2424   uv_fs_req_cleanup(&req);
2425 
2426   r = uv_fs_readlink(NULL, &req, "test_dir_symlink", NULL);
2427   ASSERT_OK(r);
2428 #ifdef _WIN32
2429   ASSERT_OK(strcmp(req.ptr, test_dir + 4));
2430 #else
2431   ASSERT_OK(strcmp(req.ptr, test_dir));
2432 #endif
2433   uv_fs_req_cleanup(&req);
2434 
2435   r = uv_fs_realpath(NULL, &req, "test_dir_symlink", NULL);
2436   ASSERT_OK(r);
2437 #ifdef _WIN32
2438   ASSERT_EQ(strlen(req.ptr), test_dir_abs_size - 4);
2439   ASSERT_OK(_strnicmp(req.ptr, test_dir + 4, test_dir_abs_size - 4));
2440 #else
2441   ASSERT_OK(strcmp(req.ptr, test_dir_abs_buf));
2442 #endif
2443   uv_fs_req_cleanup(&req);
2444 
2445   r = uv_fs_open(NULL, &open_req1, "test_dir/file1",
2446                  UV_FS_O_WRONLY | UV_FS_O_CREAT,
2447       S_IWUSR | S_IRUSR, NULL);
2448   ASSERT_GE(r, 0);
2449   uv_fs_req_cleanup(&open_req1);
2450   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
2451   ASSERT_OK(r);
2452   uv_fs_req_cleanup(&close_req);
2453 
2454   r = uv_fs_open(NULL, &open_req1, "test_dir/file2",
2455                  UV_FS_O_WRONLY | UV_FS_O_CREAT,
2456       S_IWUSR | S_IRUSR, NULL);
2457   ASSERT_GE(r, 0);
2458   uv_fs_req_cleanup(&open_req1);
2459   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
2460   ASSERT_OK(r);
2461   uv_fs_req_cleanup(&close_req);
2462 
2463   r = uv_fs_scandir(NULL, &scandir_req, "test_dir_symlink", 0, NULL);
2464   ASSERT_EQ(2, r);
2465   ASSERT_EQ(2, scandir_req.result);
2466   ASSERT(scandir_req.ptr);
2467   while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) {
2468     ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0);
2469     assert_is_file_type(dent);
2470   }
2471   uv_fs_req_cleanup(&scandir_req);
2472   ASSERT(!scandir_req.ptr);
2473 
2474   /* unlink will remove the directory symlink */
2475   r = uv_fs_unlink(NULL, &req, "test_dir_symlink", NULL);
2476   ASSERT_OK(r);
2477   uv_fs_req_cleanup(&req);
2478 
2479   r = uv_fs_scandir(NULL, &scandir_req, "test_dir_symlink", 0, NULL);
2480   ASSERT_EQ(r, UV_ENOENT);
2481   uv_fs_req_cleanup(&scandir_req);
2482 
2483   r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL);
2484   ASSERT_EQ(2, r);
2485   ASSERT_EQ(2, scandir_req.result);
2486   ASSERT(scandir_req.ptr);
2487   while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) {
2488     ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0);
2489     assert_is_file_type(dent);
2490   }
2491   uv_fs_req_cleanup(&scandir_req);
2492   ASSERT(!scandir_req.ptr);
2493 
2494   /* clean-up */
2495   unlink("test_dir/file1");
2496   unlink("test_dir/file2");
2497   rmdir("test_dir");
2498   rmdir("test_dir_symlink");
2499 
2500   MAKE_VALGRIND_HAPPY(loop);
2501   return 0;
2502 }
2503 
TEST_IMPL(fs_symlink_dir)2504 TEST_IMPL(fs_symlink_dir) {
2505   return test_symlink_dir_impl(UV_FS_SYMLINK_DIR);
2506 }
2507 
TEST_IMPL(fs_symlink_junction)2508 TEST_IMPL(fs_symlink_junction) {
2509   return test_symlink_dir_impl(UV_FS_SYMLINK_JUNCTION);
2510 }
2511 
2512 #ifdef _WIN32
TEST_IMPL(fs_non_symlink_reparse_point)2513 TEST_IMPL(fs_non_symlink_reparse_point) {
2514   uv_fs_t req;
2515   int r;
2516   HANDLE file_handle;
2517   REPARSE_GUID_DATA_BUFFER reparse_buffer;
2518   DWORD bytes_returned;
2519   uv_dirent_t dent;
2520 
2521   /* set-up */
2522   unlink("test_dir/test_file");
2523   rmdir("test_dir");
2524 
2525   loop = uv_default_loop();
2526 
2527   uv_fs_mkdir(NULL, &req, "test_dir", 0777, NULL);
2528   uv_fs_req_cleanup(&req);
2529 
2530   file_handle = CreateFile("test_dir/test_file",
2531                            GENERIC_WRITE | FILE_WRITE_ATTRIBUTES,
2532                            0,
2533                            NULL,
2534                            CREATE_ALWAYS,
2535                            FILE_FLAG_OPEN_REPARSE_POINT |
2536                              FILE_FLAG_BACKUP_SEMANTICS,
2537                            NULL);
2538   ASSERT_PTR_NE(file_handle, INVALID_HANDLE_VALUE);
2539 
2540   memset(&reparse_buffer, 0, REPARSE_GUID_DATA_BUFFER_HEADER_SIZE);
2541   reparse_buffer.ReparseTag = REPARSE_TAG;
2542   reparse_buffer.ReparseDataLength = 0;
2543   reparse_buffer.ReparseGuid = REPARSE_GUID;
2544 
2545   r = DeviceIoControl(file_handle,
2546                       FSCTL_SET_REPARSE_POINT,
2547                       &reparse_buffer,
2548                       REPARSE_GUID_DATA_BUFFER_HEADER_SIZE,
2549                       NULL,
2550                       0,
2551                       &bytes_returned,
2552                       NULL);
2553   ASSERT(r);
2554 
2555   CloseHandle(file_handle);
2556 
2557   r = uv_fs_readlink(NULL, &req, "test_dir/test_file", NULL);
2558   ASSERT(r == UV_EINVAL && GetLastError() == ERROR_SYMLINK_NOT_SUPPORTED);
2559   uv_fs_req_cleanup(&req);
2560 
2561 /*
2562   Placeholder tests for exercising the behavior fixed in issue #995.
2563   To run, update the path with the IP address of a Mac with the hard drive
2564   shared via SMB as "Macintosh HD".
2565 
2566   r = uv_fs_stat(NULL, &req, "\\\\<mac_ip>\\Macintosh HD\\.DS_Store", NULL);
2567   ASSERT_OK(r);
2568   uv_fs_req_cleanup(&req);
2569 
2570   r = uv_fs_lstat(NULL, &req, "\\\\<mac_ip>\\Macintosh HD\\.DS_Store", NULL);
2571   ASSERT_OK(r);
2572   uv_fs_req_cleanup(&req);
2573 */
2574 
2575 /*
2576   uv_fs_stat and uv_fs_lstat can only work on non-symlink reparse
2577   points when a minifilter driver is registered which intercepts
2578   associated filesystem requests. Installing a driver is beyond
2579   the scope of this test.
2580 
2581   r = uv_fs_stat(NULL, &req, "test_dir/test_file", NULL);
2582   ASSERT_OK(r);
2583   uv_fs_req_cleanup(&req);
2584 
2585   r = uv_fs_lstat(NULL, &req, "test_dir/test_file", NULL);
2586   ASSERT_OK(r);
2587   uv_fs_req_cleanup(&req);
2588 */
2589 
2590   r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL);
2591   ASSERT_EQ(1, r);
2592   ASSERT_EQ(1, scandir_req.result);
2593   ASSERT(scandir_req.ptr);
2594   while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) {
2595     ASSERT_OK(strcmp(dent.name, "test_file"));
2596     /* uv_fs_scandir incorrectly identifies non-symlink reparse points
2597        as links because it doesn't open the file and verify the reparse
2598        point tag. The PowerShell Get-ChildItem command shares this
2599        behavior, so it's reasonable to leave it as is. */
2600     ASSERT_EQ(dent.type, UV_DIRENT_LINK);
2601   }
2602   uv_fs_req_cleanup(&scandir_req);
2603   ASSERT(!scandir_req.ptr);
2604 
2605   /* clean-up */
2606   unlink("test_dir/test_file");
2607   rmdir("test_dir");
2608 
2609   MAKE_VALGRIND_HAPPY(loop);
2610   return 0;
2611 }
2612 
TEST_IMPL(fs_lstat_windows_store_apps)2613 TEST_IMPL(fs_lstat_windows_store_apps) {
2614   uv_loop_t* loop;
2615   char localappdata[MAX_PATH];
2616   char windowsapps_path[MAX_PATH];
2617   char file_path[MAX_PATH];
2618   size_t len;
2619   int r;
2620   uv_fs_t req;
2621   uv_fs_t stat_req;
2622   uv_dirent_t dirent;
2623 
2624   loop = uv_default_loop();
2625   ASSERT_NOT_NULL(loop);
2626   len = sizeof(localappdata);
2627   r = uv_os_getenv("LOCALAPPDATA", localappdata, &len);
2628   if (r == UV_ENOENT) {
2629     MAKE_VALGRIND_HAPPY(loop);
2630     return TEST_SKIP;
2631   }
2632   ASSERT_OK(r);
2633   r = snprintf(windowsapps_path,
2634               sizeof(localappdata),
2635               "%s\\Microsoft\\WindowsApps",
2636               localappdata);
2637   ASSERT_GT(r, 0);
2638   if (uv_fs_opendir(loop, &req, windowsapps_path, NULL) != 0) {
2639     /* If we cannot read the directory, skip the test. */
2640     MAKE_VALGRIND_HAPPY(loop);
2641     return TEST_SKIP;
2642   }
2643   if (uv_fs_scandir(loop, &req, windowsapps_path, 0, NULL) <= 0) {
2644     MAKE_VALGRIND_HAPPY(loop);
2645     return TEST_SKIP;
2646   }
2647   while (uv_fs_scandir_next(&req, &dirent) != UV_EOF) {
2648     if (dirent.type != UV_DIRENT_LINK) {
2649       continue;
2650     }
2651     if (snprintf(file_path,
2652                  sizeof(file_path),
2653                  "%s\\%s",
2654                  windowsapps_path,
2655                  dirent.name) < 0) {
2656       continue;
2657     }
2658     ASSERT_OK(uv_fs_lstat(loop, &stat_req, file_path, NULL));
2659   }
2660   MAKE_VALGRIND_HAPPY(loop);
2661   return 0;
2662 }
2663 #endif
2664 
2665 
TEST_IMPL(fs_utime)2666 TEST_IMPL(fs_utime) {
2667   utime_check_t checkme;
2668   const char* path = "test_file";
2669   double atime;
2670   double mtime;
2671   uv_fs_t req;
2672   int r;
2673 
2674   /* Setup. */
2675   loop = uv_default_loop();
2676   unlink(path);
2677   r = uv_fs_open(NULL, &req, path, UV_FS_O_RDWR | UV_FS_O_CREAT,
2678                  S_IWUSR | S_IRUSR,
2679                  NULL);
2680   ASSERT_GE(r, 0);
2681   ASSERT_GE(req.result, 0);
2682   uv_fs_req_cleanup(&req);
2683   uv_fs_close(loop, &req, r, NULL);
2684 
2685   atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */
2686 
2687   r = uv_fs_utime(NULL, &req, path, atime, mtime, NULL);
2688   ASSERT_OK(r);
2689   ASSERT_OK(req.result);
2690   uv_fs_req_cleanup(&req);
2691 
2692   check_utime(path, atime, mtime, /* test_lutime */ 0);
2693 
2694   atime = mtime = 1291404900.25; /* 2010-12-03 20:35:00.25 - mees <3 */
2695   checkme.path = path;
2696   checkme.atime = atime;
2697   checkme.mtime = mtime;
2698 
2699   /* async utime */
2700   utime_req.data = &checkme;
2701   r = uv_fs_utime(loop, &utime_req, path, atime, mtime, utime_cb);
2702   ASSERT_OK(r);
2703   uv_run(loop, UV_RUN_DEFAULT);
2704   ASSERT_EQ(1, utime_cb_count);
2705 
2706   /* Cleanup. */
2707   unlink(path);
2708 
2709   MAKE_VALGRIND_HAPPY(loop);
2710   return 0;
2711 }
2712 
2713 
TEST_IMPL(fs_utime_round)2714 TEST_IMPL(fs_utime_round) {
2715   const char path[] = "test_file";
2716   double atime;
2717   double mtime;
2718   uv_fs_t req;
2719   int r;
2720 
2721   loop = uv_default_loop();
2722   unlink(path);
2723   r = uv_fs_open(NULL, &req, path, UV_FS_O_RDWR | UV_FS_O_CREAT,
2724                  S_IWUSR | S_IRUSR,
2725                  NULL);
2726   ASSERT_GE(r, 0);
2727   ASSERT_GE(req.result, 0);
2728   uv_fs_req_cleanup(&req);
2729   ASSERT_OK(uv_fs_close(loop, &req, r, NULL));
2730 
2731   atime = mtime = -14245440.25;  /* 1969-07-20T02:56:00.25Z */
2732 
2733   r = uv_fs_utime(NULL, &req, path, atime, mtime, NULL);
2734 #if !defined(__linux__)     && \
2735     !defined(_WIN32)        && \
2736     !defined(__APPLE__)     && \
2737     !defined(__FreeBSD__)   && \
2738     !defined(__sun)
2739   if (r != 0) {
2740     ASSERT_EQ(r, UV_EINVAL);
2741     RETURN_SKIP("utime on some OS (z/OS, IBM i PASE, AIX) or filesystems may reject pre-epoch timestamps");
2742   }
2743 #endif
2744   ASSERT_OK(r);
2745   ASSERT_OK(req.result);
2746   uv_fs_req_cleanup(&req);
2747   check_utime(path, atime, mtime, /* test_lutime */ 0);
2748   unlink(path);
2749 
2750   MAKE_VALGRIND_HAPPY(loop);
2751   return 0;
2752 }
2753 
2754 
2755 #ifdef _WIN32
TEST_IMPL(fs_stat_root)2756 TEST_IMPL(fs_stat_root) {
2757   int r;
2758 
2759   r = uv_fs_stat(NULL, &stat_req, "\\", NULL);
2760   ASSERT_OK(r);
2761 
2762   r = uv_fs_stat(NULL, &stat_req, "..\\..\\..\\..\\..\\..\\..", NULL);
2763   ASSERT_OK(r);
2764 
2765   r = uv_fs_stat(NULL, &stat_req, "..", NULL);
2766   ASSERT_OK(r);
2767 
2768   r = uv_fs_stat(NULL, &stat_req, "..\\", NULL);
2769   ASSERT_OK(r);
2770 
2771   /* stats the current directory on c: */
2772   r = uv_fs_stat(NULL, &stat_req, "c:", NULL);
2773   ASSERT_OK(r);
2774 
2775   r = uv_fs_stat(NULL, &stat_req, "c:\\", NULL);
2776   ASSERT_OK(r);
2777 
2778   r = uv_fs_stat(NULL, &stat_req, "\\\\?\\C:\\", NULL);
2779   ASSERT_OK(r);
2780 
2781   MAKE_VALGRIND_HAPPY(uv_default_loop());
2782   return 0;
2783 }
2784 #endif
2785 
2786 
TEST_IMPL(fs_futime)2787 TEST_IMPL(fs_futime) {
2788   utime_check_t checkme;
2789   const char* path = "test_file";
2790   double atime;
2791   double mtime;
2792   uv_file file;
2793   uv_fs_t req;
2794   int r;
2795 #if defined(_AIX) && !defined(_AIX71)
2796   RETURN_SKIP("futime is not implemented for AIX versions below 7.1");
2797 #endif
2798 
2799   /* Setup. */
2800   loop = uv_default_loop();
2801   unlink(path);
2802   r = uv_fs_open(NULL, &req, path, UV_FS_O_RDWR | UV_FS_O_CREAT,
2803                  S_IWUSR | S_IRUSR,
2804                  NULL);
2805   ASSERT_GE(r, 0);
2806   ASSERT_GE(req.result, 0);
2807   uv_fs_req_cleanup(&req);
2808   uv_fs_close(loop, &req, r, NULL);
2809 
2810   atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */
2811 
2812   r = uv_fs_open(NULL, &req, path, UV_FS_O_RDWR, 0, NULL);
2813   ASSERT_GE(r, 0);
2814   ASSERT_GE(req.result, 0);
2815   file = req.result; /* FIXME probably not how it's supposed to be used */
2816   uv_fs_req_cleanup(&req);
2817 
2818   r = uv_fs_futime(NULL, &req, file, atime, mtime, NULL);
2819 #if defined(__CYGWIN__) || defined(__MSYS__)
2820   ASSERT_EQ(r, UV_ENOSYS);
2821   RETURN_SKIP("futime not supported on Cygwin");
2822 #else
2823   ASSERT_OK(r);
2824   ASSERT_OK(req.result);
2825 #endif
2826   uv_fs_req_cleanup(&req);
2827 
2828   check_utime(path, atime, mtime, /* test_lutime */ 0);
2829 
2830   atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */
2831 
2832   checkme.atime = atime;
2833   checkme.mtime = mtime;
2834   checkme.path = path;
2835 
2836   /* async futime */
2837   futime_req.data = &checkme;
2838   r = uv_fs_futime(loop, &futime_req, file, atime, mtime, futime_cb);
2839   ASSERT_OK(r);
2840   uv_run(loop, UV_RUN_DEFAULT);
2841   ASSERT_EQ(1, futime_cb_count);
2842 
2843   /* Cleanup. */
2844   unlink(path);
2845 
2846   MAKE_VALGRIND_HAPPY(loop);
2847   return 0;
2848 }
2849 
2850 
TEST_IMPL(fs_lutime)2851 TEST_IMPL(fs_lutime) {
2852   utime_check_t checkme;
2853   const char* path = "test_file";
2854   const char* symlink_path = "test_file_symlink";
2855   double atime;
2856   double mtime;
2857   uv_fs_t req;
2858   int r, s;
2859 
2860 
2861   /* Setup */
2862   loop = uv_default_loop();
2863   unlink(path);
2864   r = uv_fs_open(NULL, &req, path, UV_FS_O_RDWR | UV_FS_O_CREAT,
2865                  S_IWUSR | S_IRUSR,
2866                  NULL);
2867   ASSERT_GE(r, 0);
2868   ASSERT_GE(req.result, 0);
2869   uv_fs_req_cleanup(&req);
2870   uv_fs_close(loop, &req, r, NULL);
2871 
2872   unlink(symlink_path);
2873   s = uv_fs_symlink(NULL, &req, path, symlink_path, 0, NULL);
2874 #ifdef _WIN32
2875   if (s == UV_EPERM) {
2876     /*
2877      * Creating a symlink before Windows 10 Creators Update was only allowed
2878      * when running elevated console (with admin rights)
2879      */
2880     RETURN_SKIP(
2881         "Symlink creation requires elevated console (with admin rights)");
2882   }
2883 #endif
2884   ASSERT_OK(s);
2885   ASSERT_OK(req.result);
2886   uv_fs_req_cleanup(&req);
2887 
2888   /* Test the synchronous version. */
2889   atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */
2890 
2891   checkme.atime = atime;
2892   checkme.mtime = mtime;
2893   checkme.path = symlink_path;
2894   req.data = &checkme;
2895 
2896   r = uv_fs_lutime(NULL, &req, symlink_path, atime, mtime, NULL);
2897 #if (defined(_AIX) && !defined(_AIX71)) ||                                    \
2898      defined(__MVS__)
2899   ASSERT_EQ(r, UV_ENOSYS);
2900   RETURN_SKIP("lutime is not implemented for z/OS and AIX versions below 7.1");
2901 #endif
2902   ASSERT_OK(r);
2903   lutime_cb(&req);
2904   ASSERT_EQ(1, lutime_cb_count);
2905 
2906   /* Test the asynchronous version. */
2907   atime = mtime = 1291404900; /* 2010-12-03 20:35:00 */
2908 
2909   checkme.atime = atime;
2910   checkme.mtime = mtime;
2911   checkme.path = symlink_path;
2912 
2913   r = uv_fs_lutime(loop, &req, symlink_path, atime, mtime, lutime_cb);
2914   ASSERT_OK(r);
2915   uv_run(loop, UV_RUN_DEFAULT);
2916   ASSERT_EQ(2, lutime_cb_count);
2917 
2918   /* Cleanup. */
2919   unlink(path);
2920   unlink(symlink_path);
2921 
2922   MAKE_VALGRIND_HAPPY(loop);
2923   return 0;
2924 }
2925 
2926 
TEST_IMPL(fs_stat_missing_path)2927 TEST_IMPL(fs_stat_missing_path) {
2928   uv_fs_t req;
2929   int r;
2930 
2931   loop = uv_default_loop();
2932 
2933   r = uv_fs_stat(NULL, &req, "non_existent_file", NULL);
2934   ASSERT_EQ(r, UV_ENOENT);
2935   ASSERT_EQ(req.result, UV_ENOENT);
2936   uv_fs_req_cleanup(&req);
2937 
2938   MAKE_VALGRIND_HAPPY(loop);
2939   return 0;
2940 }
2941 
2942 
TEST_IMPL(fs_scandir_empty_dir)2943 TEST_IMPL(fs_scandir_empty_dir) {
2944   const char* path;
2945   uv_fs_t req;
2946   uv_dirent_t dent;
2947   int r;
2948 
2949   path = "./empty_dir/";
2950   loop = uv_default_loop();
2951 
2952   uv_fs_mkdir(NULL, &req, path, 0777, NULL);
2953   uv_fs_req_cleanup(&req);
2954 
2955   /* Fill the req to ensure that required fields are cleaned up */
2956   memset(&req, 0xdb, sizeof(req));
2957 
2958   r = uv_fs_scandir(NULL, &req, path, 0, NULL);
2959   ASSERT_OK(r);
2960   ASSERT_OK(req.result);
2961   ASSERT_NULL(req.ptr);
2962   ASSERT_EQ(UV_EOF, uv_fs_scandir_next(&req, &dent));
2963   uv_fs_req_cleanup(&req);
2964 
2965   r = uv_fs_scandir(loop, &scandir_req, path, 0, empty_scandir_cb);
2966   ASSERT_OK(r);
2967 
2968   ASSERT_OK(scandir_cb_count);
2969   uv_run(loop, UV_RUN_DEFAULT);
2970   ASSERT_EQ(1, scandir_cb_count);
2971 
2972   uv_fs_rmdir(NULL, &req, path, NULL);
2973   uv_fs_req_cleanup(&req);
2974 
2975   MAKE_VALGRIND_HAPPY(loop);
2976   return 0;
2977 }
2978 
2979 
TEST_IMPL(fs_scandir_non_existent_dir)2980 TEST_IMPL(fs_scandir_non_existent_dir) {
2981   const char* path;
2982   uv_fs_t req;
2983   uv_dirent_t dent;
2984   int r;
2985 
2986   path = "./non_existent_dir/";
2987   loop = uv_default_loop();
2988 
2989   uv_fs_rmdir(NULL, &req, path, NULL);
2990   uv_fs_req_cleanup(&req);
2991 
2992   /* Fill the req to ensure that required fields are cleaned up */
2993   memset(&req, 0xdb, sizeof(req));
2994 
2995   r = uv_fs_scandir(NULL, &req, path, 0, NULL);
2996   ASSERT_EQ(r, UV_ENOENT);
2997   ASSERT_EQ(req.result, UV_ENOENT);
2998   ASSERT_NULL(req.ptr);
2999   ASSERT_EQ(UV_ENOENT, uv_fs_scandir_next(&req, &dent));
3000   uv_fs_req_cleanup(&req);
3001 
3002   r = uv_fs_scandir(loop, &scandir_req, path, 0, non_existent_scandir_cb);
3003   ASSERT_OK(r);
3004 
3005   ASSERT_OK(scandir_cb_count);
3006   uv_run(loop, UV_RUN_DEFAULT);
3007   ASSERT_EQ(1, scandir_cb_count);
3008 
3009   MAKE_VALGRIND_HAPPY(loop);
3010   return 0;
3011 }
3012 
TEST_IMPL(fs_scandir_file)3013 TEST_IMPL(fs_scandir_file) {
3014   const char* path;
3015   int r;
3016 
3017   path = "test/fixtures/empty_file";
3018   loop = uv_default_loop();
3019 
3020   r = uv_fs_scandir(NULL, &scandir_req, path, 0, NULL);
3021   ASSERT_EQ(r, UV_ENOTDIR);
3022   uv_fs_req_cleanup(&scandir_req);
3023 
3024   r = uv_fs_scandir(loop, &scandir_req, path, 0, file_scandir_cb);
3025   ASSERT_OK(r);
3026 
3027   ASSERT_OK(scandir_cb_count);
3028   uv_run(loop, UV_RUN_DEFAULT);
3029   ASSERT_EQ(1, scandir_cb_count);
3030 
3031   MAKE_VALGRIND_HAPPY(loop);
3032   return 0;
3033 }
3034 
3035 
3036 /* Run in Valgrind. Should not leak when the iterator isn't exhausted. */
TEST_IMPL(fs_scandir_early_exit)3037 TEST_IMPL(fs_scandir_early_exit) {
3038   uv_dirent_t d;
3039   uv_fs_t req;
3040 
3041   ASSERT_LT(0, uv_fs_scandir(NULL, &req, "test/fixtures/one_file", 0, NULL));
3042   ASSERT_NE(UV_EOF, uv_fs_scandir_next(&req, &d));
3043   uv_fs_req_cleanup(&req);
3044 
3045   ASSERT_LT(0, uv_fs_scandir(NULL, &req, "test/fixtures", 0, NULL));
3046   ASSERT_NE(UV_EOF, uv_fs_scandir_next(&req, &d));
3047   uv_fs_req_cleanup(&req);
3048 
3049   MAKE_VALGRIND_HAPPY(uv_default_loop());
3050   return 0;
3051 }
3052 
3053 
TEST_IMPL(fs_open_dir)3054 TEST_IMPL(fs_open_dir) {
3055   const char* path;
3056   uv_fs_t req;
3057   int r, file;
3058 
3059   path = ".";
3060   loop = uv_default_loop();
3061 
3062   r = uv_fs_open(NULL, &req, path, UV_FS_O_RDONLY, 0, NULL);
3063   ASSERT_GE(r, 0);
3064   ASSERT_GE(req.result, 0);
3065   ASSERT_NULL(req.ptr);
3066   file = r;
3067   uv_fs_req_cleanup(&req);
3068 
3069   r = uv_fs_close(NULL, &req, file, NULL);
3070   ASSERT_OK(r);
3071 
3072   r = uv_fs_open(loop, &req, path, UV_FS_O_RDONLY, 0, open_cb_simple);
3073   ASSERT_OK(r);
3074 
3075   ASSERT_OK(open_cb_count);
3076   uv_run(loop, UV_RUN_DEFAULT);
3077   ASSERT_EQ(1, open_cb_count);
3078 
3079   MAKE_VALGRIND_HAPPY(loop);
3080   return 0;
3081 }
3082 
3083 
fs_file_open_append(int add_flags)3084 static void fs_file_open_append(int add_flags) {
3085   int r;
3086 
3087   /* Setup. */
3088   unlink("test_file");
3089 
3090   loop = uv_default_loop();
3091 
3092   r = uv_fs_open(NULL, &open_req1, "test_file",
3093                  UV_FS_O_WRONLY | UV_FS_O_CREAT | add_flags, S_IWUSR | S_IRUSR,
3094                  NULL);
3095   ASSERT_GE(r, 0);
3096   ASSERT_GE(open_req1.result, 0);
3097   uv_fs_req_cleanup(&open_req1);
3098 
3099   iov = uv_buf_init(test_buf, sizeof(test_buf));
3100   r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
3101   ASSERT_GE(r, 0);
3102   ASSERT_GE(write_req.result, 0);
3103   uv_fs_req_cleanup(&write_req);
3104 
3105   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3106   ASSERT_OK(r);
3107   ASSERT_OK(close_req.result);
3108   uv_fs_req_cleanup(&close_req);
3109 
3110   r = uv_fs_open(NULL, &open_req1, "test_file",
3111                  UV_FS_O_RDWR | UV_FS_O_APPEND | add_flags, 0, NULL);
3112   ASSERT_GE(r, 0);
3113   ASSERT_GE(open_req1.result, 0);
3114   uv_fs_req_cleanup(&open_req1);
3115 
3116   iov = uv_buf_init(test_buf, sizeof(test_buf));
3117   r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
3118   ASSERT_GE(r, 0);
3119   ASSERT_GE(write_req.result, 0);
3120   uv_fs_req_cleanup(&write_req);
3121 
3122   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3123   ASSERT_OK(r);
3124   ASSERT_OK(close_req.result);
3125   uv_fs_req_cleanup(&close_req);
3126 
3127   r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDONLY | add_flags,
3128       S_IRUSR, NULL);
3129   ASSERT_GE(r, 0);
3130   ASSERT_GE(open_req1.result, 0);
3131   uv_fs_req_cleanup(&open_req1);
3132 
3133   iov = uv_buf_init(buf, sizeof(buf));
3134   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
3135   printf("read = %d\n", r);
3136   ASSERT_EQ(26, r);
3137   ASSERT_EQ(26, read_req.result);
3138   ASSERT_OK(memcmp(buf,
3139                    "test-buffer\n\0test-buffer\n\0",
3140                    sizeof("test-buffer\n\0test-buffer\n\0") - 1));
3141   uv_fs_req_cleanup(&read_req);
3142 
3143   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3144   ASSERT_OK(r);
3145   ASSERT_OK(close_req.result);
3146   uv_fs_req_cleanup(&close_req);
3147 
3148   /* Cleanup */
3149   unlink("test_file");
3150 }
TEST_IMPL(fs_file_open_append)3151 TEST_IMPL(fs_file_open_append) {
3152   fs_file_open_append(0);
3153   fs_file_open_append(UV_FS_O_FILEMAP);
3154 
3155   MAKE_VALGRIND_HAPPY(uv_default_loop());
3156   return 0;
3157 }
3158 
3159 
TEST_IMPL(fs_rename_to_existing_file)3160 TEST_IMPL(fs_rename_to_existing_file) {
3161   int r;
3162 
3163   /* Setup. */
3164   unlink("test_file");
3165   unlink("test_file2");
3166 
3167   loop = uv_default_loop();
3168 
3169   r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_WRONLY | UV_FS_O_CREAT,
3170       S_IWUSR | S_IRUSR, NULL);
3171   ASSERT_GE(r, 0);
3172   ASSERT_GE(open_req1.result, 0);
3173   uv_fs_req_cleanup(&open_req1);
3174 
3175   iov = uv_buf_init(test_buf, sizeof(test_buf));
3176   r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
3177   ASSERT_GE(r, 0);
3178   ASSERT_GE(write_req.result, 0);
3179   uv_fs_req_cleanup(&write_req);
3180 
3181   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3182   ASSERT_OK(r);
3183   ASSERT_OK(close_req.result);
3184   uv_fs_req_cleanup(&close_req);
3185 
3186   r = uv_fs_open(NULL, &open_req1, "test_file2", UV_FS_O_WRONLY | UV_FS_O_CREAT,
3187       S_IWUSR | S_IRUSR, NULL);
3188   ASSERT_GE(r, 0);
3189   ASSERT_GE(open_req1.result, 0);
3190   uv_fs_req_cleanup(&open_req1);
3191 
3192   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3193   ASSERT_OK(r);
3194   ASSERT_OK(close_req.result);
3195   uv_fs_req_cleanup(&close_req);
3196 
3197   r = uv_fs_rename(NULL, &rename_req, "test_file", "test_file2", NULL);
3198   ASSERT_OK(r);
3199   ASSERT_OK(rename_req.result);
3200   uv_fs_req_cleanup(&rename_req);
3201 
3202   r = uv_fs_open(NULL, &open_req1, "test_file2", UV_FS_O_RDONLY, 0, NULL);
3203   ASSERT_GE(r, 0);
3204   ASSERT_GE(open_req1.result, 0);
3205   uv_fs_req_cleanup(&open_req1);
3206 
3207   memset(buf, 0, sizeof(buf));
3208   iov = uv_buf_init(buf, sizeof(buf));
3209   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
3210   ASSERT_GE(r, 0);
3211   ASSERT_GE(read_req.result, 0);
3212   ASSERT_OK(strcmp(buf, test_buf));
3213   uv_fs_req_cleanup(&read_req);
3214 
3215   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3216   ASSERT_OK(r);
3217   ASSERT_OK(close_req.result);
3218   uv_fs_req_cleanup(&close_req);
3219 
3220   /* Cleanup */
3221   unlink("test_file");
3222   unlink("test_file2");
3223 
3224   MAKE_VALGRIND_HAPPY(loop);
3225   return 0;
3226 }
3227 
3228 
fs_read_bufs(int add_flags)3229 static void fs_read_bufs(int add_flags) {
3230   char scratch[768];
3231   uv_buf_t bufs[4];
3232 
3233   ASSERT_LE(0, uv_fs_open(NULL, &open_req1,
3234                           "test/fixtures/lorem_ipsum.txt",
3235                           UV_FS_O_RDONLY | add_flags, 0, NULL));
3236   ASSERT_GE(open_req1.result, 0);
3237   uv_fs_req_cleanup(&open_req1);
3238 
3239   ASSERT_EQ(UV_EINVAL, uv_fs_read(NULL, &read_req, open_req1.result,
3240                                   NULL, 0, 0, NULL));
3241   ASSERT_EQ(UV_EINVAL, uv_fs_read(NULL, &read_req, open_req1.result,
3242                                   NULL, 1, 0, NULL));
3243   ASSERT_EQ(UV_EINVAL, uv_fs_read(NULL, &read_req, open_req1.result,
3244                                   bufs, 0, 0, NULL));
3245 
3246   bufs[0] = uv_buf_init(scratch + 0, 256);
3247   bufs[1] = uv_buf_init(scratch + 256, 256);
3248   bufs[2] = uv_buf_init(scratch + 512, 128);
3249   bufs[3] = uv_buf_init(scratch + 640, 128);
3250 
3251   ASSERT_EQ(446, uv_fs_read(NULL,
3252                             &read_req,
3253                             open_req1.result,
3254                             bufs + 0,
3255                             2,  /* 2x 256 bytes. */
3256                             0,  /* Positional read. */
3257                             NULL));
3258   ASSERT_EQ(446, read_req.result);
3259   uv_fs_req_cleanup(&read_req);
3260 
3261   ASSERT_EQ(190, uv_fs_read(NULL,
3262                             &read_req,
3263                             open_req1.result,
3264                             bufs + 2,
3265                             2,  /* 2x 128 bytes. */
3266                             256,  /* Positional read. */
3267                             NULL));
3268   ASSERT_EQ(read_req.result, /* 446 - 256 */ 190);
3269   uv_fs_req_cleanup(&read_req);
3270 
3271   ASSERT_OK(memcmp(bufs[1].base + 0, bufs[2].base, 128));
3272   ASSERT_OK(memcmp(bufs[1].base + 128, bufs[3].base, 190 - 128));
3273 
3274   ASSERT_OK(uv_fs_close(NULL, &close_req, open_req1.result, NULL));
3275   ASSERT_OK(close_req.result);
3276   uv_fs_req_cleanup(&close_req);
3277 }
TEST_IMPL(fs_read_bufs)3278 TEST_IMPL(fs_read_bufs) {
3279   fs_read_bufs(0);
3280   fs_read_bufs(UV_FS_O_FILEMAP);
3281 
3282   MAKE_VALGRIND_HAPPY(uv_default_loop());
3283   return 0;
3284 }
3285 
3286 
fs_read_file_eof(int add_flags)3287 static void fs_read_file_eof(int add_flags) {
3288 #if defined(__CYGWIN__) || defined(__MSYS__)
3289   RETURN_SKIP("Cygwin pread at EOF may (incorrectly) return data!");
3290 #endif
3291   int r;
3292 
3293   /* Setup. */
3294   unlink("test_file");
3295 
3296   loop = uv_default_loop();
3297 
3298   r = uv_fs_open(NULL, &open_req1, "test_file",
3299                  UV_FS_O_WRONLY | UV_FS_O_CREAT | add_flags, S_IWUSR | S_IRUSR,
3300                  NULL);
3301   ASSERT_GE(r, 0);
3302   ASSERT_GE(open_req1.result, 0);
3303   uv_fs_req_cleanup(&open_req1);
3304 
3305   iov = uv_buf_init(test_buf, sizeof(test_buf));
3306   r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
3307   ASSERT_GE(r, 0);
3308   ASSERT_GE(write_req.result, 0);
3309   uv_fs_req_cleanup(&write_req);
3310 
3311   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3312   ASSERT_OK(r);
3313   ASSERT_OK(close_req.result);
3314   uv_fs_req_cleanup(&close_req);
3315 
3316   r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDONLY | add_flags, 0,
3317       NULL);
3318   ASSERT_GE(r, 0);
3319   ASSERT_GE(open_req1.result, 0);
3320   uv_fs_req_cleanup(&open_req1);
3321 
3322   memset(buf, 0, sizeof(buf));
3323   iov = uv_buf_init(buf, sizeof(buf));
3324   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
3325   ASSERT_GE(r, 0);
3326   ASSERT_GE(read_req.result, 0);
3327   ASSERT_OK(strcmp(buf, test_buf));
3328   uv_fs_req_cleanup(&read_req);
3329 
3330   iov = uv_buf_init(buf, sizeof(buf));
3331   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1,
3332                  read_req.result, NULL);
3333   ASSERT_OK(r);
3334   ASSERT_OK(read_req.result);
3335   uv_fs_req_cleanup(&read_req);
3336 
3337   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3338   ASSERT_OK(r);
3339   ASSERT_OK(close_req.result);
3340   uv_fs_req_cleanup(&close_req);
3341 
3342   /* Cleanup */
3343   unlink("test_file");
3344 }
TEST_IMPL(fs_read_file_eof)3345 TEST_IMPL(fs_read_file_eof) {
3346   fs_read_file_eof(0);
3347   fs_read_file_eof(UV_FS_O_FILEMAP);
3348 
3349   MAKE_VALGRIND_HAPPY(uv_default_loop());
3350   return 0;
3351 }
3352 
3353 
fs_write_multiple_bufs(int add_flags)3354 static void fs_write_multiple_bufs(int add_flags) {
3355   uv_buf_t iovs[2];
3356   int r;
3357 
3358   /* Setup. */
3359   unlink("test_file");
3360 
3361   loop = uv_default_loop();
3362 
3363   r = uv_fs_open(NULL, &open_req1, "test_file",
3364                  UV_FS_O_WRONLY | UV_FS_O_CREAT | add_flags, S_IWUSR | S_IRUSR,
3365                  NULL);
3366   ASSERT_GE(r, 0);
3367   ASSERT_GE(open_req1.result, 0);
3368   uv_fs_req_cleanup(&open_req1);
3369 
3370   iovs[0] = uv_buf_init(test_buf, sizeof(test_buf));
3371   iovs[1] = uv_buf_init(test_buf2, sizeof(test_buf2));
3372   r = uv_fs_write(NULL, &write_req, open_req1.result, iovs, 2, 0, NULL);
3373   ASSERT_GE(r, 0);
3374   ASSERT_GE(write_req.result, 0);
3375   uv_fs_req_cleanup(&write_req);
3376 
3377   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3378   ASSERT_OK(r);
3379   ASSERT_OK(close_req.result);
3380   uv_fs_req_cleanup(&close_req);
3381 
3382   r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDONLY | add_flags, 0,
3383       NULL);
3384   ASSERT_GE(r, 0);
3385   ASSERT_GE(open_req1.result, 0);
3386   uv_fs_req_cleanup(&open_req1);
3387 
3388   memset(buf, 0, sizeof(buf));
3389   memset(buf2, 0, sizeof(buf2));
3390   /* Read the strings back to separate buffers. */
3391   iovs[0] = uv_buf_init(buf, sizeof(test_buf));
3392   iovs[1] = uv_buf_init(buf2, sizeof(test_buf2));
3393   ASSERT_OK(lseek(open_req1.result, 0, SEEK_CUR));
3394   r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, 2, -1, NULL);
3395   ASSERT_GE(r, 0);
3396   ASSERT_EQ(read_req.result, sizeof(test_buf) + sizeof(test_buf2));
3397   ASSERT_OK(strcmp(buf, test_buf));
3398   ASSERT_OK(strcmp(buf2, test_buf2));
3399   uv_fs_req_cleanup(&read_req);
3400 
3401   iov = uv_buf_init(buf, sizeof(buf));
3402   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
3403   ASSERT_OK(r);
3404   ASSERT_OK(read_req.result);
3405   uv_fs_req_cleanup(&read_req);
3406 
3407   /* Read the strings back to separate buffers. */
3408   iovs[0] = uv_buf_init(buf, sizeof(test_buf));
3409   iovs[1] = uv_buf_init(buf2, sizeof(test_buf2));
3410   r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, 2, 0, NULL);
3411   ASSERT_GE(r, 0);
3412   if (read_req.result == sizeof(test_buf)) {
3413     /* Infer that preadv is not available. */
3414     uv_fs_req_cleanup(&read_req);
3415     r = uv_fs_read(NULL, &read_req, open_req1.result, &iovs[1], 1, read_req.result, NULL);
3416     ASSERT_GE(r, 0);
3417     ASSERT_EQ(read_req.result, sizeof(test_buf2));
3418   } else {
3419     ASSERT_EQ(read_req.result, sizeof(test_buf) + sizeof(test_buf2));
3420   }
3421   ASSERT_OK(strcmp(buf, test_buf));
3422   ASSERT_OK(strcmp(buf2, test_buf2));
3423   uv_fs_req_cleanup(&read_req);
3424 
3425   iov = uv_buf_init(buf, sizeof(buf));
3426   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1,
3427                  sizeof(test_buf) + sizeof(test_buf2), NULL);
3428   ASSERT_OK(r);
3429   ASSERT_OK(read_req.result);
3430   uv_fs_req_cleanup(&read_req);
3431 
3432   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3433   ASSERT_OK(r);
3434   ASSERT_OK(close_req.result);
3435   uv_fs_req_cleanup(&close_req);
3436 
3437   /* Cleanup */
3438   unlink("test_file");
3439 }
TEST_IMPL(fs_write_multiple_bufs)3440 TEST_IMPL(fs_write_multiple_bufs) {
3441   fs_write_multiple_bufs(0);
3442   fs_write_multiple_bufs(UV_FS_O_FILEMAP);
3443 
3444   MAKE_VALGRIND_HAPPY(uv_default_loop());
3445   return 0;
3446 }
3447 
3448 
fs_write_alotof_bufs(int add_flags)3449 static void fs_write_alotof_bufs(int add_flags) {
3450   size_t iovcount;
3451   size_t iovmax;
3452   uv_buf_t* iovs;
3453   char* buffer;
3454   size_t index;
3455   int r;
3456 
3457   iovcount = 54321;
3458 
3459   /* Setup. */
3460   unlink("test_file");
3461 
3462   loop = uv_default_loop();
3463 
3464   iovs = malloc(sizeof(*iovs) * iovcount);
3465   ASSERT_NOT_NULL(iovs);
3466   iovmax = uv_test_getiovmax();
3467 
3468   r = uv_fs_open(NULL,
3469                  &open_req1,
3470                  "test_file",
3471                  UV_FS_O_RDWR | UV_FS_O_CREAT | add_flags,
3472                  S_IWUSR | S_IRUSR,
3473                  NULL);
3474   ASSERT_GE(r, 0);
3475   ASSERT_GE(open_req1.result, 0);
3476   uv_fs_req_cleanup(&open_req1);
3477 
3478   for (index = 0; index < iovcount; ++index)
3479     iovs[index] = uv_buf_init(test_buf, sizeof(test_buf));
3480 
3481   r = uv_fs_write(NULL,
3482                   &write_req,
3483                   open_req1.result,
3484                   iovs,
3485                   iovcount,
3486                   -1,
3487                   NULL);
3488   ASSERT_GE(r, 0);
3489   ASSERT_EQ((size_t)write_req.result, sizeof(test_buf) * iovcount);
3490   uv_fs_req_cleanup(&write_req);
3491 
3492   /* Read the strings back to separate buffers. */
3493   buffer = malloc(sizeof(test_buf) * iovcount);
3494   ASSERT_NOT_NULL(buffer);
3495 
3496   for (index = 0; index < iovcount; ++index)
3497     iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf),
3498                               sizeof(test_buf));
3499 
3500   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3501   ASSERT_OK(r);
3502   ASSERT_OK(close_req.result);
3503   uv_fs_req_cleanup(&close_req);
3504 
3505   r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDONLY | add_flags, 0,
3506     NULL);
3507   ASSERT_GE(r, 0);
3508   ASSERT_GE(open_req1.result, 0);
3509   uv_fs_req_cleanup(&open_req1);
3510 
3511   r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, iovcount, -1, NULL);
3512   if (iovcount > iovmax)
3513     iovcount = iovmax;
3514   ASSERT_GE(r, 0);
3515   ASSERT_EQ((size_t)read_req.result, sizeof(test_buf) * iovcount);
3516 
3517   for (index = 0; index < iovcount; ++index)
3518     ASSERT_OK(strncmp(buffer + index * sizeof(test_buf),
3519                       test_buf,
3520                       sizeof(test_buf)));
3521 
3522   uv_fs_req_cleanup(&read_req);
3523   free(buffer);
3524 
3525   ASSERT_EQ(lseek(open_req1.result, write_req.result, SEEK_SET),
3526             write_req.result);
3527   iov = uv_buf_init(buf, sizeof(buf));
3528   r = uv_fs_read(NULL,
3529                  &read_req,
3530                  open_req1.result,
3531                  &iov,
3532                  1,
3533                  -1,
3534                  NULL);
3535   ASSERT_OK(r);
3536   ASSERT_OK(read_req.result);
3537   uv_fs_req_cleanup(&read_req);
3538 
3539   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3540   ASSERT_OK(r);
3541   ASSERT_OK(close_req.result);
3542   uv_fs_req_cleanup(&close_req);
3543 
3544   /* Cleanup */
3545   unlink("test_file");
3546   free(iovs);
3547 }
TEST_IMPL(fs_write_alotof_bufs)3548 TEST_IMPL(fs_write_alotof_bufs) {
3549   fs_write_alotof_bufs(0);
3550   fs_write_alotof_bufs(UV_FS_O_FILEMAP);
3551 
3552   MAKE_VALGRIND_HAPPY(uv_default_loop());
3553   return 0;
3554 }
3555 
3556 
fs_write_alotof_bufs_with_offset(int add_flags)3557 static void fs_write_alotof_bufs_with_offset(int add_flags) {
3558   size_t iovcount;
3559   size_t iovmax;
3560   uv_buf_t* iovs;
3561   char* buffer;
3562   size_t index;
3563   int r;
3564   int64_t offset;
3565   char* filler;
3566   int filler_len;
3567 
3568   filler = "0123456789";
3569   filler_len = strlen(filler);
3570   iovcount = 54321;
3571 
3572   /* Setup. */
3573   unlink("test_file");
3574 
3575   loop = uv_default_loop();
3576 
3577   iovs = malloc(sizeof(*iovs) * iovcount);
3578   ASSERT_NOT_NULL(iovs);
3579   iovmax = uv_test_getiovmax();
3580 
3581   r = uv_fs_open(NULL,
3582                  &open_req1,
3583                  "test_file",
3584                  UV_FS_O_RDWR | UV_FS_O_CREAT | add_flags,
3585                  S_IWUSR | S_IRUSR,
3586                  NULL);
3587   ASSERT_GE(r, 0);
3588   ASSERT_GE(open_req1.result, 0);
3589   uv_fs_req_cleanup(&open_req1);
3590 
3591   iov = uv_buf_init(filler, filler_len);
3592   r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
3593   ASSERT_EQ(r, filler_len);
3594   ASSERT_EQ(write_req.result, filler_len);
3595   uv_fs_req_cleanup(&write_req);
3596   offset = (int64_t)r;
3597 
3598   for (index = 0; index < iovcount; ++index)
3599     iovs[index] = uv_buf_init(test_buf, sizeof(test_buf));
3600 
3601   r = uv_fs_write(NULL,
3602                   &write_req,
3603                   open_req1.result,
3604                   iovs,
3605                   iovcount,
3606                   offset,
3607                   NULL);
3608   ASSERT_GE(r, 0);
3609   ASSERT_EQ((size_t)write_req.result, sizeof(test_buf) * iovcount);
3610   uv_fs_req_cleanup(&write_req);
3611 
3612   /* Read the strings back to separate buffers. */
3613   buffer = malloc(sizeof(test_buf) * iovcount);
3614   ASSERT_NOT_NULL(buffer);
3615 
3616   for (index = 0; index < iovcount; ++index)
3617     iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf),
3618                               sizeof(test_buf));
3619 
3620   r = uv_fs_read(NULL, &read_req, open_req1.result,
3621                  iovs, iovcount, offset, NULL);
3622   ASSERT_GE(r, 0);
3623   if (r == sizeof(test_buf))
3624     iovcount = 1; /* Infer that preadv is not available. */
3625   else if (iovcount > iovmax)
3626     iovcount = iovmax;
3627   ASSERT_EQ((size_t)read_req.result, sizeof(test_buf) * iovcount);
3628 
3629   for (index = 0; index < iovcount; ++index)
3630     ASSERT_OK(strncmp(buffer + index * sizeof(test_buf),
3631                       test_buf,
3632                       sizeof(test_buf)));
3633 
3634   uv_fs_req_cleanup(&read_req);
3635   free(buffer);
3636 
3637   r = uv_fs_stat(NULL, &stat_req, "test_file", NULL);
3638   ASSERT_OK(r);
3639   ASSERT_EQ((int64_t)((uv_stat_t*)stat_req.ptr)->st_size,
3640             offset + (int64_t)write_req.result);
3641   uv_fs_req_cleanup(&stat_req);
3642 
3643   iov = uv_buf_init(buf, sizeof(buf));
3644   r = uv_fs_read(NULL,
3645                  &read_req,
3646                  open_req1.result,
3647                  &iov,
3648                  1,
3649                  offset + write_req.result,
3650                  NULL);
3651   ASSERT_OK(r);
3652   ASSERT_OK(read_req.result);
3653   uv_fs_req_cleanup(&read_req);
3654 
3655   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3656   ASSERT_OK(r);
3657   ASSERT_OK(close_req.result);
3658   uv_fs_req_cleanup(&close_req);
3659 
3660   /* Cleanup */
3661   unlink("test_file");
3662   free(iovs);
3663 }
TEST_IMPL(fs_write_alotof_bufs_with_offset)3664 TEST_IMPL(fs_write_alotof_bufs_with_offset) {
3665   fs_write_alotof_bufs_with_offset(0);
3666   fs_write_alotof_bufs_with_offset(UV_FS_O_FILEMAP);
3667 
3668   MAKE_VALGRIND_HAPPY(uv_default_loop());
3669   return 0;
3670 }
3671 
TEST_IMPL(fs_read_dir)3672 TEST_IMPL(fs_read_dir) {
3673   int r;
3674   char buf[2];
3675   loop = uv_default_loop();
3676 
3677   /* Setup */
3678   rmdir("test_dir");
3679   r = uv_fs_mkdir(loop, &mkdir_req, "test_dir", 0755, mkdir_cb);
3680   ASSERT_OK(r);
3681   uv_run(loop, UV_RUN_DEFAULT);
3682   ASSERT_EQ(1, mkdir_cb_count);
3683   /* Setup Done Here */
3684 
3685   /* Get a file descriptor for the directory */
3686   r = uv_fs_open(loop,
3687                  &open_req1,
3688                  "test_dir",
3689                  UV_FS_O_RDONLY | UV_FS_O_DIRECTORY,
3690                  S_IWUSR | S_IRUSR,
3691                  NULL);
3692   ASSERT_GE(r, 0);
3693   uv_fs_req_cleanup(&open_req1);
3694 
3695   /* Try to read data from the directory */
3696   iov = uv_buf_init(buf, sizeof(buf));
3697   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, 0, NULL);
3698 #if defined(__FreeBSD__)   || \
3699     defined(__OpenBSD__)   || \
3700     defined(__NetBSD__)    || \
3701     defined(__DragonFly__) || \
3702     defined(_AIX)          || \
3703     defined(__sun)         || \
3704     defined(__MVS__)
3705   /*
3706    * As of now, these operating systems support reading from a directory,
3707    * that too depends on the filesystem this temporary test directory is
3708    * created on. That is why this assertion is a bit lenient.
3709    */
3710   ASSERT((r >= 0) || (r == UV_EISDIR));
3711 #else
3712   ASSERT_EQ(r, UV_EISDIR);
3713 #endif
3714   uv_fs_req_cleanup(&read_req);
3715 
3716   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3717   ASSERT_OK(r);
3718   uv_fs_req_cleanup(&close_req);
3719 
3720   /* Cleanup */
3721   rmdir("test_dir");
3722 
3723   MAKE_VALGRIND_HAPPY(loop);
3724   return 0;
3725 }
3726 
3727 #ifdef _WIN32
3728 
TEST_IMPL(fs_partial_read)3729 TEST_IMPL(fs_partial_read) {
3730   RETURN_SKIP("Test not implemented on Windows.");
3731 }
3732 
TEST_IMPL(fs_partial_write)3733 TEST_IMPL(fs_partial_write) {
3734   RETURN_SKIP("Test not implemented on Windows.");
3735 }
3736 
3737 #else  /* !_WIN32 */
3738 
3739 struct thread_ctx {
3740   pthread_t pid;
3741   int fd;
3742   char* data;
3743   int size;
3744   int interval;
3745   int doread;
3746 };
3747 
thread_main(void * arg)3748 static void thread_main(void* arg) {
3749   const struct thread_ctx* ctx;
3750   int size;
3751   char* data;
3752 
3753   ctx = (struct thread_ctx*)arg;
3754   size = ctx->size;
3755   data = ctx->data;
3756 
3757   while (size > 0) {
3758     ssize_t result;
3759     int nbytes;
3760     nbytes = size < ctx->interval ? size : ctx->interval;
3761     if (ctx->doread) {
3762       result = write(ctx->fd, data, nbytes);
3763       /* Should not see EINTR (or other errors) */
3764       ASSERT_EQ(result, nbytes);
3765     } else {
3766       result = read(ctx->fd, data, nbytes);
3767       /* Should not see EINTR (or other errors),
3768        * but might get a partial read if we are faster than the writer
3769        */
3770       ASSERT(result > 0 && result <= nbytes);
3771     }
3772 
3773     pthread_kill(ctx->pid, SIGUSR1);
3774     size -= result;
3775     data += result;
3776   }
3777 }
3778 
sig_func(uv_signal_t * handle,int signum)3779 static void sig_func(uv_signal_t* handle, int signum) {
3780   uv_signal_stop(handle);
3781 }
3782 
uv_test_fs_buf_offset(uv_buf_t * bufs,size_t size)3783 static size_t uv_test_fs_buf_offset(uv_buf_t* bufs, size_t size) {
3784   size_t offset;
3785   /* Figure out which bufs are done */
3786   for (offset = 0; size > 0 && bufs[offset].len <= size; ++offset)
3787     size -= bufs[offset].len;
3788 
3789   /* Fix a partial read/write */
3790   if (size > 0) {
3791     bufs[offset].base += size;
3792     bufs[offset].len -= size;
3793   }
3794   return offset;
3795 }
3796 
test_fs_partial(int doread)3797 static void test_fs_partial(int doread) {
3798   struct thread_ctx ctx;
3799   uv_thread_t thread;
3800   uv_signal_t signal;
3801   int pipe_fds[2];
3802   size_t iovcount;
3803   uv_buf_t* iovs;
3804   char* buffer;
3805   size_t index;
3806 
3807   iovcount = 54321;
3808 
3809   iovs = malloc(sizeof(*iovs) * iovcount);
3810   ASSERT_NOT_NULL(iovs);
3811 
3812   ctx.pid = pthread_self();
3813   ctx.doread = doread;
3814   ctx.interval = 1000;
3815   ctx.size = sizeof(test_buf) * iovcount;
3816   ctx.data = calloc(ctx.size, 1);
3817   ASSERT_NOT_NULL(ctx.data);
3818   buffer = calloc(ctx.size, 1);
3819   ASSERT_NOT_NULL(buffer);
3820 
3821   for (index = 0; index < iovcount; ++index)
3822     iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf), sizeof(test_buf));
3823 
3824   loop = uv_default_loop();
3825 
3826   ASSERT_OK(uv_signal_init(loop, &signal));
3827   ASSERT_OK(uv_signal_start(&signal, sig_func, SIGUSR1));
3828 
3829   ASSERT_OK(pipe(pipe_fds));
3830 
3831   ctx.fd = pipe_fds[doread];
3832   ASSERT_OK(uv_thread_create(&thread, thread_main, &ctx));
3833 
3834   if (doread) {
3835     uv_buf_t* read_iovs;
3836     int nread;
3837     read_iovs = iovs;
3838     nread = 0;
3839     while (nread < ctx.size) {
3840       int result;
3841       result = uv_fs_read(loop, &read_req, pipe_fds[0], read_iovs, iovcount, -1, NULL);
3842       if (result > 0) {
3843         size_t read_iovcount;
3844         read_iovcount = uv_test_fs_buf_offset(read_iovs, result);
3845         read_iovs += read_iovcount;
3846         iovcount -= read_iovcount;
3847         nread += result;
3848       } else {
3849         ASSERT_EQ(result, UV_EINTR);
3850       }
3851       uv_fs_req_cleanup(&read_req);
3852     }
3853   } else {
3854     int result;
3855     result = uv_fs_write(loop, &write_req, pipe_fds[1], iovs, iovcount, -1, NULL);
3856     ASSERT_EQ(write_req.result, result);
3857     ASSERT_EQ(result, ctx.size);
3858     uv_fs_req_cleanup(&write_req);
3859   }
3860 
3861   ASSERT_OK(uv_thread_join(&thread));
3862 
3863   ASSERT_MEM_EQ(buffer, ctx.data, ctx.size);
3864 
3865   ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT));
3866 
3867   ASSERT_OK(close(pipe_fds[1]));
3868   uv_close((uv_handle_t*) &signal, NULL);
3869 
3870   { /* Make sure we read everything that we wrote. */
3871       int result;
3872       result = uv_fs_read(loop, &read_req, pipe_fds[0], iovs, 1, -1, NULL);
3873       ASSERT_OK(result);
3874       uv_fs_req_cleanup(&read_req);
3875   }
3876   ASSERT_OK(close(pipe_fds[0]));
3877 
3878   free(iovs);
3879   free(buffer);
3880   free(ctx.data);
3881 
3882   MAKE_VALGRIND_HAPPY(loop);
3883 }
3884 
TEST_IMPL(fs_partial_read)3885 TEST_IMPL(fs_partial_read) {
3886   test_fs_partial(1);
3887   return 0;
3888 }
3889 
TEST_IMPL(fs_partial_write)3890 TEST_IMPL(fs_partial_write) {
3891   test_fs_partial(0);
3892   return 0;
3893 }
3894 
3895 #endif/* _WIN32 */
3896 
TEST_IMPL(fs_read_write_null_arguments)3897 TEST_IMPL(fs_read_write_null_arguments) {
3898   int r;
3899 
3900   r = uv_fs_read(NULL, &read_req, 0, NULL, 0, -1, NULL);
3901   ASSERT_EQ(r, UV_EINVAL);
3902   uv_fs_req_cleanup(&read_req);
3903 
3904   r = uv_fs_write(NULL, &write_req, 0, NULL, 0, -1, NULL);
3905   /* Validate some memory management on failed input validation before sending
3906      fs work to the thread pool. */
3907   ASSERT_EQ(r, UV_EINVAL);
3908   ASSERT_NULL(write_req.path);
3909   ASSERT_NULL(write_req.ptr);
3910 #ifdef _WIN32
3911   ASSERT_NULL(write_req.file.pathw);
3912   ASSERT_NULL(write_req.fs.info.new_pathw);
3913   ASSERT_NULL(write_req.fs.info.bufs);
3914 #else
3915   ASSERT_NULL(write_req.new_path);
3916   ASSERT_NULL(write_req.bufs);
3917 #endif
3918   uv_fs_req_cleanup(&write_req);
3919 
3920   iov = uv_buf_init(NULL, 0);
3921   r = uv_fs_read(NULL, &read_req, 0, &iov, 0, -1, NULL);
3922   ASSERT_EQ(r, UV_EINVAL);
3923   uv_fs_req_cleanup(&read_req);
3924 
3925   iov = uv_buf_init(NULL, 0);
3926   r = uv_fs_write(NULL, &write_req, 0, &iov, 0, -1, NULL);
3927   ASSERT_EQ(r, UV_EINVAL);
3928   uv_fs_req_cleanup(&write_req);
3929 
3930   /* If the arguments are invalid, the loop should not be kept open */
3931   loop = uv_default_loop();
3932 
3933   r = uv_fs_read(loop, &read_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(&read_req);
3937 
3938   r = uv_fs_write(loop, &write_req, 0, NULL, 0, -1, fail_cb);
3939   ASSERT_EQ(r, UV_EINVAL);
3940   uv_run(loop, UV_RUN_DEFAULT);
3941   uv_fs_req_cleanup(&write_req);
3942 
3943   iov = uv_buf_init(NULL, 0);
3944   r = uv_fs_read(loop, &read_req, 0, &iov, 0, -1, fail_cb);
3945   ASSERT_EQ(r, UV_EINVAL);
3946   uv_run(loop, UV_RUN_DEFAULT);
3947   uv_fs_req_cleanup(&read_req);
3948 
3949   iov = uv_buf_init(NULL, 0);
3950   r = uv_fs_write(loop, &write_req, 0, &iov, 0, -1, fail_cb);
3951   ASSERT_EQ(r, UV_EINVAL);
3952   uv_run(loop, UV_RUN_DEFAULT);
3953   uv_fs_req_cleanup(&write_req);
3954 
3955   MAKE_VALGRIND_HAPPY(loop);
3956   return 0;
3957 }
3958 
3959 
TEST_IMPL(get_osfhandle_valid_handle)3960 TEST_IMPL(get_osfhandle_valid_handle) {
3961   int r;
3962   uv_os_fd_t fd;
3963 
3964   /* Setup. */
3965   unlink("test_file");
3966 
3967   loop = uv_default_loop();
3968 
3969   r = uv_fs_open(NULL,
3970                  &open_req1, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT,
3971                  S_IWUSR | S_IRUSR,
3972                  NULL);
3973   ASSERT_GE(r, 0);
3974   ASSERT_GE(open_req1.result, 0);
3975   uv_fs_req_cleanup(&open_req1);
3976 
3977   fd = uv_get_osfhandle(open_req1.result);
3978 #ifdef _WIN32
3979   ASSERT_PTR_NE(fd, INVALID_HANDLE_VALUE);
3980 #else
3981   ASSERT_GE(fd, 0);
3982 #endif
3983 
3984   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3985   ASSERT_OK(r);
3986   ASSERT_OK(close_req.result);
3987   uv_fs_req_cleanup(&close_req);
3988 
3989   /* Cleanup. */
3990   unlink("test_file");
3991 
3992   MAKE_VALGRIND_HAPPY(loop);
3993   return 0;
3994 }
3995 
TEST_IMPL(open_osfhandle_valid_handle)3996 TEST_IMPL(open_osfhandle_valid_handle) {
3997   int r;
3998   uv_os_fd_t handle;
3999   int fd;
4000 
4001   /* Setup. */
4002   unlink("test_file");
4003 
4004   loop = uv_default_loop();
4005 
4006   r = uv_fs_open(NULL,
4007                  &open_req1,
4008                  "test_file",
4009                  UV_FS_O_RDWR | UV_FS_O_CREAT,
4010                  S_IWUSR | S_IRUSR,
4011                  NULL);
4012   ASSERT_GE(r, 0);
4013   ASSERT_GE(open_req1.result, 0);
4014   uv_fs_req_cleanup(&open_req1);
4015 
4016   handle = uv_get_osfhandle(open_req1.result);
4017 #ifdef _WIN32
4018   ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE);
4019 #else
4020   ASSERT_GE(handle, 0);
4021 #endif
4022 
4023   fd = uv_open_osfhandle(handle);
4024 #ifdef _WIN32
4025   ASSERT_GT(fd, 0);
4026 #else
4027   ASSERT_EQ(fd, open_req1.result);
4028 #endif
4029 
4030   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
4031   ASSERT_OK(r);
4032   ASSERT_OK(close_req.result);
4033   uv_fs_req_cleanup(&close_req);
4034 
4035   /* Cleanup. */
4036   unlink("test_file");
4037 
4038   MAKE_VALGRIND_HAPPY(loop);
4039   return 0;
4040 }
4041 
TEST_IMPL(fs_file_pos_after_op_with_offset)4042 TEST_IMPL(fs_file_pos_after_op_with_offset) {
4043   int r;
4044 
4045   /* Setup. */
4046   unlink("test_file");
4047   loop = uv_default_loop();
4048 
4049   r = uv_fs_open(loop,
4050                  &open_req1, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT,
4051                  S_IWUSR | S_IRUSR,
4052                  NULL);
4053   ASSERT_GT(r, 0);
4054   uv_fs_req_cleanup(&open_req1);
4055 
4056   iov = uv_buf_init(test_buf, sizeof(test_buf));
4057   r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, 0, NULL);
4058   ASSERT_EQ(r, sizeof(test_buf));
4059   ASSERT_OK(lseek(open_req1.result, 0, SEEK_CUR));
4060   uv_fs_req_cleanup(&write_req);
4061 
4062   iov = uv_buf_init(buf, sizeof(buf));
4063   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, 0, NULL);
4064   ASSERT_EQ(r, sizeof(test_buf));
4065   ASSERT_OK(strcmp(buf, test_buf));
4066   ASSERT_OK(lseek(open_req1.result, 0, SEEK_CUR));
4067   uv_fs_req_cleanup(&read_req);
4068 
4069   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
4070   ASSERT_OK(r);
4071   uv_fs_req_cleanup(&close_req);
4072 
4073   /* Cleanup */
4074   unlink("test_file");
4075 
4076   MAKE_VALGRIND_HAPPY(loop);
4077   return 0;
4078 }
4079 
4080 #ifdef _WIN32
fs_file_pos_common(void)4081 static void fs_file_pos_common(void) {
4082   int r;
4083 
4084   iov = uv_buf_init("abc", 3);
4085   r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
4086   ASSERT_EQ(3, r);
4087   uv_fs_req_cleanup(&write_req);
4088 
4089   /* Read with offset should not change the position */
4090   iov = uv_buf_init(buf, 1);
4091   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, 1, NULL);
4092   ASSERT_EQ(1, r);
4093   ASSERT_EQ(buf[0], 'b');
4094   uv_fs_req_cleanup(&read_req);
4095 
4096   iov = uv_buf_init(buf, sizeof(buf));
4097   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
4098   ASSERT_OK(r);
4099   uv_fs_req_cleanup(&read_req);
4100 
4101   /* Write without offset should change the position */
4102   iov = uv_buf_init("d", 1);
4103   r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
4104   ASSERT_EQ(1, r);
4105   uv_fs_req_cleanup(&write_req);
4106 
4107   iov = uv_buf_init(buf, sizeof(buf));
4108   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
4109   ASSERT_OK(r);
4110   uv_fs_req_cleanup(&read_req);
4111 }
4112 
fs_file_pos_close_check(const char * contents,int size)4113 static void fs_file_pos_close_check(const char *contents, int size) {
4114   int r;
4115 
4116   /* Close */
4117   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
4118   ASSERT_OK(r);
4119   uv_fs_req_cleanup(&close_req);
4120 
4121   /* Confirm file contents */
4122   r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDONLY, 0, NULL);
4123   ASSERT_GE(r, 0);
4124   ASSERT_GE(open_req1.result, 0);
4125   uv_fs_req_cleanup(&open_req1);
4126 
4127   iov = uv_buf_init(buf, sizeof(buf));
4128   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
4129   ASSERT_EQ(r, size);
4130   ASSERT_OK(strncmp(buf, contents, size));
4131   uv_fs_req_cleanup(&read_req);
4132 
4133   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
4134   ASSERT_OK(r);
4135   uv_fs_req_cleanup(&close_req);
4136 
4137   /* Cleanup */
4138   unlink("test_file");
4139 }
4140 
fs_file_pos_write(int add_flags)4141 static void fs_file_pos_write(int add_flags) {
4142   int r;
4143 
4144   /* Setup. */
4145   unlink("test_file");
4146 
4147   r = uv_fs_open(NULL,
4148                  &open_req1,
4149                  "test_file",
4150                  UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_RDWR | add_flags,
4151                  S_IWUSR | S_IRUSR,
4152                  NULL);
4153   ASSERT_GT(r, 0);
4154   uv_fs_req_cleanup(&open_req1);
4155 
4156   fs_file_pos_common();
4157 
4158   /* Write with offset should not change the position */
4159   iov = uv_buf_init("e", 1);
4160   r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, 1, NULL);
4161   ASSERT_EQ(1, r);
4162   uv_fs_req_cleanup(&write_req);
4163 
4164   iov = uv_buf_init(buf, sizeof(buf));
4165   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
4166   ASSERT_OK(r);
4167   uv_fs_req_cleanup(&read_req);
4168 
4169   fs_file_pos_close_check("aecd", 4);
4170 }
TEST_IMPL(fs_file_pos_write)4171 TEST_IMPL(fs_file_pos_write) {
4172   fs_file_pos_write(0);
4173   fs_file_pos_write(UV_FS_O_FILEMAP);
4174 
4175   MAKE_VALGRIND_HAPPY(uv_default_loop());
4176   return 0;
4177 }
4178 
fs_file_pos_append(int add_flags)4179 static void fs_file_pos_append(int add_flags) {
4180   int r;
4181 
4182   /* Setup. */
4183   unlink("test_file");
4184 
4185   r = uv_fs_open(NULL,
4186                  &open_req1,
4187                  "test_file",
4188                  UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_RDWR | add_flags,
4189                  S_IWUSR | S_IRUSR,
4190                  NULL);
4191   ASSERT_GT(r, 0);
4192   uv_fs_req_cleanup(&open_req1);
4193 
4194   fs_file_pos_common();
4195 
4196   /* Write with offset appends (ignoring offset)
4197    * but does not change the position */
4198   iov = uv_buf_init("e", 1);
4199   r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, 1, NULL);
4200   ASSERT_EQ(1, r);
4201   uv_fs_req_cleanup(&write_req);
4202 
4203   iov = uv_buf_init(buf, sizeof(buf));
4204   r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
4205   ASSERT_EQ(1, r);
4206   ASSERT_EQ(buf[0], 'e');
4207   uv_fs_req_cleanup(&read_req);
4208 
4209   fs_file_pos_close_check("abcde", 5);
4210 }
TEST_IMPL(fs_file_pos_append)4211 TEST_IMPL(fs_file_pos_append) {
4212   fs_file_pos_append(0);
4213   fs_file_pos_append(UV_FS_O_FILEMAP);
4214 
4215   MAKE_VALGRIND_HAPPY(uv_default_loop());
4216   return 0;
4217 }
4218 #endif
4219 
TEST_IMPL(fs_null_req)4220 TEST_IMPL(fs_null_req) {
4221   /* Verify that all fs functions return UV_EINVAL when the request is NULL. */
4222   int r;
4223 
4224   r = uv_fs_open(NULL, NULL, NULL, 0, 0, NULL);
4225   ASSERT_EQ(r, UV_EINVAL);
4226 
4227   r = uv_fs_close(NULL, NULL, 0, NULL);
4228   ASSERT_EQ(r, UV_EINVAL);
4229 
4230   r = uv_fs_read(NULL, NULL, 0, NULL, 0, -1, NULL);
4231   ASSERT_EQ(r, UV_EINVAL);
4232 
4233   r = uv_fs_write(NULL, NULL, 0, NULL, 0, -1, NULL);
4234   ASSERT_EQ(r, UV_EINVAL);
4235 
4236   r = uv_fs_unlink(NULL, NULL, NULL, NULL);
4237   ASSERT_EQ(r, UV_EINVAL);
4238 
4239   r = uv_fs_mkdir(NULL, NULL, NULL, 0, NULL);
4240   ASSERT_EQ(r, UV_EINVAL);
4241 
4242   r = uv_fs_mkdtemp(NULL, NULL, NULL, NULL);
4243   ASSERT_EQ(r, UV_EINVAL);
4244 
4245   r = uv_fs_mkstemp(NULL, NULL, NULL, NULL);
4246   ASSERT_EQ(r, UV_EINVAL);
4247 
4248   r = uv_fs_rmdir(NULL, NULL, NULL, NULL);
4249   ASSERT_EQ(r, UV_EINVAL);
4250 
4251   r = uv_fs_scandir(NULL, NULL, NULL, 0, NULL);
4252   ASSERT_EQ(r, UV_EINVAL);
4253 
4254   r = uv_fs_link(NULL, NULL, NULL, NULL, NULL);
4255   ASSERT_EQ(r, UV_EINVAL);
4256 
4257   r = uv_fs_symlink(NULL, NULL, NULL, NULL, 0, NULL);
4258   ASSERT_EQ(r, UV_EINVAL);
4259 
4260   r = uv_fs_readlink(NULL, NULL, NULL, NULL);
4261   ASSERT_EQ(r, UV_EINVAL);
4262 
4263   r = uv_fs_realpath(NULL, NULL, NULL, NULL);
4264   ASSERT_EQ(r, UV_EINVAL);
4265 
4266   r = uv_fs_chown(NULL, NULL, NULL, 0, 0, NULL);
4267   ASSERT_EQ(r, UV_EINVAL);
4268 
4269   r = uv_fs_fchown(NULL, NULL, 0, 0, 0, NULL);
4270   ASSERT_EQ(r, UV_EINVAL);
4271 
4272   r = uv_fs_stat(NULL, NULL, NULL, NULL);
4273   ASSERT_EQ(r, UV_EINVAL);
4274 
4275   r = uv_fs_lstat(NULL, NULL, NULL, NULL);
4276   ASSERT_EQ(r, UV_EINVAL);
4277 
4278   r = uv_fs_fstat(NULL, NULL, 0, NULL);
4279   ASSERT_EQ(r, UV_EINVAL);
4280 
4281   r = uv_fs_rename(NULL, NULL, NULL, NULL, NULL);
4282   ASSERT_EQ(r, UV_EINVAL);
4283 
4284   r = uv_fs_fsync(NULL, NULL, 0, NULL);
4285   ASSERT_EQ(r, UV_EINVAL);
4286 
4287   r = uv_fs_fdatasync(NULL, NULL, 0, NULL);
4288   ASSERT_EQ(r, UV_EINVAL);
4289 
4290   r = uv_fs_ftruncate(NULL, NULL, 0, 0, NULL);
4291   ASSERT_EQ(r, UV_EINVAL);
4292 
4293   r = uv_fs_copyfile(NULL, NULL, NULL, NULL, 0, NULL);
4294   ASSERT_EQ(r, UV_EINVAL);
4295 
4296   r = uv_fs_sendfile(NULL, NULL, 0, 0, 0, 0, NULL);
4297   ASSERT_EQ(r, UV_EINVAL);
4298 
4299   r = uv_fs_access(NULL, NULL, NULL, 0, NULL);
4300   ASSERT_EQ(r, UV_EINVAL);
4301 
4302   r = uv_fs_chmod(NULL, NULL, NULL, 0, NULL);
4303   ASSERT_EQ(r, UV_EINVAL);
4304 
4305   r = uv_fs_fchmod(NULL, NULL, 0, 0, NULL);
4306   ASSERT_EQ(r, UV_EINVAL);
4307 
4308   r = uv_fs_utime(NULL, NULL, NULL, 0.0, 0.0, NULL);
4309   ASSERT_EQ(r, UV_EINVAL);
4310 
4311   r = uv_fs_futime(NULL, NULL, 0, 0.0, 0.0, NULL);
4312   ASSERT_EQ(r, UV_EINVAL);
4313 
4314   r = uv_fs_statfs(NULL, NULL, NULL, NULL);
4315   ASSERT_EQ(r, UV_EINVAL);
4316 
4317   /* This should be a no-op. */
4318   uv_fs_req_cleanup(NULL);
4319 
4320   return 0;
4321 }
4322 
4323 #ifdef _WIN32
TEST_IMPL(fs_exclusive_sharing_mode)4324 TEST_IMPL(fs_exclusive_sharing_mode) {
4325   int r;
4326 
4327   /* Setup. */
4328   unlink("test_file");
4329 
4330   ASSERT_GT(UV_FS_O_EXLOCK, 0);
4331 
4332   r = uv_fs_open(NULL,
4333                  &open_req1,
4334                  "test_file",
4335                  UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_EXLOCK,
4336                  S_IWUSR | S_IRUSR,
4337                  NULL);
4338   ASSERT_GE(r, 0);
4339   ASSERT_GE(open_req1.result, 0);
4340   uv_fs_req_cleanup(&open_req1);
4341 
4342   r = uv_fs_open(NULL,
4343                  &open_req2,
4344                  "test_file", UV_FS_O_RDONLY | UV_FS_O_EXLOCK,
4345                  S_IWUSR | S_IRUSR,
4346                  NULL);
4347   ASSERT_LT(r, 0);
4348   ASSERT_LT(open_req2.result, 0);
4349   uv_fs_req_cleanup(&open_req2);
4350 
4351   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
4352   ASSERT_OK(r);
4353   ASSERT_OK(close_req.result);
4354   uv_fs_req_cleanup(&close_req);
4355 
4356   r = uv_fs_open(NULL,
4357                  &open_req2,
4358                  "test_file", UV_FS_O_RDONLY | UV_FS_O_EXLOCK,
4359                  S_IWUSR | S_IRUSR,
4360                  NULL);
4361   ASSERT_GE(r, 0);
4362   ASSERT_GE(open_req2.result, 0);
4363   uv_fs_req_cleanup(&open_req2);
4364 
4365   r = uv_fs_close(NULL, &close_req, open_req2.result, NULL);
4366   ASSERT_OK(r);
4367   ASSERT_OK(close_req.result);
4368   uv_fs_req_cleanup(&close_req);
4369 
4370   /* Cleanup */
4371   unlink("test_file");
4372 
4373   MAKE_VALGRIND_HAPPY(uv_default_loop());
4374   return 0;
4375 }
4376 #endif
4377 
4378 #ifdef _WIN32
TEST_IMPL(fs_file_flag_no_buffering)4379 TEST_IMPL(fs_file_flag_no_buffering) {
4380   int r;
4381 
4382   /* Setup. */
4383   unlink("test_file");
4384 
4385   ASSERT_GT(UV_FS_O_APPEND, 0);
4386   ASSERT_GT(UV_FS_O_CREAT, 0);
4387   ASSERT_GT(UV_FS_O_DIRECT, 0);
4388   ASSERT_GT(UV_FS_O_RDWR, 0);
4389 
4390   /* FILE_APPEND_DATA must be excluded from FILE_GENERIC_WRITE: */
4391   r = uv_fs_open(NULL,
4392                  &open_req1,
4393                  "test_file",
4394                  UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_DIRECT,
4395                  S_IWUSR | S_IRUSR,
4396                  NULL);
4397   ASSERT_GE(r, 0);
4398   ASSERT_GE(open_req1.result, 0);
4399   uv_fs_req_cleanup(&open_req1);
4400 
4401   r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
4402   ASSERT_OK(r);
4403   ASSERT_OK(close_req.result);
4404   uv_fs_req_cleanup(&close_req);
4405 
4406   /* FILE_APPEND_DATA and FILE_FLAG_NO_BUFFERING are mutually exclusive: */
4407   r = uv_fs_open(NULL,
4408                  &open_req2,
4409                  "test_file",
4410                  UV_FS_O_APPEND | UV_FS_O_DIRECT,
4411                  S_IWUSR | S_IRUSR,
4412                  NULL);
4413   ASSERT_EQ(r, UV_EINVAL);
4414   ASSERT_EQ(open_req2.result, UV_EINVAL);
4415   uv_fs_req_cleanup(&open_req2);
4416 
4417   /* Cleanup */
4418   unlink("test_file");
4419 
4420   MAKE_VALGRIND_HAPPY(uv_default_loop());
4421   return 0;
4422 }
4423 #endif
4424 
4425 #ifdef _WIN32
call_icacls(const char * command,...)4426 int call_icacls(const char* command, ...) {
4427     char icacls_command[1024];
4428     va_list args;
4429 
4430     va_start(args, command);
4431     vsnprintf(icacls_command, ARRAYSIZE(icacls_command), command, args);
4432     va_end(args);
4433     return system(icacls_command);
4434 }
4435 
TEST_IMPL(fs_open_readonly_acl)4436 TEST_IMPL(fs_open_readonly_acl) {
4437     uv_passwd_t pwd;
4438     uv_fs_t req;
4439     int r;
4440 
4441     /*
4442         Based on Node.js test from
4443         https://github.com/nodejs/node/commit/3ba81e34e86a5c32658e218cb6e65b13e8326bc5
4444 
4445         If anything goes wrong, you can delte the test_fle_icacls with:
4446 
4447             icacls test_file_icacls /remove "%USERNAME%" /inheritance:e
4448             attrib -r test_file_icacls
4449             del test_file_icacls
4450     */
4451 
4452     /* Setup - clear the ACL and remove the file */
4453     loop = uv_default_loop();
4454     r = uv_os_get_passwd(&pwd);
4455     ASSERT_OK(r);
4456     call_icacls("icacls test_file_icacls /remove \"%s\" /inheritance:e",
4457                 pwd.username);
4458     uv_fs_chmod(loop, &req, "test_file_icacls", S_IWUSR, NULL);
4459     unlink("test_file_icacls");
4460 
4461     /* Create the file */
4462     r = uv_fs_open(loop,
4463                    &open_req1,
4464                    "test_file_icacls",
4465                    UV_FS_O_RDONLY | UV_FS_O_CREAT,
4466                    S_IRUSR,
4467                    NULL);
4468     ASSERT_GE(r, 0);
4469     ASSERT_GE(open_req1.result, 0);
4470     uv_fs_req_cleanup(&open_req1);
4471     r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
4472     ASSERT_OK(r);
4473     ASSERT_OK(close_req.result);
4474     uv_fs_req_cleanup(&close_req);
4475 
4476     /* Set up ACL */
4477     r = call_icacls("icacls test_file_icacls /inheritance:r /remove \"%s\"",
4478                     pwd.username);
4479     if (r != 0) {
4480         goto acl_cleanup;
4481     }
4482     r = call_icacls("icacls test_file_icacls /grant \"%s\":RX", pwd.username);
4483     if (r != 0) {
4484         goto acl_cleanup;
4485     }
4486 
4487     /* Try opening the file */
4488     r = uv_fs_open(NULL, &open_req1, "test_file_icacls", UV_FS_O_RDONLY, 0,
4489                    NULL);
4490     if (r < 0) {
4491         goto acl_cleanup;
4492     }
4493     uv_fs_req_cleanup(&open_req1);
4494     r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
4495     if (r != 0) {
4496         goto acl_cleanup;
4497     }
4498     uv_fs_req_cleanup(&close_req);
4499 
4500  acl_cleanup:
4501     /* Cleanup */
4502     call_icacls("icacls test_file_icacls /remove \"%s\" /inheritance:e",
4503                 pwd.username);
4504     unlink("test_file_icacls");
4505     uv_os_free_passwd(&pwd);
4506     ASSERT_OK(r);
4507     MAKE_VALGRIND_HAPPY(loop);
4508     return 0;
4509 }
4510 #endif
4511 
4512 #ifdef _WIN32
TEST_IMPL(fs_fchmod_archive_readonly)4513 TEST_IMPL(fs_fchmod_archive_readonly) {
4514     uv_fs_t req;
4515     uv_file file;
4516     int r;
4517     /* Test clearing read-only flag from files with Archive flag cleared */
4518 
4519     /* Setup*/
4520     unlink("test_file");
4521     r = uv_fs_open(NULL,
4522                    &req, "test_file", UV_FS_O_WRONLY | UV_FS_O_CREAT,
4523                    S_IWUSR | S_IRUSR,
4524                    NULL);
4525     ASSERT_GE(r, 0);
4526     ASSERT_GE(req.result, 0);
4527     file = req.result;
4528     uv_fs_req_cleanup(&req);
4529     r = uv_fs_close(NULL, &req, file, NULL);
4530     ASSERT_OK(r);
4531     uv_fs_req_cleanup(&req);
4532     /* Make the file read-only and clear archive flag */
4533     r = SetFileAttributes("test_file", FILE_ATTRIBUTE_READONLY);
4534     ASSERT(r);
4535     check_permission("test_file", 0400);
4536     /* Try fchmod */
4537     r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDONLY, 0, NULL);
4538     ASSERT_GE(r, 0);
4539     ASSERT_GE(req.result, 0);
4540     file = req.result;
4541     uv_fs_req_cleanup(&req);
4542     r = uv_fs_fchmod(NULL, &req, file, S_IWUSR, NULL);
4543     ASSERT_OK(r);
4544     ASSERT_OK(req.result);
4545     uv_fs_req_cleanup(&req);
4546     r = uv_fs_close(NULL, &req, file, NULL);
4547     ASSERT_OK(r);
4548     uv_fs_req_cleanup(&req);
4549     check_permission("test_file", S_IWUSR);
4550 
4551     /* Restore Archive flag for rest of the tests */
4552     r = SetFileAttributes("test_file", FILE_ATTRIBUTE_ARCHIVE);
4553     ASSERT(r);
4554 
4555     return 0;
4556 }
4557 
TEST_IMPL(fs_invalid_mkdir_name)4558 TEST_IMPL(fs_invalid_mkdir_name) {
4559   uv_loop_t* loop;
4560   uv_fs_t req;
4561   int r;
4562 
4563   loop = uv_default_loop();
4564   r = uv_fs_mkdir(loop, &req, "invalid>", 0, NULL);
4565   ASSERT_EQ(r, UV_EINVAL);
4566   ASSERT_EQ(UV_EINVAL, uv_fs_mkdir(loop, &req, "test:lol", 0, NULL));
4567 
4568   return 0;
4569 }
4570 #endif
4571 
TEST_IMPL(fs_statfs)4572 TEST_IMPL(fs_statfs) {
4573   uv_fs_t req;
4574   int r;
4575 
4576   loop = uv_default_loop();
4577 
4578   /* Test the synchronous version. */
4579   r = uv_fs_statfs(NULL, &req, ".", NULL);
4580   ASSERT_OK(r);
4581   statfs_cb(&req);
4582   ASSERT_EQ(1, statfs_cb_count);
4583 
4584   /* Test the asynchronous version. */
4585   r = uv_fs_statfs(loop, &req, ".", statfs_cb);
4586   ASSERT_OK(r);
4587   uv_run(loop, UV_RUN_DEFAULT);
4588   ASSERT_EQ(2, statfs_cb_count);
4589 
4590   MAKE_VALGRIND_HAPPY(loop);
4591   return 0;
4592 }
4593 
TEST_IMPL(fs_get_system_error)4594 TEST_IMPL(fs_get_system_error) {
4595   uv_fs_t req;
4596   int r;
4597   int system_error;
4598 
4599   r = uv_fs_statfs(NULL, &req, "non_existing_file", NULL);
4600   ASSERT(r);
4601 
4602   system_error = uv_fs_get_system_error(&req);
4603 #ifdef _WIN32
4604   ASSERT_EQ(system_error, ERROR_FILE_NOT_FOUND);
4605 #else
4606   ASSERT_EQ(system_error, ENOENT);
4607 #endif
4608 
4609   return 0;
4610 }
4611 
4612 
TEST_IMPL(fs_stat_batch_multiple)4613 TEST_IMPL(fs_stat_batch_multiple) {
4614   uv_fs_t req[300];
4615   int r;
4616   int i;
4617 
4618   rmdir("test_dir");
4619 
4620   r = uv_fs_mkdir(NULL, &mkdir_req, "test_dir", 0755, NULL);
4621   ASSERT_OK(r);
4622 
4623   loop = uv_default_loop();
4624 
4625   for (i = 0; i < (int) ARRAY_SIZE(req); ++i) {
4626     r = uv_fs_stat(loop, &req[i], "test_dir", stat_batch_cb);
4627     ASSERT_OK(r);
4628   }
4629 
4630   uv_run(loop, UV_RUN_DEFAULT);
4631   ASSERT_EQ(stat_cb_count, ARRAY_SIZE(req));
4632 
4633   MAKE_VALGRIND_HAPPY(loop);
4634   return 0;
4635 }
4636 
4637 
4638 #ifdef _WIN32
TEST_IMPL(fs_wtf)4639 TEST_IMPL(fs_wtf) {
4640   int r;
4641   HANDLE file_handle;
4642   uv_dirent_t dent;
4643   static char test_file_buf[PATHMAX];
4644 
4645   /* set-up */
4646   _wunlink(L"test_dir/hi\xD801\x0037");
4647   rmdir("test_dir");
4648 
4649   loop = uv_default_loop();
4650 
4651   r = uv_fs_mkdir(NULL, &mkdir_req, "test_dir", 0777, NULL);
4652   ASSERT_OK(r);
4653   uv_fs_req_cleanup(&mkdir_req);
4654 
4655   file_handle = CreateFileW(L"test_dir/hi\xD801\x0037",
4656                             GENERIC_WRITE | FILE_WRITE_ATTRIBUTES,
4657                             0,
4658                             NULL,
4659                             CREATE_ALWAYS,
4660                             FILE_FLAG_OPEN_REPARSE_POINT |
4661                               FILE_FLAG_BACKUP_SEMANTICS,
4662                             NULL);
4663   ASSERT_PTR_NE(file_handle, INVALID_HANDLE_VALUE);
4664 
4665   CloseHandle(file_handle);
4666 
4667   r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL);
4668   ASSERT_EQ(1, r);
4669   ASSERT_EQ(1, scandir_req.result);
4670   ASSERT_NOT_NULL(scandir_req.ptr);
4671   while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) {
4672     snprintf(test_file_buf, sizeof(test_file_buf), "test_dir\\%s", dent.name);
4673     printf("stat %s\n", test_file_buf);
4674     r = uv_fs_stat(NULL, &stat_req, test_file_buf, NULL);
4675     ASSERT_OK(r);
4676   }
4677   uv_fs_req_cleanup(&scandir_req);
4678   ASSERT_NULL(scandir_req.ptr);
4679 
4680   /* clean-up */
4681   _wunlink(L"test_dir/hi\xD801\x0037");
4682   rmdir("test_dir");
4683 
4684   MAKE_VALGRIND_HAPPY(loop);
4685   return 0;
4686 }
4687 #endif
4688