maint.mk: Update system header list for #include syntax checks.
[gnulib.git] / tests / test-supersede-open.h
blobaab6aaa9989ddb6196a7a0406cc331763b37ef12
1 /* Tests for opening a file without destroying an old file with the same name.
3 Copyright (C) 2020-2024 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
18 /* Written by Bruno Haible, 2020. */
20 static void
21 test_open_supersede (bool supersede_if_exists, bool supersede_if_does_not_exist)
23 char xtemplate[] = "gnulibtestXXXXXX";
24 char *dir = mkdtemp (xtemplate);
25 char *filename = file_name_concat (dir, "test.mo", NULL);
26 struct stat statbuf;
28 /* Test the case that the file does not yet exist. */
30 ASSERT (stat (filename, &statbuf) < 0);
32 struct supersede_final_action action;
33 int fd = open_supersede (filename, O_RDWR | O_BINARY | O_TRUNC, 0666,
34 supersede_if_exists, supersede_if_does_not_exist,
35 &action);
36 ASSERT (fd >= 0);
37 ASSERT (write (fd, "Hello world\n", 12) == 12);
38 if (supersede_if_does_not_exist)
39 ASSERT (stat (filename, &statbuf) < 0);
40 else
41 ASSERT (stat (filename, &statbuf) == 0);
42 ASSERT (close_supersede (fd, &action) == 0);
44 ASSERT (stat (filename, &statbuf) == 0);
46 size_t file_size;
47 char *file_contents = read_file (filename, RF_BINARY, &file_size);
48 ASSERT (file_size == 12);
49 ASSERT (memcmp (file_contents, "Hello world\n", 12) == 0);
52 /* Test the case that the file exists and is a regular file. */
54 ASSERT (stat (filename, &statbuf) == 0);
55 dev_t orig_dev = statbuf.st_dev;
56 ino_t orig_ino = statbuf.st_ino;
58 struct supersede_final_action action;
59 int fd = open_supersede (filename, O_RDWR | O_BINARY | O_TRUNC, 0666,
60 supersede_if_exists, supersede_if_does_not_exist,
61 &action);
62 ASSERT (fd >= 0);
63 ASSERT (write (fd, "Foobar\n", 7) == 7);
64 ASSERT (stat (filename, &statbuf) == 0);
66 size_t file_size;
67 char *file_contents = read_file (filename, RF_BINARY, &file_size);
68 if (supersede_if_exists)
70 ASSERT (file_size == 12);
71 ASSERT (memcmp (file_contents, "Hello world\n", 12) == 0);
73 else
75 ASSERT (file_size == 7);
76 ASSERT (memcmp (file_contents, "Foobar\n", 7) == 0);
79 ASSERT (close_supersede (fd, &action) == 0);
81 ASSERT (stat (filename, &statbuf) == 0);
83 size_t file_size;
84 char *file_contents = read_file (filename, RF_BINARY, &file_size);
85 ASSERT (file_size == 7);
86 ASSERT (memcmp (file_contents, "Foobar\n", 7) == 0);
88 if (supersede_if_exists)
90 /* Verify that the file now has a different inode number, on the same
91 device. */
92 #if !(defined _WIN32 && !defined __CYGWIN__)
93 /* Note: On Linux/mips, statbuf.st_dev is smaller than a dev_t! */
94 dev_t new_dev = statbuf.st_dev;
95 ASSERT (memcmp (&orig_dev, &new_dev, sizeof (dev_t)) == 0);
96 ASSERT (memcmp (&orig_ino, &statbuf.st_ino, sizeof (ino_t)) != 0);
97 #endif
101 /* Test the case that the file exists and is a character device. */
103 ASSERT (stat (DEV_NULL, &statbuf) == 0);
105 struct supersede_final_action action;
106 int fd = open_supersede (DEV_NULL, O_RDWR | O_BINARY | O_TRUNC, 0666,
107 supersede_if_exists, supersede_if_does_not_exist,
108 &action);
109 ASSERT (fd >= 0);
110 ASSERT (write (fd, "Foobar\n", 7) == 7);
111 ASSERT (stat (DEV_NULL, &statbuf) == 0);
112 ASSERT (close_supersede (fd, &action) == 0);
114 ASSERT (stat (DEV_NULL, &statbuf) == 0);
117 /* Test the case that the file is a symbolic link to an existing regular
118 file. */
120 const char *linkname = "link1";
121 unlink (linkname);
122 if (symlink (filename, linkname) >= 0)
124 ASSERT (stat (linkname, &statbuf) == 0);
125 dev_t orig_dev = statbuf.st_dev;
126 ino_t orig_ino = statbuf.st_ino;
128 struct supersede_final_action action;
129 int fd =
130 open_supersede (linkname, O_RDWR | O_BINARY | O_TRUNC, 0666,
131 supersede_if_exists, supersede_if_does_not_exist,
132 &action);
133 ASSERT (fd >= 0);
134 ASSERT (write (fd, "New\n", 4) == 4);
135 ASSERT (stat (linkname, &statbuf) == 0);
137 size_t file_size;
138 char *file_contents = read_file (linkname, RF_BINARY, &file_size);
139 if (supersede_if_exists)
141 ASSERT (file_size == 7);
142 ASSERT (memcmp (file_contents, "Foobar\n", 7) == 0);
144 else
146 ASSERT (file_size == 4);
147 ASSERT (memcmp (file_contents, "New\n", 4) == 0);
150 ASSERT (close_supersede (fd, &action) == 0);
152 ASSERT (stat (linkname, &statbuf) == 0);
154 size_t file_size;
155 char *file_contents = read_file (linkname, RF_BINARY, &file_size);
156 ASSERT (file_size == 4);
157 ASSERT (memcmp (file_contents, "New\n", 4) == 0);
159 if (supersede_if_exists)
161 /* Verify that the file now has a different inode number, on the
162 same device. */
163 #if !(defined _WIN32 && !defined __CYGWIN__)
164 /* Note: On Linux/mips, statbuf.st_dev is smaller than a dev_t! */
165 dev_t new_dev = statbuf.st_dev;
166 ASSERT (memcmp (&orig_dev, &new_dev, sizeof (dev_t)) == 0);
167 ASSERT (memcmp (&orig_ino, &statbuf.st_ino, sizeof (ino_t)) != 0);
168 #endif
171 /* Clean up. */
172 unlink (linkname);
176 /* Test the case that the file is a symbolic link to an existing character
177 device. */
179 const char *linkname = "link2";
180 unlink (linkname);
181 if (symlink (DEV_NULL, linkname) >= 0)
183 ASSERT (stat (linkname, &statbuf) == 0);
185 struct supersede_final_action action;
186 int fd =
187 open_supersede (linkname, O_RDWR | O_BINARY | O_TRUNC, 0666,
188 supersede_if_exists, supersede_if_does_not_exist,
189 &action);
190 ASSERT (fd >= 0);
191 ASSERT (write (fd, "New\n", 4) == 4);
192 ASSERT (stat (linkname, &statbuf) == 0);
193 ASSERT (close_supersede (fd, &action) == 0);
195 ASSERT (stat (linkname, &statbuf) == 0);
197 /* Clean up. */
198 unlink (linkname);
202 /* Clean up. */
203 unlink (filename);
205 /* Test the case that the file is a symbolic link to a nonexistent file in an
206 existing directory. */
208 const char *linkname = "link3";
209 unlink (linkname);
210 if (symlink (filename, linkname) >= 0)
212 ASSERT (stat (linkname, &statbuf) < 0);
214 struct supersede_final_action action;
215 int fd =
216 open_supersede (linkname, O_RDWR | O_BINARY | O_TRUNC, 0666,
217 supersede_if_exists, supersede_if_does_not_exist,
218 &action);
219 ASSERT (fd >= 0);
220 ASSERT (write (fd, "Hello world\n", 12) == 12);
221 if (supersede_if_does_not_exist)
222 ASSERT (stat (linkname, &statbuf) < 0);
223 else
224 ASSERT (stat (linkname, &statbuf) == 0);
225 ASSERT (close_supersede (fd, &action) == 0);
227 ASSERT (stat (linkname, &statbuf) == 0);
229 size_t file_size;
230 char *file_contents = read_file (linkname, RF_BINARY, &file_size);
231 ASSERT (file_size == 12);
232 ASSERT (memcmp (file_contents, "Hello world\n", 12) == 0);
234 /* Clean up. */
235 unlink (linkname);
239 /* Test the case that the file is a symbolic link to a nonexistent file in a
240 nonexistent directory. */
242 const char *linkname = "link4";
243 unlink (linkname);
244 if (symlink ("/nonexistent/gnulibtest8237/24715863701440", linkname) >= 0)
246 ASSERT (stat (linkname, &statbuf) < 0);
248 struct supersede_final_action action;
249 int fd =
250 open_supersede (linkname, O_RDWR | O_BINARY | O_TRUNC, 0666,
251 supersede_if_exists, supersede_if_does_not_exist,
252 &action);
253 ASSERT (fd < 0);
254 ASSERT (errno == ENOENT);
256 ASSERT (stat (linkname, &statbuf) < 0);
258 /* Clean up. */
259 unlink (linkname);
263 /* Clean up. */
264 unlink (filename);
265 rmdir (dir);