1 #include <stic.h>
2 
3 #include <sys/stat.h> /* chmod() */
4 
5 #include <stdint.h> /* uint64_t */
6 #include <stdio.h> /* remove() rename() */
7 #include <string.h> /* strcmp() */
8 
9 #include "../../src/io/iop.h"
10 #include "../../src/io/ior.h"
11 #include "../../src/utils/env.h"
12 #include "../../src/utils/fs.h"
13 
14 #include "utils.h"
15 
16 static IoErrCbResult ignore_errors(struct io_args_t *args,
17 		const ioe_err_t *err);
18 static int can_rename_changing_case(void);
19 
TEST(file_is_moved)20 TEST(file_is_moved)
21 {
22 	create_empty_file(SANDBOX_PATH "/binary-data");
23 
24 	{
25 		io_args_t args = {
26 			.arg1.src = SANDBOX_PATH "/binary-data",
27 			.arg2.dst = SANDBOX_PATH "/moved-binary-data",
28 		};
29 		assert_success(ior_mv(&args));
30 	}
31 
32 	assert_false(file_exists(SANDBOX_PATH "/binary-data"));
33 	assert_true(file_exists(SANDBOX_PATH "/moved-binary-data"));
34 
35 	remove(SANDBOX_PATH "/moved-binary-data");
36 }
37 
TEST(empty_directory_is_moved)38 TEST(empty_directory_is_moved)
39 {
40 	create_empty_dir(SANDBOX_PATH "/empty-dir");
41 
42 	{
43 		io_args_t args = {
44 			.arg1.src = SANDBOX_PATH "/empty-dir",
45 			.arg2.dst = SANDBOX_PATH "/moved-empty-dir",
46 		};
47 		assert_success(ior_mv(&args));
48 	}
49 
50 	assert_false(is_dir(SANDBOX_PATH "/empty-dir"));
51 	assert_true(is_dir(SANDBOX_PATH "/moved-empty-dir"));
52 
53 	delete_dir(SANDBOX_PATH "/moved-empty-dir");
54 }
55 
TEST(non_empty_directory_is_moved)56 TEST(non_empty_directory_is_moved)
57 {
58 	create_non_empty_dir(SANDBOX_PATH "/non-empty-dir", "a-file");
59 
60 	{
61 		io_args_t args = {
62 			.arg1.src = SANDBOX_PATH "/non-empty-dir",
63 			.arg2.dst = SANDBOX_PATH "/moved-non-empty-dir",
64 		};
65 		assert_success(ior_mv(&args));
66 	}
67 
68 	assert_true(file_exists(SANDBOX_PATH "/moved-non-empty-dir/a-file"));
69 
70 	delete_tree(SANDBOX_PATH "/moved-non-empty-dir");
71 }
72 
TEST(empty_nested_directory_is_moved)73 TEST(empty_nested_directory_is_moved)
74 {
75 	create_empty_nested_dir(SANDBOX_PATH "/non-empty-dir", "empty-nested-dir");
76 
77 	{
78 		io_args_t args = {
79 			.arg1.src = SANDBOX_PATH "/non-empty-dir",
80 			.arg2.dst = SANDBOX_PATH "/moved-non-empty-dir",
81 		};
82 		assert_success(ior_mv(&args));
83 	}
84 
85 	assert_true(is_dir(SANDBOX_PATH "/moved-non-empty-dir/empty-nested-dir"));
86 
87 	delete_tree(SANDBOX_PATH "/moved-non-empty-dir");
88 }
89 
TEST(non_empty_nested_directory_is_moved)90 TEST(non_empty_nested_directory_is_moved)
91 {
92 	create_non_empty_nested_dir(SANDBOX_PATH "/non-empty-dir", "nested-dir",
93 			"a-file");
94 
95 	{
96 		io_args_t args = {
97 			.arg1.src = SANDBOX_PATH "/non-empty-dir",
98 			.arg2.dst = SANDBOX_PATH "/moved-non-empty-dir",
99 		};
100 		assert_success(ior_mv(&args));
101 	}
102 
103 	assert_false(file_exists(SANDBOX_PATH "/non-empty-dir/nested-dir/a-file"));
104 	assert_true(file_exists(SANDBOX_PATH
105 				"/moved-non-empty-dir/nested-dir/a-file"));
106 
107 	delete_tree(SANDBOX_PATH "/moved-non-empty-dir");
108 }
109 
TEST(fails_to_overwrite_file_by_default)110 TEST(fails_to_overwrite_file_by_default)
111 {
112 	create_empty_file(SANDBOX_PATH "/a-file");
113 
114 	{
115 		io_args_t args = {
116 			.arg1.src = TEST_DATA_PATH "/read/two-lines",
117 			.arg2.dst = SANDBOX_PATH "/a-file",
118 		};
119 		assert_failure(ior_mv(&args));
120 	}
121 
122 	delete_file(SANDBOX_PATH "/a-file");
123 }
124 
TEST(fails_to_overwrite_dir_by_default)125 TEST(fails_to_overwrite_dir_by_default)
126 {
127 	create_empty_dir(SANDBOX_PATH "/empty-dir");
128 
129 	{
130 		io_args_t args = {
131 			.arg1.src = TEST_DATA_PATH "/read",
132 			.arg2.dst = SANDBOX_PATH "/empty-dir",
133 		};
134 		assert_failure(ior_mv(&args));
135 	}
136 
137 	delete_dir(SANDBOX_PATH "/empty-dir");
138 }
139 
TEST(overwrites_file_when_asked)140 TEST(overwrites_file_when_asked)
141 {
142 	create_empty_file(SANDBOX_PATH "/a-file");
143 	clone_file(TEST_DATA_PATH "/read/two-lines", SANDBOX_PATH "/two-lines");
144 
145 	{
146 		io_args_t args = {
147 			.arg1.src = SANDBOX_PATH "/two-lines",
148 			.arg2.dst = SANDBOX_PATH "/a-file",
149 			.arg3.crs = IO_CRS_REPLACE_FILES,
150 		};
151 		assert_success(ior_mv(&args));
152 	}
153 
154 	delete_file(SANDBOX_PATH "/a-file");
155 }
156 
TEST(overwrites_dir_when_asked)157 TEST(overwrites_dir_when_asked)
158 {
159 	create_empty_dir(SANDBOX_PATH "/dir");
160 
161 	{
162 		io_args_t args = {
163 			.arg1.src = TEST_DATA_PATH "/read",
164 			.arg2.dst = SANDBOX_PATH "/read",
165 		};
166 		assert_success(ior_cp(&args));
167 	}
168 
169 	assert_success(chmod(SANDBOX_PATH "/read", 0700));
170 
171 	{
172 		io_args_t args = {
173 			.arg1.src = SANDBOX_PATH "/read",
174 			.arg2.dst = SANDBOX_PATH "/dir",
175 			.arg3.crs = IO_CRS_REPLACE_ALL,
176 		};
177 		assert_success(ior_mv(&args));
178 	}
179 
180 	{
181 		io_args_t args = {
182 			.arg1.path = SANDBOX_PATH "/dir",
183 		};
184 		assert_failure(iop_rmdir(&args));
185 	}
186 
187 	delete_tree(SANDBOX_PATH "/dir");
188 }
189 
TEST(appending_fails_for_directories)190 TEST(appending_fails_for_directories)
191 {
192 	create_empty_dir(SANDBOX_PATH "/dir");
193 
194 	{
195 		io_args_t args = {
196 			.arg1.src = TEST_DATA_PATH "/read",
197 			.arg2.dst = SANDBOX_PATH "/read",
198 		};
199 		assert_success(ior_cp(&args));
200 	}
201 
202 	assert_success(chmod(SANDBOX_PATH "/read", 0700));
203 
204 	{
205 		io_args_t args = {
206 			.arg1.src = SANDBOX_PATH "/read",
207 			.arg2.dst = SANDBOX_PATH "/dir",
208 			.arg3.crs = IO_CRS_APPEND_TO_FILES,
209 		};
210 		assert_failure(ior_mv(&args));
211 	}
212 
213 	delete_dir(SANDBOX_PATH "/dir");
214 
215 	delete_tree(SANDBOX_PATH "/read");
216 }
217 
TEST(appending_works_for_files)218 TEST(appending_works_for_files)
219 {
220 	uint64_t size;
221 
222 	clone_file(TEST_DATA_PATH "/read/two-lines", SANDBOX_PATH "/two-lines");
223 
224 	size = get_file_size(SANDBOX_PATH "/two-lines");
225 
226 	clone_file(TEST_DATA_PATH "/read/two-lines", SANDBOX_PATH "/two-lines2");
227 
228 	{
229 		io_args_t args = {
230 			.arg1.src = SANDBOX_PATH "/two-lines2",
231 			.arg2.dst = SANDBOX_PATH "/two-lines",
232 			.arg3.crs = IO_CRS_APPEND_TO_FILES,
233 		};
234 		assert_success(ior_mv(&args));
235 	}
236 
237 	assert_int_equal(size, get_file_size(SANDBOX_PATH "/two-lines"));
238 
239 	delete_file(SANDBOX_PATH "/two-lines");
240 }
241 
TEST(directories_can_be_merged)242 TEST(directories_can_be_merged)
243 {
244 	create_empty_dir(SANDBOX_PATH "/first");
245 	create_empty_file(SANDBOX_PATH "/first/first-file");
246 
247 	create_empty_dir(SANDBOX_PATH "/second");
248 	create_empty_file(SANDBOX_PATH "/second/second-file");
249 
250 	{
251 		io_args_t args = {
252 			.arg1.src = SANDBOX_PATH "/first",
253 			.arg2.dst = SANDBOX_PATH "/second",
254 			.arg3.crs = IO_CRS_REPLACE_FILES,
255 		};
256 		assert_success(ior_mv(&args));
257 	}
258 
259 	/* Original directory must be deleted. */
260 	assert_false(file_exists(SANDBOX_PATH "/first"));
261 
262 	assert_true(file_exists(SANDBOX_PATH "/second/second-file"));
263 	assert_true(file_exists(SANDBOX_PATH "/second/first-file"));
264 
265 	delete_tree(SANDBOX_PATH "/second");
266 }
267 
TEST(nested_directories_can_be_merged)268 TEST(nested_directories_can_be_merged)
269 {
270 	create_empty_dir(SANDBOX_PATH "/first");
271 	create_empty_dir(SANDBOX_PATH "/first/nested");
272 	create_empty_file(SANDBOX_PATH "/first/nested/first-file");
273 
274 	create_empty_dir(SANDBOX_PATH "/second");
275 	create_empty_dir(SANDBOX_PATH "/second/nested");
276 	create_empty_file(SANDBOX_PATH "/second/nested/second-file");
277 
278 	{
279 		io_args_t args = {
280 			.arg1.src = SANDBOX_PATH "/first",
281 			.arg2.dst = SANDBOX_PATH "/second",
282 			.arg3.crs = IO_CRS_REPLACE_FILES,
283 		};
284 		assert_success(ior_mv(&args));
285 	}
286 
287 	/* Original directory must be deleted. */
288 	assert_false(file_exists(SANDBOX_PATH "/first/nested"));
289 	assert_false(file_exists(SANDBOX_PATH "/first"));
290 
291 	assert_true(file_exists(SANDBOX_PATH "/second/nested/second-file"));
292 	assert_true(file_exists(SANDBOX_PATH "/second/nested/first-file"));
293 
294 	delete_tree(SANDBOX_PATH "/second");
295 }
296 
TEST(fails_to_move_directory_inside_itself)297 TEST(fails_to_move_directory_inside_itself)
298 {
299 	create_empty_dir(SANDBOX_PATH "/empty-dir");
300 
301 	{
302 		io_args_t args = {
303 			.arg1.src = SANDBOX_PATH "/empty-dir",
304 			.arg2.dst = SANDBOX_PATH "/empty-dir/empty-dir-copy",
305 		};
306 		assert_failure(ior_mv(&args));
307 	}
308 
309 	delete_dir(SANDBOX_PATH "/empty-dir");
310 }
311 
312 /* Creating symbolic links on Windows requires administrator rights. */
TEST(symlink_is_symlink_after_move,IF (not_windows))313 TEST(symlink_is_symlink_after_move, IF(not_windows))
314 {
315 	{
316 		io_args_t args = {
317 			.arg1.path = TEST_DATA_PATH "/read/two-lines",
318 			.arg2.target = SANDBOX_PATH "/sym-link",
319 		};
320 		assert_success(iop_ln(&args));
321 	}
322 
323 	assert_true(is_symlink(SANDBOX_PATH "/sym-link"));
324 
325 	{
326 		io_args_t args = {
327 			.arg1.src = SANDBOX_PATH "/sym-link",
328 			.arg2.dst = SANDBOX_PATH "/moved-sym-link",
329 		};
330 		assert_success(ior_mv(&args));
331 	}
332 
333 	assert_false(is_symlink(SANDBOX_PATH "/sym-link"));
334 	assert_true(is_symlink(SANDBOX_PATH "/moved-sym-link"));
335 
336 	delete_file(SANDBOX_PATH "/moved-sym-link");
337 }
338 
TEST(case_change_on_rename,IF (can_rename_changing_case))339 TEST(case_change_on_rename, IF(can_rename_changing_case))
340 {
341 	create_empty_file(SANDBOX_PATH "/a-file");
342 
343 	{
344 		io_args_t args = {
345 			.arg1.src = SANDBOX_PATH "/a-file",
346 			.arg2.dst = SANDBOX_PATH "/A-file",
347 		};
348 		assert_success(ior_mv(&args));
349 	}
350 
351 	delete_file(SANDBOX_PATH "/A-file");
352 }
353 
TEST(error_on_move_preserves_source_file,IF (not_windows))354 TEST(error_on_move_preserves_source_file, IF(not_windows))
355 {
356 	io_args_t args = {
357 		.arg1.src = SANDBOX_PATH "/file",
358 		.arg2.dst = SANDBOX_PATH "/ro/file",
359 
360 		.result.errors = IOE_ERRLST_INIT,
361 		.result.errors_cb = &ignore_errors,
362 	};
363 
364 	create_empty_file(SANDBOX_PATH "/file");
365 	create_empty_dir(SANDBOX_PATH "/ro");
366 	assert_success(chmod(SANDBOX_PATH "/ro", 0500));
367 
368 	assert_success(ior_mv(&args));
369 	assert_int_equal(1, args.result.errors.error_count);
370 	ioe_errlst_free(&args.result.errors);
371 
372 	delete_file(SANDBOX_PATH "/file");
373 	delete_dir(SANDBOX_PATH "/ro");
374 }
375 
376 static IoErrCbResult
ignore_errors(struct io_args_t * args,const ioe_err_t * err)377 ignore_errors(struct io_args_t *args, const ioe_err_t *err)
378 {
379 	return IO_ECR_IGNORE;
380 }
381 
382 static int
can_rename_changing_case(void)383 can_rename_changing_case(void)
384 {
385 	int ok;
386 	create_empty_file(SANDBOX_PATH "/file");
387 	ok = rename(SANDBOX_PATH "/file", SANDBOX_PATH "/FiLe") == 0;
388 	if(ok)
389 	{
390 		delete_file(SANDBOX_PATH "/FiLe");
391 	}
392 	else
393 	{
394 		delete_file(SANDBOX_PATH "/file");
395 	}
396 	return ok;
397 }
398 
399 /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */
400 /* vim: set cinoptions+=t0 filetype=c : */
401