libuv-svace-build

Форк
0
4642 строки · 116.5 Кб
1
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2
 *
3
 * Permission is hereby granted, free of charge, to any person obtaining a copy
4
 * of this software and associated documentation files (the "Software"), to
5
 * deal in the Software without restriction, including without limitation the
6
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
 * sell copies of the Software, and to permit persons to whom the Software is
8
 * furnished to do so, subject to the following conditions:
9
 *
10
 * The above copyright notice and this permission notice shall be included in
11
 * all copies or substantial portions of the Software.
12
 *
13
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19
 * IN THE SOFTWARE.
20
 */
21

22
#include "uv.h"
23
#include "task.h"
24

25
#include <errno.h>
26
#include <string.h> /* memset */
27
#include <fcntl.h>
28
#include <sys/stat.h>
29
#include <limits.h> /* INT_MAX, PATH_MAX, IOV_MAX */
30

31
#ifndef _WIN32
32
# include <unistd.h> /* unlink, rmdir, etc. */
33
#else
34
# include <winioctl.h>
35
# include <direct.h>
36
# include <io.h>
37
# ifndef ERROR_SYMLINK_NOT_SUPPORTED
38
#  define ERROR_SYMLINK_NOT_SUPPORTED 1464
39
# endif
40
# ifndef S_IFIFO
41
#  define S_IFIFO _S_IFIFO
42
# endif
43
# define unlink _unlink
44
# define rmdir _rmdir
45
# define open _open
46
# define write _write
47
# define close _close
48
# ifndef stat
49
#  define stat _stati64
50
# endif
51
# ifndef lseek
52
#   define lseek _lseek
53
# endif
54
# define S_IFDIR _S_IFDIR
55
# define S_IFCHR _S_IFCHR
56
# define S_IFREG _S_IFREG
57
#endif
58

59
#define TOO_LONG_NAME_LENGTH 65536
60
#define PATHMAX 4096
61

62
typedef struct {
63
  const char* path;
64
  double atime;
65
  double mtime;
66
} utime_check_t;
67

68

69
static int dummy_cb_count;
70
static int close_cb_count;
71
static int create_cb_count;
72
static int open_cb_count;
73
static int read_cb_count;
74
static int write_cb_count;
75
static int unlink_cb_count;
76
static int mkdir_cb_count;
77
static int mkdtemp_cb_count;
78
static int mkstemp_cb_count;
79
static int rmdir_cb_count;
80
static int scandir_cb_count;
81
static int stat_cb_count;
82
static int rename_cb_count;
83
static int fsync_cb_count;
84
static int fdatasync_cb_count;
85
static int ftruncate_cb_count;
86
static int sendfile_cb_count;
87
static int fstat_cb_count;
88
static int access_cb_count;
89
static int chmod_cb_count;
90
static int fchmod_cb_count;
91
static int chown_cb_count;
92
static int fchown_cb_count;
93
static int lchown_cb_count;
94
static int link_cb_count;
95
static int symlink_cb_count;
96
static int readlink_cb_count;
97
static int realpath_cb_count;
98
static int utime_cb_count;
99
static int futime_cb_count;
100
static int lutime_cb_count;
101
static int statfs_cb_count;
102

103
static uv_loop_t* loop;
104

105
static uv_fs_t open_req1;
106
static uv_fs_t open_req2;
107
static uv_fs_t read_req;
108
static uv_fs_t write_req;
109
static uv_fs_t unlink_req;
110
static uv_fs_t close_req;
111
static uv_fs_t mkdir_req;
112
static uv_fs_t mkdtemp_req1;
113
static uv_fs_t mkdtemp_req2;
114
static uv_fs_t mkstemp_req1;
115
static uv_fs_t mkstemp_req2;
116
static uv_fs_t mkstemp_req3;
117
static uv_fs_t rmdir_req;
118
static uv_fs_t scandir_req;
119
static uv_fs_t stat_req;
120
static uv_fs_t rename_req;
121
static uv_fs_t fsync_req;
122
static uv_fs_t fdatasync_req;
123
static uv_fs_t ftruncate_req;
124
static uv_fs_t sendfile_req;
125
static uv_fs_t utime_req;
126
static uv_fs_t futime_req;
127

128
static char buf[32];
129
static char buf2[32];
130
static char test_buf[] = "test-buffer\n";
131
static char test_buf2[] = "second-buffer\n";
132
static uv_buf_t iov;
133

134
#ifdef _WIN32
135
int uv_test_getiovmax(void) {
136
  return INT32_MAX; /* Emulated by libuv, so no real limit. */
137
}
138
#else
139
int uv_test_getiovmax(void) {
140
#if defined(IOV_MAX)
141
  return IOV_MAX;
142
#elif defined(_SC_IOV_MAX)
143
  static int iovmax = -1;
144
  if (iovmax == -1) {
145
    iovmax = sysconf(_SC_IOV_MAX);
146
    /* On some embedded devices (arm-linux-uclibc based ip camera),
147
     * sysconf(_SC_IOV_MAX) can not get the correct value. The return
148
     * value is -1 and the errno is EINPROGRESS. Degrade the value to 1.
149
     */
150
    if (iovmax == -1) iovmax = 1;
151
  }
152
  return iovmax;
153
#else
154
  return 1024;
155
#endif
156
}
157
#endif
158

159
#ifdef _WIN32
160
/*
161
 * This tag and guid have no special meaning, and don't conflict with
162
 * reserved ids.
163
*/
164
static unsigned REPARSE_TAG = 0x9913;
165
static GUID REPARSE_GUID = {
166
  0x1bf6205f, 0x46ae, 0x4527,
167
  { 0xb1, 0x0c, 0xc5, 0x09, 0xb7, 0x55, 0x22, 0x80 }};
168
#endif
169

170
static void check_permission(const char* filename, unsigned int mode) {
171
  int r;
172
  uv_fs_t req;
173
  uv_stat_t* s;
174

175
  r = uv_fs_stat(NULL, &req, filename, NULL);
176
  ASSERT_OK(r);
177
  ASSERT_OK(req.result);
178

179
  s = &req.statbuf;
180
#if defined(_WIN32) || defined(__CYGWIN__) || defined(__MSYS__)
181
  /*
182
   * On Windows, chmod can only modify S_IWUSR (_S_IWRITE) bit,
183
   * so only testing for the specified flags.
184
   */
185
  ASSERT((s->st_mode & 0777) & mode);
186
#else
187
  ASSERT((s->st_mode & 0777) == mode);
188
#endif
189

190
  uv_fs_req_cleanup(&req);
191
}
192

193

194
static void dummy_cb(uv_fs_t* req) {
195
  (void) req;
196
  dummy_cb_count++;
197
}
198

199

200
static void link_cb(uv_fs_t* req) {
201
  ASSERT_EQ(req->fs_type, UV_FS_LINK);
202
  ASSERT_OK(req->result);
203
  link_cb_count++;
204
  uv_fs_req_cleanup(req);
205
}
206

207

208
static void symlink_cb(uv_fs_t* req) {
209
  ASSERT_EQ(req->fs_type, UV_FS_SYMLINK);
210
  ASSERT_OK(req->result);
211
  symlink_cb_count++;
212
  uv_fs_req_cleanup(req);
213
}
214

215
static void readlink_cb(uv_fs_t* req) {
216
  ASSERT_EQ(req->fs_type, UV_FS_READLINK);
217
  ASSERT_OK(req->result);
218
  ASSERT_OK(strcmp(req->ptr, "test_file_symlink2"));
219
  readlink_cb_count++;
220
  uv_fs_req_cleanup(req);
221
}
222

223

224
static void realpath_cb(uv_fs_t* req) {
225
  char test_file_abs_buf[PATHMAX];
226
  size_t test_file_abs_size = sizeof(test_file_abs_buf);
227
  ASSERT_EQ(req->fs_type, UV_FS_REALPATH);
228
  ASSERT_OK(req->result);
229

230
  uv_cwd(test_file_abs_buf, &test_file_abs_size);
231
#ifdef _WIN32
232
  strcat(test_file_abs_buf, "\\test_file");
233
  ASSERT_OK(_stricmp(req->ptr, test_file_abs_buf));
234
#else
235
  strcat(test_file_abs_buf, "/test_file");
236
  ASSERT_OK(strcmp(req->ptr, test_file_abs_buf));
237
#endif
238
  realpath_cb_count++;
239
  uv_fs_req_cleanup(req);
240
}
241

242

243
static void access_cb(uv_fs_t* req) {
244
  ASSERT_EQ(req->fs_type, UV_FS_ACCESS);
245
  access_cb_count++;
246
  uv_fs_req_cleanup(req);
247
}
248

249

250
static void fchmod_cb(uv_fs_t* req) {
251
  ASSERT_EQ(req->fs_type, UV_FS_FCHMOD);
252
  ASSERT_OK(req->result);
253
  fchmod_cb_count++;
254
  uv_fs_req_cleanup(req);
255
  check_permission("test_file", *(int*)req->data);
256
}
257

258

259
static void chmod_cb(uv_fs_t* req) {
260
  ASSERT_EQ(req->fs_type, UV_FS_CHMOD);
261
  ASSERT_OK(req->result);
262
  chmod_cb_count++;
263
  uv_fs_req_cleanup(req);
264
  check_permission("test_file", *(int*)req->data);
265
}
266

267

268
static void fchown_cb(uv_fs_t* req) {
269
  ASSERT_EQ(req->fs_type, UV_FS_FCHOWN);
270
  ASSERT_OK(req->result);
271
  fchown_cb_count++;
272
  uv_fs_req_cleanup(req);
273
}
274

275

276
static void chown_cb(uv_fs_t* req) {
277
  ASSERT_EQ(req->fs_type, UV_FS_CHOWN);
278
  ASSERT_OK(req->result);
279
  chown_cb_count++;
280
  uv_fs_req_cleanup(req);
281
}
282

283
static void lchown_cb(uv_fs_t* req) {
284
  ASSERT_EQ(req->fs_type, UV_FS_LCHOWN);
285
  ASSERT_OK(req->result);
286
  lchown_cb_count++;
287
  uv_fs_req_cleanup(req);
288
}
289

290
static void chown_root_cb(uv_fs_t* req) {
291
  ASSERT_EQ(req->fs_type, UV_FS_CHOWN);
292
#if defined(_WIN32) || defined(__MSYS__)
293
  /* On windows, chown is a no-op and always succeeds. */
294
  ASSERT_OK(req->result);
295
#else
296
  /* On unix, chown'ing the root directory is not allowed -
297
   * unless you're root, of course.
298
   */
299
  if (geteuid() == 0)
300
    ASSERT_OK(req->result);
301
  else
302
#   if defined(__CYGWIN__)
303
    /* On Cygwin, uid 0 is invalid (no root). */
304
    ASSERT_EQ(req->result, UV_EINVAL);
305
#   elif defined(__PASE__)
306
    /* On IBMi PASE, there is no root user. uid 0 is user qsecofr.
307
     * User may grant qsecofr's privileges, including changing 
308
     * the file's ownership to uid 0.
309
     */
310
    ASSERT(req->result == 0 || req->result == UV_EPERM);
311
#   else
312
    ASSERT_EQ(req->result, UV_EPERM);
313
#   endif
314
#endif
315
  chown_cb_count++;
316
  uv_fs_req_cleanup(req);
317
}
318

319
static void unlink_cb(uv_fs_t* req) {
320
  ASSERT_PTR_EQ(req, &unlink_req);
321
  ASSERT_EQ(req->fs_type, UV_FS_UNLINK);
322
  ASSERT_OK(req->result);
323
  unlink_cb_count++;
324
  uv_fs_req_cleanup(req);
325
}
326

327
static void fstat_cb(uv_fs_t* req) {
328
  uv_stat_t* s = req->ptr;
329
  ASSERT_EQ(req->fs_type, UV_FS_FSTAT);
330
  ASSERT_OK(req->result);
331
  ASSERT_EQ(s->st_size, sizeof(test_buf));
332
  uv_fs_req_cleanup(req);
333
  fstat_cb_count++;
334
}
335

336

337
static void statfs_cb(uv_fs_t* req) {
338
  uv_statfs_t* stats;
339

340
  ASSERT_EQ(req->fs_type, UV_FS_STATFS);
341
  ASSERT_OK(req->result);
342
  ASSERT_NOT_NULL(req->ptr);
343
  stats = req->ptr;
344

345
#if defined(_WIN32) || defined(__sun) || defined(_AIX) || defined(__MVS__) || \
346
  defined(__OpenBSD__) || defined(__NetBSD__)
347
  ASSERT_OK(stats->f_type);
348
#else
349
  ASSERT_UINT64_GT(stats->f_type, 0);
350
#endif
351

352
  ASSERT_GT(stats->f_bsize, 0);
353
  ASSERT_GT(stats->f_blocks, 0);
354
  ASSERT_LE(stats->f_bfree, stats->f_blocks);
355
  ASSERT_LE(stats->f_bavail, stats->f_bfree);
356

357
#ifdef _WIN32
358
  ASSERT_OK(stats->f_files);
359
  ASSERT_OK(stats->f_ffree);
360
#else
361
  /* There is no assertion for stats->f_files that makes sense, so ignore it. */
362
  ASSERT_LE(stats->f_ffree, stats->f_files);
363
#endif
364
  uv_fs_req_cleanup(req);
365
  ASSERT_NULL(req->ptr);
366
  statfs_cb_count++;
367
}
368

369

370
static void close_cb(uv_fs_t* req) {
371
  int r;
372
  ASSERT_PTR_EQ(req, &close_req);
373
  ASSERT_EQ(req->fs_type, UV_FS_CLOSE);
374
  ASSERT_OK(req->result);
375
  close_cb_count++;
376
  uv_fs_req_cleanup(req);
377
  if (close_cb_count == 3) {
378
    r = uv_fs_unlink(loop, &unlink_req, "test_file2", unlink_cb);
379
    ASSERT_OK(r);
380
  }
381
}
382

383

384
static void ftruncate_cb(uv_fs_t* req) {
385
  int r;
386
  ASSERT_PTR_EQ(req, &ftruncate_req);
387
  ASSERT_EQ(req->fs_type, UV_FS_FTRUNCATE);
388
  ASSERT_OK(req->result);
389
  ftruncate_cb_count++;
390
  uv_fs_req_cleanup(req);
391
  r = uv_fs_close(loop, &close_req, open_req1.result, close_cb);
392
  ASSERT_OK(r);
393
}
394

395
static void fail_cb(uv_fs_t* req) {
396
  FATAL("fail_cb should not have been called");
397
}
398

399
static void read_cb(uv_fs_t* req) {
400
  int r;
401
  ASSERT_PTR_EQ(req, &read_req);
402
  ASSERT_EQ(req->fs_type, UV_FS_READ);
403
  ASSERT_GE(req->result, 0);  /* FIXME(bnoordhuis) Check if requested size? */
404
  read_cb_count++;
405
  uv_fs_req_cleanup(req);
406
  if (read_cb_count == 1) {
407
    ASSERT_OK(strcmp(buf, test_buf));
408
    r = uv_fs_ftruncate(loop, &ftruncate_req, open_req1.result, 7,
409
        ftruncate_cb);
410
  } else {
411
    ASSERT_OK(strcmp(buf, "test-bu"));
412
    r = uv_fs_close(loop, &close_req, open_req1.result, close_cb);
413
  }
414
  ASSERT_OK(r);
415
}
416

417

418
static void open_cb(uv_fs_t* req) {
419
  int r;
420
  ASSERT_PTR_EQ(req, &open_req1);
421
  ASSERT_EQ(req->fs_type, UV_FS_OPEN);
422
  if (req->result < 0) {
423
    fprintf(stderr, "async open error: %d\n", (int) req->result);
424
    ASSERT(0);
425
  }
426
  open_cb_count++;
427
  ASSERT(req->path);
428
  ASSERT_OK(memcmp(req->path, "test_file2\0", 11));
429
  uv_fs_req_cleanup(req);
430
  memset(buf, 0, sizeof(buf));
431
  iov = uv_buf_init(buf, sizeof(buf));
432
  r = uv_fs_read(loop, &read_req, open_req1.result, &iov, 1, -1,
433
      read_cb);
434
  ASSERT_OK(r);
435
}
436

437

438
static void open_cb_simple(uv_fs_t* req) {
439
  ASSERT_EQ(req->fs_type, UV_FS_OPEN);
440
  if (req->result < 0) {
441
    fprintf(stderr, "async open error: %d\n", (int) req->result);
442
    ASSERT(0);
443
  }
444
  open_cb_count++;
445
  ASSERT(req->path);
446
  uv_fs_req_cleanup(req);
447
}
448

449

450
static void fsync_cb(uv_fs_t* req) {
451
  int r;
452
  ASSERT_PTR_EQ(req, &fsync_req);
453
  ASSERT_EQ(req->fs_type, UV_FS_FSYNC);
454
  ASSERT_OK(req->result);
455
  fsync_cb_count++;
456
  uv_fs_req_cleanup(req);
457
  r = uv_fs_close(loop, &close_req, open_req1.result, close_cb);
458
  ASSERT_OK(r);
459
}
460

461

462
static void fdatasync_cb(uv_fs_t* req) {
463
  int r;
464
  ASSERT_PTR_EQ(req, &fdatasync_req);
465
  ASSERT_EQ(req->fs_type, UV_FS_FDATASYNC);
466
  ASSERT_OK(req->result);
467
  fdatasync_cb_count++;
468
  uv_fs_req_cleanup(req);
469
  r = uv_fs_fsync(loop, &fsync_req, open_req1.result, fsync_cb);
470
  ASSERT_OK(r);
471
}
472

473

474
static void write_cb(uv_fs_t* req) {
475
  int r;
476
  ASSERT_PTR_EQ(req, &write_req);
477
  ASSERT_EQ(req->fs_type, UV_FS_WRITE);
478
  ASSERT_GE(req->result, 0);  /* FIXME(bnoordhuis) Check if requested size? */
479
  write_cb_count++;
480
  uv_fs_req_cleanup(req);
481
  r = uv_fs_fdatasync(loop, &fdatasync_req, open_req1.result, fdatasync_cb);
482
  ASSERT_OK(r);
483
}
484

485

486
static void create_cb(uv_fs_t* req) {
487
  int r;
488
  ASSERT_PTR_EQ(req, &open_req1);
489
  ASSERT_EQ(req->fs_type, UV_FS_OPEN);
490
  ASSERT_GE(req->result, 0);
491
  create_cb_count++;
492
  uv_fs_req_cleanup(req);
493
  iov = uv_buf_init(test_buf, sizeof(test_buf));
494
  r = uv_fs_write(loop, &write_req, req->result, &iov, 1, -1, write_cb);
495
  ASSERT_OK(r);
496
}
497

498

499
static void rename_cb(uv_fs_t* req) {
500
  ASSERT_PTR_EQ(req, &rename_req);
501
  ASSERT_EQ(req->fs_type, UV_FS_RENAME);
502
  ASSERT_OK(req->result);
503
  rename_cb_count++;
504
  uv_fs_req_cleanup(req);
505
}
506

507

508
static void mkdir_cb(uv_fs_t* req) {
509
  ASSERT_PTR_EQ(req, &mkdir_req);
510
  ASSERT_EQ(req->fs_type, UV_FS_MKDIR);
511
  ASSERT_OK(req->result);
512
  mkdir_cb_count++;
513
  ASSERT(req->path);
514
  ASSERT_OK(memcmp(req->path, "test_dir\0", 9));
515
  uv_fs_req_cleanup(req);
516
}
517

518

519
static void check_mkdtemp_result(uv_fs_t* req) {
520
  int r;
521

522
  ASSERT_EQ(req->fs_type, UV_FS_MKDTEMP);
523
  ASSERT_OK(req->result);
524
  ASSERT(req->path);
525
  ASSERT_EQ(15, strlen(req->path));
526
  ASSERT_OK(memcmp(req->path, "test_dir_", 9));
527
  ASSERT_NE(0, memcmp(req->path + 9, "XXXXXX", 6));
528
  check_permission(req->path, 0700);
529

530
  /* Check if req->path is actually a directory */
531
  r = uv_fs_stat(NULL, &stat_req, req->path, NULL);
532
  ASSERT_OK(r);
533
  ASSERT(((uv_stat_t*)stat_req.ptr)->st_mode & S_IFDIR);
534
  uv_fs_req_cleanup(&stat_req);
535
}
536

537

538
static void mkdtemp_cb(uv_fs_t* req) {
539
  ASSERT_PTR_EQ(req, &mkdtemp_req1);
540
  check_mkdtemp_result(req);
541
  mkdtemp_cb_count++;
542
}
543

544

545
static void check_mkstemp_result(uv_fs_t* req) {
546
  int r;
547

548
  ASSERT_EQ(req->fs_type, UV_FS_MKSTEMP);
549
  ASSERT_GE(req->result, 0);
550
  ASSERT(req->path);
551
  ASSERT_EQ(16, strlen(req->path));
552
  ASSERT_OK(memcmp(req->path, "test_file_", 10));
553
  ASSERT_NE(0, memcmp(req->path + 10, "XXXXXX", 6));
554
  check_permission(req->path, 0600);
555

556
  /* Check if req->path is actually a file */
557
  r = uv_fs_stat(NULL, &stat_req, req->path, NULL);
558
  ASSERT_OK(r);
559
  ASSERT(stat_req.statbuf.st_mode & S_IFREG);
560
  uv_fs_req_cleanup(&stat_req);
561
}
562

563

564
static void mkstemp_cb(uv_fs_t* req) {
565
  ASSERT_PTR_EQ(req, &mkstemp_req1);
566
  check_mkstemp_result(req);
567
  mkstemp_cb_count++;
568
}
569

570

571
static void rmdir_cb(uv_fs_t* req) {
572
  ASSERT_PTR_EQ(req, &rmdir_req);
573
  ASSERT_EQ(req->fs_type, UV_FS_RMDIR);
574
  ASSERT_OK(req->result);
575
  rmdir_cb_count++;
576
  ASSERT(req->path);
577
  ASSERT_OK(memcmp(req->path, "test_dir\0", 9));
578
  uv_fs_req_cleanup(req);
579
}
580

581

582
static void assert_is_file_type(uv_dirent_t dent) {
583
#ifdef HAVE_DIRENT_TYPES
584
  /*
585
   * For Apple and Windows, we know getdents is expected to work but for other
586
   * environments, the filesystem dictates whether or not getdents supports
587
   * returning the file type.
588
   *
589
   *   See:
590
   *     http://man7.org/linux/man-pages/man2/getdents.2.html
591
   *     https://github.com/libuv/libuv/issues/501
592
   */
593
  #if defined(__APPLE__) || defined(_WIN32)
594
    ASSERT_EQ(dent.type, UV_DIRENT_FILE);
595
  #else
596
    ASSERT(dent.type == UV_DIRENT_FILE || dent.type == UV_DIRENT_UNKNOWN);
597
  #endif
598
#else
599
  ASSERT_EQ(dent.type, UV_DIRENT_UNKNOWN);
600
#endif
601
}
602

603

604
static void scandir_cb(uv_fs_t* req) {
605
  uv_dirent_t dent;
606
  ASSERT_PTR_EQ(req, &scandir_req);
607
  ASSERT_EQ(req->fs_type, UV_FS_SCANDIR);
608
  ASSERT_EQ(2, req->result);
609
  ASSERT(req->ptr);
610

611
  while (UV_EOF != uv_fs_scandir_next(req, &dent)) {
612
    ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0);
613
    assert_is_file_type(dent);
614
  }
615
  scandir_cb_count++;
616
  ASSERT(req->path);
617
  ASSERT_OK(memcmp(req->path, "test_dir\0", 9));
618
  uv_fs_req_cleanup(req);
619
  ASSERT(!req->ptr);
620
}
621

622

