maint: update copyright
[gnulib.git] / tests / test-lutimens.h
1 /* Test of file timestamp modification functions.
2    Copyright (C) 2009-2014 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 #include "test-utimens-common.h"
18
19 /* This file is designed to test both lutimens(a,b) and
20    utimensat(AT_FDCWD,a,b,AT_SYMLINK_NOFOLLOW).  FUNC is the function
21    to test.  Assumes that BASE and ASSERT are already defined.  If
22    PRINT, warn before skipping tests with status 77.  */
23 static int
24 test_lutimens (int (*func) (char const *, struct timespec const *), bool print)
25 {
26   int result;
27   int saved_errno;
28   struct stat st1;
29   struct stat st2;
30   bool atime_supported = true;
31
32   /* Non-symlinks should be handled just like utimens.  */
33   errno = 0;
34   ASSERT (func ("no_such", NULL) == -1);
35   ASSERT (errno == ENOENT);
36   errno = 0;
37   ASSERT (func ("no_such/", NULL) == -1);
38   ASSERT (errno == ENOENT || errno == ENOTDIR);
39   errno = 0;
40   ASSERT (func ("", NULL) == -1);
41   ASSERT (errno == ENOENT);
42   ASSERT (close (creat (BASE "file", 0600)) == 0);
43   ASSERT (stat (BASE "file", &st1) == 0);
44   ASSERT (st1.st_atime != Y2K);
45   ASSERT (st1.st_mtime != Y2K);
46   {
47     struct timespec ts[2] = { { Y2K, 0 }, { Y2K, 0 } };
48     errno = 0;
49     ASSERT (func (BASE "file/", ts) == -1);
50     ASSERT (errno == ENOTDIR);
51     ASSERT (stat (BASE "file", &st2) == 0);
52     ASSERT (st1.st_atime == st2.st_atime);
53     ASSERT (st1.st_mtime == st2.st_mtime);
54   }
55   {
56     struct timespec ts[2] = { { Y2K, 0 }, { Y2K, 0 } };
57     nap ();
58     ASSERT (func (BASE "file", ts) == 0);
59   }
60   ASSERT (stat (BASE "file", &st2) == 0);
61   ASSERT (st2.st_atime == Y2K);
62   ASSERT (st2.st_mtime == Y2K);
63   if (check_ctime)
64     ASSERT (ctime_compare (&st1, &st2) < 0);
65
66   /* Play with symlink timestamps.  */
67   if (symlink (BASE "file", BASE "link"))
68     {
69       ASSERT (unlink (BASE "file") == 0);
70       if (print)
71         fputs ("skipping test: symlinks not supported on this file system\n",
72                stderr);
73       return 77;
74     }
75   errno = 0;
76   result = func (BASE "link", NULL);
77   saved_errno = errno;
78   /* Make sure we did not reference through link by accident.  */
79   ASSERT (stat (BASE "file", &st1) == 0);
80   ASSERT (st1.st_atime == Y2K);
81   ASSERT (st1.st_mtime == Y2K);
82   ASSERT (lstat (BASE "link", &st1) == 0);
83   ASSERT (st1.st_atime != Y2K);
84   ASSERT (st1.st_mtime != Y2K);
85   ASSERT (unlink (BASE "file") == 0);
86   if (result == -1 && saved_errno == ENOSYS)
87     {
88       ASSERT (unlink (BASE "link") == 0);
89       if (print)
90         fputs ("skipping test: "
91                "setting symlink time not supported on this file system\n",
92                stderr);
93       return 77;
94     }
95   ASSERT (!result);
96   ASSERT (lstat (BASE "link", &st1) == 0);
97   /* On cygwin, lstat() changes atime of symlinks, so that lutimens
98      can only effectively modify mtime.  */
99   nap ();
100   ASSERT (lstat (BASE "link", &st2) == 0);
101   if (st1.st_atime != st2.st_atime
102       || get_stat_atime_ns (&st1) != get_stat_atime_ns (&st2))
103     atime_supported = false;
104   ASSERT (st1.st_ctime == st2.st_ctime);
105   ASSERT (get_stat_ctime_ns (&st1) == get_stat_ctime_ns (&st2));
106
107   /* Invalid arguments.  */
108   {
109     struct timespec ts[2] = { { Y2K, UTIME_BOGUS_POS }, { Y2K, 0 } };
110     errno = 0;
111     ASSERT (func (BASE "link", ts) == -1);
112     ASSERT (errno == EINVAL);
113   }
114   {
115     struct timespec ts[2] = { { Y2K, 0 }, { Y2K, UTIME_BOGUS_NEG } };
116     errno = 0;
117     ASSERT (func (BASE "link", ts) == -1);
118     ASSERT (errno == EINVAL);
119   }
120   ASSERT (lstat (BASE "link", &st2) == 0);
121   if (atime_supported)
122     {
123       ASSERT (st1.st_atime == st2.st_atime);
124       ASSERT (get_stat_atime_ns (&st1) == get_stat_atime_ns (&st2));
125     }
126   ASSERT (utimecmp (BASE "link", &st1, &st2, 0) == 0);
127
128   /* Set both times.  */
129   {
130     struct timespec ts[2] = { { Y2K, BILLION / 2 - 1 }, { Y2K, BILLION - 1 } };
131     nap ();
132     ASSERT (func (BASE "link", ts) == 0);
133     ASSERT (lstat (BASE "link", &st2) == 0);
134     if (atime_supported)
135       {
136         ASSERT (st2.st_atime == Y2K);
137         ASSERT (0 <= get_stat_atime_ns (&st2));
138         ASSERT (get_stat_atime_ns (&st2) < BILLION / 2);
139       }
140     ASSERT (st2.st_mtime == Y2K);
141     ASSERT (0 <= get_stat_mtime_ns (&st2));
142     ASSERT (get_stat_mtime_ns (&st2) < BILLION);
143     if (check_ctime)
144       ASSERT (ctime_compare (&st1, &st2) < 0);
145   }
146
147   /* Play with UTIME_OMIT, UTIME_NOW.  */
148   {
149     struct stat st3;
150     struct timespec ts[2] = { { BILLION, UTIME_OMIT }, { 0, UTIME_NOW } };
151     nap ();
152     ASSERT (func (BASE "link", ts) == 0);
153     ASSERT (lstat (BASE "link", &st3) == 0);
154     if (atime_supported)
155       {
156         ASSERT (st3.st_atime == Y2K);
157         ASSERT (0 <= get_stat_atime_ns (&st3));
158         ASSERT (get_stat_atime_ns (&st3) < BILLION / 2);
159       }
160     ASSERT (utimecmp (BASE "link", &st1, &st3, 0) <= 0);
161     if (check_ctime)
162       ASSERT (ctime_compare (&st2, &st3) < 0);
163     nap ();
164     ts[0].tv_nsec = 0;
165     ts[1].tv_nsec = UTIME_OMIT;
166     ASSERT (func (BASE "link", ts) == 0);
167     ASSERT (lstat (BASE "link", &st2) == 0);
168     if (atime_supported)
169       {
170         ASSERT (st2.st_atime == BILLION);
171         ASSERT (get_stat_atime_ns (&st2) == 0);
172       }
173     ASSERT (st3.st_mtime == st2.st_mtime);
174     ASSERT (get_stat_mtime_ns (&st3) == get_stat_mtime_ns (&st2));
175     if (check_ctime)
176       ASSERT (ctime_compare (&st3, &st2) < 0);
177   }
178
179   /* Symlink to directory.  */
180   ASSERT (unlink (BASE "link") == 0);
181   ASSERT (symlink (BASE "dir", BASE "link") == 0);
182   ASSERT (mkdir (BASE "dir", 0700) == 0);
183   {
184     struct timespec ts[2] = { { Y2K, 0 }, { Y2K, 0 } };
185     ASSERT (func (BASE "link/", ts) == 0);
186   }
187   /* On cygwin 1.5, stat() changes atime of directories, so only check
188      mtime.  */
189   ASSERT (stat (BASE "dir", &st1) == 0);
190   ASSERT (st1.st_mtime == Y2K);
191   ASSERT (lstat (BASE "link", &st1) == 0);
192   ASSERT (st1.st_atime != Y2K);
193   ASSERT (st1.st_mtime != Y2K);
194   ASSERT (func (BASE "link", NULL) == 0);
195   ASSERT (stat (BASE "dir", &st1) == 0);
196   ASSERT (st1.st_mtime == Y2K);
197   ASSERT (lstat (BASE "link", &st1) == 0);
198   ASSERT (st1.st_atime != Y2K);
199   ASSERT (st1.st_mtime != Y2K);
200
201   /* Cleanup.  */
202   ASSERT (rmdir (BASE "dir") == 0);
203   ASSERT (unlink (BASE "link") == 0);
204   return 0;
205 }