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