1 /*
2 ** Copyright (C) 2002-2014 Erik de Castro Lopo <erikd@mega-nerd.com>
3 ** Copyright (C) 2003 Ross Bencina <rbencina@iprimus.com.au>
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU Lesser General Public License as published by
7 ** the Free Software Foundation; either version 2.1 of the License, or
8 ** (at your option) any later version.
9 **
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 Lesser General Public License for more details.
14 **
15 ** You should have received a copy of the GNU Lesser General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 /*
21 ** The file is split into three sections as follows:
22 ** - The top section (USE_WINDOWS_API == 0) for Linux, Unix and MacOSX
23 ** systems (including Cygwin).
24 ** - The middle section (USE_WINDOWS_API == 1) for microsoft windows
25 ** (including MinGW) using the native windows API.
26 ** - A legacy windows section which attempted to work around grevious
27 ** bugs in microsoft's POSIX implementation.
28 */
29
30 /*
31 ** The header file sfconfig.h MUST be included before the others to ensure
32 ** that large file support is enabled correctly on Unix systems.
33 */
34
35 #include "sfconfig.h"
36
37 #if USE_WINDOWS_API
38
39 /* Don't include rarely used headers, speed up build */
40 #define WIN32_LEAN_AND_MEAN
41
42 #include <windows.h>
43 #endif
44
45 #include <stdio.h>
46 #include <stdlib.h>
47
48 #if HAVE_UNISTD_H
49 #include <unistd.h>
50 #else
51 #include <io.h>
52 #endif
53
54 #if (HAVE_DECL_S_IRGRP == 0)
55 #include <sf_unistd.h>
56 #endif
57
58 #include <string.h>
59 #include <fcntl.h>
60 #include <errno.h>
61 #include <sys/stat.h>
62
63 #include "sndfile.h"
64 #include "common.h"
65
66 #define SENSIBLE_SIZE (0x40000000)
67
68 /*
69 ** Neat solution to the Win32/OS2 binary file flage requirement.
70 ** If O_BINARY isn't already defined by the inclusion of the system
71 ** headers, set it to zero.
72 */
73 #ifndef O_BINARY
74 #define O_BINARY 0
75 #endif
76
77 static void psf_log_syserr (SF_PRIVATE *psf, int error) ;
78
79 #if (USE_WINDOWS_API == 0)
80
81 /*------------------------------------------------------------------------------
82 ** Win32 stuff at the bottom of the file. Unix and other sensible OSes here.
83 */
84
85 static int psf_close_fd (int fd) ;
86 static int psf_open_fd (PSF_FILE * pfile) ;
87 static sf_count_t psf_get_filelen_fd (int fd) ;
88
89 int
psf_fopen(SF_PRIVATE * psf)90 psf_fopen (SF_PRIVATE *psf)
91 {
92 psf->error = 0 ;
93 psf->file.filedes = psf_open_fd (&psf->file) ;
94
95 if (psf->file.filedes == - SFE_BAD_OPEN_MODE)
96 { psf->error = SFE_BAD_OPEN_MODE ;
97 psf->file.filedes = -1 ;
98 return psf->error ;
99 } ;
100
101 if (psf->file.filedes == -1)
102 psf_log_syserr (psf, errno) ;
103
104 return psf->error ;
105 } /* psf_fopen */
106
107 int
psf_fclose(SF_PRIVATE * psf)108 psf_fclose (SF_PRIVATE *psf)
109 { int retval ;
110
111 if (psf->virtual_io)
112 return 0 ;
113
114 if (psf->file.do_not_close_descriptor)
115 { psf->file.filedes = -1 ;
116 return 0 ;
117 } ;
118
119 if ((retval = psf_close_fd (psf->file.filedes)) == -1)
120 psf_log_syserr (psf, errno) ;
121
122 psf->file.filedes = -1 ;
123
124 return retval ;
125 } /* psf_fclose */
126
127 int
psf_open_rsrc(SF_PRIVATE * psf)128 psf_open_rsrc (SF_PRIVATE *psf)
129 { size_t count ;
130
131 if (psf->rsrc.filedes > 0)
132 return 0 ;
133
134 /* Test for MacOSX style resource fork on HPFS or HPFS+ filesystems. */
135 count = snprintf (psf->rsrc.path.c, sizeof (psf->rsrc.path.c), "%s/..namedfork/rsrc", psf->file.path.c) ;
136 psf->error = SFE_NO_ERROR ;
137 if (count < sizeof (psf->rsrc.path.c))
138 { if ((psf->rsrc.filedes = psf_open_fd (&psf->rsrc)) >= 0)
139 { psf->rsrclength = psf_get_filelen_fd (psf->rsrc.filedes) ;
140 if (psf->rsrclength > 0 || (psf->rsrc.mode & SFM_WRITE))
141 return SFE_NO_ERROR ;
142 psf_close_fd (psf->rsrc.filedes) ;
143 psf->rsrc.filedes = -1 ;
144 } ;
145
146 if (psf->rsrc.filedes == - SFE_BAD_OPEN_MODE)
147 { psf->error = SFE_BAD_OPEN_MODE ;
148 return psf->error ;
149 } ;
150 } ;
151
152 /*
153 ** Now try for a resource fork stored as a separate file in the same
154 ** directory, but preceded with a dot underscore.
155 */
156 count = snprintf (psf->rsrc.path.c, sizeof (psf->rsrc.path.c), "%s._%s", psf->file.dir.c, psf->file.name.c) ;
157 psf->error = SFE_NO_ERROR ;
158 if (count < sizeof (psf->rsrc.path.c) && (psf->rsrc.filedes = psf_open_fd (&psf->rsrc)) >= 0)
159 { psf->rsrclength = psf_get_filelen_fd (psf->rsrc.filedes) ;
160 return SFE_NO_ERROR ;
161 } ;
162
163 /*
164 ** Now try for a resource fork stored in a separate file in the
165 ** .AppleDouble/ directory.
166 */
167 count = snprintf (psf->rsrc.path.c, sizeof (psf->rsrc.path.c), "%s.AppleDouble/%s", psf->file.dir.c, psf->file.name.c) ;
168 psf->error = SFE_NO_ERROR ;
169 if (count < sizeof (psf->rsrc.path.c))
170 { if ((psf->rsrc.filedes = psf_open_fd (&psf->rsrc)) >= 0)
171 { psf->rsrclength = psf_get_filelen_fd (psf->rsrc.filedes) ;
172 return SFE_NO_ERROR ;
173 } ;
174
175 /* No resource file found. */
176 if (psf->rsrc.filedes == -1)
177 psf_log_syserr (psf, errno) ;
178 }
179 else
180 { psf->error = SFE_OPEN_FAILED ;
181 } ;
182
183 psf->rsrc.filedes = -1 ;
184
185 return psf->error ;
186 } /* psf_open_rsrc */
187
188 sf_count_t
psf_get_filelen(SF_PRIVATE * psf)189 psf_get_filelen (SF_PRIVATE *psf)
190 { sf_count_t filelen ;
191
192 if (psf->virtual_io)
193 return psf->vio.get_filelen (psf->vio_user_data) ;
194
195 filelen = psf_get_filelen_fd (psf->file.filedes) ;
196
197 if (filelen == -1)
198 { psf_log_syserr (psf, errno) ;
199 return (sf_count_t) -1 ;
200 } ;
201
202 if (filelen == -SFE_BAD_STAT_SIZE)
203 { psf->error = SFE_BAD_STAT_SIZE ;
204 return (sf_count_t) -1 ;
205 } ;
206
207 switch (psf->file.mode)
208 { case SFM_WRITE :
209 filelen = filelen - psf->fileoffset ;
210 break ;
211
212 case SFM_READ :
213 if (psf->fileoffset > 0 && psf->filelength > 0)
214 filelen = psf->filelength ;
215 break ;
216
217 case SFM_RDWR :
218 /*
219 ** Cannot open embedded files SFM_RDWR so we don't need to
220 ** subtract psf->fileoffset. We already have the answer we
221 ** need.
222 */
223 break ;
224
225 default :
226 /* Shouldn't be here, so return error. */
227 filelen = -1 ;
228 } ;
229
230 return filelen ;
231 } /* psf_get_filelen */
232
233 int
psf_close_rsrc(SF_PRIVATE * psf)234 psf_close_rsrc (SF_PRIVATE *psf)
235 { psf_close_fd (psf->rsrc.filedes) ;
236 psf->rsrc.filedes = -1 ;
237 return 0 ;
238 } /* psf_close_rsrc */
239
240 int
psf_set_stdio(SF_PRIVATE * psf)241 psf_set_stdio (SF_PRIVATE *psf)
242 { int error = 0 ;
243
244 switch (psf->file.mode)
245 { case SFM_RDWR :
246 error = SFE_OPEN_PIPE_RDWR ;
247 break ;
248
249 case SFM_READ :
250 psf->file.filedes = 0 ;
251 break ;
252
253 case SFM_WRITE :
254 psf->file.filedes = 1 ;
255 break ;
256
257 default :
258 error = SFE_BAD_OPEN_MODE ;
259 break ;
260 } ;
261 psf->filelength = 0 ;
262
263 return error ;
264 } /* psf_set_stdio */
265
266 void
psf_set_file(SF_PRIVATE * psf,int fd)267 psf_set_file (SF_PRIVATE *psf, int fd)
268 { psf->file.filedes = fd ;
269 } /* psf_set_file */
270
271 int
psf_file_valid(SF_PRIVATE * psf)272 psf_file_valid (SF_PRIVATE *psf)
273 { return (psf->file.filedes >= 0) ? SF_TRUE : SF_FALSE ;
274 } /* psf_set_file */
275
276 sf_count_t
psf_fseek(SF_PRIVATE * psf,sf_count_t offset,int whence)277 psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence)
278 { sf_count_t absolute_position ;
279
280 if (psf->virtual_io)
281 return psf->vio.seek (offset, whence, psf->vio_user_data) ;
282
283 /* When decoding from pipes sometimes see seeks to the pipeoffset, which appears to mean do nothing. */
284 if (psf->is_pipe)
285 { if (whence != SEEK_SET || offset != psf->pipeoffset)
286 psf_log_printf (psf, "psf_fseek : pipe seek to value other than pipeoffset\n") ;
287 return offset ;
288 }
289
290 switch (whence)
291 { case SEEK_SET :
292 offset += psf->fileoffset ;
293 break ;
294
295 case SEEK_END :
296 break ;
297
298 case SEEK_CUR :
299 break ;
300
301 default :
302 /* We really should not be here. */
303 psf_log_printf (psf, "psf_fseek : whence is %d *****.\n", whence) ;
304 return 0 ;
305 } ;
306
307 absolute_position = lseek (psf->file.filedes, offset, whence) ;
308
309 if (absolute_position < 0)
310 psf_log_syserr (psf, errno) ;
311
312 return absolute_position - psf->fileoffset ;
313 } /* psf_fseek */
314
315 sf_count_t
psf_fread(void * ptr,sf_count_t bytes,sf_count_t items,SF_PRIVATE * psf)316 psf_fread (void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf)
317 { sf_count_t total = 0 ;
318 ssize_t count ;
319
320 if (psf->virtual_io)
321 return psf->vio.read (ptr, bytes*items, psf->vio_user_data) / bytes ;
322
323 items *= bytes ;
324
325 /* Do this check after the multiplication above. */
326 if (items <= 0)
327 return 0 ;
328
329 while (items > 0)
330 { /* Break the read down to a sensible size. */
331 count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ;
332
333 count = read (psf->file.filedes, ((char*) ptr) + total, (size_t) count) ;
334
335 if (count == -1)
336 { if (errno == EINTR)
337 continue ;
338
339 psf_log_syserr (psf, errno) ;
340 break ;
341 } ;
342
343 if (count == 0)
344 break ;
345
346 total += count ;
347 items -= count ;
348 } ;
349
350 if (psf->is_pipe)
351 psf->pipeoffset += total ;
352
353 return total / bytes ;
354 } /* psf_fread */
355
356 sf_count_t
psf_fwrite(const void * ptr,sf_count_t bytes,sf_count_t items,SF_PRIVATE * psf)357 psf_fwrite (const void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf)
358 { sf_count_t total = 0 ;
359 ssize_t count ;
360
361 if (bytes == 0 || items == 0)
362 return 0 ;
363
364 if (psf->virtual_io)
365 return psf->vio.write (ptr, bytes*items, psf->vio_user_data) / bytes ;
366
367 items *= bytes ;
368
369 /* Do this check after the multiplication above. */
370 if (items <= 0)
371 return 0 ;
372
373 while (items > 0)
374 { /* Break the writes down to a sensible size. */
375 count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : items ;
376
377 count = write (psf->file.filedes, ((const char*) ptr) + total, count) ;
378
379 if (count == -1)
380 { if (errno == EINTR)
381 continue ;
382
383 psf_log_syserr (psf, errno) ;
384 break ;
385 } ;
386
387 if (count == 0)
388 break ;
389
390 total += count ;
391 items -= count ;
392 } ;
393
394 if (psf->is_pipe)
395 psf->pipeoffset += total ;
396
397 return total / bytes ;
398 } /* psf_fwrite */
399
400 sf_count_t
psf_ftell(SF_PRIVATE * psf)401 psf_ftell (SF_PRIVATE *psf)
402 { sf_count_t pos ;
403
404 if (psf->virtual_io)
405 return psf->vio.tell (psf->vio_user_data) ;
406
407 if (psf->is_pipe)
408 return psf->pipeoffset ;
409
410 pos = lseek (psf->file.filedes, 0, SEEK_CUR) ;
411
412 if (pos == ((sf_count_t) -1))
413 { psf_log_syserr (psf, errno) ;
414 return -1 ;
415 } ;
416
417 return pos - psf->fileoffset ;
418 } /* psf_ftell */
419
420 static int
psf_close_fd(int fd)421 psf_close_fd (int fd)
422 { int retval ;
423
424 if (fd < 0)
425 return 0 ;
426
427 while ((retval = close (fd)) == -1 && errno == EINTR)
428 /* Do nothing. */ ;
429
430 return retval ;
431 } /* psf_close_fd */
432
433 sf_count_t
psf_fgets(char * buffer,sf_count_t bufsize,SF_PRIVATE * psf)434 psf_fgets (char *buffer, sf_count_t bufsize, SF_PRIVATE *psf)
435 { sf_count_t k = 0 ;
436 sf_count_t count ;
437
438 while (k < bufsize - 1)
439 { count = read (psf->file.filedes, &(buffer [k]), 1) ;
440
441 if (count == -1)
442 { if (errno == EINTR)
443 continue ;
444
445 psf_log_syserr (psf, errno) ;
446 break ;
447 } ;
448
449 if (count == 0 || buffer [k++] == '\n')
450 break ;
451 } ;
452
453 buffer [k] = 0 ;
454
455 return k ;
456 } /* psf_fgets */
457
458 int
psf_is_pipe(SF_PRIVATE * psf)459 psf_is_pipe (SF_PRIVATE *psf)
460 { struct stat statbuf ;
461
462 if (psf->virtual_io)
463 return SF_FALSE ;
464
465 if (fstat (psf->file.filedes, &statbuf) == -1)
466 { psf_log_syserr (psf, errno) ;
467 /* Default to maximum safety. */
468 return SF_TRUE ;
469 } ;
470
471 if (S_ISFIFO (statbuf.st_mode) || S_ISSOCK (statbuf.st_mode))
472 return SF_TRUE ;
473
474 return SF_FALSE ;
475 } /* psf_is_pipe */
476
477 static sf_count_t
psf_get_filelen_fd(int fd)478 psf_get_filelen_fd (int fd)
479 {
480 #if (SIZEOF_OFF_T == 4 && SIZEOF_SF_COUNT_T == 8 && HAVE_FSTAT64)
481 struct stat64 statbuf ;
482
483 if (fstat64 (fd, &statbuf) == -1)
484 return (sf_count_t) -1 ;
485
486 return statbuf.st_size ;
487 #else
488 struct stat statbuf ;
489
490 if (fstat (fd, &statbuf) == -1)
491 return (sf_count_t) -1 ;
492
493 return statbuf.st_size ;
494 #endif
495 } /* psf_get_filelen_fd */
496
497 int
psf_ftruncate(SF_PRIVATE * psf,sf_count_t len)498 psf_ftruncate (SF_PRIVATE *psf, sf_count_t len)
499 { int retval ;
500
501 /* Returns 0 on success, non-zero on failure. */
502 if (len < 0)
503 return -1 ;
504
505 if ((sizeof (off_t) < sizeof (sf_count_t)) && len > 0x7FFFFFFF)
506 return -1 ;
507
508 retval = ftruncate (psf->file.filedes, len) ;
509
510 if (retval == -1)
511 psf_log_syserr (psf, errno) ;
512
513 return retval ;
514 } /* psf_ftruncate */
515
516 void
psf_init_files(SF_PRIVATE * psf)517 psf_init_files (SF_PRIVATE *psf)
518 { psf->file.filedes = -1 ;
519 psf->rsrc.filedes = -1 ;
520 psf->file.savedes = -1 ;
521 } /* psf_init_files */
522
523 void
psf_use_rsrc(SF_PRIVATE * psf,int on_off)524 psf_use_rsrc (SF_PRIVATE *psf, int on_off)
525 {
526 if (on_off)
527 { if (psf->file.filedes != psf->rsrc.filedes)
528 { psf->file.savedes = psf->file.filedes ;
529 psf->file.filedes = psf->rsrc.filedes ;
530 } ;
531 }
532 else if (psf->file.filedes == psf->rsrc.filedes)
533 psf->file.filedes = psf->file.savedes ;
534
535 return ;
536 } /* psf_use_rsrc */
537
538 static int
psf_open_fd(PSF_FILE * pfile)539 psf_open_fd (PSF_FILE * pfile)
540 { int fd, oflag, mode ;
541
542 /*
543 ** Sanity check. If everything is OK, this test and the printfs will
544 ** be optimised out. This is meant to catch the problems caused by
545 ** "sfconfig.h" being included after <stdio.h>.
546 */
547 if (sizeof (sf_count_t) != 8)
548 { puts ("\n\n*** Fatal error : sizeof (sf_count_t) != 8") ;
549 puts ("*** This means that libsndfile was not configured correctly.\n") ;
550 exit (1) ;
551 } ;
552
553 switch (pfile->mode)
554 { case SFM_READ :
555 oflag = O_RDONLY | O_BINARY ;
556 mode = 0 ;
557 break ;
558
559 case SFM_WRITE :
560 oflag = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY ;
561 mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ;
562 break ;
563
564 case SFM_RDWR :
565 oflag = O_RDWR | O_CREAT | O_BINARY ;
566 mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ;
567 break ;
568
569 default :
570 return - SFE_BAD_OPEN_MODE ;
571 break ;
572 } ;
573
574 if (mode == 0)
575 fd = open (pfile->path.c, oflag) ;
576 else
577 fd = open (pfile->path.c, oflag, mode) ;
578
579 return fd ;
580 } /* psf_open_fd */
581
582 static void
psf_log_syserr(SF_PRIVATE * psf,int error)583 psf_log_syserr (SF_PRIVATE *psf, int error)
584 {
585 /* Only log an error if no error has been set yet. */
586 if (psf->error == 0)
587 { psf->error = SFE_SYSTEM ;
588 snprintf (psf->syserr, sizeof (psf->syserr), "System error : %s.", strerror (error)) ;
589 } ;
590
591 return ;
592 } /* psf_log_syserr */
593
594 void
psf_fsync(SF_PRIVATE * psf)595 psf_fsync (SF_PRIVATE *psf)
596 {
597 #if HAVE_FSYNC
598 if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
599 fsync (psf->file.filedes) ;
600 #else
601 psf = NULL ;
602 #endif
603 } /* psf_fsync */
604
605 #elif USE_WINDOWS_API
606
607 /* Win32 file i/o functions implemented using native Win32 API */
608
609 #ifndef WINAPI_PARTITION_SYSTEM
610 #define WINAPI_PARTITION_SYSTEM 0
611 #endif
612
613 static int psf_close_handle (HANDLE handle) ;
614 static HANDLE psf_open_handle (PSF_FILE * pfile) ;
615 static sf_count_t psf_get_filelen_handle (HANDLE handle) ;
616
617 /* USE_WINDOWS_API */ int
psf_fopen(SF_PRIVATE * psf)618 psf_fopen (SF_PRIVATE *psf)
619 {
620 psf->error = 0 ;
621 psf->file.handle = psf_open_handle (&psf->file) ;
622
623 if (psf->file.handle == NULL)
624 psf_log_syserr (psf, GetLastError ()) ;
625
626 return psf->error ;
627 } /* psf_fopen */
628
629 /* USE_WINDOWS_API */ int
psf_fclose(SF_PRIVATE * psf)630 psf_fclose (SF_PRIVATE *psf)
631 { int retval ;
632
633 if (psf->virtual_io)
634 return 0 ;
635
636 if (psf->file.do_not_close_descriptor)
637 { psf->file.handle = NULL ;
638 return 0 ;
639 } ;
640
641 if ((retval = psf_close_handle (psf->file.handle)) == -1)
642 psf_log_syserr (psf, GetLastError ()) ;
643
644 psf->file.handle = NULL ;
645
646 return retval ;
647 } /* psf_fclose */
648
649 /* USE_WINDOWS_API */ int
psf_open_rsrc(SF_PRIVATE * psf)650 psf_open_rsrc (SF_PRIVATE *psf)
651 {
652 if (psf->rsrc.handle != NULL)
653 return 0 ;
654
655 /* Test for MacOSX style resource fork on HPFS or HPFS+ filesystems. */
656 snprintf (psf->rsrc.path.c, sizeof (psf->rsrc.path.c), "%s/rsrc", psf->file.path.c) ;
657 psf->error = SFE_NO_ERROR ;
658 if ((psf->rsrc.handle = psf_open_handle (&psf->rsrc)) != NULL)
659 { psf->rsrclength = psf_get_filelen_handle (psf->rsrc.handle) ;
660 return SFE_NO_ERROR ;
661 } ;
662
663 /*
664 ** Now try for a resource fork stored as a separate file in the same
665 ** directory, but preceded with a dot underscore.
666 */
667 snprintf (psf->rsrc.path.c, sizeof (psf->rsrc.path.c), "%s._%s", psf->file.dir.c, psf->file.name.c) ;
668 psf->error = SFE_NO_ERROR ;
669 if ((psf->rsrc.handle = psf_open_handle (&psf->rsrc)) != NULL)
670 { psf->rsrclength = psf_get_filelen_handle (psf->rsrc.handle) ;
671 return SFE_NO_ERROR ;
672 } ;
673
674 /*
675 ** Now try for a resource fork stored in a separate file in the
676 ** .AppleDouble/ directory.
677 */
678 snprintf (psf->rsrc.path.c, sizeof (psf->rsrc.path.c), "%s.AppleDouble/%s", psf->file.dir.c, psf->file.name.c) ;
679 psf->error = SFE_NO_ERROR ;
680 if ((psf->rsrc.handle = psf_open_handle (&psf->rsrc)) != NULL)
681 { psf->rsrclength = psf_get_filelen_handle (psf->rsrc.handle) ;
682 return SFE_NO_ERROR ;
683 } ;
684
685 /* No resource file found. */
686 if (psf->rsrc.handle == NULL)
687 psf_log_syserr (psf, GetLastError ()) ;
688
689 psf->rsrc.handle = NULL ;
690
691 return psf->error ;
692 } /* psf_open_rsrc */
693
694 /* USE_WINDOWS_API */ sf_count_t
psf_get_filelen(SF_PRIVATE * psf)695 psf_get_filelen (SF_PRIVATE *psf)
696 { sf_count_t filelen ;
697
698 if (psf->virtual_io)
699 return psf->vio.get_filelen (psf->vio_user_data) ;
700
701 filelen = psf_get_filelen_handle (psf->file.handle) ;
702
703 if (filelen == -1)
704 { psf_log_syserr (psf, errno) ;
705 return (sf_count_t) -1 ;
706 } ;
707
708 if (filelen == -SFE_BAD_STAT_SIZE)
709 { psf->error = SFE_BAD_STAT_SIZE ;
710 return (sf_count_t) -1 ;
711 } ;
712
713 switch (psf->file.mode)
714 { case SFM_WRITE :
715 filelen = filelen - psf->fileoffset ;
716 break ;
717
718 case SFM_READ :
719 if (psf->fileoffset > 0 && psf->filelength > 0)
720 filelen = psf->filelength ;
721 break ;
722
723 case SFM_RDWR :
724 /*
725 ** Cannot open embedded files SFM_RDWR so we don't need to
726 ** subtract psf->fileoffset. We already have the answer we
727 ** need.
728 */
729 break ;
730
731 default :
732 /* Shouldn't be here, so return error. */
733 filelen = -1 ;
734 } ;
735
736 return filelen ;
737 } /* psf_get_filelen */
738
739 /* USE_WINDOWS_API */ void
psf_init_files(SF_PRIVATE * psf)740 psf_init_files (SF_PRIVATE *psf)
741 { psf->file.handle = NULL ;
742 psf->rsrc.handle = NULL ;
743 psf->file.hsaved = NULL ;
744 } /* psf_init_files */
745
746 /* USE_WINDOWS_API */ void
psf_use_rsrc(SF_PRIVATE * psf,int on_off)747 psf_use_rsrc (SF_PRIVATE *psf, int on_off)
748 {
749 if (on_off)
750 { if (psf->file.handle != psf->rsrc.handle)
751 { psf->file.hsaved = psf->file.handle ;
752 psf->file.handle = psf->rsrc.handle ;
753 } ;
754 }
755 else if (psf->file.handle == psf->rsrc.handle)
756 psf->file.handle = psf->file.hsaved ;
757
758 return ;
759 } /* psf_use_rsrc */
760
761 /* USE_WINDOWS_API */ static HANDLE
psf_open_handle(PSF_FILE * pfile)762 psf_open_handle (PSF_FILE * pfile)
763 { DWORD dwDesiredAccess ;
764 DWORD dwShareMode ;
765 DWORD dwCreationDistribution ;
766 HANDLE handle ;
767
768 switch (pfile->mode)
769 { case SFM_READ :
770 dwDesiredAccess = GENERIC_READ ;
771 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ;
772 dwCreationDistribution = OPEN_EXISTING ;
773 break ;
774
775 case SFM_WRITE :
776 dwDesiredAccess = GENERIC_WRITE ;
777 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ;
778 dwCreationDistribution = CREATE_ALWAYS ;
779 break ;
780
781 case SFM_RDWR :
782 dwDesiredAccess = GENERIC_READ | GENERIC_WRITE ;
783 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ;
784 dwCreationDistribution = OPEN_ALWAYS ;
785 break ;
786
787 default :
788 return NULL ;
789 } ;
790
791 #if defined (WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
792 if (!pfile->use_wchar)
793 return NULL ;
794
795 CREATEFILE2_EXTENDED_PARAMETERS cfParams = { 0 } ;
796 cfParams.dwSize = sizeof (CREATEFILE2_EXTENDED_PARAMETERS) ;
797 cfParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL ;
798
799 handle = CreateFile2 (pfile->path.wc, dwDesiredAccess, dwShareMode, dwCreationDistribution, &cfParams) ;
800
801 if (handle == INVALID_HANDLE_VALUE)
802 return NULL ;
803
804 return handle ;
805 #else
806 if (pfile->use_wchar)
807 handle = CreateFileW (
808 pfile->path.wc, /* pointer to name of the file */
809 dwDesiredAccess, /* access (read-write) mode */
810 dwShareMode, /* share mode */
811 0, /* pointer to security attributes */
812 dwCreationDistribution, /* how to create */
813 FILE_ATTRIBUTE_NORMAL, /* file attributes (could use FILE_FLAG_SEQUENTIAL_SCAN) */
814 NULL /* handle to file with attributes to copy */
815 ) ;
816 else
817 handle = CreateFileA (
818 pfile->path.c, /* pointer to name of the file */
819 dwDesiredAccess, /* access (read-write) mode */
820 dwShareMode, /* share mode */
821 0, /* pointer to security attributes */
822 dwCreationDistribution, /* how to create */
823 FILE_ATTRIBUTE_NORMAL, /* file attributes (could use FILE_FLAG_SEQUENTIAL_SCAN) */
824 NULL /* handle to file with attributes to copy */
825 ) ;
826
827 if (handle == INVALID_HANDLE_VALUE)
828 return NULL ;
829
830 return handle ;
831 #endif
832 } /* psf_open_handle */
833
834 /* USE_WINDOWS_API */ static void
psf_log_syserr(SF_PRIVATE * psf,int error)835 psf_log_syserr (SF_PRIVATE *psf, int error)
836 { LPVOID lpMsgBuf ;
837
838 /* Only log an error if no error has been set yet. */
839 if (psf->error == 0)
840 { psf->error = SFE_SYSTEM ;
841
842 FormatMessage (
843 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
844 NULL,
845 error,
846 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
847 (LPTSTR) &lpMsgBuf,
848 0,
849 NULL
850 ) ;
851
852 snprintf (psf->syserr, sizeof (psf->syserr), "System error : %s", (char*) lpMsgBuf) ;
853 LocalFree (lpMsgBuf) ;
854 } ;
855
856 return ;
857 } /* psf_log_syserr */
858
859
860 /* USE_WINDOWS_API */ int
psf_close_rsrc(SF_PRIVATE * psf)861 psf_close_rsrc (SF_PRIVATE *psf)
862 { psf_close_handle (psf->rsrc.handle) ;
863 psf->rsrc.handle = NULL ;
864 return 0 ;
865 } /* psf_close_rsrc */
866
867
868 /* USE_WINDOWS_API */ int
psf_set_stdio(SF_PRIVATE * psf)869 psf_set_stdio (SF_PRIVATE *psf)
870 { HANDLE handle = NULL ;
871 int error = 0 ;
872
873 switch (psf->file.mode)
874 { case SFM_RDWR :
875 error = SFE_OPEN_PIPE_RDWR ;
876 break ;
877
878 case SFM_READ :
879 handle = GetStdHandle (STD_INPUT_HANDLE) ;
880 psf->file.do_not_close_descriptor = 1 ;
881 break ;
882
883 case SFM_WRITE :
884 handle = GetStdHandle (STD_OUTPUT_HANDLE) ;
885 psf->file.do_not_close_descriptor = 1 ;
886 break ;
887
888 default :
889 error = SFE_BAD_OPEN_MODE ;
890 break ;
891 } ;
892
893 psf->file.handle = handle ;
894 psf->filelength = 0 ;
895
896 return error ;
897 } /* psf_set_stdio */
898
899 /* USE_WINDOWS_API */ void
psf_set_file(SF_PRIVATE * psf,int fd)900 psf_set_file (SF_PRIVATE *psf, int fd)
901 { HANDLE handle ;
902 intptr_t osfhandle ;
903
904 osfhandle = _get_osfhandle (fd) ;
905 handle = (HANDLE) osfhandle ;
906
907 psf->file.handle = handle ;
908 } /* psf_set_file */
909
910 /* USE_WINDOWS_API */ int
psf_file_valid(SF_PRIVATE * psf)911 psf_file_valid (SF_PRIVATE *psf)
912 { if (psf->file.handle == NULL)
913 return SF_FALSE ;
914 if (psf->file.handle == INVALID_HANDLE_VALUE)
915 return SF_FALSE ;
916 return SF_TRUE ;
917 } /* psf_set_file */
918
919 /* USE_WINDOWS_API */ sf_count_t
psf_fseek(SF_PRIVATE * psf,sf_count_t offset,int whence)920 psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence)
921 { sf_count_t new_position ;
922 LARGE_INTEGER liDistanceToMove, liNewFilePointer ;
923 DWORD dwMoveMethod ;
924 BOOL fResult ;
925 DWORD dwError ;
926
927 if (psf->virtual_io)
928 return psf->vio.seek (offset, whence, psf->vio_user_data) ;
929
930 switch (whence)
931 { case SEEK_SET :
932 offset += psf->fileoffset ;
933 dwMoveMethod = FILE_BEGIN ;
934 break ;
935
936 case SEEK_END :
937 dwMoveMethod = FILE_END ;
938 break ;
939
940 default :
941 dwMoveMethod = FILE_CURRENT ;
942 break ;
943 } ;
944
945 liDistanceToMove.QuadPart = offset ;
946
947 fResult = SetFilePointerEx (psf->file.handle, liDistanceToMove, &liNewFilePointer, dwMoveMethod) ;
948
949 if (fResult == FALSE)
950 dwError = GetLastError () ;
951 else
952 dwError = NO_ERROR ;
953
954 if (dwError != NO_ERROR)
955 { psf_log_syserr (psf, dwError) ;
956 return -1 ;
957 } ;
958
959 new_position = liNewFilePointer.QuadPart - psf->fileoffset ;
960
961 return new_position ;
962 } /* psf_fseek */
963
964 /* USE_WINDOWS_API */ sf_count_t
psf_fread(void * ptr,sf_count_t bytes,sf_count_t items,SF_PRIVATE * psf)965 psf_fread (void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf)
966 { sf_count_t total = 0 ;
967 ssize_t count ;
968 DWORD dwNumberOfBytesRead ;
969
970 if (psf->virtual_io)
971 return psf->vio.read (ptr, bytes*items, psf->vio_user_data) / bytes ;
972
973 items *= bytes ;
974
975 /* Do this check after the multiplication above. */
976 if (items <= 0)
977 return 0 ;
978
979 while (items > 0)
980 { /* Break the writes down to a sensible size. */
981 count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ;
982
983 if (ReadFile (psf->file.handle, ((char*) ptr) + total, count, &dwNumberOfBytesRead, 0) == 0)
984 { psf_log_syserr (psf, GetLastError ()) ;
985 break ;
986 }
987 else
988 count = dwNumberOfBytesRead ;
989
990 if (count == 0)
991 break ;
992
993 total += count ;
994 items -= count ;
995 } ;
996
997 if (psf->is_pipe)
998 psf->pipeoffset += total ;
999
1000 return total / bytes ;
1001 } /* psf_fread */
1002
1003 /* USE_WINDOWS_API */ sf_count_t
psf_fwrite(const void * ptr,sf_count_t bytes,sf_count_t items,SF_PRIVATE * psf)1004 psf_fwrite (const void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf)
1005 { sf_count_t total = 0 ;
1006 ssize_t count ;
1007 DWORD dwNumberOfBytesWritten ;
1008
1009 if (psf->virtual_io)
1010 return psf->vio.write (ptr, bytes * items, psf->vio_user_data) / bytes ;
1011
1012 items *= bytes ;
1013
1014 /* Do this check after the multiplication above. */
1015 if (items <= 0)
1016 return 0 ;
1017
1018 while (items > 0)
1019 { /* Break the writes down to a sensible size. */
1020 count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ;
1021
1022 if (WriteFile (psf->file.handle, ((const char*) ptr) + total, count, &dwNumberOfBytesWritten, 0) == 0)
1023 { psf_log_syserr (psf, GetLastError ()) ;
1024 break ;
1025 }
1026 else
1027 count = dwNumberOfBytesWritten ;
1028
1029 if (count == 0)
1030 break ;
1031
1032 total += count ;
1033 items -= count ;
1034 } ;
1035
1036 if (psf->is_pipe)
1037 psf->pipeoffset += total ;
1038
1039 return total / bytes ;
1040 } /* psf_fwrite */
1041
1042 /* USE_WINDOWS_API */ sf_count_t
psf_ftell(SF_PRIVATE * psf)1043 psf_ftell (SF_PRIVATE *psf)
1044 { sf_count_t pos ;
1045 LARGE_INTEGER liDistanceToMove, liNewFilePointer ;
1046 BOOL fResult ;
1047 DWORD dwError ;
1048
1049 if (psf->virtual_io)
1050 return psf->vio.tell (psf->vio_user_data) ;
1051
1052 if (psf->is_pipe)
1053 return psf->pipeoffset ;
1054
1055 liDistanceToMove.QuadPart = 0 ;
1056
1057 fResult = SetFilePointerEx (psf->file.handle, liDistanceToMove, &liNewFilePointer, FILE_CURRENT) ;
1058
1059 if (fResult == FALSE)
1060 dwError = GetLastError () ;
1061 else
1062 dwError = NO_ERROR ;
1063
1064 if (dwError != NO_ERROR)
1065 { psf_log_syserr (psf, dwError) ;
1066 return -1 ;
1067 } ;
1068
1069 pos = liNewFilePointer.QuadPart ;
1070
1071 return pos - psf->fileoffset ;
1072 } /* psf_ftell */
1073
1074 /* USE_WINDOWS_API */ static int
psf_close_handle(HANDLE handle)1075 psf_close_handle (HANDLE handle)
1076 { if (handle == NULL)
1077 return 0 ;
1078
1079 if (CloseHandle (handle) == 0)
1080 return -1 ;
1081
1082 return 0 ;
1083 } /* psf_close_handle */
1084
1085 /* USE_WINDOWS_API */ sf_count_t
psf_fgets(char * buffer,sf_count_t bufsize,SF_PRIVATE * psf)1086 psf_fgets (char *buffer, sf_count_t bufsize, SF_PRIVATE *psf)
1087 { sf_count_t k = 0 ;
1088 sf_count_t count ;
1089 DWORD dwNumberOfBytesRead ;
1090
1091 while (k < bufsize - 1)
1092 { if (ReadFile (psf->file.handle, &(buffer [k]), 1, &dwNumberOfBytesRead, 0) == 0)
1093 { psf_log_syserr (psf, GetLastError ()) ;
1094 break ;
1095 }
1096 else
1097 { count = dwNumberOfBytesRead ;
1098 /* note that we only check for '\n' not other line endings such as CRLF */
1099 if (count == 0 || buffer [k++] == '\n')
1100 break ;
1101 } ;
1102 } ;
1103
1104 buffer [k] = 0 ;
1105
1106 return k ;
1107 } /* psf_fgets */
1108
1109 /* USE_WINDOWS_API */ int
psf_is_pipe(SF_PRIVATE * psf)1110 psf_is_pipe (SF_PRIVATE *psf)
1111 {
1112 if (psf->virtual_io)
1113 return SF_FALSE ;
1114
1115 if (GetFileType (psf->file.handle) == FILE_TYPE_DISK)
1116 return SF_FALSE ;
1117
1118 /* Default to maximum safety. */
1119 return SF_TRUE ;
1120 } /* psf_is_pipe */
1121
1122 /* USE_WINDOWS_API */ sf_count_t
psf_get_filelen_handle(HANDLE handle)1123 psf_get_filelen_handle (HANDLE handle)
1124 { sf_count_t filelen ;
1125 LARGE_INTEGER liFileSize ;
1126 BOOL fResult ;
1127 DWORD dwError = NO_ERROR ;
1128
1129 fResult = GetFileSizeEx (handle, &liFileSize) ;
1130
1131 if (fResult == FALSE)
1132 dwError = GetLastError () ;
1133
1134 if (dwError != NO_ERROR)
1135 return (sf_count_t) -1 ;
1136
1137 filelen = liFileSize.QuadPart ;
1138
1139 return filelen ;
1140 } /* psf_get_filelen_handle */
1141
1142 /* USE_WINDOWS_API */ void
psf_fsync(SF_PRIVATE * psf)1143 psf_fsync (SF_PRIVATE *psf)
1144 { FlushFileBuffers (psf->file.handle) ;
1145 } /* psf_fsync */
1146
1147
1148 /* USE_WINDOWS_API */ int
psf_ftruncate(SF_PRIVATE * psf,sf_count_t len)1149 psf_ftruncate (SF_PRIVATE *psf, sf_count_t len)
1150 { int retval = 0 ;
1151 LARGE_INTEGER liDistanceToMove ;
1152 BOOL fResult ;
1153 DWORD dwError = NO_ERROR ;
1154
1155 /* This implementation trashes the current file position.
1156 ** should it save and restore it? what if the current position is past
1157 ** the new end of file?
1158 */
1159
1160 /* Returns 0 on success, non-zero on failure. */
1161 if (len < 0)
1162 return 1 ;
1163
1164 liDistanceToMove.QuadPart = (sf_count_t) len ;
1165
1166 fResult = SetFilePointerEx (psf->file.handle, liDistanceToMove, NULL, FILE_BEGIN) ;
1167
1168 if (fResult == FALSE)
1169 dwError = GetLastError () ;
1170
1171 if (dwError != NO_ERROR)
1172 { retval = -1 ;
1173 psf_log_syserr (psf, dwError) ;
1174 }
1175 else
1176 { /* Note: when SetEndOfFile is used to extend a file, the contents of the
1177 ** new portion of the file is undefined. This is unlike chsize(),
1178 ** which guarantees that the new portion of the file will be zeroed.
1179 ** Not sure if this is important or not.
1180 */
1181 if (SetEndOfFile (psf->file.handle) == 0)
1182 { retval = -1 ;
1183 psf_log_syserr (psf, GetLastError ()) ;
1184 } ;
1185 } ;
1186
1187 return retval ;
1188 } /* psf_ftruncate */
1189
1190
1191 #else
1192 /* Win32 file i/o functions implemented using Unix-style file i/o API */
1193
1194 /* Win32 has a 64 file offset seek function:
1195 **
1196 ** __int64 _lseeki64 (int handle, __int64 offset, int origin) ;
1197 **
1198 ** It also has a 64 bit fstat function:
1199 **
1200 ** int fstati64 (int, struct _stati64) ;
1201 **
1202 ** but the fscking thing doesn't work!!!!! The file size parameter returned
1203 ** by this function is only valid up until more data is written at the end of
1204 ** the file. That makes this function completely 100% useless.
1205 */
1206
1207 #include <io.h>
1208 #include <direct.h>
1209
1210 /* Win32 */ int
psf_fopen(SF_PRIVATE * psf,const char * pathname,int open_mode)1211 psf_fopen (SF_PRIVATE *psf, const char *pathname, int open_mode)
1212 { int oflag, mode ;
1213
1214 switch (open_mode)
1215 { case SFM_READ :
1216 oflag = O_RDONLY | O_BINARY ;
1217 mode = 0 ;
1218 break ;
1219
1220 case SFM_WRITE :
1221 oflag = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY ;
1222 mode = S_IRUSR | S_IWUSR | S_IRGRP ;
1223 break ;
1224
1225 case SFM_RDWR :
1226 oflag = O_RDWR | O_CREAT | O_BINARY ;
1227 mode = S_IRUSR | S_IWUSR | S_IRGRP ;
1228 break ;
1229
1230 default :
1231 psf->error = SFE_BAD_OPEN_MODE ;
1232 return -1 ;
1233 break ;
1234 } ;
1235
1236 if (mode == 0)
1237 psf->file.filedes = open (pathname, oflag) ;
1238 else
1239 psf->file.filedes = open (pathname, oflag, mode) ;
1240
1241 if (psf->file.filedes == -1)
1242 psf_log_syserr (psf, errno) ;
1243
1244 return psf->file.filedes ;
1245 } /* psf_fopen */
1246
1247 /* Win32 */ sf_count_t
psf_fseek(SF_PRIVATE * psf,sf_count_t offset,int whence)1248 psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence)
1249 { sf_count_t new_position ;
1250
1251 if (psf->virtual_io)
1252 return psf->vio.seek (offset, whence, psf->vio_user_data) ;
1253
1254 switch (whence)
1255 { case SEEK_SET :
1256 offset += psf->fileoffset ;
1257 break ;
1258
1259 case SEEK_END :
1260 if (psf->file.mode == SFM_WRITE)
1261 { new_position = _lseeki64 (psf->file.filedes, offset, whence) ;
1262
1263 if (new_position < 0)
1264 psf_log_syserr (psf, errno) ;
1265
1266 return new_position - psf->fileoffset ;
1267 } ;
1268
1269 /* Transform SEEK_END into a SEEK_SET, ie find the file
1270 ** length add the requested offset (should be <= 0) to
1271 ** get the offset wrt the start of file.
1272 */
1273 whence = SEEK_SET ;
1274 offset = _lseeki64 (psf->file.filedes, 0, SEEK_END) + offset ;
1275 break ;
1276
1277 default :
1278 /* No need to do anything about SEEK_CUR. */
1279 break ;
1280 } ;
1281
1282 /*
1283 ** Bypass weird Win32-ism if necessary.
1284 ** _lseeki64() returns an "invalid parameter" error if called with the
1285 ** offset == 0 and whence == SEEK_CUR.
1286 *** Use the _telli64() function instead.
1287 */
1288 if (offset == 0 && whence == SEEK_CUR)
1289 new_position = _telli64 (psf->file.filedes) ;
1290 else
1291 new_position = _lseeki64 (psf->file.filedes, offset, whence) ;
1292
1293 if (new_position < 0)
1294 psf_log_syserr (psf, errno) ;
1295
1296 new_position -= psf->fileoffset ;
1297
1298 return new_position ;
1299 } /* psf_fseek */
1300
1301 /* Win32 */ sf_count_t
psf_fread(void * ptr,sf_count_t bytes,sf_count_t items,SF_PRIVATE * psf)1302 psf_fread (void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf)
1303 { sf_count_t total = 0 ;
1304 ssize_t count ;
1305
1306 if (psf->virtual_io)
1307 return psf->vio.read (ptr, bytes*items, psf->vio_user_data) / bytes ;
1308
1309 items *= bytes ;
1310
1311 /* Do this check after the multiplication above. */
1312 if (items <= 0)
1313 return 0 ;
1314
1315 while (items > 0)
1316 { /* Break the writes down to a sensible size. */
1317 count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ;
1318
1319 count = read (psf->file.filedes, ((char*) ptr) + total, (size_t) count) ;
1320
1321 if (count == -1)
1322 { if (errno == EINTR)
1323 continue ;
1324
1325 psf_log_syserr (psf, errno) ;
1326 break ;
1327 } ;
1328
1329 if (count == 0)
1330 break ;
1331
1332 total += count ;
1333 items -= count ;
1334 } ;
1335
1336 return total / bytes ;
1337 } /* psf_fread */
1338
1339 /* Win32 */ sf_count_t
psf_fwrite(const void * ptr,sf_count_t bytes,sf_count_t items,SF_PRIVATE * psf)1340 psf_fwrite (const void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf)
1341 { sf_count_t total = 0 ;
1342 ssize_t count ;
1343
1344 if (psf->virtual_io)
1345 return psf->vio.write (ptr, bytes*items, psf->vio_user_data) / bytes ;
1346
1347 items *= bytes ;
1348
1349 /* Do this check after the multiplication above. */
1350 if (items <= 0)
1351 return 0 ;
1352
1353 while (items > 0)
1354 { /* Break the writes down to a sensible size. */
1355 count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : items ;
1356
1357 count = write (psf->file.filedes, ((const char*) ptr) + total, count) ;
1358
1359 if (count == -1)
1360 { if (errno == EINTR)
1361 continue ;
1362
1363 psf_log_syserr (psf, errno) ;
1364 break ;
1365 } ;
1366
1367 if (count == 0)
1368 break ;
1369
1370 total += count ;
1371 items -= count ;
1372 } ;
1373
1374 return total / bytes ;
1375 } /* psf_fwrite */
1376
1377 /* Win32 */ sf_count_t
psf_ftell(SF_PRIVATE * psf)1378 psf_ftell (SF_PRIVATE *psf)
1379 { sf_count_t pos ;
1380
1381 if (psf->virtual_io)
1382 return psf->vio.tell (psf->vio_user_data) ;
1383
1384 pos = _telli64 (psf->file.filedes) ;
1385
1386 if (pos == ((sf_count_t) -1))
1387 { psf_log_syserr (psf, errno) ;
1388 return -1 ;
1389 } ;
1390
1391 return pos - psf->fileoffset ;
1392 } /* psf_ftell */
1393
1394 /* Win32 */ int
psf_fclose(SF_PRIVATE * psf)1395 psf_fclose (SF_PRIVATE *psf)
1396 { int retval ;
1397
1398 while ((retval = close (psf->file.filedes)) == -1 && errno == EINTR)
1399 /* Do nothing. */ ;
1400
1401 if (retval == -1)
1402 psf_log_syserr (psf, errno) ;
1403
1404 psf->file.filedes = -1 ;
1405
1406 return retval ;
1407 } /* psf_fclose */
1408
1409 /* Win32 */ sf_count_t
psf_fgets(char * buffer,sf_count_t bufsize,SF_PRIVATE * psf)1410 psf_fgets (char *buffer, sf_count_t bufsize, SF_PRIVATE *psf)
1411 { sf_count_t k = 0 ;
1412 sf_count_t count ;
1413
1414 while (k < bufsize - 1)
1415 { count = read (psf->file.filedes, &(buffer [k]), 1) ;
1416
1417 if (count == -1)
1418 { if (errno == EINTR)
1419 continue ;
1420
1421 psf_log_syserr (psf, errno) ;
1422 break ;
1423 } ;
1424
1425 if (count == 0 || buffer [k++] == '\n')
1426 break ;
1427 } ;
1428
1429 buffer [k] = 0 ;
1430
1431 return k ;
1432 } /* psf_fgets */
1433
1434 /* Win32 */ int
psf_is_pipe(SF_PRIVATE * psf)1435 psf_is_pipe (SF_PRIVATE *psf)
1436 { struct stat statbuf ;
1437
1438 if (psf->virtual_io)
1439 return SF_FALSE ;
1440
1441 /* Not sure if this works. */
1442 if (fstat (psf->file.filedes, &statbuf) == -1)
1443 { psf_log_syserr (psf, errno) ;
1444 /* Default to maximum safety. */
1445 return SF_TRUE ;
1446 } ;
1447
1448 /* These macros are defined in Win32/unistd.h. */
1449 if (S_ISFIFO (statbuf.st_mode) || S_ISSOCK (statbuf.st_mode))
1450 return SF_TRUE ;
1451
1452 return SF_FALSE ;
1453 } /* psf_checkpipe */
1454
1455 /* Win32 */ sf_count_t
psf_get_filelen(SF_PRIVATE * psf)1456 psf_get_filelen (SF_PRIVATE *psf)
1457 {
1458 #if 0
1459 /*
1460 ** Windoze is SOOOOO FUCKED!!!!!!!
1461 ** This code should work but doesn't. Why?
1462 ** Code below does work.
1463 */
1464 struct _stati64 statbuf ;
1465
1466 if (_fstati64 (psf->file.filedes, &statbuf))
1467 { psf_log_syserr (psf, errno) ;
1468 return (sf_count_t) -1 ;
1469 } ;
1470
1471 return statbuf.st_size ;
1472 #else
1473 sf_count_t current, filelen ;
1474
1475 if (psf->virtual_io)
1476 return psf->vio.get_filelen (psf->vio_user_data) ;
1477
1478 if ((current = _telli64 (psf->file.filedes)) < 0)
1479 { psf_log_syserr (psf, errno) ;
1480 return (sf_count_t) -1 ;
1481 } ;
1482
1483 /*
1484 ** Lets face it, windoze if FUBAR!!!
1485 **
1486 ** For some reason, I have to call _lseeki64() TWICE to get to the
1487 ** end of the file.
1488 **
1489 ** This might have been avoided if windows had implemented the POSIX
1490 ** standard function fsync() but NO, that would have been too easy.
1491 **
1492 ** I am VERY close to saying that windoze will no longer be supported
1493 ** by libsndfile and changing the license to GPL at the same time.
1494 */
1495
1496 _lseeki64 (psf->file.filedes, 0, SEEK_END) ;
1497
1498 if ((filelen = _lseeki64 (psf->file.filedes, 0, SEEK_END)) < 0)
1499 { psf_log_syserr (psf, errno) ;
1500 return (sf_count_t) -1 ;
1501 } ;
1502
1503 if (filelen > current)
1504 _lseeki64 (psf->file.filedes, current, SEEK_SET) ;
1505
1506 switch (psf->file.mode)
1507 { case SFM_WRITE :
1508 filelen = filelen - psf->fileoffset ;
1509 break ;
1510
1511 case SFM_READ :
1512 if (psf->fileoffset > 0 && psf->filelength > 0)
1513 filelen = psf->filelength ;
1514 break ;
1515
1516 case SFM_RDWR :
1517 /*
1518 ** Cannot open embedded files SFM_RDWR so we don't need to
1519 ** subtract psf->fileoffset. We already have the answer we
1520 ** need.
1521 */
1522 break ;
1523
1524 default :
1525 filelen = 0 ;
1526 } ;
1527
1528 return filelen ;
1529 #endif
1530 } /* psf_get_filelen */
1531
1532 /* Win32 */ int
psf_ftruncate(SF_PRIVATE * psf,sf_count_t len)1533 psf_ftruncate (SF_PRIVATE *psf, sf_count_t len)
1534 { int retval ;
1535
1536 /* Returns 0 on success, non-zero on failure. */
1537 if (len < 0)
1538 return 1 ;
1539
1540 /* The global village idiots at micorsoft decided to implement
1541 ** nearly all the required 64 bit file offset functions except
1542 ** for one, truncate. The fscking morons!
1543 **
1544 ** This is not 64 bit file offset clean. Somone needs to clean
1545 ** this up.
1546 */
1547 if (len > 0x7FFFFFFF)
1548 return -1 ;
1549
1550 retval = chsize (psf->file.filedes, len) ;
1551
1552 if (retval == -1)
1553 psf_log_syserr (psf, errno) ;
1554
1555 return retval ;
1556 } /* psf_ftruncate */
1557
1558
1559 static void
psf_log_syserr(SF_PRIVATE * psf,int error)1560 psf_log_syserr (SF_PRIVATE *psf, int error)
1561 {
1562 /* Only log an error if no error has been set yet. */
1563 if (psf->error == 0)
1564 { psf->error = SFE_SYSTEM ;
1565 snprintf (psf->syserr, sizeof (psf->syserr), "System error : %s", strerror (error)) ;
1566 } ;
1567
1568 return ;
1569 } /* psf_log_syserr */
1570
1571 #endif
1572
1573