623
static void empty_scandir_cb(uv_fs_t* req) {
624
  uv_dirent_t dent;
625

626
  ASSERT_PTR_EQ(req, &scandir_req);
627
  ASSERT_EQ(req->fs_type, UV_FS_SCANDIR);
628
  ASSERT_OK(req->result);
629
  ASSERT_NULL(req->ptr);
630
  ASSERT_EQ(UV_EOF, uv_fs_scandir_next(req, &dent));
631
  uv_fs_req_cleanup(req);
632
  scandir_cb_count++;
633
}
634

635
static void non_existent_scandir_cb(uv_fs_t* req) {
636
  uv_dirent_t dent;
637

638
  ASSERT_PTR_EQ(req, &scandir_req);
639
  ASSERT_EQ(req->fs_type, UV_FS_SCANDIR);
640
  ASSERT_EQ(req->result, UV_ENOENT);
641
  ASSERT_NULL(req->ptr);
642
  ASSERT_EQ(UV_ENOENT, uv_fs_scandir_next(req, &dent));
643
  uv_fs_req_cleanup(req);
644
  scandir_cb_count++;
645
}
646

647

648
static void file_scandir_cb(uv_fs_t* req) {
649
  ASSERT_PTR_EQ(req, &scandir_req);
650
  ASSERT_EQ(req->fs_type, UV_FS_SCANDIR);
651
  ASSERT_EQ(req->result, UV_ENOTDIR);
652
  ASSERT_NULL(req->ptr);
653
  uv_fs_req_cleanup(req);
654
  scandir_cb_count++;
655
}
656

657

658
static void stat_cb(uv_fs_t* req) {
659
  ASSERT_PTR_EQ(req, &stat_req);
660
  ASSERT(req->fs_type == UV_FS_STAT || req->fs_type == UV_FS_LSTAT);
661
  ASSERT_OK(req->result);
662
  ASSERT(req->ptr);
663
  stat_cb_count++;
664
  uv_fs_req_cleanup(req);
665
  ASSERT(!req->ptr);
666
}
667

668
static void stat_batch_cb(uv_fs_t* req) {
669
  ASSERT(req->fs_type == UV_FS_STAT || req->fs_type == UV_FS_LSTAT);
670
  ASSERT_OK(req->result);
671
  ASSERT(req->ptr);
672
  stat_cb_count++;
673
  uv_fs_req_cleanup(req);
674
  ASSERT(!req->ptr);
675
}
676

677

678
static void sendfile_cb(uv_fs_t* req) {
679
  ASSERT_PTR_EQ(req, &sendfile_req);
680
  ASSERT_EQ(req->fs_type, UV_FS_SENDFILE);
681
  ASSERT_EQ(65545, req->result);
682
  sendfile_cb_count++;
683
  uv_fs_req_cleanup(req);
684
}
685

686

687
static void sendfile_nodata_cb(uv_fs_t* req) {
688
  ASSERT_PTR_EQ(req, &sendfile_req);
689
  ASSERT_EQ(req->fs_type, UV_FS_SENDFILE);
690
  ASSERT_OK(req->result);
691
  sendfile_cb_count++;
692
  uv_fs_req_cleanup(req);
693
}
694

695

696
static void open_noent_cb(uv_fs_t* req) {
697
  ASSERT_EQ(req->fs_type, UV_FS_OPEN);
698
  ASSERT_EQ(req->result, UV_ENOENT);
699
  open_cb_count++;
700
  uv_fs_req_cleanup(req);
701
}
702

703
static void open_nametoolong_cb(uv_fs_t* req) {
704
  ASSERT_EQ(req->fs_type, UV_FS_OPEN);
705
  ASSERT_EQ(req->result, UV_ENAMETOOLONG);
706
  open_cb_count++;
707
  uv_fs_req_cleanup(req);
708
}
709

710
static void open_loop_cb(uv_fs_t* req) {
711
  ASSERT_EQ(req->fs_type, UV_FS_OPEN);
712
  ASSERT_EQ(req->result, UV_ELOOP);
713
  open_cb_count++;
714
  uv_fs_req_cleanup(req);
715
}
716

717

718
TEST_IMPL(fs_file_noent) {
719
  uv_fs_t req;
720
  int r;
721

722
  loop = uv_default_loop();
723

724
  r = uv_fs_open(NULL, &req, "does_not_exist", UV_FS_O_RDONLY, 0, NULL);
725
  ASSERT_EQ(r, UV_ENOENT);
726
  ASSERT_EQ(req.result, UV_ENOENT);
727
  uv_fs_req_cleanup(&req);
728

729
  r = uv_fs_open(loop, &req, "does_not_exist", UV_FS_O_RDONLY, 0,
730
                 open_noent_cb);
731
  ASSERT_OK(r);
732

733
  ASSERT_OK(open_cb_count);
734
  uv_run(loop, UV_RUN_DEFAULT);
735
  ASSERT_EQ(1, open_cb_count);
736

737
  /* TODO add EACCES test */
738

739
  MAKE_VALGRIND_HAPPY(loop);
740
  return 0;
741
}
742

743
TEST_IMPL(fs_file_nametoolong) {
744
  uv_fs_t req;
745
  int r;
746
  char name[TOO_LONG_NAME_LENGTH + 1];
747

748
  loop = uv_default_loop();
749

750
  memset(name, 'a', TOO_LONG_NAME_LENGTH);
751
  name[TOO_LONG_NAME_LENGTH] = 0;
752

753
  r = uv_fs_open(NULL, &req, name, UV_FS_O_RDONLY, 0, NULL);
754
  ASSERT_EQ(r, UV_ENAMETOOLONG);
755
  ASSERT_EQ(req.result, UV_ENAMETOOLONG);
756
  uv_fs_req_cleanup(&req);
757

758
  r = uv_fs_open(loop, &req, name, UV_FS_O_RDONLY, 0, open_nametoolong_cb);
759
  ASSERT_OK(r);
760

761
  ASSERT_OK(open_cb_count);
762
  uv_run(loop, UV_RUN_DEFAULT);
763
  ASSERT_EQ(1, open_cb_count);
764

765
  MAKE_VALGRIND_HAPPY(loop);
766
  return 0;
767
}
768

769
TEST_IMPL(fs_file_loop) {
770
  uv_fs_t req;
771
  int r;
772

773
  loop = uv_default_loop();
774

775
  unlink("test_symlink");
776
  r = uv_fs_symlink(NULL, &req, "test_symlink", "test_symlink", 0, NULL);
777
#ifdef _WIN32
778
  /*
779
   * Symlinks are only suported but only when elevated, otherwise
780
   * we'll see UV_EPERM.
781
   */
782
  if (r == UV_EPERM)
783
    return 0;
784
#elif defined(__MSYS__)
785
  /* MSYS2's approximation of symlinks with copies does not work for broken
786
     links.  */
787
  if (r == UV_ENOENT)
788
    return 0;
789
#endif
790
  ASSERT_OK(r);
791
  uv_fs_req_cleanup(&req);
792

793
  r = uv_fs_open(NULL, &req, "test_symlink", UV_FS_O_RDONLY, 0, NULL);
794
  ASSERT_EQ(r, UV_ELOOP);
795
  ASSERT_EQ(req.result, UV_ELOOP);
796
  uv_fs_req_cleanup(&req);
797

798
  r = uv_fs_open(loop, &req, "test_symlink", UV_FS_O_RDONLY, 0, open_loop_cb);
799
  ASSERT_OK(r);
800

801
  ASSERT_OK(open_cb_count);
802
  uv_run(loop, UV_RUN_DEFAULT);
803
  ASSERT_EQ(1, open_cb_count);
804

805
  unlink("test_symlink");
806

807
  MAKE_VALGRIND_HAPPY(loop);
808
  return 0;
809
}
810

811
static void check_utime(const char* path,
812
                        double atime,
813
                        double mtime,
814
                        int test_lutime) {
815
  uv_stat_t* s;
816
  uv_fs_t req;
817
  int r;
818

819
  if (test_lutime)
820
    r = uv_fs_lstat(loop, &req, path, NULL);
821
  else
822
    r = uv_fs_stat(loop, &req, path, NULL);
823

824
  ASSERT_OK(r);
825

826
  ASSERT_OK(req.result);
827
  s = &req.statbuf;
828

829
  if (s->st_atim.tv_nsec == 0 && s->st_mtim.tv_nsec == 0) {
830
    /*
831
     * Test sub-second timestamps only when supported (such as Windows with
832
     * NTFS). Some other platforms support sub-second timestamps, but that
833
     * support is filesystem-dependent. Notably OS X (HFS Plus) does NOT
834
     * support sub-second timestamps. But kernels may round or truncate in
835
     * either direction, so we may accept either possible answer.
836
     */
837
#ifdef _WIN32
838
    ASSERT_DOUBLE_EQ(atime, (long) atime);
839
    ASSERT_DOUBLE_EQ(mtime, (long) atime);
840
#endif
841
    if (atime > 0 || (long) atime == atime)
842
      ASSERT_EQ(s->st_atim.tv_sec, (long) atime);
843
    if (mtime > 0 || (long) mtime == mtime)
844
      ASSERT_EQ(s->st_mtim.tv_sec, (long) mtime);
845
    ASSERT_GE(s->st_atim.tv_sec, (long) atime - 1);
846
    ASSERT_GE(s->st_mtim.tv_sec, (long) mtime - 1);
847
    ASSERT_LE(s->st_atim.tv_sec, (long) atime);
848
    ASSERT_LE(s->st_mtim.tv_sec, (long) mtime);
849
  } else {
850
    double st_atim;
851
    double st_mtim;
852
#if !defined(__APPLE__) && !defined(__SUNPRO_C)
853
    /* TODO(vtjnash): would it be better to normalize this? */
854
    ASSERT_DOUBLE_GE(s->st_atim.tv_nsec, 0);
855
    ASSERT_DOUBLE_GE(s->st_mtim.tv_nsec, 0);
856
#endif
857
    st_atim = s->st_atim.tv_sec + s->st_atim.tv_nsec / 1e9;
858
    st_mtim = s->st_mtim.tv_sec + s->st_mtim.tv_nsec / 1e9;
859
    /*
860
     * Linux does not allow reading reliably the atime of a symlink
861
     * since readlink() can update it
862
     */
863
    if (!test_lutime)
864
      ASSERT_DOUBLE_EQ(st_atim, atime);
865
    ASSERT_DOUBLE_EQ(st_mtim, mtime);
866
  }
867

868
  uv_fs_req_cleanup(&req);
869
}
870

871

872
static void utime_cb(uv_fs_t* req) {
873
  utime_check_t* c;
874

875
  ASSERT_PTR_EQ(req, &utime_req);
876
  ASSERT_OK(req->result);
877
  ASSERT_EQ(req->fs_type, UV_FS_UTIME);
878

879
  c = req->data;
880
  check_utime(c->path, c->atime, c->mtime, /* test_lutime */ 0);
881

882
  uv_fs_req_cleanup(req);
883
  utime_cb_count++;
884
}
885

886

887
static void futime_cb(uv_fs_t* req) {
888
  utime_check_t* c;
889

890
  ASSERT_PTR_EQ(req, &futime_req);
891
  ASSERT_OK(req->result);
892
  ASSERT_EQ(req->fs_type, UV_FS_FUTIME);
893

894
  c = req->data;
895
  check_utime(c->path, c->atime, c->mtime, /* test_lutime */ 0);
896

897
  uv_fs_req_cleanup(req);
898
  futime_cb_count++;
899
}
900

901

902
static void lutime_cb(uv_fs_t* req) {
903
  utime_check_t* c;
904

905
  ASSERT_OK(req->result);
906
  ASSERT_EQ(req->fs_type, UV_FS_LUTIME);
907

908
  c = req->data;
909
  check_utime(c->path, c->atime, c->mtime, /* test_lutime */ 1);
910

911
  uv_fs_req_cleanup(req);
912
  lutime_cb_count++;
913
}
914

915

916
TEST_IMPL(fs_file_async) {
917
  int r;
918

919
  /* Setup. */
920
  unlink("test_file");
921
  unlink("test_file2");
922

923
  loop = uv_default_loop();
924

925
  r = uv_fs_open(loop, &open_req1, "test_file", UV_FS_O_WRONLY | UV_FS_O_CREAT,
926
      S_IRUSR | S_IWUSR, create_cb);
927
  ASSERT_OK(r);
928
  uv_run(loop, UV_RUN_DEFAULT);
929

930
  ASSERT_EQ(1, create_cb_count);
931
  ASSERT_EQ(1, write_cb_count);
932
  ASSERT_EQ(1, fsync_cb_count);
933
  ASSERT_EQ(1, fdatasync_cb_count);
934
  ASSERT_EQ(1, close_cb_count);
935

936
  r = uv_fs_rename(loop, &rename_req, "test_file", "test_file2", rename_cb);
937
  ASSERT_OK(r);
938

939
  uv_run(loop, UV_RUN_DEFAULT);
940
  ASSERT_EQ(1, create_cb_count);
941
  ASSERT_EQ(1, write_cb_count);
942
  ASSERT_EQ(1, close_cb_count);
943
  ASSERT_EQ(1, rename_cb_count);
944

945
  r = uv_fs_open(loop, &open_req1, "test_file2", UV_FS_O_RDWR, 0, open_cb);
946
  ASSERT_OK(r);
947

948
  uv_run(loop, UV_RUN_DEFAULT);
949
  ASSERT_EQ(1, open_cb_count);
950
  ASSERT_EQ(1, read_cb_count);
951
  ASSERT_EQ(2, close_cb_count);
952
  ASSERT_EQ(1, rename_cb_count);
953
  ASSERT_EQ(1, create_cb_count);
954
  ASSERT_EQ(1, write_cb_count);
955
  ASSERT_EQ(1, ftruncate_cb_count);
956

957
  r = uv_fs_open(loop, &open_req1, "test_file2", UV_FS_O_RDONLY, 0, open_cb);
958
  ASSERT_OK(r);
959

960
  uv_run(loop, UV_RUN_DEFAULT);
961
  ASSERT_EQ(2, open_cb_count);
962
  ASSERT_EQ(2, read_cb_count);
963
  ASSERT_EQ(3, close_cb_count);
964
  ASSERT_EQ(1, rename_cb_count);
965
  ASSERT_EQ(1, unlink_cb_count);
966
  ASSERT_EQ(1, create_cb_count);
967
  ASSERT_EQ(1, write_cb_count);
968
  ASSERT_EQ(1, ftruncate_cb_count);
969

970
  /* Cleanup. */
971
  unlink("test_file");
972
  unlink("test_file2");
973

974
  MAKE_VALGRIND_HAPPY(loop);
975
  return 0;
976
}
977

978

979
static void fs_file_sync(int add_flags) {
980
  int r;
981

982
  /* Setup. */
983
  unlink("test_file");
984
  unlink("test_file2");
985

986
  loop = uv_default_loop();
987

988
  r = uv_fs_open(loop, &open_req1, "test_file",
989
                 UV_FS_O_WRONLY | UV_FS_O_CREAT | add_flags, S_IWUSR | S_IRUSR,
990
                 NULL);
991
  ASSERT_GE(r, 0);
992
  ASSERT_GE(open_req1.result, 0);
993
  uv_fs_req_cleanup(&open_req1);
994

995
  iov = uv_buf_init(test_buf, sizeof(test_buf));
996
  r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
997
  ASSERT_GE(r, 0);
998
  ASSERT_GE(write_req.result, 0);
999
  uv_fs_req_cleanup(&write_req);
1000

1001
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
1002
  ASSERT_OK(r);
1003
  ASSERT_OK(close_req.result);
1004
  uv_fs_req_cleanup(&close_req);
1005

1006
  r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDWR | add_flags, 0,
1007
                 NULL);
1008
  ASSERT_GE(r, 0);
1009
  ASSERT_GE(open_req1.result, 0);
1010
  uv_fs_req_cleanup(&open_req1);
1011

1012
  iov = uv_buf_init(buf, sizeof(buf));
1013
  r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
1014
  ASSERT_GE(r, 0);
1015
  ASSERT_GE(read_req.result, 0);
1016
  ASSERT_OK(strcmp(buf, test_buf));
1017
  uv_fs_req_cleanup(&read_req);
1018

1019
  r = uv_fs_ftruncate(NULL, &ftruncate_req, open_req1.result, 7, NULL);
1020
  ASSERT_OK(r);
1021
  ASSERT_OK(ftruncate_req.result);
1022
  uv_fs_req_cleanup(&ftruncate_req);
1023

1024
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
1025
  ASSERT_OK(r);
1026
  ASSERT_OK(close_req.result);
1027
  uv_fs_req_cleanup(&close_req);
1028

1029
  r = uv_fs_rename(NULL, &rename_req, "test_file", "test_file2", NULL);
1030
  ASSERT_OK(r);
1031
  ASSERT_OK(rename_req.result);
1032
  uv_fs_req_cleanup(&rename_req);
1033

1034
  r = uv_fs_open(NULL, &open_req1, "test_file2", UV_FS_O_RDONLY | add_flags, 0,
1035
      NULL);
1036
  ASSERT_GE(r, 0);
1037
  ASSERT_GE(open_req1.result, 0);
1038
  uv_fs_req_cleanup(&open_req1);
1039

1040
  memset(buf, 0, sizeof(buf));
1041
  iov = uv_buf_init(buf, sizeof(buf));
1042
  r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
1043
  ASSERT_GE(r, 0);
1044
  ASSERT_GE(read_req.result, 0);
1045
  ASSERT_OK(strcmp(buf, "test-bu"));
1046
  uv_fs_req_cleanup(&read_req);
1047

1048
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
1049
  ASSERT_OK(r);
1050
  ASSERT_OK(close_req.result);
1051
  uv_fs_req_cleanup(&close_req);
1052

1053
  r = uv_fs_unlink(NULL, &unlink_req, "test_file2", NULL);
1054
  ASSERT_OK(r);
1055
  ASSERT_OK(unlink_req.result);
1056
  uv_fs_req_cleanup(&unlink_req);
1057

1058
  /* Cleanup */
1059
  unlink("test_file");
1060
  unlink("test_file2");
1061
}
1062
TEST_IMPL(fs_file_sync) {
1063
  fs_file_sync(0);
1064
  fs_file_sync(UV_FS_O_FILEMAP);
1065

1066
  MAKE_VALGRIND_HAPPY(uv_default_loop());
1067
  return 0;
1068
}
1069

1070

1071
static void fs_file_write_null_buffer(int add_flags) {
1072
  int r;
1073

1074
  /* Setup. */
1075
  unlink("test_file");
1076

1077
  loop = uv_default_loop();
1078

1079
  r = uv_fs_open(NULL, &open_req1, "test_file",
1080
                 UV_FS_O_WRONLY | UV_FS_O_CREAT | add_flags, S_IWUSR | S_IRUSR,
1081
                 NULL);
1082
  ASSERT_GE(r, 0);
1083
  ASSERT_GE(open_req1.result, 0);
1084
  uv_fs_req_cleanup(&open_req1);
1085

1086
  iov = uv_buf_init(NULL, 0);
1087
  r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
1088
  ASSERT_OK(r);
1089
  ASSERT_OK(write_req.result);
1090
  uv_fs_req_cleanup(&write_req);
1091

1092
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
1093
  ASSERT_OK(r);
1094
  ASSERT_OK(close_req.result);
1095
  uv_fs_req_cleanup(&close_req);
1096

1097
  unlink("test_file");
1098
}
1099
TEST_IMPL(fs_file_write_null_buffer) {
1100
  fs_file_write_null_buffer(0);
1101
  fs_file_write_null_buffer(UV_FS_O_FILEMAP);
1102

1103
  MAKE_VALGRIND_HAPPY(loop);
1104
  return 0;
1105
}
1106

1107

1108
TEST_IMPL(fs_async_dir) {
1109
  int r;
1110
  uv_dirent_t dent;
1111

1112
  /* Setup */
1113
  unlink("test_dir/file1");
1114
  unlink("test_dir/file2");
1115
  rmdir("test_dir");
1116

1117
  loop = uv_default_loop();
1118

1119
  r = uv_fs_mkdir(loop, &mkdir_req, "test_dir", 0755, mkdir_cb);
1120
  ASSERT_OK(r);
1121

1122
  uv_run(loop, UV_RUN_DEFAULT);
1123
  ASSERT_EQ(1, mkdir_cb_count);
1124

1125
  /* Create 2 files synchronously. */
1126
  r = uv_fs_open(NULL, &open_req1, "test_dir/file1",
1127
                 UV_FS_O_WRONLY | UV_FS_O_CREAT,
1128
      S_IWUSR | S_IRUSR, NULL);
1129
  ASSERT_GE(r, 0);
1130
  uv_fs_req_cleanup(&open_req1);
1131
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
1132
  ASSERT_OK(r);
1133
  uv_fs_req_cleanup(&close_req);
1134

1135
  r = uv_fs_open(NULL, &open_req1, "test_dir/file2",
1136
                 UV_FS_O_WRONLY | UV_FS_O_CREAT,
1137
      S_IWUSR | S_IRUSR, NULL);
1138
  ASSERT_GE(r, 0);
1139
  uv_fs_req_cleanup(&open_req1);
1140
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
1141
  ASSERT_OK(r);
1142
  uv_fs_req_cleanup(&close_req);
1143

1144
  r = uv_fs_scandir(loop, &scandir_req, "test_dir", 0, scandir_cb);
1145
  ASSERT_OK(r);
1146

1147
  uv_run(loop, UV_RUN_DEFAULT);
1148
  ASSERT_EQ(1, scandir_cb_count);
1149

1150
  /* sync uv_fs_scandir */
1151
  r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL);
1152
  ASSERT_EQ(2, r);
1153
  ASSERT_EQ(2, scandir_req.result);
1154
  ASSERT(scandir_req.ptr);
1155
  while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) {
1156
    ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0);
1157
    assert_is_file_type(dent);
1158
  }
1159
  uv_fs_req_cleanup(&scandir_req);
1160
  ASSERT(!scandir_req.ptr);
1161

1162
  r = uv_fs_stat(loop, &stat_req, "test_dir", stat_cb);
1163
  ASSERT_OK(r);
1164
  uv_run(loop, UV_RUN_DEFAULT);
1165

1166
  r = uv_fs_stat(loop, &stat_req, "test_dir/", stat_cb);
1167
  ASSERT_OK(r);
1168
  uv_run(loop, UV_RUN_DEFAULT);
1169

1170
  r = uv_fs_lstat(loop, &stat_req, "test_dir", stat_cb);
1171
  ASSERT_OK(r);
1172
  uv_run(loop, UV_RUN_DEFAULT);
1173

1174
  r = uv_fs_lstat(loop, &stat_req, "test_dir/", stat_cb);
1175
  ASSERT_OK(r);
1176
  uv_run(loop, UV_RUN_DEFAULT);
1177

1178
  ASSERT_EQ(4, stat_cb_count);
1179

1180
  r = uv_fs_unlink(loop, &unlink_req, "test_dir/file1", unlink_cb);
1181
  ASSERT_OK(r);
1182
  uv_run(loop, UV_RUN_DEFAULT);
1183
  ASSERT_EQ(1, unlink_cb_count);
1184

1185
  r = uv_fs_unlink(loop, &unlink_req, "test_dir/file2", unlink_cb);
1186
  ASSERT_OK(r);
1187
  uv_run(loop, UV_RUN_DEFAULT);
1188
  ASSERT_EQ(2, unlink_cb_count);
1189

1190
  r = uv_fs_rmdir(loop, &rmdir_req, "test_dir", rmdir_cb);
1191
  ASSERT_OK(r);
1192
  uv_run(loop, UV_RUN_DEFAULT);
1193
  ASSERT_EQ(1, rmdir_cb_count);
1194

1195
  /* Cleanup */
1196
  unlink("test_dir/file1");
1197
  unlink("test_dir/file2");
1198
  rmdir("test_dir");
1199

1200
  MAKE_VALGRIND_HAPPY(loop);
