]>
Commit | Line | Data |
---|---|---|
2050f7b5 | 1 | /* Tests of fseek and fseeko. |
04277e02 | 2 | Copyright (C) 2000-2019 Free Software Foundation, Inc. |
2050f7b5 UD |
3 | This file is part of the GNU C Library. |
4 | Contributed by Ulrich Drepper <drepper@redhat.com>, 2000. | |
5 | ||
6 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
7 | modify it under the terms of the GNU Lesser General Public |
8 | License as published by the Free Software Foundation; either | |
9 | version 2.1 of the License, or (at your option) any later version. | |
2050f7b5 UD |
10 | |
11 | The GNU C Library is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 14 | Lesser General Public License for more details. |
2050f7b5 | 15 | |
41bdb6e2 | 16 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 | 17 | License along with the GNU C Library; if not, see |
5a82c748 | 18 | <https://www.gnu.org/licenses/>. */ |
2050f7b5 UD |
19 | |
20 | #include <error.h> | |
21 | #include <errno.h> | |
22 | #include <stdio.h> | |
23 | #include <stdlib.h> | |
24 | #include <string.h> | |
25 | #include <unistd.h> | |
78f056db | 26 | #include <time.h> |
2050f7b5 UD |
27 | #include <sys/stat.h> |
28 | ||
29 | ||
0e426475 AS |
30 | static int |
31 | do_test (void) | |
2050f7b5 UD |
32 | { |
33 | const char *tmpdir; | |
34 | char *fname; | |
35 | int fd; | |
36 | FILE *fp; | |
37 | const char outstr[] = "hello world!\n"; | |
38 | char strbuf[sizeof outstr]; | |
39 | char buf[200]; | |
40 | struct stat64 st1; | |
41 | struct stat64 st2; | |
42 | int result = 0; | |
43 | ||
44 | tmpdir = getenv ("TMPDIR"); | |
45 | if (tmpdir == NULL || tmpdir[0] == '\0') | |
46 | tmpdir = "/tmp"; | |
47 | ||
48 | asprintf (&fname, "%s/tst-fseek.XXXXXX", tmpdir); | |
49 | if (fname == NULL) | |
50 | error (EXIT_FAILURE, errno, "cannot generate name for temporary file"); | |
51 | ||
52 | /* Create a temporary file. */ | |
53 | fd = mkstemp (fname); | |
54 | if (fd == -1) | |
55 | error (EXIT_FAILURE, errno, "cannot open temporary file"); | |
56 | ||
57 | fp = fdopen (fd, "w+"); | |
58 | if (fp == NULL) | |
59 | error (EXIT_FAILURE, errno, "cannot get FILE for temporary file"); | |
60 | ||
61 | setbuffer (fp, strbuf, sizeof (outstr) -1); | |
62 | ||
63 | if (fwrite (outstr, sizeof (outstr) - 1, 1, fp) != 1) | |
64 | { | |
78ce5a3b | 65 | printf ("%d: write error\n", __LINE__); |
2050f7b5 UD |
66 | result = 1; |
67 | goto out; | |
68 | } | |
69 | ||
70 | /* The EOF flag must be reset. */ | |
71 | if (fgetc (fp) != EOF) | |
72 | { | |
78ce5a3b | 73 | printf ("%d: managed to read at end of file\n", __LINE__); |
2050f7b5 UD |
74 | result = 1; |
75 | } | |
76 | else if (! feof (fp)) | |
77 | { | |
78ce5a3b | 78 | printf ("%d: EOF flag not set\n", __LINE__); |
2050f7b5 UD |
79 | result = 1; |
80 | } | |
81 | if (fseek (fp, 0, SEEK_CUR) != 0) | |
82 | { | |
78ce5a3b | 83 | printf ("%d: fseek(fp, 0, SEEK_CUR) failed\n", __LINE__); |
2050f7b5 UD |
84 | result = 1; |
85 | } | |
86 | else if (feof (fp)) | |
87 | { | |
78ce5a3b | 88 | printf ("%d: fseek() didn't reset EOF flag\n", __LINE__); |
2050f7b5 UD |
89 | result = 1; |
90 | } | |
91 | ||
92 | /* Do the same for fseeko(). */ | |
2050f7b5 UD |
93 | if (fgetc (fp) != EOF) |
94 | { | |
78ce5a3b | 95 | printf ("%d: managed to read at end of file\n", __LINE__); |
2050f7b5 UD |
96 | result = 1; |
97 | } | |
98 | else if (! feof (fp)) | |
99 | { | |
78ce5a3b | 100 | printf ("%d: EOF flag not set\n", __LINE__); |
2050f7b5 UD |
101 | result = 1; |
102 | } | |
103 | if (fseeko (fp, 0, SEEK_CUR) != 0) | |
104 | { | |
78ce5a3b | 105 | printf ("%d: fseek(fp, 0, SEEK_CUR) failed\n", __LINE__); |
2050f7b5 UD |
106 | result = 1; |
107 | } | |
108 | else if (feof (fp)) | |
109 | { | |
78ce5a3b | 110 | printf ("%d: fseek() didn't reset EOF flag\n", __LINE__); |
2050f7b5 UD |
111 | result = 1; |
112 | } | |
2050f7b5 UD |
113 | |
114 | /* Go back to the beginning of the file: absolute. */ | |
115 | if (fseek (fp, 0, SEEK_SET) != 0) | |
116 | { | |
78ce5a3b | 117 | printf ("%d: fseek(fp, 0, SEEK_SET) failed\n", __LINE__); |
2050f7b5 UD |
118 | result = 1; |
119 | } | |
120 | else if (fflush (fp) != 0) | |
121 | { | |
78ce5a3b | 122 | printf ("%d: fflush() failed\n", __LINE__); |
2050f7b5 UD |
123 | result = 1; |
124 | } | |
125 | else if (lseek (fd, 0, SEEK_CUR) != 0) | |
126 | { | |
78ce5a3b | 127 | printf ("%d: lseek() returned different position\n", __LINE__); |
2050f7b5 UD |
128 | result = 1; |
129 | } | |
130 | else if (fread (buf, sizeof (outstr) - 1, 1, fp) != 1) | |
131 | { | |
78ce5a3b | 132 | printf ("%d: fread() failed\n", __LINE__); |
2050f7b5 UD |
133 | result = 1; |
134 | } | |
135 | else if (memcmp (buf, outstr, sizeof (outstr) - 1) != 0) | |
136 | { | |
78ce5a3b | 137 | printf ("%d: content after fseek(,,SEEK_SET) wrong\n", __LINE__); |
2050f7b5 UD |
138 | result = 1; |
139 | } | |
140 | ||
2050f7b5 UD |
141 | /* Now with fseeko. */ |
142 | if (fseeko (fp, 0, SEEK_SET) != 0) | |
143 | { | |
78ce5a3b | 144 | printf ("%d: fseeko(fp, 0, SEEK_SET) failed\n", __LINE__); |
2050f7b5 UD |
145 | result = 1; |
146 | } | |
147 | else if (fflush (fp) != 0) | |
148 | { | |
78ce5a3b | 149 | printf ("%d: fflush() failed\n", __LINE__); |
2050f7b5 UD |
150 | result = 1; |
151 | } | |
152 | else if (lseek (fd, 0, SEEK_CUR) != 0) | |
153 | { | |
78ce5a3b | 154 | printf ("%d: lseek() returned different position\n", __LINE__); |
2050f7b5 UD |
155 | result = 1; |
156 | } | |
157 | else if (fread (buf, sizeof (outstr) - 1, 1, fp) != 1) | |
158 | { | |
78ce5a3b | 159 | printf ("%d: fread() failed\n", __LINE__); |
2050f7b5 UD |
160 | result = 1; |
161 | } | |
162 | else if (memcmp (buf, outstr, sizeof (outstr) - 1) != 0) | |
163 | { | |
78ce5a3b | 164 | printf ("%d: content after fseeko(,,SEEK_SET) wrong\n", __LINE__); |
2050f7b5 UD |
165 | result = 1; |
166 | } | |
2050f7b5 UD |
167 | |
168 | /* Go back to the beginning of the file: relative. */ | |
ffa8d2a0 | 169 | if (fseek (fp, -((int) sizeof (outstr) - 1), SEEK_CUR) != 0) |
2050f7b5 | 170 | { |
78ce5a3b | 171 | printf ("%d: fseek(fp, 0, SEEK_SET) failed\n", __LINE__); |
2050f7b5 UD |
172 | result = 1; |
173 | } | |
174 | else if (fflush (fp) != 0) | |
175 | { | |
78ce5a3b | 176 | printf ("%d: fflush() failed\n", __LINE__); |
2050f7b5 UD |
177 | result = 1; |
178 | } | |
179 | else if (lseek (fd, 0, SEEK_CUR) != 0) | |
180 | { | |
78ce5a3b | 181 | printf ("%d: lseek() returned different position\n", __LINE__); |
2050f7b5 UD |
182 | result = 1; |
183 | } | |
184 | else if (fread (buf, sizeof (outstr) - 1, 1, fp) != 1) | |
185 | { | |
78ce5a3b | 186 | printf ("%d: fread() failed\n", __LINE__); |
2050f7b5 UD |
187 | result = 1; |
188 | } | |
189 | else if (memcmp (buf, outstr, sizeof (outstr) - 1) != 0) | |
190 | { | |
78ce5a3b | 191 | printf ("%d: content after fseek(,,SEEK_SET) wrong\n", __LINE__); |
2050f7b5 UD |
192 | result = 1; |
193 | } | |
194 | ||
2050f7b5 | 195 | /* Now with fseeko. */ |
ffa8d2a0 | 196 | if (fseeko (fp, -((int) sizeof (outstr) - 1), SEEK_CUR) != 0) |
2050f7b5 | 197 | { |
78ce5a3b | 198 | printf ("%d: fseeko(fp, 0, SEEK_SET) failed\n", __LINE__); |
2050f7b5 UD |
199 | result = 1; |
200 | } | |
201 | else if (fflush (fp) != 0) | |
202 | { | |
78ce5a3b | 203 | printf ("%d: fflush() failed\n", __LINE__); |
2050f7b5 UD |
204 | result = 1; |
205 | } | |
206 | else if (lseek (fd, 0, SEEK_CUR) != 0) | |
207 | { | |
78ce5a3b | 208 | printf ("%d: lseek() returned different position\n", __LINE__); |
2050f7b5 UD |
209 | result = 1; |
210 | } | |
211 | else if (fread (buf, sizeof (outstr) - 1, 1, fp) != 1) | |
212 | { | |
78ce5a3b | 213 | printf ("%d: fread() failed\n", __LINE__); |
2050f7b5 UD |
214 | result = 1; |
215 | } | |
216 | else if (memcmp (buf, outstr, sizeof (outstr) - 1) != 0) | |
217 | { | |
78ce5a3b | 218 | printf ("%d: content after fseeko(,,SEEK_SET) wrong\n", __LINE__); |
2050f7b5 UD |
219 | result = 1; |
220 | } | |
2050f7b5 UD |
221 | |
222 | /* Go back to the beginning of the file: from the end. */ | |
ffa8d2a0 | 223 | if (fseek (fp, -((int) sizeof (outstr) - 1), SEEK_END) != 0) |
2050f7b5 | 224 | { |
78ce5a3b | 225 | printf ("%d: fseek(fp, 0, SEEK_SET) failed\n", __LINE__); |
2050f7b5 UD |
226 | result = 1; |
227 | } | |
228 | else if (fflush (fp) != 0) | |
229 | { | |
78ce5a3b | 230 | printf ("%d: fflush() failed\n", __LINE__); |
2050f7b5 UD |
231 | result = 1; |
232 | } | |
233 | else if (lseek (fd, 0, SEEK_CUR) != 0) | |
234 | { | |
78ce5a3b | 235 | printf ("%d: lseek() returned different position\n", __LINE__); |
2050f7b5 UD |
236 | result = 1; |
237 | } | |
238 | else if (fread (buf, sizeof (outstr) - 1, 1, fp) != 1) | |
239 | { | |
78ce5a3b | 240 | printf ("%d: fread() failed\n", __LINE__); |
2050f7b5 UD |
241 | result = 1; |
242 | } | |
243 | else if (memcmp (buf, outstr, sizeof (outstr) - 1) != 0) | |
244 | { | |
78ce5a3b | 245 | printf ("%d: content after fseek(,,SEEK_SET) wrong\n", __LINE__); |
2050f7b5 UD |
246 | result = 1; |
247 | } | |
248 | ||
2050f7b5 | 249 | /* Now with fseeko. */ |
ffa8d2a0 | 250 | if (fseeko (fp, -((int) sizeof (outstr) - 1), SEEK_END) != 0) |
2050f7b5 | 251 | { |
78ce5a3b | 252 | printf ("%d: fseeko(fp, 0, SEEK_SET) failed\n", __LINE__); |
2050f7b5 UD |
253 | result = 1; |
254 | } | |
255 | else if (fflush (fp) != 0) | |
256 | { | |
78ce5a3b | 257 | printf ("%d: fflush() failed\n", __LINE__); |
2050f7b5 UD |
258 | result = 1; |
259 | } | |
260 | else if (lseek (fd, 0, SEEK_CUR) != 0) | |
261 | { | |
78ce5a3b | 262 | printf ("%d: lseek() returned different position\n", __LINE__); |
2050f7b5 UD |
263 | result = 1; |
264 | } | |
265 | else if (fread (buf, sizeof (outstr) - 1, 1, fp) != 1) | |
266 | { | |
78ce5a3b | 267 | printf ("%d: fread() failed\n", __LINE__); |
2050f7b5 UD |
268 | result = 1; |
269 | } | |
270 | else if (memcmp (buf, outstr, sizeof (outstr) - 1) != 0) | |
271 | { | |
78ce5a3b | 272 | printf ("%d: content after fseeko(,,SEEK_SET) wrong\n", __LINE__); |
2050f7b5 UD |
273 | result = 1; |
274 | } | |
2050f7b5 UD |
275 | |
276 | if (fwrite (outstr, sizeof (outstr) - 1, 1, fp) != 1) | |
277 | { | |
78ce5a3b | 278 | printf ("%d: write error 2\n", __LINE__); |
2050f7b5 UD |
279 | result = 1; |
280 | goto out; | |
281 | } | |
282 | ||
283 | if (fwrite (outstr, sizeof (outstr) - 1, 1, fp) != 1) | |
284 | { | |
78ce5a3b | 285 | printf ("%d: write error 3\n", __LINE__); |
2050f7b5 UD |
286 | result = 1; |
287 | goto out; | |
288 | } | |
289 | ||
290 | if (fwrite (outstr, sizeof (outstr) - 1, 1, fp) != 1) | |
291 | { | |
78ce5a3b | 292 | printf ("%d: write error 4\n", __LINE__); |
2050f7b5 UD |
293 | result = 1; |
294 | goto out; | |
295 | } | |
296 | ||
297 | if (fwrite (outstr, sizeof (outstr) - 1, 1, fp) != 1) | |
298 | { | |
78ce5a3b | 299 | printf ("%d: write error 5\n", __LINE__); |
2050f7b5 UD |
300 | result = 1; |
301 | goto out; | |
302 | } | |
303 | ||
304 | if (fputc ('1', fp) == EOF || fputc ('2', fp) == EOF) | |
305 | { | |
78ce5a3b | 306 | printf ("%d: cannot add characters at the end\n", __LINE__); |
2050f7b5 UD |
307 | result = 1; |
308 | goto out; | |
309 | } | |
310 | ||
311 | /* Check the access time. */ | |
312 | if (fstat64 (fd, &st1) < 0) | |
313 | { | |
78ce5a3b | 314 | printf ("%d: fstat64() before fseeko() failed\n\n", __LINE__); |
2050f7b5 UD |
315 | result = 1; |
316 | } | |
317 | else | |
318 | { | |
319 | sleep (1); | |
320 | ||
321 | if (fseek (fp, -(2 + 2 * (sizeof (outstr) - 1)), SEEK_CUR) != 0) | |
322 | { | |
78ce5a3b | 323 | printf ("%d: fseek() after write characters failed\n", __LINE__); |
2050f7b5 UD |
324 | result = 1; |
325 | goto out; | |
326 | } | |
327 | else | |
328 | { | |
329 | ||
330 | time_t t; | |
331 | /* Make sure the timestamp actually can be different. */ | |
332 | sleep (1); | |
333 | t = time (NULL); | |
334 | ||
335 | if (fstat64 (fd, &st2) < 0) | |
336 | { | |
78ce5a3b | 337 | printf ("%d: fstat64() after fseeko() failed\n\n", __LINE__); |
2050f7b5 UD |
338 | result = 1; |
339 | } | |
340 | if (st1.st_ctime >= t) | |
341 | { | |
78ce5a3b | 342 | printf ("%d: st_ctime not updated\n", __LINE__); |
2050f7b5 UD |
343 | result = 1; |
344 | } | |
345 | if (st1.st_mtime >= t) | |
346 | { | |
78ce5a3b | 347 | printf ("%d: st_mtime not updated\n", __LINE__); |
2050f7b5 UD |
348 | result = 1; |
349 | } | |
350 | if (st1.st_ctime >= st2.st_ctime) | |
351 | { | |
78ce5a3b | 352 | printf ("%d: st_ctime not changed\n", __LINE__); |
2050f7b5 UD |
353 | result = 1; |
354 | } | |
355 | if (st1.st_mtime >= st2.st_mtime) | |
356 | { | |
78ce5a3b | 357 | printf ("%d: st_mtime not changed\n", __LINE__); |
2050f7b5 UD |
358 | result = 1; |
359 | } | |
360 | } | |
361 | } | |
362 | ||
363 | if (fread (buf, 1, 2 + 2 * (sizeof (outstr) - 1), fp) | |
364 | != 2 + 2 * (sizeof (outstr) - 1)) | |
365 | { | |
78ce5a3b | 366 | printf ("%d: reading 2 records plus bits failed\n", __LINE__); |
2050f7b5 UD |
367 | result = 1; |
368 | } | |
369 | else if (memcmp (buf, outstr, sizeof (outstr) - 1) != 0 | |
370 | || memcmp (&buf[sizeof (outstr) - 1], outstr, | |
371 | sizeof (outstr) - 1) != 0 | |
372 | || buf[2 * (sizeof (outstr) - 1)] != '1' | |
373 | || buf[2 * (sizeof (outstr) - 1) + 1] != '2') | |
374 | { | |
78ce5a3b | 375 | printf ("%d: reading records failed\n", __LINE__); |
2050f7b5 UD |
376 | result = 1; |
377 | } | |
378 | else if (ungetc ('9', fp) == EOF) | |
379 | { | |
78ce5a3b | 380 | printf ("%d: ungetc() failed\n", __LINE__); |
2050f7b5 UD |
381 | result = 1; |
382 | } | |
383 | else if (fseek (fp, -(2 + 2 * (sizeof (outstr) - 1)), SEEK_END) != 0) | |
384 | { | |
78ce5a3b | 385 | printf ("%d: fseek after ungetc failed\n", __LINE__); |
2050f7b5 UD |
386 | result = 1; |
387 | } | |
388 | else if (fread (buf, 1, 2 + 2 * (sizeof (outstr) - 1), fp) | |
389 | != 2 + 2 * (sizeof (outstr) - 1)) | |
390 | { | |
78ce5a3b | 391 | printf ("%d: reading 2 records plus bits failed\n", __LINE__); |
2050f7b5 UD |
392 | result = 1; |
393 | } | |
394 | else if (memcmp (buf, outstr, sizeof (outstr) - 1) != 0 | |
395 | || memcmp (&buf[sizeof (outstr) - 1], outstr, | |
396 | sizeof (outstr) - 1) != 0 | |
397 | || buf[2 * (sizeof (outstr) - 1)] != '1') | |
398 | { | |
78ce5a3b | 399 | printf ("%d: reading records for the second time failed\n", __LINE__); |
2050f7b5 UD |
400 | result = 1; |
401 | } | |
402 | else if (buf[2 * (sizeof (outstr) - 1) + 1] == '9') | |
403 | { | |
78ce5a3b | 404 | printf ("%d: unget character not ignored\n", __LINE__); |
2050f7b5 UD |
405 | result = 1; |
406 | } | |
407 | else if (buf[2 * (sizeof (outstr) - 1) + 1] != '2') | |
408 | { | |
78ce5a3b | 409 | printf ("%d: unget somehow changed character\n", __LINE__); |
2050f7b5 UD |
410 | result = 1; |
411 | } | |
412 | ||
903b3396 UD |
413 | fclose (fp); |
414 | ||
903b3396 UD |
415 | fp = fopen (fname, "r"); |
416 | if (fp == NULL) | |
417 | { | |
78ce5a3b | 418 | printf ("%d: fopen() failed\n\n", __LINE__); |
903b3396 UD |
419 | result = 1; |
420 | } | |
421 | else if (fstat64 (fileno (fp), &st1) < 0) | |
422 | { | |
78ce5a3b | 423 | printf ("%d: fstat64() before fseeko() failed\n\n", __LINE__); |
903b3396 UD |
424 | result = 1; |
425 | } | |
426 | else if (fseeko (fp, 0, SEEK_END) != 0) | |
427 | { | |
78ce5a3b | 428 | printf ("%d: fseeko(fp, 0, SEEK_END) failed\n", __LINE__); |
903b3396 UD |
429 | result = 1; |
430 | } | |
431 | else if (ftello (fp) != st1.st_size) | |
432 | { | |
78ce5a3b UD |
433 | printf ("%d: fstat64 st_size %zd ftello %zd\n", __LINE__, |
434 | (size_t) st1.st_size, (size_t) ftello (fp)); | |
903b3396 UD |
435 | result = 1; |
436 | } | |
437 | else | |
78ce5a3b | 438 | printf ("%d: SEEK_END works\n", __LINE__); |
903b3396 UD |
439 | if (fp != NULL) |
440 | fclose (fp); | |
441 | ||
442 | fp = fopen (fname, "r"); | |
443 | if (fp == NULL) | |
444 | { | |
78ce5a3b | 445 | printf ("%d: fopen() failed\n\n", __LINE__); |
903b3396 UD |
446 | result = 1; |
447 | } | |
448 | else if (fstat64 (fileno (fp), &st1) < 0) | |
449 | { | |
78ce5a3b | 450 | printf ("%d: fstat64() before fgetc() failed\n\n", __LINE__); |
903b3396 UD |
451 | result = 1; |
452 | } | |
453 | else if (fgetc (fp) == EOF) | |
454 | { | |
78ce5a3b | 455 | printf ("%d: fgetc() before fseeko() failed\n\n", __LINE__); |
903b3396 UD |
456 | result = 1; |
457 | } | |
458 | else if (fseeko (fp, 0, SEEK_END) != 0) | |
459 | { | |
78ce5a3b | 460 | printf ("%d: fseeko(fp, 0, SEEK_END) failed\n", __LINE__); |
903b3396 UD |
461 | result = 1; |
462 | } | |
463 | else if (ftello (fp) != st1.st_size) | |
464 | { | |
78ce5a3b UD |
465 | printf ("%d: fstat64 st_size %zd ftello %zd\n", __LINE__, |
466 | (size_t) st1.st_size, (size_t) ftello (fp)); | |
903b3396 UD |
467 | result = 1; |
468 | } | |
469 | else | |
78ce5a3b | 470 | printf ("%d: SEEK_END works\n", __LINE__); |
903b3396 UD |
471 | if (fp != NULL) |
472 | fclose (fp); | |
903b3396 | 473 | |
2050f7b5 UD |
474 | out: |
475 | unlink (fname); | |
476 | ||
477 | return result; | |
478 | } | |
0e426475 | 479 | |
0e426475 AS |
480 | #define TEST_FUNCTION do_test () |
481 | #include "../test-skeleton.c" |