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
19bool 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
74bool 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
96RUN_FOR_ALL_FILESYSTEMS(basic_tests,
97    RUN_TEST_MEDIUM(test_basic)
98    RUN_TEST_MEDIUM(test_unclean_close)
99)
100