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