.
[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
20 int
21 ftruncate (fd, length)
22      int fd;
23      off_t length;
24 {
25   return fcntl (fd, F_CHSIZE, length);
26 }
27
28 #else /* not F_CHSIZE */
29 #ifdef F_FREESP
30
31 /* By William Kucharski <kucharsk@netcom.com>.  */
32
33 #include <sys/stat.h>
34 #include <errno.h>
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38
39 int
40 ftruncate (fd, length)
41      int fd;
42      off_t length;
43 {
44   struct flock fl;
45   struct stat filebuf;
46
47   if (fstat (fd, &filebuf) < 0)
48     return -1;
49
50   if (filebuf.st_size < length)
51     {
52       /* Extend file length. */
53       if (lseek (fd, (length - 1), SEEK_SET) < 0)
54         return -1;
55
56       /* Write a "0" byte. */
57       if (write (fd, "", 1) != 1)
58         return -1;
59     }
60   else
61     {
62
63       /* Truncate length. */
64
65       fl.l_whence = 0;
66       fl.l_len = 0;
67       fl.l_start = length;
68       fl.l_type = F_WRLCK;      /* write lock on file space */
69
70       /* This relies on the *undocumented* F_FREESP argument to fcntl,
71          which truncates the file so that it ends at the position
72          indicated by fl.l_start.  Will minor miracles never cease?  */
73
74       if (fcntl (fd, F_FREESP, &fl) < 0)
75         return -1;
76     }
77
78   return 0;
79 }
80
81 #else /* not F_CHSIZE nor F_FREESP */
82 #ifdef HAVE_CHSIZE
83
84 int
85 ftruncate (fd, length)
86      int fd;
87      off_t length;
88 {
89   return chsize (fd, length);
90 }
91
92 #else /* not F_CHSIZE nor F_FREESP nor HAVE_CHSIZE */
93
94 #include <errno.h>
95 #ifndef errno
96 extern int errno;
97 #endif
98
99 int
100 ftruncate (fd, length)
101      int fd;
102      off_t length;
103 {
104   errno = EIO;
105   return -1;
106 }
107
108 #endif /* not HAVE_CHSIZE */
109 #endif /* not F_FREESP */
110 #endif /* not F_CHSIZE */