truncate: Add support for -s % and /

% round up to the multiple size and / round down
This is compatible with gnu truncate.
Add tests and document in the man page.
This commit is contained in:
Emmanuel Vadot 2018-07-09 19:03:30 +00:00
parent dde27dbc9b
commit 1017327049
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=336140
3 changed files with 110 additions and 9 deletions

View file

@ -57,7 +57,7 @@ create_stderr_usage_file()
_custom_create_file creat _custom_create_file creat
_custom_create_file print "${1}" _custom_create_file print "${1}"
_custom_create_file print \ _custom_create_file print \
"usage: truncate [-c] -s [+|-]size[K|k|M|m|G|g|T|t] file ..." "usage: truncate [-c] -s [+|-|%|/]size[K|k|M|m|G|g|T|t] file ..."
_custom_create_file print " truncate [-c] -r rfile file ..." _custom_create_file print " truncate [-c] -r rfile file ..."
} }
@ -378,6 +378,66 @@ negative_body()
[ ${st_size} -eq 0 ] || atf_fail "new file should now be zero bytes" [ ${st_size} -eq 0 ] || atf_fail "new file should now be zero bytes"
} }
atf_test_case roundup
roundup_head()
{
atf_set "descr" "Verifies truncate round up"
}
roundup_body()
{
# Create a 5 byte file.
printf "abcd\n" > afile
eval $(stat -s afile)
[ ${st_size} -eq 5 ] || atf_fail "afile file should be 5 bytes"
create_stderr_file
# Create a new file and do a 100 byte roundup.
atf_check -e file:stderr.txt truncate -s%100 afile
eval $(stat -s afile)
[ ${st_size} -eq 100 ] || atf_fail "new file should now be 100 bytes"
}
atf_test_case rounddown
rounddown_head()
{
atf_set "descr" "Verifies truncate round down"
}
rounddown_body()
{
# Create a 5 byte file.
printf "abcd\n" > afile
eval $(stat -s afile)
[ ${st_size} -eq 5 ] || atf_fail "afile file should be 5 bytes"
create_stderr_file
# Create a new file and do a 2 byte roundup.
atf_check -e file:stderr.txt truncate -s/2 afile
eval $(stat -s afile)
[ ${st_size} -eq 4 ] || atf_fail "new file should now be 4 bytes"
}
atf_test_case rounddown_zero
rounddown_zero_head()
{
atf_set "descr" "Verifies truncate round down to zero"
}
rounddown_zero_body()
{
# Create a 5 byte file.
printf "abcd\n" > afile
eval $(stat -s afile)
[ ${st_size} -eq 5 ] || atf_fail "afile file should be 5 bytes"
create_stderr_file
# Create a new file and do a 10 byte roundup.
atf_check -e file:stderr.txt truncate -s/10 afile
eval $(stat -s afile)
[ ${st_size} -eq 0 ] || atf_fail "new file should now be 0 bytes"
}
atf_init_test_cases() atf_init_test_cases()
{ {
atf_add_test_case illegal_option atf_add_test_case illegal_option
@ -396,4 +456,7 @@ atf_init_test_cases()
atf_add_test_case reference atf_add_test_case reference
atf_add_test_case new_zero atf_add_test_case new_zero
atf_add_test_case negative atf_add_test_case negative
atf_add_test_case roundup
atf_add_test_case rounddown
atf_add_test_case rounddown_zero
} }

View file

