View | Details | Raw Unified | Return to bug 196273
Collapse All | Expand All

(-)tests/Makefile (-1 / +9 lines)
Lines 1-6 Link Here
1
# $FreeBSD$
1
# $FreeBSD$
2
2
3
TESTSDIR=	${TESTSBASE}/usr.bin/truncate
3
TESTSDIR=	${TESTSBASE}/usr.bin/truncate
4
ATF_TESTS_SH=	truncate_test 
4
ATF_TESTS_SH=	allocate_test truncate_test 
5
ATF_TESTS_C=	sparse_test
6
CLEANFILES+=	allocate_test.sh truncate_test.sh
5
7
8
allocate_test.sh: base_test.func allocate_test.func
9
	cat ${.ALLSRC} > ${.TARGET}
10
11
truncate_test.sh: base_test.func truncate_test.func
12
	cat ${.ALLSRC} > ${.TARGET}
13
6
.include <bsd.test.mk>
14
.include <bsd.test.mk>
(-)tests/allocate_test.func (+21 lines)
Line 0 Link Here
1
atf_init_test_cases()
2
{
3
	TRUNC="truncate -a"
4
5
	atf_add_test_case illegal_option
6
	atf_add_test_case illegal_size
7
	atf_add_test_case too_large_size
8
	atf_add_test_case opt_c
9
	atf_add_test_case opt_rs
10
	atf_add_test_case no_files
11
	atf_add_test_case bad_refer
12
	atf_add_test_case bad_truncate
13
	atf_add_test_case cannot_open
14
	atf_add_test_case new_absolute_grow
15
	atf_add_test_case new_absolute_shrink
16
	atf_add_test_case new_relative_grow
17
	atf_add_test_case new_relative_shrink
18
	atf_add_test_case reference
19
	atf_add_test_case new_zero
20
	atf_add_test_case negative
21
}
(-)tests/base_test.func (-46 / +26 lines)
Lines 57-64 Link Here
57
	_custom_create_file creat
57
	_custom_create_file creat
58
	_custom_create_file print "${1}"
58
	_custom_create_file print "${1}"
59
	_custom_create_file print \
59
	_custom_create_file print \
60
	    "usage: truncate [-c] -s [+|-]size[K|k|M|m|G|g|T|t] file ..."
60
	    "usage: truncate [-ac] -s [+|-]size[K|k|M|m|G|g|T|t|P|p|E|e] file ..."
61
	_custom_create_file print "       truncate [-c] -r rfile file ..."
61
	_custom_create_file print "       truncate [-ac] -r rfile file ..."
62
}
62
}
63
63
64
atf_test_case illegal_option
64
atf_test_case illegal_option
Lines 72-78 Link Here
72
	create_stderr_usage_file 'truncate: illegal option -- 7'
72
	create_stderr_usage_file 'truncate: illegal option -- 7'
73
73
74
	# We expect the error message, with no new files.
74
	# We expect the error message, with no new files.
75
	atf_check -s not-exit:0 -e file:stderr.txt truncate -7 -s0 output.txt
75
	atf_check -s not-exit:0 -e file:stderr.txt ${TRUNC} -7 -s0 output.txt
76
	[ ! -e output.txt ] || atf_fail "output.txt should not exist"
76
	[ ! -e output.txt ] || atf_fail "output.txt should not exist"
77
}
77
}
78
78
Lines 87-93 Link Here
87
	create_stderr_file "truncate: invalid size argument \`+1L'"
87
	create_stderr_file "truncate: invalid size argument \`+1L'"
88
88
89
	# We expect the error message, with no new files.
89
	# We expect the error message, with no new files.
90
	atf_check -s not-exit:0 -e file:stderr.txt truncate -s+1L output.txt
90
	atf_check -s not-exit:0 -e file:stderr.txt ${TRUNC} -s+1L output.txt
91
	[ ! -e output.txt ] || atf_fail "output.txt should not exist"
91
	[ ! -e output.txt ] || atf_fail "output.txt should not exist"
92
}
92
}
93
93
Lines 103-109 Link Here
103
103
104
	# We expect the error message, with no new files.
104
	# We expect the error message, with no new files.
105
	atf_check -s not-exit:0 -e file:stderr.txt \
105
	atf_check -s not-exit:0 -e file:stderr.txt \
