aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKa Ho Ng <khng@FreeBSD.org>2021-08-19 10:30:41 +0000
committerKa Ho Ng <khng@FreeBSD.org>2021-08-19 10:30:41 +0000
commit5ee2c35751ef5d131222423bf3e25073f997c337 (patch)
treee0a48371ceaea5d0bb34f137e6484ecc71ce4118
parent78267c2e703c236d37692da77a4ee92da9502943 (diff)
downloadsrc-5ee2c35751ef5d131222423bf3e25073f997c337.tar.gz
src-5ee2c35751ef5d131222423bf3e25073f997c337.zip
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
-rw-r--r--usr.bin/truncate/truncate.163
-rw-r--r--usr.bin/truncate/truncate.c79
2 files changed, 115 insertions, 27 deletions
diff --git a/usr.bin/truncate/truncate.1 b/usr.bin/truncate/truncate.1
index 2058530162c5..54780ccbca83 100644
--- a/usr.bin/truncate/truncate.1
+++ b/usr.bin/truncate/truncate.1
@@ -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 .
diff --git a/usr.bin/truncate/truncate.c b/usr.bin/truncate/truncate.c
index a7579227f299..529d2c7e6dab 100644
--- a/usr.bin/truncate/truncate.c
+++ b/usr.bin/truncate/truncate.c
@@ -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);
}