@ -37,7 +37,7 @@
.Bk -words .Bk -words
.Fl s Xo .Fl s Xo
.Sm off .Sm off
.Op Cm + | - .Op Cm + | - | % | /
.Ar size .Ar size
.Op Cm K | k | M | m | G | g | T | t .Op Cm K | k | M | m | G | g | T | t
.Sm on .Sm on
@ -69,7 +69,7 @@ Truncate or extend files to the length of the file
.Ar rfile . .Ar rfile .
.It Fl s Xo .It Fl s Xo
.Sm off .Sm off
.Op Cm + | - .Op Cm + | - | % | /
.Ar size .Ar size
.Op Cm K | k | M | m | G | g | T | t .Op Cm K | k | M | m | G | g | T | t
.Sm on .Sm on
@ -85,6 +85,17 @@ argument is preceded by a dash
.Pq Cm - , .Pq Cm - ,
file lengths will be reduced by no more than this number of bytes, file lengths will be reduced by no more than this number of bytes,
to a minimum length of zero bytes. to a minimum length of zero bytes.
If the
.Ar size
argument is preceded by a percent sign
.Pq Cm % ,
files will be round up to a multiple of this number of bytes.
If the
.Ar size
argument is preceded by a slash sign
.Pq Cm / ,
files will be round down to a multiple of this number of bytes,
to a minimum length of zero bytes.
Otherwise, the Otherwise, the
.Ar size .Ar size
argument specifies an absolute length to which all files argument specifies an absolute length to which all files

View file

@ -56,13 +56,15 @@ main(int argc, char **argv)
int ch, error, fd, oflags; int ch, error, fd, oflags;
int no_create; int no_create;
int do_relative; int do_relative;
int do_round;
int do_refer; int do_refer;
int got_size; int got_size;
int round;
char *fname, *rname; char *fname, *rname;
fd = -1; fd = -1;
rsize = tsize = sz = 0; rsize = tsize = sz = 0;
no_create = do_relative = do_refer = got_size = 0; no_create = do_relative = do_round = do_refer = got_size = 0;
error = 0; error = 0;
rname = NULL; rname = NULL;
while ((ch = getopt(argc, argv, "cr:s:")) != -1) while ((ch = getopt(argc, argv, "cr:s:")) != -1)
@ -75,13 +77,19 @@ main(int argc, char **argv)
rname = optarg; rname = optarg;
break; break;
case 's': case 's':
do_relative = *optarg == '+' || *optarg == '-'; if (*optarg == '+' || *optarg == '-') {
if (expand_number(do_relative ? optarg + 1 : optarg, do_relative = 1;
} else if (*optarg == '%' || *optarg == '/') {
do_round = 1;
}
if (expand_number(do_relative || do_round ?
optarg + 1 : optarg,
&usz) == -1 || (off_t)usz < 0) &usz) == -1 || (off_t)usz < 0)
errx(EXIT_FAILURE, errx(EXIT_FAILURE,
"invalid size argument `%s'", optarg); "invalid size argument `%s'", optarg);
sz = (*optarg == '-') ? -(off_t)usz : (off_t)usz; sz = (*optarg == '-' || *optarg == '/') ?
-(off_t)usz : (off_t)usz;
got_size = 1; got_size = 1;
break; break;
default: default:
@ -103,7 +111,7 @@ main(int argc, char **argv)
if (stat(rname, &sb) == -1) if (stat(rname, &sb) == -1)
err(EXIT_FAILURE, "%s", rname); err(EXIT_FAILURE, "%s", rname);
tsize = sb.st_size; tsize = sb.st_size;
} else if (do_relative) } else if (do_relative || do_round)
rsize = sz; rsize = sz;
else else
tsize = sz; tsize = sz;
@ -139,6 +147,25 @@ main(int argc, char **argv)
} }
tsize = oflow; tsize = oflow;
} }
if (do_round) {
if (fstat(fd, &sb) == -1) {
warn("%s", fname);
error++;
continue;
}
sz = rsize;
if (sz < 0)
sz = -sz;
if (sb.st_size % sz) {
round = sb.st_size / sz;
if (round != sz && rsize < 0)
round--;
else if (rsize > 0)
round++;
tsize = (round < 0 ? 0 : round) * sz;
} else
tsize = sb.st_size;
}
if (tsize < 0) if (tsize < 0)
tsize = 0; tsize = 0;
@ -158,7 +185,7 @@ static void
usage(void) usage(void)
{ {
fprintf(stderr, "%s\n%s\n", fprintf(stderr, "%s\n%s\n",
"usage: truncate [-c] -s [+|-]size[K|k|M|m|G|g|T|t] file ...", "usage: truncate [-c] -s [+|-|%|/]size[K|k|M|m|G|g|T|t] file ...",
" truncate [-c] -r rfile file ..."); " truncate [-c] -r rfile file ...");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }