summaryrefslogtreecommitdiff
path: root/gold/ftruncate.c
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@airs.com>2009-03-17 22:25:30 +0000
committerIan Lance Taylor <ian@airs.com>2009-03-17 22:25:30 +0000
commit335eda146d54b3a34aff78ffd0cfba9c5df64ec8 (patch)
tree6beb1ca8d039c537c43f5163297d5d88d10800ae /gold/ftruncate.c
parent03c00b5bae458ee2859cffd51c32261c3b1a7106 (diff)
downloadbinutils-redhat-335eda146d54b3a34aff78ffd0cfba9c5df64ec8.tar.gz
* configure.ac: Check for chsize and posix_fallocate. Replace
ftruncate. * ftruncate.c: New file, from gnulib. * output.cc (posix_fallocate): Define dummy version if not HAVE_POSIX_FALLOCATE. (Output_file::map): Call posix_fallocate rather than lseek and write. * gold.h (ftruncate): Declare if not HAVE_FTRUNCATE. * configure, Makefile.in, config.in: Rebuild.
Diffstat (limited to 'gold/ftruncate.c')
-rw-r--r--gold/ftruncate.c90
1 files changed, 90 insertions, 0 deletions
diff --git a/gold/ftruncate.c b/gold/ftruncate.c
new file mode 100644
index 0000000000..ff7d11b090
--- /dev/null
+++ b/gold/ftruncate.c
@@ -0,0 +1,90 @@
+/* ftruncate emulations that work on some System V's.
+ This file is in the public domain. */
+
+#include <config.h>
+
+/* Specification. */
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <fcntl.h>
+
+#ifdef F_CHSIZE
+
+int
+ftruncate (int fd, off_t length)
+{
+ return fcntl (fd, F_CHSIZE, length);
+}
+
+#else /* not F_CHSIZE */
+# ifdef F_FREESP
+
+/* By William Kucharski <kucharsk@netcom.com>. */
+
+# include <sys/stat.h>
+# include <errno.h>
+
+int
+ftruncate (int fd, off_t length)
+{
+ struct flock fl;
+ struct stat filebuf;
+
+ if (fstat (fd, &filebuf) < 0)
+ return -1;
+
+ if (filebuf.st_size < length)
+ {
+ /* Extend file length. */
+ if (lseek (fd, (length - 1), SEEK_SET) < 0)
+ return -1;
+
+ /* Write a "0" byte. */
+ if (write (fd, "", 1) != 1)
+ return -1;
+ }
+ else
+ {
+
+ /* Truncate length. */
+
+ fl.l_whence = 0;
+ fl.l_len = 0;
+ fl.l_start = length;
+ fl.l_type = F_WRLCK; /* write lock on file space */
+
+ /* This relies on the *undocumented* F_FREESP argument to fcntl,
+ which truncates the file so that it ends at the position
+ indicated by fl.l_start. Will minor miracles never cease? */
+
+ if (fcntl (fd, F_FREESP, &fl) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+# else /* not F_CHSIZE nor F_FREESP */
+# if HAVE_CHSIZE /* native Windows, e.g. mingw */
+
+int
+ftruncate (int fd, off_t length)
+{
+ return chsize (fd, length);
+}
+
+# else /* not F_CHSIZE nor F_FREESP nor HAVE_CHSIZE */
+
+# include <errno.h>
+
+int
+ftruncate (int fd, off_t length)
+{
+ errno = EIO;
+ return -1;
+}
+
+# endif /* not HAVE_CHSIZE */
+# endif /* not F_FREESP */
+#endif /* not F_CHSIZE */