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