1201
  return 0;
1202
}
1203

1204

1205
static int test_sendfile(void (*setup)(int), uv_fs_cb cb, size_t expected_size) {
1206
  int f, r;
1207
  struct stat s1, s2;
1208
  uv_fs_t req;
1209
  char buf1[1];
1210

1211
  loop = uv_default_loop();
1212

1213
  /* Setup. */
1214
  unlink("test_file");
1215
  unlink("test_file2");
1216

1217
  f = open("test_file", UV_FS_O_WRONLY | UV_FS_O_CREAT, S_IWUSR | S_IRUSR);
1218
  ASSERT_NE(f, -1);
1219

1220
  if (setup != NULL)
1221
    setup(f);
1222

1223
  r = close(f);
1224
  ASSERT_OK(r);
1225

1226
  /* Test starts here. */
1227
  r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDWR, 0, NULL);
1228
  ASSERT_GE(r, 0);
1229
  ASSERT_GE(open_req1.result, 0);
1230
  uv_fs_req_cleanup(&open_req1);
1231

1232
  r = uv_fs_open(NULL, &open_req2, "test_file2", UV_FS_O_WRONLY | UV_FS_O_CREAT,
1233
      S_IWUSR | S_IRUSR, NULL);
1234
  ASSERT_GE(r, 0);
1235
  ASSERT_GE(open_req2.result, 0);
1236
  uv_fs_req_cleanup(&open_req2);
1237

1238
  r = uv_fs_sendfile(loop, &sendfile_req, open_req2.result, open_req1.result,
1239
      1, 131072, cb);
1240
  ASSERT_OK(r);
1241
  uv_run(loop, UV_RUN_DEFAULT);
1242

1243
  ASSERT_EQ(1, sendfile_cb_count);
1244

1245
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
1246
  ASSERT_OK(r);
1247
  uv_fs_req_cleanup(&close_req);
1248
  r = uv_fs_close(NULL, &close_req, open_req2.result, NULL);
1249
  ASSERT_OK(r);
1250
  uv_fs_req_cleanup(&close_req);
1251

1252
  memset(&s1, 0, sizeof(s1));
1253
  memset(&s2, 0, sizeof(s2));
1254
  ASSERT_OK(stat("test_file", &s1));
1255
  ASSERT_OK(stat("test_file2", &s2));
1256
  ASSERT_EQ(s2.st_size, expected_size);
1257

1258
  if (expected_size > 0) {
1259
    ASSERT_UINT64_EQ(s1.st_size, s2.st_size + 1);
1260
    r = uv_fs_open(NULL, &open_req1, "test_file2", UV_FS_O_RDWR, 0, NULL);
1261
    ASSERT_GE(r, 0);
1262
    ASSERT_GE(open_req1.result, 0);
1263
    uv_fs_req_cleanup(&open_req1);
1264

1265
    memset(buf1, 0, sizeof(buf1));
1266
    iov = uv_buf_init(buf1, sizeof(buf1));
1267
    r = uv_fs_read(NULL, &req, open_req1.result, &iov, 1, -1, NULL);
1268
    ASSERT_GE(r, 0);
1269
    ASSERT_GE(req.result, 0);
1270
    ASSERT_EQ(buf1[0], 'e'); /* 'e' from begin */
1271
    uv_fs_req_cleanup(&req);
1272
  } else {
1273
    ASSERT_UINT64_EQ(s1.st_size, s2.st_size);
1274
  }
1275

1276
  /* Cleanup. */
1277
  unlink("test_file");
1278
  unlink("test_file2");
1279

1280
  MAKE_VALGRIND_HAPPY(loop);
1281
  return 0;
1282
}
1283

1284

1285
static void sendfile_setup(int f) {
1286
  ASSERT_EQ(6, write(f, "begin\n", 6));
1287
  ASSERT_EQ(65542, lseek(f, 65536, SEEK_CUR));
1288
  ASSERT_EQ(4, write(f, "end\n", 4));
1289
}
1290

1291

1292
TEST_IMPL(fs_async_sendfile) {
1293
  return test_sendfile(sendfile_setup, sendfile_cb, 65545);
1294
}
1295

1296

1297
TEST_IMPL(fs_async_sendfile_nodata) {
1298
  return test_sendfile(NULL, sendfile_nodata_cb, 0);
1299
}
1300

1301

1302
TEST_IMPL(fs_mkdtemp) {
1303
  int r;
1304
  const char* path_template = "test_dir_XXXXXX";
1305

1306
  loop = uv_default_loop();
1307

1308
  r = uv_fs_mkdtemp(loop, &mkdtemp_req1, path_template, mkdtemp_cb);
1309
  ASSERT_OK(r);
1310

1311
  uv_run(loop, UV_RUN_DEFAULT);
1312
  ASSERT_EQ(1, mkdtemp_cb_count);
1313

1314
  /* sync mkdtemp */
1315
  r = uv_fs_mkdtemp(NULL, &mkdtemp_req2, path_template, NULL);
1316
  ASSERT_OK(r);
1317
  check_mkdtemp_result(&mkdtemp_req2);
1318

1319
  /* mkdtemp return different values on subsequent calls */
1320
  ASSERT_NE(0, strcmp(mkdtemp_req1.path, mkdtemp_req2.path));
1321

1322
  /* Cleanup */
1323
  rmdir(mkdtemp_req1.path);
1324
  rmdir(mkdtemp_req2.path);
1325
  uv_fs_req_cleanup(&mkdtemp_req1);
1326
  uv_fs_req_cleanup(&mkdtemp_req2);
1327

1328
  MAKE_VALGRIND_HAPPY(loop);
1329
  return 0;
1330
}
1331

1332

1333
TEST_IMPL(fs_mkstemp) {
1334
  int r;
1335
  int fd;
1336
  const char path_template[] = "test_file_XXXXXX";
1337
  uv_fs_t req;
1338

1339
  loop = uv_default_loop();
1340

1341
  r = uv_fs_mkstemp(loop, &mkstemp_req1, path_template, mkstemp_cb);
1342
  ASSERT_OK(r);
1343

1344
  uv_run(loop, UV_RUN_DEFAULT);
1345
  ASSERT_EQ(1, mkstemp_cb_count);
1346

1347
  /* sync mkstemp */
1348
  r = uv_fs_mkstemp(NULL, &mkstemp_req2, path_template, NULL);
1349
  ASSERT_GE(r, 0);
1350
  check_mkstemp_result(&mkstemp_req2);
1351

1352
  /* mkstemp return different values on subsequent calls */
1353
  ASSERT_NE(0, strcmp(mkstemp_req1.path, mkstemp_req2.path));
1354

1355
  /* invalid template returns EINVAL */
1356
  ASSERT_EQ(UV_EINVAL, uv_fs_mkstemp(NULL, &mkstemp_req3, "test_file", NULL));
1357

1358
  /* Make sure that path is empty string */
1359
  ASSERT_OK(strlen(mkstemp_req3.path));
1360

1361
  uv_fs_req_cleanup(&mkstemp_req3);
1362

1363
  /* We can write to the opened file */
1364
  iov = uv_buf_init(test_buf, sizeof(test_buf));
1365
  r = uv_fs_write(NULL, &req, mkstemp_req1.result, &iov, 1, -1, NULL);
1366
  ASSERT_EQ(r, sizeof(test_buf));
1367
  ASSERT_EQ(req.result, sizeof(test_buf));
1368
  uv_fs_req_cleanup(&req);
1369

1370
  /* Cleanup */
1371
  uv_fs_close(NULL, &req, mkstemp_req1.result, NULL);
1372
  uv_fs_req_cleanup(&req);
1373
  uv_fs_close(NULL, &req, mkstemp_req2.result, NULL);
1374
  uv_fs_req_cleanup(&req);
1375

1376
  fd = uv_fs_open(NULL, &req, mkstemp_req1.path, UV_FS_O_RDONLY, 0, NULL);
1377
  ASSERT_GE(fd, 0);
1378
  uv_fs_req_cleanup(&req);
1379

1380
  memset(buf, 0, sizeof(buf));
1381
  iov = uv_buf_init(buf, sizeof(buf));
1382
  r = uv_fs_read(NULL, &req, fd, &iov, 1, -1, NULL);
1383
  ASSERT_GE(r, 0);
1384
  ASSERT_GE(req.result, 0);
1385
  ASSERT_OK(strcmp(buf, test_buf));
1386
  uv_fs_req_cleanup(&req);
1387

1388
  uv_fs_close(NULL, &req, fd, NULL);
1389
  uv_fs_req_cleanup(&req);
1390

1391
  unlink(mkstemp_req1.path);
1392
  unlink(mkstemp_req2.path);
1393
  uv_fs_req_cleanup(&mkstemp_req1);
1394
  uv_fs_req_cleanup(&mkstemp_req2);
1395

1396
  MAKE_VALGRIND_HAPPY(loop);
1397
  return 0;
1398
}
1399

1400

1401
TEST_IMPL(fs_fstat) {
1402
  int r;
1403
  uv_fs_t req;
1404
  uv_file file;
1405
  uv_stat_t* s;
1406
#ifndef _WIN32
1407
  struct stat t;
1408
#endif
1409

1410
#if defined(__s390__) && defined(__QEMU__)
1411
  /* qemu-user-s390x has this weird bug where statx() reports nanoseconds
1412
   * but plain fstat() does not.
1413
   */
1414
  RETURN_SKIP("Test does not currently work in QEMU");
1415
#endif
1416

1417
  /* Setup. */
1418
  unlink("test_file");
1419

1420
  loop = uv_default_loop();
1421

1422
  r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT,
1423
      S_IWUSR | S_IRUSR, NULL);
1424
  ASSERT_GE(r, 0);
1425
  ASSERT_GE(req.result, 0);
1426
  file = req.result;
1427
  uv_fs_req_cleanup(&req);
1428

1429
#ifndef _WIN32
1430
  memset(&t, 0, sizeof(t));
1431
  ASSERT_OK(fstat(file, &t));
1432
  ASSERT_OK(uv_fs_fstat(NULL, &req, file, NULL));
1433
  ASSERT_OK(req.result);
1434
  s = req.ptr;
1435
# if defined(__APPLE__)
1436
  ASSERT_EQ(s->st_birthtim.tv_sec, t.st_birthtimespec.tv_sec);
1437
  ASSERT_EQ(s->st_birthtim.tv_nsec, t.st_birthtimespec.tv_nsec);
1438
# elif defined(__linux__)
1439
  /* If statx() is supported, the birth time should be equal to the change time
1440
   * because we just created the file. On older kernels, it's set to zero.
1441
   */
1442
  ASSERT(s->st_birthtim.tv_sec == 0 ||
1443
         s->st_birthtim.tv_sec == t.st_ctim.tv_sec);
1444
  ASSERT(s->st_birthtim.tv_nsec == 0 ||
1445
         s->st_birthtim.tv_nsec == t.st_ctim.tv_nsec);
1446
# endif
1447
#endif
1448

1449
  iov = uv_buf_init(test_buf, sizeof(test_buf));
1450
  r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
1451
  ASSERT_EQ(r, sizeof(test_buf));
1452
  ASSERT_EQ(req.result, sizeof(test_buf));
1453
  uv_fs_req_cleanup(&req);
1454

1455
  memset(&req.statbuf, 0xaa, sizeof(req.statbuf));
1456
  r = uv_fs_fstat(NULL, &req, file, NULL);
1457
  ASSERT_OK(r);
1458
  ASSERT_OK(req.result);
1459
  s = req.ptr;
1460
  ASSERT_EQ(s->st_size, sizeof(test_buf));
1461

1462
#ifndef _WIN32
1463
  r = fstat(file, &t);
1464
  ASSERT_OK(r);
1465

1466
  ASSERT_EQ(s->st_dev, (uint64_t) t.st_dev);
1467
  ASSERT_EQ(s->st_mode, (uint64_t) t.st_mode);
1468
  ASSERT_EQ(s->st_nlink, (uint64_t) t.st_nlink);
1469
  ASSERT_EQ(s->st_uid, (uint64_t) t.st_uid);
1470
  ASSERT_EQ(s->st_gid, (uint64_t) t.st_gid);
1471
  ASSERT_EQ(s->st_rdev, (uint64_t) t.st_rdev);
1472
  ASSERT_EQ(s->st_ino, (uint64_t) t.st_ino);
1473
  ASSERT_EQ(s->st_size, (uint64_t) t.st_size);
1474
  ASSERT_EQ(s->st_blksize, (uint64_t) t.st_blksize);
1475
  ASSERT_EQ(s->st_blocks, (uint64_t) t.st_blocks);
1476
#if defined(__APPLE__)
1477
  ASSERT_EQ(s->st_atim.tv_sec, t.st_atimespec.tv_sec);
1478
  ASSERT_EQ(s->st_atim.tv_nsec, t.st_atimespec.tv_nsec);
1479
  ASSERT_EQ(s->st_mtim.tv_sec, t.st_mtimespec.tv_sec);
1480
  ASSERT_EQ(s->st_mtim.tv_nsec, t.st_mtimespec.tv_nsec);
1481
  ASSERT_EQ(s->st_ctim.tv_sec, t.st_ctimespec.tv_sec);
1482
  ASSERT_EQ(s->st_ctim.tv_nsec, t.st_ctimespec.tv_nsec);
1483
#elif defined(_AIX)    || \
1484
      defined(__MVS__)
1485
  ASSERT_EQ(s->st_atim.tv_sec, t.st_atime);
1486
  ASSERT_OK(s->st_atim.tv_nsec);
1487
  ASSERT_EQ(s->st_mtim.tv_sec, t.st_mtime);
1488
  ASSERT_OK(s->st_mtim.tv_nsec);
1489
  ASSERT_EQ(s->st_ctim.tv_sec, t.st_ctime);
1490
  ASSERT_OK(s->st_ctim.tv_nsec);
1491
#elif defined(__ANDROID__)
1492
  ASSERT_EQ(s->st_atim.tv_sec, t.st_atime);
1493
  ASSERT_EQ(s->st_atim.tv_nsec, t.st_atimensec);
1494
  ASSERT_EQ(s->st_mtim.tv_sec, t.st_mtime);
1495
  ASSERT_EQ(s->st_mtim.tv_nsec, t.st_mtimensec);
1496
  ASSERT_EQ(s->st_ctim.tv_sec, t.st_ctime);
1497
  ASSERT_EQ(s->st_ctim.tv_nsec, t.st_ctimensec);
1498
#elif defined(__sun)           || \
1499
      defined(__DragonFly__)   || \
1500
      defined(__FreeBSD__)     || \
1501
      defined(__OpenBSD__)     || \
1502
      defined(__NetBSD__)      || \
1503
      defined(_GNU_SOURCE)     || \
1504
      defined(_BSD_SOURCE)     || \
1505
      defined(_SVID_SOURCE)    || \
1506
      defined(_XOPEN_SOURCE)   || \
1507
      defined(_DEFAULT_SOURCE)
1508
  ASSERT_EQ(s->st_atim.tv_sec, t.st_atim.tv_sec);
1509
  ASSERT_EQ(s->st_atim.tv_nsec, t.st_atim.tv_nsec);
1510
  ASSERT_EQ(s->st_mtim.tv_sec, t.st_mtim.tv_sec);
1511
  ASSERT_EQ(s->st_mtim.tv_nsec, t.st_mtim.tv_nsec);
1512
  ASSERT_EQ(s->st_ctim.tv_sec, t.st_ctim.tv_sec);
1513
  ASSERT_EQ(s->st_ctim.tv_nsec, t.st_ctim.tv_nsec);
1514
# if defined(__FreeBSD__)    || \
1515
     defined(__NetBSD__)
1516
  ASSERT_EQ(s->st_birthtim.tv_sec, t.st_birthtim.tv_sec);
1517
  ASSERT_EQ(s->st_birthtim.tv_nsec, t.st_birthtim.tv_nsec);
1518
# endif
1519
#else
1520
  ASSERT_EQ(s->st_atim.tv_sec, t.st_atime);
1521
  ASSERT_OK(s->st_atim.tv_nsec);
1522
  ASSERT_EQ(s->st_mtim.tv_sec, t.st_mtime);
1523
  ASSERT_OK(s->st_mtim.tv_nsec);
1524
  ASSERT_EQ(s->st_ctim.tv_sec, t.st_ctime);
1525
  ASSERT_OK(s->st_ctim.tv_nsec);
1526
#endif
1527
#endif
1528

1529
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
1530
  ASSERT_EQ(s->st_flags, t.st_flags);
1531
  ASSERT_EQ(s->st_gen, t.st_gen);
1532
#else
1533
  ASSERT_OK(s->st_flags);
1534
  ASSERT_OK(s->st_gen);
1535
#endif
1536

1537
  uv_fs_req_cleanup(&req);
1538

1539
  /* Now do the uv_fs_fstat call asynchronously */
1540
  r = uv_fs_fstat(loop, &req, file, fstat_cb);
1541
  ASSERT_OK(r);
1542
  uv_run(loop, UV_RUN_DEFAULT);
1543
  ASSERT_EQ(1, fstat_cb_count);
1544

1545

1546
  r = uv_fs_close(NULL, &req, file, NULL);
1547
  ASSERT_OK(r);
1548
  ASSERT_OK(req.result);
1549
  uv_fs_req_cleanup(&req);
1550

1551
  /*
1552
   * Run the loop just to check we don't have make any extraneous uv_ref()
1553
   * calls. This should drop out immediately.
1554
   */
1555
  uv_run(loop, UV_RUN_DEFAULT);
1556

1557
  /* Cleanup. */
1558
  unlink("test_file");
1559

1560
  MAKE_VALGRIND_HAPPY(loop);
1561
  return 0;
1562
}
1563

1564

1565
TEST_IMPL(fs_fstat_stdio) {
1566
  int fd;
1567
  int res;
1568
  uv_fs_t req;
1569
#ifdef _WIN32
1570
  uv_stat_t* st;
1571
  DWORD ft;
1572
#endif
1573

1574
  for (fd = 0; fd <= 2; ++fd) {
1575
    res = uv_fs_fstat(NULL, &req, fd, NULL);
1576
    ASSERT_OK(res);
1577
    ASSERT_OK(req.result);
1578

1579
#ifdef _WIN32
1580
    st = req.ptr;
1581
    ft = uv_guess_handle(fd);
1582
    switch (ft) {
1583
    case UV_TTY:
1584
    case UV_NAMED_PIPE:
1585
      ASSERT_EQ(st->st_mode, (ft == UV_TTY ? S_IFCHR : S_IFIFO));
1586
      ASSERT_EQ(1, st->st_nlink);
1587
      ASSERT_EQ(st->st_rdev,
1588
                (ft == UV_TTY ? FILE_DEVICE_CONSOLE : FILE_DEVICE_NAMED_PIPE)
1589
                << 16);
1590
      break;
1591
    default:
1592
      break;
1593
    }
1594
#endif
1595

1596
    uv_fs_req_cleanup(&req);
1597
  }
1598

1599
  MAKE_VALGRIND_HAPPY(uv_default_loop());
1600
  return 0;
1601
}
1602

1603

1604
TEST_IMPL(fs_access) {
1605
  int r;
1606
  uv_fs_t req;
1607
  uv_file file;
1608

1609
  /* Setup. */
1610
  unlink("test_file");
1611
  rmdir("test_dir");
1612

1613
  loop = uv_default_loop();
1614

1615
  /* File should not exist */
1616
  r = uv_fs_access(NULL, &req, "test_file", F_OK, NULL);
1617
  ASSERT_LT(r, 0);
1618
  ASSERT_LT(req.result, 0);
1619
  uv_fs_req_cleanup(&req);
1620

1621
  /* File should not exist */
1622
  r = uv_fs_access(loop, &req, "test_file", F_OK, access_cb);
1623
  ASSERT_OK(r);
1624
  uv_run(loop, UV_RUN_DEFAULT);
1625
  ASSERT_EQ(1, access_cb_count);
1626
  access_cb_count = 0; /* reset for the next test */
1627

1628
  /* Create file */
1629
  r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT,
1630
                 S_IWUSR | S_IRUSR, NULL);
1631
  ASSERT_GE(r, 0);
1632
  ASSERT_GE(req.result, 0);
1633
  file = req.result;
1634
  uv_fs_req_cleanup(&req);
1635

1636
  /* File should exist */
1637
  r = uv_fs_access(NULL, &req, "test_file", F_OK, NULL);
1638
  ASSERT_OK(r);
1639
  ASSERT_OK(req.result);
1640
  uv_fs_req_cleanup(&req);
1641

1642
  /* File should exist */
1643
  r = uv_fs_access(loop, &req, "test_file", F_OK, access_cb);
1644
  ASSERT_OK(r);
1645
  uv_run(loop, UV_RUN_DEFAULT);
1646
  ASSERT_EQ(1, access_cb_count);
1647
  access_cb_count = 0; /* reset for the next test */
1648

1649
  /* Close file */
1650
  r = uv_fs_close(NULL, &req, file, NULL);
1651
  ASSERT_OK(r);
1652
  ASSERT_OK(req.result);
1653
  uv_fs_req_cleanup(&req);
1654

1655
  /* Directory access */
1656
  r = uv_fs_mkdir(NULL, &req, "test_dir", 0777, NULL);
1657
  ASSERT_OK(r);
1658
  uv_fs_req_cleanup(&req);
1659

1660
  r = uv_fs_access(NULL, &req, "test_dir", W_OK, NULL);
1661
  ASSERT_OK(r);
1662
  ASSERT_OK(req.result);
1663
  uv_fs_req_cleanup(&req);
1664

1665
  /*
1666
   * Run the loop just to check we don't have make any extraneous uv_ref()
1667
   * calls. This should drop out immediately.
1668
   */
1669
  uv_run(loop, UV_RUN_DEFAULT);
1670

1671
  /* Cleanup. */
1672
  unlink("test_file");
1673
  rmdir("test_dir");
1674

1675
  MAKE_VALGRIND_HAPPY(loop);
1676
  return 0;
1677
}
1678

1679

1680
TEST_IMPL(fs_chmod) {
1681
  int r;
1682
  uv_fs_t req;
1683
  uv_file file;
1684

1685
  /* Setup. */
1686
  unlink("test_file");
1687

1688
  loop = uv_default_loop();
1689

1690
  r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT,
1691
      S_IWUSR | S_IRUSR, NULL);
1692
  ASSERT_GE(r, 0);
1693
  ASSERT_GE(req.result, 0);
1694
  file = req.result;
1695
  uv_fs_req_cleanup(&req);
1696

1697
  iov = uv_buf_init(test_buf, sizeof(test_buf));
1698
  r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
1699
  ASSERT_EQ(r, sizeof(test_buf));
1700
  ASSERT_EQ(req.result, sizeof(test_buf));
1701
  uv_fs_req_cleanup(&req);
1702

1703
#ifndef _WIN32
1704
  /* Make the file write-only */
1705
  r = uv_fs_chmod(NULL, &req, "test_file", 0200, NULL);
1706
  ASSERT_OK(r);
1707
  ASSERT_OK(req.result);
1708
  uv_fs_req_cleanup(&req);
1709

1710
  check_permission("test_file", 0200);
1711
#endif
1712

1713
  /* Make the file read-only */
1714
  r = uv_fs_chmod(NULL, &req, "test_file", 0400, NULL);
1715
  ASSERT_OK(r);
1716
  ASSERT_OK(req.result);
1717
  uv_fs_req_cleanup(&req);
1718

1719
  check_permission("test_file", 0400);
1720

1721
  /* Make the file read+write with sync uv_fs_fchmod */
1722
  r = uv_fs_fchmod(NULL, &req, file, 0600, NULL);
1723
  ASSERT_OK(r);
1724
  ASSERT_OK(req.result);
1725
  uv_fs_req_cleanup(&req);
1726

1727
  check_permission("test_file", 0600);
1728

1729
#ifndef _WIN32
1730
  /* async chmod */
