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 <assert.h>
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <limits.h>
9 #include <stdint.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/stat.h>
14 #include <unistd.h>
15
16 #include <zircon/compiler.h>
17 #include <fbl/algorithm.h>
18
19 #include "filesystems.h"
20
21 // Make some files, then unlink them.
TestUnlinkSimple(void)22 bool TestUnlinkSimple(void) {
23 BEGIN_TEST;
24 const char* const paths[] = {"::abc", "::def", "::ghi", "::jkl", "::mnopqrstuvxyz"};
25 for (size_t i = 0; i < fbl::count_of(paths); i++) {
26 int fd = open(paths[i], O_RDWR | O_CREAT | O_EXCL, 0644);
27 ASSERT_GT(fd, 0);
28 ASSERT_EQ(close(fd), 0);
29 }
30 for (size_t i = 0; i < fbl::count_of(paths); i++) {
31 ASSERT_EQ(unlink(paths[i]), 0);
32 }
33 END_TEST;
34 }
35
36 const char* const STRING_DATA[] = {
37 "Hello, world",
38 "Foo bar baz blat",
39 "This is yet another sample string",
40 };
41
simple_read_test(int fd,size_t data_index)42 static bool simple_read_test(int fd, size_t data_index) {
43 ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0);
44 char buf[1024];
45 memset(buf, 0, sizeof(buf));
46 ssize_t len = strlen(STRING_DATA[data_index]);
47 ASSERT_EQ(read(fd, buf, len), len);
48 ASSERT_EQ(memcmp(STRING_DATA[data_index], buf, strlen(STRING_DATA[data_index])), 0);
49 return true;
50 }
51
simple_write_test(int fd,size_t data_index)52 static bool simple_write_test(int fd, size_t data_index) {
53 ASSERT_EQ(ftruncate(fd, 0), 0);
54 ASSERT_EQ(lseek(fd, 0, SEEK_SET), 0);
55 ssize_t len = strlen(STRING_DATA[data_index]);
56 ASSERT_EQ(write(fd, STRING_DATA[data_index], len), len);
57 return simple_read_test(fd, data_index);
58 }
59
TestUnlinkUseAfterwards(void)60 bool TestUnlinkUseAfterwards(void) {
61 BEGIN_TEST;
62
63 const char* path = "::foobar";
64 int fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0644);
65 ASSERT_GT(fd, 0);
66
67 ASSERT_TRUE(simple_write_test(fd, 1));
68
69 // When we unlink path, fd is still open.
70 ASSERT_EQ(unlink(path), 0);
71 ASSERT_TRUE(simple_read_test(fd, 1)); // It should contain the same data as before
72 ASSERT_TRUE(simple_write_test(fd, 2)); // It should still be writable
73 ASSERT_EQ(close(fd), 0); // This actually releases the file
74
75 // Now, opening the file should fail without O_CREAT
76 ASSERT_EQ(open(path, O_RDWR, 0644), -1);
77
78 END_TEST;
79 }
80
TestUnlinkOpenElsewhere(void)81 bool TestUnlinkOpenElsewhere(void) {
82 BEGIN_TEST;
83
84 const char* path = "::foobar";
85 int fd1 = open(path, O_RDWR | O_CREAT | O_EXCL, 0644);
86 ASSERT_GT(fd1, 0);
87 int fd2 = open(path, O_RDWR, 0644);
88 ASSERT_GT(fd2, 0);
89
90 ASSERT_TRUE(simple_write_test(fd1, 0));
91 ASSERT_EQ(close(fd1), 0);
92
93 // When we unlink path, fd2 is still open.
94 ASSERT_EQ(unlink(path), 0);
95 ASSERT_TRUE(simple_read_test(fd2, 0)); // It should contain the same data as before
96 ASSERT_TRUE(simple_write_test(fd2, 1)); // It should still be writable
97 ASSERT_EQ(close(fd2), 0); // This actually releases the file
98
99 // Now, opening the file should fail without O_CREAT
100 ASSERT_EQ(open(path, O_RDWR, 0644), -1);
101
102 END_TEST;
103 }
104
test_remove(void)105 bool test_remove(void) {
106 BEGIN_TEST;
107
108 // Test the trivial cases of removing files and directories
109 const char* filename = "::file";
110 int fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0644);
111 ASSERT_GT(fd, 0);
112 ASSERT_EQ(remove(filename), 0);
113 ASSERT_EQ(remove(filename), -1);
114 ASSERT_EQ(errno, ENOENT);
115 ASSERT_EQ(close(fd), 0);
116
117 const char* dirname = "::dir";
118 ASSERT_EQ(mkdir(dirname, 0666), 0);
119 ASSERT_EQ(remove(dirname), 0);
120 ASSERT_EQ(remove(dirname), -1);
121 ASSERT_EQ(errno, ENOENT);
122
123 // Test that we cannot remove non-empty directories, and that
124 // we see the expected error code too.
125 ASSERT_EQ(mkdir("::dir", 0666), 0);
126 ASSERT_EQ(mkdir("::dir/subdir", 0666), 0);
127 ASSERT_EQ(remove("::dir"), -1);
128 ASSERT_EQ(errno, ENOTEMPTY);
129 ASSERT_EQ(remove("::dir/subdir"), 0);
130 ASSERT_EQ(remove("::dir"), 0);
131 ASSERT_EQ(remove("::dir"), -1);
132 ASSERT_EQ(errno, ENOENT);
133
134 END_TEST;
135 }
136
137 RUN_FOR_ALL_FILESYSTEMS(unlink_tests,
138 RUN_TEST_MEDIUM(TestUnlinkSimple)
139 RUN_TEST_MEDIUM(TestUnlinkUseAfterwards)
140 RUN_TEST_MEDIUM(TestUnlinkOpenElsewhere)
141 RUN_TEST_MEDIUM(test_remove);
142 )
143