1/* trunc.c
2   Truncate a file to zero length.  */
3
4#include "uucp.h"
5
6#include "uudefs.h"
7#include "sysdep.h"
8#include "system.h"
9
10#include <errno.h>
11
12#if HAVE_FCNTL_H
13#include <fcntl.h>
14#else
15#if HAVE_SYS_FILE_H
16#include <sys/file.h>
17#endif
18#endif
19
20#ifndef FD_CLOEXEC
21#define FD_CLOEXEC 1
22#endif
23
24#ifndef SEEK_SET
25#define SEEK_SET 0
26#endif
27
28/* External functions.  */
29#ifndef lseek
30extern off_t lseek ();
31#endif
32
33/* Truncate a file to zero length.  If this fails, it closes and
34   removes the file.  We support a number of different means of
35   truncation, which is probably a waste of time since this function
36   is currently only called when the 'f' protocol resends a file.  */
37
38#if HAVE_FTRUNCATE
39#undef HAVE_LTRUNC
40#define HAVE_LTRUNC 0
41#endif
42
43#if ! HAVE_FTRUNCATE && ! HAVE_LTRUNC
44#ifdef F_CHSIZE
45#define HAVE_F_CHSIZE 1
46#else /* ! defined (F_CHSIZE) */
47#ifdef F_FREESP
48#define HAVE_F_FREESP 1
49#endif /* defined (F_FREESP) */
50#endif /* ! defined (F_CHSIZE) */
51#endif /* ! HAVE_FTRUNCATE && ! HAVE_LTRUNC */
52
53openfile_t
54esysdep_truncate (e, zname)
55     openfile_t e;
56     const char *zname;
57{
58  int o;
59
60#if HAVE_FTRUNCATE || HAVE_LTRUNC || HAVE_F_CHSIZE || HAVE_F_FREESP
61  int itrunc;
62
63  if (! ffilerewind (e))
64    {
65      ulog (LOG_ERROR, "rewind: %s", strerror (errno));
66      (void) ffileclose (e);
67      (void) remove (zname);
68      return EFILECLOSED;
69    }
70
71#if USE_STDIO
72  o = fileno (e);
73#else
74  o = e;
75#endif
76
77#if HAVE_FTRUNCATE
78  itrunc = ftruncate (o, 0);
79#endif
80#if HAVE_LTRUNC
81  itrunc = ltrunc (o, (long) 0, SEEK_SET);
82#endif
83#if HAVE_F_CHSIZE
84  itrunc = fcntl (o, F_CHSIZE, (off_t) 0);
85#endif
86#if HAVE_F_FREESP
87  /* This selection is based on an implementation of ftruncate by
88     kucharsk@Solbourne.com (William Kucharski).  */
89  {
90    struct flock fl;
91
92    fl.l_whence = 0;
93    fl.l_len = 0;
94    fl.l_start = 0;
95    fl.l_type = F_WRLCK;
96
97    itrunc = fcntl (o, F_FREESP, &fl);
98  }
99#endif
100
101  if (itrunc != 0)
102    {
103#if HAVE_FTRUNCATE
104      ulog (LOG_ERROR, "ftruncate: %s", strerror (errno));
105#endif
106#ifdef HAVE_LTRUNC
107      ulog (LOG_ERROR, "ltrunc: %s", strerror (errno));
108#endif
109#ifdef HAVE_F_CHSIZE
110      ulog (LOG_ERROR, "fcntl (F_CHSIZE): %s", strerror (errno));
111#endif
112#ifdef HAVE_F_FREESP
113      ulog (LOG_ERROR, "fcntl (F_FREESP): %s", strerror (errno));
114#endif
115
116      (void) ffileclose (e);
117      (void) remove (zname);
118      return EFILECLOSED;
119    }
120
121  return e;
122#else /* ! (HAVE_FTRUNCATE || HAVE_LTRUNC || HAVE_F_CHSIZE || HAVE_F_FREESP) */
123  (void) ffileclose (e);
124  (void) remove (zname);
125
126  o = creat ((char *) zname, IPRIVATE_FILE_MODE);
127
128  if (o == -1)
129    {
130      ulog (LOG_ERROR, "creat during esysdep_truncate (%s): %s", zname, strerror (errno));
131      return EFILECLOSED;
132    }
133
134  if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
135    {
136      ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
137      (void) close (o);
138      return EFILECLOSED;
139    }
140
141#if USE_STDIO
142  e = fdopen (o, (char *) BINWRITE);
143
144  if (e == NULL)
145    {
146      ulog (LOG_ERROR, "fdopen (%s): %s", zname, strerror (errno));
147      (void) close (o);
148      (void) remove (zname);
149      return NULL;
150    }
151#else /* ! USE_STDIO */
152  e = o;
153#endif /* ! USE_STDIO */
154
155  return e;
156#endif /* ! (HAVE_FTRUNCATE || HAVE_LTRUNC || HAVE_F_CHSIZE || HAVE_F_FREESP) */
157}
158