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