106
	    truncate -s8388608t output.txt
106
	    ${TRUNC} -s8388608t output.txt
107
	[ ! -e output.txt ] || atf_fail "output.txt should not exist"
107
	[ ! -e output.txt ] || atf_fail "output.txt should not exist"
108
}
108
}
109
109
Lines 115-124 Link Here
115
opt_c_body()
115
opt_c_body()
116
{
116
{
117
	# No new files and truncate returns 0 as if this is a success.
117
	# No new files and truncate returns 0 as if this is a success.
118
	atf_check truncate -c -s 0 doesnotexist.txt
118
	atf_check ${TRUNC} -c -s 0 doesnotexist.txt
119
	[ ! -e output.txt ] || atf_fail "doesnotexist.txt should not exist"
119
	[ ! -e output.txt ] || atf_fail "doesnotexist.txt should not exist"
120
	> reference
120
	> reference
121
	atf_check truncate -c -r reference doesnotexist.txt
121
	atf_check ${TRUNC} -c -r reference doesnotexist.txt
122
	[ ! -e output.txt ] || atf_fail "doesnotexist.txt should not exist"
122
	[ ! -e output.txt ] || atf_fail "doesnotexist.txt should not exist"
123
123
124
	create_stderr_file
124
	create_stderr_file
Lines 125-131 Link Here
125
125
126
	# The existing file will be altered by truncate.
126
	# The existing file will be altered by truncate.
127
	> exists.txt
127
	> exists.txt
128
	atf_check -e file:stderr.txt truncate -c -s1 exists.txt
128
	atf_check -e file:stderr.txt ${TRUNC} -c -s1 exists.txt
129
	[ -s exists.txt ] || atf_fail "exists.txt be larger than zero bytes"
129
	[ -s exists.txt ] || atf_fail "exists.txt be larger than zero bytes"
130
}
130
}
131
131
Lines 141-147 Link Here
141
141
142
	# Force an error due to the use of both -s and -r.
142
	# Force an error due to the use of both -s and -r.
143
	> afile
143
	> afile
144
	atf_check -s not-exit:0 -e file:stderr.txt truncate -s0 -r afile afile
144
	atf_check -s not-exit:0 -e file:stderr.txt ${TRUNC} -s0 -r afile afile
145
}
145
}
146
146
147
atf_test_case no_files
147
atf_test_case no_files
Lines 155-161 Link Here
155
	create_stderr_usage_file
155
	create_stderr_usage_file
156
156
157
	# A list of files must be present on the command line.
157
	# A list of files must be present on the command line.
158
	atf_check -s not-exit:0 -e file:stderr.txt truncate -s1
158
	atf_check -s not-exit:0 -e file:stderr.txt ${TRUNC} -s1
159
}
159
}
160
160
161
atf_test_case bad_refer
161
atf_test_case bad_refer
Lines 169-175 Link Here
169
	create_stderr_file "truncate: afile: No such file or directory"
169
	create_stderr_file "truncate: afile: No such file or directory"
170
170
171
	# The reference file must exist before you try to use it.
171
	# The reference file must exist before you try to use it.
172
	atf_check -s not-exit:0 -e file:stderr.txt truncate -r afile afile
172
	atf_check -s not-exit:0 -e file:stderr.txt ${TRUNC} -r afile afile
173
	[ ! -e afile ] || atf_fail "afile should not exist"
173
	[ ! -e afile ] || atf_fail "afile should not exist"
174
}
174
}
175
175
Lines 185-193 Link Here
185
185
186
	# Trying to get the ftruncate() call to return -1.
186
	# Trying to get the ftruncate() call to return -1.
187
	> exists.txt
187
	> exists.txt
188
	atf_check chflags uimmutable exists.txt
188
	chflags schg exists.txt || atf_skip "expected immutable flag support"
189
189
190
	atf_check -s not-exit:0 -e file:stderr.txt truncate -s1 exists.txt
190
	atf_check -s not-exit:0 -e file:stderr.txt ${TRUNC} -s1 exists.txt
