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