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 33char *TCID = "openat03"; 34int TST_TOTAL = 3; 35static ssize_t size; 36static char buf[1024]; 37static const ssize_t blocks_num = 4; 38static struct stat st; 39 40static void cleanup(void) 41{ 42 tst_rmdir(); 43} 44 45static 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 65static 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 75static 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 83void 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 '%zu'", st.st_size); 96 97 if (st.st_size != blocks_num * size) { 98 tst_resm(TFAIL, "not expected size: '%zu' != '%zu'", 99 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 125static 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 139static 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 174static 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 185static 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 242int 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