1 /*
2 * Copyright (c) 2015-2016 Oracle and/or its affiliates. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Author: Alexey Kodanev <alexey.kodanev@oracle.com>
18 *
19 */
20
21 #define _GNU_SOURCE
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <errno.h>
27
28 #include "test.h"
29 #include "safe_macros.h"
30 #include "lapi/fcntl.h"
31
32 char *TCID = "open14";
33 int TST_TOTAL = 3;
34 static ssize_t size;
35 static char buf[1024];
36 static const ssize_t blocks_num = 4;
37 static struct stat st;
38
cleanup(void)39 static void cleanup(void)
40 {
41 tst_rmdir();
42 }
43
setup(void)44 static void setup(void)
45 {
46 tst_tmpdir();
47
48 size = sizeof(buf);
49
50 memset(buf, 1, size);
51
52 int fd = open(".", O_TMPFILE | O_RDWR, 0600);
53
54 if (fd == -1) {
55 if (errno == EISDIR || errno == ENOTSUP)
56 tst_brkm(TCONF, cleanup, "O_TMPFILE not supported");
57
58 tst_brkm(TBROK | TERRNO, cleanup, "open() failed");
59 }
60
61 SAFE_CLOSE(cleanup, fd);
62 }
63
write_file(int fd)64 static void write_file(int fd)
65 {
66 int i;
67
68 for (i = 0; i < blocks_num; ++i)
69 SAFE_WRITE(cleanup, 1, fd, buf, size);
70 }
71
test01(void)72 void test01(void)
73 {
74 int fd;
75 char path[PATH_MAX], tmp[PATH_MAX];
76
77 tst_resm(TINFO, "creating a file with O_TMPFILE flag");
78 fd = SAFE_OPEN(cleanup, ".", O_TMPFILE | O_RDWR, 0600);
79
80 tst_resm(TINFO, "writing data to the file");
81 write_file(fd);
82
83 SAFE_FSTAT(cleanup, fd, &st);
84 tst_resm(TINFO, "file size is '%zu'", st.st_size);
85
86 if (st.st_size != blocks_num * size) {
87 tst_resm(TFAIL, "not expected size: '%zu' != '%zu'",
88 st.st_size, blocks_num * size);
89 SAFE_CLOSE(cleanup, fd);
90 return;
91 }
92
93 tst_resm(TINFO, "looking for the file in '.'");
94 if (!tst_dir_is_empty(cleanup, ".", 1))
95 tst_brkm(TFAIL, cleanup, "found a file, this is not expected");
96 tst_resm(TINFO, "file not found, OK");
97
98 snprintf(path, PATH_MAX, "/proc/self/fd/%d", fd);
99 SAFE_READLINK(cleanup, path, tmp, PATH_MAX);
100
101 tst_resm(TINFO, "renaming '%s' -> 'tmpfile'", tmp);
102 SAFE_LINKAT(cleanup, AT_FDCWD, path, AT_FDCWD, "tmpfile",
103 AT_SYMLINK_FOLLOW);
104
105 if (tst_dir_is_empty(cleanup, ".", 1))
106 tst_brkm(TFAIL, cleanup, "file not found");
107
108 SAFE_UNLINK(cleanup, "tmpfile");
109 SAFE_CLOSE(cleanup, fd);
110
111 tst_resm(TPASS, "single file tests passed");
112 }
113
read_file(int fd)114 static void read_file(int fd)
115 {
116 int i;
117 char tmp[size];
118
119 SAFE_LSEEK(cleanup, fd, 0, SEEK_SET);
120
121 for (i = 0; i < blocks_num; ++i) {
122 SAFE_READ(cleanup, 0, fd, tmp, size);
123 if (memcmp(buf, tmp, size))
124 tst_brkm(TFAIL, cleanup, "got unexepected data");
125 }
126 }
127
test02(void)128 static void test02(void)
129 {
130 const int files_num = 100;
131 int i, fd[files_num];
132 char path[PATH_MAX];
133
134 tst_resm(TINFO, "create files in multiple directories");
135 for (i = 0; i < files_num; ++i) {
136 snprintf(path, PATH_MAX, "tst02_%d", i);
137 SAFE_MKDIR(cleanup, path, 0700);
138 SAFE_CHDIR(cleanup, path);
139
140 fd[i] = SAFE_OPEN(cleanup, ".", O_TMPFILE | O_RDWR, 0600);
141 }
142
143 tst_resm(TINFO, "removing test directories");
144 for (i = files_num - 1; i >= 0; --i) {
145 SAFE_CHDIR(cleanup, "..");
146 snprintf(path, PATH_MAX, "tst02_%d", i);
147 SAFE_RMDIR(cleanup, path);
148 }
149
150 tst_resm(TINFO, "writing/reading temporary files");
151 for (i = 0; i < files_num; ++i) {
152 write_file(fd[i]);
153 read_file(fd[i]);
154 }
155
156 tst_resm(TINFO, "closing temporary files");
157 for (i = 0; i < files_num; ++i)
158 SAFE_CLOSE(cleanup, fd[i]);
159
160 tst_resm(TPASS, "multiple files tests passed");
161 }
162
link_tmp_file(int fd)163 static void link_tmp_file(int fd)
164 {
165 char path1[PATH_MAX], path2[PATH_MAX];
166
167 snprintf(path1, PATH_MAX, "/proc/self/fd/%d", fd);
168 snprintf(path2, PATH_MAX, "tmpfile_%d", fd);
169
170 SAFE_LINKAT(cleanup, AT_FDCWD, path1, AT_FDCWD, path2,
171 AT_SYMLINK_FOLLOW);
172 }
173
test03(void)174 static void test03(void)
175 {
176 const int files_num = 100;
177 const mode_t test_perms[] = { 0, 07777, 001, 0755, 0644, 0440 };
178
179 int i, fd[files_num];
180 char path[PATH_MAX];
181 struct stat st;
182 mode_t mask = umask(0), perm;
183
184 umask(mask);
185
186 tst_resm(TINFO, "create multiple directories, link files into them");
187 tst_resm(TINFO, "and check file permissions");
188 for (i = 0; i < files_num; ++i) {
189
190 snprintf(path, PATH_MAX, "tst03_%d", i);
191 SAFE_MKDIR(cleanup, path, 0700);
192 SAFE_CHDIR(cleanup, path);
193
194 perm = test_perms[i % ARRAY_SIZE(test_perms)];
195
196 fd[i] = SAFE_OPEN(cleanup, ".", O_TMPFILE | O_RDWR, perm);
197
198 write_file(fd[i]);
199 read_file(fd[i]);
200
201 link_tmp_file(fd[i]);
202
203 snprintf(path, PATH_MAX, "tmpfile_%d", fd[i]);
204
205 SAFE_LSTAT(cleanup, path, &st);
206
207 mode_t exp_mode = perm & ~mask;
208
209 if ((st.st_mode & ~S_IFMT) != exp_mode) {
210 tst_brkm(TFAIL, cleanup,
211 "file mode read %o, but expected %o",
212 st.st_mode & ~S_IFMT, exp_mode);
213 }
214 }
215
216 tst_resm(TINFO, "remove files, directories");
217 for (i = files_num - 1; i >= 0; --i) {
218 snprintf(path, PATH_MAX, "tmpfile_%d", fd[i]);
219 SAFE_UNLINK(cleanup, path);
220 SAFE_CLOSE(cleanup, fd[i]);
221
222 SAFE_CHDIR(cleanup, "..");
223
224 snprintf(path, PATH_MAX, "tst03_%d", i);
225 SAFE_RMDIR(cleanup, path);
226 }
227
228 tst_resm(TPASS, "file permission tests passed");
229 }
230
main(int ac,char * av[])231 int main(int ac, char *av[])
232 {
233 int lc;
234
235 tst_parse_opts(ac, av, NULL, NULL);
236
237 setup();
238
239 for (lc = 0; TEST_LOOPING(lc); ++lc) {
240 tst_count = 0;
241 test01();
242 test02();
243 test03();
244 }
245
246 cleanup();
247 tst_exit();
248 }
249