191
}
191
}
192
bad_truncate_cleanup()
192
bad_truncate_cleanup()
193
{
193
{
Lines 204-210 Link Here
204
	create_stderr_file
204
	create_stderr_file
205
205
206
	# Create a new file and grow it to 1024 bytes.
206
	# Create a new file and grow it to 1024 bytes.
207
	atf_check -s exit:0 -e file:stderr.txt truncate -s1k output.txt
207
	atf_check -s exit:0 -e file:stderr.txt ${TRUNC} -s1k output.txt
208
	atf_check -s exit:1 cmp -s output.txt /dev/zero
208
	atf_check -s exit:1 cmp -s output.txt /dev/zero
209
	eval $(stat -s output.txt)
209
	eval $(stat -s output.txt)
210
	[ ${st_size} -eq 1024 ] || atf_fail "expected file size of 1k"
210
	[ ${st_size} -eq 1024 ] || atf_fail "expected file size of 1k"
Lines 212-218 Link Here
212
	create_stderr_file
212
	create_stderr_file
213
213
214
	# Grow the existing file to 1M.  We are using absolute sizes.
214
	# Grow the existing file to 1M.  We are using absolute sizes.
215
	atf_check -s exit:0 -e file:stderr.txt truncate -c -s1M output.txt
215
	atf_check -s exit:0 -e file:stderr.txt ${TRUNC} -c -s1M output.txt
216
	atf_check -s exit:1 cmp -s output.txt /dev/zero
216
	atf_check -s exit:1 cmp -s output.txt /dev/zero
217
	eval $(stat -s output.txt)
217
	eval $(stat -s output.txt)
218
	[ ${st_size} -eq 1048576 ] || atf_fail "expected file size of 1m"
218
	[ ${st_size} -eq 1048576 ] || atf_fail "expected file size of 1m"
Lines 229-235 Link Here
229
	create_stderr_file
229
	create_stderr_file
230
230
231
	# Create a new file and grow it to 1048576 bytes.
231
	# Create a new file and grow it to 1048576 bytes.
232
	atf_check -s exit:0 -e file:stderr.txt truncate -s1M output.txt
232
	atf_check -s exit:0 -e file:stderr.txt ${TRUNC} -s1M output.txt
233
	atf_check -s exit:1 cmp -s output.txt /dev/zero
233
	atf_check -s exit:1 cmp -s output.txt /dev/zero
234
	eval $(stat -s output.txt)
234
	eval $(stat -s output.txt)
235
	[ ${st_size} -eq 1048576 ] || atf_fail "expected file size of 1m"
235
	[ ${st_size} -eq 1048576 ] || atf_fail "expected file size of 1m"
Lines 237-243 Link Here
237
	create_stderr_file
237
	create_stderr_file
238
238
239
	# Shrink the existing file to 1k.  We are using absolute sizes.
239
	# Shrink the existing file to 1k.  We are using absolute sizes.
240
	atf_check -s exit:0 -e file:stderr.txt truncate -s1k output.txt
240
	atf_check -s exit:0 -e file:stderr.txt ${TRUNC} -s1k output.txt
241
	atf_check -s exit:1 cmp -s output.txt /dev/zero
241
	atf_check -s exit:1 cmp -s output.txt /dev/zero
242
	eval $(stat -s output.txt)
242
	eval $(stat -s output.txt)
243
	[ ${st_size} -eq 1024 ] || atf_fail "expected file size of 1k"
243
	[ ${st_size} -eq 1024 ] || atf_fail "expected file size of 1k"
Lines 254-260 Link Here
254
	create_stderr_file
254
	create_stderr_file
255
255
256
	# Create a new file and grow it to 1024 bytes.
256
	# Create a new file and grow it to 1024 bytes.
257
	atf_check -s exit:0 -e file:stderr.txt truncate -s+1k output.txt
257
	atf_check -s exit:0 -e file:stderr.txt ${TRUNC} -s+1k output.txt
258
	atf_check -s exit:1 cmp -s output.txt /dev/zero
258
	atf_check -s exit:1 cmp -s output.txt /dev/zero
259
	eval $(stat -s output.txt)
259
	eval $(stat -s output.txt)
260
	[ ${st_size} -eq 1024 ] || atf_fail "expected file size of 1k"
260
	[ ${st_size} -eq 1024 ] || atf_fail "expected file size of 1k"
Lines 262-268 Link Here
262
	create_stderr_file
262
	create_stderr_file
263
263
264
	# Grow the existing file to 1M.  We are using relative sizes.
264
	# Grow the existing file to 1M.  We are using relative sizes.
265
	atf_check -s exit:0 -e file:stderr.txt truncate -s+1047552 output.txt
265
	atf_check -s exit:0 -e file:stderr.txt ${TRUNC} -s+1047552 output.txt
266
	atf_check -s exit:1 cmp -s output.txt /dev/zero
266
	atf_check -s exit:1 cmp -s output.txt /dev/zero
267
	eval $(stat -s output.txt)
267
	eval $(stat -s output.txt)
268
	[ ${st_size} -eq 1048576 ] || atf_fail "expected file size of 1m"
268
	[ ${st_size} -eq 1048576 ] || atf_fail "expected file size of 1m"
Lines 279-285 Link Here
279
	create_stderr_file
279
	create_stderr_file
280
280
281
	# Create a new file and grow it to 1049600 bytes.
281
	# Create a new file and grow it to 1049600 bytes.
282
	atf_check -s exit:0 -e file:stderr.txt truncate -s+1049600 output.txt
282
	atf_check -s exit:0 -e file:stderr.txt ${TRUNC} -s+1049600 output.txt
283
	atf_check -s exit:1 cmp -s output.txt /dev/zero
283
	atf_check -s exit:1 cmp -s output.txt /dev/zero
284
	eval $(stat -s output.txt)
284
	eval $(stat -s output.txt)
285
	[ ${st_size} -eq 1049600 ] || atf_fail "expected file size of 1m"
285
	[ ${st_size} -eq 1049600 ] || atf_fail "expected file size of 1m"
Lines 287-293 Link Here
287
	create_stderr_file
287
	create_stderr_file
288
288
289
	# Shrink the existing file to 1k.  We are using relative sizes.
289
	# Shrink the existing file to 1k.  We are using relative sizes.
290
	atf_check -s exit:0 -e file:stderr.txt truncate -s-1M output.txt
290
	atf_check -s exit:0 -e file:stderr.txt ${TRUNC} -s-1M output.txt
291
	atf_check -s exit:1 cmp -s output.txt /dev/zero
291
	atf_check -s exit:1 cmp -s output.txt /dev/zero
292
	eval $(stat -s output.txt)
292
	eval $(stat -s output.txt)
293
	[ ${st_size} -eq 1024 ] || atf_fail "expected file size of 1k"
293
	[ ${st_size} -eq 1024 ] || atf_fail "expected file size of 1k"
Lines 312-318 Link Here
312
312
313
	# Create a new file and grow it to 1024 bytes.
313
	# Create a new file and grow it to 1024 bytes.
314
	atf_check -s not-exit:0 -e file:stderr.txt \
314
	atf_check -s not-exit:0 -e file:stderr.txt \
315
	truncate -c -s1k before 0000 after
315
	${TRUNC} -c -s1k before 0000 after
316
	eval $(stat -s before)
316
	eval $(stat -s before)
317
	[ ${st_size} -eq 1024 ] || atf_fail "expected file size of 1k"
317
	[ ${st_size} -eq 1024 ] || atf_fail "expected file size of 1k"
318
	eval $(stat -s after)
318
	eval $(stat -s after)
Lines 336-342 Link Here
336
	create_stderr_file
336
	create_stderr_file
337
337
338
	# Create a new file and grow it to 4 bytes.
338
	# Create a new file and grow it to 4 bytes.
339
	atf_check -e file:stderr.txt truncate -r reference afile
339
	atf_check -e file:stderr.txt ${TRUNC} -r reference afile
340
	eval $(stat -s afile)
340
	eval $(stat -s afile)
341
	[ ${st_size} -eq 4 ] || atf_fail "new file should also be 4 bytes"
341
	[ ${st_size} -eq 4 ] || atf_fail "new file should also be 4 bytes"
342
}
342
}
Lines 351-362 Link Here
351
	create_stderr_file