1731
  {
1732
    static int mode = 0200;
1733
    req.data = &mode;
1734
  }
1735
  r = uv_fs_chmod(loop, &req, "test_file", 0200, chmod_cb);
1736
  ASSERT_OK(r);
1737
  uv_run(loop, UV_RUN_DEFAULT);
1738
  ASSERT_EQ(1, chmod_cb_count);
1739
  chmod_cb_count = 0; /* reset for the next test */
1740
#endif
1741

1742
  /* async chmod */
1743
  {
1744
    static int mode = 0400;
1745
    req.data = &mode;
1746
  }
1747
  r = uv_fs_chmod(loop, &req, "test_file", 0400, chmod_cb);
1748
  ASSERT_OK(r);
1749
  uv_run(loop, UV_RUN_DEFAULT);
1750
  ASSERT_EQ(1, chmod_cb_count);
1751

1752
  /* async fchmod */
1753
  {
1754
    static int mode = 0600;
1755
    req.data = &mode;
1756
  }
1757
  r = uv_fs_fchmod(loop, &req, file, 0600, fchmod_cb);
1758
  ASSERT_OK(r);
1759
  uv_run(loop, UV_RUN_DEFAULT);
1760
  ASSERT_EQ(1, fchmod_cb_count);
1761

1762
  uv_fs_close(loop, &req, file, NULL);
1763

1764
  /*
1765
   * Run the loop just to check we don't have make any extraneous uv_ref()
1766
   * calls. This should drop out immediately.
1767
   */
1768
  uv_run(loop, UV_RUN_DEFAULT);
1769

1770
  /* Cleanup. */
1771
  unlink("test_file");
1772

1773
  MAKE_VALGRIND_HAPPY(loop);
1774
  return 0;
1775
}
1776

1777

1778
TEST_IMPL(fs_unlink_readonly) {
1779
  int r;
1780
  uv_fs_t req;
1781
  uv_file file;
1782

1783
  /* Setup. */
1784
  unlink("test_file");
1785

1786
  loop = uv_default_loop();
1787

1788
  r = uv_fs_open(NULL,
1789
                 &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT,
1790
                 S_IWUSR | S_IRUSR,
1791
                 NULL);
1792
  ASSERT_GE(r, 0);
1793
  ASSERT_GE(req.result, 0);
1794
  file = req.result;
1795
  uv_fs_req_cleanup(&req);
1796

1797
  iov = uv_buf_init(test_buf, sizeof(test_buf));
1798
  r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
1799
  ASSERT_EQ(r, sizeof(test_buf));
1800
  ASSERT_EQ(req.result, sizeof(test_buf));
1801
  uv_fs_req_cleanup(&req);
1802

1803
  uv_fs_close(loop, &req, file, NULL);
1804

1805
  /* Make the file read-only */
1806
  r = uv_fs_chmod(NULL, &req, "test_file", 0400, NULL);
1807
  ASSERT_OK(r);
1808
  ASSERT_OK(req.result);
1809
  uv_fs_req_cleanup(&req);
1810

1811
  check_permission("test_file", 0400);
1812

1813
  /* Try to unlink the file */
1814
  r = uv_fs_unlink(NULL, &req, "test_file", NULL);
1815
  ASSERT_OK(r);
1816
  ASSERT_OK(req.result);
1817
  uv_fs_req_cleanup(&req);
1818

1819
  /*
1820
  * Run the loop just to check we don't have make any extraneous uv_ref()
1821
  * calls. This should drop out immediately.
1822
  */
1823
  uv_run(loop, UV_RUN_DEFAULT);
1824

1825
  /* Cleanup. */
1826
  uv_fs_chmod(NULL, &req, "test_file", 0600, NULL);
1827
  uv_fs_req_cleanup(&req);
1828
  unlink("test_file");
1829

1830
  MAKE_VALGRIND_HAPPY(loop);
1831
  return 0;
1832
}
1833

1834
#ifdef _WIN32
1835
TEST_IMPL(fs_unlink_archive_readonly) {
1836
  int r;
1837
  uv_fs_t req;
1838
  uv_file file;
1839

1840
  /* Setup. */
1841
  unlink("test_file");
1842

1843
  loop = uv_default_loop();
1844

1845
  r = uv_fs_open(NULL,
1846
                 &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT,
1847
                 S_IWUSR | S_IRUSR,
1848
                 NULL);
1849
  ASSERT_GE(r, 0);
1850
  ASSERT_GE(req.result, 0);
1851
  file = req.result;
1852
  uv_fs_req_cleanup(&req);
1853

1854
  iov = uv_buf_init(test_buf, sizeof(test_buf));
1855
  r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
1856
  ASSERT_EQ(r, sizeof(test_buf));
1857
  ASSERT_EQ(req.result, sizeof(test_buf));
1858
  uv_fs_req_cleanup(&req);
1859

1860
  uv_fs_close(loop, &req, file, NULL);
1861

1862
  /* Make the file read-only and clear archive flag */
1863
  r = SetFileAttributes("test_file", FILE_ATTRIBUTE_READONLY);
1864
  ASSERT(r);
1865
  uv_fs_req_cleanup(&req);
1866

1867
  check_permission("test_file", 0400);
1868

1869
  /* Try to unlink the file */
1870
  r = uv_fs_unlink(NULL, &req, "test_file", NULL);
1871
  ASSERT_OK(r);
1872
  ASSERT_OK(req.result);
1873
  uv_fs_req_cleanup(&req);
1874

1875
  /*
1876
  * Run the loop just to check we don't have make any extraneous uv_ref()
1877
  * calls. This should drop out immediately.
1878
  */
1879
  uv_run(loop, UV_RUN_DEFAULT);
1880

1881
  /* Cleanup. */
1882
  uv_fs_chmod(NULL, &req, "test_file", 0600, NULL);
1883
  uv_fs_req_cleanup(&req);
1884
  unlink("test_file");
1885

1886
  MAKE_VALGRIND_HAPPY(loop);
1887
  return 0;
1888
}
1889
#endif
1890

1891
TEST_IMPL(fs_chown) {
1892
  int r;
1893
  uv_fs_t req;
1894
  uv_file file;
1895

1896
  /* Setup. */
1897
  unlink("test_file");
1898
  unlink("test_file_link");
1899

1900
  loop = uv_default_loop();
1901

1902
  r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT,
1903
      S_IWUSR | S_IRUSR, NULL);
1904
  ASSERT_GE(r, 0);
1905
  ASSERT_GE(req.result, 0);
1906
  file = req.result;
1907
  uv_fs_req_cleanup(&req);
1908

1909
  /* sync chown */
1910
  r = uv_fs_chown(NULL, &req, "test_file", -1, -1, NULL);
1911
  ASSERT_OK(r);
1912
  ASSERT_OK(req.result);
1913
  uv_fs_req_cleanup(&req);
1914

1915
  /* sync fchown */
1916
  r = uv_fs_fchown(NULL, &req, file, -1, -1, NULL);
1917
  ASSERT_OK(r);
1918
  ASSERT_OK(req.result);
1919
  uv_fs_req_cleanup(&req);
1920

1921
  /* async chown */
1922
  r = uv_fs_chown(loop, &req, "test_file", -1, -1, chown_cb);
1923
  ASSERT_OK(r);
1924
  uv_run(loop, UV_RUN_DEFAULT);
1925
  ASSERT_EQ(1, chown_cb_count);
1926

1927
#ifndef __MVS__
1928
  /* chown to root (fail) */
1929
  chown_cb_count = 0;
1930
  r = uv_fs_chown(loop, &req, "test_file", 0, 0, chown_root_cb);
1931
  ASSERT_OK(r);
1932
  uv_run(loop, UV_RUN_DEFAULT);
1933
  ASSERT_EQ(1, chown_cb_count);
1934
#endif
1935

1936
  /* async fchown */
1937
  r = uv_fs_fchown(loop, &req, file, -1, -1, fchown_cb);
1938
  ASSERT_OK(r);
1939
  uv_run(loop, UV_RUN_DEFAULT);
1940
  ASSERT_EQ(1, fchown_cb_count);
1941

1942
#ifndef __HAIKU__
1943
  /* Haiku doesn't support hardlink */
1944
  /* sync link */
1945
  r = uv_fs_link(NULL, &req, "test_file", "test_file_link", NULL);
1946
  ASSERT_OK(r);
1947
  ASSERT_OK(req.result);
1948
  uv_fs_req_cleanup(&req);
1949

1950
  /* sync lchown */
1951
  r = uv_fs_lchown(NULL, &req, "test_file_link", -1, -1, NULL);
1952
  ASSERT_OK(r);
1953
  ASSERT_OK(req.result);
1954
  uv_fs_req_cleanup(&req);
1955

1956
  /* async lchown */
1957
  r = uv_fs_lchown(loop, &req, "test_file_link", -1, -1, lchown_cb);
1958
  ASSERT_OK(r);
1959
  uv_run(loop, UV_RUN_DEFAULT);
1960
  ASSERT_EQ(1, lchown_cb_count);
1961
#endif
1962

1963
  /* Close file */
1964
  r = uv_fs_close(NULL, &req, file, NULL);
1965
  ASSERT_OK(r);
1966
  ASSERT_OK(req.result);
1967
  uv_fs_req_cleanup(&req);
1968

1969
  /*
1970
   * Run the loop just to check we don't have make any extraneous uv_ref()
1971
   * calls. This should drop out immediately.
1972
   */
1973
  uv_run(loop, UV_RUN_DEFAULT);
1974

1975
  /* Cleanup. */
1976
  unlink("test_file");
1977
  unlink("test_file_link");
1978

1979
  MAKE_VALGRIND_HAPPY(loop);
1980
  return 0;
1981
}
1982

1983

1984
TEST_IMPL(fs_link) {
1985
  int r;
1986
  uv_fs_t req;
1987
  uv_file file;
1988
  uv_file link;
1989

1990
  /* Setup. */
1991
  unlink("test_file");
1992
  unlink("test_file_link");
1993
  unlink("test_file_link2");
1994

1995
  loop = uv_default_loop();
1996

1997
  r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT,
1998
      S_IWUSR | S_IRUSR, NULL);
1999
  ASSERT_GE(r, 0);
2000
  ASSERT_GE(req.result, 0);
2001
  file = req.result;
2002
  uv_fs_req_cleanup(&req);
2003

2004
  iov = uv_buf_init(test_buf, sizeof(test_buf));
2005
  r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
2006
  ASSERT_EQ(r, sizeof(test_buf));
2007
  ASSERT_EQ(req.result, sizeof(test_buf));
2008
  uv_fs_req_cleanup(&req);
2009

2010
  uv_fs_close(loop, &req, file, NULL);
2011

2012
  /* sync link */
2013
  r = uv_fs_link(NULL, &req, "test_file", "test_file_link", NULL);
2014
  ASSERT_OK(r);
2015
  ASSERT_OK(req.result);
2016
  uv_fs_req_cleanup(&req);
2017

2018
  r = uv_fs_open(NULL, &req, "test_file_link", UV_FS_O_RDWR, 0, NULL);
2019
  ASSERT_GE(r, 0);
2020
  ASSERT_GE(req.result, 0);
2021
  link = req.result;
2022
  uv_fs_req_cleanup(&req);
2023

2024
  memset(buf, 0, sizeof(buf));
2025
  iov = uv_buf_init(buf, sizeof(buf));
2026
  r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
2027
  ASSERT_GE(r, 0);
2028
  ASSERT_GE(req.result, 0);
2029
  ASSERT_OK(strcmp(buf, test_buf));
2030

2031
  close(link);
2032

2033
  /* async link */
2034
  r = uv_fs_link(loop, &req, "test_file", "test_file_link2", link_cb);
2035
  ASSERT_OK(r);
2036
  uv_run(loop, UV_RUN_DEFAULT);
2037
  ASSERT_EQ(1, link_cb_count);
2038

2039
  r = uv_fs_open(NULL, &req, "test_file_link2", UV_FS_O_RDWR, 0, NULL);
2040
  ASSERT_GE(r, 0);
2041
  ASSERT_GE(req.result, 0);
2042
  link = req.result;
2043
  uv_fs_req_cleanup(&req);
2044

2045
  memset(buf, 0, sizeof(buf));
2046
  iov = uv_buf_init(buf, sizeof(buf));
2047
  r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
2048
  ASSERT_GE(r, 0);
2049
  ASSERT_GE(req.result, 0);
2050
  ASSERT_OK(strcmp(buf, test_buf));
2051

2052
  uv_fs_close(loop, &req, link, NULL);
2053

2054
  /*
2055
   * Run the loop just to check we don't have make any extraneous uv_ref()
2056
   * calls. This should drop out immediately.
2057
   */
2058
  uv_run(loop, UV_RUN_DEFAULT);
2059

2060
  /* Cleanup. */
2061
  unlink("test_file");
2062
  unlink("test_file_link");
2063
  unlink("test_file_link2");
2064

2065
  MAKE_VALGRIND_HAPPY(loop);
2066
  return 0;
2067
}
2068

2069

2070
TEST_IMPL(fs_readlink) {
2071
  /* Must return UV_ENOENT on an inexistent file */
2072
  {
2073
    uv_fs_t req;
2074

2075
    loop = uv_default_loop();
2076
    ASSERT_OK(uv_fs_readlink(loop, &req, "no_such_file", dummy_cb));
2077
    ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT));
2078
    ASSERT_EQ(1, dummy_cb_count);
2079
    ASSERT_NULL(req.ptr);
2080
    ASSERT_EQ(req.result, UV_ENOENT);
2081
    uv_fs_req_cleanup(&req);
2082

2083
    ASSERT_EQ(UV_ENOENT, uv_fs_readlink(NULL, &req, "no_such_file", NULL));
2084
    ASSERT_NULL(req.ptr);
2085
    ASSERT_EQ(req.result, UV_ENOENT);
2086
    uv_fs_req_cleanup(&req);
2087
  }
2088

2089
  /* Must return UV_EINVAL on a non-symlink file */
2090
  {
2091
    int r;
2092
    uv_fs_t req;
2093
    uv_file file;
2094

2095
    /* Setup */
2096

2097
    /* Create a non-symlink file */
2098
    r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT,
2099
                   S_IWUSR | S_IRUSR, NULL);
2100
    ASSERT_GE(r, 0);
2101
    ASSERT_GE(req.result, 0);
2102
    file = req.result;
2103
    uv_fs_req_cleanup(&req);
2104

2105
    r = uv_fs_close(NULL, &req, file, NULL);
2106
    ASSERT_OK(r);
2107
    ASSERT_OK(req.result);
2108
    uv_fs_req_cleanup(&req);
2109

2110
    /* Test */
2111
    r = uv_fs_readlink(NULL, &req, "test_file", NULL);
2112
    ASSERT_EQ(r, UV_EINVAL);
2113
    uv_fs_req_cleanup(&req);
2114

2115
    /* Cleanup */
2116
    unlink("test_file");
2117
  }
2118

2119
  MAKE_VALGRIND_HAPPY(loop);
2120
  return 0;
2121
}
2122

2123

2124
TEST_IMPL(fs_realpath) {
2125
  uv_fs_t req;
2126

2127
  loop = uv_default_loop();
2128
  ASSERT_OK(uv_fs_realpath(loop, &req, "no_such_file", dummy_cb));
2129
  ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT));
2130
  ASSERT_EQ(1, dummy_cb_count);
2131
  ASSERT_NULL(req.ptr);
2132
  ASSERT_EQ(req.result, UV_ENOENT);
2133
  uv_fs_req_cleanup(&req);
2134

2135
  ASSERT_EQ(UV_ENOENT, uv_fs_realpath(NULL, &req, "no_such_file", NULL));
2136
  ASSERT_NULL(req.ptr);
2137
  ASSERT_EQ(req.result, UV_ENOENT);
2138
  uv_fs_req_cleanup(&req);
2139

2140
  MAKE_VALGRIND_HAPPY(loop);
2141
  return 0;
2142
}
2143

2144

2145
TEST_IMPL(fs_symlink) {
2146
  int r;
2147
  uv_fs_t req;
2148
  uv_file file;
2149
  uv_file link;
2150
  char test_file_abs_buf[PATHMAX];
2151
  size_t test_file_abs_size;
2152

2153
  /* Setup. */
2154
  unlink("test_file");
2155
  unlink("test_file_symlink");
2156
  unlink("test_file_symlink2");
2157
  unlink("test_file_symlink_symlink");
2158
  unlink("test_file_symlink2_symlink");
2159
  test_file_abs_size = sizeof(test_file_abs_buf);
2160
#ifdef _WIN32
2161
  uv_cwd(test_file_abs_buf, &test_file_abs_size);
2162
  strcat(test_file_abs_buf, "\\test_file");
2163
#else
2164
  uv_cwd(test_file_abs_buf, &test_file_abs_size);
2165
  strcat(test_file_abs_buf, "/test_file");
2166
#endif
2167

2168
  loop = uv_default_loop();
2169

2170
  r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT,
2171
      S_IWUSR | S_IRUSR, NULL);
2172
  ASSERT_GE(r, 0);
2173
  ASSERT_GE(req.result, 0);
2174
  file = req.result;
2175
  uv_fs_req_cleanup(&req);
2176

2177
  iov = uv_buf_init(test_buf, sizeof(test_buf));
2178
  r = uv_fs_write(NULL, &req, file, &iov, 1, -1, NULL);
2179
  ASSERT_EQ(r, sizeof(test_buf));
2180
  ASSERT_EQ(req.result, sizeof(test_buf));
2181
  uv_fs_req_cleanup(&req);
2182

2183
  uv_fs_close(loop, &req, file, NULL);
2184

2185
  /* sync symlink */
2186
  r = uv_fs_symlink(NULL, &req, "test_file", "test_file_symlink", 0, NULL);
2187
#ifdef _WIN32
2188
  if (r < 0) {
2189
    if (r == UV_ENOTSUP) {
2190
      /*
2191
       * Windows doesn't support symlinks on older versions.
2192
       * We just pass the test and bail out early if we get ENOTSUP.
2193
       */
2194
      return 0;
2195
    } else if (r == UV_EPERM) {
2196
      /*
2197
       * Creating a symlink is only allowed when running elevated.
2198
       * We pass the test and bail out early if we get UV_EPERM.
2199
       */
2200
      return 0;
2201
    }
2202
  }
2203
#endif
2204
  ASSERT_OK(r);
2205
  ASSERT_OK(req.result);
2206
  uv_fs_req_cleanup(&req);
2207

2208
  r = uv_fs_open(NULL, &req, "test_file_symlink", UV_FS_O_RDWR, 0, NULL);
2209
  ASSERT_GE(r, 0);
2210
  ASSERT_GE(req.result, 0);
2211
  link = req.result;
2212
  uv_fs_req_cleanup(&req);
2213

2214
  memset(buf, 0, sizeof(buf));
2215
  iov = uv_buf_init(buf, sizeof(buf));
2216
  r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
2217
  ASSERT_GE(r, 0);
2218
  ASSERT_GE(req.result, 0);
2219
  ASSERT_OK(strcmp(buf, test_buf));
2220

2221
  uv_fs_close(loop, &req, link, NULL);
2222

2223
  r = uv_fs_symlink(NULL,
2224
                    &req,
2225
                    "test_file_symlink",
2226
                    "test_file_symlink_symlink",
2227
                    0,
2228
                    NULL);
2229
  ASSERT_OK(r);
2230
  uv_fs_req_cleanup(&req);
2231

2232
#if defined(__MSYS__)
2233
  RETURN_SKIP("symlink reading is not supported on MSYS2");
2234
#endif
2235

2236
  r = uv_fs_readlink(NULL, &req, "test_file_symlink_symlink", NULL);
2237
  ASSERT_OK(r);
2238
  ASSERT_OK(strcmp(req.ptr, "test_file_symlink"));
2239
  uv_fs_req_cleanup(&req);
2240

2241
  r = uv_fs_realpath(NULL, &req, "test_file_symlink_symlink", NULL);
2242
  ASSERT_OK(r);
2243
#ifdef _WIN32
2244
  ASSERT_OK(_stricmp(req.ptr, test_file_abs_buf));
2245
#else
2246
  ASSERT_OK(strcmp(req.ptr, test_file_abs_buf));
2247
#endif
2248
  uv_fs_req_cleanup(&req);
2249

2250
  /* async link */
2251
  r = uv_fs_symlink(loop,
2252
                    &req,
2253
                    "test_file",
2254
                    "test_file_symlink2",
2255
                    0,
2256
                    symlink_cb);
2257
  ASSERT_OK(r);
2258
  uv_run(loop, UV_RUN_DEFAULT);
2259
  ASSERT_EQ(1, symlink_cb_count);
2260

2261
  r = uv_fs_open(NULL, &req, "test_file_symlink2", UV_FS_O_RDWR, 0, NULL);
2262
  ASSERT_GE(r, 0);
2263
  ASSERT_GE(req.result, 0);
2264
  link = req.result;
2265
  uv_fs_req_cleanup(&req);
2266

2267
  memset(buf, 0, sizeof(buf));
2268
  iov = uv_buf_init(buf, sizeof(buf));
2269
  r = uv_fs_read(NULL, &req, link, &iov, 1, 0, NULL);
2270
  ASSERT_GE(r, 0);
2271
  ASSERT_GE(req.result, 0);
2272
  ASSERT_OK(strcmp(buf, test_buf));
2273

2274
  uv_fs_close(loop, &req, link, NULL);
2275

2276
  r = uv_fs_symlink(NULL,
2277
                    &req,
2278
                    "test_file_symlink2",
2279
                    "test_file_symlink2_symlink",
2280
                    0,
2281
                    NULL);
2282
  ASSERT_OK(r);
2283
  uv_fs_req_cleanup(&req);
2284

2285
  r = uv_fs_readlink(loop, &req, "test_file_symlink2_symlink", readlink_cb);
2286
  ASSERT_OK(r);
2287
  uv_run(loop, UV_RUN_DEFAULT);
2288
  ASSERT_EQ(1, readlink_cb_count);
2289

2290
  r = uv_fs_realpath(loop, &req, "test_file", realpath_cb);
2291
  ASSERT_OK(r);
2292
  uv_run(loop, UV_RUN_DEFAULT);
2293
  ASSERT_EQ(1, realpath_cb_count);
2294

2295
  /*
2296
   * Run the loop just to check we don't have make any extraneous uv_ref()
2297
   * calls. This should drop out immediately.
2298
   */
2299
  uv_run(loop, UV_RUN_DEFAULT);
2300

2301
  /* Cleanup. */
2302
  unlink("test_file");
2303
  unlink("test_file_symlink");
2304
  unlink("test_file_symlink_symlink");
2305
  unlink("test_file_symlink2");
2306
  unlink("test_file_symlink2_symlink");
2307

2308
  MAKE_VALGRIND_HAPPY(loop);
2309
  return 0;
2310
}
2311

2312

