1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2010-11-17     Bernard      first version
9  */
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <finsh.h>
14 #include <sys/errno.h>
15 #include <sys/fcntl.h>
16 #include <sys/stat.h>
17 
18 const char* text = "this is a test string\n";
libc_fstat()19 void libc_fstat()
20 {
21     int fd;
22     struct stat s;
23 
24     fd = open("/tmp/tt.txt", O_WRONLY | O_CREAT, 0);
25     if (fd < 0)
26     {
27         printf("open failed\n");
28         return;
29     }
30 
31     write(fd, text, strlen(text) + 1);
32     printf("begin: %d\n", lseek(fd, 0, SEEK_SET));
33     printf("end: %d\n", lseek(fd, 0, SEEK_END));
34 
35     printf("fstat result: %d\n", fstat(fd, &s));
36     close(fd);
37 }
38 FINSH_FUNCTION_EXPORT(libc_fstat, fstat test for libc);
39 
libc_lseek()40 void libc_lseek()
41 {
42     int fd;
43 
44     fd = open("/tmp/tt.txt", O_WRONLY | O_CREAT, 0);
45     if (fd < 0)
46     {
47         printf("open failed\n");
48         return;
49     }
50 
51     write(fd, text, strlen(text) + 1);
52     printf("begin: %d\n", lseek(fd, 0, SEEK_SET));
53     printf("end: %d\n", lseek(fd, 0, SEEK_END));
54     close(fd);
55 }
56 FINSH_FUNCTION_EXPORT(libc_lseek, lseek test for libc);
57 
sleep(int tick)58 void sleep(int tick)
59 {
60     rt_thread_delay(tick);
61 }
62 
libc_fseek(void)63 int libc_fseek(void)
64 {
65     const char *tmpdir;
66     char *fname;
67     int fd;
68     FILE *fp;
69     const char outstr[] = "hello world!\n";
70     char strbuf[sizeof outstr];
71     char buf[200];
72     struct stat st1;
73     struct stat st2;
74     int result = 0;
75 
76     tmpdir = getenv("TMPDIR");
77     if (tmpdir == NULL || tmpdir[0] == '\0')
78         tmpdir = "/tmp";
79 
80     asprintf(&fname, "%s/tst-fseek.XXXXXX", tmpdir);
81     if (fname == NULL)
82     {
83         fprintf(stderr, "cannot generate name for temporary file: %s\n",
84                 strerror(errno));
85         return 1;
86     }
87 
88     /* Create a temporary file.   */
89     fd = mkstemp(fname);
90     if (fd == -1)
91     {
92         fprintf(stderr, "cannot open temporary file: %s\n", strerror(errno));
93         return 1;
94     }
95 
96     fp = fdopen(fd, "w+");
97     if (fp == NULL)
98     {
99         fprintf(stderr, "cannot get FILE for temporary file: %s\n", strerror(
100                 errno));
101         return 1;
102     }
103     setbuffer(fp, strbuf, sizeof(outstr) - 1);
104 
105     if (fwrite(outstr, sizeof(outstr) - 1, 1, fp) != 1)
106     {
107         printf("%d: write error\n", __LINE__);
108         result = 1;
109         goto out;
110     }
111 
112     /* The EOF flag must be reset.  */
113     if (fgetc(fp) != EOF)
114     {
115         printf("%d: managed to read at end of file\n", __LINE__);
116         result = 1;
117     }
118     else if (!feof(fp))
119     {
120         printf("%d: EOF flag not set\n", __LINE__);
121         result = 1;
122     }
123     if (fseek(fp, 0, SEEK_CUR) != 0)
124     {
125         printf("%d: fseek(fp, 0, SEEK_CUR) failed\n", __LINE__);
126         result = 1;
127     }
128     else if (feof(fp))
129     {
130         printf("%d: fseek() didn't reset EOF flag\n", __LINE__);
131         result = 1;
132     }
133 
134     /* Do the same for fseeko().  */
135     if (fgetc(fp) != EOF)
136     {
137         printf("%d: managed to read at end of file\n", __LINE__);
138         result = 1;
139     }
140     else if (!feof(fp))
141     {
142         printf("%d: EOF flag not set\n", __LINE__);
143         result = 1;
144     }
145     if (fseeko(fp, 0, SEEK_CUR) != 0)
146     {
147         printf("%d: fseek(fp, 0, SEEK_CUR) failed\n", __LINE__);
148         result = 1;
149     }
150     else if (feof(fp))
151     {
152         printf("%d: fseek() didn't reset EOF flag\n", __LINE__);
153         result = 1;
154     }
155 
156     /* Go back to the beginning of the file: absolute.  */
157     if (fseek(fp, 0, SEEK_SET) != 0)
158     {
159         printf("%d: fseek(fp, 0, SEEK_SET) failed\n", __LINE__);
160         result = 1;
161     }
162     else if (fflush(fp) != 0)
163     {
164         printf("%d: fflush() failed\n", __LINE__);
165         result = 1;
166     }
167     else if (lseek(fd, 0, SEEK_CUR) != 0)
168     {
169         int pos = lseek(fd, 0, SEEK_CUR);
170         printf("%d: lseek() returned different position, pos %d\n", __LINE__,
171                 pos);
172         result = 1;
173     }
174     else if (fread(buf, sizeof(outstr) - 1, 1, fp) != 1)
175     {
176         printf("%d: fread() failed\n", __LINE__);
177         result = 1;
178     }
179     else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0)
180     {
181         printf("%d: content after fseek(,,SEEK_SET) wrong\n", __LINE__);
182         result = 1;
183     }
184 
185     /* Now with fseeko.  */
186     if (fseeko(fp, 0, SEEK_SET) != 0)
187     {
188         printf("%d: fseeko(fp, 0, SEEK_SET) failed\n", __LINE__);
189         result = 1;
190     }
191     else if (fflush(fp) != 0)
192     {
193         printf("%d: fflush() failed\n", __LINE__);
194         result = 1;
195     }
196     else if (lseek(fd, 0, SEEK_CUR) != 0)
197     {
198         printf("%d: lseek() returned different position\n", __LINE__);
199         result = 1;
200     }
201     else if (fread(buf, sizeof(outstr) - 1, 1, fp) != 1)
202     {
203         printf("%d: fread() failed\n", __LINE__);
204         result = 1;
205     }
206     else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0)
207     {
208         printf("%d: content after fseeko(,,SEEK_SET) wrong\n", __LINE__);
209         result = 1;
210     }
211 
212     /* Go back to the beginning of the file: relative.  */
213     if (fseek(fp, -((int) sizeof(outstr) - 1), SEEK_CUR) != 0)
214     {
215         printf("%d: fseek(fp, 0, SEEK_SET) failed\n", __LINE__);
216         result = 1;
217     }
218     else if (fflush(fp) != 0)
219     {
220         printf("%d: fflush() failed\n", __LINE__);
221         result = 1;
222     }
223     else if (lseek(fd, 0, SEEK_CUR) != 0)
224     {
225         printf("%d: lseek() returned different position\n", __LINE__);
226         result = 1;
227     }
228     else if (fread(buf, sizeof(outstr) - 1, 1, fp) != 1)
229     {
230         printf("%d: fread() failed\n", __LINE__);
231         result = 1;
232     }
233     else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0)
234     {
235         printf("%d: content after fseek(,,SEEK_SET) wrong\n", __LINE__);
236         result = 1;
237     }
238 
239     /* Now with fseeko.  */
240     if (fseeko(fp, -((int) sizeof(outstr) - 1), SEEK_CUR) != 0)
241     {
242         printf("%d: fseeko(fp, 0, SEEK_SET) failed\n", __LINE__);
243         result = 1;
244     }
245     else if (fflush(fp) != 0)
246     {
247         printf("%d: fflush() failed\n", __LINE__);
248         result = 1;
249     }
250     else if (lseek(fd, 0, SEEK_CUR) != 0)
251     {
252         printf("%d: lseek() returned different position\n", __LINE__);
253         result = 1;
254     }
255     else if (fread(buf, sizeof(outstr) - 1, 1, fp) != 1)
256     {
257         printf("%d: fread() failed\n", __LINE__);
258         result = 1;
259     }
260     else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0)
261     {
262         printf("%d: content after fseeko(,,SEEK_SET) wrong\n", __LINE__);
263         result = 1;
264     }
265 
266     /* Go back to the beginning of the file: from the end.  */
267     if (fseek(fp, -((int) sizeof(outstr) - 1), SEEK_END) != 0)
268     {
269         printf("%d: fseek(fp, 0, SEEK_SET) failed\n", __LINE__);
270         result = 1;
271     }
272     else if (fflush(fp) != 0)
273     {
274         printf("%d: fflush() failed\n", __LINE__);
275         result = 1;
276     }
277     else if (lseek(fd, 0, SEEK_CUR) != 0)
278     {
279         printf("%d: lseek() returned different position\n", __LINE__);
280         result = 1;
281     }
282     else if (fread(buf, sizeof(outstr) - 1, 1, fp) != 1)
283     {
284         printf("%d: fread() failed\n", __LINE__);
285         result = 1;
286     }
287     else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0)
288     {
289         printf("%d: content after fseek(,,SEEK_SET) wrong\n", __LINE__);
290         result = 1;
291     }
292 
293     /* Now with fseeko.  */
294     if (fseeko(fp, -((int) sizeof(outstr) - 1), SEEK_END) != 0)
295     {
296         printf("%d: fseeko(fp, 0, SEEK_SET) failed\n", __LINE__);
297         result = 1;
298     }
299     else if (fflush(fp) != 0)
300     {
301         printf("%d: fflush() failed\n", __LINE__);
302         result = 1;
303     }
304     else if (lseek(fd, 0, SEEK_CUR) != 0)
305     {
306         printf("%d: lseek() returned different position\n", __LINE__);
307         result = 1;
308     }
309     else if (fread(buf, sizeof(outstr) - 1, 1, fp) != 1)
310     {
311         printf("%d: fread() failed\n", __LINE__);
312         result = 1;
313     }
314     else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0)
315     {
316         printf("%d: content after fseeko(,,SEEK_SET) wrong\n", __LINE__);
317         result = 1;
318     }
319 
320     if (fwrite(outstr, sizeof(outstr) - 1, 1, fp) != 1)
321     {
322         printf("%d: write error 2\n", __LINE__);
323         result = 1;
324         goto out;
325     }
326 
327     if (fwrite(outstr, sizeof(outstr) - 1, 1, fp) != 1)
328     {
329         printf("%d: write error 3\n", __LINE__);
330         result = 1;
331         goto out;
332     }
333 
334     if (fwrite(outstr, sizeof(outstr) - 1, 1, fp) != 1)
335     {
336         printf("%d: write error 4\n", __LINE__);
337         result = 1;
338         goto out;
339     }
340 
341     if (fwrite(outstr, sizeof(outstr) - 1, 1, fp) != 1)
342     {
343         printf("%d: write error 5\n", __LINE__);
344         result = 1;
345         goto out;
346     }
347 
348     if (fputc('1', fp) == EOF || fputc('2', fp) == EOF)
349     {
350         printf("%d: cannot add characters at the end\n", __LINE__);
351         result = 1;
352         goto out;
353     }
354 
355     /* Check the access time.  */
356     if (fstat(fd, &st1) < 0)
357     {
358         printf("%d: fstat64() before fseeko() failed\n\n", __LINE__);
359         result = 1;
360     }
361     else
362     {
363         sleep(1);
364 
365         if (fseek(fp, -(2 + 2 * (sizeof(outstr) - 1)), SEEK_CUR) != 0)
366         {
367             printf("%d: fseek() after write characters failed\n", __LINE__);
368             result = 1;
369             goto out;
370         }
371         else
372         {
373 
374             time_t t;
375             /* Make sure the timestamp actually can be different.  */
376             sleep(1);
377             t = time(NULL);
378 
379             if (fstat(fd, &st2) < 0)
380             {
381                 printf("%d: fstat64() after fseeko() failed\n\n", __LINE__);
382                 result = 1;
383             }
384             if (st1.st_ctime >= t)
385             {
386                 printf("%d: st_ctime not updated\n", __LINE__);
387                 result = 1;
388             }
389             if (st1.st_mtime >= t)
390             {
391                 printf("%d: st_mtime not updated\n", __LINE__);
392                 result = 1;
393             }
394             if (st1.st_ctime >= st2.st_ctime)
395             {
396                 printf("%d: st_ctime not changed\n", __LINE__);
397                 result = 1;
398             }
399             if (st1.st_mtime >= st2.st_mtime)
400             {
401                 printf("%d: st_mtime not changed\n", __LINE__);
402                 result = 1;
403             }
404         }
405     }
406 
407     if (fread(buf, 1, 2 + 2 * (sizeof(outstr) - 1), fp) != 2 + 2
408             * (sizeof(outstr) - 1))
409     {
410         printf("%d: reading 2 records plus bits failed\n", __LINE__);
411         result = 1;
412     }
413     else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0 || memcmp(
414             &buf[sizeof(outstr) - 1], outstr, sizeof(outstr) - 1) != 0 || buf[2
415             * (sizeof(outstr) - 1)] != '1' || buf[2 * (sizeof(outstr) - 1) + 1]
416             != '2')
417     {
418         printf("%d: reading records failed\n", __LINE__);
419         result = 1;
420     }
421     else if (ungetc('9', fp) == EOF)
422     {
423         printf("%d: ungetc() failed\n", __LINE__);
424         result = 1;
425     }
426     else if (fseek(fp, -(2 + 2 * (sizeof(outstr) - 1)), SEEK_END) != 0)
427     {
428         printf("%d: fseek after ungetc failed\n", __LINE__);
429         result = 1;
430     }
431     else if (fread(buf, 1, 2 + 2 * (sizeof(outstr) - 1), fp) != 2 + 2
432             * (sizeof(outstr) - 1))
433     {
434         printf("%d: reading 2 records plus bits failed\n", __LINE__);
435         result = 1;
436     }
437     else if (memcmp(buf, outstr, sizeof(outstr) - 1) != 0 || memcmp(
438             &buf[sizeof(outstr) - 1], outstr, sizeof(outstr) - 1) != 0 || buf[2
439             * (sizeof(outstr) - 1)] != '1')
440     {
441         printf("%d: reading records for the second time failed\n", __LINE__);
442         result = 1;
443     }
444     else if (buf[2 * (sizeof(outstr) - 1) + 1] == '9')
445     {
446         printf("%d: unget character not ignored\n", __LINE__);
447         result = 1;
448     }
449     else if (buf[2 * (sizeof(outstr) - 1) + 1] != '2')
450     {
451         printf("%d: unget somehow changed character\n", __LINE__);
452         result = 1;
453     }
454 
455     fclose(fp);
456 
457     fp = fopen(fname, "r");
458     if (fp == NULL)
459     {
460         printf("%d: fopen() failed\n\n", __LINE__);
461         result = 1;
462     }
463     else if (fstat(fileno(fp), &st1) < 0)
464     {
465         printf("%d: fstat64() before fseeko() failed\n\n", __LINE__);
466         result = 1;
467     }
468     else if (fseeko(fp, 0, SEEK_END) != 0)
469     {
470         printf("%d: fseeko(fp, 0, SEEK_END) failed\n", __LINE__);
471         result = 1;
472     }
473     else if (ftello(fp) != st1.st_size)
474     {
475         printf("%d: fstat64 st_size %zd ftello %zd\n", __LINE__,
476                 (size_t) st1.st_size, (size_t) ftello(fp));
477         result = 1;
478     }
479     else
480         printf("%d: SEEK_END works\n", __LINE__);
481     if (fp != NULL)
482         fclose(fp);
483 
484     fp = fopen(fname, "r");
485     if (fp == NULL)
486     {
487         printf("%d: fopen() failed\n\n", __LINE__);
488         result = 1;
489     }
490     else if (fstat(fileno(fp), &st1) < 0)
491     {
492         printf("%d: fstat64() before fgetc() failed\n\n", __LINE__);
493         result = 1;
494     }
495     else if (fgetc(fp) == EOF)
496     {
497         printf("%d: fgetc() before fseeko() failed\n\n", __LINE__);
498         result = 1;
499     }
500     else if (fseeko(fp, 0, SEEK_END) != 0)
501     {
502         printf("%d: fseeko(fp, 0, SEEK_END) failed\n", __LINE__);
503         result = 1;
504     }
505     else if (ftello(fp) != st1.st_size)
506     {
507         printf("%d: fstat64 st_size %zd ftello %zd\n", __LINE__,
508                 (size_t) st1.st_size, (size_t) ftello(fp));
509         result = 1;
510     }
511     else
512         printf("%d: SEEK_END works\n", __LINE__);
513     if (fp != NULL)
514         fclose(fp);
515 
516     out: unlink(fname);
517 
518     return result;
519 }
520 FINSH_FUNCTION_EXPORT(libc_fseek, lseek test for libc);
521