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 <[email protected]> --- 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 +...@node mkfile invocation +...@section @command{mkfile}: Create large file efficiently -...@node Special file types +...@pindex mkfile +...@cindex data, creating, swap +...@cindex creating files + +...@command{mkfile} creates files of specified size. Synopsis: + +...@example +mkfile @var{opti...@dots{} @var{size} @var{file} +...@end example + +...@var{file} of the size @var{size} is created, existing one is +overwritten. + +...@cindex sparse files, creating +...@cindex holes, creating files with + +The program accepts the following options. Also see @ref{Common options}. + +...@table @samp + +...@item -n +...@itemx --sparse-file +...@opindex -n +...@opindex --sparse-file +Create sparse file + +...@item -v +...@itemx --verbose +...@opindex -v +...@opindex --verbose +Be more verbose, report the size of the file created (including +number of blocks occupied). + +...@var{size} 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. + +...@end table + +...@exitstatus + +...@node 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 <[email protected]> + + 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 <[email protected]> + +# 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 <[email protected]> + +# 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 <[email protected]> + +# 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 _______________________________________________ Bug-coreutils mailing list [email protected] http://lists.gnu.org/mailman/listinfo/bug-coreutils
