summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@linux.intel.com>2016-02-18 14:24:40 -0800
committerH. Peter Anvin <hpa@linux.intel.com>2016-02-18 14:24:40 -0800
commite65e81b172ceed17621c0f0ca4392a531018071e (patch)
treee019ca547c7a00e9cbd3917960f0064d7030c2e4
parent28ec7d1ddfbf3f1d01a03c772132ba1b9fa08d50 (diff)
downloadnasm-e65e81b172ceed17621c0f0ca4392a531018071e.tar.gz
nasmlib: allow writing of sparse files
On systems that support it, allow the writing of sparse files. This can be useful for some file formats (like binary, or ELF if the alignments are very large) that can contain large amounts of zeroes. This is not inherently portable code, so condition it on certain known systems. Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
-rw-r--r--configure.in8
-rw-r--r--nasmlib.c29
-rw-r--r--nasmlib.h8
3 files changed, 43 insertions, 2 deletions
diff --git a/configure.in b/configure.in
index e762777f..98e151ca 100644
--- a/configure.in
+++ b/configure.in
@@ -111,6 +111,9 @@ AC_CHECK_HEADERS(strings.h)
dnl Look for <stdbool.h>
AC_HEADER_STDBOOL
+dnl Look for <io.h>
+AC_CHECK_HEADERS(io.h)
+
dnl Look for <unistd.h>
AC_CHECK_HEADERS(unistd.h)
@@ -135,6 +138,11 @@ AC_CHECK_FUNCS(canonicalize_file_name)
AC_CHECK_FUNCS(_fullpath)
AC_CHECK_FUNCS(pathconf)
+AC_TYPE_OFF_T
+AC_FUNC_FSEEKO
+AC_CHECK_FUNCS([ftruncate _chsize _chsize_s])
+AC_CHECK_FUNCS([fileno])
+
PA_HAVE_FUNC(__builtin_ctz, (0U))
PA_HAVE_FUNC(__builtin_ctzl, (0UL))
PA_HAVE_FUNC(__builtin_ctzll, (0ULL))
diff --git a/nasmlib.c b/nasmlib.c
index 49f1e470..eb0217d1 100644
--- a/nasmlib.c
+++ b/nasmlib.c
@@ -165,7 +165,7 @@ no_return nasm_assert_failed(const char *file, int line, const char *msg)
void nasm_write(const void *ptr, size_t size, FILE *f)
{
size_t n = fwrite(ptr, 1, size, f);
- if (n != size)
+ if (n != size || ferror(f) || feof(f))
nasm_error(ERR_FATAL, "unable to write output: %s", strerror(errno));
}
@@ -459,10 +459,37 @@ void fwriteaddr(uint64_t data, int size, FILE * fp)
#endif
+#ifndef HAVE_FSEEKO
+# define fseeko fseek
+# define ftello ftell
+#endif
+
+#ifdef HAVE_FILENO /* Useless without fileno() */
+# ifdef HAVE__CHSIZE_S
+# define nasm_ftruncate(fd,size) _chsize_s(fd,size)
+# elif defined(HAVE__CHSIZE)
+# define nasm_ftruncate(fd,size) _chsize(fd,size)
+# elif defined(HAVE_FTRUNCATE)
+# define nasm_ftruncate(fd,size) ftruncate(fd,size)
+# endif
+#endif
+
void fwritezero(size_t bytes, FILE *fp)
{
size_t blksize;
+#ifdef nasm_ftruncate
+ if (bytes >= BUFSIZ && !ferror(fp) && !feof(fp)) {
+ off_t pos = ftello(fp);
+ if (pos >= 0) {
+ if (!fflush(fp) &&
+ !nasm_ftruncate(fileno(fp), pos + bytes) &&
+ !fseeko(fp, pos+bytes, SEEK_SET))
+ return;
+ }
+ }
+#endif
+
while (bytes) {
blksize = (bytes < ZERO_BUF_SIZE) ? bytes : ZERO_BUF_SIZE;
diff --git a/nasmlib.h b/nasmlib.h
index 96c488a4..534324db 100644
--- a/nasmlib.h
+++ b/nasmlib.h
@@ -44,7 +44,13 @@
#include <stdio.h>
#include <string.h>
#ifdef HAVE_STRINGS_H
-#include <strings.h>
+# include <strings.h>
+#endif
+#ifdef HAVE_IO_H
+# include <io.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
#endif
/*