GNU file utilities
[gnulib.git] / lib / ftruncate.c
1 /* ftruncate emulations that work on some System V's.
2    This file is in the public domain. */
3
4 #ifdef HAVE_CONFIG_H
5 #if defined (CONFIG_BROKETS)
6 /* We use <config.h> instead of "config.h" so that a compilation
7    using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
8    (which it would do because it found this file in $srcdir).  */
9 #include <config.h>
10 #else
11 #include "config.h"
12 #endif
13 #endif
14
15 #include <sys/types.h>
16 #include <fcntl.h>
17
18 #ifdef F_CHSIZE
19 int
20 ftruncate (fd, length)
21      int fd;
22      off_t length;
23 {
24   return fcntl (fd, F_CHSIZE, length);
25 }
26 #else
27 #ifdef F_FREESP
28 /* The following function was written by
29    kucharsk@Solbourne.com (William Kucharski) */
30
31 #include <sys/stat.h>
32 #include <errno.h>
33 #include <unistd.h>
34
35 int
36 ftruncate (fd, length)
37      int fd;
38      off_t length;
39 {
40   struct flock fl;
41   struct stat filebuf;
42
43   if (fstat (fd, &filebuf) < 0)
44     return -1;
45
46   if (filebuf.st_size < length)
47     {
48       /* Extend file length. */
49       if (lseek (fd, (length - 1), SEEK_SET) < 0)
50         return -1;
51
52       /* Write a "0" byte. */
53       if (write (fd, "", 1) != 1)
54         return -1;
55     }
56   else
57     {
58       /* Truncate length. */
59       fl.l_whence = 0;
60       fl.l_len = 0;
61       fl.l_start = length;
62       fl.l_type = F_WRLCK;      /* Write lock on file space. */
63
64       /* This relies on the UNDOCUMENTED F_FREESP argument to
65          fcntl, which truncates the file so that it ends at the
66          position indicated by fl.l_start.
67          Will minor miracles never cease? */
68       if (fcntl (fd, F_FREESP, &fl) < 0)
69         return -1;
70     }
71
72   return 0;
73 }
74 #else
75 int
76 ftruncate (fd, length)
77      int fd;
78      off_t length;
79 {
80   return chsize (fd, length);
81 }
82 #endif
83 #endif