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