1 /* io-test.c --- tests for some i/o functions
2 *
3 * ====================================================================
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 * ====================================================================
21 */
22
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <string.h>
26 #include <stdio.h>
27
28 #include <apr.h>
29 #include <apr_version.h>
30
31 #include "svn_pools.h"
32 #include "svn_string.h"
33 #include "svn_io.h"
34 #include "private/svn_skel.h"
35 #include "private/svn_dep_compat.h"
36 #include "private/svn_io_private.h"
37
38 #include "../svn_test.h"
39 #include "../svn_test_fs.h"
40
41
42 /* Helpers to create the test data directory. */
43
44 #define TEST_DIR_PREFIX "io-test-temp"
45
46 /* The definition for the test data files. */
47 struct test_file_definition_t
48 {
49 /* The name of the test data file. */
50 const char* const name;
51
52 /* The string needs to contain up to 5 bytes, they
53 * are interpreded as:
54 * - first byte
55 * - filler between first and medium byte
56 * - medium byte (the byte in the middle of the file)
57 * - filler between medium and last byte
58 * - last byte.
59 * If the string is shorter than the file length,
60 * the test will fail. */
61 const char* const data;
62
63 /* The size of the file actually to create. */
64 const apr_off_t size;
65
66 /* The created path of the file. Will be filled in
67 * by create_test_file() */
68 char* created_path;
69 };
70
71 static struct test_file_definition_t test_file_definitions_template[] =
72 {
73 {"empty", "", 0},
74 {"single_a", "a", 1},
75 {"single_b", "b", 1},
76 {"hundred_a", "aaaaa", 100},
77 {"hundred_b", "bbbbb", 100},
78 {"hundred_b1", "baaaa", 100},
79 {"hundred_b2", "abaaa", 100},
80 {"hundred_b3", "aabaa", 100},
81 {"hundred_b4", "aaaba", 100},
82 {"hundred_b5", "aaaab", 100},
83 {"chunk_minus_one_a", "aaaaa", SVN__STREAM_CHUNK_SIZE - 1},
84 {"chunk_minus_one_b1", "baaaa", SVN__STREAM_CHUNK_SIZE - 1},
85 {"chunk_minus_one_b2", "abaaa", SVN__STREAM_CHUNK_SIZE - 1},
86 {"chunk_minus_one_b3", "aabaa", SVN__STREAM_CHUNK_SIZE - 1},
87 {"chunk_minus_one_b4", "aaaba", SVN__STREAM_CHUNK_SIZE - 1},
88 {"chunk_minus_one_b5", "aaaab", SVN__STREAM_CHUNK_SIZE - 1},
89 {"chunk_a", "aaaaa", SVN__STREAM_CHUNK_SIZE},
90 {"chunk_b1", "baaaa", SVN__STREAM_CHUNK_SIZE},
91 {"chunk_b2", "abaaa", SVN__STREAM_CHUNK_SIZE},
92 {"chunk_b3", "aabaa", SVN__STREAM_CHUNK_SIZE},
93 {"chunk_b4", "aaaba", SVN__STREAM_CHUNK_SIZE},
94 {"chunk_b5", "aaaab", SVN__STREAM_CHUNK_SIZE},
95 {"chunk_plus_one_a", "aaaaa", SVN__STREAM_CHUNK_SIZE + 1},
96 {"chunk_plus_one_b1", "baaaa", SVN__STREAM_CHUNK_SIZE + 1},
97 {"chunk_plus_one_b2", "abaaa", SVN__STREAM_CHUNK_SIZE + 1},
98 {"chunk_plus_one_b3", "aabaa", SVN__STREAM_CHUNK_SIZE + 1},
99 {"chunk_plus_one_b4", "aaaba", SVN__STREAM_CHUNK_SIZE + 1},
100 {"chunk_plus_one_b5", "aaaab", SVN__STREAM_CHUNK_SIZE + 1},
101 {"twochunk_minus_one_a", "aaaaa", SVN__STREAM_CHUNK_SIZE*2 - 1},
102 {"twochunk_minus_one_b1", "baaaa", SVN__STREAM_CHUNK_SIZE*2 - 1},
103 {"twochunk_minus_one_b2", "abaaa", SVN__STREAM_CHUNK_SIZE*2 - 1},
104 {"twochunk_minus_one_b3", "aabaa", SVN__STREAM_CHUNK_SIZE*2 - 1},
105 {"twochunk_minus_one_b4", "aaaba", SVN__STREAM_CHUNK_SIZE*2 - 1},
106 {"twochunk_minus_one_b5", "aaaab", SVN__STREAM_CHUNK_SIZE*2 - 1},
107 {"twochunk_a", "aaaaa", SVN__STREAM_CHUNK_SIZE*2},
108 {"twochunk_b1", "baaaa", SVN__STREAM_CHUNK_SIZE*2},
109 {"twochunk_b2", "abaaa", SVN__STREAM_CHUNK_SIZE*2},
110 {"twochunk_b3", "aabaa", SVN__STREAM_CHUNK_SIZE*2},
111 {"twochunk_b4", "aaaba", SVN__STREAM_CHUNK_SIZE*2},
112 {"twochunk_b5", "aaaab", SVN__STREAM_CHUNK_SIZE*2},
113 {"twochunk_plus_one_a", "aaaaa", SVN__STREAM_CHUNK_SIZE*2 + 1},
114 {"twochunk_plus_one_b1", "baaaa", SVN__STREAM_CHUNK_SIZE*2 + 1},
115 {"twochunk_plus_one_b2", "abaaa", SVN__STREAM_CHUNK_SIZE*2 + 1},
116 {"twochunk_plus_one_b3", "aabaa", SVN__STREAM_CHUNK_SIZE*2 + 1},
117 {"twochunk_plus_one_b4", "aaaba", SVN__STREAM_CHUNK_SIZE*2 + 1},
118 {"twochunk_plus_one_b5", "aaaab", SVN__STREAM_CHUNK_SIZE*2 + 1},
119 {0},
120 };
121
122 /* Function to prepare a single test file */
123
124 static svn_error_t *
create_test_file(struct test_file_definition_t * definition,const char * test_dir,apr_pool_t * pool,apr_pool_t * scratch_pool)125 create_test_file(struct test_file_definition_t* definition,
126 const char *test_dir,
127 apr_pool_t *pool,
128 apr_pool_t *scratch_pool)
129 {
130 apr_status_t status = 0;
131 apr_file_t *file_h;
132 apr_off_t midpos = definition->size / 2;
133 svn_error_t *err = NULL;
134 int i;
135
136 if (definition->size < 5)
137 SVN_ERR_ASSERT(strlen(definition->data) >= (apr_size_t)definition->size);
138 else
139 SVN_ERR_ASSERT(strlen(definition->data) >= 5);
140
141
142 definition->created_path = svn_dirent_join(test_dir,
143 definition->name,
144 pool);
145
146 SVN_ERR(svn_io_file_open(&file_h,
147 definition->created_path,
148 (APR_WRITE | APR_CREATE | APR_EXCL | APR_BUFFERED),
149 APR_OS_DEFAULT,
150 scratch_pool));
151
152 for (i=1; i <= definition->size; i += 1)
153 {
154 char c;
155 if (i == 1)
156 c = definition->data[0];
157 else if (i < midpos)
158 c = definition->data[1];
159 else if (i == midpos)
160 c = definition->data[2];
161 else if (i < definition->size)
162 c = definition->data[3];
163 else
164 c = definition->data[4];
165
166 status = apr_file_putc(c, file_h);
167
168 if (status)
169 break;
170 }
171
172 if (status)
173 err = svn_error_wrap_apr(status, "Can't write to file '%s'",
174 definition->name);
175
176 return svn_error_compose_create(err,
177 svn_io_file_close(file_h, scratch_pool));
178 }
179
180 /* Function to prepare the whole set of on-disk files to be compared. */
181 static svn_error_t *
create_comparison_candidates(struct test_file_definition_t ** definitions,const char * testname,apr_pool_t * pool)182 create_comparison_candidates(struct test_file_definition_t **definitions,
183 const char *testname,
184 apr_pool_t *pool)
185 {
186 apr_pool_t *iterpool = svn_pool_create(pool);
187 struct test_file_definition_t *candidate;
188 svn_error_t *err = SVN_NO_ERROR;
189 apr_size_t count = 0;
190 const char *test_dir;
191
192 SVN_ERR(svn_test_make_sandbox_dir(&test_dir, testname, pool));
193
194 for (candidate = test_file_definitions_template;
195 candidate->name != NULL;
196 candidate += 1)
197 count++;
198
199 *definitions = apr_pmemdup(pool, test_file_definitions_template,
200 (count + 1) * sizeof(**definitions));
201 for (candidate = *definitions; candidate->name != NULL; candidate += 1)
202 {
203 svn_pool_clear(iterpool);
204 err = create_test_file(candidate, test_dir, pool, iterpool);
205 if (err)
206 break;
207 }
208
209 svn_pool_destroy(iterpool);
210
211 return err;
212 }
213
214 /* Create an on-disk tree with optional read-only attributes on some
215 files and/or directories. */
216 static svn_error_t *
create_dir_tree(const char ** dir_path,const char * testname,svn_boolean_t dir_readonly,svn_boolean_t file_readonly,apr_pool_t * pool)217 create_dir_tree(const char **dir_path,
218 const char *testname,
219 svn_boolean_t dir_readonly,
220 svn_boolean_t file_readonly,
221 apr_pool_t *pool)
222 {
223 const char *test_dir_path;
224 const char *sub_dir_path;
225 const char *file_path;
226
227 SVN_ERR(svn_test_make_sandbox_dir(&test_dir_path, testname, pool));
228
229 sub_dir_path = svn_dirent_join(test_dir_path, "dir", pool);
230 SVN_ERR(svn_io_dir_make(sub_dir_path, APR_OS_DEFAULT, pool));
231
232 file_path = svn_dirent_join(sub_dir_path, "file", pool);
233 SVN_ERR(svn_io_file_create_empty(file_path, pool));
234
235 if (file_readonly)
236 SVN_ERR(svn_io_set_file_read_only(file_path, FALSE, pool));
237
238 if (dir_readonly)
239 SVN_ERR(svn_io_set_file_read_only(sub_dir_path, FALSE, pool));
240
241 *dir_path = sub_dir_path;
242 return SVN_NO_ERROR;
243 }
244
245
246
247 /* Functions to check the 2-way and 3-way file comparison functions. */
248
249 /* Test 2-way file size checking */
250 static svn_error_t *
test_two_file_size_comparison(apr_pool_t * scratch_pool)251 test_two_file_size_comparison(apr_pool_t *scratch_pool)
252 {
253 struct test_file_definition_t *inner, *outer;
254 svn_boolean_t actual;
255 svn_boolean_t expected;
256 svn_error_t *err = SVN_NO_ERROR;
257 svn_error_t *cmp_err;
258 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
259 struct test_file_definition_t *test_file_definitions;
260
261 SVN_ERR(create_comparison_candidates(&test_file_definitions,
262 "test_two_file_size_comparison",
263 scratch_pool));
264
265 for (outer = test_file_definitions; outer->name != NULL; outer += 1)
266 {
267 #ifdef SVN_IO_TEST_ALL_PERMUTATIONS
268 inner = test_file_definitions;
269 #else
270 inner = outer;
271 #endif
272 for (; inner->name != NULL; inner += 1)
273 {
274 svn_pool_clear(iterpool);
275
276 expected = inner->size != outer->size;
277
278 cmp_err = svn_io_filesizes_different_p(&actual,
279 inner->created_path,
280 outer->created_path,
281 iterpool);
282
283 if (cmp_err)
284 {
285 err = svn_error_compose_create(err, cmp_err);
286 }
287 else if (expected != actual)
288 {
289 err = svn_error_compose_create(err,
290 svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
291 "size comparison problem: '%s' and '%s'",
292 inner->created_path,
293 outer->created_path));
294 }
295 }
296 }
297
298 svn_pool_destroy(iterpool);
299 return err;
300 }
301
302
303 /* Test 2-way file content checking */
304 static svn_error_t *
test_two_file_content_comparison(apr_pool_t * scratch_pool)305 test_two_file_content_comparison(apr_pool_t *scratch_pool)
306 {
307 struct test_file_definition_t *inner, *outer;
308 svn_boolean_t actual;
309 svn_boolean_t expected;
310 svn_error_t *err = SVN_NO_ERROR;
311 svn_error_t *cmp_err;
312 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
313 struct test_file_definition_t *test_file_definitions;
314
315 SVN_ERR(create_comparison_candidates(&test_file_definitions,
316 "test_two_file_content_comparison",
317 scratch_pool));
318
319 for (outer = test_file_definitions; outer->name != NULL; outer += 1)
320 {
321 #ifdef SVN_IO_TEST_ALL_PERMUTATIONS
322 inner = test_file_definitions;
323 #else
324 inner = outer;
325 #endif
326 for (; inner->name != NULL; inner += 1)
327 {
328 svn_pool_clear(iterpool);
329
330 expected = inner->size == outer->size
331 && strcmp(inner->data, outer->data) == 0;
332
333 cmp_err = svn_io_files_contents_same_p(&actual,
334 inner->created_path,
335 outer->created_path,
336 iterpool);
337
338 if (cmp_err)
339 {
340 err = svn_error_compose_create(err, cmp_err);
341 }
342 else
343 {
344 if (expected != actual)
345 err = svn_error_compose_create(err,
346 svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
347 "content comparison problem: '%s' and '%s'",
348 inner->created_path,
349 outer->created_path));
350 }
351 }
352 }
353
354 svn_pool_destroy(iterpool);
355 return err;
356 }
357
358
359 /* Test 3-way file size checking */
360 static svn_error_t *
test_three_file_size_comparison(apr_pool_t * scratch_pool)361 test_three_file_size_comparison(apr_pool_t *scratch_pool)
362 {
363 struct test_file_definition_t *inner, *middle, *outer;
364 svn_boolean_t actual12, actual23, actual13;
365 svn_boolean_t expected12, expected23, expected13;
366 svn_error_t *err = SVN_NO_ERROR;
367 svn_error_t *cmp_err;
368 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
369 struct test_file_definition_t *test_file_definitions;
370
371 SVN_ERR(create_comparison_candidates(&test_file_definitions,
372 "test_three_file_size_comparison",
373 scratch_pool));
374
375 for (outer = test_file_definitions; outer->name != NULL; outer += 1)
376 {
377 #ifdef SVN_IO_TEST_ALL_PERMUTATIONS
378 middle = test_file_definitions;
379 #else
380 middle = outer;
381 #endif
382 for (; middle->name != NULL; middle += 1)
383 {
384 #ifdef SVN_IO_TEST_ALL_PERMUTATIONS
385 inner = test_file_definitions;
386 #else
387 inner = middle;
388 #endif
389 for (; inner->name != NULL; inner += 1)
390 {
391 svn_pool_clear(iterpool);
392
393 expected12 = inner->size != middle->size;
394 expected23 = middle->size != outer->size;
395 expected13 = inner->size != outer->size;
396
397 cmp_err = svn_io_filesizes_three_different_p(&actual12,
398 &actual23,
399 &actual13,
400 inner->created_path,
401 middle->created_path,
402 outer->created_path,
403 iterpool);
404
405 if (cmp_err)
406 {
407 err = svn_error_compose_create(err, cmp_err);
408 }
409 else
410 {
411 if (expected12 != actual12)
412 err = svn_error_compose_create(err,
413 svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
414 "size comparison problem: '%s' and '%s'",
415 inner->created_path,
416 middle->created_path));
417
418 if (expected23 != actual23)
419 err = svn_error_compose_create(err,
420 svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
421 "size comparison problem: '%s' and '%s'",
422 middle->created_path,
423 outer->created_path));
424
425 if (expected13 != actual13)
426 err = svn_error_compose_create(err,
427 svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
428 "size comparison problem: '%s' and '%s'",
429 inner->created_path,
430 outer->created_path));
431 }
432 }
433 }
434 }
435
436 svn_pool_destroy(iterpool);
437
438 return err;
439 }
440
441
442 /* Test 3-way file content checking */
443 static svn_error_t *
test_three_file_content_comparison(apr_pool_t * scratch_pool)444 test_three_file_content_comparison(apr_pool_t *scratch_pool)
445 {
446 struct test_file_definition_t *inner, *middle, *outer;
447 svn_boolean_t actual12, actual23, actual13;
448 svn_boolean_t expected12, expected23, expected13;
449 svn_error_t *err = SVN_NO_ERROR;
450 svn_error_t *cmp_err;
451 apr_pool_t *iterpool = svn_pool_create(scratch_pool);
452 struct test_file_definition_t *test_file_definitions;
453
454 SVN_ERR(create_comparison_candidates(&test_file_definitions,
455 "test_three_file_content_comparison",
456 scratch_pool));
457
458 for (outer = test_file_definitions; outer->name != NULL; outer += 1)
459 {
460 #ifdef SVN_IO_TEST_ALL_PERMUTATIONS
461 middle = test_file_definitions;
462 #else
463 middle = outer;
464 #endif
465 for (; middle->name != NULL; middle += 1)
466 {
467 #ifdef SVN_IO_TEST_ALL_PERMUTATIONS
468 inner = test_file_definitions;
469 #else
470 inner = middle;
471 #endif
472 for (; inner->name != NULL; inner += 1)
473 {
474 svn_pool_clear(iterpool);
475
476 expected12 = outer->size == middle->size
477 && strcmp(outer->data, middle->data) == 0;
478 expected23 = middle->size == inner->size
479 && strcmp(middle->data, inner->data) == 0;
480 expected13 = outer->size == inner->size
481 && strcmp(outer->data, inner->data) == 0;
482
483 cmp_err = svn_io_files_contents_three_same_p(&actual12,
484 &actual23,
485 &actual13,
486 outer->created_path,
487 middle->created_path,
488 inner->created_path,
489 iterpool);
490
491 if (cmp_err)
492 {
493 err = svn_error_compose_create(err, cmp_err);
494 }
495 else
496 {
497 if (expected12 != actual12)
498 err = svn_error_compose_create(err,
499 svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
500 "size comparison problem: '%s' and '%s'",
501 inner->created_path,
502 middle->created_path));
503
504 if (expected23 != actual23)
505 err = svn_error_compose_create(err,
506 svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
507 "size comparison problem: '%s' and '%s'",
508 middle->created_path,
509 outer->created_path));
510
511 if (expected13 != actual13)
512 err = svn_error_compose_create(err,
513 svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
514 "size comparison problem: '%s' and '%s'",
515 inner->created_path,
516 outer->created_path));
517 }
518 }
519 }
520 }
521
522 return err;
523 }
524
525 static svn_error_t *
read_length_line_shouldnt_loop(apr_pool_t * pool)526 read_length_line_shouldnt_loop(apr_pool_t *pool)
527 {
528 const char *tmp_dir;
529 const char *tmp_file;
530 char buffer[4];
531 apr_size_t buffer_limit = sizeof(buffer);
532 apr_file_t *f;
533
534 SVN_ERR(svn_test_make_sandbox_dir(&tmp_dir, "read_length_tmp", pool));
535
536 SVN_ERR(svn_io_write_unique(&tmp_file, tmp_dir, "1234\r\n", 6,
537 svn_io_file_del_on_pool_cleanup, pool));
538
539 SVN_ERR(svn_io_file_open(&f, tmp_file, APR_READ, APR_OS_DEFAULT, pool));
540
541 SVN_TEST_ASSERT_ERROR(svn_io_read_length_line(f, buffer, &buffer_limit,
542 pool), SVN_ERR_MALFORMED_FILE);
543 SVN_TEST_ASSERT(buffer_limit == 4);
544
545 return SVN_NO_ERROR;
546 }
547
548 static svn_error_t *
test_read_length_line(apr_pool_t * pool)549 test_read_length_line(apr_pool_t *pool)
550 {
551 const char *tmp_dir;
552 const char *tmp_file;
553 char buffer[80];
554 apr_size_t buffer_limit;
555 apr_file_t *f;
556 svn_error_t *err;
557
558 SVN_ERR(svn_test_make_sandbox_dir(&tmp_dir, "test_read_length_line",
559 pool));
560
561 /* Test 1: Read empty file. */
562 tmp_file = svn_dirent_join(tmp_dir, "empty", pool);
563 SVN_ERR(svn_io_file_create(tmp_file, "", pool));
564
565 SVN_ERR(svn_io_file_open(&f, tmp_file, APR_READ | APR_BUFFERED,
566 APR_OS_DEFAULT, pool));
567 buffer_limit = sizeof(buffer);
568 err = svn_io_read_length_line(f, buffer, &buffer_limit, pool);
569 SVN_TEST_ASSERT_ERROR(err, APR_EOF);
570
571 SVN_ERR(svn_io_file_close(f, pool));
572
573 /* Test 2: Read empty line.*/
574 tmp_file = svn_dirent_join(tmp_dir, "empty-line", pool);
575 SVN_ERR(svn_io_file_create(tmp_file, "\n", pool));
576
577 SVN_ERR(svn_io_file_open(&f, tmp_file, APR_READ | APR_BUFFERED,
578 APR_OS_DEFAULT, pool));
579 buffer_limit = sizeof(buffer);
580 err = svn_io_read_length_line(f, buffer, &buffer_limit, pool);
581 SVN_ERR(err);
582 SVN_TEST_ASSERT(buffer_limit == 0);
583 SVN_TEST_STRING_ASSERT(buffer, "");
584 SVN_ERR(svn_io_file_close(f, pool));
585
586 /* Test 3: Read two lines.*/
587 tmp_file = svn_dirent_join(tmp_dir, "lines", pool);
588 SVN_ERR(svn_io_file_create(tmp_file, "first\nsecond\n", pool));
589
590 SVN_ERR(svn_io_file_open(&f, tmp_file, APR_READ | APR_BUFFERED,
591 APR_OS_DEFAULT, pool));
592
593 buffer_limit = sizeof(buffer);
594 err = svn_io_read_length_line(f, buffer, &buffer_limit, pool);
595 SVN_ERR(err);
596 SVN_TEST_ASSERT(buffer_limit == 5);
597 SVN_TEST_STRING_ASSERT(buffer, "first");
598
599 buffer_limit = sizeof(buffer);
600 err = svn_io_read_length_line(f, buffer, &buffer_limit, pool);
601 SVN_ERR(err);
602 SVN_TEST_ASSERT(buffer_limit == 6);
603 SVN_TEST_STRING_ASSERT(buffer, "second");
604
605 buffer_limit = sizeof(buffer);
606 err = svn_io_read_length_line(f, buffer, &buffer_limit, pool);
607 SVN_TEST_ASSERT_ERROR(err, APR_EOF);
608
609 SVN_ERR(svn_io_file_close(f, pool));
610
611 /* Test 4: Content without end-of-line.*/
612 tmp_file = svn_dirent_join(tmp_dir, "no-eol", pool);
613 SVN_ERR(svn_io_file_create(tmp_file, "text", pool));
614
615 SVN_ERR(svn_io_file_open(&f, tmp_file, APR_READ | APR_BUFFERED,
616 APR_OS_DEFAULT, pool));
617
618 buffer_limit = sizeof(buffer);
619 err = svn_io_read_length_line(f, buffer, &buffer_limit, pool);
620 SVN_TEST_ASSERT_ERROR(err, APR_EOF);
621
622 SVN_ERR(svn_io_file_close(f, pool));
623
624 return SVN_NO_ERROR;
625 }
626
627 static svn_error_t *
test_file_readline(apr_pool_t * pool)628 test_file_readline(apr_pool_t *pool)
629 {
630 const char *tmp_dir;
631 const char *tmp_file;
632 svn_stringbuf_t *buf;
633 apr_file_t *f;
634 svn_error_t *err;
635 const char *eol;
636 svn_boolean_t eof;
637 apr_off_t pos;
638
639 SVN_ERR(svn_test_make_sandbox_dir(&tmp_dir, "test_file_readline",
640 pool));
641
642 tmp_file = svn_dirent_join(tmp_dir, "foo", pool);
643
644 SVN_ERR(svn_io_file_create(tmp_file, "CR\rLF\nCRLF\r\nno-eol", pool));
645
646 SVN_ERR(svn_io_file_open(&f, tmp_file, APR_READ | APR_BUFFERED,
647 APR_OS_DEFAULT, pool));
648 err = svn_io_file_readline(f, &buf, &eol, &eof, APR_SIZE_MAX, pool, pool);
649 SVN_ERR(err);
650 SVN_TEST_STRING_ASSERT(buf->data, "CR");
651 SVN_TEST_STRING_ASSERT(eol, "\r");
652 SVN_TEST_ASSERT(!eof);
653
654 /* Check that APR file reports correct offset. See r1719196 why it's
655 important. */
656 SVN_ERR(svn_io_file_get_offset(&pos, f, pool));
657 SVN_TEST_INT_ASSERT(pos, 3);
658
659 err = svn_io_file_readline(f, &buf, &eol, &eof, APR_SIZE_MAX, pool, pool);
660 SVN_ERR(err);
661 SVN_TEST_STRING_ASSERT(buf->data, "LF");
662 SVN_TEST_STRING_ASSERT(eol, "\n");
663 SVN_TEST_ASSERT(!eof);
664
665 /* Check that APR file reports correct offset. See r1719196 why it's
666 important. */
667 SVN_ERR(svn_io_file_get_offset(&pos, f, pool));
668 SVN_TEST_INT_ASSERT(pos, 6);
669
670 err = svn_io_file_readline(f, &buf, &eol, &eof, APR_SIZE_MAX, pool, pool);
671 SVN_ERR(err);
672 SVN_TEST_STRING_ASSERT(buf->data, "CRLF");
673 SVN_TEST_STRING_ASSERT(eol, "\r\n");
674 SVN_TEST_ASSERT(!eof);
675
676 /* Check that APR file reports correct offset. See r1719196 why it's
677 important. */
678 SVN_ERR(svn_io_file_get_offset(&pos, f, pool));
679 SVN_TEST_INT_ASSERT(pos, 12);
680
681 err = svn_io_file_readline(f, &buf, &eol, &eof, APR_SIZE_MAX, pool, pool);
682 SVN_ERR(err);
683 SVN_TEST_STRING_ASSERT(buf->data, "no-eol");
684 SVN_TEST_STRING_ASSERT(eol, NULL);
685 SVN_TEST_ASSERT(eof);
686
687 /* Check that APR file reports correct offset. See r1719196 why it's
688 important. */
689 SVN_ERR(svn_io_file_get_offset(&pos, f, pool));
690 SVN_TEST_INT_ASSERT(pos, 18);
691
692 /* Further reads still returns EOF. */
693 err = svn_io_file_readline(f, &buf, &eol, &eof, APR_SIZE_MAX, pool, pool);
694 SVN_ERR(err);
695 SVN_TEST_STRING_ASSERT(buf->data, "");
696 SVN_TEST_STRING_ASSERT(eol, NULL);
697 SVN_TEST_ASSERT(eof);
698
699 /* Check that APR file reports correct offset. See r1719196 why it's
700 important. */
701 SVN_ERR(svn_io_file_get_offset(&pos, f, pool));
702 SVN_TEST_INT_ASSERT(pos, 18);
703
704 SVN_ERR(svn_io_file_close(f, pool));
705
706 return SVN_NO_ERROR;
707 }
708
709 static svn_error_t *
test_open_uniquely_named(apr_pool_t * pool)710 test_open_uniquely_named(apr_pool_t *pool)
711 {
712 const char *tmp_dir;
713 apr_file_t *file;
714 const char *path;
715 svn_error_t *err;
716
717 SVN_ERR(svn_test_make_sandbox_dir(&tmp_dir, "test_open_uniquely_named",
718 pool));
719
720 /* Test #1: File 'foo.tmp' doesn't exist. */
721 SVN_ERR(svn_io_open_uniquely_named(&file, &path, tmp_dir, "foo", ".tmp",
722 svn_io_file_del_none, pool, pool));
723 SVN_TEST_STRING_ASSERT(path, svn_dirent_join(tmp_dir, "foo.tmp", pool));
724 SVN_ERR(svn_io_file_close(file, pool));
725
726 /* Test #2: File 'foo.tmp' is already exist. */
727 SVN_ERR(svn_io_open_uniquely_named(NULL, &path, tmp_dir, "foo", ".tmp",
728 svn_io_file_del_none, pool, pool));
729 SVN_TEST_STRING_ASSERT(path, svn_dirent_join(tmp_dir, "foo.2.tmp", pool));
730
731 /* Test #3: Directory named 'bar.tmp' is already exist. */
732 SVN_ERR(svn_io_dir_make(svn_dirent_join(tmp_dir, "bar.tmp", pool),
733 APR_OS_DEFAULT, pool));
734 SVN_ERR(svn_io_open_uniquely_named(NULL, &path, tmp_dir, "bar", ".tmp",
735 svn_io_file_del_none, pool, pool));
736 SVN_TEST_STRING_ASSERT(path, svn_dirent_join(tmp_dir, "bar.2.tmp", pool));
737
738
739 /* Test #4: Attempt create file in non-existing directory. */
740 err = svn_io_open_uniquely_named(NULL, &path,
741 svn_dirent_join(tmp_dir, "non-existing", pool),
742 NULL, NULL, svn_io_file_del_none, pool, pool);
743 if (err && APR_STATUS_IS_ENOENT(err->apr_err))
744 {
745 svn_error_clear(err);
746 }
747 else if (err)
748 {
749 return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
750 "Expected error APR_STATUS_IS_ENOTDIR() but "
751 "got %s",
752 svn_error_symbolic_name(err->apr_err));
753 }
754 else
755 {
756 SVN_TEST_ASSERT_ANY_ERROR(err);
757 }
758
759 /* Test #5: File 'yota.tmp' is already exist and readonly. */
760 SVN_ERR(svn_io_file_create_empty(svn_dirent_join(tmp_dir, "yota.tmp", pool),
761 pool));
762 SVN_ERR(svn_io_set_file_read_only(svn_dirent_join(tmp_dir, "yota.tmp", pool),
763 FALSE, pool));
764 SVN_ERR(svn_io_open_uniquely_named(NULL, &path, tmp_dir, "yota", ".tmp",
765 svn_io_file_del_none, pool, pool));
766 SVN_TEST_STRING_ASSERT(path, svn_dirent_join(tmp_dir, "yota.2.tmp", pool));
767
768 return SVN_NO_ERROR;
769 }
770
771 /* Move the read pointer in FILE to absolute position OFFSET and align
772 * the read buffer to multiples of BLOCK_SIZE. BUFFERED is set only if
773 * FILE actually uses a read buffer. Use POOL for allocations.
774 */
775 static svn_error_t *
aligned_seek(apr_file_t * file,apr_size_t block_size,apr_size_t offset,svn_boolean_t buffered,apr_pool_t * pool)776 aligned_seek(apr_file_t *file,
777 apr_size_t block_size,
778 apr_size_t offset,
779 svn_boolean_t buffered,
780 apr_pool_t *pool)
781 {
782 apr_off_t block_start;
783 apr_off_t current;
784
785 SVN_ERR(svn_io_file_aligned_seek(file, (apr_off_t)block_size,
786 &block_start, (apr_off_t)offset, pool));
787
788 /* block start shall be aligned to multiples of block_size.
789 If it isn't, it must be aligned to APR's default block size(pre-1.3 APR)
790 */
791 if (buffered)
792 {
793 SVN_TEST_ASSERT(block_start % block_size == 0);
794 SVN_TEST_ASSERT(offset - block_start < block_size);
795 }
796
797 /* we must be at the desired offset */
798 SVN_ERR(svn_io_file_get_offset(¤t, file, pool));
799 SVN_TEST_ASSERT(current == (apr_off_t)offset);
800
801 return SVN_NO_ERROR;
802 }
803
804 /* Move the read pointer in FILE to absolute position OFFSET, align the
805 * read buffer to multiples of BLOCK_SIZE and read one byte from that
806 * position. Verify that it matches the CONTENTS for that offset.
807 * BUFFERED is set only if FILE actually uses a read buffer.
808 * Use POOL for allocations.
809 */
810 static svn_error_t *
aligned_read_at(apr_file_t * file,svn_stringbuf_t * contents,apr_size_t block_size,apr_size_t offset,svn_boolean_t buffered,apr_pool_t * pool)811 aligned_read_at(apr_file_t *file,
812 svn_stringbuf_t *contents,
813 apr_size_t block_size,
814 apr_size_t offset,
815 svn_boolean_t buffered,
816 apr_pool_t *pool)
817 {
818 char c;
819 SVN_ERR(aligned_seek(file, block_size, offset, buffered, pool));
820
821 /* the data we read must match whatever we wrote there */
822 SVN_ERR(svn_io_file_getc(&c, file, pool));
823 SVN_TEST_ASSERT(c == contents->data[offset]);
824
825 return SVN_NO_ERROR;
826 }
827
828 /* Verify that aligned seek with the given BLOCK_SIZE works for FILE.
829 * CONTENTS is the data expected from FILE. BUFFERED is set only if FILE
830 * actually uses a read buffer. Use POOL for allocations.
831 */
832 static svn_error_t *
aligned_read(apr_file_t * file,svn_stringbuf_t * contents,apr_size_t block_size,svn_boolean_t buffered,apr_pool_t * pool)833 aligned_read(apr_file_t *file,
834 svn_stringbuf_t *contents,
835 apr_size_t block_size,
836 svn_boolean_t buffered,
837 apr_pool_t *pool)
838 {
839 apr_size_t i;
840 apr_size_t offset = 0;
841 const apr_size_t prime = 78427;
842
843 /* "random" access to different offsets */
844 for (i = 0, offset = prime; i < 10; ++i, offset += prime)
845 SVN_ERR(aligned_read_at(file, contents, block_size,
846 offset % contents->len, buffered, pool));
847
848 /* we can seek to EOF */
849 SVN_ERR(aligned_seek(file, contents->len, block_size, buffered, pool));
850
851 /* reversed order access to all bytes */
852 for (i = contents->len; i > 0; --i)
853 SVN_ERR(aligned_read_at(file, contents, block_size, i - 1, buffered,
854 pool));
855
856 /* forward order access to all bytes */
857 for (i = 0; i < contents->len; ++i)
858 SVN_ERR(aligned_read_at(file, contents, block_size, i, buffered, pool));
859
860 return SVN_NO_ERROR;
861 }
862
863 static svn_error_t *
aligned_seek_test(apr_pool_t * pool)864 aligned_seek_test(apr_pool_t *pool)
865 {
866 apr_size_t i;
867 const char *tmp_dir;
868 const char *tmp_file;
869 apr_file_t *f;
870 svn_stringbuf_t *contents;
871 const apr_size_t file_size = 100000;
872
873 /* create a temp folder & schedule it for automatic cleanup */
874 SVN_ERR(svn_test_make_sandbox_dir(&tmp_dir, "aligned_seek_tmp", pool));
875
876 /* create a temp file with know contents */
877
878 contents = svn_stringbuf_create_ensure(file_size, pool);
879 for (i = 0; i < file_size; ++i)
880 svn_stringbuf_appendbyte(contents, (char)rand());
881
882 SVN_ERR(svn_io_write_unique(&tmp_file, tmp_dir, contents->data,
883 contents->len,
884 svn_io_file_del_on_pool_cleanup, pool));
885
886 /* now, access read data with varying alignment sizes */
887 SVN_ERR(svn_io_file_open(&f, tmp_file, APR_READ | APR_BUFFERED,
888 APR_OS_DEFAULT, pool));
889 SVN_ERR(aligned_read(f, contents, 0x1000, TRUE, pool)); /* APR default */
890 SVN_ERR(aligned_read(f, contents, 0x8000, TRUE, pool)); /* "unusual" 32K */
891 SVN_ERR(aligned_read(f, contents, 0x10000, TRUE, pool)); /* FSX default */
892 SVN_ERR(aligned_read(f, contents, 0x100000, TRUE, pool)); /* larger than file */
893 SVN_ERR(aligned_read(f, contents, 10001, TRUE, pool)); /* odd, larger than
894 APR default */
895 SVN_ERR(aligned_read(f, contents, 1003, TRUE, pool)); /* odd, smaller than
896 APR default */
897 SVN_ERR(svn_io_file_close(f, pool));
898
899 /* now, try read data with buffering disabled.
900 That is a special case because APR reports a buffer size of 0. */
901 SVN_ERR(svn_io_file_open(&f, tmp_file, APR_READ, APR_OS_DEFAULT, pool));
902 SVN_ERR(aligned_read(f, contents, 0x1000, FALSE, pool));
903 SVN_ERR(aligned_read(f, contents, 0x8000, FALSE, pool));
904 SVN_ERR(aligned_read(f, contents, 0x10000, FALSE, pool));
905 SVN_ERR(aligned_read(f, contents, 0x100000, FALSE, pool));
906 SVN_ERR(aligned_read(f, contents, 10001, FALSE, pool));
907 SVN_ERR(aligned_read(f, contents, 1003, FALSE, pool));
908 SVN_ERR(svn_io_file_close(f, pool));
909
910 return SVN_NO_ERROR;
911 }
912
913 static svn_error_t *
ignore_enoent(apr_pool_t * pool)914 ignore_enoent(apr_pool_t *pool)
915 {
916 const char *tmp_dir, *path;
917 const svn_io_dirent2_t *dirent_p;
918 apr_file_t *file;
919
920 /* Create an empty directory. */
921 SVN_ERR(svn_test_make_sandbox_dir(&tmp_dir, "ignore_enoent", pool));
922
923 /* Path does not exist. */
924 path = svn_dirent_join(tmp_dir, "not-present", pool);
925 SVN_ERR(svn_io_remove_dir2(path, TRUE, NULL, NULL, pool));
926 SVN_ERR(svn_io_remove_file2(path, TRUE, pool));
927 SVN_ERR(svn_io_set_file_read_only(path, TRUE, pool));
928 SVN_ERR(svn_io_set_file_read_write(path, TRUE, pool));
929 SVN_ERR(svn_io_set_file_executable(path, TRUE, TRUE, pool));
930 SVN_ERR(svn_io_set_file_executable(path, FALSE, TRUE, pool));
931 SVN_ERR(svn_io_stat_dirent2(&dirent_p, path, TRUE, TRUE, pool, pool));
932 SVN_ERR(svn_io_stat_dirent2(&dirent_p, path, FALSE, TRUE, pool, pool));
933
934 /* Neither path nor parent exists. */
935 path = svn_dirent_join(path, "not-present", pool);
936 SVN_ERR(svn_io_remove_dir2(path, TRUE, NULL, NULL, pool));
937 SVN_ERR(svn_io_remove_file2(path, TRUE, pool));
938 SVN_ERR(svn_io_set_file_read_only(path, TRUE, pool));
939 SVN_ERR(svn_io_set_file_read_write(path, TRUE, pool));
940 SVN_ERR(svn_io_set_file_executable(path, TRUE, TRUE, pool));
941 SVN_ERR(svn_io_set_file_executable(path, FALSE, TRUE, pool));
942 SVN_ERR(svn_io_stat_dirent2(&dirent_p, path, TRUE, TRUE, pool, pool));
943 SVN_ERR(svn_io_stat_dirent2(&dirent_p, path, FALSE, TRUE, pool, pool));
944
945 /* File does exist. */
946 path = svn_dirent_join(tmp_dir, "present", pool);
947 SVN_ERR(svn_io_file_open(&file, path,
948 APR_WRITE | APR_CREATE | APR_TRUNCATE,
949 APR_OS_DEFAULT,
950 pool));
951 SVN_ERR(svn_io_file_close(file, pool));
952
953 /* Path does not exist as child of file. */
954 path = svn_dirent_join(path, "not-present", pool);
955 SVN_ERR(svn_io_remove_dir2(path, TRUE, NULL, NULL, pool));
956 SVN_ERR(svn_io_remove_file2(path, TRUE, pool));
957 SVN_ERR(svn_io_set_file_read_only(path, TRUE, pool));
958 SVN_ERR(svn_io_set_file_read_write(path, TRUE, pool));
959 SVN_ERR(svn_io_set_file_executable(path, TRUE, TRUE, pool));
960 SVN_ERR(svn_io_set_file_executable(path, FALSE, TRUE, pool));
961 SVN_ERR(svn_io_stat_dirent2(&dirent_p, path, TRUE, TRUE, pool, pool));
962 SVN_ERR(svn_io_stat_dirent2(&dirent_p, path, FALSE, TRUE, pool, pool));
963
964 return SVN_NO_ERROR;
965 }
966
967 static svn_error_t *
test_install_stream_to_longpath(apr_pool_t * pool)968 test_install_stream_to_longpath(apr_pool_t *pool)
969 {
970 const char *tmp_dir;
971 const char *final_abspath;
972 const char *deep_dir;
973 svn_stream_t *stream;
974 svn_stringbuf_t *actual_content;
975 int i;
976
977 /* Create an empty directory. */
978 SVN_ERR(svn_test_make_sandbox_dir(&tmp_dir,
979 "test_install_stream_to_longpath",
980 pool));
981
982 deep_dir = tmp_dir;
983
984 /* Generate very long path (> 260 symbols) */
985 for (i = 0; i < 26; i++)
986 {
987 deep_dir = svn_dirent_join(deep_dir, "1234567890", pool);
988 SVN_ERR(svn_io_make_dir_recursively(deep_dir, pool));
989 }
990
991 final_abspath = svn_dirent_join(deep_dir, "stream1", pool);
992 SVN_ERR(svn_stream__create_for_install(&stream, deep_dir, pool, pool));
993 SVN_ERR(svn_stream_puts(stream, "stream1 content"));
994 SVN_ERR(svn_stream_close(stream));
995 SVN_ERR(svn_stream__install_stream(stream,
996 final_abspath,
997 TRUE,
998 pool));
999
1000 SVN_ERR(svn_stringbuf_from_file2(&actual_content,
1001 final_abspath,
1002 pool));
1003
1004 SVN_TEST_STRING_ASSERT(actual_content->data, "stream1 content");
1005
1006 return SVN_NO_ERROR;
1007 }
1008
1009 static svn_error_t *
test_install_stream_over_readonly_file(apr_pool_t * pool)1010 test_install_stream_over_readonly_file(apr_pool_t *pool)
1011 {
1012 const char *tmp_dir;
1013 const char *final_abspath;
1014 svn_stream_t *stream;
1015 svn_stringbuf_t *actual_content;
1016
1017 /* Create an empty directory. */
1018 SVN_ERR(svn_test_make_sandbox_dir(&tmp_dir,
1019 "test_install_stream_over_readonly_file",
1020 pool));
1021
1022 final_abspath = svn_dirent_join(tmp_dir, "stream1", pool);
1023
1024 /* Create empty read-only file. */
1025 SVN_ERR(svn_io_file_create_empty(final_abspath, pool));
1026 SVN_ERR(svn_io_set_file_read_only(final_abspath, FALSE, pool));
1027
1028 SVN_ERR(svn_stream__create_for_install(&stream, tmp_dir, pool, pool));
1029 SVN_ERR(svn_stream_puts(stream, "stream1 content"));
1030 SVN_ERR(svn_stream_close(stream));
1031 SVN_ERR(svn_stream__install_stream(stream,
1032 final_abspath,
1033 TRUE,
1034 pool));
1035
1036 SVN_ERR(svn_stringbuf_from_file2(&actual_content,
1037 final_abspath,
1038 pool));
1039
1040 SVN_TEST_STRING_ASSERT(actual_content->data, "stream1 content");
1041
1042 return SVN_NO_ERROR;
1043 }
1044
1045 static svn_error_t *
test_file_size_get(apr_pool_t * pool)1046 test_file_size_get(apr_pool_t *pool)
1047 {
1048 const char *tmp_dir, *path;
1049 apr_file_t *file;
1050 svn_filesize_t filesize;
1051
1052 /* Create an empty directory. */
1053 SVN_ERR(svn_test_make_sandbox_dir(&tmp_dir, "test_file_size_get", pool));
1054
1055 /* Path does not exist. */
1056 path = svn_dirent_join(tmp_dir, "file", pool);
1057
1058 /* Create a file.*/
1059 SVN_ERR(svn_io_file_open(&file, path,
1060 APR_WRITE | APR_CREATE | APR_BUFFERED,
1061 APR_OS_DEFAULT, pool));
1062 SVN_ERR(svn_io_file_size_get(&filesize, file, pool));
1063 SVN_TEST_ASSERT(filesize == 0);
1064
1065 /* Write 8 bytes and check new size. */
1066 SVN_ERR(svn_io_file_write_full(file, "12345678", 8, NULL, pool));
1067
1068 SVN_ERR(svn_io_file_size_get(&filesize, file, pool));
1069 SVN_TEST_ASSERT(filesize == 8);
1070
1071 /* Truncate to 2 bytes. */
1072 SVN_ERR(svn_io_file_trunc(file, 2, pool));
1073
1074 SVN_ERR(svn_io_file_size_get(&filesize, file, pool));
1075 SVN_TEST_ASSERT(filesize == 2);
1076
1077 /* Close the file. */
1078 SVN_ERR(svn_io_file_close(file, pool));
1079 return SVN_NO_ERROR;
1080 }
1081
1082 static svn_error_t *
test_file_rename2(apr_pool_t * pool)1083 test_file_rename2(apr_pool_t *pool)
1084 {
1085 const char *tmp_dir;
1086 const char *foo_path;
1087 const char *bar_path;
1088 svn_stringbuf_t *actual_content;
1089 svn_node_kind_t actual_kind;
1090
1091 /* Create an empty directory. */
1092 SVN_ERR(svn_test_make_sandbox_dir(&tmp_dir, "test_file_rename2", pool));
1093
1094 foo_path = svn_dirent_join(tmp_dir, "foo", pool);
1095 bar_path = svn_dirent_join(tmp_dir, "bar", pool);
1096
1097 /* Test 1: Simple file rename. */
1098 SVN_ERR(svn_io_file_create(foo_path, "file content", pool));
1099
1100 SVN_ERR(svn_io_file_rename2(foo_path, bar_path, FALSE, pool));
1101
1102 SVN_ERR(svn_stringbuf_from_file2(&actual_content, bar_path, pool));
1103 SVN_TEST_STRING_ASSERT(actual_content->data, "file content");
1104
1105 SVN_ERR(svn_io_check_path(foo_path, &actual_kind, pool));
1106 SVN_TEST_ASSERT(actual_kind == svn_node_none);
1107 SVN_ERR(svn_io_remove_file2(bar_path, FALSE, pool));
1108
1109 /* Test 2: Rename file with flush_to_disk flag. */
1110 SVN_ERR(svn_io_file_create(foo_path, "file content", pool));
1111
1112 SVN_ERR(svn_io_file_rename2(foo_path, bar_path, TRUE, pool));
1113
1114 SVN_ERR(svn_stringbuf_from_file2(&actual_content, bar_path, pool));
1115 SVN_TEST_STRING_ASSERT(actual_content->data, "file content");
1116 SVN_ERR(svn_io_check_path(foo_path, &actual_kind, pool));
1117 SVN_TEST_ASSERT(actual_kind == svn_node_none);
1118
1119 SVN_ERR(svn_io_remove_file2(bar_path, FALSE, pool));
1120
1121 /* Test 3: Rename file over existing read-only file. */
1122 SVN_ERR(svn_io_file_create(foo_path, "file content", pool));
1123 SVN_ERR(svn_io_file_create(bar_path, "bar content", pool));
1124 SVN_ERR(svn_io_set_file_read_only(bar_path, FALSE, pool));
1125
1126 SVN_ERR(svn_io_file_rename2(foo_path, bar_path, FALSE, pool));
1127
1128 SVN_ERR(svn_stringbuf_from_file2(&actual_content, bar_path, pool));
1129 SVN_TEST_STRING_ASSERT(actual_content->data, "file content");
1130 SVN_ERR(svn_io_check_path(foo_path, &actual_kind, pool));
1131 SVN_TEST_ASSERT(actual_kind == svn_node_none);
1132 SVN_ERR(svn_io_remove_file2(bar_path, FALSE, pool));
1133
1134 return SVN_NO_ERROR;
1135 }
1136
1137 static svn_error_t *
test_apr_trunc_workaround(apr_pool_t * pool)1138 test_apr_trunc_workaround(apr_pool_t *pool)
1139 {
1140 const char *tmp_dir;
1141 const char *tmp_file;
1142 apr_file_t *f;
1143 apr_size_t len;
1144 apr_off_t offset;
1145 char dummy;
1146
1147 /* create a temp folder & schedule it for automatic cleanup */
1148 SVN_ERR(svn_dirent_get_absolute(&tmp_dir, "test_apr_trunc_workaround",
1149 pool));
1150 SVN_ERR(svn_io_remove_dir2(tmp_dir, TRUE, NULL, NULL, pool));
1151 SVN_ERR(svn_io_make_dir_recursively(tmp_dir, pool));
1152 svn_test_add_dir_cleanup(tmp_dir);
1153
1154 /* create an r/w file */
1155 tmp_file = svn_dirent_join(tmp_dir, "file", pool);
1156 SVN_ERR(svn_io_file_open(&f, tmp_file,
1157 APR_READ | APR_WRITE | APR_BUFFERED | APR_CREATE |
1158 APR_TRUNCATE,
1159 APR_OS_DEFAULT, pool));
1160
1161 /* write some content and put it internally into read mode */
1162 len = 10;
1163 SVN_ERR(svn_io_file_write(f, "0123456789", &len, pool));
1164
1165 offset = 0;
1166 SVN_ERR(svn_io_file_seek(f, APR_SET, &offset, pool));
1167 SVN_ERR(svn_io_file_getc(&dummy, f, pool));
1168
1169 /* clear the file and write some new content */
1170 SVN_ERR(svn_io_file_trunc(f, 0, pool));
1171 len = 3;
1172 SVN_ERR(svn_io_file_write(f, "abc", &len, pool));
1173
1174 /* we should now be positioned at the end of the new content */
1175 offset = 0;
1176 SVN_ERR(svn_io_file_seek(f, APR_CUR, &offset, pool));
1177 SVN_TEST_ASSERT(offset == (int)len);
1178
1179 return SVN_NO_ERROR;
1180 }
1181
1182
1183 /* Issue #4806 */
1184 static svn_error_t *
test_rmtree_all_writable(apr_pool_t * pool)1185 test_rmtree_all_writable(apr_pool_t *pool)
1186 {
1187 const char *dir_path = NULL;
1188
1189 SVN_ERR(create_dir_tree(&dir_path, "test_rmtree_all_writable",
1190 FALSE, FALSE, pool));
1191 SVN_ERR(svn_io_remove_dir2(dir_path, FALSE, NULL, NULL, pool));
1192 return SVN_NO_ERROR;
1193 }
1194
1195 /* Issue #4806 */
1196 static svn_error_t *
test_rmtree_file_readonly(apr_pool_t * pool)1197 test_rmtree_file_readonly(apr_pool_t *pool)
1198 {
1199 const char *dir_path = NULL;
1200
1201 SVN_ERR(create_dir_tree(&dir_path, "test_rmtree_file_readonly",
1202 FALSE, TRUE, pool));
1203 SVN_ERR(svn_io_remove_dir2(dir_path, FALSE, NULL, NULL, pool));
1204 return SVN_NO_ERROR;
1205 }
1206
1207 /* Issue #4806 */
1208 static svn_error_t *
test_rmtree_dir_readonly(apr_pool_t * pool)1209 test_rmtree_dir_readonly(apr_pool_t *pool)
1210 {
1211 const char *dir_path = NULL;
1212
1213 SVN_ERR(create_dir_tree(&dir_path, "test_rmtree_dir_readonly",
1214 TRUE, FALSE, pool));
1215 SVN_ERR(svn_io_remove_dir2(dir_path, FALSE, NULL, NULL, pool));
1216 return SVN_NO_ERROR;
1217 }
1218
1219 /* Issue #4806 */
1220 static svn_error_t *
test_rmtree_all_readonly(apr_pool_t * pool)1221 test_rmtree_all_readonly(apr_pool_t *pool)
1222 {
1223 const char *dir_path = NULL;
1224
1225 SVN_ERR(create_dir_tree(&dir_path, "test_rmtree_all_readonly",
1226 TRUE, TRUE, pool));
1227 SVN_ERR(svn_io_remove_dir2(dir_path, FALSE, NULL, NULL, pool));
1228 return SVN_NO_ERROR;
1229 }
1230
1231
1232 /* The test table. */
1233
1234 static int max_threads = 3;
1235
1236 static struct svn_test_descriptor_t test_funcs[] =
1237 {
1238 SVN_TEST_NULL,
1239 SVN_TEST_PASS2(test_two_file_size_comparison,
1240 "two file size comparison"),
1241 SVN_TEST_PASS2(test_two_file_content_comparison,
1242 "two file content comparison"),
1243 SVN_TEST_PASS2(test_three_file_size_comparison,
1244 "three file size comparison"),
1245 SVN_TEST_PASS2(test_three_file_content_comparison,
1246 "three file content comparison"),
1247 SVN_TEST_PASS2(read_length_line_shouldnt_loop,
1248 "svn_io_read_length_line() shouldn't loop"),
1249 SVN_TEST_PASS2(aligned_seek_test,
1250 "test aligned seek"),
1251 SVN_TEST_PASS2(ignore_enoent,
1252 "test ignore-enoent"),
1253 SVN_TEST_PASS2(test_install_stream_to_longpath,
1254 "test svn_stream__install_stream to long path"),
1255 SVN_TEST_PASS2(test_install_stream_over_readonly_file,
1256 "test svn_stream__install_stream over RO file"),
1257 SVN_TEST_PASS2(test_file_size_get,
1258 "test svn_io_file_size_get"),
1259 SVN_TEST_PASS2(test_file_rename2,
1260 "test svn_io_file_rename2"),
1261 SVN_TEST_PASS2(test_read_length_line,
1262 "test svn_io_read_length_line()"),
1263 SVN_TEST_PASS2(test_file_readline,
1264 "test svn_io_file_readline()"),
1265 SVN_TEST_PASS2(test_open_uniquely_named,
1266 "test svn_io_open_uniquely_named()"),
1267 SVN_TEST_PASS2(test_apr_trunc_workaround,
1268 "test workaround for APR in svn_io_file_trunc"),
1269 SVN_TEST_PASS2(test_rmtree_all_writable,
1270 "test svn_io_remove_dir2() with writable tree"),
1271 SVN_TEST_PASS2(test_rmtree_file_readonly,
1272 "test svn_io_remove_dir2() with read-only file"),
1273 SVN_TEST_PASS2(test_rmtree_dir_readonly,
1274 "test svn_io_remove_dir2() with read-only directory"),
1275 SVN_TEST_PASS2(test_rmtree_all_readonly,
1276 "test svn_io_remove_dir2() with read-only tree"),
1277 SVN_TEST_NULL
1278 };
1279
1280 SVN_TEST_MAIN
1281