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