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