New module 'mbsrchr'.
[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 #include <config.h>
5
6 #include <sys/types.h>
7 #include <fcntl.h>
8
9 #ifdef F_CHSIZE
10
11 int
12 ftruncate (int fd, off_t length)
13 {
14   return fcntl (fd, F_CHSIZE, length);
15 }
16
17 #else /* not F_CHSIZE */
18 # ifdef F_FREESP
19
20 /* By William Kucharski <kucharsk@netcom.com>.  */
21
22 #  include <sys/stat.h>
23 #  include <errno.h>
24 #  include <unistd.h>
25
26 int
27 ftruncate (int fd, off_t length)
28 {
29   struct flock fl;
30   struct stat filebuf;
31
32   if (fstat (fd, &filebuf) < 0)
33     return -1;
34
35   if (filebuf.st_size < length)
36     {
37       /* Extend file length. */
38       if (lseek (fd, (length - 1), SEEK_SET) < 0)
39         return -1;
40
41       /* Write a "0" byte. */
42       if (write (fd, "", 1) != 1)
43         return -1;
44     }
45   else
46     {
47
48       /* Truncate length. */
49
50       fl.l_whence = 0;
51       fl.l_len = 0;
52       fl.l_start = length;
53       fl.l_type = F_WRLCK;      /* write lock on file space */
54
55       /* This relies on the *undocumented* F_FREESP argument to fcntl,
56          which truncates the file so that it ends at the position
57          indicated by fl.l_start.  Will minor miracles never cease?  */
58
59       if (fcntl (fd, F_FREESP, &fl) < 0)
60         return -1;
61     }
62
63   return 0;
64 }
65
66 # else /* not F_CHSIZE nor F_FREESP */
67 #  if HAVE_CHSIZE
68
69 int
70 ftruncate (int fd, off_t length)
71 {
72   return chsize (fd, length);
73 }
74
75 #  else /* not F_CHSIZE nor F_FREESP nor HAVE_CHSIZE */
76
77 #   include <errno.h>
78
79 int
80 ftruncate (int fd, off_t length)
81 {
82   errno = EIO;
83   return -1;
84 }
85
86 #  endif /* not HAVE_CHSIZE */
87 # endif /* not F_FREESP */
88 #endif /* not F_CHSIZE */