2313
int test_symlink_dir_impl(int type) {
2314
  uv_fs_t req;
2315
  int r;
2316
  char* test_dir;
2317
  uv_dirent_t dent;
2318
  static char test_dir_abs_buf[PATHMAX];
2319
  size_t test_dir_abs_size;
2320

2321
  /* set-up */
2322
  unlink("test_dir/file1");
2323
  unlink("test_dir/file2");
2324
  rmdir("test_dir");
2325
  rmdir("test_dir_symlink");
2326
  test_dir_abs_size = sizeof(test_dir_abs_buf);
2327

2328
  loop = uv_default_loop();
2329

2330
  uv_fs_mkdir(NULL, &req, "test_dir", 0777, NULL);
2331
  uv_fs_req_cleanup(&req);
2332

2333
#ifdef _WIN32
2334
  strcpy(test_dir_abs_buf, "\\\\?\\");
2335
  uv_cwd(test_dir_abs_buf + 4, &test_dir_abs_size);
2336
  test_dir_abs_size += 4;
2337
  strcat(test_dir_abs_buf, "\\test_dir\\");
2338
  test_dir_abs_size += strlen("\\test_dir\\");
2339
  test_dir = test_dir_abs_buf;
2340
#else
2341
  uv_cwd(test_dir_abs_buf, &test_dir_abs_size);
2342
  strcat(test_dir_abs_buf, "/test_dir");
2343
  test_dir_abs_size += strlen("/test_dir");
2344
  test_dir = "test_dir";
2345
#endif
2346

2347
  r = uv_fs_symlink(NULL, &req, test_dir, "test_dir_symlink", type, NULL);
2348
  if (type == UV_FS_SYMLINK_DIR && (r == UV_ENOTSUP || r == UV_EPERM)) {
2349
    uv_fs_req_cleanup(&req);
2350
    RETURN_SKIP("this version of Windows doesn't support unprivileged "
2351
                "creation of directory symlinks");
2352
  }
2353
  fprintf(stderr, "r == %i\n", r);
2354
  ASSERT_OK(r);
2355
  ASSERT_OK(req.result);
2356
  uv_fs_req_cleanup(&req);
2357

2358
  r = uv_fs_stat(NULL, &req, "test_dir_symlink", NULL);
2359
  ASSERT_OK(r);
2360
  ASSERT(((uv_stat_t*)req.ptr)->st_mode & S_IFDIR);
2361
  uv_fs_req_cleanup(&req);
2362

2363
  r = uv_fs_lstat(NULL, &req, "test_dir_symlink", NULL);
2364
  ASSERT_OK(r);
2365
#if defined(__MSYS__)
2366
  RETURN_SKIP("symlink reading is not supported on MSYS2");
2367
#endif
2368
  ASSERT(((uv_stat_t*)req.ptr)->st_mode & S_IFLNK);
2369
#ifdef _WIN32
2370
  ASSERT_EQ(((uv_stat_t*)req.ptr)->st_size, strlen(test_dir + 4));
2371
#else
2372
# ifdef __PASE__
2373
  /* On IBMi PASE, st_size returns the length of the symlink itself. */
2374
  ASSERT_EQ(((uv_stat_t*)req.ptr)->st_size, strlen("test_dir_symlink"));
2375
# else
2376
  ASSERT_EQ(((uv_stat_t*)req.ptr)->st_size, strlen(test_dir));
2377
# endif
2378
#endif
2379
  uv_fs_req_cleanup(&req);
2380

2381
  r = uv_fs_readlink(NULL, &req, "test_dir_symlink", NULL);
2382
  ASSERT_OK(r);
2383
#ifdef _WIN32
2384
  ASSERT_OK(strcmp(req.ptr, test_dir + 4));
2385
#else
2386
  ASSERT_OK(strcmp(req.ptr, test_dir));
2387
#endif
2388
  uv_fs_req_cleanup(&req);
2389

2390
  r = uv_fs_realpath(NULL, &req, "test_dir_symlink", NULL);
2391
  ASSERT_OK(r);
2392
#ifdef _WIN32
2393
  ASSERT_EQ(strlen(req.ptr), test_dir_abs_size - 5);
2394
  ASSERT_OK(_strnicmp(req.ptr, test_dir + 4, test_dir_abs_size - 5));
2395
#else
2396
  ASSERT_OK(strcmp(req.ptr, test_dir_abs_buf));
2397
#endif
2398
  uv_fs_req_cleanup(&req);
2399

2400
  r = uv_fs_open(NULL, &open_req1, "test_dir/file1",
2401
                 UV_FS_O_WRONLY | UV_FS_O_CREAT,
2402
      S_IWUSR | S_IRUSR, NULL);
2403
  ASSERT_GE(r, 0);
2404
  uv_fs_req_cleanup(&open_req1);
2405
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
2406
  ASSERT_OK(r);
2407
  uv_fs_req_cleanup(&close_req);
2408

2409
  r = uv_fs_open(NULL, &open_req1, "test_dir/file2",
2410
                 UV_FS_O_WRONLY | UV_FS_O_CREAT,
2411
      S_IWUSR | S_IRUSR, NULL);
2412
  ASSERT_GE(r, 0);
2413
  uv_fs_req_cleanup(&open_req1);
2414
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
2415
  ASSERT_OK(r);
2416
  uv_fs_req_cleanup(&close_req);
2417

2418
  r = uv_fs_scandir(NULL, &scandir_req, "test_dir_symlink", 0, NULL);
2419
  ASSERT_EQ(2, r);
2420
  ASSERT_EQ(2, scandir_req.result);
2421
  ASSERT(scandir_req.ptr);
2422
  while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) {
2423
    ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0);
2424
    assert_is_file_type(dent);
2425
  }
2426
  uv_fs_req_cleanup(&scandir_req);
2427
  ASSERT(!scandir_req.ptr);
2428

2429
  /* unlink will remove the directory symlink */
2430
  r = uv_fs_unlink(NULL, &req, "test_dir_symlink", NULL);
2431
  ASSERT_OK(r);
2432
  uv_fs_req_cleanup(&req);
2433

2434
  r = uv_fs_scandir(NULL, &scandir_req, "test_dir_symlink", 0, NULL);
2435
  ASSERT_EQ(r, UV_ENOENT);
2436
  uv_fs_req_cleanup(&scandir_req);
2437

2438
  r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL);
2439
  ASSERT_EQ(2, r);
2440
  ASSERT_EQ(2, scandir_req.result);
2441
  ASSERT(scandir_req.ptr);
2442
  while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) {
2443
    ASSERT(strcmp(dent.name, "file1") == 0 || strcmp(dent.name, "file2") == 0);
2444
    assert_is_file_type(dent);
2445
  }
2446
  uv_fs_req_cleanup(&scandir_req);
2447
  ASSERT(!scandir_req.ptr);
2448

2449
  /* clean-up */
2450
  unlink("test_dir/file1");
2451
  unlink("test_dir/file2");
2452
  rmdir("test_dir");
2453
  rmdir("test_dir_symlink");
2454

2455
  MAKE_VALGRIND_HAPPY(loop);
2456
  return 0;
2457
}
2458

2459
TEST_IMPL(fs_symlink_dir) {
2460
  return test_symlink_dir_impl(UV_FS_SYMLINK_DIR);
2461
}
2462

2463
TEST_IMPL(fs_symlink_junction) {
2464
  return test_symlink_dir_impl(UV_FS_SYMLINK_JUNCTION);
2465
}
2466

2467
#ifdef _WIN32
2468
TEST_IMPL(fs_non_symlink_reparse_point) {
2469
  uv_fs_t req;
2470
  int r;
2471
  HANDLE file_handle;
2472
  REPARSE_GUID_DATA_BUFFER reparse_buffer;
2473
  DWORD bytes_returned;
2474
  uv_dirent_t dent;
2475

2476
  /* set-up */
2477
  unlink("test_dir/test_file");
2478
  rmdir("test_dir");
2479

2480
  loop = uv_default_loop();
2481

2482
  uv_fs_mkdir(NULL, &req, "test_dir", 0777, NULL);
2483
  uv_fs_req_cleanup(&req);
2484

2485
  file_handle = CreateFile("test_dir/test_file",
2486
                           GENERIC_WRITE | FILE_WRITE_ATTRIBUTES,
2487
                           0,
2488
                           NULL,
2489
                           CREATE_ALWAYS,
2490
                           FILE_FLAG_OPEN_REPARSE_POINT |
2491
                             FILE_FLAG_BACKUP_SEMANTICS,
2492
                           NULL);
2493
  ASSERT_PTR_NE(file_handle, INVALID_HANDLE_VALUE);
2494

2495
  memset(&reparse_buffer, 0, REPARSE_GUID_DATA_BUFFER_HEADER_SIZE);
2496
  reparse_buffer.ReparseTag = REPARSE_TAG;
2497
  reparse_buffer.ReparseDataLength = 0;
2498
  reparse_buffer.ReparseGuid = REPARSE_GUID;
2499

2500
  r = DeviceIoControl(file_handle,
2501
                      FSCTL_SET_REPARSE_POINT,
2502
                      &reparse_buffer,
2503
                      REPARSE_GUID_DATA_BUFFER_HEADER_SIZE,
2504
                      NULL,
2505
                      0,
2506
                      &bytes_returned,
2507
                      NULL);
2508
  ASSERT(r);
2509

2510
  CloseHandle(file_handle);
2511

2512
  r = uv_fs_readlink(NULL, &req, "test_dir/test_file", NULL);
2513
  ASSERT(r == UV_EINVAL && GetLastError() == ERROR_SYMLINK_NOT_SUPPORTED);
2514
  uv_fs_req_cleanup(&req);
2515

2516
/*
2517
  Placeholder tests for exercising the behavior fixed in issue #995.
2518
  To run, update the path with the IP address of a Mac with the hard drive
2519
  shared via SMB as "Macintosh HD".
2520

2521
  r = uv_fs_stat(NULL, &req, "\\\\<mac_ip>\\Macintosh HD\\.DS_Store", NULL);
2522
  ASSERT_OK(r);
2523
  uv_fs_req_cleanup(&req);
2524

2525
  r = uv_fs_lstat(NULL, &req, "\\\\<mac_ip>\\Macintosh HD\\.DS_Store", NULL);
2526
  ASSERT_OK(r);
2527
  uv_fs_req_cleanup(&req);
2528
*/
2529

2530
/*
2531
  uv_fs_stat and uv_fs_lstat can only work on non-symlink reparse
2532
  points when a minifilter driver is registered which intercepts
2533
  associated filesystem requests. Installing a driver is beyond
2534
  the scope of this test.
2535

2536
  r = uv_fs_stat(NULL, &req, "test_dir/test_file", NULL);
2537
  ASSERT_OK(r);
2538
  uv_fs_req_cleanup(&req);
2539

2540
  r = uv_fs_lstat(NULL, &req, "test_dir/test_file", NULL);
2541
  ASSERT_OK(r);
2542
  uv_fs_req_cleanup(&req);
2543
*/
2544

2545
  r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL);
2546
  ASSERT_EQ(1, r);
2547
  ASSERT_EQ(1, scandir_req.result);
2548
  ASSERT(scandir_req.ptr);
2549
  while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) {
2550
    ASSERT_OK(strcmp(dent.name, "test_file"));
2551
    /* uv_fs_scandir incorrectly identifies non-symlink reparse points
2552
       as links because it doesn't open the file and verify the reparse
2553
       point tag. The PowerShell Get-ChildItem command shares this
2554
       behavior, so it's reasonable to leave it as is. */
2555
    ASSERT_EQ(dent.type, UV_DIRENT_LINK);
2556
  }
2557
  uv_fs_req_cleanup(&scandir_req);
2558
  ASSERT(!scandir_req.ptr);
2559

2560
  /* clean-up */
2561
  unlink("test_dir/test_file");
2562
  rmdir("test_dir");
2563

2564
  MAKE_VALGRIND_HAPPY(loop);
2565
  return 0;
2566
}
2567

2568
TEST_IMPL(fs_lstat_windows_store_apps) {
2569
  uv_loop_t* loop;
2570
  char localappdata[MAX_PATH];
2571
  char windowsapps_path[MAX_PATH];
2572
  char file_path[MAX_PATH];
2573
  size_t len;
2574
  int r;
2575
  uv_fs_t req;
2576
  uv_fs_t stat_req;
2577
  uv_dirent_t dirent;
2578

2579
  loop = uv_default_loop();
2580
  ASSERT_NOT_NULL(loop);
2581
  len = sizeof(localappdata);
2582
  r = uv_os_getenv("LOCALAPPDATA", localappdata, &len);
2583
  if (r == UV_ENOENT) {
2584
    MAKE_VALGRIND_HAPPY(loop);
2585
    return TEST_SKIP;
2586
  }
2587
  ASSERT_OK(r);
2588
  r = snprintf(windowsapps_path,
2589
              sizeof(localappdata),
2590
              "%s\\Microsoft\\WindowsApps",
2591
              localappdata);
2592
  ASSERT_GT(r, 0);
2593
  if (uv_fs_opendir(loop, &req, windowsapps_path, NULL) != 0) {
2594
    /* If we cannot read the directory, skip the test. */
2595
    MAKE_VALGRIND_HAPPY(loop);
2596
    return TEST_SKIP;
2597
  }
2598
  if (uv_fs_scandir(loop, &req, windowsapps_path, 0, NULL) <= 0) {
2599
    MAKE_VALGRIND_HAPPY(loop);
2600
    return TEST_SKIP;
2601
  }
2602
  while (uv_fs_scandir_next(&req, &dirent) != UV_EOF) {
2603
    if (dirent.type != UV_DIRENT_LINK) {
2604
      continue;
2605
    }
2606
    if (snprintf(file_path,
2607
                 sizeof(file_path),
2608
                 "%s\\%s",
2609
                 windowsapps_path,
2610
                 dirent.name) < 0) {
2611
      continue;
2612
    }
2613
    ASSERT_OK(uv_fs_lstat(loop, &stat_req, file_path, NULL));
2614
  }
2615
  MAKE_VALGRIND_HAPPY(loop);
2616
  return 0;
2617
}
2618
#endif
2619

2620

2621
TEST_IMPL(fs_utime) {
2622
  utime_check_t checkme;
2623
  const char* path = "test_file";
2624
  double atime;
2625
  double mtime;
2626
  uv_fs_t req;
2627
  int r;
2628

2629
  /* Setup. */
2630
  loop = uv_default_loop();
2631
  unlink(path);
2632
  r = uv_fs_open(NULL, &req, path, UV_FS_O_RDWR | UV_FS_O_CREAT,
2633
                 S_IWUSR | S_IRUSR,
2634
                 NULL);
2635
  ASSERT_GE(r, 0);
2636
  ASSERT_GE(req.result, 0);
2637
  uv_fs_req_cleanup(&req);
2638
  uv_fs_close(loop, &req, r, NULL);
2639

2640
  atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */
2641

2642
  r = uv_fs_utime(NULL, &req, path, atime, mtime, NULL);
2643
  ASSERT_OK(r);
2644
  ASSERT_OK(req.result);
2645
  uv_fs_req_cleanup(&req);
2646

2647
  check_utime(path, atime, mtime, /* test_lutime */ 0);
2648

2649
  atime = mtime = 1291404900.25; /* 2010-12-03 20:35:00.25 - mees <3 */
2650
  checkme.path = path;
2651
  checkme.atime = atime;
2652
  checkme.mtime = mtime;
2653

2654
  /* async utime */
2655
  utime_req.data = &checkme;
2656
  r = uv_fs_utime(loop, &utime_req, path, atime, mtime, utime_cb);
2657
  ASSERT_OK(r);
2658
  uv_run(loop, UV_RUN_DEFAULT);
2659
  ASSERT_EQ(1, utime_cb_count);
2660

2661
  /* Cleanup. */
2662
  unlink(path);
2663

2664
  MAKE_VALGRIND_HAPPY(loop);
2665
  return 0;
2666
}
2667

2668

2669
TEST_IMPL(fs_utime_round) {
2670
  const char path[] = "test_file";
2671
  double atime;
2672
  double mtime;
2673
  uv_fs_t req;
2674
  int r;
2675

2676
  loop = uv_default_loop();
2677
  unlink(path);
2678
  r = uv_fs_open(NULL, &req, path, UV_FS_O_RDWR | UV_FS_O_CREAT,
2679
                 S_IWUSR | S_IRUSR,
2680
                 NULL);
2681
  ASSERT_GE(r, 0);
2682
  ASSERT_GE(req.result, 0);
2683
  uv_fs_req_cleanup(&req);
2684
  ASSERT_OK(uv_fs_close(loop, &req, r, NULL));
2685

2686
  atime = mtime = -14245440.25;  /* 1969-07-20T02:56:00.25Z */
2687

2688
  r = uv_fs_utime(NULL, &req, path, atime, mtime, NULL);
2689
#if !defined(__linux__)     && \
2690
    !defined(_WIN32)        && \
2691
    !defined(__APPLE__)     && \
2692
    !defined(__FreeBSD__)   && \
2693
    !defined(__sun)
2694
  if (r != 0) {
2695
    ASSERT_EQ(r, UV_EINVAL);
2696
    RETURN_SKIP("utime on some OS (z/OS, IBM i PASE, AIX) or filesystems may reject pre-epoch timestamps");
2697
  }
2698
#endif
2699
  ASSERT_OK(r);
2700
  ASSERT_OK(req.result);
2701
  uv_fs_req_cleanup(&req);
2702
  check_utime(path, atime, mtime, /* test_lutime */ 0);
2703
  unlink(path);
2704

2705
  MAKE_VALGRIND_HAPPY(loop);
2706
  return 0;
2707
}
2708

2709

2710
#ifdef _WIN32
2711
TEST_IMPL(fs_stat_root) {
2712
  int r;
2713

2714
  r = uv_fs_stat(NULL, &stat_req, "\\", NULL);
2715
  ASSERT_OK(r);
2716

2717
  r = uv_fs_stat(NULL, &stat_req, "..\\..\\..\\..\\..\\..\\..", NULL);
2718
  ASSERT_OK(r);
2719

2720
  r = uv_fs_stat(NULL, &stat_req, "..", NULL);
2721
  ASSERT_OK(r);
2722

2723
  r = uv_fs_stat(NULL, &stat_req, "..\\", NULL);
2724
  ASSERT_OK(r);
2725

2726
  /* stats the current directory on c: */
2727
  r = uv_fs_stat(NULL, &stat_req, "c:", NULL);
2728
  ASSERT_OK(r);
2729

2730
  r = uv_fs_stat(NULL, &stat_req, "c:\\", NULL);
2731
  ASSERT_OK(r);
2732

2733
  r = uv_fs_stat(NULL, &stat_req, "\\\\?\\C:\\", NULL);
2734
  ASSERT_OK(r);
2735

2736
  MAKE_VALGRIND_HAPPY(uv_default_loop());
2737
  return 0;
2738
}
2739
#endif
2740

2741

2742
TEST_IMPL(fs_futime) {
2743
  utime_check_t checkme;
2744
  const char* path = "test_file";
2745
  double atime;
2746
  double mtime;
2747
  uv_file file;
2748
  uv_fs_t req;
2749
  int r;
2750
#if defined(_AIX) && !defined(_AIX71)
2751
  RETURN_SKIP("futime is not implemented for AIX versions below 7.1");
2752
#endif
2753

2754
  /* Setup. */
2755
  loop = uv_default_loop();
2756
  unlink(path);
2757
  r = uv_fs_open(NULL, &req, path, UV_FS_O_RDWR | UV_FS_O_CREAT,
2758
                 S_IWUSR | S_IRUSR,
2759
                 NULL);
2760
  ASSERT_GE(r, 0);
2761
  ASSERT_GE(req.result, 0);
2762
  uv_fs_req_cleanup(&req);
2763
  uv_fs_close(loop, &req, r, NULL);
2764

2765
  atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */
2766

2767
  r = uv_fs_open(NULL, &req, path, UV_FS_O_RDWR, 0, NULL);
2768
  ASSERT_GE(r, 0);
2769
  ASSERT_GE(req.result, 0);
2770
  file = req.result; /* FIXME probably not how it's supposed to be used */
2771
  uv_fs_req_cleanup(&req);
2772

2773
  r = uv_fs_futime(NULL, &req, file, atime, mtime, NULL);
2774
#if defined(__CYGWIN__) || defined(__MSYS__)
2775
  ASSERT_EQ(r, UV_ENOSYS);
2776
  RETURN_SKIP("futime not supported on Cygwin");
2777
#else
2778
  ASSERT_OK(r);
2779
  ASSERT_OK(req.result);
2780
#endif
2781
  uv_fs_req_cleanup(&req);
2782

2783
  check_utime(path, atime, mtime, /* test_lutime */ 0);
2784

2785
  atime = mtime = 1291404900; /* 2010-12-03 20:35:00 - mees <3 */
2786

2787
  checkme.atime = atime;
2788
  checkme.mtime = mtime;
2789
  checkme.path = path;
2790

2791
  /* async futime */
2792
  futime_req.data = &checkme;
2793
  r = uv_fs_futime(loop, &futime_req, file, atime, mtime, futime_cb);
2794
  ASSERT_OK(r);
2795
  uv_run(loop, UV_RUN_DEFAULT);
2796
  ASSERT_EQ(1, futime_cb_count);
2797

2798
  /* Cleanup. */
2799
  unlink(path);
2800

2801
  MAKE_VALGRIND_HAPPY(loop);
2802
  return 0;
2803
}
2804

2805

2806
TEST_IMPL(fs_lutime) {
2807
  utime_check_t checkme;
2808
  const char* path = "test_file";
2809
  const char* symlink_path = "test_file_symlink";
2810
  double atime;
2811
  double mtime;
2812
  uv_fs_t req;
2813
  int r, s;
2814

2815

2816
  /* Setup */
2817
  loop = uv_default_loop();
2818
  unlink(path);
2819
  r = uv_fs_open(NULL, &req, path, UV_FS_O_RDWR | UV_FS_O_CREAT,
2820
                 S_IWUSR | S_IRUSR,
2821
                 NULL);
2822
  ASSERT_GE(r, 0);
2823
  ASSERT_GE(req.result, 0);
2824
  uv_fs_req_cleanup(&req);
2825
  uv_fs_close(loop, &req, r, NULL);
2826

2827
  unlink(symlink_path);
2828
  s = uv_fs_symlink(NULL, &req, path, symlink_path, 0, NULL);
2829
#ifdef _WIN32
2830
  if (s == UV_EPERM) {
2831
    /*
2832
     * Creating a symlink before Windows 10 Creators Update was only allowed
2833
     * when running elevated console (with admin rights)
2834
     */
2835
    RETURN_SKIP(
2836
        "Symlink creation requires elevated console (with admin rights)");
2837
  }
2838
#endif
2839
  ASSERT_OK(s);
2840
  ASSERT_OK(req.result);
2841
  uv_fs_req_cleanup(&req);
2842

2843
  /* Test the synchronous version. */
2844
  atime = mtime = 400497753.25; /* 1982-09-10 11:22:33.25 */
2845

2846
  checkme.atime = atime;
2847
  checkme.mtime = mtime;
2848
  checkme.path = symlink_path;
2849
  req.data = &checkme;
2850

2851
  r = uv_fs_lutime(NULL, &req, symlink_path, atime, mtime, NULL);
2852
#if (defined(_AIX) && !defined(_AIX71)) ||                                    \
2853
     defined(__MVS__)
2854
  ASSERT_EQ(r, UV_ENOSYS);
2855
  RETURN_SKIP("lutime is not implemented for z/OS and AIX versions below 7.1");
2856
#endif
2857
  ASSERT_OK(r);
2858
  lutime_cb(&req);
2859
  ASSERT_EQ(1, lutime_cb_count);
2860

2861
  /* Test the asynchronous version. */
2862
  atime = mtime = 1291404900; /* 2010-12-03 20:35:00 */
2863

2864
  checkme.atime = atime;
2865
  checkme.mtime = mtime;
2866
  checkme.path = symlink_path;
2867

2868
  r = uv_fs_lutime(loop, &req, symlink_path, atime, mtime, lutime_cb);
2869
  ASSERT_OK(r);
2870
  uv_run(loop, UV_RUN_DEFAULT);
2871
  ASSERT_EQ(2, lutime_cb_count);
2872

2873
  /* Cleanup. */
2874
  unlink(path);
2875
  unlink(symlink_path);
2876

2877
  MAKE_VALGRIND_HAPPY(loop);
2878
  return 0;
2879
}
2880

2881

2882
TEST_IMPL(fs_stat_missing_path) {
2883
  uv_fs_t req;
2884
  int r;
2885

2886
  loop = uv_default_loop();
2887

2888
  r = uv_fs_stat(NULL, &req, "non_existent_file", NULL);
2889
  ASSERT_EQ(r, UV_ENOENT);
2890
  ASSERT_EQ(req.result, UV_ENOENT);
2891
  uv_fs_req_cleanup(&req);
2892

2893
  MAKE_VALGRIND_HAPPY(loop);
2894
  return 0;
2895
}
2896

