1 /* 2 * Copyright (c) 2015 Cedric Hnyda <chnyda (at) suse.com> 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, write the Free Software Foundation, 16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19 /* Description: 20 * Verify that: 21 * 1) renameat2(2) returns -1 and sets errno to EEXIST because newpath 22 * already exists and the flag RENAME_NOREPLACE is used. 23 * 2) renameat2(2) returns 0. 24 * 3) renameat2(2) returns -1 and sets errno to ENOENT because the flag 25 * RENAME_EXCHANGE is used and newpath does not exist. 26 * 4) renameat2(2) returns 0 because the flag RENAME_NOREPLACE is used, 27 * both olddirfd and newdirfd are valid and oldpath exists and 28 * newpath does not exist. 29 * 5) renameat2(2) returns -1 and sets errno to EINVAL because 30 * RENAME_NOREPLACE and RENAME_EXCHANGE are used together 31 * 6) renameat2(2) returns -1 and sets errno to EINVAL because 32 * RENAME_WHITEOUT and RENAME_EXCHANGE are used together 33 */ 34 35 #define _GNU_SOURCE 36 37 #include "test.h" 38 #include "safe_macros.h" 39 #include "lapi/fcntl.h" 40 #include "renameat2.h" 41 42 #define TEST_DIR "test_dir/" 43 #define TEST_DIR2 "test_dir2/" 44 45 #define TEST_FILE "test_file" 46 #define TEST_FILE2 "test_file2" 47 #define TEST_FILE3 "test_file3" 48 #define NON_EXIST "non_exist" 49 50 char *TCID = "renameat201"; 51 52 static int olddirfd; 53 static int newdirfd; 54 static long fs_type; 55 56 static struct test_case { 57 int *olddirfd; 58 const char *oldpath; 59 int *newdirfd; 60 const char *newpath; 61 int flags; 62 int exp_errno; 63 } test_cases[] = { 64 {&olddirfd, TEST_FILE, &newdirfd, TEST_FILE2, RENAME_NOREPLACE, EEXIST}, 65 {&olddirfd, TEST_FILE, &newdirfd, TEST_FILE2, RENAME_EXCHANGE, 0}, 66 {&olddirfd, TEST_FILE, &newdirfd, NON_EXIST, RENAME_EXCHANGE, ENOENT}, 67 {&olddirfd, TEST_FILE, &newdirfd, TEST_FILE3, RENAME_NOREPLACE, 0}, 68 {&olddirfd, TEST_FILE, &newdirfd, TEST_FILE2, RENAME_NOREPLACE 69 | RENAME_EXCHANGE, EINVAL}, 70 {&olddirfd, TEST_FILE, &newdirfd, TEST_FILE2, RENAME_WHITEOUT 71 | RENAME_EXCHANGE, EINVAL} 72 }; 73 74 int TST_TOTAL = ARRAY_SIZE(test_cases); 75 76 static void setup(void); 77 static void cleanup(void); 78 static void renameat2_verify(const struct test_case *test); 79 80 81 int main(int ac, char **av) 82 { 83 int i; 84 int lc; 85 86 tst_parse_opts(ac, av, NULL, NULL); 87 88 setup(); 89 90 for (lc = 0; lc < TEST_LOOPING(lc); lc++) { 91 tst_count = 0; 92 93 for (i = 0; i < TST_TOTAL; i++) 94 renameat2_verify(&test_cases[i]); 95 } 96 97 cleanup(); 98 tst_exit(); 99 } 100 101 static void setup(void) 102 { 103 if ((tst_kvercmp(3, 15, 0)) < 0) { 104 tst_brkm(TCONF, NULL, 105 "This test can only run on kernels that are 3.15. and higher"); 106 } 107 108 tst_tmpdir(); 109 110 fs_type = tst_fs_type(cleanup, "."); 111 112 SAFE_MKDIR(cleanup, TEST_DIR, 0700); 113 SAFE_MKDIR(cleanup, TEST_DIR2, 0700); 114 115 SAFE_TOUCH(cleanup, TEST_DIR TEST_FILE, 0600, NULL); 116 SAFE_TOUCH(cleanup, TEST_DIR2 TEST_FILE2, 0600, NULL); 117 SAFE_TOUCH(cleanup, TEST_DIR TEST_FILE3, 0600, NULL); 118 119 olddirfd = SAFE_OPEN(cleanup, TEST_DIR, O_DIRECTORY); 120 newdirfd = SAFE_OPEN(cleanup, TEST_DIR2, O_DIRECTORY); 121 } 122 123 static void cleanup(void) 124 { 125 if (olddirfd > 0 && close(olddirfd) < 0) 126 tst_resm(TWARN | TERRNO, "close olddirfd failed"); 127 128 if (newdirfd > 0 && close(newdirfd) < 0) 129 tst_resm(TWARN | TERRNO, "close newdirfd failed"); 130 131 tst_rmdir(); 132 133 } 134 135 static void renameat2_verify(const struct test_case *test) 136 { 137 TEST(renameat2(*(test->olddirfd), test->oldpath, 138 *(test->newdirfd), test->newpath, test->flags)); 139 140 if ((test->flags & RENAME_EXCHANGE) && EINVAL == TEST_ERRNO 141 && fs_type == TST_BTRFS_MAGIC) { 142 tst_resm(TCONF, 143 "RENAME_EXCHANGE flag is not implemeted on %s", 144 tst_fs_type_name(fs_type)); 145 return; 146 } 147 148 if (test->exp_errno && TEST_RETURN != -1) { 149 tst_resm(TFAIL, "renameat2() succeeded unexpectedly"); 150 return; 151 } 152 153 if (test->exp_errno == 0 && TEST_RETURN != 0) { 154 tst_resm(TFAIL | TTERRNO, "renameat2() failed unexpectedly"); 155 return; 156 } 157 158 if (test->exp_errno == TEST_ERRNO) { 159 tst_resm(TPASS | TTERRNO, 160 "renameat2() returned the expected value"); 161 return; 162 } 163 164 tst_resm(TFAIL | TTERRNO, 165 "renameat2() got unexpected return value: expected: %d - %s", 166 test->exp_errno, tst_strerrno(test->exp_errno)); 167 168 } 169