351
	create_stderr_file
352
352
353
	# Create a new file and grow it to zero bytes.
353
	# Create a new file and grow it to zero bytes.
354
	atf_check -s exit:0 -e file:stderr.txt truncate -s0 output.txt
354
	atf_check -s exit:0 -e file:stderr.txt ${TRUNC} -s0 output.txt
355
	eval $(stat -s output.txt)
355
	eval $(stat -s output.txt)
356
	[ ${st_size} -eq 0 ] || atf_fail "expected file size of zero"
356
	[ ${st_size} -eq 0 ] || atf_fail "expected file size of zero"
357
357
358
	# Pretend to grow the file.
358
	# Pretend to grow the file.
359
	atf_check -s exit:0 -e file:stderr.txt truncate -s+0 output.txt
359
	atf_check -s exit:0 -e file:stderr.txt ${TRUNC} -s+0 output.txt
360
	eval $(stat -s output.txt)
360
	eval $(stat -s output.txt)
361
	[ ${st_size} -eq 0 ] || atf_fail "expected file size of zero"
361
	[ ${st_size} -eq 0 ] || atf_fail "expected file size of zero"
362
}
362
}
Lines 376-402 Link Here
376
	create_stderr_file
376
	create_stderr_file
377
377
378
	# Create a new file and do a 100 byte negative relative shrink.
