bug-coreutils
[Top][All Lists]
Advanced

[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





reply via email to

[Prev in Thread] Current Thread [Next in Thread]