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