378
	# Create a new file and do a 100 byte negative relative shrink.
379
	atf_check -e file:stderr.txt truncate -s-100 afile
379
	atf_check -e file:stderr.txt ${TRUNC} -s-100 afile
380
	eval $(stat -s afile)
380
	eval $(stat -s afile)
381
	[ ${st_size} -eq 0 ] || atf_fail "new file should now be zero bytes"
381
	[ ${st_size} -eq 0 ] || atf_fail "new file should now be zero bytes"
382
}
382
}
383
384
atf_init_test_cases()
385
{
386
	atf_add_test_case illegal_option
387
	atf_add_test_case illegal_size
388
	atf_add_test_case too_large_size
389
	atf_add_test_case opt_c
390
	atf_add_test_case opt_rs
391
	atf_add_test_case no_files
392
	atf_add_test_case bad_refer
393
	atf_add_test_case bad_truncate
394
	atf_add_test_case cannot_open
395
	atf_add_test_case new_absolute_grow
396
	atf_add_test_case new_absolute_shrink
397
	atf_add_test_case new_relative_grow
398
	atf_add_test_case new_relative_shrink
399
	atf_add_test_case reference
400
	atf_add_test_case new_zero
401
	atf_add_test_case negative
402
}
(-)tests/sparse_test.c (+198 lines)
Line 0 Link Here
1
/*-
2
 * Copyright 2014, Google Inc. All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions
6
 * are met:
7
 *
8
 *  * Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 *  * Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *  * Neither the name of Google nor the names of its contributors may
14
 *    be used to endorse or promote products derived from this software
15
 *    without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
 * POSSIBILITY OF SUCH DAMAGE.
28
 */