2897

2898
TEST_IMPL(fs_scandir_empty_dir) {
2899
  const char* path;
2900
  uv_fs_t req;
2901
  uv_dirent_t dent;
2902
  int r;
2903

2904
  path = "./empty_dir/";
2905
  loop = uv_default_loop();
2906

2907
  uv_fs_mkdir(NULL, &req, path, 0777, NULL);
2908
  uv_fs_req_cleanup(&req);
2909

2910
  /* Fill the req to ensure that required fields are cleaned up */
2911
  memset(&req, 0xdb, sizeof(req));
2912

2913
  r = uv_fs_scandir(NULL, &req, path, 0, NULL);
2914
  ASSERT_OK(r);
2915
  ASSERT_OK(req.result);
2916
  ASSERT_NULL(req.ptr);
2917
  ASSERT_EQ(UV_EOF, uv_fs_scandir_next(&req, &dent));
2918
  uv_fs_req_cleanup(&req);
2919

2920
  r = uv_fs_scandir(loop, &scandir_req, path, 0, empty_scandir_cb);
2921
  ASSERT_OK(r);
2922

2923
  ASSERT_OK(scandir_cb_count);
2924
  uv_run(loop, UV_RUN_DEFAULT);
2925
  ASSERT_EQ(1, scandir_cb_count);
2926

2927
  uv_fs_rmdir(NULL, &req, path, NULL);
2928
  uv_fs_req_cleanup(&req);
2929

2930
  MAKE_VALGRIND_HAPPY(loop);
2931
  return 0;
2932
}
2933

2934

2935
TEST_IMPL(fs_scandir_non_existent_dir) {
2936
  const char* path;
2937
  uv_fs_t req;
2938
  uv_dirent_t dent;
2939
  int r;
2940

2941
  path = "./non_existent_dir/";
2942
  loop = uv_default_loop();
2943

2944
  uv_fs_rmdir(NULL, &req, path, NULL);
2945
  uv_fs_req_cleanup(&req);
2946

2947
  /* Fill the req to ensure that required fields are cleaned up */
2948
  memset(&req, 0xdb, sizeof(req));
2949

2950
  r = uv_fs_scandir(NULL, &req, path, 0, NULL);
2951
  ASSERT_EQ(r, UV_ENOENT);
2952
  ASSERT_EQ(req.result, UV_ENOENT);
2953
  ASSERT_NULL(req.ptr);
2954
  ASSERT_EQ(UV_ENOENT, uv_fs_scandir_next(&req, &dent));
2955
  uv_fs_req_cleanup(&req);
2956

2957
  r = uv_fs_scandir(loop, &scandir_req, path, 0, non_existent_scandir_cb);
2958
  ASSERT_OK(r);
2959

2960
  ASSERT_OK(scandir_cb_count);
2961
  uv_run(loop, UV_RUN_DEFAULT);
2962
  ASSERT_EQ(1, scandir_cb_count);
2963

2964
  MAKE_VALGRIND_HAPPY(loop);
2965
  return 0;
2966
}
2967

2968
TEST_IMPL(fs_scandir_file) {
2969
  const char* path;
2970
  int r;
2971

2972
  path = "test/fixtures/empty_file";
2973
  loop = uv_default_loop();
2974

2975
  r = uv_fs_scandir(NULL, &scandir_req, path, 0, NULL);
2976
  ASSERT_EQ(r, UV_ENOTDIR);
2977
  uv_fs_req_cleanup(&scandir_req);
2978

2979
  r = uv_fs_scandir(loop, &scandir_req, path, 0, file_scandir_cb);
2980
  ASSERT_OK(r);
2981

2982
  ASSERT_OK(scandir_cb_count);
2983
  uv_run(loop, UV_RUN_DEFAULT);
2984
  ASSERT_EQ(1, scandir_cb_count);
2985

2986
  MAKE_VALGRIND_HAPPY(loop);
2987
  return 0;
2988
}
2989

2990

2991
/* Run in Valgrind. Should not leak when the iterator isn't exhausted. */
2992
TEST_IMPL(fs_scandir_early_exit) {
2993
  uv_dirent_t d;
2994
  uv_fs_t req;
2995

2996
  ASSERT_LT(0, uv_fs_scandir(NULL, &req, "test/fixtures/one_file", 0, NULL));
2997
  ASSERT_NE(UV_EOF, uv_fs_scandir_next(&req, &d));
2998
  uv_fs_req_cleanup(&req);
2999

3000
  ASSERT_LT(0, uv_fs_scandir(NULL, &req, "test/fixtures", 0, NULL));
3001
  ASSERT_NE(UV_EOF, uv_fs_scandir_next(&req, &d));
3002
  uv_fs_req_cleanup(&req);
3003

3004
  MAKE_VALGRIND_HAPPY(uv_default_loop());
3005
  return 0;
3006
}
3007

3008

3009
TEST_IMPL(fs_open_dir) {
3010
  const char* path;
3011
  uv_fs_t req;
3012
  int r, file;
3013

3014
  path = ".";
3015
  loop = uv_default_loop();
3016

3017
  r = uv_fs_open(NULL, &req, path, UV_FS_O_RDONLY, 0, NULL);
3018
  ASSERT_GE(r, 0);
3019
  ASSERT_GE(req.result, 0);
3020
  ASSERT_NULL(req.ptr);
3021
  file = r;
3022
  uv_fs_req_cleanup(&req);
3023

3024
  r = uv_fs_close(NULL, &req, file, NULL);
3025
  ASSERT_OK(r);
3026

3027
  r = uv_fs_open(loop, &req, path, UV_FS_O_RDONLY, 0, open_cb_simple);
3028
  ASSERT_OK(r);
3029

3030
  ASSERT_OK(open_cb_count);
3031
  uv_run(loop, UV_RUN_DEFAULT);
3032
  ASSERT_EQ(1, open_cb_count);
3033

3034
  MAKE_VALGRIND_HAPPY(loop);
3035
  return 0;
3036
}
3037

3038

3039
static void fs_file_open_append(int add_flags) {
3040
  int r;
3041

3042
  /* Setup. */
3043
  unlink("test_file");
3044

3045
  loop = uv_default_loop();
3046

3047
  r = uv_fs_open(NULL, &open_req1, "test_file",
3048
                 UV_FS_O_WRONLY | UV_FS_O_CREAT | add_flags, S_IWUSR | S_IRUSR,
3049
                 NULL);
3050
  ASSERT_GE(r, 0);
3051
  ASSERT_GE(open_req1.result, 0);
3052
  uv_fs_req_cleanup(&open_req1);
3053

3054
  iov = uv_buf_init(test_buf, sizeof(test_buf));
3055
  r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
3056
  ASSERT_GE(r, 0);
3057
  ASSERT_GE(write_req.result, 0);
3058
  uv_fs_req_cleanup(&write_req);
3059

3060
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3061
  ASSERT_OK(r);
3062
  ASSERT_OK(close_req.result);
3063
  uv_fs_req_cleanup(&close_req);
3064

3065
  r = uv_fs_open(NULL, &open_req1, "test_file",
3066
                 UV_FS_O_RDWR | UV_FS_O_APPEND | add_flags, 0, NULL);
3067
  ASSERT_GE(r, 0);
3068
  ASSERT_GE(open_req1.result, 0);
3069
  uv_fs_req_cleanup(&open_req1);
3070

3071
  iov = uv_buf_init(test_buf, sizeof(test_buf));
3072
  r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
3073
  ASSERT_GE(r, 0);
3074
  ASSERT_GE(write_req.result, 0);
3075
  uv_fs_req_cleanup(&write_req);
3076

3077
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3078
  ASSERT_OK(r);
3079
  ASSERT_OK(close_req.result);
3080
  uv_fs_req_cleanup(&close_req);
3081

3082
  r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDONLY | add_flags,
3083
      S_IRUSR, NULL);
3084
  ASSERT_GE(r, 0);
3085
  ASSERT_GE(open_req1.result, 0);
3086
  uv_fs_req_cleanup(&open_req1);
3087

3088
  iov = uv_buf_init(buf, sizeof(buf));
3089
  r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
3090
  printf("read = %d\n", r);
3091
  ASSERT_EQ(26, r);
3092
  ASSERT_EQ(26, read_req.result);
3093
  ASSERT_OK(memcmp(buf,
3094
                   "test-buffer\n\0test-buffer\n\0",
3095
                   sizeof("test-buffer\n\0test-buffer\n\0") - 1));
3096
  uv_fs_req_cleanup(&read_req);
3097

3098
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3099
  ASSERT_OK(r);
3100
  ASSERT_OK(close_req.result);
3101
  uv_fs_req_cleanup(&close_req);
3102

3103
  /* Cleanup */
3104
  unlink("test_file");
3105
}
3106
TEST_IMPL(fs_file_open_append) {
3107
  fs_file_open_append(0);
3108
  fs_file_open_append(UV_FS_O_FILEMAP);
3109

3110
  MAKE_VALGRIND_HAPPY(uv_default_loop());
3111
  return 0;
3112
}
3113

3114

3115
TEST_IMPL(fs_rename_to_existing_file) {
3116
  int r;
3117

3118
  /* Setup. */
3119
  unlink("test_file");
3120
  unlink("test_file2");
3121

3122
  loop = uv_default_loop();
3123

3124
  r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_WRONLY | UV_FS_O_CREAT,
3125
      S_IWUSR | S_IRUSR, NULL);
3126
  ASSERT_GE(r, 0);
3127
  ASSERT_GE(open_req1.result, 0);
3128
  uv_fs_req_cleanup(&open_req1);
3129

3130
  iov = uv_buf_init(test_buf, sizeof(test_buf));
3131
  r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
3132
  ASSERT_GE(r, 0);
3133
  ASSERT_GE(write_req.result, 0);
3134
  uv_fs_req_cleanup(&write_req);
3135

3136
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3137
  ASSERT_OK(r);
3138
  ASSERT_OK(close_req.result);
3139
  uv_fs_req_cleanup(&close_req);
3140

3141
  r = uv_fs_open(NULL, &open_req1, "test_file2", UV_FS_O_WRONLY | UV_FS_O_CREAT,
3142
      S_IWUSR | S_IRUSR, NULL);
3143
  ASSERT_GE(r, 0);
3144
  ASSERT_GE(open_req1.result, 0);
3145
  uv_fs_req_cleanup(&open_req1);
3146

3147
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3148
  ASSERT_OK(r);
3149
  ASSERT_OK(close_req.result);
3150
  uv_fs_req_cleanup(&close_req);
3151

3152
  r = uv_fs_rename(NULL, &rename_req, "test_file", "test_file2", NULL);
3153
  ASSERT_OK(r);
3154
  ASSERT_OK(rename_req.result);
3155
  uv_fs_req_cleanup(&rename_req);
3156

3157
  r = uv_fs_open(NULL, &open_req1, "test_file2", UV_FS_O_RDONLY, 0, NULL);
3158
  ASSERT_GE(r, 0);
3159
  ASSERT_GE(open_req1.result, 0);
3160
  uv_fs_req_cleanup(&open_req1);
3161

3162
  memset(buf, 0, sizeof(buf));
3163
  iov = uv_buf_init(buf, sizeof(buf));
3164
  r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
3165
  ASSERT_GE(r, 0);
3166
  ASSERT_GE(read_req.result, 0);
3167
  ASSERT_OK(strcmp(buf, test_buf));
3168
  uv_fs_req_cleanup(&read_req);
3169

3170
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3171
  ASSERT_OK(r);
3172
  ASSERT_OK(close_req.result);
3173
  uv_fs_req_cleanup(&close_req);
3174

3175
  /* Cleanup */
3176
  unlink("test_file");
3177
  unlink("test_file2");
3178

3179
  MAKE_VALGRIND_HAPPY(loop);
3180
  return 0;
3181
}
3182

3183

3184
static void fs_read_bufs(int add_flags) {
3185
  char scratch[768];
3186
  uv_buf_t bufs[4];
3187

3188
  ASSERT_LE(0, uv_fs_open(NULL, &open_req1,
3189
                          "test/fixtures/lorem_ipsum.txt",
3190
                          UV_FS_O_RDONLY | add_flags, 0, NULL));
3191
  ASSERT_GE(open_req1.result, 0);
3192
  uv_fs_req_cleanup(&open_req1);
3193

3194
  ASSERT_EQ(UV_EINVAL, uv_fs_read(NULL, &read_req, open_req1.result,
3195
                                  NULL, 0, 0, NULL));
3196
  ASSERT_EQ(UV_EINVAL, uv_fs_read(NULL, &read_req, open_req1.result,
3197
                                  NULL, 1, 0, NULL));
3198
  ASSERT_EQ(UV_EINVAL, uv_fs_read(NULL, &read_req, open_req1.result,
3199
                                  bufs, 0, 0, NULL));
3200

3201
  bufs[0] = uv_buf_init(scratch + 0, 256);
3202
  bufs[1] = uv_buf_init(scratch + 256, 256);
3203
  bufs[2] = uv_buf_init(scratch + 512, 128);
3204
  bufs[3] = uv_buf_init(scratch + 640, 128);
3205

3206
  ASSERT_EQ(446, uv_fs_read(NULL,
3207
                            &read_req,
3208
                            open_req1.result,
3209
                            bufs + 0,
3210
                            2,  /* 2x 256 bytes. */
3211
                            0,  /* Positional read. */
3212
                            NULL));
3213
  ASSERT_EQ(446, read_req.result);
3214
  uv_fs_req_cleanup(&read_req);
3215

3216
  ASSERT_EQ(190, uv_fs_read(NULL,
3217
                            &read_req,
3218
                            open_req1.result,
3219
                            bufs + 2,
3220
                            2,  /* 2x 128 bytes. */
3221
                            256,  /* Positional read. */
3222
                            NULL));
3223
  ASSERT_EQ(read_req.result, /* 446 - 256 */ 190);
3224
  uv_fs_req_cleanup(&read_req);
3225

3226
  ASSERT_OK(memcmp(bufs[1].base + 0, bufs[2].base, 128));
3227
  ASSERT_OK(memcmp(bufs[1].base + 128, bufs[3].base, 190 - 128));
3228

3229
  ASSERT_OK(uv_fs_close(NULL, &close_req, open_req1.result, NULL));
3230
  ASSERT_OK(close_req.result);
3231
  uv_fs_req_cleanup(&close_req);
3232
}
3233
TEST_IMPL(fs_read_bufs) {
3234
  fs_read_bufs(0);
3235
  fs_read_bufs(UV_FS_O_FILEMAP);
3236

3237
  MAKE_VALGRIND_HAPPY(uv_default_loop());
3238
  return 0;
3239
}
3240

3241

3242
static void fs_read_file_eof(int add_flags) {
3243
#if defined(__CYGWIN__) || defined(__MSYS__)
3244
  RETURN_SKIP("Cygwin pread at EOF may (incorrectly) return data!");
3245
#endif
3246
  int r;
3247

3248
  /* Setup. */
3249
  unlink("test_file");
3250

3251
  loop = uv_default_loop();
3252

3253
  r = uv_fs_open(NULL, &open_req1, "test_file",
3254
                 UV_FS_O_WRONLY | UV_FS_O_CREAT | add_flags, S_IWUSR | S_IRUSR,
3255
                 NULL);
3256
  ASSERT_GE(r, 0);
3257
  ASSERT_GE(open_req1.result, 0);
3258
  uv_fs_req_cleanup(&open_req1);
3259

3260
  iov = uv_buf_init(test_buf, sizeof(test_buf));
3261
  r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
3262
  ASSERT_GE(r, 0);
3263
  ASSERT_GE(write_req.result, 0);
3264
  uv_fs_req_cleanup(&write_req);
3265

3266
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3267
  ASSERT_OK(r);
3268
  ASSERT_OK(close_req.result);
3269
  uv_fs_req_cleanup(&close_req);
3270

3271
  r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDONLY | add_flags, 0,
3272
      NULL);
3273
  ASSERT_GE(r, 0);
3274
  ASSERT_GE(open_req1.result, 0);
3275
  uv_fs_req_cleanup(&open_req1);
3276

3277
  memset(buf, 0, sizeof(buf));
3278
  iov = uv_buf_init(buf, sizeof(buf));
3279
  r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
3280
  ASSERT_GE(r, 0);
3281
  ASSERT_GE(read_req.result, 0);
3282
  ASSERT_OK(strcmp(buf, test_buf));
3283
  uv_fs_req_cleanup(&read_req);
3284

3285
  iov = uv_buf_init(buf, sizeof(buf));
3286
  r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1,
3287
                 read_req.result, NULL);
3288
  ASSERT_OK(r);
3289
  ASSERT_OK(read_req.result);
3290
  uv_fs_req_cleanup(&read_req);
3291

3292
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3293
  ASSERT_OK(r);
3294
  ASSERT_OK(close_req.result);
3295
  uv_fs_req_cleanup(&close_req);
3296

3297
  /* Cleanup */
3298
  unlink("test_file");
3299
}
3300
TEST_IMPL(fs_read_file_eof) {
3301
  fs_read_file_eof(0);
3302
  fs_read_file_eof(UV_FS_O_FILEMAP);
3303

3304
  MAKE_VALGRIND_HAPPY(uv_default_loop());
3305
  return 0;
3306
}
3307

3308

3309
static void fs_write_multiple_bufs(int add_flags) {
3310
  uv_buf_t iovs[2];
3311
  int r;
3312

3313
  /* Setup. */
3314
  unlink("test_file");
3315

3316
  loop = uv_default_loop();
3317

3318
  r = uv_fs_open(NULL, &open_req1, "test_file",
3319
                 UV_FS_O_WRONLY | UV_FS_O_CREAT | add_flags, S_IWUSR | S_IRUSR,
3320
                 NULL);
3321
  ASSERT_GE(r, 0);
3322
  ASSERT_GE(open_req1.result, 0);
3323
  uv_fs_req_cleanup(&open_req1);
3324

3325
  iovs[0] = uv_buf_init(test_buf, sizeof(test_buf));
3326
  iovs[1] = uv_buf_init(test_buf2, sizeof(test_buf2));
3327
  r = uv_fs_write(NULL, &write_req, open_req1.result, iovs, 2, 0, NULL);
3328
  ASSERT_GE(r, 0);
3329
  ASSERT_GE(write_req.result, 0);
3330
  uv_fs_req_cleanup(&write_req);
3331

3332
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3333
  ASSERT_OK(r);
3334
  ASSERT_OK(close_req.result);
3335
  uv_fs_req_cleanup(&close_req);
3336

3337
  r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDONLY | add_flags, 0,
3338
      NULL);
3339
  ASSERT_GE(r, 0);
3340
  ASSERT_GE(open_req1.result, 0);
3341
  uv_fs_req_cleanup(&open_req1);
3342

3343
  memset(buf, 0, sizeof(buf));
3344
  memset(buf2, 0, sizeof(buf2));
3345
  /* Read the strings back to separate buffers. */
3346
  iovs[0] = uv_buf_init(buf, sizeof(test_buf));
3347
  iovs[1] = uv_buf_init(buf2, sizeof(test_buf2));
3348
  ASSERT_OK(lseek(open_req1.result, 0, SEEK_CUR));
3349
  r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, 2, -1, NULL);
3350
  ASSERT_GE(r, 0);
3351
  ASSERT_EQ(read_req.result, sizeof(test_buf) + sizeof(test_buf2));
3352
  ASSERT_OK(strcmp(buf, test_buf));
3353
  ASSERT_OK(strcmp(buf2, test_buf2));
3354
  uv_fs_req_cleanup(&read_req);
3355

3356
  iov = uv_buf_init(buf, sizeof(buf));
3357
  r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
3358
  ASSERT_OK(r);
3359
  ASSERT_OK(read_req.result);
3360
  uv_fs_req_cleanup(&read_req);
3361

3362
  /* Read the strings back to separate buffers. */
3363
  iovs[0] = uv_buf_init(buf, sizeof(test_buf));
3364
  iovs[1] = uv_buf_init(buf2, sizeof(test_buf2));
3365
  r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, 2, 0, NULL);
3366
  ASSERT_GE(r, 0);
3367
  if (read_req.result == sizeof(test_buf)) {
3368
    /* Infer that preadv is not available. */
3369
    uv_fs_req_cleanup(&read_req);
3370
    r = uv_fs_read(NULL, &read_req, open_req1.result, &iovs[1], 1, read_req.result, NULL);
3371
    ASSERT_GE(r, 0);
3372
    ASSERT_EQ(read_req.result, sizeof(test_buf2));
3373
  } else {
3374
    ASSERT_EQ(read_req.result, sizeof(test_buf) + sizeof(test_buf2));
3375
  }
3376
  ASSERT_OK(strcmp(buf, test_buf));
3377
  ASSERT_OK(strcmp(buf2, test_buf2));
3378
  uv_fs_req_cleanup(&read_req);
3379

3380
  iov = uv_buf_init(buf, sizeof(buf));
3381
  r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1,
3382
                 sizeof(test_buf) + sizeof(test_buf2), NULL);
3383
  ASSERT_OK(r);
3384
  ASSERT_OK(read_req.result);
3385
  uv_fs_req_cleanup(&read_req);
3386

3387
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3388
  ASSERT_OK(r);
3389
  ASSERT_OK(close_req.result);
3390
  uv_fs_req_cleanup(&close_req);
3391

3392
  /* Cleanup */
3393
  unlink("test_file");
3394
}
3395
TEST_IMPL(fs_write_multiple_bufs) {
3396
  fs_write_multiple_bufs(0);
3397
  fs_write_multiple_bufs(UV_FS_O_FILEMAP);
3398

3399
  MAKE_VALGRIND_HAPPY(uv_default_loop());
3400
  return 0;
3401
}
3402

3403

3404
static void fs_write_alotof_bufs(int add_flags) {
3405
  size_t iovcount;
3406
  size_t iovmax;
3407
  uv_buf_t* iovs;
3408
  char* buffer;
3409
  size_t index;
3410
  int r;
3411

3412
  iovcount = 54321;
3413

3414
  /* Setup. */
3415
  unlink("test_file");
3416

3417
  loop = uv_default_loop();
3418

3419
  iovs = malloc(sizeof(*iovs) * iovcount);
3420
  ASSERT_NOT_NULL(iovs);
3421
  iovmax = uv_test_getiovmax();
3422

3423
  r = uv_fs_open(NULL,
3424
                 &open_req1,
3425
                 "test_file",
3426
                 UV_FS_O_RDWR | UV_FS_O_CREAT | add_flags,
3427
                 S_IWUSR | S_IRUSR,
3428
                 NULL);
3429
  ASSERT_GE(r, 0);
3430
  ASSERT_GE(open_req1.result, 0);
3431
  uv_fs_req_cleanup(&open_req1);
3432

3433
  for (index = 0; index < iovcount; ++index)
3434
    iovs[index] = uv_buf_init(test_buf, sizeof(test_buf));
3435

3436
  r = uv_fs_write(NULL,
3437
                  &write_req,
3438
                  open_req1.result,
3439
                  iovs,
3440
                  iovcount,
3441
                  -1,
3442
                  NULL);
3443
  ASSERT_GE(r, 0);
3444
  ASSERT_EQ((size_t)write_req.result, sizeof(test_buf) * iovcount);
3445
  uv_fs_req_cleanup(&write_req);
3446

3447
  /* Read the strings back to separate buffers. */
3448
  buffer = malloc(sizeof(test_buf) * iovcount);
3449
  ASSERT_NOT_NULL(buffer);
3450

3451
  for (index = 0; index < iovcount; ++index)
3452
    iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf),
3453
                              sizeof(test_buf));
3454

3455
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3456
  ASSERT_OK(r);
3457
  ASSERT_OK(close_req.result);
