truncate(1): Add hole-punching support
This commit adds hole-punching support to the truncate(1) utility. If the option -d is specified, truncate(1) performs zeroing, and if possible hole-punching in case the operation is supported by the underlying file system of the specified files. Sponsored by: The FreeBSD Foundation Reviewed by: kib Differential Revision: https://reviews.freebsd.org/D31556
This commit is contained in:
parent
78267c2e70
commit
5ee2c35751
@ -1,6 +1,10 @@
|
||||
.\"
|
||||
.\" Copyright (c) 2000 Sheldon Hearn <sheldonh@FreeBSD.org>.
|
||||
.\" All rights reserved.
|
||||
.\" Copyright (c) 2021 The FreeBSD Foundation
|
||||
.\"
|
||||
.\" Portions of this manual page were written by Ka Ho Ng <khng@FreeBSD.org>
|
||||
.\" under sponsorship from the FreeBSD Foundation.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
@ -25,12 +29,12 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 27, 2020
|
||||
.Dd August 18, 2021
|
||||
.Dt TRUNCATE 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm truncate
|
||||
.Nd truncate or extend the length of files
|
||||
.Nd truncate, extend the length of files, or perform space management in files
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl c
|
||||
@ -39,7 +43,7 @@
|
||||
.Sm off
|
||||
.Op Cm + | - | % | /
|
||||
.Ar size
|
||||
.Op Cm K | k | M | m | G | g | T | t
|
||||
.Op Cm SUFFIX
|
||||
.Sm on
|
||||
.Xc
|
||||
.Ek
|
||||
@ -50,10 +54,32 @@
|
||||
.Fl r Ar rfile
|
||||
.Ek
|
||||
.Ar
|
||||
.Nm
|
||||
.Op Fl c
|
||||
.Bk -words
|
||||
.Fl d
|
||||
.Oo
|
||||
.Fl o Xo
|
||||
.Sm off
|
||||
.Ar offset
|
||||
.Op Cm SUFFIX
|
||||
.Sm on
|
||||
.Xc
|
||||
.Oc
|
||||
.Fl l Xo
|
||||
.Sm off
|
||||
.Ar length
|
||||
.Op Cm SUFFIX
|
||||
.Sm on
|
||||
.Xc
|
||||
.Ek
|
||||
.Ar
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
utility adjusts the length of each regular file given on the command-line.
|
||||
utility adjusts the length of each regular file given on the command-line, or
|
||||
performs space management with the given offset and the length over a regular
|
||||
file given on the command-line.
|
||||
.Pp
|
||||
The following options are available:
|
||||
.Bl -tag -width indent
|
||||
@ -71,7 +97,7 @@ Truncate or extend files to the length of the file
|
||||
.Sm off
|
||||
.Op Cm + | - | % | /
|
||||
.Ar size
|
||||
.Op Cm K | k | M | m | G | g | T | t
|
||||
.Op Cm SUFFIX
|
||||
.Sm on
|
||||
.Xc
|
||||
If the
|
||||
@ -100,10 +126,28 @@ Otherwise, the
|
||||
.Ar size
|
||||
argument specifies an absolute length to which all files
|
||||
should be extended or reduced as appropriate.
|
||||
.It Fl d
|
||||
Zero a region in the specified file.
|
||||
If the underlying file system of the given file supports hole-punching,
|
||||
file system space deallocation may be performed in the operation region.
|
||||
.It Fl o Ar offset
|
||||
The space management operation is performed at the given
|
||||
.Ar offset
|
||||
bytes in the file.
|
||||
If this option is not specified, the operation is performed at the beginning of the file.
|
||||
.It Fl l Ar length
|
||||
The length of the operation range in bytes.
|
||||
This option must always be specified if option
|
||||
.Fl d
|
||||
is specified, and must be greater than 0.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Ar size
|
||||
argument may be suffixed with one of
|
||||
.Ar size ,
|
||||
.Ar offset
|
||||
and
|
||||
.Ar length
|
||||
arguments may be suffixed with one of
|
||||
.Cm K ,
|
||||
.Cm M ,
|
||||
.Cm G
|
||||
@ -112,7 +156,6 @@ or
|
||||
(either upper or lower case) to indicate a multiple of
|
||||
Kilobytes, Megabytes, Gigabytes or Terabytes
|
||||
respectively.
|
||||
.El
|
||||
.Pp
|
||||
Exactly one of the
|
||||
.Fl r
|
||||
@ -183,6 +226,7 @@ ls -l test_file*
|
||||
.Sh SEE ALSO
|
||||
.Xr dd 1 ,
|
||||
.Xr touch 1 ,
|
||||
.Xr fspacectl 2 ,
|
||||
.Xr truncate 2
|
||||
.Sh STANDARDS
|
||||
The
|
||||
@ -198,3 +242,6 @@ The
|
||||
.Nm
|
||||
utility was written by
|
||||
.An Sheldon Hearn Aq Mt sheldonh@starjuice.net .
|
||||
Hole-punching support of this
|
||||
utility was developed by
|
||||
.An Ka Ho Ng Aq Mt khng@FreeBSD.org .
|
||||
|
@ -4,6 +4,11 @@
|
||||
* Copyright (c) 2000 Sheldon Hearn <sheldonh@FreeBSD.org>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Copyright (c) 2021 The FreeBSD Foundation
|
||||
*
|
||||
* Portions of this software were developed by Ka Ho Ng <khng@FreeBSD.org>
|
||||
* under sponsorship from the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
@ -49,26 +54,36 @@ main(int argc, char **argv)
|
||||
{
|
||||
struct stat sb;
|
||||
mode_t omode;
|
||||
off_t oflow, rsize, sz, tsize, round;
|
||||
off_t oflow, rsize, sz, tsize, round, off, len;
|
||||
uint64_t usz;
|
||||
int ch, error, fd, oflags;
|
||||
int ch, error, fd, oflags, r;
|
||||
int do_dealloc;
|
||||
int do_truncate;
|
||||
int no_create;
|
||||
int do_relative;
|
||||
int do_round;
|
||||
int do_refer;
|
||||
int got_size;
|
||||
char *fname, *rname;
|
||||
struct spacectl_range sr;
|
||||
|
||||
fd = -1;
|
||||
rsize = tsize = sz = 0;
|
||||
no_create = do_relative = do_round = do_refer = got_size = 0;
|
||||
error = 0;
|
||||
rsize = tsize = sz = off = 0;
|
||||
len = -1;
|
||||
do_dealloc = no_create = do_relative = do_round = do_refer =
|
||||
got_size = 0;
|
||||
do_truncate = 1;
|
||||
error = r = 0;
|
||||
rname = NULL;
|
||||
while ((ch = getopt(argc, argv, "cr:s:")) != -1)
|
||||
while ((ch = getopt(argc, argv, "cdr:s:o:l:")) != -1)
|
||||
switch (ch) {
|
||||
case 'c':
|
||||
no_create = 1;
|
||||
break;
|
||||
case 'd':
|
||||
do_dealloc = 1;
|
||||
do_truncate = 0;
|
||||
break;
|
||||
case 'r':
|
||||
do_refer = 1;
|
||||
rname = optarg;
|
||||
@ -89,6 +104,22 @@ main(int argc, char **argv)
|
||||
-(off_t)usz : (off_t)usz;
|
||||
got_size = 1;
|
||||
break;
|
||||
case 'o':
|
||||
if (expand_number(optarg, &usz) == -1 ||
|
||||
(off_t)usz < 0)
|
||||
errx(EXIT_FAILURE,
|
||||
"invalid offset argument `%s'", optarg);
|
||||
|
||||
off = usz;
|
||||
break;
|
||||
case 'l':
|
||||
if (expand_number(optarg, &usz) == -1 ||
|
||||
(off_t)usz <= 0)
|
||||
errx(EXIT_FAILURE,
|
||||
"invalid length argument `%s'", optarg);
|
||||
|
||||
len = usz;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
@ -98,19 +129,22 @@ main(int argc, char **argv)
|
||||
argc -= optind;
|
||||
|
||||
/*
|
||||
* Exactly one of do_refer or got_size must be specified. Since
|
||||
* do_relative implies got_size, do_relative and do_refer are
|
||||
* also mutually exclusive. See usage() for allowed invocations.
|
||||
* Exactly one of do_refer, got_size or do_dealloc must be specified.
|
||||
* Since do_relative implies got_size, do_relative, do_refer and
|
||||
* do_dealloc are also mutually exclusive. If do_dealloc is specified,
|
||||
* the length argument must be set. See usage() for allowed
|
||||
* invocations.
|
||||
*/
|
||||
if (do_refer + got_size != 1 || argc < 1)
|
||||
if (argc < 1 || do_refer + got_size + do_dealloc != 1 ||
|
||||
(do_dealloc == 1 && len == -1))
|
||||
usage();
|
||||
if (do_refer) {
|
||||
if (do_refer == 1) {
|
||||
if (stat(rname, &sb) == -1)
|
||||
err(EXIT_FAILURE, "%s", rname);
|
||||
tsize = sb.st_size;
|
||||
} else if (do_relative || do_round)
|
||||
} else if (do_relative == 1 || do_round == 1)
|
||||
rsize = sz;
|
||||
else
|
||||
else if (do_dealloc == 0)
|
||||
tsize = sz;
|
||||
|
||||
if (no_create)
|
||||
@ -129,7 +163,7 @@ main(int argc, char **argv)
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (do_relative) {
|
||||
if (do_relative == 1) {
|
||||
if (fstat(fd, &sb) == -1) {
|
||||
warn("%s", fname);
|
||||
error++;
|
||||
@ -144,7 +178,7 @@ main(int argc, char **argv)
|
||||
}
|
||||
tsize = oflow;
|
||||
}
|
||||
if (do_round) {
|
||||
if (do_round == 1) {
|
||||
if (fstat(fd, &sb) == -1) {
|
||||
warn("%s", fname);
|
||||
error++;
|
||||
@ -166,10 +200,16 @@ main(int argc, char **argv)
|
||||
if (tsize < 0)
|
||||
tsize = 0;
|
||||
|
||||
if (ftruncate(fd, tsize) == -1) {
|
||||
if (do_dealloc == 1) {
|
||||
sr.r_offset = off;
|
||||
sr.r_len = len;
|
||||
r = fspacectl(fd, SPACECTL_DEALLOC, &sr, 0, &sr);
|
||||
}
|
||||
if (do_truncate == 1)
|
||||
r = ftruncate(fd, tsize);
|
||||
if (r == -1) {
|
||||
warn("%s", fname);
|
||||
error++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (fd != -1)
|
||||
@ -181,8 +221,9 @@ main(int argc, char **argv)
|
||||
static void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, "%s\n%s\n",
|
||||
fprintf(stderr, "%s\n%s\n%s\n",
|
||||
"usage: truncate [-c] -s [+|-|%|/]size[K|k|M|m|G|g|T|t] file ...",
|
||||
" truncate [-c] -r rfile file ...");
|
||||
" truncate [-c] -r rfile file ...",
|
||||
" truncate [-c] -d [-o offset[K|k|M|m|G|g|T|t]] -l length[K|k|M|m|G|g|T|t] file ...");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user