29
30
#include <sys/cdefs.h>
31
__FBSDID("$FreeBSD$");
32
33
#include <sys/types.h>
34
#include <sys/wait.h>
35
36
#include <assert.h>
37
#include <errno.h>
38
#include <fcntl.h>
39
#include <spawn.h>
40
#include <unistd.h>
41
42
#include <atf-c.h>
43
44
/* Create child process and block for successful termination. */
45
void
46
run_truncate(const char *const *argv)
47
{
48
	int status;
49
	pid_t child;
50
	extern char **environ;
51
52
	ATF_REQUIRE(posix_spawnp(&child, argv[0], NULL, NULL,
53
	    (char *const *)argv, environ) == 0);
54
	ATF_REQUIRE(waitpid(child, &status, 0) == child);
55
	ATF_REQUIRE(WIFEXITED(status));
56
	ATF_REQUIRE(WEXITSTATUS(status) == 0);
57
}
58
59
/* Return the number of bytes used for holes or data in this file. */
60
off_t
61
get_size(const char *path, int whence)
62
{
63
	int fd, opposite;
64
	off_t hstart, hend, total;
65
66
	assert(whence == SEEK_HOLE || whence == SEEK_DATA);
67
68
	/* We expect the file to exist and to have SEEK_HOLE support. */
69
	ATF_REQUIRE((fd = open(path, O_RDONLY)) != -1);
70
	if (fpathconf(fd, _PC_MIN_HOLE_SIZE) <= 0)
71
		atf_tc_skip("Require _PC_MIN_HOLE_SIZE support.");
72
73
	hstart = hend = total = 0;
74
	opposite = (whence == SEEK_DATA) ? SEEK_HOLE : SEEK_DATA;
75
	for (;;) {
76
		if ((hstart = lseek(fd, hend, whence)) == -1) {
77
			ATF_REQUIRE(errno == ENXIO);
78
			break;
79
		}
80
		if ((hend = lseek(fd, hstart, opposite)) == -1) {
81
			ATF_REQUIRE(errno == ENXIO);
82
			ATF_REQUIRE((hend = lseek(fd, 0, SEEK_END)) != -1);
83
		}
84
		total += hend - hstart;
85
	}
86
87
	ATF_REQUIRE(close(fd) == 0);
88
	return (total);
89
}
90
91
/* Return the number of bytes used for holes in this sparse file. */
92
off_t
93
get_hole_size(const char *path)
94
{
95
96
	return (get_size(path, SEEK_HOLE));
97
}
98
99
/* Return the number of bytes actually allocated in this file. */
100
off_t
101
get_allocated_size(const char *path)
102
{
103
104
	return (get_size(path, SEEK_DATA));
105
}
106
107
ATF_TC_WITHOUT_HEAD(default_absolute_file_is_sparse);
108
ATF_TC_BODY(default_absolute_file_is_sparse, tc)
109
{
110
	off_t hole, data, expected;
111
	const char *filename = "afile";
112
	const char *const cmd[] = { "truncate", "-s", "5m", filename, NULL };
113
114
	run_truncate(cmd);
115
116
	expected = 5242880;
117
	hole = get_hole_size(filename);
118
	data = get_allocated_size(filename);
119
120
	if (hole + data != expected)
121
		atf_tc_fail("Expected size of %jd, but got %jd + %jd.",
122
		    expected, hole, data);
123
	else if (hole <= 0)
124
		atf_tc_fail("Expected a sparse file, but got %jd of data.",
125
		    data);
126
}
127
128
ATF_TC_WITHOUT_HEAD(default_relative_file_is_sparse);
129
ATF_TC_BODY(default_relative_file_is_sparse, tc)
130
{
131
	off_t hole, data, expected;
132
	const char *const before[] = { "truncate", "-s", "1", "afile", NULL };
133
	const char *const after[] = { "truncate", "-cs", "+5242879", "afile",
134
	    NULL };
135
136
	run_truncate(before);
137
	run_truncate(after);
138
139
	expected = 5242880;
140
	hole = get_hole_size(before[3]);
141
	data = get_allocated_size(before[3]);
142
143
	if (hole + data != expected)
144
		atf_tc_fail("Expected size of %jd, but got %jd + %jd.",
145
		    expected, hole, data);
146
	else if (hole <= 0)
147
		atf_tc_fail("Expected a sparse file, but got %jd of data.",
148
		    data);
149
}
150
151
ATF_TC_WITHOUT_HEAD(allocate_absolute_file);
152
ATF_TC_BODY(allocate_absolute_file, tc)
153
{
154
	off_t hole, data, expected;
155
	const char *filename = "afile";
156
	const char *const cmd[] = { "truncate", "-as", "5m", filename, NULL };
157
158
	run_truncate(cmd);
159
160
	expected = 5242880;
161
	hole = get_hole_size(filename);
162
	data = get_allocated_size(filename);
163
164
	if (hole != 0 || data != expected)
165
		atf_tc_fail("Expected size of %jd, but got %jd + %jd.",
166
		    expected, hole, data);
167
}
168
169
ATF_TC_WITHOUT_HEAD(allocate_relative_file);
170
ATF_TC_BODY(allocate_relative_file, tc)
171
{
172
	off_t hole, data, expected;
173
	const char *filename = "afile";
174
	const char *const before[] = { "truncate", "-s1m", filename, NULL };
175
	const char *const after[] = { "truncate", "-acs+4m", filename, NULL };
176
177
	run_truncate(before);
178
	run_truncate(after);
179
180
	expected = 5242880;
181
	hole = get_hole_size(filename);
182
	data = get_allocated_size(filename);
183
184
	if (hole + data != expected)
185
		atf_tc_fail("Expected size of %jd, but got %jd + %jd.",
186
		    expected, hole, data);
187
	else if (hole <= 0 || data < 4194304)
188
		atf_tc_fail("got hole=%jd and data=%jd.", hole, data);
189
}
190
191
ATF_TP_ADD_TCS(tp)
192
{
193
	ATF_TP_ADD_TC(tp, default_absolute_file_is_sparse);
194
	ATF_TP_ADD_TC(tp, default_relative_file_is_sparse);
195
	ATF_TP_ADD_TC(tp, allocate_absolute_file);
196
	ATF_TP_ADD_TC(tp, allocate_relative_file);
197
	return atf_no_error();
198
}
(-)tests/truncate_test.func (+21 lines)
Line 0 Link Here
1
atf_init_test_cases()
2
{
3
	TRUNC="truncate"
4
5
	atf_add_test_case illegal_option
6
	atf_add_test_case illegal_size
7
	atf_add_test_case too_large_size
8
	atf_add_test_case opt_c
9
	atf_add_test_case opt_rs
10
	atf_add_test_case no_files
11
	atf_add_test_case bad_refer
12
	atf_add_test_case bad_truncate
13
	atf_add_test_case cannot_open
14
	atf_add_test_case new_absolute_grow
15
	atf_add_test_case new_absolute_shrink
16
	atf_add_test_case new_relative_grow
17
	atf_add_test_case new_relative_shrink
18
	atf_add_test_case reference
19
	atf_add_test_case new_zero
20
	atf_add_test_case negative
21
}
(-)truncate.1 (-11 / +30 lines)
Lines 33-38 Link Here
33
.Nd truncate or extend the length of files
33
.Nd truncate or extend the length of files
34
.Sh SYNOPSIS
34
.Sh SYNOPSIS
35
.Nm
35
.Nm
36
.Op Fl a
36
.Op Fl c
37
.Op Fl c
37
.Bk -words
38
.Bk -words
38
.Fl s Xo
39
.Fl s Xo
Lines 39-50 Link Here
39
.Sm off
40
.Sm off
40
.Op Cm + | -
41
.Op Cm + | -
41
.Ar size
42
.Ar size
42
.Op Cm K | k | M | m | G | g | T | t
43
.Op Cm K | k | M | m | G | g | T | t | P | p | E | e
43
.Sm on
44
.Sm on
44
.Xc
45
.Xc
45
.Ek
46
.Ek
46
.Ar
47
.Ar
47
.Nm
48
.Nm
49
.Op Fl a
48
.Op Fl c
50
.Op Fl c
49
.Bk -words
51
.Bk -words
50
.Fl r Ar rfile
52
.Fl r Ar rfile
Lines 57-62 Link Here
57
.Pp
59
.Pp
58
The following options are available:
60
The following options are available:
59
.Bl -tag -width indent
61
.Bl -tag -width indent
62
.It Fl a
63
When increasing the size of a file,
64
allocate the required disk storage instead of using a
65
.Qq hole.
60
.It Fl c
66
.It Fl c
61
Do not create files if they do not exist.
67
Do not create files if they do not exist.
62
The
68
The
Lines 71-77 Link Here
71
.Sm off
77
.Sm off
72
.Op Cm + | -
78
.Op Cm + | -
73
.Ar size
79
.Ar size
74
.Op Cm K | k | M | m | G | g | T | t
80
.Op Cm K | k | M | m | G | g | T | t | P | p | E | e
75
.Sm on
81
.Sm on
76
.Xc
82
.Xc
77
If the
83
If the
Lines 119-131 Link Here
119
.Pp
125
.Pp
120
Note that,
126
Note that,
121
while truncating a file causes space on disk to be freed,
127
while truncating a file causes space on disk to be freed,
122
extending a file does not cause space to be allocated.
128
extending a file does not cause space to be allocated on disk.
123
To extend a file and actually allocate the space,
129
To extend a file and actually allocate the disk space,
124
it is necessary to explicitly write data to it,
130
it is necessary to to specify the
125
using (for example) the shell's
131
.Fl a
126
.Ql >>
132
option.
127
redirection syntax, or
128
.Xr dd 1 .
129
.Sh EXIT STATUS
133
.Sh EXIT STATUS
130
.Ex -std
134
.Ex -std
131
If the operation fails for an argument,
135
If the operation fails for an argument,
Lines 132-140 Link Here
132
.Nm
136
.Nm
133
will issue a diagnostic
137
will issue a diagnostic
134
and continue processing the remaining arguments.
138
and continue processing the remaining arguments.
139
.Sh EXAMPLES
140
The following commands:
141
.Dl rm -f rz35.dsk
142
.Dl truncate -s 852m rz35.dsk
143
creates a sparse file that can be used as an emulated disk image.
144
Future writes to the sparse file could fail to the a lack of free space
145
on the base file system storage.
146
.Pp
147
The following commands:
148
.Dl rm -f rz28.dsk
149
.Dl truncate -a -s 2100m rz28.dsk
150
creates a file that can be used as an emulated disk image.
151
The required disk space should have been reserved on the storage media.
152
We do not expect future writes to fail due to lack of free space on the
153
base file system storage.
135
.Sh SEE ALSO
154
.Sh SEE ALSO
136
.Xr dd 1 ,
155
.Xr lseek 2 ,
137
.Xr touch 1 ,
156
.Xr posix_fallocate 2 ,
138
.Xr truncate 2
157
.Xr truncate 2
139
.Sh STANDARDS
158
.Sh STANDARDS
140
The
159
The
(-)truncate.c (-13 / +24 lines)
Lines 45-50 Link Here
45
static void	usage(void);
45
static void	usage(void);
46
46
47
static int	no_create;
47
static int	no_create;
48
static int	do_allocate;
48
static int	do_relative;
49
static int	do_relative;
49
static int	do_refer;
50
static int	do_refer;
50
static int	got_size;
51
static int	got_size;
Lines 63-70 Link Here
63
	rsize = tsize = sz = 0;
64
	rsize = tsize = sz = 0;
64
	error = 0;
65
	error = 0;
65
	rname = NULL;
66
	rname = NULL;
66
	while ((ch = getopt(argc, argv, "cr:s:")) != -1)
67
	while ((ch = getopt(argc, argv, "acr:s:")) != -1)
67
		switch (ch) {
68
		switch (ch) {
69
		case 'a':
70
			do_allocate = 1;
71
			break;
68
		case 'c':
72
		case 'c':
69
			no_create = 1;
73
			no_create = 1;
70
			break;
74
			break;
Lines 122-133 Link Here
122
			}
126
			}
123
			continue;
127
			continue;
124
		}
128
		}
129
		if (fstat(fd, &sb) == -1) {
130
			warn("%s", fname);
131
			error++;
132
			continue;
133
		}
125
		if (do_relative) {
134
		if (do_relative) {
126
			if (fstat(fd, &sb) == -1) {
127
				warn("%s", fname);
128
				error++;
129
				continue;
130
			}
131
			oflow = sb.st_size + rsize;
135
			oflow = sb.st_size + rsize;
132
			if (oflow < (sb.st_size + rsize)) {
136
			if (oflow < (sb.st_size + rsize)) {
133
				errno = EFBIG;
137
				errno = EFBIG;
Lines 135-146 Link Here
135
				error++;
139
				error++;
136
				continue;
140
				continue;
137
			}
141
			}
138
			tsize = oflow;
142
			tsize = oflow < 0 ? 0 : oflow;
143
		} else {
144
			rsize = tsize - sb.st_size;
139
		}
145
		}
