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