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 <errno.h>
26
27 #include "test.h"
28 #include "safe_macros.h"
29 #include "lapi/fcntl.h"
30 #include "openat.h"
31
32 char *TCID = "openat03";
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 = openat(AT_FDCWD, ".", 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, "openat() failed");
59 }
60
61 SAFE_CLOSE(cleanup, fd);
62 }
63
openat_tmp(int mode)64 static int openat_tmp(int mode)
65 {
66 int fd = openat(AT_FDCWD, ".", O_TMPFILE | O_RDWR, mode);
67
68 if (fd >= 0)
69 return fd;
70
71 tst_brkm(TBROK | TERRNO, cleanup, "openat() failed");
72 }
73
write_file(int fd)74 static void write_file(int fd)
75 {
76 int i;
77
78 for (i = 0; i < blocks_num; ++i)
79 SAFE_WRITE(cleanup, SAFE_WRITE_ALL, fd, buf, size);
80 }
81
test01(void)82 void test01(void)
83 {
84 int fd;
85 char path[PATH_MAX], tmp[PATH_MAX];
86
87 tst_resm(TINFO, "creating a file with O_TMPFILE flag");
88 fd = openat_tmp(0600);
89
90 tst_resm(TINFO, "writing data to the file");
91 write_file(fd);
92
93 SAFE_FSTAT(cleanup, fd, &st);
94 tst_resm(TINFO, "file size is '%li'", (long)st.st_size);
95
96 if (st.st_size != blocks_num * size) {
97 tst_resm(TFAIL, "not expected size: '%li' != '%zu'",
98 (long)st.st_size, blocks_num * size);
99 SAFE_CLOSE(cleanup, fd);
100 return;
101 }
102
103 tst_resm(TINFO, "looking for the file in '.'");
104 if (!tst_dir_is_empty(cleanup, ".", 1))
105 tst_brkm(TFAIL, cleanup, "found a file, this is not expected");
106 tst_resm(TINFO, "file not found, OK");
107
108 snprintf(path, PATH_MAX, "/proc/self/fd/%d", fd);
109 SAFE_READLINK(cleanup, path, tmp, PATH_MAX);
110
111 tst_resm(TINFO, "renaming '%s' -> 'tmpfile'", tmp);
112 SAFE_LINKAT(cleanup, AT_FDCWD, path, AT_FDCWD, "tmpfile",
113 AT_SYMLINK_FOLLOW);
114
115 if (tst_dir_is_empty(cleanup, ".", 1))
116 tst_brkm(TFAIL, cleanup, "file not found");
117
118 SAFE_UNLINK(cleanup, "tmpfile");
119 SAFE_CLOSE(cleanup, fd);
120
121 tst_resm(TPASS, "single file tests passed");
122 }
123
read_file(int fd)124 static void read_file(int fd)
125 {
126 int i;
127 char tmp[size];
128
129 SAFE_LSEEK(cleanup, fd, 0, SEEK_SET);
130
131 for (i = 0; i < blocks_num; ++i) {
132 SAFE_READ(cleanup, 0, fd, tmp, size);
133 if (memcmp(buf, tmp, size))
134 tst_brkm(TFAIL, cleanup, "got unexepected data");
135 }
136 }
137
test02(void)138 static void test02(void)
139 {
140 const int files_num = 100;
141 int i, fd[files_num];
142 char path[PATH_MAX];
143
144 tst_resm(TINFO, "create files in multiple directories");
145 for (i = 0; i < files_num; ++i) {
146 snprintf(path, PATH_MAX, "tst02_%d", i);
147 SAFE_MKDIR(cleanup, path, 0700);
148 SAFE_CHDIR(cleanup, path);
149
150 fd[i] = openat_tmp(0600);
151 }
152
153 tst_resm(TINFO, "removing test directories");
154 for (i = files_num - 1; i >= 0; --i) {
155 SAFE_CHDIR(cleanup, "..");
156 snprintf(path, PATH_MAX, "tst02_%d", i);
157 SAFE_RMDIR(cleanup, path);
158 }
159
160 tst_resm(TINFO, "writing/reading temporary files");
161 for (i = 0; i < files_num; ++i) {
162 write_file(fd[i]);
163 read_file(fd[i]);
164 }
165
166 tst_resm(TINFO, "closing temporary files");
167 for (i = 0; i < files_num; ++i)
168 SAFE_CLOSE(cleanup, fd[i]);
169
170 tst_resm(TPASS, "multiple files tests passed");
171 }
172
link_tmp_file(int fd)173 static void link_tmp_file(int fd)
174 {
175 char path1[PATH_MAX], path2[PATH_MAX];
176
177 snprintf(path1, PATH_MAX, "/proc/self/fd/%d", fd);
178 snprintf(path2, PATH_MAX, "tmpfile_%d", fd);
179
180 SAFE_LINKAT(cleanup, AT_FDCWD, path1, AT_FDCWD, path2,
181 AT_SYMLINK_FOLLOW);
182 }
183
test03(void)184 static void test03(void)
185 {
186 const int files_num = 100;
187 const mode_t test_perms[] = { 0, 07777, 001, 0755, 0644, 0440 };
188
189 int i, fd[files_num];
190 char path[PATH_MAX];
191 struct stat st;
192 mode_t mask = umask(0), perm;
193
194 umask(mask);
195
196 tst_resm(TINFO, "create multiple directories, link files into them");
197 tst_resm(TINFO, "and check file permissions");
198 for (i = 0; i < files_num; ++i) {
199
200 snprintf(path, PATH_MAX, "tst03_%d", i);
201 SAFE_MKDIR(cleanup, path, 0700);
202 SAFE_CHDIR(cleanup, path);
203
204 perm = test_perms[i % ARRAY_SIZE(test_perms)];
205
206 fd[i] = openat_tmp(perm);
207
208 write_file(fd[i]);
209 read_file(fd[i]);
210
211 link_tmp_file(fd[i]);
212
213 snprintf(path, PATH_MAX, "tmpfile_%d", fd[i]);
214
215 SAFE_LSTAT(cleanup, path, &st);
216
217 mode_t exp_mode = perm & ~mask;
218
219 if ((st.st_mode & ~S_IFMT) != exp_mode) {
220 tst_brkm(TFAIL, cleanup,
221 "file mode read %o, but expected %o",
222 st.st_mode & ~S_IFMT, exp_mode);
223 }
224 }
225
226 tst_resm(TINFO, "remove files, directories");
227 for (i = files_num - 1; i >= 0; --i) {
228 snprintf(path, PATH_MAX, "tmpfile_%d", fd[i]);
229 SAFE_UNLINK(cleanup, path);
230 SAFE_CLOSE(cleanup, fd[i]);
231
232 SAFE_CHDIR(cleanup, "..");
233
234 snprintf(path, PATH_MAX, "tst03_%d", i);
235 SAFE_RMDIR(cleanup, path);
236 }
237
238 tst_resm(TPASS, "file permission tests passed");
239 }
240
main(int ac,char * av[])241 int main(int ac, char *av[])
242 {
243 int lc;
244
245 tst_parse_opts(ac, av, NULL, NULL);
246
247 setup();
248
249 for (lc = 0; TEST_LOOPING(lc); ++lc) {
250 tst_count = 0;
251 test01();
252 test02();
253 test03();
254 }
255
256 cleanup();
257 tst_exit();
258 }
259