2 ** Copyright (C) 2002-2005 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)
58 static void psf_log_syserr (SF_PRIVATE *psf, int error) ;
60 #if (USE_WINDOWS_API == 0)
62 /*------------------------------------------------------------------------------
63 ** Win32 stuff at the bottom of the file. Unix and other sensible OSes here.
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) ;
71 psf_fopen (SF_PRIVATE *psf, const char *pathname, int open_mode)
74 psf->filedes = psf_open_fd (pathname, open_mode) ;
76 if (psf->filedes == - SFE_BAD_OPEN_MODE)
77 { psf->error = SFE_BAD_OPEN_MODE ;
82 if (psf->filedes == -1)
83 psf_log_syserr (psf, errno) ;
85 psf->mode = open_mode ;
91 psf_fclose (SF_PRIVATE *psf)
97 if (psf->do_not_close_descriptor)
102 if ((retval = psf_close_fd (psf->filedes)) == -1)
103 psf_log_syserr (psf, errno) ;
111 psf_open_rsrc (SF_PRIVATE *psf, int open_mode)
113 if (psf->rsrcdes > 0)
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) ;
127 if (psf->rsrcdes == - SFE_BAD_OPEN_MODE)
128 { psf->error = SFE_BAD_OPEN_MODE ;
133 ** Now try for a resource fork stored as a separate file in the same
134 ** directory, but preceded with a dot underscore.
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 ;
144 ** Now try for a resource fork stored in a separate file in the
145 ** .AppleDouble/ directory.
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 ;
154 /* No resource file found. */
155 if (psf->rsrcdes == -1)
156 psf_log_syserr (psf, errno) ;
161 } /* psf_open_rsrc */
164 psf_get_filelen (SF_PRIVATE *psf)
165 { sf_count_t filelen ;
168 return psf->vio.get_filelen (psf->vio_user_data) ;
170 filelen = psf_get_filelen_fd (psf->filedes) ;
173 { psf_log_syserr (psf, errno) ;
174 return (sf_count_t) -1 ;
177 if (filelen == -SFE_BAD_STAT_SIZE)
178 { psf->error = SFE_BAD_STAT_SIZE ;
179 return (sf_count_t) -1 ;
184 filelen = filelen - psf->fileoffset ;
188 if (psf->fileoffset > 0 && psf->filelength > 0)
189 filelen = psf->filelength ;
194 ** Cannot open embedded files SFM_RDWR so we don't need to
195 ** subtract psf->fileoffset. We already have the answer we
201 /* Shouldn't be here, so return error. */
206 } /* psf_get_filelen */
209 psf_close_rsrc (SF_PRIVATE *psf)
211 if (psf->rsrcdes >= 0)
212 psf_close_fd (psf->rsrcdes) ;
215 } /* psf_close_rsrc */
218 psf_set_stdio (SF_PRIVATE *psf, int mode)
223 error = SFE_OPEN_PIPE_RDWR ;
235 error = SFE_BAD_OPEN_MODE ;
238 psf->filelength = 0 ;
241 } /* psf_set_stdio */
244 psf_set_file (SF_PRIVATE *psf, int fd)
245 { psf->filedes = fd ;
249 psf_file_valid (SF_PRIVATE *psf)
250 { return (psf->filedes >= 0) ? SF_TRUE : SF_FALSE ;
254 psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence)
255 { sf_count_t new_position ;
258 return psf->vio.seek (offset, whence, psf->vio_user_data) ;
262 offset += psf->fileoffset ;
266 if (psf->mode == SFM_WRITE)
267 { new_position = lseek (psf->filedes, offset, whence) ;
269 if (new_position < 0)
270 psf_log_syserr (psf, errno) ;
272 return new_position - psf->fileoffset ;
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.
280 offset = lseek (psf->filedes, 0, SEEK_END) + offset ;
284 /* No need to do anything about SEEK_CUR. */
288 new_position = lseek (psf->filedes, offset, whence) ;
290 if (new_position < 0)
291 psf_log_syserr (psf, errno) ;
293 new_position -= psf->fileoffset ;
295 return new_position ;
299 psf_fread (void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf)
300 { sf_count_t total = 0 ;
304 return psf->vio.read (ptr, bytes*items, psf->vio_user_data) / bytes ;
308 /* Do this check after the multiplication above. */
313 { /* Break the read down to a sensible size. */
314 count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ;
316 count = read (psf->filedes, ((char*) ptr) + total, (size_t) count) ;
319 { if (errno == EINTR)
322 psf_log_syserr (psf, errno) ;
334 psf->pipeoffset += total ;
336 return total / bytes ;
340 psf_fwrite (const void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf)
341 { sf_count_t total = 0 ;
345 return psf->vio.write (ptr, bytes*items, psf->vio_user_data) / bytes ;
349 /* Do this check after the multiplication above. */
354 { /* Break the writes down to a sensible size. */
355 count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : items ;
357 count = write (psf->filedes, ((const char*) ptr) + total, count) ;
360 { if (errno == EINTR)
363 psf_log_syserr (psf, errno) ;
375 psf->pipeoffset += total ;
377 return total / bytes ;
381 psf_ftell (SF_PRIVATE *psf)
385 return psf->vio.tell (psf->vio_user_data) ;
388 return psf->pipeoffset ;
390 pos = lseek (psf->filedes, 0, SEEK_CUR) ;
392 if (pos == ((sf_count_t) -1))
393 { psf_log_syserr (psf, errno) ;
397 return pos - psf->fileoffset ;
401 psf_close_fd (int fd)
404 while ((retval = close (fd)) == -1 && errno == EINTR)
411 psf_fgets (char *buffer, sf_count_t bufsize, SF_PRIVATE *psf)
415 while (k < bufsize - 1)
416 { count = read (psf->filedes, &(buffer [k]), 1) ;
419 { if (errno == EINTR)
422 psf_log_syserr (psf, errno) ;
426 if (count == 0 || buffer [k++] == '\n')
436 psf_is_pipe (SF_PRIVATE *psf)
437 { struct stat statbuf ;
442 if (fstat (psf->filedes, &statbuf) == -1)
443 { psf_log_syserr (psf, errno) ;
444 /* Default to maximum safety. */
448 if (S_ISFIFO (statbuf.st_mode) || S_ISSOCK (statbuf.st_mode))
455 psf_get_filelen_fd (int fd)
456 { struct stat statbuf ;
460 ** If everything is OK, this will be optimised out.
462 if (sizeof (statbuf.st_size) == 4 && sizeof (sf_count_t) == 8)
463 return (sf_count_t) -SFE_BAD_STAT_SIZE ;
465 if (fstat (fd, &statbuf) == -1)
466 return (sf_count_t) -1 ;
468 return statbuf.st_size ;
469 } /* psf_get_filelen_fd */
472 psf_ftruncate (SF_PRIVATE *psf, sf_count_t len)
475 /* Returns 0 on success, non-zero on failure. */
479 if ((sizeof (off_t) < sizeof (sf_count_t)) && len > 0x7FFFFFFF)
482 retval = ftruncate (psf->filedes, len) ;
485 psf_log_syserr (psf, errno) ;
488 } /* psf_ftruncate */
491 psf_init_files (SF_PRIVATE *psf)
492 { psf->filedes = -1 ;
495 } /* psf_init_files */
498 psf_use_rsrc (SF_PRIVATE *psf, int on_off)
501 { if (psf->filedes != psf->rsrcdes)
502 { psf->savedes = psf->filedes ;
503 psf->filedes = psf->rsrcdes ;
506 else if (psf->filedes == psf->rsrcdes)
507 psf->filedes = psf->savedes ;
513 psf_open_fd (const char * pathname, int open_mode)
514 { int fd, oflag, mode ;
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>.
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") ;
534 oflag = O_WRONLY | O_CREAT | O_TRUNC ;
535 mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ;
539 oflag = O_RDWR | O_CREAT ;
540 mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ;
544 return - SFE_BAD_OPEN_MODE ;
554 fd = open (pathname, oflag) ;
556 fd = open (pathname, oflag, mode) ;
562 psf_log_syserr (SF_PRIVATE *psf, int error)
564 /* Only log an error if no error has been set yet. */
566 { psf->error = SFE_SYSTEM ;
567 LSF_SNPRINTF (psf->syserr, sizeof (psf->syserr), "System error : %s.", strerror (error)) ;
571 } /* psf_log_syserr */
574 psf_fsync (SF_PRIVATE *psf)
577 if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
578 fsync (psf->filedes) ;
584 #elif USE_WINDOWS_API
586 /* Win32 file i/o functions implemented using native Win32 API */
592 typedef long ssize_t ;
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) ;
599 /* USE_WINDOWS_API */ int
600 psf_fopen (SF_PRIVATE *psf, const char *pathname, int open_mode)
603 psf->hfile = psf_open_handle (pathname, open_mode) ;
605 if (psf->hfile == NULL)
606 psf_log_syserr (psf, errno) ;
608 psf->mode = open_mode ;
613 /* USE_WINDOWS_API */ int
614 psf_fclose (SF_PRIVATE *psf)
620 if (psf->do_not_close_descriptor)
621 { psf->hfile = NULL ;
625 if ((retval = psf_close_handle (psf->hfile)) == -1)
626 psf_log_syserr (psf, errno) ;
633 /* USE_WINDOWS_API */ int
634 psf_open_rsrc (SF_PRIVATE *psf, int open_mode)
636 if (psf->hrsrc != NULL)
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 ;
648 ** Now try for a resource fork stored as a separate file in the same
649 ** directory, but preceded with a dot underscore.
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 ;
659 ** Now try for a resource fork stored in a separate file in the
660 ** .AppleDouble/ directory.
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 ;
669 /* No resource file found. */
670 if (psf->hrsrc == NULL)
671 psf_log_syserr (psf, errno) ;
676 } /* psf_open_rsrc */
678 /* USE_WINDOWS_API */ sf_count_t
679 psf_get_filelen (SF_PRIVATE *psf)
680 { sf_count_t filelen ;
683 return psf->vio.get_filelen (psf->vio_user_data) ;
685 filelen = psf_get_filelen_handle (psf->hfile) ;
688 { psf_log_syserr (psf, errno) ;
689 return (sf_count_t) -1 ;
692 if (filelen == -SFE_BAD_STAT_SIZE)
693 { psf->error = SFE_BAD_STAT_SIZE ;
694 return (sf_count_t) -1 ;
699 filelen = filelen - psf->fileoffset ;
703 if (psf->fileoffset > 0 && psf->filelength > 0)
704 filelen = psf->filelength ;
709 ** Cannot open embedded files SFM_RDWR so we don't need to
710 ** subtract psf->fileoffset. We already have the answer we
716 /* Shouldn't be here, so return error. */
721 } /* psf_get_filelen */
723 /* USE_WINDOWS_API */ void
724 psf_init_files (SF_PRIVATE *psf)
725 { psf->hfile = NULL ;
728 } /* psf_init_files */
730 /* USE_WINDOWS_API */ void
731 psf_use_rsrc (SF_PRIVATE *psf, int on_off)
734 { if (psf->hfile != psf->hrsrc)
735 { psf->hsaved = psf->hfile ;
736 psf->hfile = psf->hrsrc ;
739 else if (psf->hfile == psf->hrsrc)
740 psf->hfile = psf->hsaved ;
745 /* USE_WINDOWS_API */ static HANDLE
746 psf_open_handle (const char * pathname, int open_mode)
747 { DWORD dwDesiredAccess ;
749 DWORD dwCreationDistribution ;
754 dwDesiredAccess = GENERIC_READ ;
755 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ;
756 dwCreationDistribution = OPEN_EXISTING ;
760 dwDesiredAccess = GENERIC_WRITE ;
761 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ;
762 dwCreationDistribution = CREATE_ALWAYS ;
766 dwDesiredAccess = GENERIC_READ | GENERIC_WRITE ;
767 dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ;
768 dwCreationDistribution = OPEN_ALWAYS ;
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 */
785 if (handle == INVALID_HANDLE_VALUE)
789 } /* psf_open_handle */
791 /* USE_WINDOWS_API */ static void
792 psf_log_syserr (SF_PRIVATE *psf, int error)
795 /* Only log an error if no error has been set yet. */
797 { psf->error = SFE_SYSTEM ;
800 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
803 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
809 LSF_SNPRINTF (psf->syserr, sizeof (psf->syserr), "System error : %s", lpMsgBuf) ;
810 LocalFree (lpMsgBuf) ;
814 } /* psf_log_syserr */
817 /* USE_WINDOWS_API */ int
818 psf_close_rsrc (SF_PRIVATE *psf)
820 if (psf->hrsrc != NULL)
821 psf_close_handle (psf->hrsrc) ;
824 } /* psf_close_rsrc */
827 /* USE_WINDOWS_API */ int
828 psf_set_stdio (SF_PRIVATE *psf, int mode)
829 { HANDLE handle = NULL ;
834 error = SFE_OPEN_PIPE_RDWR ;
838 handle = GetStdHandle (STD_INPUT_HANDLE) ;
839 psf->do_not_close_descriptor = 1 ;
843 handle = GetStdHandle (STD_OUTPUT_HANDLE) ;
844 psf->do_not_close_descriptor = 1 ;
848 error = SFE_BAD_OPEN_MODE ;
852 psf->hfile = handle ;
853 psf->filelength = 0 ;
856 } /* psf_set_stdio */
858 /* USE_WINDOWS_API */ void
859 psf_set_file (SF_PRIVATE *psf, int fd)
863 osfhandle = _get_osfhandle (fd) ;
864 handle = (HANDLE) osfhandle ;
866 psf->hfile = handle ;
869 /* USE_WINDOWS_API */ int
870 psf_file_valid (SF_PRIVATE *psf)
871 { if (psf->hfile == NULL)
873 if (psf->hfile == INVALID_HANDLE_VALUE)
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 ;
883 DWORD dwResult, dwError ;
886 return psf->vio.seek (offset, whence, psf->vio_user_data) ;
890 offset += psf->fileoffset ;
891 dwMoveMethod = FILE_BEGIN ;
895 dwMoveMethod = FILE_END ;
899 dwMoveMethod = FILE_CURRENT ;
903 lDistanceToMove = (DWORD) (offset & 0xFFFFFFFF) ;
904 lDistanceToMoveHigh = (DWORD) ((offset >> 32) & 0xFFFFFFFF) ;
906 dwResult = SetFilePointer (psf->hfile, lDistanceToMove, &lDistanceToMoveHigh, dwMoveMethod) ;
908 if (dwResult == 0xFFFFFFFF)
909 dwError = GetLastError () ;
913 if (dwError != NO_ERROR)
914 { psf_log_syserr (psf, dwError) ;
918 new_position = (dwResult + ((__int64) lDistanceToMoveHigh << 32)) - psf->fileoffset ;
920 return new_position ;
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 ;
927 DWORD dwNumberOfBytesRead ;
930 return psf->vio.read (ptr, bytes*items, psf->vio_user_data) / bytes ;
934 /* Do this check after the multiplication above. */
939 { /* Break the writes down to a sensible size. */
940 count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ;
942 if (ReadFile (psf->hfile, ((char*) ptr) + total, count, &dwNumberOfBytesRead, 0) == 0)
943 { psf_log_syserr (psf, GetLastError ()) ;
947 count = dwNumberOfBytesRead ;
957 psf->pipeoffset += total ;
959 return total / bytes ;
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 ;
966 DWORD dwNumberOfBytesWritten ;
969 return psf->vio.write (ptr, bytes * items, psf->vio_user_data) / bytes ;
973 /* Do this check after the multiplication above. */
978 { /* Break the writes down to a sensible size. */
979 count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ;
981 if (WriteFile (psf->hfile, ((const char*) ptr) + total, count, &dwNumberOfBytesWritten, 0) == 0)
982 { psf_log_syserr (psf, GetLastError ()) ;
986 count = dwNumberOfBytesWritten ;
996 psf->pipeoffset += total ;
998 return total / bytes ;
1001 /* USE_WINDOWS_API */ sf_count_t
1002 psf_ftell (SF_PRIVATE *psf)
1004 LONG lDistanceToMoveLow, lDistanceToMoveHigh ;
1005 DWORD dwResult, dwError ;
1007 if (psf->virtual_io)
1008 return psf->vio.tell (psf->vio_user_data) ;
1011 return psf->pipeoffset ;
1013 lDistanceToMoveLow = 0 ;
1014 lDistanceToMoveHigh = 0 ;
1016 dwResult = SetFilePointer (psf->hfile, lDistanceToMoveLow, &lDistanceToMoveHigh, FILE_CURRENT) ;
1018 if (dwResult == 0xFFFFFFFF)
1019 dwError = GetLastError () ;
1021 dwError = NO_ERROR ;
1023 if (dwError != NO_ERROR)
1024 { psf_log_syserr (psf, dwError) ;
1028 pos = (dwResult + ((__int64) lDistanceToMoveHigh << 32)) ;
1030 return pos - psf->fileoffset ;
1033 /* USE_WINDOWS_API */ static int
1034 psf_close_handle (HANDLE handle)
1035 { if (CloseHandle (handle) == 0)
1039 } /* psf_close_handle */
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 ;
1045 DWORD dwNumberOfBytesRead ;
1047 while (k < bufsize - 1)
1048 { if (ReadFile (psf->hfile, &(buffer [k]), 1, &dwNumberOfBytesRead, 0) == 0)
1049 { psf_log_syserr (psf, GetLastError ()) ;
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')
1065 /* USE_WINDOWS_API */ int
1066 psf_is_pipe (SF_PRIVATE *psf)
1068 if (psf->virtual_io)
1071 if (GetFileType (psf->hfile) == FILE_TYPE_DISK)
1074 /* Default to maximum safety. */
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 ;
1083 dwFileSizeLow = GetFileSize (handle, &dwFileSizeHigh) ;
1085 if (dwFileSizeLow == 0xFFFFFFFF)
1086 dwError = GetLastError () ;
1088 if (dwError != NO_ERROR)
1089 return (sf_count_t) -1 ;
1091 filelen = dwFileSizeLow + ((__int64) dwFileSizeHigh << 32) ;
1094 } /* psf_get_filelen_handle */
1096 /* USE_WINDOWS_API */ void
1097 psf_fsync (SF_PRIVATE *psf)
1098 { FlushFileBuffers (psf->hfile) ;
1102 /* USE_WINDOWS_API */ int
1103 psf_ftruncate (SF_PRIVATE *psf, sf_count_t len)
1105 LONG lDistanceToMoveLow, lDistanceToMoveHigh ;
1106 DWORD dwResult, dwError = NO_ERROR ;
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?
1113 /* Returns 0 on success, non-zero on failure. */
1117 lDistanceToMoveLow = (DWORD) (len & 0xFFFFFFFF) ;
1118 lDistanceToMoveHigh = (DWORD) ((len >> 32) & 0xFFFFFFFF) ;
1120 dwResult = SetFilePointer (psf->hfile, lDistanceToMoveLow, &lDistanceToMoveHigh, FILE_BEGIN) ;
1122 if (dwResult == 0xFFFFFFFF)
1123 dwError = GetLastError () ;
1125 if (dwError != NO_ERROR)
1127 psf_log_syserr (psf, dwError) ;
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.
1135 if (SetEndOfFile (psf->hfile) == 0)
1137 psf_log_syserr (psf, GetLastError ()) ;
1142 } /* psf_ftruncate */
1146 /* Win32 file i/o functions implemented using Unix-style file i/o API */
1148 /* Win32 has a 64 file offset seek function:
1150 ** __int64 _lseeki64 (int handle, __int64 offset, int origin) ;
1152 ** It also has a 64 bit fstat function:
1154 ** int fstati64 (int, struct _stati64) ;
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.
1164 #ifndef HAVE_SSIZE_T
1165 typedef long ssize_t ;
1169 psf_fopen (SF_PRIVATE *psf, const char *pathname, int open_mode)
1174 oflag = O_RDONLY | O_BINARY ;
1179 oflag = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY ;
1180 mode = S_IRUSR | S_IWUSR | S_IRGRP ;
1184 oflag = O_RDWR | O_CREAT | O_BINARY ;
1185 mode = S_IRUSR | S_IWUSR | S_IRGRP ;
1189 psf->error = SFE_BAD_OPEN_MODE ;
1195 psf->filedes = open (pathname, oflag) ;
1197 psf->filedes = open (pathname, oflag, mode) ;
1199 if (psf->filedes == -1)
1200 psf_log_syserr (psf, errno) ;
1202 return psf->filedes ;
1205 /* Win32 */ sf_count_t
1206 psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence)
1207 { sf_count_t new_position ;
1209 if (psf->virtual_io)
1210 return psf->vio.seek (offset, whence, psf->vio_user_data) ;
1214 offset += psf->fileoffset ;
1218 if (psf->mode == SFM_WRITE)
1219 { new_position = _lseeki64 (psf->filedes, offset, whence) ;
1221 if (new_position < 0)
1222 psf_log_syserr (psf, errno) ;
1224 return new_position - psf->fileoffset ;
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.
1232 offset = _lseeki64 (psf->filedes, 0, SEEK_END) + offset ;
1236 /* No need to do anything about SEEK_CUR. */
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.
1246 if (offset == 0 && whence == SEEK_CUR)
1247 new_position = _telli64 (psf->filedes) ;
1249 new_position = _lseeki64 (psf->filedes, offset, whence) ;
1251 if (new_position < 0)
1252 psf_log_syserr (psf, errno) ;
1254 new_position -= psf->fileoffset ;
1256 return new_position ;
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 ;
1264 if (psf->virtual_io)
1265 return psf->vio.read (ptr, bytes*items, psf->vio_user_data) / bytes ;
1269 /* Do this check after the multiplication above. */
1274 { /* Break the writes down to a sensible size. */
1275 count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ;
1277 count = read (psf->filedes, ((char*) ptr) + total, (size_t) count) ;
1280 { if (errno == EINTR)
1283 psf_log_syserr (psf, errno) ;
1294 return total / bytes ;
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 ;
1302 if (psf->virtual_io)
1303 return psf->vio.write (ptr, bytes*items, psf->vio_user_data) / bytes ;
1307 /* Do this check after the multiplication above. */
1312 { /* Break the writes down to a sensible size. */
1313 count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : items ;
1315 count = write (psf->filedes, ((const char*) ptr) + total, count) ;
1318 { if (errno == EINTR)
1321 psf_log_syserr (psf, errno) ;
1332 return total / bytes ;
1335 /* Win32 */ sf_count_t
1336 psf_ftell (SF_PRIVATE *psf)
1339 if (psf->virtual_io)
1340 return psf->vio.tell (psf->vio_user_data) ;
1342 pos = _telli64 (psf->filedes) ;
1344 if (pos == ((sf_count_t) -1))
1345 { psf_log_syserr (psf, errno) ;
1349 return pos - psf->fileoffset ;
1353 psf_fclose (SF_PRIVATE *psf)
1356 while ((retval = close (psf->filedes)) == -1 && errno == EINTR)
1360 psf_log_syserr (psf, errno) ;
1367 /* Win32 */ sf_count_t
1368 psf_fgets (char *buffer, sf_count_t bufsize, SF_PRIVATE *psf)
1369 { sf_count_t k = 0 ;
1372 while (k < bufsize - 1)
1373 { count = read (psf->filedes, &(buffer [k]), 1) ;
1376 { if (errno == EINTR)
1379 psf_log_syserr (psf, errno) ;
1383 if (count == 0 || buffer [k++] == '\n')
1393 psf_is_pipe (SF_PRIVATE *psf)
1394 { struct stat statbuf ;
1396 if (psf->virtual_io)
1399 /* Not sure if this works. */
1400 if (fstat (psf->filedes, &statbuf) == -1)
1401 { psf_log_syserr (psf, errno) ;
1402 /* Default to maximum safety. */
1406 /* These macros are defined in Win32/unistd.h. */
1407 if (S_ISFIFO (statbuf.st_mode) || S_ISSOCK (statbuf.st_mode))
1411 } /* psf_checkpipe */
1413 /* Win32 */ sf_count_t
1414 psf_get_filelen (SF_PRIVATE *psf)
1418 ** Windoze is SOOOOO FUCKED!!!!!!!
1419 ** This code should work but doesn't. Why?
1420 ** Code below does work.
1422 struct _stati64 statbuf ;
1424 if (_fstati64 (psf->filedes, &statbuf))
1425 { psf_log_syserr (psf, errno) ;
1426 return (sf_count_t) -1 ;
1429 return statbuf.st_size ;
1431 sf_count_t current, filelen ;
1433 if (psf->virtual_io)
1434 return psf->vio.get_filelen (psf->vio_user_data) ;
1436 if ((current = _telli64 (psf->filedes)) < 0)
1437 { psf_log_syserr (psf, errno) ;
1438 return (sf_count_t) -1 ;
1442 ** Lets face it, windoze if FUBAR!!!
1444 ** For some reason, I have to call _lseeki64() TWICE to get to the
1447 ** This might have been avoided if windows had implemented the POSIX
1448 ** standard function fsync() but NO, that would have been too easy.
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.
1454 _lseeki64 (psf->filedes, 0, SEEK_END) ;
1456 if ((filelen = _lseeki64 (psf->filedes, 0, SEEK_END)) < 0)
1457 { psf_log_syserr (psf, errno) ;
1458 return (sf_count_t) -1 ;
1461 if (filelen > current)
1462 _lseeki64 (psf->filedes, current, SEEK_SET) ;
1466 filelen = filelen - psf->fileoffset ;
1470 if (psf->fileoffset > 0 && psf->filelength > 0)
1471 filelen = psf->filelength ;
1476 ** Cannot open embedded files SFM_RDWR so we don't need to
1477 ** subtract psf->fileoffset. We already have the answer we
1488 } /* psf_get_filelen */
1491 psf_ftruncate (SF_PRIVATE *psf, sf_count_t len)
1494 /* Returns 0 on success, non-zero on failure. */
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!
1502 ** This is not 64 bit file offset clean. Somone needs to clean
1505 if (len > 0x7FFFFFFF)
1508 retval = chsize (psf->filedes, len) ;
1511 psf_log_syserr (psf, errno) ;
1514 } /* psf_ftruncate */
1518 psf_log_syserr (SF_PRIVATE *psf, int error)
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)) ;
1527 } /* psf_log_syserr */
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.
1536 ** arch-tag: 749740d7-ecc7-47bd-8cf7-600f31d32e6d