* utimens.c (ENOSYS): Define if not already defined.
[pspp] / lib / utimens.c
1 /* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
2
3    This program is free software; you can redistribute it and/or modify it
4    under the terms of the GNU General Public License as published by the
5    Free Software Foundation; either version 2, or (at your option) any
6    later version.
7
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software Foundation,
15    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
16
17 /* Written by Paul Eggert.  */
18
19 /* derived from a function in touch.c */
20
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24
25 #include "utimens.h"
26
27 #include <errno.h>
28 #include <fcntl.h>
29
30 #if HAVE_UTIME_H
31 # include <utime.h>
32 #endif
33
34 /* Some systems (even some that do have <utime.h>) don't declare this
35    structure anywhere.  */
36 #ifndef HAVE_STRUCT_UTIMBUF
37 struct utimbuf
38 {
39   long actime;
40   long modtime;
41 };
42 #endif
43
44 /* Some systems don't have ENOSYS.  */
45 #ifndef ENOSYS
46 # ifdef ENOTSUP
47 #  define ENOSYS ENOTSUP
48 # else
49 /* Some systems don't have ENOTSUP either.  */
50 #  define ENOSYS EINVAL
51 # endif
52 #endif
53
54 #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__
55 # define __attribute__(x)
56 #endif
57
58 #ifndef ATTRIBUTE_UNUSED
59 # define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
60 #endif
61
62 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
63    TIMESPEC[0] and TIMESPEC[1], respectively.
64    FD must be either negative -- in which case it is ignored --
65    or a file descriptor that is open on FILE.
66    If FD is nonnegative, then FILE can be NULL, which means
67    use just futimes (or equivalent) instead of utimes (or equivalent),
68    and fail if on an old system without futimes (or equivalent).
69    If TIMESPEC is null, set the time stamps to the current time.
70    Return 0 on success, -1 (setting errno) on failure.  */
71
72 int
73 futimens (int fd ATTRIBUTE_UNUSED,
74           char const *file, struct timespec const timespec[2])
75 {
76   /* There's currently no interface to set file timestamps with
77      nanosecond resolution, so do the best we can, discarding any
78      fractional part of the timestamp.  */
79 #if HAVE_FUTIMESAT || HAVE_WORKING_UTIMES
80   struct timeval timeval[2];
81   struct timeval const *t;
82   if (timespec)
83     {
84       timeval[0].tv_sec = timespec[0].tv_sec;
85       timeval[0].tv_usec = timespec[0].tv_nsec / 1000;
86       timeval[1].tv_sec = timespec[1].tv_sec;
87       timeval[1].tv_usec = timespec[1].tv_nsec / 1000;
88       t = timeval;
89     }
90   else
91     t = NULL;
92
93 # if HAVE_FUTIMESAT
94   return fd < 0 ? futimesat (AT_FDCWD, file, t) : futimesat (fd, NULL, t);
95 # elif HAVE_FUTIMES
96   if (0 <= fd)
97     {
98       if (futimes (fd, t) == 0)
99         return 0;
100
101       /* On GNU/Linux without the futimes syscall and without /proc
102          mounted, glibc futimes fails with errno == ENOENT.  Fall back
103          on utimes if we get a weird error number like that.  */
104       switch (errno)
105         {
106         case EACCES:
107         case EIO:
108         case EPERM:
109         case EROFS:
110           return -1;
111         }
112     }
113 # endif
114 #endif
115
116 #if ! HAVE_FUTIMES_AT
117
118   if (!file)
119     {
120       errno = ENOSYS;
121       return -1;
122     }
123
124 # if HAVE_WORKING_UTIMES
125   return utimes (file, t);
126 # else
127   {
128     struct utimbuf utimbuf;
129     struct utimbuf const *ut;
130     if (timespec)
131       {
132         utimbuf.actime = timespec[0].tv_sec;
133         utimbuf.modtime = timespec[1].tv_sec;
134         ut = &utimbuf;
135       }
136     else
137       ut = NULL;
138
139     return utime (file, ut);
140   }
141 # endif
142
143 #endif
144 }
145
146 /* Set the access and modification time stamps of FILE to be
147    TIMESPEC[0] and TIMESPEC[1], respectively.  */
148 int
149 utimens (char const *file, struct timespec const timespec[2])
150 {
151   return futimens (-1, file, timespec);
152 }