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