Alexandre Lision | 7c6f4a6 | 2013-09-05 13:27:01 -0400 | [diff] [blame] | 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 |
| 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 |
| 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 |
| 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 |
| 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 |
| 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 */ |