2 ** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
3 ** Copyright (C) 2003 Ross Bencina <rbencina@iprimus.com.au>
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.
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.
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.
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.
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.
44 #if (HAVE_DECL_S_IRGRP == 0)
45 #include <sf_unistd.h>
56 #define SENSIBLE_SIZE (0x40000000)
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.
67 static void psf_log_syserr (SF_PRIVATE
*psf
, int error
) ;
69 #if (USE_WINDOWS_API == 0)
71 /*------------------------------------------------------------------------------
72 ** Win32 stuff at the bottom of the file. Unix and other sensible OSes here.
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
) ;
80 psf_fopen (SF_PRIVATE
*psf
)
83 psf
->file
.filedes
= psf_open_fd (&psf
->file
) ;
85 if (psf
->file
.filedes
== - SFE_BAD_OPEN_MODE
)
86 { psf
->error
= SFE_BAD_OPEN_MODE
;
87 psf
->file
.filedes
= -1 ;
91 if (psf
->file
.filedes
== -1)
92 psf_log_syserr (psf
, errno
) ;
98 psf_fclose (SF_PRIVATE
*psf
)
104 if (psf
->file
.do_not_close_descriptor
)
105 { psf
->file
.filedes
= -1 ;
109 if ((retval
= psf_close_fd (psf
->file
.filedes
)) == -1)
110 psf_log_syserr (psf
, errno
) ;
112 psf
->file
.filedes
= -1 ;
118 psf_open_rsrc (SF_PRIVATE
*psf
)
120 if (psf
->rsrc
.filedes
> 0)
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 ;
134 if (psf
->rsrc
.filedes
== - SFE_BAD_OPEN_MODE
)
135 { psf
->error
= SFE_BAD_OPEN_MODE
;
140 ** Now try for a resource fork stored as a separate file in the same
141 ** directory, but preceded with a dot underscore.
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
;
151 ** Now try for a resource fork stored in a separate file in the
152 ** .AppleDouble/ directory.
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
;
161 /* No resource file found. */
162 if (psf
->rsrc
.filedes
== -1)
163 psf_log_syserr (psf
, errno
) ;
165 psf
->rsrc
.filedes
= -1 ;
168 } /* psf_open_rsrc */
171 psf_get_filelen (SF_PRIVATE
*psf
)
172 { sf_count_t filelen
;
175 return psf
->vio
.get_filelen (psf
->vio_user_data
) ;
177 filelen
= psf_get_filelen_fd (psf
->file
.filedes
) ;
180 { psf_log_syserr (psf
, errno
) ;
181 return (sf_count_t
) -1 ;
184 if (filelen
== -SFE_BAD_STAT_SIZE
)
185 { psf
->error
= SFE_BAD_STAT_SIZE
;
186 return (sf_count_t
) -1 ;
189 switch (psf
->file
.mode
)
191 filelen
= filelen
- psf
->fileoffset
;
195 if (psf
->fileoffset
> 0 && psf
->filelength
> 0)
196 filelen
= psf
->filelength
;
201 ** Cannot open embedded files SFM_RDWR so we don't need to
202 ** subtract psf->fileoffset. We already have the answer we
208 /* Shouldn't be here, so return error. */
213 } /* psf_get_filelen */
216 psf_close_rsrc (SF_PRIVATE
*psf
)
217 { psf_close_fd (psf
->rsrc
.filedes
) ;
218 psf
->rsrc
.filedes
= -1 ;
220 } /* psf_close_rsrc */
223 psf_set_stdio (SF_PRIVATE
*psf
)
226 switch (psf
->file
.mode
)
228 error
= SFE_OPEN_PIPE_RDWR
;
232 psf
->file
.filedes
= 0 ;
236 psf
->file
.filedes
= 1 ;
240 error
= SFE_BAD_OPEN_MODE
;
243 psf
->filelength
= 0 ;
246 } /* psf_set_stdio */
249 psf_set_file (SF_PRIVATE
*psf
, int fd
)
250 { psf
->file
.filedes
= fd
;
254 psf_file_valid (SF_PRIVATE
*psf
)
255 { return (psf
->file
.filedes
>= 0) ? SF_TRUE
: SF_FALSE
;
259 psf_fseek (SF_PRIVATE
*psf
, sf_count_t offset
, int whence
)
260 { sf_count_t current_pos
, new_position
;
263 return psf
->vio
.seek (offset
, whence
, psf
->vio_user_data
) ;
265 current_pos
= psf_ftell (psf
) ;
269 offset
+= psf
->fileoffset
;
273 if (psf
->file
.mode
== SFM_WRITE
)
274 { new_position
= lseek (psf
->file
.filedes
, offset
, whence
) ;
276 if (new_position
< 0)
277 psf_log_syserr (psf
, errno
) ;
279 return new_position
- psf
->fileoffset
;
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.
287 offset
= lseek (psf
->file
.filedes
, 0, SEEK_END
) + offset
;
291 /* Translate a SEEK_CUR into a SEEK_SET. */
292 offset
+= current_pos
;
297 /* We really should not be here. */
298 psf_log_printf (psf
, "psf_fseek : whence is %d *****.\n", whence
) ;
302 if (current_pos
!= offset
)
303 new_position
= lseek (psf
->file
.filedes
, offset
, whence
) ;
305 new_position
= offset
;
307 if (new_position
< 0)
308 psf_log_syserr (psf
, errno
) ;
310 new_position
-= psf
->fileoffset
;
312 return new_position
;
316 psf_fread (void *ptr
, sf_count_t bytes
, sf_count_t items
, SF_PRIVATE
*psf
)
317 { sf_count_t total
= 0 ;
321 return psf
->vio
.read (ptr
, bytes
*items
, psf
->vio_user_data
) / bytes
;
325 /* Do this check after the multiplication above. */
330 { /* Break the read down to a sensible size. */
331 count
= (items
> SENSIBLE_SIZE
) ? SENSIBLE_SIZE
: (ssize_t
) items
;
333 count
= read (psf
->file
.filedes
, ((char*) ptr
) + total
, (size_t) count
) ;
336 { if (errno
== EINTR
)
339 psf_log_syserr (psf
, errno
) ;
351 psf
->pipeoffset
+= total
;
353 return total
/ bytes
;
357 psf_fwrite (const void *ptr
, sf_count_t bytes
, sf_count_t items
, SF_PRIVATE
*psf
)
358 { sf_count_t total
= 0 ;
362 return psf
->vio
.write (ptr
, bytes
*items
, psf
->vio_user_data
) / bytes
;
366 /* Do this check after the multiplication above. */
371 { /* Break the writes down to a sensible size. */
372 count
= (items
> SENSIBLE_SIZE
) ? SENSIBLE_SIZE
: items
;
374 count
= write (psf
->file
.filedes
, ((const char*) ptr
) + total
, count
) ;
377 { if (errno
== EINTR
)
380 psf_log_syserr (psf
, errno
) ;
392 psf
->pipeoffset
+= total
;
394 return total
/ bytes
;
398 psf_ftell (SF_PRIVATE
*psf
)
402 return psf
->vio
.tell (psf
->vio_user_data
) ;
405 return psf
->pipeoffset
;
407 pos
= lseek (psf
->file
.filedes
, 0, SEEK_CUR
) ;
409 if (pos
== ((sf_count_t
) -1))
410 { psf_log_syserr (psf
, errno
) ;
414 return pos
- psf
->fileoffset
;
418 psf_close_fd (int fd
)
424 while ((retval
= close (fd
)) == -1 && errno
== EINTR
)
431 psf_fgets (char *buffer
, sf_count_t bufsize
, SF_PRIVATE
*psf
)
435 while (k
< bufsize
- 1)
436 { count
= read (psf
->file
.filedes
, &(buffer
[k
]), 1) ;
439 { if (errno
== EINTR
)
442 psf_log_syserr (psf
, errno
) ;
446 if (count
== 0 || buffer
[k
++] == '\n')
456 psf_is_pipe (SF_PRIVATE
*psf
)
457 { struct stat statbuf
;
462 if (fstat (psf
->file
.filedes
, &statbuf
) == -1)
463 { psf_log_syserr (psf
, errno
) ;
464 /* Default to maximum safety. */
468 if (S_ISFIFO (statbuf
.st_mode
) || S_ISSOCK (statbuf
.st_mode
))
475 psf_get_filelen_fd (int fd
)
476 { struct stat statbuf
;
480 ** If everything is OK, this will be optimised out.
482 if (sizeof (statbuf
.st_size
) == 4 && sizeof (sf_count_t
) == 8)
483 return (sf_count_t
) -SFE_BAD_STAT_SIZE
;
485 if (fstat (fd
, &statbuf
) == -1)
486 return (sf_count_t
) -1 ;
488 return statbuf
.st_size
;
489 } /* psf_get_filelen_fd */
492 psf_ftruncate (SF_PRIVATE
*psf
, sf_count_t len
)
495 /* Returns 0 on success, non-zero on failure. */
499 if ((sizeof (off_t
) < sizeof (sf_count_t
)) && len
> 0x7FFFFFFF)
502 retval
= ftruncate (psf
->file
.filedes
, len
) ;
505 psf_log_syserr (psf
, errno
) ;
508 } /* psf_ftruncate */
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 */
518 psf_use_rsrc (SF_PRIVATE
*psf
, int on_off
)
521 { if (psf
->file
.filedes
!= psf
->rsrc
.filedes
)
522 { psf
->file
.savedes
= psf
->file
.filedes
;
523 psf
->file
.filedes
= psf
->rsrc
.filedes
;
526 else if (psf
->file
.filedes
== psf
->rsrc
.filedes
)
527 psf
->file
.filedes
= psf
->file
.savedes
;
533 psf_open_fd (PSF_FILE
* pfile
)
534 { int fd
, oflag
, mode
;
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>.
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") ;
549 oflag
= O_RDONLY
| O_BINARY
;
554 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
;
555 mode
= S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
;
559 oflag
= O_RDWR
| O_CREAT
| O_BINARY
;
560 mode
= S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
;
564 return - SFE_BAD_OPEN_MODE
;
569 fd
= open (pfile
->path
.c
, oflag
) ;
571 fd
= open (pfile
->path
.c
, oflag
, mode
) ;
577 psf_log_syserr (SF_PRIVATE
*psf
, int error
)
579 /* Only log an error if no error has been set yet. */
581 { psf
->error
= SFE_SYSTEM
;
582 snprintf (psf
->syserr
, sizeof (psf
->syserr
), "System error : %s.", strerror (error
)) ;
586 } /* psf_log_syserr */
589 psf_fsync (SF_PRIVATE
*psf
)
592 if (psf
->file
.mode
== SFM_WRITE
|| psf
->file
.mode
== SFM_RDWR
)
593 fsync (psf
->file
.filedes
) ;
599 #elif USE_WINDOWS_API
601 /* Win32 file i/o functions implemented using native Win32 API */
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
) ;
610 /* USE_WINDOWS_API */ int
611 psf_fopen (SF_PRIVATE
*psf
)
614 psf
->file
.handle
= psf_open_handle (&psf
->file
) ;
616 if (psf
->file
.handle
== NULL
)
617 psf_log_syserr (psf
, GetLastError ()) ;
622 /* USE_WINDOWS_API */ int
623 psf_fclose (SF_PRIVATE
*psf
)
629 if (psf
->file
.do_not_close_descriptor
)
630 { psf
->file
.handle
= NULL
;
634 if ((retval
= psf_close_handle (psf
->file
.handle
)) == -1)
635 psf_log_syserr (psf
, GetLastError ()) ;
637 psf
->file
.handle
= NULL
;
642 /* USE_WINDOWS_API */ int
643 psf_open_rsrc (SF_PRIVATE
*psf
)
645 if (psf
->rsrc
.handle
!= NULL
)
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
;
657 ** Now try for a resource fork stored as a separate file in the same
658 ** directory, but preceded with a dot underscore.
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
;
668 ** Now try for a resource fork stored in a separate file in the
669 ** .AppleDouble/ directory.
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
;
678 /* No resource file found. */
679 if (psf
->rsrc
.handle
== NULL
)
680 psf_log_syserr (psf
, GetLastError ()) ;
682 psf
->rsrc
.handle
= NULL
;
685 } /* psf_open_rsrc */
687 /* USE_WINDOWS_API */ sf_count_t
688 psf_get_filelen (SF_PRIVATE
*psf
)
689 { sf_count_t filelen
;
692 return psf
->vio
.get_filelen (psf
->vio_user_data
) ;
694 filelen
= psf_get_filelen_handle (psf
->file
.handle
) ;
697 { psf_log_syserr (psf
, errno
) ;
698 return (sf_count_t
) -1 ;
701 if (filelen
== -SFE_BAD_STAT_SIZE
)
702 { psf
->error
= SFE_BAD_STAT_SIZE
;
703 return (sf_count_t
) -1 ;
706 switch (psf
->file
.mode
)
708 filelen
= filelen
- psf
->fileoffset
;
712 if (psf
->fileoffset
> 0 && psf
->filelength
> 0)
713 filelen
= psf
->filelength
;
718 ** Cannot open embedded files SFM_RDWR so we don't need to
719 ** subtract psf->fileoffset. We already have the answer we
725 /* Shouldn't be here, so return error. */
730 } /* psf_get_filelen */
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 */
739 /* USE_WINDOWS_API */ void
740 psf_use_rsrc (SF_PRIVATE
*psf
, int on_off
)
743 { if (psf
->file
.handle
!= psf
->rsrc
.handle
)
744 { psf
->file
.hsaved
= psf
->file
.handle
;
745 psf
->file
.handle
= psf
->rsrc
.handle
;
748 else if (psf
->file
.handle
== psf
->rsrc
.handle
)
749 psf
->file
.handle
= psf
->file
.hsaved
;
754 /* USE_WINDOWS_API */ static HANDLE
755 psf_open_handle (PSF_FILE
* pfile
)
756 { DWORD dwDesiredAccess
;
758 DWORD dwCreationDistribution
;
763 dwDesiredAccess
= GENERIC_READ
;
764 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
765 dwCreationDistribution
= OPEN_EXISTING
;
769 dwDesiredAccess
= GENERIC_WRITE
;
770 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
771 dwCreationDistribution
= CREATE_ALWAYS
;
775 dwDesiredAccess
= GENERIC_READ
| GENERIC_WRITE
;
776 dwShareMode
= FILE_SHARE_READ
| FILE_SHARE_WRITE
;
777 dwCreationDistribution
= OPEN_ALWAYS
;
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 */
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 */
805 if (handle
== INVALID_HANDLE_VALUE
)
809 } /* psf_open_handle */
811 /* USE_WINDOWS_API */ static void
812 psf_log_syserr (SF_PRIVATE
*psf
, int error
)
815 /* Only log an error if no error has been set yet. */
817 { psf
->error
= SFE_SYSTEM
;
820 FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
823 MAKELANGID (LANG_NEUTRAL
, SUBLANG_DEFAULT
),
829 snprintf (psf
->syserr
, sizeof (psf
->syserr
), "System error : %s", (char*) lpMsgBuf
) ;
830 LocalFree (lpMsgBuf
) ;
834 } /* psf_log_syserr */
837 /* USE_WINDOWS_API */ int
838 psf_close_rsrc (SF_PRIVATE
*psf
)
839 { psf_close_handle (psf
->rsrc
.handle
) ;
840 psf
->rsrc
.handle
= NULL
;
842 } /* psf_close_rsrc */
845 /* USE_WINDOWS_API */ int
846 psf_set_stdio (SF_PRIVATE
*psf
)
847 { HANDLE handle
= NULL
;
850 switch (psf
->file
.mode
)
852 error
= SFE_OPEN_PIPE_RDWR
;
856 handle
= GetStdHandle (STD_INPUT_HANDLE
) ;
857 psf
->file
.do_not_close_descriptor
= 1 ;
861 handle
= GetStdHandle (STD_OUTPUT_HANDLE
) ;
862 psf
->file
.do_not_close_descriptor
= 1 ;
866 error
= SFE_BAD_OPEN_MODE
;
870 psf
->file
.handle
= handle
;
871 psf
->filelength
= 0 ;
874 } /* psf_set_stdio */
876 /* USE_WINDOWS_API */ void
877 psf_set_file (SF_PRIVATE
*psf
, int fd
)
881 osfhandle
= _get_osfhandle (fd
) ;
882 handle
= (HANDLE
) osfhandle
;
884 psf
->file
.handle
= handle
;
887 /* USE_WINDOWS_API */ int
888 psf_file_valid (SF_PRIVATE
*psf
)
889 { if (psf
->file
.handle
== NULL
)
891 if (psf
->file
.handle
== INVALID_HANDLE_VALUE
)
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
;
901 DWORD dwResult
, dwError
;
904 return psf
->vio
.seek (offset
, whence
, psf
->vio_user_data
) ;
908 offset
+= psf
->fileoffset
;
909 dwMoveMethod
= FILE_BEGIN
;
913 dwMoveMethod
= FILE_END
;
917 dwMoveMethod
= FILE_CURRENT
;
921 lDistanceToMove
= (DWORD
) (offset
& 0xFFFFFFFF) ;
922 lDistanceToMoveHigh
= (DWORD
) ((offset
>> 32) & 0xFFFFFFFF) ;
924 dwResult
= SetFilePointer (psf
->file
.handle
, lDistanceToMove
, &lDistanceToMoveHigh
, dwMoveMethod
) ;
926 if (dwResult
== 0xFFFFFFFF)
927 dwError
= GetLastError () ;
931 if (dwError
!= NO_ERROR
)
932 { psf_log_syserr (psf
, dwError
) ;
936 new_position
= (dwResult
+ ((__int64
) lDistanceToMoveHigh
<< 32)) - psf
->fileoffset
;
938 return new_position
;
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 ;
945 DWORD dwNumberOfBytesRead
;
948 return psf
->vio
.read (ptr
, bytes
*items
, psf
->vio_user_data
) / bytes
;
952 /* Do this check after the multiplication above. */
957 { /* Break the writes down to a sensible size. */
958 count
= (items
> SENSIBLE_SIZE
) ? SENSIBLE_SIZE
: (ssize_t
) items
;
960 if (ReadFile (psf
->file
.handle
, ((char*) ptr
) + total
, count
, &dwNumberOfBytesRead
, 0) == 0)
961 { psf_log_syserr (psf
, GetLastError ()) ;
965 count
= dwNumberOfBytesRead
;
975 psf
->pipeoffset
+= total
;
977 return total
/ bytes
;
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 ;
984 DWORD dwNumberOfBytesWritten
;
987 return psf
->vio
.write (ptr
, bytes
* items
, psf
->vio_user_data
) / bytes
;
991 /* Do this check after the multiplication above. */
996 { /* Break the writes down to a sensible size. */
997 count
= (items
> SENSIBLE_SIZE
) ? SENSIBLE_SIZE
: (ssize_t
) items
;
999 if (WriteFile (psf
->file
.handle
, ((const char*) ptr
) + total
, count
, &dwNumberOfBytesWritten
, 0) == 0)
1000 { psf_log_syserr (psf
, GetLastError ()) ;
1004 count
= dwNumberOfBytesWritten
;
1014 psf
->pipeoffset
+= total
;
1016 return total
/ bytes
;
1019 /* USE_WINDOWS_API */ sf_count_t
1020 psf_ftell (SF_PRIVATE
*psf
)
1022 LONG lDistanceToMoveLow
, lDistanceToMoveHigh
;
1023 DWORD dwResult
, dwError
;
1025 if (psf
->virtual_io
)
1026 return psf
->vio
.tell (psf
->vio_user_data
) ;
1029 return psf
->pipeoffset
;
1031 lDistanceToMoveLow
= 0 ;
1032 lDistanceToMoveHigh
= 0 ;
1034 dwResult
= SetFilePointer (psf
->file
.handle
, lDistanceToMoveLow
, &lDistanceToMoveHigh
, FILE_CURRENT
) ;
1036 if (dwResult
== 0xFFFFFFFF)
1037 dwError
= GetLastError () ;
1039 dwError
= NO_ERROR
;
1041 if (dwError
!= NO_ERROR
)
1042 { psf_log_syserr (psf
, dwError
) ;
1046 pos
= (dwResult
+ ((__int64
) lDistanceToMoveHigh
<< 32)) ;
1048 return pos
- psf
->fileoffset
;
1051 /* USE_WINDOWS_API */ static int
1052 psf_close_handle (HANDLE handle
)
1053 { if (handle
== NULL
)
1056 if (CloseHandle (handle
) == 0)
1060 } /* psf_close_handle */
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 ;
1066 DWORD dwNumberOfBytesRead
;
1068 while (k
< bufsize
- 1)
1069 { if (ReadFile (psf
->file
.handle
, &(buffer
[k
]), 1, &dwNumberOfBytesRead
, 0) == 0)
1070 { psf_log_syserr (psf
, GetLastError ()) ;
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')
1086 /* USE_WINDOWS_API */ int
1087 psf_is_pipe (SF_PRIVATE
*psf
)
1089 if (psf
->virtual_io
)
1092 if (GetFileType (psf
->file
.handle
) == FILE_TYPE_DISK
)
1095 /* Default to maximum safety. */
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
;
1104 dwFileSizeLow
= GetFileSize (handle
, &dwFileSizeHigh
) ;
1106 if (dwFileSizeLow
== 0xFFFFFFFF)
1107 dwError
= GetLastError () ;
1109 if (dwError
!= NO_ERROR
)
1110 return (sf_count_t
) -1 ;
1112 filelen
= dwFileSizeLow
+ ((__int64
) dwFileSizeHigh
<< 32) ;
1115 } /* psf_get_filelen_handle */
1117 /* USE_WINDOWS_API */ void
1118 psf_fsync (SF_PRIVATE
*psf
)
1119 { FlushFileBuffers (psf
->file
.handle
) ;
1123 /* USE_WINDOWS_API */ int
1124 psf_ftruncate (SF_PRIVATE
*psf
, sf_count_t len
)
1126 LONG lDistanceToMoveLow
, lDistanceToMoveHigh
;
1127 DWORD dwResult
, dwError
= NO_ERROR
;
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?
1134 /* Returns 0 on success, non-zero on failure. */
1138 lDistanceToMoveLow
= (DWORD
) (len
& 0xFFFFFFFF) ;
1139 lDistanceToMoveHigh
= (DWORD
) ((len
>> 32) & 0xFFFFFFFF) ;
1141 dwResult
= SetFilePointer (psf
->file
.handle
, lDistanceToMoveLow
, &lDistanceToMoveHigh
, FILE_BEGIN
) ;
1143 if (dwResult
== 0xFFFFFFFF)
1144 dwError
= GetLastError () ;
1146 if (dwError
!= NO_ERROR
)
1148 psf_log_syserr (psf
, dwError
) ;
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.
1156 if (SetEndOfFile (psf
->file
.handle
) == 0)
1158 psf_log_syserr (psf
, GetLastError ()) ;
1163 } /* psf_ftruncate */
1167 /* Win32 file i/o functions implemented using Unix-style file i/o API */
1169 /* Win32 has a 64 file offset seek function:
1171 ** __int64 _lseeki64 (int handle, __int64 offset, int origin) ;
1173 ** It also has a 64 bit fstat function:
1175 ** int fstati64 (int, struct _stati64) ;
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.
1186 psf_fopen (SF_PRIVATE
*psf
, const char *pathname
, int open_mode
)
1191 oflag
= O_RDONLY
| O_BINARY
;
1196 oflag
= O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
;
1197 mode
= S_IRUSR
| S_IWUSR
| S_IRGRP
;
1201 oflag
= O_RDWR
| O_CREAT
| O_BINARY
;
1202 mode
= S_IRUSR
| S_IWUSR
| S_IRGRP
;
1206 psf
->error
= SFE_BAD_OPEN_MODE
;
1212 psf
->file
.filedes
= open (pathname
, oflag
) ;
1214 psf
->file
.filedes
= open (pathname
, oflag
, mode
) ;
1216 if (psf
->file
.filedes
== -1)
1217 psf_log_syserr (psf
, errno
) ;
1219 return psf
->file
.filedes
;
1222 /* Win32 */ sf_count_t
1223 psf_fseek (SF_PRIVATE
*psf
, sf_count_t offset
, int whence
)
1224 { sf_count_t new_position
;
1226 if (psf
->virtual_io
)
1227 return psf
->vio
.seek (offset
, whence
, psf
->vio_user_data
) ;
1231 offset
+= psf
->fileoffset
;
1235 if (psf
->file
.mode
== SFM_WRITE
)
1236 { new_position
= _lseeki64 (psf
->file
.filedes
, offset
, whence
) ;
1238 if (new_position
< 0)
1239 psf_log_syserr (psf
, errno
) ;
1241 return new_position
- psf
->fileoffset
;
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.
1249 offset
= _lseeki64 (psf
->file
.filedes
, 0, SEEK_END
) + offset
;
1253 /* No need to do anything about SEEK_CUR. */
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.
1263 if (offset
== 0 && whence
== SEEK_CUR
)
1264 new_position
= _telli64 (psf
->file
.filedes
) ;
1266 new_position
= _lseeki64 (psf
->file
.filedes
, offset
, whence
) ;
1268 if (new_position
< 0)
1269 psf_log_syserr (psf
, errno
) ;
1271 new_position
-= psf
->fileoffset
;
1273 return new_position
;
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 ;
1281 if (psf
->virtual_io
)
1282 return psf
->vio
.read (ptr
, bytes
*items
, psf
->vio_user_data
) / bytes
;
1286 /* Do this check after the multiplication above. */
1291 { /* Break the writes down to a sensible size. */
1292 count
= (items
> SENSIBLE_SIZE
) ? SENSIBLE_SIZE
: (ssize_t
) items
;
1294 count
= read (psf
->file
.filedes
, ((char*) ptr
) + total
, (size_t) count
) ;
1297 { if (errno
== EINTR
)
1300 psf_log_syserr (psf
, errno
) ;
1311 return total
/ bytes
;
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 ;
1319 if (psf
->virtual_io
)
1320 return psf
->vio
.write (ptr
, bytes
*items
, psf
->vio_user_data
) / bytes
;
1324 /* Do this check after the multiplication above. */
1329 { /* Break the writes down to a sensible size. */
1330 count
= (items
> SENSIBLE_SIZE
) ? SENSIBLE_SIZE
: items
;
1332 count
= write (psf
->file
.filedes
, ((const char*) ptr
) + total
, count
) ;
1335 { if (errno
== EINTR
)
1338 psf_log_syserr (psf
, errno
) ;
1349 return total
/ bytes
;
1352 /* Win32 */ sf_count_t
1353 psf_ftell (SF_PRIVATE
*psf
)
1356 if (psf
->virtual_io
)
1357 return psf
->vio
.tell (psf
->vio_user_data
) ;
1359 pos
= _telli64 (psf
->file
.filedes
) ;
1361 if (pos
== ((sf_count_t
) -1))
1362 { psf_log_syserr (psf
, errno
) ;
1366 return pos
- psf
->fileoffset
;
1370 psf_fclose (SF_PRIVATE
*psf
)
1373 while ((retval
= close (psf
->file
.filedes
)) == -1 && errno
== EINTR
)
1377 psf_log_syserr (psf
, errno
) ;
1379 psf
->file
.filedes
= -1 ;
1384 /* Win32 */ sf_count_t
1385 psf_fgets (char *buffer
, sf_count_t bufsize
, SF_PRIVATE
*psf
)
1386 { sf_count_t k
= 0 ;
1389 while (k
< bufsize
- 1)
1390 { count
= read (psf
->file
.filedes
, &(buffer
[k
]), 1) ;
1393 { if (errno
== EINTR
)
1396 psf_log_syserr (psf
, errno
) ;
1400 if (count
== 0 || buffer
[k
++] == '\n')
1410 psf_is_pipe (SF_PRIVATE
*psf
)
1411 { struct stat statbuf
;
1413 if (psf
->virtual_io
)
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. */
1423 /* These macros are defined in Win32/unistd.h. */
1424 if (S_ISFIFO (statbuf
.st_mode
) || S_ISSOCK (statbuf
.st_mode
))
1428 } /* psf_checkpipe */
1430 /* Win32 */ sf_count_t
1431 psf_get_filelen (SF_PRIVATE
*psf
)
1435 ** Windoze is SOOOOO FUCKED!!!!!!!
1436 ** This code should work but doesn't. Why?
1437 ** Code below does work.
1439 struct _stati64 statbuf
;
1441 if (_fstati64 (psf
->file
.filedes
, &statbuf
))
1442 { psf_log_syserr (psf
, errno
) ;
1443 return (sf_count_t
) -1 ;
1446 return statbuf
.st_size
;
1448 sf_count_t current
, filelen
;
1450 if (psf
->virtual_io
)
1451 return psf
->vio
.get_filelen (psf
->vio_user_data
) ;
1453 if ((current
= _telli64 (psf
->file
.filedes
)) < 0)
1454 { psf_log_syserr (psf
, errno
) ;
1455 return (sf_count_t
) -1 ;
1459 ** Lets face it, windoze if FUBAR!!!
1461 ** For some reason, I have to call _lseeki64() TWICE to get to the
1464 ** This might have been avoided if windows had implemented the POSIX
1465 ** standard function fsync() but NO, that would have been too easy.
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.
1471 _lseeki64 (psf
->file
.filedes
, 0, SEEK_END
) ;
1473 if ((filelen
= _lseeki64 (psf
->file
.filedes
, 0, SEEK_END
)) < 0)
1474 { psf_log_syserr (psf
, errno
) ;
1475 return (sf_count_t
) -1 ;
1478 if (filelen
> current
)
1479 _lseeki64 (psf
->file
.filedes
, current
, SEEK_SET
) ;
1481 switch (psf
->file
.mode
)
1483 filelen
= filelen
- psf
->fileoffset
;
1487 if (psf
->fileoffset
> 0 && psf
->filelength
> 0)
1488 filelen
= psf
->filelength
;
1493 ** Cannot open embedded files SFM_RDWR so we don't need to
1494 ** subtract psf->fileoffset. We already have the answer we
1505 } /* psf_get_filelen */
1508 psf_ftruncate (SF_PRIVATE
*psf
, sf_count_t len
)
1511 /* Returns 0 on success, non-zero on failure. */
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!
1519 ** This is not 64 bit file offset clean. Somone needs to clean
1522 if (len
> 0x7FFFFFFF)
1525 retval
= chsize (psf
->file
.filedes
, len
) ;
1528 psf_log_syserr (psf
, errno
) ;
1531 } /* psf_ftruncate */
1535 psf_log_syserr (SF_PRIVATE
*psf
, int error
)
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
)) ;
1544 } /* psf_log_syserr */