[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] mkfile -- create large files efficiently
From: |
Matej Cepl |
Subject: |
[PATCH] mkfile -- create large files efficiently |
Date: |
Fri, 6 Feb 2009 18:01:08 +0100 |
src/mkfile.c: new file
src/.gitignore: add mkfile to ignored files
src/Makefile.am: add building of mkfile
README-prereq: fix small typos
doc/coreutils.texi: texinfo @node on mkfile added
man/mkfile.x: footer for mkfile(1)
tests/mkfile/01-mkfile-normal: test for creating of normal file
tests/mkfile/02-mkfile-sparse: test for creating of sparse file
tests/mkfile/03-mkfile-wrong-behavior: tests for incorrect use
Signed-off-by: Matej Cepl <address@hidden>
---
README-prereq | 6 +-
doc/coreutils.texi | 50 ++++++-
man/mkfile.x | 6 +
src/.gitignore | 1 +
src/Makefile.am | 4 +-
src/mkfile.c | 263 +++++++++++++++++++++++++++++++++
tests/mkfile/01-mkfile-normal | 38 +++++
tests/mkfile/02-mkfile-sparse | 41 +++++
tests/mkfile/03-mkfile-wrong-behavior | 36 +++++
9 files changed, 440 insertions(+), 5 deletions(-)
create mode 100644 man/mkfile.x
create mode 100644 src/mkfile.c
create mode 100644 tests/mkfile/01-mkfile-normal
create mode 100644 tests/mkfile/02-mkfile-sparse
create mode 100644 tests/mkfile/03-mkfile-wrong-behavior
diff --git a/README-prereq b/README-prereq
index 91676f4..e48c1c0 100644
--- a/README-prereq
+++ b/README-prereq
@@ -24,8 +24,10 @@ getting the prerequisites for particular systems.
just to coreutils:
# yum install help2man #required to build automake fully
$ git clone git://git.sv.gnu.org/automake.git
- $ cd automake && ./configure --prefix=$HOME/coreutils/deps
+ $ cd automake
+ $ ./bootstrap
+ $ ./configure --prefix=$(readlink -f ../deps)
$ make install
Now we can build coreutils as described in README-hacking
- as long as $PATH starts with $HOME/coreutils/deps
+ as long as $PATH starts with .../coreutils/deps/bin
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index c3a1164..06c3feb 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -79,6 +79,7 @@
* md5sum: (coreutils)md5sum invocation. Print or check MD5 digests.
* mkdir: (coreutils)mkdir invocation. Create directories.
* mkfifo: (coreutils)mkfifo invocation. Create FIFOs (named pipes).
+* mkfile: (coreutils)mkfile invocation. Create large files efficiently.
* mknod: (coreutils)mknod invocation. Create special files.
* mv: (coreutils)mv invocation. Rename files.
* nice: (coreutils)nice invocation. Modify niceness.
@@ -185,7 +186,7 @@ Free Documentation License''.
* Operating on fields within a line:: cut paste join
* Operating on characters:: tr expand unexpand
* Directory listing:: ls dir vdir dircolors
-* Basic operations:: cp dd install mv rm shred
+* Basic operations:: cp dd install mv rm shred mkfile
* Special file types:: ln mkdir rmdir mkfifo mknod
* Changing file attributes:: chgrp chmod chown touch
* Disk usage:: df du stat sync truncate
@@ -313,6 +314,7 @@ Basic operations
* mv invocation:: Move (rename) files
* rm invocation:: Remove files or directories
* shred invocation:: Remove files more securely
+* mkfile invocation:: Create large files efficinetly
Special file types
@@ -7166,6 +7168,7 @@ copying, moving (renaming), and deleting (removing).
* mv invocation:: Move (rename) files.
* rm invocation:: Remove files or directories.
* shred invocation:: Remove files more securely.
+* mkfile invocation:: Create large files efficientl.
@end menu
@@ -8554,8 +8557,51 @@ Bourne-compatible shell) the command @samp{shred -
1<>file} instead.
@exitstatus
address@hidden mkfile invocation
address@hidden @command{mkfile}: Create large file efficiently
address@hidden Special file types
address@hidden mkfile
address@hidden data, creating, swap
address@hidden creating files
+
address@hidden creates files of specified size. Synopsis:
+
address@hidden
+mkfile @address@hidden @var{size} @var{file}
address@hidden example
+
address@hidden of the size @var{size} is created, existing one is
+overwritten.
+
address@hidden sparse files, creating
address@hidden holes, creating files with
+
+The program accepts the following options. Also see @ref{Common options}.
+
address@hidden @samp
+
address@hidden -n
address@hidden --sparse-file
address@hidden -n
address@hidden --sparse-file
+Create sparse file
+
address@hidden -v
address@hidden --verbose
address@hidden -v
address@hidden --verbose
+Be more verbose, report the size of the file created (including
+number of blocks occupied).
+
address@hidden may also be followed by one of the @command{dd} BLOCK
+size suffixes and lowercase g,t,m for BSD compatibility. Note we
+don't support dd's b=512, c=1, w=2 or 21x512MiB formats.
+
address@hidden table
+
address@hidden
+
address@hidden Special file types, Changing file attributes, Basic operations,
Top
@chapter Special file types
@cindex special file types
diff --git a/man/mkfile.x b/man/mkfile.x
new file mode 100644
index 0000000..ae3c10f
--- /dev/null
+++ b/man/mkfile.x
@@ -0,0 +1,6 @@
+[NAME]
+mkfile \- make files efficiently (e.g., for swap files)
+[DESCRIPTION]
+.\" Add any additional description here
+[SEE ALSO]
+touch(1), posix_fallocate(3), lseek(3)
diff --git a/src/.gitignore b/src/.gitignore
index bc14523..78cf1ae 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -49,6 +49,7 @@ ls
md5sum
mkdir
mkfifo
+mkfile
mknod
mktemp
mv
diff --git a/src/Makefile.am b/src/Makefile.am
index b88db6b..3273e70 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -33,7 +33,7 @@ EXTRA_PROGRAMS = \
$(build_if_possible__progs) \
[ chcon chgrp chown chmod cp dd dircolors du \
ginstall link ln dir vdir ls mkdir \
- mkfifo mknod mktemp \
+ mkfifo mknod mktemp mkfile \
mv nohup readlink rm rmdir shred stat sync touch unlink \
cat cksum comm csplit cut expand fmt fold head join groups md5sum \
nl od paste pr ptx sha1sum sha224sum sha256sum sha384sum sha512sum \
@@ -89,6 +89,7 @@ ptx_LDADD = $(LDADD)
split_LDADD = $(LDADD)
timeout_LDADD = $(LDADD)
truncate_LDADD = $(LDADD)
+mkfile_LDADD = $(LDADD)
# for eaccess in lib/euidaccess.c.
chcon_LDADD = $(LDADD) $(LIB_SELINUX)
@@ -168,6 +169,7 @@ ptx_LDADD += $(LIBICONV)
split_LDADD += $(LIBICONV)
timeout_LDADD += $(LIBICONV)
truncate_LDADD += $(LIBICONV)
+mkfile_LDADD += $(LIBICONV)
# programs that use getaddrinfo (e.g., via canon_host)
pinky_LDADD = $(LDADD) $(GETADDRINFO_LIB)
diff --git a/src/mkfile.c b/src/mkfile.c
new file mode 100644
index 0000000..1b63732
--- /dev/null
+++ b/src/mkfile.c
@@ -0,0 +1,263 @@
+/* mkfile -- create a file of given size using fallocate
+ Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+ Written by MatÄj Cepl <address@hidden>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+ This is backwards compatible with the FreeBSD utility
+ (http://www.infolab.ne.jp/~hatanou/freebsd/mkfile/), but is more
+ flexible wrt the size specifications and the use of long options,
+ to better fit the GNU environment.
+
+*/
+
+#include <config.h>
+#include "system.h"
+#include <getopt.h>
+#include <error.h>
+#include <sys/vfs.h>
+#include <libgen.h>
+#include "xstrtol.h"
+
+/* The official name of this program (e.g., no `g' prefix). */
+#define PROGRAM_NAME "mkfile"
+
+#define AUTHORS proper_name_utf8 ("Matej Cepl", "MatÄj Cepl")
+
+/* (-v) Flag set by `--verbose'. */
+static bool verbose_flag;
+
+/* (-n) Flag set by `--null'. */
+static bool null_file_flag;
+
+/* size of block on the current file system */
+static unsigned long write_size;
+
+/*Â name of the file to be created */
+static char *file_name;
+
+void
+usage (int status)
+{
+ if (status != EXIT_SUCCESS)
+ fprintf (stderr, _("Try `%s --help' for more information.\n"),
+ program_name);
+ else
+ {
+ printf (_("Usage: %s OPTION... SIZE FILE\n"), program_name);
+ fputs (_("\
+Create a file named FILE that is suitable for example for swap areas.\n\
+\n\
+"), stdout);
+ fputs (_("\
+ -n, --sparse-file create sparse file\n\
+"), stdout);
+ fputs (_("\
+ -v, --verbose to be more verbose\n\
+"), stdout);
+ fputs (HELP_OPTION_DESCRIPTION, stdout);
+ fputs (VERSION_OPTION_DESCRIPTION, stdout);
+ fputs (_("\n\
+SIZE is a number which may be followed by dd BLOCK size suffixes\n\
+and lowercase g,t,m for BSD compatibility.\n\
+Note we don't support dd's b=512, c=1, w=2 or 21x512MiB formats.\n\
+"), stdout);
+ emit_bug_reporting_address ();
+ }
+ exit (status);
+}
+
+/**
+ * Parse the length string.
+ *
+ * @param str string with the input value
+ * @param size *off_t pointer where the value in bytes will be
+ * set
+ * @return errorlevel
+ *
+ * This supports dd BLOCK size suffixes + lowercase g,t,m for bsd
+ * compat Note we don't support dd's b=512, c=1, w=2 or 21x512MiB
+ * formats.
+ */
+static int
+parse_len (char const *str, off_t * size)
+{
+ enum strtol_error e;
+ uintmax_t tmp_size;
+ e = xstrtoumax (str, NULL, 10, &tmp_size, "EgGkKmMPtTYZ0");
+ if (e == LONGINT_OK && !(0 <= tmp_size && tmp_size <= UINTMAX_MAX))
+ e = LONGINT_OVERFLOW;
+
+ if (e == LONGINT_OK)
+ {
+ errno = 0;
+ *size = (off_t) tmp_size;
+ return 0;
+ }
+
+ errno = (e == LONGINT_OVERFLOW ? EOVERFLOW : 0);
+ return -1;
+}
+
+/**
+ * Create the file number of blocks long.
+ *
+ * @param filename string with filename
+ * @param count long for number of blocks the file should be long
+ * @param sparse int to decide whether sparse file should be created
+ * @return integer handler of the file just created, or
+ * EXIT_FAILURE if file was not created.
+ * The file is padded with zeros by default.
+ */
+static int
+create_file (char *filename, off_t real_size, bool sparse)
+{
+ off_t newPos;
+ char buf[1];
+ int err, ret = -1;
+
+ int f = creat (filename, S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR | S_IWGRP);
+ if (f == -1)
+ {
+ error (0, errno, _("cannot create the file"));
+ goto abort;
+ }
+
+ if (sparse)
+ {
+ newPos = lseek (f, real_size-sizeof(buf), SEEK_SET);
+ if (newPos == -1)
+ {
+ error (0, errno, _("lseek failed"));
+ goto abort;
+ }
+ err = write (f, buf, sizeof(buf));
+ if (err == -1)
+ {
+ error (0, errno, _("writing to the end of the file failed"));
+ goto abort;
+ }
+ }
+ else
+ {
+ err = posix_fallocate (f, 0, write_size);
+ if (err != 0)
+ {
+ error (0, errno, _("setting file to the correct size of file
failed"));
+ goto abort;
+ }
+ }
+ ret = 0;
+abort:
+ if (f >= 0)
+ err = close (f);
+ if (err != 0)
+ {
+ error (0, errno, _("closing the file failed"));
+ ret = -1;
+ }
+ return ret;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int c, fd;
+ int err, new_file;
+ char *size_str, *dir_name;
+ off_t block_size;
+
+ static struct option const long_options[] = {
+ /* These options set a flag. */
+ {"verbose", no_argument, NULL, 'v'},
+ {"null", no_argument, NULL, 'n'},
+ {GETOPT_HELP_OPTION_DECL},
+ {GETOPT_VERSION_OPTION_DECL},
+ {NULL, 0, NULL, 0}
+ };
+
+ /*Â gettext initialization */
+ initialize_main (&argc, &argv);
+ set_program_name (argv[0]);
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+
+ atexit (close_stdout);
+
+ while ((c = getopt_long (argc, argv, "vnh", long_options, NULL)) != -1)
+ {
+ switch (c)
+ {
+ case 0:
+ break;
+ case 'v':
+ verbose_flag = true;
+ break;
+ case 'n':
+ null_file_flag = true;
+ break;
+ case_GETOPT_HELP_CHAR;
+
+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
+
+ default:
+ fprintf (stderr, _("Value of c is %d\n"), c);
+ usage (EXIT_FAILURE);
+ }
+ }
+
+ /* Get a size of the file to be created */
+ size_str = argv[optind++];
+
+ /* Get a file name to be created. */
+ if (optind == argc)
+ {
+ fprintf (stderr, _("Not enough parameters -- %d\n"), argc);
+ usage (EXIT_FAILURE);
+ }
+
+ file_name = argv[optind++];
+ if (!file_name || !*file_name)
+ error (EXIT_FAILURE, 0, _("no filename set"));
+
+ if (optind < argc)
+ error (EXIT_FAILURE, 0, _("there are too many parameters"));
+
+ err = parse_len (size_str, &write_size);
+ if (err != EXIT_SUCCESS)
+ error (EXIT_FAILURE, 0, _("cannot get requested size of the file"));
+
+ new_file = create_file (file_name, write_size, null_file_flag);
+ if (new_file != 0)
+ {
+ unlink (file_name);
+ /* no need to check errorlevel of unlink, when we end with
+ * EXIT_FAILURE anyway ;-)
+ */
+ exit (EXIT_FAILURE);
+ }
+ else
+ {
+ if (verbose_flag)
+ {
+ struct stat stat_buf;
+ err = stat (file_name, &stat_buf);
+ fprintf (stderr, _("Writen %" PRIdMAX " bytes (file size %" PRIdMAX
").\n"),
+ stat_buf.st_blocks * 512, stat_buf.st_size);
+ }
+ exit (EXIT_SUCCESS);
+ }
+}
diff --git a/tests/mkfile/01-mkfile-normal b/tests/mkfile/01-mkfile-normal
new file mode 100644
index 0000000..c9111b3
--- /dev/null
+++ b/tests/mkfile/01-mkfile-normal
@@ -0,0 +1,38 @@
+#!/bin/sh
+# mkfile -- test creation of normal (i.e., non-sparse) file.
+
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+# Written by MatÄj Cepl <address@hidden>
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+export LANG=C
+TEST_FILE=testfile
+FILE_SIZE=200k
+
+if test "$VERBOSE" = yes; then
+ set -x
+ mkfile --version
+fi
+
+. ../../tests/test-lib.sh
+
+trap EXIT rm -f $TEST_FILE
+
+fail=0
+mkfile $FILE_SIZE $TEST_FILE || fail=1
+size=$(/usr/bin/stat --format="%s" $TEST_FILE)
+[ "$(($size - 204800))" -gt 1024 ] && fail=1
+
+Exit $fail
diff --git a/tests/mkfile/02-mkfile-sparse b/tests/mkfile/02-mkfile-sparse
new file mode 100644
index 0000000..ad55412
--- /dev/null
+++ b/tests/mkfile/02-mkfile-sparse
@@ -0,0 +1,41 @@
+#!/bin/sh
+# mkfile -- test creation of sparse file.
+
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+# Written by MatÄj Cepl <address@hidden>
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+export LANG=C
+TEST_FILE=testfile
+FILE_SIZE=100k
+
+if test "$VERBOSE" = yes; then
+ set -x
+ mkfile --version
+fi
+
+. ../../tests/test-lib.sh
+
+trap EXIT rm -f $TEST_FILE
+
+fail=0
+mkfile -n $FILE_SIZE $TEST_FILE || fail=1
+size=$(/usr/bin/stat --format="%s" $TEST_FILE)
+[ "$(($size - 102400))" -gt 1024 ] && fail=1
+
+blocks=$(/usr/bin/stat --format="%b" $TEST_FILE)
+[ "$blocks" -gt 100 ]Â && fail=1
+
+Exit $fail
diff --git a/tests/mkfile/03-mkfile-wrong-behavior
b/tests/mkfile/03-mkfile-wrong-behavior
new file mode 100644
index 0000000..076e067
--- /dev/null
+++ b/tests/mkfile/03-mkfile-wrong-behavior
@@ -0,0 +1,36 @@
+#!/bin/sh
+# mkfile -- test creation of sparse file.
+
+# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+# Written by MatÄj Cepl <address@hidden>
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+export LANG=C
+TEST_FILE=testfile
+FILE_SIZE=100k
+
+if test "$VERBOSE" = yes; then
+ set -x
+ mkfile --version
+fi
+
+. ../../tests/test-lib.sh
+
+trap EXIT rm -f $TEST_FILE
+
+fail=0
+mkfile -n $FILE_SIZE || fail=1
+
+Exit $fail
--
1.6.0.6
- mkfile -- create large files efficiently, Matej Cepl, 2009/02/06
- [PATCH] mkfile -- create large files efficiently,
Matej Cepl <=
- Re: mkfile -- create large files efficiently, Pádraig Brady, 2009/02/06
- Re: mkfile -- create large files efficiently, Matej Cepl, 2009/02/07
- Re: mkfile -- create large files efficiently, Pádraig Brady, 2009/02/07
- Re: mkfile -- create large files efficiently, Matej Cepl, 2009/02/08
- Re: mkfile -- create large files efficiently, Pádraig Brady, 2009/02/08
- Re: mkfile -- create large files efficiently, Jim Meyering, 2009/02/09
- [PATCH] Trying to finalize loose ends of truncate.c fallocate, Matej Cepl, 2009/02/27
- Re: [PATCH] Trying to finalize loose ends of truncate.c fallocate, Eric Blake, 2009/02/27
- Re: [PATCH] Trying to finalize loose ends of truncate.c fallocate, Pádraig Brady, 2009/02/27
- Re: [PATCH] Trying to finalize loose ends of truncate.c fallocate, Matej Cepl, 2009/02/27