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