1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <fcntl.h>
6 #include <stdint.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <sys/stat.h>
10 #include <unistd.h>
11
12 #include <lib/fdio/limits.h>
13 #include <lib/fdio/util.h>
14 #include <unittest/unittest.h>
15 #include <zircon/syscalls.h>
16
17 #include "filesystems.h"
18
test_basic(void)19 bool test_basic(void) {
20 BEGIN_TEST;
21
22 ASSERT_EQ(mkdir("::alpha", 0755), 0, "");
23 ASSERT_EQ(mkdir("::alpha/bravo", 0755), 0, "");
24 ASSERT_EQ(mkdir("::alpha/bravo/charlie", 0755), 0, "");
25 ASSERT_EQ(mkdir("::alpha/bravo/charlie/delta", 0755), 0, "");
26 ASSERT_EQ(mkdir("::alpha/bravo/charlie/delta/echo", 0755), 0, "");
27 int fd1 = open("::alpha/bravo/charlie/delta/echo/foxtrot", O_RDWR | O_CREAT, 0644);
28 ASSERT_GT(fd1, 0, "");
29 int fd2 = open("::alpha/bravo/charlie/delta/echo/foxtrot", O_RDWR, 0644);
30 ASSERT_GT(fd2, 0, "");
31 ASSERT_EQ(write(fd1, "Hello, World!\n", 14), 14, "");
32 ASSERT_EQ(close(fd1), 0, "");
33 ASSERT_EQ(close(fd2), 0, "");
34
35 // test pipelined opens
36 // the open itself will always succeed if the remote side exists,
37 // but we'll get an error when we try to do an operation on the file
38 fd1 = open("::alpha/bravo/charlie/delta/echo/foxtrot", O_RDONLY | O_PIPELINE, 0644);
39 ASSERT_GT(fd1, 0, "");
40 char tmp[14];
41 ASSERT_EQ(read(fd1, tmp, 14), 14, "");
42 ASSERT_EQ(close(fd1), 0, "");
43 ASSERT_EQ(memcmp(tmp, "Hello, World!\n", 14), 0, "");
44
45 fd1 = open("::alpha/banana", O_RDONLY | O_PIPELINE, 0644);
46 ASSERT_GT(fd1, 0, "");
47 ASSERT_EQ(read(fd1, tmp, 14), -1, "");
48 ASSERT_EQ(close(fd1), -1, "");
49
50 fd1 = open("::file.txt", O_CREAT | O_RDWR, 0644);
51 ASSERT_GT(fd1, 0, "");
52 ASSERT_EQ(close(fd1), 0, "");
53
54 ASSERT_EQ(unlink("::file.txt"), 0, "");
55 ASSERT_EQ(mkdir("::emptydir", 0755), 0, "");
56 fd1 = open("::emptydir", O_RDONLY, 0644);
57 ASSERT_GT(fd1, 0, "");
58
59 // Zero-sized reads should always succeed
60 ASSERT_EQ(read(fd1, NULL, 0), 0, "");
61 // But nonzero reads to directories should always fail
62 char buf;
63 ASSERT_EQ(read(fd1, &buf, 1), -1, "");
64 ASSERT_EQ(write(fd1, "Don't write to directories", 26), -1, "");
65 ASSERT_EQ(ftruncate(fd1, 0), -1, "");
66 ASSERT_EQ(rmdir("::emptydir"), 0, "");
67 ASSERT_EQ(rmdir("::emptydir"), -1, "");
68 ASSERT_EQ(close(fd1), 0, "");
69 ASSERT_EQ(rmdir("::emptydir"), -1, "");
70
71 END_TEST;
72 }
73
test_unclean_close(void)74 bool test_unclean_close(void) {
75 BEGIN_TEST;
76
77 int fd = open("::foobar", O_CREAT | O_RDWR);
78 ASSERT_GT(fd, 0, "");
79
80 // Try closing a connection to a file with an "unclean" shutdown,
81 // noticed by the filesystem server as a closed handle rather than
82 // an explicit "Close" call.
83 zx_handle_t handles[FDIO_MAX_HANDLES];
84 uint32_t types[FDIO_MAX_HANDLES];
85 zx_status_t r = fdio_transfer_fd(fd, 0, handles, types);
86 ASSERT_GE(fd, 0, "");
87 for (size_t i = 0; i < (size_t) r; i++) {
88 ASSERT_EQ(zx_handle_close(handles[i]), ZX_OK, "");
89 }
90
91 ASSERT_EQ(unlink("::foobar"), 0, "");
92
93 END_TEST;
94 }
95
96 RUN_FOR_ALL_FILESYSTEMS(basic_tests,
97 RUN_TEST_MEDIUM(test_basic)
98 RUN_TEST_MEDIUM(test_unclean_close)
99 )
100