140
		if (tsize < 0)
141
			tsize = 0;
142
146
143
		if (ftruncate(fd, tsize) == -1) {
147
		/*
148
		 * Use posix_fallocate() when we need to grow the file with
149
		 * the required on-disk storage.  In all other cases, use
150
		 * ftruncate().
151
		 */
152
		if (((do_allocate && rsize > 0) ?
153
		    posix_fallocate(fd, sb.st_size, rsize) :
154
		    ftruncate(fd, tsize)) == -1) {
144
			warn("%s", fname);
155
			warn("%s", fname);
145
			error++;
156
			error++;
146
			continue;
157
			continue;
Lines 155-162 Link Here
155
static void
166
static void
156
usage(void)
167
usage(void)
157
{
168
{
158
	fprintf(stderr, "%s\n%s\n",
169
	fprintf(stderr, "usage: %s\n       %s\n",
159
	    "usage: truncate [-c] -s [+|-]size[K|k|M|m|G|g|T|t] file ...",
170
	    "truncate [-ac] -s [+|-]size[K|k|M|m|G|g|T|t|P|p|E|e] file ...",
160
	    "       truncate [-c] -r rfile file ...");
171
	    "truncate [-ac] -r rfile file ...");
161
	exit(EXIT_FAILURE);
172
	exit(EXIT_FAILURE);
162
}
173
}

Return to bug 196273