*** empty log message ***
[gnulib.git] / 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
29 #if HAVE_UTIME_H
30 # include <utime.h>
31 #endif
32
33 /* Some systems (even some that do have <utime.h>) don't declare this
34    structure anywhere.  */
35 #ifndef HAVE_STRUCT_UTIMBUF
36 struct utimbuf
37 {
38   long actime;
39   long modtime;
40 };
41 #endif
42
43 #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__
44 # define __attribute__(x)
45 #endif
46
47 #ifndef ATTRIBUTE_UNUSED
48 # define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
49 #endif
50
51 /* Set the access and modification time stamps of FD (a.k.a. FILE) to be
52    TIMESPEC[0] and TIMESPEC[1], respectively.
53    FD must be either negative -- in which case it is ignored --
54    or a file descriptor that is open on FILE.
55    If TIMESPEC is null, set the time stamps to the current time.  */
56
57 int
58 futimens (int fd ATTRIBUTE_UNUSED,
59           char const *file, struct timespec const timespec[2])
60 {
61   /* There's currently no interface to set file timestamps with
62      nanosecond resolution, so do the best we can, discarding any
63      fractional part of the timestamp.  */
64 #if HAVE_WORKING_UTIMES
65   struct timeval timeval[2];
66   struct timeval const *t;
67   if (timespec)
68     {
69       timeval[0].tv_sec = timespec[0].tv_sec;
70       timeval[0].tv_usec = timespec[0].tv_nsec / 1000;
71       timeval[1].tv_sec = timespec[1].tv_sec;
72       timeval[1].tv_usec = timespec[1].tv_nsec / 1000;
73       t = timeval;
74     }
75   else
76     t = NULL;
77 # if HAVE_FUTIMES
78   if (0 <= fd)
79     {
80       if (futimes (fd, t) == 0)
81         return 0;
82
83       /* On GNU/Linux without the futimes syscall and without /proc
84          mounted, glibc futimes fails with errno == ENOENT.  Fall back
85          on utimes if we get a weird error number like that.  */
86       switch (errno)
87         {
88         case EACCES:
89         case EIO:
90         case EPERM:
91         case EROFS:
92           return -1;
93         }
94     }
95 # endif
96   return utimes (file, t);
97
98 #else
99
100   struct utimbuf utimbuf;
101   struct utimbuf const *t;
102   if (timespec)
103     {
104       utimbuf.actime = timespec[0].tv_sec;
105       utimbuf.modtime = timespec[1].tv_sec;
106       t = &utimbuf;
107     }
108   else
109     t = NULL;
110   return utime (file, t);
111
112 #endif
113 }
114
115 /* Set the access and modification time stamps of FILE to be
116    TIMESPEC[0] and TIMESPEC[1], respectively.  */
117 int
118 utimens (char const *file, struct timespec const timespec[2])
119 {
120   return futimens (-1, file, timespec);
121 }