3458
  uv_fs_req_cleanup(&close_req);
3459

3460
  r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDONLY | add_flags, 0,
3461
    NULL);
3462
  ASSERT_GE(r, 0);
3463
  ASSERT_GE(open_req1.result, 0);
3464
  uv_fs_req_cleanup(&open_req1);
3465

3466
  r = uv_fs_read(NULL, &read_req, open_req1.result, iovs, iovcount, -1, NULL);
3467
  if (iovcount > iovmax)
3468
    iovcount = iovmax;
3469
  ASSERT_GE(r, 0);
3470
  ASSERT_EQ((size_t)read_req.result, sizeof(test_buf) * iovcount);
3471

3472
  for (index = 0; index < iovcount; ++index)
3473
    ASSERT_OK(strncmp(buffer + index * sizeof(test_buf),
3474
                      test_buf,
3475
                      sizeof(test_buf)));
3476

3477
  uv_fs_req_cleanup(&read_req);
3478
  free(buffer);
3479

3480
  ASSERT_EQ(lseek(open_req1.result, write_req.result, SEEK_SET),
3481
            write_req.result);
3482
  iov = uv_buf_init(buf, sizeof(buf));
3483
  r = uv_fs_read(NULL,
3484
                 &read_req,
3485
                 open_req1.result,
3486
                 &iov,
3487
                 1,
3488
                 -1,
3489
                 NULL);
3490
  ASSERT_OK(r);
3491
  ASSERT_OK(read_req.result);
3492
  uv_fs_req_cleanup(&read_req);
3493

3494
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3495
  ASSERT_OK(r);
3496
  ASSERT_OK(close_req.result);
3497
  uv_fs_req_cleanup(&close_req);
3498

3499
  /* Cleanup */
3500
  unlink("test_file");
3501
  free(iovs);
3502
}
3503
TEST_IMPL(fs_write_alotof_bufs) {
3504
  fs_write_alotof_bufs(0);
3505
  fs_write_alotof_bufs(UV_FS_O_FILEMAP);
3506

3507
  MAKE_VALGRIND_HAPPY(uv_default_loop());
3508
  return 0;
3509
}
3510

3511

3512
static void fs_write_alotof_bufs_with_offset(int add_flags) {
3513
  size_t iovcount;
3514
  size_t iovmax;
3515
  uv_buf_t* iovs;
3516
  char* buffer;
3517
  size_t index;
3518
  int r;
3519
  int64_t offset;
3520
  char* filler;
3521
  int filler_len;
3522

3523
  filler = "0123456789";
3524
  filler_len = strlen(filler);
3525
  iovcount = 54321;
3526

3527
  /* Setup. */
3528
  unlink("test_file");
3529

3530
  loop = uv_default_loop();
3531

3532
  iovs = malloc(sizeof(*iovs) * iovcount);
3533
  ASSERT_NOT_NULL(iovs);
3534
  iovmax = uv_test_getiovmax();
3535

3536
  r = uv_fs_open(NULL,
3537
                 &open_req1,
3538
                 "test_file",
3539
                 UV_FS_O_RDWR | UV_FS_O_CREAT | add_flags,
3540
                 S_IWUSR | S_IRUSR,
3541
                 NULL);
3542
  ASSERT_GE(r, 0);
3543
  ASSERT_GE(open_req1.result, 0);
3544
  uv_fs_req_cleanup(&open_req1);
3545

3546
  iov = uv_buf_init(filler, filler_len);
3547
  r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
3548
  ASSERT_EQ(r, filler_len);
3549
  ASSERT_EQ(write_req.result, filler_len);
3550
  uv_fs_req_cleanup(&write_req);
3551
  offset = (int64_t)r;
3552

3553
  for (index = 0; index < iovcount; ++index)
3554
    iovs[index] = uv_buf_init(test_buf, sizeof(test_buf));
3555

3556
  r = uv_fs_write(NULL,
3557
                  &write_req,
3558
                  open_req1.result,
3559
                  iovs,
3560
                  iovcount,
3561
                  offset,
3562
                  NULL);
3563
  ASSERT_GE(r, 0);
3564
  ASSERT_EQ((size_t)write_req.result, sizeof(test_buf) * iovcount);
3565
  uv_fs_req_cleanup(&write_req);
3566

3567
  /* Read the strings back to separate buffers. */
3568
  buffer = malloc(sizeof(test_buf) * iovcount);
3569
  ASSERT_NOT_NULL(buffer);
3570

3571
  for (index = 0; index < iovcount; ++index)
3572
    iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf),
3573
                              sizeof(test_buf));
3574

3575
  r = uv_fs_read(NULL, &read_req, open_req1.result,
3576
                 iovs, iovcount, offset, NULL);
3577
  ASSERT_GE(r, 0);
3578
  if (r == sizeof(test_buf))
3579
    iovcount = 1; /* Infer that preadv is not available. */
3580
  else if (iovcount > iovmax)
3581
    iovcount = iovmax;
3582
  ASSERT_EQ((size_t)read_req.result, sizeof(test_buf) * iovcount);
3583

3584
  for (index = 0; index < iovcount; ++index)
3585
    ASSERT_OK(strncmp(buffer + index * sizeof(test_buf),
3586
                      test_buf,
3587
                      sizeof(test_buf)));
3588

3589
  uv_fs_req_cleanup(&read_req);
3590
  free(buffer);
3591

3592
  r = uv_fs_stat(NULL, &stat_req, "test_file", NULL);
3593
  ASSERT_OK(r);
3594
  ASSERT_EQ((int64_t)((uv_stat_t*)stat_req.ptr)->st_size,
3595
            offset + (int64_t)write_req.result);
3596
  uv_fs_req_cleanup(&stat_req);
3597

3598
  iov = uv_buf_init(buf, sizeof(buf));
3599
  r = uv_fs_read(NULL,
3600
                 &read_req,
3601
                 open_req1.result,
3602
                 &iov,
3603
                 1,
3604
                 offset + write_req.result,
3605
                 NULL);
3606
  ASSERT_OK(r);
3607
  ASSERT_OK(read_req.result);
3608
  uv_fs_req_cleanup(&read_req);
3609

3610
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3611
  ASSERT_OK(r);
3612
  ASSERT_OK(close_req.result);
3613
  uv_fs_req_cleanup(&close_req);
3614

3615
  /* Cleanup */
3616
  unlink("test_file");
3617
  free(iovs);
3618
}
3619
TEST_IMPL(fs_write_alotof_bufs_with_offset) {
3620
  fs_write_alotof_bufs_with_offset(0);
3621
  fs_write_alotof_bufs_with_offset(UV_FS_O_FILEMAP);
3622

3623
  MAKE_VALGRIND_HAPPY(uv_default_loop());
3624
  return 0;
3625
}
3626

3627
TEST_IMPL(fs_read_dir) {
3628
  int r;
3629
  char buf[2];
3630
  loop = uv_default_loop();
3631

3632
  /* Setup */
3633
  rmdir("test_dir");
3634
  r = uv_fs_mkdir(loop, &mkdir_req, "test_dir", 0755, mkdir_cb);
3635
  ASSERT_OK(r);
3636
  uv_run(loop, UV_RUN_DEFAULT);
3637
  ASSERT_EQ(1, mkdir_cb_count);
3638
  /* Setup Done Here */
3639

3640
  /* Get a file descriptor for the directory */
3641
  r = uv_fs_open(loop,
3642
                 &open_req1,
3643
                 "test_dir",
3644
                 UV_FS_O_RDONLY | UV_FS_O_DIRECTORY,
3645
                 S_IWUSR | S_IRUSR,
3646
                 NULL);
3647
  ASSERT_GE(r, 0);
3648
  uv_fs_req_cleanup(&open_req1);
3649

3650
  /* Try to read data from the directory */
3651
  iov = uv_buf_init(buf, sizeof(buf));
3652
  r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, 0, NULL);
3653
#if defined(__FreeBSD__)   || \
3654
    defined(__OpenBSD__)   || \
3655
    defined(__NetBSD__)    || \
3656
    defined(__DragonFly__) || \
3657
    defined(_AIX)          || \
3658
    defined(__sun)         || \
3659
    defined(__MVS__)
3660
  /*
3661
   * As of now, these operating systems support reading from a directory,
3662
   * that too depends on the filesystem this temporary test directory is
3663
   * created on. That is why this assertion is a bit lenient.
3664
   */
3665
  ASSERT((r >= 0) || (r == UV_EISDIR));
3666
#else
3667
  ASSERT_EQ(r, UV_EISDIR);
3668
#endif
3669
  uv_fs_req_cleanup(&read_req);
3670

3671
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3672
  ASSERT_OK(r);
3673
  uv_fs_req_cleanup(&close_req);
3674

3675
  /* Cleanup */
3676
  rmdir("test_dir");
3677

3678
  MAKE_VALGRIND_HAPPY(loop);
3679
  return 0;
3680
}
3681

3682
#ifdef _WIN32
3683

3684
TEST_IMPL(fs_partial_read) {
3685
  RETURN_SKIP("Test not implemented on Windows.");
3686
}
3687

3688
TEST_IMPL(fs_partial_write) {
3689
  RETURN_SKIP("Test not implemented on Windows.");
3690
}
3691

3692
#else  /* !_WIN32 */
3693

3694
struct thread_ctx {
3695
  pthread_t pid;
3696
  int fd;
3697
  char* data;
3698
  int size;
3699
  int interval;
3700
  int doread;
3701
};
3702

3703
static void thread_main(void* arg) {
3704
  const struct thread_ctx* ctx;
3705
  int size;
3706
  char* data;
3707

3708
  ctx = (struct thread_ctx*)arg;
3709
  size = ctx->size;
3710
  data = ctx->data;
3711

3712
  while (size > 0) {
3713
    ssize_t result;
3714
    int nbytes;
3715
    nbytes = size < ctx->interval ? size : ctx->interval;
3716
    if (ctx->doread) {
3717
      result = write(ctx->fd, data, nbytes);
3718
      /* Should not see EINTR (or other errors) */
3719
      ASSERT_EQ(result, nbytes);
3720
    } else {
3721
      result = read(ctx->fd, data, nbytes);
3722
      /* Should not see EINTR (or other errors),
3723
       * but might get a partial read if we are faster than the writer
3724
       */
3725
      ASSERT(result > 0 && result <= nbytes);
3726
    }
3727

3728
    pthread_kill(ctx->pid, SIGUSR1);
3729
    size -= result;
3730
    data += result;
3731
  }
3732
}
3733

3734
static void sig_func(uv_signal_t* handle, int signum) {
3735
  uv_signal_stop(handle);
3736
}
3737

3738
static size_t uv_test_fs_buf_offset(uv_buf_t* bufs, size_t size) {
3739
  size_t offset;
3740
  /* Figure out which bufs are done */
3741
  for (offset = 0; size > 0 && bufs[offset].len <= size; ++offset)
3742
    size -= bufs[offset].len;
3743

3744
  /* Fix a partial read/write */
3745
  if (size > 0) {
3746
    bufs[offset].base += size;
3747
    bufs[offset].len -= size;
3748
  }
3749
  return offset;
3750
}
3751

3752
static void test_fs_partial(int doread) {
3753
  struct thread_ctx ctx;
3754
  uv_thread_t thread;
3755
  uv_signal_t signal;
3756
  int pipe_fds[2];
3757
  size_t iovcount;
3758
  uv_buf_t* iovs;
3759
  char* buffer;
3760
  size_t index;
3761

3762
  iovcount = 54321;
3763

3764
  iovs = malloc(sizeof(*iovs) * iovcount);
3765
  ASSERT_NOT_NULL(iovs);
3766

3767
  ctx.pid = pthread_self();
3768
  ctx.doread = doread;
3769
  ctx.interval = 1000;
3770
  ctx.size = sizeof(test_buf) * iovcount;
3771
  ctx.data = calloc(ctx.size, 1);
3772
  ASSERT_NOT_NULL(ctx.data);
3773
  buffer = calloc(ctx.size, 1);
3774
  ASSERT_NOT_NULL(buffer);
3775

3776
  for (index = 0; index < iovcount; ++index)
3777
    iovs[index] = uv_buf_init(buffer + index * sizeof(test_buf), sizeof(test_buf));
3778

3779
  loop = uv_default_loop();
3780

3781
  ASSERT_OK(uv_signal_init(loop, &signal));
3782
  ASSERT_OK(uv_signal_start(&signal, sig_func, SIGUSR1));
3783

3784
  ASSERT_OK(pipe(pipe_fds));
3785

3786
  ctx.fd = pipe_fds[doread];
3787
  ASSERT_OK(uv_thread_create(&thread, thread_main, &ctx));
3788

3789
  if (doread) {
3790
    uv_buf_t* read_iovs;
3791
    int nread;
3792
    read_iovs = iovs;
3793
    nread = 0;
3794
    while (nread < ctx.size) {
3795
      int result;
3796
      result = uv_fs_read(loop, &read_req, pipe_fds[0], read_iovs, iovcount, -1, NULL);
3797
      if (result > 0) {
3798
        size_t read_iovcount;
3799
        read_iovcount = uv_test_fs_buf_offset(read_iovs, result);
3800
        read_iovs += read_iovcount;
3801
        iovcount -= read_iovcount;
3802
        nread += result;
3803
      } else {
3804
        ASSERT_EQ(result, UV_EINTR);
3805
      }
3806
      uv_fs_req_cleanup(&read_req);
3807
    }
3808
  } else {
3809
    int result;
3810
    result = uv_fs_write(loop, &write_req, pipe_fds[1], iovs, iovcount, -1, NULL);
3811
    ASSERT_EQ(write_req.result, result);
3812
    ASSERT_EQ(result, ctx.size);
3813
    uv_fs_req_cleanup(&write_req);
3814
  }
3815

3816
  ASSERT_OK(uv_thread_join(&thread));
3817

3818
  ASSERT_MEM_EQ(buffer, ctx.data, ctx.size);
3819

3820
  ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT));
3821

3822
  ASSERT_OK(close(pipe_fds[1]));
3823
  uv_close((uv_handle_t*) &signal, NULL);
3824

3825
  { /* Make sure we read everything that we wrote. */
3826
      int result;
3827
      result = uv_fs_read(loop, &read_req, pipe_fds[0], iovs, 1, -1, NULL);
3828
      ASSERT_OK(result);
3829
      uv_fs_req_cleanup(&read_req);
3830
  }
3831
  ASSERT_OK(close(pipe_fds[0]));
3832

3833
  free(iovs);
3834
  free(buffer);
3835
  free(ctx.data);
3836

3837
  MAKE_VALGRIND_HAPPY(loop);
3838
}
3839

3840
TEST_IMPL(fs_partial_read) {
3841
  test_fs_partial(1);
3842
  return 0;
3843
}
3844

3845
TEST_IMPL(fs_partial_write) {
3846
  test_fs_partial(0);
3847
  return 0;
3848
}
3849

3850
#endif/* _WIN32 */
3851

3852
TEST_IMPL(fs_read_write_null_arguments) {
3853
  int r;
3854

3855
  r = uv_fs_read(NULL, &read_req, 0, NULL, 0, -1, NULL);
3856
  ASSERT_EQ(r, UV_EINVAL);
3857
  uv_fs_req_cleanup(&read_req);
3858

3859
  r = uv_fs_write(NULL, &write_req, 0, NULL, 0, -1, NULL);
3860
  /* Validate some memory management on failed input validation before sending
3861
     fs work to the thread pool. */
3862
  ASSERT_EQ(r, UV_EINVAL);
3863
  ASSERT_NULL(write_req.path);
3864
  ASSERT_NULL(write_req.ptr);
3865
#ifdef _WIN32
3866
  ASSERT_NULL(write_req.file.pathw);
3867
  ASSERT_NULL(write_req.fs.info.new_pathw);
3868
  ASSERT_NULL(write_req.fs.info.bufs);
3869
#else
3870
  ASSERT_NULL(write_req.new_path);
3871
  ASSERT_NULL(write_req.bufs);
3872
#endif
3873
  uv_fs_req_cleanup(&write_req);
3874

3875
  iov = uv_buf_init(NULL, 0);
3876
  r = uv_fs_read(NULL, &read_req, 0, &iov, 0, -1, NULL);
3877
  ASSERT_EQ(r, UV_EINVAL);
3878
  uv_fs_req_cleanup(&read_req);
3879

3880
  iov = uv_buf_init(NULL, 0);
3881
  r = uv_fs_write(NULL, &write_req, 0, &iov, 0, -1, NULL);
3882
  ASSERT_EQ(r, UV_EINVAL);
3883
  uv_fs_req_cleanup(&write_req);
3884

3885
  /* If the arguments are invalid, the loop should not be kept open */
3886
  loop = uv_default_loop();
3887

3888
  r = uv_fs_read(loop, &read_req, 0, NULL, 0, -1, fail_cb);
3889
  ASSERT_EQ(r, UV_EINVAL);
3890
  uv_run(loop, UV_RUN_DEFAULT);
3891
  uv_fs_req_cleanup(&read_req);
3892

3893
  r = uv_fs_write(loop, &write_req, 0, NULL, 0, -1, fail_cb);
3894
  ASSERT_EQ(r, UV_EINVAL);
3895
  uv_run(loop, UV_RUN_DEFAULT);
3896
  uv_fs_req_cleanup(&write_req);
3897

3898
  iov = uv_buf_init(NULL, 0);
3899
  r = uv_fs_read(loop, &read_req, 0, &iov, 0, -1, fail_cb);
3900
  ASSERT_EQ(r, UV_EINVAL);
3901
  uv_run(loop, UV_RUN_DEFAULT);
3902
  uv_fs_req_cleanup(&read_req);
3903

3904
  iov = uv_buf_init(NULL, 0);
3905
  r = uv_fs_write(loop, &write_req, 0, &iov, 0, -1, fail_cb);
3906
  ASSERT_EQ(r, UV_EINVAL);
3907
  uv_run(loop, UV_RUN_DEFAULT);
3908
  uv_fs_req_cleanup(&write_req);
3909

3910
  MAKE_VALGRIND_HAPPY(loop);
3911
  return 0;
3912
}
3913

3914

3915
TEST_IMPL(get_osfhandle_valid_handle) {
3916
  int r;
3917
  uv_os_fd_t fd;
3918

3919
  /* Setup. */
3920
  unlink("test_file");
3921

3922
  loop = uv_default_loop();
3923

3924
  r = uv_fs_open(NULL,
3925
                 &open_req1, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT,
3926
                 S_IWUSR | S_IRUSR,
3927
                 NULL);
3928
  ASSERT_GE(r, 0);
3929
  ASSERT_GE(open_req1.result, 0);
3930
  uv_fs_req_cleanup(&open_req1);
3931

3932
  fd = uv_get_osfhandle(open_req1.result);
3933
#ifdef _WIN32
3934
  ASSERT_PTR_NE(fd, INVALID_HANDLE_VALUE);
3935
#else
3936
  ASSERT_GE(fd, 0);
3937
#endif
3938

3939
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3940
  ASSERT_OK(r);
3941
  ASSERT_OK(close_req.result);
3942
  uv_fs_req_cleanup(&close_req);
3943

3944
  /* Cleanup. */
3945
  unlink("test_file");
3946

3947
  MAKE_VALGRIND_HAPPY(loop);
3948
  return 0;
3949
}
3950

3951
TEST_IMPL(open_osfhandle_valid_handle) {
3952
  int r;
3953
  uv_os_fd_t handle;
3954
  int fd;
3955

3956
  /* Setup. */
3957
  unlink("test_file");
3958

3959
  loop = uv_default_loop();
3960

3961
  r = uv_fs_open(NULL,
3962
                 &open_req1,
3963
                 "test_file",
3964
                 UV_FS_O_RDWR | UV_FS_O_CREAT,
3965
                 S_IWUSR | S_IRUSR,
3966
                 NULL);
3967
  ASSERT_GE(r, 0);
3968
  ASSERT_GE(open_req1.result, 0);
3969
  uv_fs_req_cleanup(&open_req1);
3970

3971
  handle = uv_get_osfhandle(open_req1.result);
3972
#ifdef _WIN32
3973
  ASSERT_PTR_NE(handle, INVALID_HANDLE_VALUE);
3974
#else
3975
  ASSERT_GE(handle, 0);
3976
#endif
3977

3978
  fd = uv_open_osfhandle(handle);
3979
#ifdef _WIN32
3980
  ASSERT_GT(fd, 0);
3981
#else
3982
  ASSERT_EQ(fd, open_req1.result);
3983
#endif
3984

3985
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
3986
  ASSERT_OK(r);
3987
  ASSERT_OK(close_req.result);
3988
  uv_fs_req_cleanup(&close_req);
3989

3990
  /* Cleanup. */
3991
  unlink("test_file");
3992

3993
  MAKE_VALGRIND_HAPPY(loop);
3994
  return 0;
3995
}
3996

3997
TEST_IMPL(fs_file_pos_after_op_with_offset) {
3998
  int r;
3999

4000
  /* Setup. */
4001
  unlink("test_file");
4002
  loop = uv_default_loop();
4003

4004
  r = uv_fs_open(loop,
4005
                 &open_req1, "test_file", UV_FS_O_RDWR | UV_FS_O_CREAT,
4006
                 S_IWUSR | S_IRUSR,
4007
                 NULL);
4008
  ASSERT_GT(r, 0);
4009
  uv_fs_req_cleanup(&open_req1);
4010

4011
  iov = uv_buf_init(test_buf, sizeof(test_buf));
4012
  r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, 0, NULL);
4013
  ASSERT_EQ(r, sizeof(test_buf));
4014
  ASSERT_OK(lseek(open_req1.result, 0, SEEK_CUR));
4015
  uv_fs_req_cleanup(&write_req);
4016

4017
  iov = uv_buf_init(buf, sizeof(buf));
4018
  r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, 0, NULL);
4019
  ASSERT_EQ(r, sizeof(test_buf));
4020
  ASSERT_OK(strcmp(buf, test_buf));
4021
  ASSERT_OK(lseek(open_req1.result, 0, SEEK_CUR));
4022
  uv_fs_req_cleanup(&read_req);
4023

4024
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
4025
  ASSERT_OK(r);
4026
  uv_fs_req_cleanup(&close_req);
4027

4028
  /* Cleanup */
4029
  unlink("test_file");
4030

4031
  MAKE_VALGRIND_HAPPY(loop);
4032
  return 0;
4033
}
4034

4035
#ifdef _WIN32
4036
static void fs_file_pos_common(void) {
4037
  int r;
4038

4039
  iov = uv_buf_init("abc", 3);
4040
  r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
4041
  ASSERT_EQ(3, r);
4042
  uv_fs_req_cleanup(&write_req);
4043

4044
  /* Read with offset should not change the position */
4045
  iov = uv_buf_init(buf, 1);
4046
  r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, 1, NULL);
4047
  ASSERT_EQ(1, r);
4048
  ASSERT_EQ(buf[0], 'b');
4049
  uv_fs_req_cleanup(&read_req);
4050

4051
  iov = uv_buf_init(buf, sizeof(buf));
4052
  r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
4053
  ASSERT_OK(r);
4054
  uv_fs_req_cleanup(&read_req);
4055

4056
  /* Write without offset should change the position */
4057
  iov = uv_buf_init("d", 1);
4058
  r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, -1, NULL);
4059
  ASSERT_EQ(1, r);
4060
  uv_fs_req_cleanup(&write_req);
4061

4062
  iov = uv_buf_init(buf, sizeof(buf));
4063
  r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
4064
  ASSERT_OK(r);
4065
  uv_fs_req_cleanup(&read_req);
4066
}
4067

