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