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