4068
static void fs_file_pos_close_check(const char *contents, int size) {
4069
  int r;
4070

4071
  /* Close */
4072
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
4073
  ASSERT_OK(r);
4074
  uv_fs_req_cleanup(&close_req);
4075

4076
  /* Confirm file contents */
4077
  r = uv_fs_open(NULL, &open_req1, "test_file", UV_FS_O_RDONLY, 0, NULL);
4078
  ASSERT_GE(r, 0);
4079
  ASSERT_GE(open_req1.result, 0);
4080
  uv_fs_req_cleanup(&open_req1);
4081

4082
  iov = uv_buf_init(buf, sizeof(buf));
4083
  r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
4084
  ASSERT_EQ(r, size);
4085
  ASSERT_OK(strncmp(buf, contents, size));
4086
  uv_fs_req_cleanup(&read_req);
4087

4088
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
4089
  ASSERT_OK(r);
4090
  uv_fs_req_cleanup(&close_req);
4091

4092
  /* Cleanup */
4093
  unlink("test_file");
4094
}
4095

4096
static void fs_file_pos_write(int add_flags) {
4097
  int r;
4098

4099
  /* Setup. */
4100
  unlink("test_file");
4101

4102
  r = uv_fs_open(NULL,
4103
                 &open_req1,
4104
                 "test_file",
4105
                 UV_FS_O_TRUNC | UV_FS_O_CREAT | UV_FS_O_RDWR | add_flags,
4106
                 S_IWUSR | S_IRUSR,
4107
                 NULL);
4108
  ASSERT_GT(r, 0);
4109
  uv_fs_req_cleanup(&open_req1);
4110

4111
  fs_file_pos_common();
4112

4113
  /* Write with offset should not change the position */
4114
  iov = uv_buf_init("e", 1);
4115
  r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, 1, NULL);
4116
  ASSERT_EQ(1, r);
4117
  uv_fs_req_cleanup(&write_req);
4118

4119
  iov = uv_buf_init(buf, sizeof(buf));
4120
  r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
4121
  ASSERT_OK(r);
4122
  uv_fs_req_cleanup(&read_req);
4123

4124
  fs_file_pos_close_check("aecd", 4);
4125
}
4126
TEST_IMPL(fs_file_pos_write) {
4127
  fs_file_pos_write(0);
4128
  fs_file_pos_write(UV_FS_O_FILEMAP);
4129

4130
  MAKE_VALGRIND_HAPPY(uv_default_loop());
4131
  return 0;
4132
}
4133

4134
static void fs_file_pos_append(int add_flags) {
4135
  int r;
4136

4137
  /* Setup. */
4138
  unlink("test_file");
4139

4140
  r = uv_fs_open(NULL,
4141
                 &open_req1,
4142
                 "test_file",
4143
                 UV_FS_O_APPEND | UV_FS_O_CREAT | UV_FS_O_RDWR | add_flags,
4144
                 S_IWUSR | S_IRUSR,
4145
                 NULL);
4146
  ASSERT_GT(r, 0);
4147
  uv_fs_req_cleanup(&open_req1);
4148

4149
  fs_file_pos_common();
4150

4151
  /* Write with offset appends (ignoring offset)
4152
   * but does not change the position */
4153
  iov = uv_buf_init("e", 1);
4154
  r = uv_fs_write(NULL, &write_req, open_req1.result, &iov, 1, 1, NULL);
4155
  ASSERT_EQ(1, r);
4156
  uv_fs_req_cleanup(&write_req);
4157

4158
  iov = uv_buf_init(buf, sizeof(buf));
4159
  r = uv_fs_read(NULL, &read_req, open_req1.result, &iov, 1, -1, NULL);
4160
  ASSERT_EQ(1, r);
4161
  ASSERT_EQ(buf[0], 'e');
4162
  uv_fs_req_cleanup(&read_req);
4163

4164
  fs_file_pos_close_check("abcde", 5);
4165
}
4166
TEST_IMPL(fs_file_pos_append) {
4167
  fs_file_pos_append(0);
4168
  fs_file_pos_append(UV_FS_O_FILEMAP);
4169

4170
  MAKE_VALGRIND_HAPPY(uv_default_loop());
4171
  return 0;
4172
}
4173
#endif
4174

4175
TEST_IMPL(fs_null_req) {
4176
  /* Verify that all fs functions return UV_EINVAL when the request is NULL. */
4177
  int r;
4178

4179
  r = uv_fs_open(NULL, NULL, NULL, 0, 0, NULL);
4180
  ASSERT_EQ(r, UV_EINVAL);
4181

4182
  r = uv_fs_close(NULL, NULL, 0, NULL);
4183
  ASSERT_EQ(r, UV_EINVAL);
4184

4185
  r = uv_fs_read(NULL, NULL, 0, NULL, 0, -1, NULL);
4186
  ASSERT_EQ(r, UV_EINVAL);
4187

4188
  r = uv_fs_write(NULL, NULL, 0, NULL, 0, -1, NULL);
4189
  ASSERT_EQ(r, UV_EINVAL);
4190

4191
  r = uv_fs_unlink(NULL, NULL, NULL, NULL);
4192
  ASSERT_EQ(r, UV_EINVAL);
4193

4194
  r = uv_fs_mkdir(NULL, NULL, NULL, 0, NULL);
4195
  ASSERT_EQ(r, UV_EINVAL);
4196

4197
  r = uv_fs_mkdtemp(NULL, NULL, NULL, NULL);
4198
  ASSERT_EQ(r, UV_EINVAL);
4199

4200
  r = uv_fs_mkstemp(NULL, NULL, NULL, NULL);
4201
  ASSERT_EQ(r, UV_EINVAL);
4202

4203
  r = uv_fs_rmdir(NULL, NULL, NULL, NULL);
4204
  ASSERT_EQ(r, UV_EINVAL);
4205

4206
  r = uv_fs_scandir(NULL, NULL, NULL, 0, NULL);
4207
  ASSERT_EQ(r, UV_EINVAL);
4208

4209
  r = uv_fs_link(NULL, NULL, NULL, NULL, NULL);
4210
  ASSERT_EQ(r, UV_EINVAL);
4211

4212
  r = uv_fs_symlink(NULL, NULL, NULL, NULL, 0, NULL);
4213
  ASSERT_EQ(r, UV_EINVAL);
4214

4215
  r = uv_fs_readlink(NULL, NULL, NULL, NULL);
4216
  ASSERT_EQ(r, UV_EINVAL);
4217

4218
  r = uv_fs_realpath(NULL, NULL, NULL, NULL);
4219
  ASSERT_EQ(r, UV_EINVAL);
4220

4221
  r = uv_fs_chown(NULL, NULL, NULL, 0, 0, NULL);
4222
  ASSERT_EQ(r, UV_EINVAL);
4223

4224
  r = uv_fs_fchown(NULL, NULL, 0, 0, 0, NULL);
4225
  ASSERT_EQ(r, UV_EINVAL);
4226

4227
  r = uv_fs_stat(NULL, NULL, NULL, NULL);
4228
  ASSERT_EQ(r, UV_EINVAL);
4229

4230
  r = uv_fs_lstat(NULL, NULL, NULL, NULL);
4231
  ASSERT_EQ(r, UV_EINVAL);
4232

4233
  r = uv_fs_fstat(NULL, NULL, 0, NULL);
4234
  ASSERT_EQ(r, UV_EINVAL);
4235

4236
  r = uv_fs_rename(NULL, NULL, NULL, NULL, NULL);
4237
  ASSERT_EQ(r, UV_EINVAL);
4238

4239
  r = uv_fs_fsync(NULL, NULL, 0, NULL);
4240
  ASSERT_EQ(r, UV_EINVAL);
4241

4242
  r = uv_fs_fdatasync(NULL, NULL, 0, NULL);
4243
  ASSERT_EQ(r, UV_EINVAL);
4244

4245
  r = uv_fs_ftruncate(NULL, NULL, 0, 0, NULL);
4246
  ASSERT_EQ(r, UV_EINVAL);
4247

4248
  r = uv_fs_copyfile(NULL, NULL, NULL, NULL, 0, NULL);
4249
  ASSERT_EQ(r, UV_EINVAL);
4250

4251
  r = uv_fs_sendfile(NULL, NULL, 0, 0, 0, 0, NULL);
4252
  ASSERT_EQ(r, UV_EINVAL);
4253

4254
  r = uv_fs_access(NULL, NULL, NULL, 0, NULL);
4255
  ASSERT_EQ(r, UV_EINVAL);
4256

4257
  r = uv_fs_chmod(NULL, NULL, NULL, 0, NULL);
4258
  ASSERT_EQ(r, UV_EINVAL);
4259

4260
  r = uv_fs_fchmod(NULL, NULL, 0, 0, NULL);
4261
  ASSERT_EQ(r, UV_EINVAL);
4262

4263
  r = uv_fs_utime(NULL, NULL, NULL, 0.0, 0.0, NULL);
4264
  ASSERT_EQ(r, UV_EINVAL);
4265

4266
  r = uv_fs_futime(NULL, NULL, 0, 0.0, 0.0, NULL);
4267
  ASSERT_EQ(r, UV_EINVAL);
4268

4269
  r = uv_fs_statfs(NULL, NULL, NULL, NULL);
4270
  ASSERT_EQ(r, UV_EINVAL);
4271

4272
  /* This should be a no-op. */
4273
  uv_fs_req_cleanup(NULL);
4274

4275
  return 0;
4276
}
4277

4278
#ifdef _WIN32
4279
TEST_IMPL(fs_exclusive_sharing_mode) {
4280
  int r;
4281

4282
  /* Setup. */
4283
  unlink("test_file");
4284

4285
  ASSERT_GT(UV_FS_O_EXLOCK, 0);
4286

4287
  r = uv_fs_open(NULL,
4288
                 &open_req1,
4289
                 "test_file",
4290
                 UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_EXLOCK,
4291
                 S_IWUSR | S_IRUSR,
4292
                 NULL);
4293
  ASSERT_GE(r, 0);
4294
  ASSERT_GE(open_req1.result, 0);
4295
  uv_fs_req_cleanup(&open_req1);
4296

4297
  r = uv_fs_open(NULL,
4298
                 &open_req2,
4299
                 "test_file", UV_FS_O_RDONLY | UV_FS_O_EXLOCK,
4300
                 S_IWUSR | S_IRUSR,
4301
                 NULL);
4302
  ASSERT_LT(r, 0);
4303
  ASSERT_LT(open_req2.result, 0);
4304
  uv_fs_req_cleanup(&open_req2);
4305

4306
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
4307
  ASSERT_OK(r);
4308
  ASSERT_OK(close_req.result);
4309
  uv_fs_req_cleanup(&close_req);
4310

4311
  r = uv_fs_open(NULL,
4312
                 &open_req2,
4313
                 "test_file", UV_FS_O_RDONLY | UV_FS_O_EXLOCK,
4314
                 S_IWUSR | S_IRUSR,
4315
                 NULL);
4316
  ASSERT_GE(r, 0);
4317
  ASSERT_GE(open_req2.result, 0);
4318
  uv_fs_req_cleanup(&open_req2);
4319

4320
  r = uv_fs_close(NULL, &close_req, open_req2.result, NULL);
4321
  ASSERT_OK(r);
4322
  ASSERT_OK(close_req.result);
4323
  uv_fs_req_cleanup(&close_req);
4324

4325
  /* Cleanup */
4326
  unlink("test_file");
4327

4328
  MAKE_VALGRIND_HAPPY(uv_default_loop());
4329
  return 0;
4330
}
4331
#endif
4332

4333
#ifdef _WIN32
4334
TEST_IMPL(fs_file_flag_no_buffering) {
4335
  int r;
4336

4337
  /* Setup. */
4338
  unlink("test_file");
4339

4340
  ASSERT_GT(UV_FS_O_APPEND, 0);
4341
  ASSERT_GT(UV_FS_O_CREAT, 0);
4342
  ASSERT_GT(UV_FS_O_DIRECT, 0);
4343
  ASSERT_GT(UV_FS_O_RDWR, 0);
4344

4345
  /* FILE_APPEND_DATA must be excluded from FILE_GENERIC_WRITE: */
4346
  r = uv_fs_open(NULL,
4347
                 &open_req1,
4348
                 "test_file",
4349
                 UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_DIRECT,
4350
                 S_IWUSR | S_IRUSR,
4351
                 NULL);
4352
  ASSERT_GE(r, 0);
4353
  ASSERT_GE(open_req1.result, 0);
4354
  uv_fs_req_cleanup(&open_req1);
4355

4356
  r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
4357
  ASSERT_OK(r);
4358
  ASSERT_OK(close_req.result);
4359
  uv_fs_req_cleanup(&close_req);
4360

4361
  /* FILE_APPEND_DATA and FILE_FLAG_NO_BUFFERING are mutually exclusive: */
4362
  r = uv_fs_open(NULL,
4363
                 &open_req2,
4364
                 "test_file",
4365
                 UV_FS_O_APPEND | UV_FS_O_DIRECT,
4366
                 S_IWUSR | S_IRUSR,
4367
                 NULL);
4368
  ASSERT_EQ(r, UV_EINVAL);
4369
  ASSERT_EQ(open_req2.result, UV_EINVAL);
4370
  uv_fs_req_cleanup(&open_req2);
4371

4372
  /* Cleanup */
4373
  unlink("test_file");
4374

4375
  MAKE_VALGRIND_HAPPY(uv_default_loop());
4376
  return 0;
4377
}
4378
#endif
4379

4380
#ifdef _WIN32
4381
int call_icacls(const char* command, ...) {
4382
    char icacls_command[1024];
4383
    va_list args;
4384

4385
    va_start(args, command);
4386
    vsnprintf(icacls_command, ARRAYSIZE(icacls_command), command, args);
4387
    va_end(args);
4388
    return system(icacls_command);
4389
}
4390

4391
TEST_IMPL(fs_open_readonly_acl) {
4392
    uv_passwd_t pwd;
4393
    uv_fs_t req;
4394
    int r;
4395

4396
    /*
4397
        Based on Node.js test from
4398
        https://github.com/nodejs/node/commit/3ba81e34e86a5c32658e218cb6e65b13e8326bc5
4399

4400
        If anything goes wrong, you can delte the test_fle_icacls with:
4401

4402
            icacls test_file_icacls /remove "%USERNAME%" /inheritance:e
4403
            attrib -r test_file_icacls
4404
            del test_file_icacls
4405
    */
4406

4407
    /* Setup - clear the ACL and remove the file */
4408
    loop = uv_default_loop();
4409
    r = uv_os_get_passwd(&pwd);
4410
    ASSERT_OK(r);
4411
    call_icacls("icacls test_file_icacls /remove \"%s\" /inheritance:e",
4412
                pwd.username);
4413
    uv_fs_chmod(loop, &req, "test_file_icacls", S_IWUSR, NULL);
4414
    unlink("test_file_icacls");
4415

4416
    /* Create the file */
4417
    r = uv_fs_open(loop,
4418
                   &open_req1,
4419
                   "test_file_icacls",
4420
                   UV_FS_O_RDONLY | UV_FS_O_CREAT,
4421
                   S_IRUSR,
4422
                   NULL);
4423
    ASSERT_GE(r, 0);
4424
    ASSERT_GE(open_req1.result, 0);
4425
    uv_fs_req_cleanup(&open_req1);
4426
    r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
4427
    ASSERT_OK(r);
4428
    ASSERT_OK(close_req.result);
4429
    uv_fs_req_cleanup(&close_req);
4430

4431
    /* Set up ACL */
4432
    r = call_icacls("icacls test_file_icacls /inheritance:r /remove \"%s\"",
4433
                    pwd.username);
4434
    if (r != 0) {
4435
        goto acl_cleanup;
4436
    }
4437
    r = call_icacls("icacls test_file_icacls /grant \"%s\":RX", pwd.username);
4438
    if (r != 0) {
4439
        goto acl_cleanup;
4440
    }
4441

4442
    /* Try opening the file */
4443
    r = uv_fs_open(NULL, &open_req1, "test_file_icacls", UV_FS_O_RDONLY, 0,
4444
                   NULL);
4445
    if (r < 0) {
4446
        goto acl_cleanup;
4447
    }
4448
    uv_fs_req_cleanup(&open_req1);
4449
    r = uv_fs_close(NULL, &close_req, open_req1.result, NULL);
4450
    if (r != 0) {
4451
        goto acl_cleanup;
4452
    }
4453
    uv_fs_req_cleanup(&close_req);
4454

4455
 acl_cleanup:
4456
    /* Cleanup */
4457
    call_icacls("icacls test_file_icacls /remove \"%s\" /inheritance:e",
4458
                pwd.username);
4459
    unlink("test_file_icacls");
4460
    uv_os_free_passwd(&pwd);
4461
    ASSERT_OK(r);
4462
    MAKE_VALGRIND_HAPPY(loop);
4463
    return 0;
4464
}
4465
#endif
4466

4467
#ifdef _WIN32
4468
TEST_IMPL(fs_fchmod_archive_readonly) {
4469
    uv_fs_t req;
4470
    uv_file file;
4471
    int r;
4472
    /* Test clearing read-only flag from files with Archive flag cleared */
4473

4474
    /* Setup*/
4475
    unlink("test_file");
4476
    r = uv_fs_open(NULL,
4477
                   &req, "test_file", UV_FS_O_WRONLY | UV_FS_O_CREAT,
4478
                   S_IWUSR | S_IRUSR,
4479
                   NULL);
4480
    ASSERT_GE(r, 0);
4481
    ASSERT_GE(req.result, 0);
4482
    file = req.result;
4483
    uv_fs_req_cleanup(&req);
4484
    r = uv_fs_close(NULL, &req, file, NULL);
4485
    ASSERT_OK(r);
4486
    uv_fs_req_cleanup(&req);
4487
    /* Make the file read-only and clear archive flag */
4488
    r = SetFileAttributes("test_file", FILE_ATTRIBUTE_READONLY);
4489
    ASSERT(r);
4490
    check_permission("test_file", 0400);
4491
    /* Try fchmod */
4492
    r = uv_fs_open(NULL, &req, "test_file", UV_FS_O_RDONLY, 0, NULL);
4493
    ASSERT_GE(r, 0);
4494
    ASSERT_GE(req.result, 0);
4495
    file = req.result;
4496
    uv_fs_req_cleanup(&req);
4497
    r = uv_fs_fchmod(NULL, &req, file, S_IWUSR, NULL);
4498
    ASSERT_OK(r);
4499
    ASSERT_OK(req.result);
4500
    uv_fs_req_cleanup(&req);
4501
    r = uv_fs_close(NULL, &req, file, NULL);
4502
    ASSERT_OK(r);
4503
    uv_fs_req_cleanup(&req);
4504
    check_permission("test_file", S_IWUSR);
4505

4506
    /* Restore Archive flag for rest of the tests */
4507
    r = SetFileAttributes("test_file", FILE_ATTRIBUTE_ARCHIVE);
4508
    ASSERT(r);
4509

4510
    return 0;
4511
}
4512

4513
TEST_IMPL(fs_invalid_mkdir_name) {
4514
  uv_loop_t* loop;
4515
  uv_fs_t req;
4516
  int r;
4517

4518
  loop = uv_default_loop();
4519
  r = uv_fs_mkdir(loop, &req, "invalid>", 0, NULL);
4520
  ASSERT_EQ(r, UV_EINVAL);
4521
  ASSERT_EQ(UV_EINVAL, uv_fs_mkdir(loop, &req, "test:lol", 0, NULL));
4522

4523
  return 0;
4524
}
4525
#endif
4526

4527
TEST_IMPL(fs_statfs) {
4528
  uv_fs_t req;
4529
  int r;
4530

4531
  loop = uv_default_loop();
4532

4533
  /* Test the synchronous version. */
4534
  r = uv_fs_statfs(NULL, &req, ".", NULL);
4535
  ASSERT_OK(r);
4536
  statfs_cb(&req);
4537
  ASSERT_EQ(1, statfs_cb_count);
4538

4539
  /* Test the asynchronous version. */
4540
  r = uv_fs_statfs(loop, &req, ".", statfs_cb);
4541
  ASSERT_OK(r);
4542
  uv_run(loop, UV_RUN_DEFAULT);
4543
  ASSERT_EQ(2, statfs_cb_count);
4544

4545
  MAKE_VALGRIND_HAPPY(loop);
4546
  return 0;
4547
}
4548

4549
TEST_IMPL(fs_get_system_error) {
4550
  uv_fs_t req;
4551
  int r;
4552
  int system_error;
4553

4554
  r = uv_fs_statfs(NULL, &req, "non_existing_file", NULL);
4555
  ASSERT(r);
4556

4557
  system_error = uv_fs_get_system_error(&req);
4558
#ifdef _WIN32
4559
  ASSERT_EQ(system_error, ERROR_FILE_NOT_FOUND);
4560
#else
4561
  ASSERT_EQ(system_error, ENOENT);
4562
#endif
4563

4564
  return 0;
4565
}
4566

4567

4568
TEST_IMPL(fs_stat_batch_multiple) {
4569
  uv_fs_t req[300];
4570
  int r;
4571
  int i;
4572

4573
  rmdir("test_dir");
4574

4575
  r = uv_fs_mkdir(NULL, &mkdir_req, "test_dir", 0755, NULL);
4576
  ASSERT_OK(r);
4577

4578
  loop = uv_default_loop();
4579

4580
  for (i = 0; i < (int) ARRAY_SIZE(req); ++i) {
4581
    r = uv_fs_stat(loop, &req[i], "test_dir", stat_batch_cb);
4582
    ASSERT_OK(r);
4583
  }
4584

4585
  uv_run(loop, UV_RUN_DEFAULT);
4586
  ASSERT_EQ(stat_cb_count, ARRAY_SIZE(req));
4587

4588
  MAKE_VALGRIND_HAPPY(loop);
4589
  return 0;
4590
}
4591

4592

4593
#ifdef _WIN32
4594
TEST_IMPL(fs_wtf) {
4595
  int r;
4596
  HANDLE file_handle;
4597
  uv_dirent_t dent;
4598
  static char test_file_buf[PATHMAX];
4599

4600
  /* set-up */
4601
  _wunlink(L"test_dir/hi\xD801\x0037");
4602
  rmdir("test_dir");
4603

4604
  loop = uv_default_loop();
4605

4606
  r = uv_fs_mkdir(NULL, &mkdir_req, "test_dir", 0777, NULL);
4607
  ASSERT_OK(r);
4608
  uv_fs_req_cleanup(&mkdir_req);
4609

4610
  file_handle = CreateFileW(L"test_dir/hi\xD801\x0037",
4611
                            GENERIC_WRITE | FILE_WRITE_ATTRIBUTES,
4612
                            0,
4613
                            NULL,
4614
                            CREATE_ALWAYS,
4615
                            FILE_FLAG_OPEN_REPARSE_POINT |
4616
                              FILE_FLAG_BACKUP_SEMANTICS,
4617
                            NULL);
4618
  ASSERT_PTR_NE(file_handle, INVALID_HANDLE_VALUE);
4619

4620
  CloseHandle(file_handle);
4621

4622
  r = uv_fs_scandir(NULL, &scandir_req, "test_dir", 0, NULL);
4623
  ASSERT_EQ(1, r);
4624
  ASSERT_EQ(1, scandir_req.result);
4625
  ASSERT_NOT_NULL(scandir_req.ptr);
4626
  while (UV_EOF != uv_fs_scandir_next(&scandir_req, &dent)) {
4627
    snprintf(test_file_buf, sizeof(test_file_buf), "test_dir\\%s", dent.name);
4628
    printf("stat %s\n", test_file_buf);
4629
    r = uv_fs_stat(NULL, &stat_req, test_file_buf, NULL);
4630
    ASSERT_OK(r);
4631
  }
4632
  uv_fs_req_cleanup(&scandir_req);
4633
  ASSERT_NULL(scandir_req.ptr);
4634

4635
  /* clean-up */
4636
  _wunlink(L"test_dir/hi\xD801\x0037");
4637
  rmdir("test_dir");
4638

4639
  MAKE_VALGRIND_HAPPY(loop);
4640
  return 0;
4641
}
4642
#endif
4643

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.