1 /*
2 ** Copyright (C) 2001-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
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 2 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, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #include "sfconfig.h"
20 #include "sndfile.h"
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <assert.h>
25
26 #if HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29
30 #if (HAVE_DECL_S_IRGRP == 0)
31 #include <sf_unistd.h>
32 #endif
33
34 #include <string.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39
40 #define SIGNED_SIZEOF(x) ((int) sizeof (x))
41
42 /* EMX is OS/2. */
43 #if defined (__CYGWIN__) || defined (__EMX__)
44
45 #define LSEEK lseek
46 #define FSTAT fstat
47
48 typedef struct stat STATBUF ;
49 typedef off_t INT64 ;
50
51 static char dir_cmd [] = "ls -l" ;
52
53 #elif (defined (WIN32) || defined (_WIN32))
54
55 #define LSEEK _lseeki64
56 #define FSTAT _fstati64
57
58 typedef struct _stati64 STATBUF ;
59 typedef __int64 INT64 ;
60
61 static char dir_cmd [] = "dir" ;
62
63 #else
64
65 #define LSEEK lseek
66 #define FSTAT fstat
67
68 typedef struct stat STATBUF ;
69 typedef sf_count_t INT64 ;
70
71 #define O_BINARY 0
72 static char dir_cmd [] = "ls -l" ;
73
74 #endif
75
76 static void show_fstat_error (void) ;
77 static void show_lseek_error (void) ;
78 static void show_stat_fstat_error (void) ;
79 static void write_to_closed_file (void) ;
80
81 int
main(void)82 main (void)
83 {
84 puts ("\n\n\n\n"
85 "This program shows up errors in the Win32 implementation of\n"
86 "a couple of POSIX API functions on some versions of windoze.\n"
87 "It can also be compiled on Linux (which works correctly) and\n"
88 "other OSes just to provide a sanity check.\n"
89 ) ;
90
91 show_fstat_error () ;
92 show_lseek_error () ;
93 show_stat_fstat_error () ;
94 write_to_closed_file () ;
95
96 puts ("\n\n") ;
97
98 return 0 ;
99 } /* main */
100
101 static void
show_fstat_error(void)102 show_fstat_error (void)
103 { static const char *filename = "fstat.dat" ;
104 static char data [256] ;
105
106 STATBUF statbuf ;
107 int fd, mode, flags ;
108
109 if (sizeof (statbuf.st_size) != sizeof (INT64))
110 { printf ("\n\nLine %d: Error, sizeof (statbuf.st_size) != 8.\n\n", __LINE__) ;
111 return ;
112 } ;
113
114 puts ("\n64 bit fstat() test.\n--------------------") ;
115
116 printf ("0) Create a file, write %d bytes and close it.\n", SIGNED_SIZEOF (data)) ;
117 mode = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY ;
118 flags = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ;
119 if ((fd = open (filename, mode, flags)) < 0)
120 { printf ("\n\nLine %d: open() failed : %s\n\n", __LINE__, strerror (errno)) ;
121 return ;
122 } ;
123 assert (write (fd, data, sizeof (data)) > 0) ;
124 close (fd) ;
125
126 printf ("1) Re-open file in read/write mode and write another %d bytes at the end.\n", SIGNED_SIZEOF (data)) ;
127 mode = O_RDWR | O_BINARY ;
128 flags = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ;
129 if ((fd = open (filename, mode, flags)) < 0)
130 { printf ("\n\nLine %d: open() failed : %s\n\n", __LINE__, strerror (errno)) ;
131 return ;
132 } ;
133 LSEEK (fd, 0, SEEK_END) ;
134 assert (write (fd, data, sizeof (data)) > 0) ;
135
136 printf ("2) Now use system (\"%s %s\") to show the file length.\n\n", dir_cmd, filename) ;
137
138 /* Would use snprintf, but thats not really available on windows. */
139 memset (data, 0, sizeof (data)) ;
140 strncpy (data, dir_cmd, sizeof (data) - 1) ;
141 strncat (data, " ", sizeof (data) - 1 - strlen (data)) ;
142 strncat (data, filename, sizeof (data) - 1 - strlen (data)) ;
143
144 assert (system (data) >= 0) ;
145 puts ("") ;
146
147 printf ("3) Now use fstat() to get the file length.\n") ;
148 if (FSTAT (fd, &statbuf) != 0)
149 { printf ("\n\nLine %d: fstat() returned error : %s\n", __LINE__, strerror (errno)) ;
150 return ;
151 } ;
152
153 printf ("4) According to fstat(), the file length is %ld, ", (long) statbuf.st_size) ;
154
155 close (fd) ;
156
157 if (statbuf.st_size != 2 * sizeof (data))
158 printf ("but thats just plain ***WRONG***.\n\n") ;
159 else
160 { printf ("which is correct.\n\n") ;
161 unlink (filename) ;
162 } ;
163
164 } /* show_fstat_error */
165
166 static void
show_lseek_error(void)167 show_lseek_error (void)
168 { static const char *filename = "fstat.dat" ;
169 static char data [256] ;
170
171 INT64 retval ;
172 int fd, mode, flags ;
173
174 puts ("\n64 bit lseek() test.\n--------------------") ;
175
176 printf ("0) Create a file, write %d bytes and close it.\n", SIGNED_SIZEOF (data)) ;
177 mode = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY ;
178 flags = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ;
179 if ((fd = open (filename, mode, flags)) < 0)
180 { printf ("\n\nLine %d: open() failed : %s\n\n", __LINE__, strerror (errno)) ;
181 return ;
182 } ;
183 assert (write (fd, data, sizeof (data)) > 0) ;
184 close (fd) ;
185
186 printf ("1) Re-open file in read/write mode and write another %d bytes at the end.\n", SIGNED_SIZEOF (data)) ;
187 mode = O_RDWR | O_BINARY ;
188 flags = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ;
189 if ((fd = open (filename, mode, flags)) < 0)
190 { printf ("\n\nLine %d: open() failed : %s\n\n", __LINE__, strerror (errno)) ;
191 return ;
192 } ;
193
194 LSEEK (fd, 0, SEEK_END) ;
195 assert (write (fd, data, sizeof (data)) > 0) ;
196
197 printf ("2) Now use system (\"%s %s\") to show the file length.\n\n", dir_cmd, filename) ;
198
199 /* Would use snprintf, but thats not really available on windows. */
200 memset (data, 0, sizeof (data)) ;
201 strncpy (data, dir_cmd, sizeof (data) - 1) ;
202 strncat (data, " ", sizeof (data) - 1 - strlen (data)) ;
203 strncat (data, filename, sizeof (data) - 1 - strlen (data)) ;
204
205 assert (system (data) >= 0) ;
206 puts ("") ;
207
208 printf ("3) Now use lseek() to go to the end of the file.\n") ;
209 retval = LSEEK (fd, 0, SEEK_END) ;
210
211 printf ("4) We are now at position %ld, ", (long) retval) ;
212
213 close (fd) ;
214
215 if (retval != 2 * sizeof (data))
216 printf ("but thats just plain ***WRONG***.\n\n") ;
217 else
218 { printf ("which is correct.\n\n") ;
219 unlink (filename) ;
220 } ;
221
222 } /* show_lseek_error */
223
224 static void
show_stat_fstat_error(void)225 show_stat_fstat_error (void)
226 { static const char *filename = "stat_fstat.dat" ;
227 static char data [256] ;
228
229 int fd, mode, flags ;
230 int stat_size, fstat_size ;
231 struct stat buf ;
232
233 /* Known to fail on WinXP. */
234 puts ("\nstat/fstat test.\n----------------") ;
235
236 printf ("0) Create a file and write %d bytes.\n", SIGNED_SIZEOF (data)) ;
237
238 mode = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY ;
239 flags = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ;
240 if ((fd = open (filename, mode, flags)) < 0)
241 { printf ("\n\nLine %d: open() failed : %s\n\n", __LINE__, strerror (errno)) ;
242 return ;
243 } ;
244
245 assert (write (fd, data, sizeof (data)) > 0) ;
246
247 printf ("1) Now call stat and fstat on the file and retreive the file lengths.\n") ;
248
249 if (stat (filename, &buf) != 0)
250 { printf ("\n\nLine %d: stat() failed : %s\n\n", __LINE__, strerror (errno)) ;
251 goto error_exit ;
252 } ;
253 stat_size = buf.st_size ;
254
255 if (fstat (fd, &buf) != 0)
256 { printf ("\n\nLine %d: fstat() failed : %s\n\n", __LINE__, strerror (errno)) ;
257 goto error_exit ;
258 } ;
259 fstat_size = buf.st_size ;
260
261 printf ("2) Size returned by stat and fstat is %d and %d, ", stat_size, fstat_size) ;
262
263
264 if (stat_size == 0 || stat_size != fstat_size)
265 printf ("but thats just plain ***WRONG***.\n\n") ;
266 else
267 printf ("which is correct.\n\n") ;
268
269 error_exit :
270
271 close (fd) ;
272 unlink (filename) ;
273
274 return ;
275 } /* show_stat_fstat_error */
276
277
278 static void
write_to_closed_file(void)279 write_to_closed_file (void)
280 { const char * filename = "closed_write_test.txt" ;
281 struct stat buf ;
282 FILE * file ;
283 int fd ;
284
285 puts ("\nWrite to closed file test.\n--------------------------") ;
286
287 printf ("0) First we open file for write using fopen().\n") ;
288 if ((file = fopen (filename, "w")) == NULL)
289 { printf ("\n\nLine %d: fopen() failed : %s\n\n", __LINE__, strerror (errno)) ;
290 return ;
291 } ;
292
293 printf ("1) Now we grab the file descriptor fileno().\n") ;
294 fd = fileno (file) ;
295
296 printf ("2) Write some text via the file descriptor.\n") ;
297 assert (write (fd, "a\n", 2) > 0) ;
298
299 printf ("3) Now we close the file using fclose().\n") ;
300 fclose (file) ;
301
302 stat (filename, &buf) ;
303 printf (" File size is %d bytes.\n", (int) buf.st_size) ;
304
305 printf ("4) Now write more data to the file descriptor which should fail.\n") ;
306 if (write (fd, "b\n", 2) < 0)
307 printf ("5) Good, write returned an error code as it should have.\n") ;
308 else
309 { printf ("5) Attempting to write to a closed file should have failed but didn't! *** WRONG ***\n") ;
310
311 stat (filename, &buf) ;
312 printf (" File size is %d bytes.\n", (int) buf.st_size) ;
313 } ;
314
315 unlink (filename) ;
316
317 return ;
318 } /* write_to_closed_file */
319