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