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