| /* |
| ** Copyright (C) 2002-2011 Erik de Castro Lopo <erikd@mega-nerd.com> |
| ** Copyright (C) 2003 Ross Bencina <rbencina@iprimus.com.au> |
| ** |
| ** This program is free software; you can redistribute it and/or modify |
| ** it under the terms of the GNU Lesser General Public License as published by |
| ** the Free Software Foundation; either version 2.1 of the License, or |
| ** (at your option) any later version. |
| ** |
| ** This program is distributed in the hope that it will be useful, |
| ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
| ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| ** GNU Lesser General Public License for more details. |
| ** |
| ** You should have received a copy of the GNU Lesser General Public License |
| ** along with this program; if not, write to the Free Software |
| ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| */ |
| |
| /* |
| ** The file is split into three sections as follows: |
| ** - The top section (USE_WINDOWS_API == 0) for Linux, Unix and MacOSX |
| ** systems (including Cygwin). |
| ** - The middle section (USE_WINDOWS_API == 1) for microsoft windows |
| ** (including MinGW) using the native windows API. |
| ** - A legacy windows section which attempted to work around grevious |
| ** bugs in microsoft's POSIX implementation. |
| */ |
| |
| /* |
| ** The header file sfconfig.h MUST be included before the others to ensure |
| ** that large file support is enabled correctly on Unix systems. |
| */ |
| |
| #include "sfconfig.h" |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| |
| #if HAVE_UNISTD_H |
| #include <unistd.h> |
| #endif |
| |
| #if (HAVE_DECL_S_IRGRP == 0) |
| #include <sf_unistd.h> |
| #endif |
| |
| #include <string.h> |
| #include <fcntl.h> |
| #include <errno.h> |
| #include <sys/stat.h> |
| |
| #include "sndfile.h" |
| #include "common.h" |
| |
| #define SENSIBLE_SIZE (0x40000000) |
| |
| /* |
| ** Neat solution to the Win32/OS2 binary file flage requirement. |
| ** If O_BINARY isn't already defined by the inclusion of the system |
| ** headers, set it to zero. |
| */ |
| #ifndef O_BINARY |
| #define O_BINARY 0 |
| #endif |
| |
| static void psf_log_syserr (SF_PRIVATE *psf, int error) ; |
| |
| #if (USE_WINDOWS_API == 0) |
| |
| /*------------------------------------------------------------------------------ |
| ** Win32 stuff at the bottom of the file. Unix and other sensible OSes here. |
| */ |
| |
| static int psf_close_fd (int fd) ; |
| static int psf_open_fd (PSF_FILE * pfile) ; |
| static sf_count_t psf_get_filelen_fd (int fd) ; |
| |
| int |
| psf_fopen (SF_PRIVATE *psf) |
| { |
| psf->error = 0 ; |
| psf->file.filedes = psf_open_fd (&psf->file) ; |
| if (psf->file.filedes == - SFE_BAD_OPEN_MODE) |
| { psf->error = SFE_BAD_OPEN_MODE ; |
| psf->file.filedes = -1 ; |
| return psf->error ; |
| } ; |
| if (psf->file.filedes == -1) |
| psf_log_syserr (psf, errno) ; |
| |
| return psf->error ; |
| } /* psf_fopen */ |
| |
| int |
| psf_fclose (SF_PRIVATE *psf) |
| { int retval ; |
| |
| if (psf->virtual_io) |
| return 0 ; |
| |
| if (psf->file.do_not_close_descriptor) |
| { psf->file.filedes = -1 ; |
| return 0 ; |
| } ; |
| |
| if ((retval = psf_close_fd (psf->file.filedes)) == -1) |
| psf_log_syserr (psf, errno) ; |
| |
| psf->file.filedes = -1 ; |
| |
| return retval ; |
| } /* psf_fclose */ |
| |
| int |
| psf_open_rsrc (SF_PRIVATE *psf) |
| { |
| if (psf->rsrc.filedes > 0) |
| return 0 ; |
| |
| /* Test for MacOSX style resource fork on HPFS or HPFS+ filesystems. */ |
| snprintf (psf->rsrc.path.c, sizeof (psf->rsrc.path.c), "%s/rsrc", psf->file.path.c) ; |
| psf->error = SFE_NO_ERROR ; |
| if ((psf->rsrc.filedes = psf_open_fd (&psf->rsrc)) >= 0) |
| { psf->rsrclength = psf_get_filelen_fd (psf->rsrc.filedes) ; |
| if (psf->rsrclength > 0 || (psf->rsrc.mode & SFM_WRITE)) |
| return SFE_NO_ERROR ; |
| psf_close_fd (psf->rsrc.filedes) ; |
| psf->rsrc.filedes = -1 ; |
| } ; |
| |
| if (psf->rsrc.filedes == - SFE_BAD_OPEN_MODE) |
| { psf->error = SFE_BAD_OPEN_MODE ; |
| return psf->error ; |
| } ; |
| |
| /* |
| ** Now try for a resource fork stored as a separate file in the same |
| ** directory, but preceded with a dot underscore. |
| */ |
| snprintf (psf->rsrc.path.c, sizeof (psf->rsrc.path.c), "%s._%s", psf->file.dir.c, psf->file.name.c) ; |
| psf->error = SFE_NO_ERROR ; |
| if ((psf->rsrc.filedes = psf_open_fd (&psf->rsrc)) >= 0) |
| { psf->rsrclength = psf_get_filelen_fd (psf->rsrc.filedes) ; |
| return SFE_NO_ERROR ; |
| } ; |
| |
| /* |
| ** Now try for a resource fork stored in a separate file in the |
| ** .AppleDouble/ directory. |
| */ |
| snprintf (psf->rsrc.path.c, sizeof (psf->rsrc.path.c), "%s.AppleDouble/%s", psf->file.dir.c, psf->file.name.c) ; |
| psf->error = SFE_NO_ERROR ; |
| if ((psf->rsrc.filedes = psf_open_fd (&psf->rsrc)) >= 0) |
| { psf->rsrclength = psf_get_filelen_fd (psf->rsrc.filedes) ; |
| return SFE_NO_ERROR ; |
| } ; |
| |
| /* No resource file found. */ |
| if (psf->rsrc.filedes == -1) |
| psf_log_syserr (psf, errno) ; |
| |
| psf->rsrc.filedes = -1 ; |
| |
| return psf->error ; |
| } /* psf_open_rsrc */ |
| |
| sf_count_t |
| psf_get_filelen (SF_PRIVATE *psf) |
| { sf_count_t filelen ; |
| |
| if (psf->virtual_io) |
| return psf->vio.get_filelen (psf->vio_user_data) ; |
| |
| filelen = psf_get_filelen_fd (psf->file.filedes) ; |
| |
| if (filelen == -1) |
| { psf_log_syserr (psf, errno) ; |
| return (sf_count_t) -1 ; |
| } ; |
| |
| if (filelen == -SFE_BAD_STAT_SIZE) |
| { psf->error = SFE_BAD_STAT_SIZE ; |
| return (sf_count_t) -1 ; |
| } ; |
| |
| switch (psf->file.mode) |
| { case SFM_WRITE : |
| filelen = filelen - psf->fileoffset ; |
| break ; |
| |
| case SFM_READ : |
| if (psf->fileoffset > 0 && psf->filelength > 0) |
| filelen = psf->filelength ; |
| break ; |
| |
| case SFM_RDWR : |
| /* |
| ** Cannot open embedded files SFM_RDWR so we don't need to |
| ** subtract psf->fileoffset. We already have the answer we |
| ** need. |
| */ |
| break ; |
| |
| default : |
| /* Shouldn't be here, so return error. */ |
| filelen = -1 ; |
| } ; |
| |
| return filelen ; |
| } /* psf_get_filelen */ |
| |
| int |
| psf_close_rsrc (SF_PRIVATE *psf) |
| { psf_close_fd (psf->rsrc.filedes) ; |
| psf->rsrc.filedes = -1 ; |
| return 0 ; |
| } /* psf_close_rsrc */ |
| |
| int |
| psf_set_stdio (SF_PRIVATE *psf) |
| { int error = 0 ; |
| |
| switch (psf->file.mode) |
| { case SFM_RDWR : |
| error = SFE_OPEN_PIPE_RDWR ; |
| break ; |
| |
| case SFM_READ : |
| psf->file.filedes = 0 ; |
| break ; |
| |
| case SFM_WRITE : |
| psf->file.filedes = 1 ; |
| break ; |
| |
| default : |
| error = SFE_BAD_OPEN_MODE ; |
| break ; |
| } ; |
| psf->filelength = 0 ; |
| |
| return error ; |
| } /* psf_set_stdio */ |
| |
| void |
| psf_set_file (SF_PRIVATE *psf, int fd) |
| { psf->file.filedes = fd ; |
| } /* psf_set_file */ |
| |
| int |
| psf_file_valid (SF_PRIVATE *psf) |
| { return (psf->file.filedes >= 0) ? SF_TRUE : SF_FALSE ; |
| } /* psf_set_file */ |
| |
| sf_count_t |
| psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence) |
| { sf_count_t current_pos, new_position ; |
| |
| if (psf->virtual_io) |
| return psf->vio.seek (offset, whence, psf->vio_user_data) ; |
| |
| current_pos = psf_ftell (psf) ; |
| |
| switch (whence) |
| { case SEEK_SET : |
| offset += psf->fileoffset ; |
| break ; |
| |
| case SEEK_END : |
| if (psf->file.mode == SFM_WRITE) |
| { new_position = lseek (psf->file.filedes, offset, whence) ; |
| |
| if (new_position < 0) |
| psf_log_syserr (psf, errno) ; |
| |
| return new_position - psf->fileoffset ; |
| } ; |
| |
| /* Transform SEEK_END into a SEEK_SET, ie find the file |
| ** length add the requested offset (should be <= 0) to |
| ** get the offset wrt the start of file. |
| */ |
| whence = SEEK_SET ; |
| offset = lseek (psf->file.filedes, 0, SEEK_END) + offset ; |
| break ; |
| |
| case SEEK_CUR : |
| /* Translate a SEEK_CUR into a SEEK_SET. */ |
| offset += current_pos ; |
| whence = SEEK_SET ; |
| break ; |
| |
| default : |
| /* We really should not be here. */ |
| psf_log_printf (psf, "psf_fseek : whence is %d *****.\n", whence) ; |
| return 0 ; |
| } ; |
| |
| if (current_pos != offset) |
| new_position = lseek (psf->file.filedes, offset, whence) ; |
| else |
| new_position = offset ; |
| |
| if (new_position < 0) |
| psf_log_syserr (psf, errno) ; |
| |
| new_position -= psf->fileoffset ; |
| |
| return new_position ; |
| } /* psf_fseek */ |
| |
| sf_count_t |
| psf_fread (void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf) |
| { sf_count_t total = 0 ; |
| ssize_t count ; |
| |
| if (psf->virtual_io) |
| return psf->vio.read (ptr, bytes*items, psf->vio_user_data) / bytes ; |
| |
| items *= bytes ; |
| |
| /* Do this check after the multiplication above. */ |
| if (items <= 0) |
| return 0 ; |
| |
| while (items > 0) |
| { /* Break the read down to a sensible size. */ |
| count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ; |
| |
| count = read (psf->file.filedes, ((char*) ptr) + total, (size_t) count) ; |
| |
| if (count == -1) |
| { if (errno == EINTR) |
| continue ; |
| |
| psf_log_syserr (psf, errno) ; |
| break ; |
| } ; |
| |
| if (count == 0) |
| break ; |
| |
| total += count ; |
| items -= count ; |
| } ; |
| |
| if (psf->is_pipe) |
| psf->pipeoffset += total ; |
| |
| return total / bytes ; |
| } /* psf_fread */ |
| |
| sf_count_t |
| psf_fwrite (const void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf) |
| { sf_count_t total = 0 ; |
| ssize_t count ; |
| |
| if (psf->virtual_io) |
| return psf->vio.write (ptr, bytes*items, psf->vio_user_data) / bytes ; |
| |
| items *= bytes ; |
| |
| /* Do this check after the multiplication above. */ |
| if (items <= 0) |
| return 0 ; |
| |
| while (items > 0) |
| { /* Break the writes down to a sensible size. */ |
| count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : items ; |
| |
| count = write (psf->file.filedes, ((const char*) ptr) + total, count) ; |
| |
| if (count == -1) |
| { if (errno == EINTR) |
| continue ; |
| |
| psf_log_syserr (psf, errno) ; |
| break ; |
| } ; |
| |
| if (count == 0) |
| break ; |
| |
| total += count ; |
| items -= count ; |
| } ; |
| |
| if (psf->is_pipe) |
| psf->pipeoffset += total ; |
| |
| return total / bytes ; |
| } /* psf_fwrite */ |
| |
| sf_count_t |
| psf_ftell (SF_PRIVATE *psf) |
| { sf_count_t pos ; |
| |
| if (psf->virtual_io) |
| return psf->vio.tell (psf->vio_user_data) ; |
| |
| if (psf->is_pipe) |
| return psf->pipeoffset ; |
| |
| pos = lseek (psf->file.filedes, 0, SEEK_CUR) ; |
| |
| if (pos == ((sf_count_t) -1)) |
| { psf_log_syserr (psf, errno) ; |
| return -1 ; |
| } ; |
| |
| return pos - psf->fileoffset ; |
| } /* psf_ftell */ |
| |
| static int |
| psf_close_fd (int fd) |
| { int retval ; |
| |
| if (fd < 0) |
| return 0 ; |
| |
| while ((retval = close (fd)) == -1 && errno == EINTR) |
| /* Do nothing. */ ; |
| |
| return retval ; |
| } /* psf_close_fd */ |
| |
| sf_count_t |
| psf_fgets (char *buffer, sf_count_t bufsize, SF_PRIVATE *psf) |
| { sf_count_t k = 0 ; |
| sf_count_t count ; |
| |
| while (k < bufsize - 1) |
| { count = read (psf->file.filedes, &(buffer [k]), 1) ; |
| |
| if (count == -1) |
| { if (errno == EINTR) |
| continue ; |
| |
| psf_log_syserr (psf, errno) ; |
| break ; |
| } ; |
| |
| if (count == 0 || buffer [k++] == '\n') |
| break ; |
| } ; |
| |
| buffer [k] = 0 ; |
| |
| return k ; |
| } /* psf_fgets */ |
| |
| int |
| psf_is_pipe (SF_PRIVATE *psf) |
| { struct stat statbuf ; |
| |
| if (psf->virtual_io) |
| return SF_FALSE ; |
| |
| if (fstat (psf->file.filedes, &statbuf) == -1) |
| { psf_log_syserr (psf, errno) ; |
| /* Default to maximum safety. */ |
| return SF_TRUE ; |
| } ; |
| |
| if (S_ISFIFO (statbuf.st_mode) || S_ISSOCK (statbuf.st_mode)) |
| return SF_TRUE ; |
| |
| return SF_FALSE ; |
| } /* psf_is_pipe */ |
| |
| static sf_count_t |
| psf_get_filelen_fd (int fd) |
| { struct stat statbuf ; |
| |
| /* |
| ** Sanity check. |
| ** If everything is OK, this will be optimised out. |
| */ |
| if (sizeof (statbuf.st_size) == 4 && sizeof (sf_count_t) == 8) |
| return (sf_count_t) -SFE_BAD_STAT_SIZE ; |
| |
| if (fstat (fd, &statbuf) == -1) |
| return (sf_count_t) -1 ; |
| |
| return statbuf.st_size ; |
| } /* psf_get_filelen_fd */ |
| |
| int |
| psf_ftruncate (SF_PRIVATE *psf, sf_count_t len) |
| { int retval ; |
| |
| /* Returns 0 on success, non-zero on failure. */ |
| if (len < 0) |
| return -1 ; |
| |
| if ((sizeof (off_t) < sizeof (sf_count_t)) && len > 0x7FFFFFFF) |
| return -1 ; |
| |
| retval = ftruncate (psf->file.filedes, len) ; |
| |
| if (retval == -1) |
| psf_log_syserr (psf, errno) ; |
| |
| return retval ; |
| } /* psf_ftruncate */ |
| |
| void |
| psf_init_files (SF_PRIVATE *psf) |
| { psf->file.filedes = -1 ; |
| psf->rsrc.filedes = -1 ; |
| psf->file.savedes = -1 ; |
| } /* psf_init_files */ |
| |
| void |
| psf_use_rsrc (SF_PRIVATE *psf, int on_off) |
| { |
| if (on_off) |
| { if (psf->file.filedes != psf->rsrc.filedes) |
| { psf->file.savedes = psf->file.filedes ; |
| psf->file.filedes = psf->rsrc.filedes ; |
| } ; |
| } |
| else if (psf->file.filedes == psf->rsrc.filedes) |
| psf->file.filedes = psf->file.savedes ; |
| |
| return ; |
| } /* psf_use_rsrc */ |
| |
| static int |
| psf_open_fd (PSF_FILE * pfile) |
| { int fd, oflag, mode ; |
| /* |
| ** Sanity check. If everything is OK, this test and the printfs will |
| ** be optimised out. This is meant to catch the problems caused by |
| ** "sfconfig.h" being included after <stdio.h>. |
| */ |
| if (sizeof (off64_t) != sizeof (sf_count_t)) |
| { puts ("\n\n*** Fatal error : sizeof (off_t) != sizeof (sf_count_t)") ; |
| puts ("*** This means that libsndfile was not configured correctly.\n") ; |
| exit (1) ; |
| } ; |
| switch (pfile->mode) |
| { case SFM_READ : |
| oflag = O_RDONLY | O_BINARY ; |
| mode = 0 ; |
| break ; |
| |
| case SFM_WRITE : |
| oflag = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY ; |
| mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ; |
| break ; |
| |
| case SFM_RDWR : |
| oflag = O_RDWR | O_CREAT | O_BINARY ; |
| mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ; |
| break ; |
| |
| default : |
| return - SFE_BAD_OPEN_MODE ; |
| break ; |
| } ; |
| |
| if (mode == 0) |
| fd = open (pfile->path.c, oflag) ; |
| else |
| fd = open (pfile->path.c, oflag, mode) ; |
| |
| return fd ; |
| } /* psf_open_fd */ |
| |
| static void |
| psf_log_syserr (SF_PRIVATE *psf, int error) |
| { |
| /* Only log an error if no error has been set yet. */ |
| if (psf->error == 0) |
| { psf->error = SFE_SYSTEM ; |
| snprintf (psf->syserr, sizeof (psf->syserr), "System error : %s.", strerror (error)) ; |
| } ; |
| |
| return ; |
| } /* psf_log_syserr */ |
| |
| void |
| psf_fsync (SF_PRIVATE *psf) |
| { |
| #if HAVE_FSYNC |
| if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) |
| fsync (psf->file.filedes) ; |
| #else |
| psf = NULL ; |
| #endif |
| } /* psf_fsync */ |
| |
| #elif USE_WINDOWS_API |
| |
| /* Win32 file i/o functions implemented using native Win32 API */ |
| |
| #include <windows.h> |
| #include <io.h> |
| |
| static int psf_close_handle (HANDLE handle) ; |
| static HANDLE psf_open_handle (PSF_FILE * pfile) ; |
| static sf_count_t psf_get_filelen_handle (HANDLE handle) ; |
| |
| /* USE_WINDOWS_API */ int |
| psf_fopen (SF_PRIVATE *psf) |
| { |
| psf->error = 0 ; |
| psf->file.handle = psf_open_handle (&psf->file) ; |
| |
| if (psf->file.handle == NULL) |
| psf_log_syserr (psf, GetLastError ()) ; |
| |
| return psf->error ; |
| } /* psf_fopen */ |
| |
| /* USE_WINDOWS_API */ int |
| psf_fclose (SF_PRIVATE *psf) |
| { int retval ; |
| |
| if (psf->virtual_io) |
| return 0 ; |
| |
| if (psf->file.do_not_close_descriptor) |
| { psf->file.handle = NULL ; |
| return 0 ; |
| } ; |
| |
| if ((retval = psf_close_handle (psf->file.handle)) == -1) |
| psf_log_syserr (psf, GetLastError ()) ; |
| |
| psf->file.handle = NULL ; |
| |
| return retval ; |
| } /* psf_fclose */ |
| |
| /* USE_WINDOWS_API */ int |
| psf_open_rsrc (SF_PRIVATE *psf) |
| { |
| if (psf->rsrc.handle != NULL) |
| return 0 ; |
| |
| /* Test for MacOSX style resource fork on HPFS or HPFS+ filesystems. */ |
| snprintf (psf->rsrc.path.c, sizeof (psf->rsrc.path.c), "%s/rsrc", psf->file.path.c) ; |
| psf->error = SFE_NO_ERROR ; |
| if ((psf->rsrc.handle = psf_open_handle (&psf->rsrc)) != NULL) |
| { psf->rsrclength = psf_get_filelen_handle (psf->rsrc.handle) ; |
| return SFE_NO_ERROR ; |
| } ; |
| |
| /* |
| ** Now try for a resource fork stored as a separate file in the same |
| ** directory, but preceded with a dot underscore. |
| */ |
| snprintf (psf->rsrc.path.c, sizeof (psf->rsrc.path.c), "%s._%s", psf->file.dir.c, psf->file.name.c) ; |
| psf->error = SFE_NO_ERROR ; |
| if ((psf->rsrc.handle = psf_open_handle (&psf->rsrc)) != NULL) |
| { psf->rsrclength = psf_get_filelen_handle (psf->rsrc.handle) ; |
| return SFE_NO_ERROR ; |
| } ; |
| |
| /* |
| ** Now try for a resource fork stored in a separate file in the |
| ** .AppleDouble/ directory. |
| */ |
| snprintf (psf->rsrc.path.c, sizeof (psf->rsrc.path.c), "%s.AppleDouble/%s", psf->file.dir.c, psf->file.name.c) ; |
| psf->error = SFE_NO_ERROR ; |
| if ((psf->rsrc.handle = psf_open_handle (&psf->rsrc)) != NULL) |
| { psf->rsrclength = psf_get_filelen_handle (psf->rsrc.handle) ; |
| return SFE_NO_ERROR ; |
| } ; |
| |
| /* No resource file found. */ |
| if (psf->rsrc.handle == NULL) |
| psf_log_syserr (psf, GetLastError ()) ; |
| |
| psf->rsrc.handle = NULL ; |
| |
| return psf->error ; |
| } /* psf_open_rsrc */ |
| |
| /* USE_WINDOWS_API */ sf_count_t |
| psf_get_filelen (SF_PRIVATE *psf) |
| { sf_count_t filelen ; |
| |
| if (psf->virtual_io) |
| return psf->vio.get_filelen (psf->vio_user_data) ; |
| |
| filelen = psf_get_filelen_handle (psf->file.handle) ; |
| |
| if (filelen == -1) |
| { psf_log_syserr (psf, errno) ; |
| return (sf_count_t) -1 ; |
| } ; |
| |
| if (filelen == -SFE_BAD_STAT_SIZE) |
| { psf->error = SFE_BAD_STAT_SIZE ; |
| return (sf_count_t) -1 ; |
| } ; |
| |
| switch (psf->file.mode) |
| { case SFM_WRITE : |
| filelen = filelen - psf->fileoffset ; |
| break ; |
| |
| case SFM_READ : |
| if (psf->fileoffset > 0 && psf->filelength > 0) |
| filelen = psf->filelength ; |
| break ; |
| |
| case SFM_RDWR : |
| /* |
| ** Cannot open embedded files SFM_RDWR so we don't need to |
| ** subtract psf->fileoffset. We already have the answer we |
| ** need. |
| */ |
| break ; |
| |
| default : |
| /* Shouldn't be here, so return error. */ |
| filelen = -1 ; |
| } ; |
| |
| return filelen ; |
| } /* psf_get_filelen */ |
| |
| /* USE_WINDOWS_API */ void |
| psf_init_files (SF_PRIVATE *psf) |
| { psf->file.handle = NULL ; |
| psf->rsrc.handle = NULL ; |
| psf->file.hsaved = NULL ; |
| } /* psf_init_files */ |
| |
| /* USE_WINDOWS_API */ void |
| psf_use_rsrc (SF_PRIVATE *psf, int on_off) |
| { |
| if (on_off) |
| { if (psf->file.handle != psf->rsrc.handle) |
| { psf->file.hsaved = psf->file.handle ; |
| psf->file.handle = psf->rsrc.handle ; |
| } ; |
| } |
| else if (psf->file.handle == psf->rsrc.handle) |
| psf->file.handle = psf->file.hsaved ; |
| |
| return ; |
| } /* psf_use_rsrc */ |
| |
| /* USE_WINDOWS_API */ static HANDLE |
| psf_open_handle (PSF_FILE * pfile) |
| { DWORD dwDesiredAccess ; |
| DWORD dwShareMode ; |
| DWORD dwCreationDistribution ; |
| HANDLE handle ; |
| |
| switch (pfile->mode) |
| { case SFM_READ : |
| dwDesiredAccess = GENERIC_READ ; |
| dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ; |
| dwCreationDistribution = OPEN_EXISTING ; |
| break ; |
| |
| case SFM_WRITE : |
| dwDesiredAccess = GENERIC_WRITE ; |
| dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ; |
| dwCreationDistribution = CREATE_ALWAYS ; |
| break ; |
| |
| case SFM_RDWR : |
| dwDesiredAccess = GENERIC_READ | GENERIC_WRITE ; |
| dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ; |
| dwCreationDistribution = OPEN_ALWAYS ; |
| break ; |
| |
| default : |
| return NULL ; |
| } ; |
| |
| if (pfile->use_wchar) |
| handle = CreateFileW ( |
| pfile->path.wc, /* pointer to name of the file */ |
| dwDesiredAccess, /* access (read-write) mode */ |
| dwShareMode, /* share mode */ |
| 0, /* pointer to security attributes */ |
| dwCreationDistribution, /* how to create */ |
| FILE_ATTRIBUTE_NORMAL, /* file attributes (could use FILE_FLAG_SEQUENTIAL_SCAN) */ |
| NULL /* handle to file with attributes to copy */ |
| ) ; |
| else |
| handle = CreateFile ( |
| pfile->path.c, /* pointer to name of the file */ |
| dwDesiredAccess, /* access (read-write) mode */ |
| dwShareMode, /* share mode */ |
| 0, /* pointer to security attributes */ |
| dwCreationDistribution, /* how to create */ |
| FILE_ATTRIBUTE_NORMAL, /* file attributes (could use FILE_FLAG_SEQUENTIAL_SCAN) */ |
| NULL /* handle to file with attributes to copy */ |
| ) ; |
| |
| if (handle == INVALID_HANDLE_VALUE) |
| return NULL ; |
| |
| return handle ; |
| } /* psf_open_handle */ |
| |
| /* USE_WINDOWS_API */ static void |
| psf_log_syserr (SF_PRIVATE *psf, int error) |
| { LPVOID lpMsgBuf ; |
| |
| /* Only log an error if no error has been set yet. */ |
| if (psf->error == 0) |
| { psf->error = SFE_SYSTEM ; |
| |
| FormatMessage ( |
| FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, |
| NULL, |
| error, |
| MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), |
| (LPTSTR) &lpMsgBuf, |
| 0, |
| NULL |
| ) ; |
| |
| snprintf (psf->syserr, sizeof (psf->syserr), "System error : %s", (char*) lpMsgBuf) ; |
| LocalFree (lpMsgBuf) ; |
| } ; |
| |
| return ; |
| } /* psf_log_syserr */ |
| |
| |
| /* USE_WINDOWS_API */ int |
| psf_close_rsrc (SF_PRIVATE *psf) |
| { psf_close_handle (psf->rsrc.handle) ; |
| psf->rsrc.handle = NULL ; |
| return 0 ; |
| } /* psf_close_rsrc */ |
| |
| |
| /* USE_WINDOWS_API */ int |
| psf_set_stdio (SF_PRIVATE *psf) |
| { HANDLE handle = NULL ; |
| int error = 0 ; |
| |
| switch (psf->file.mode) |
| { case SFM_RDWR : |
| error = SFE_OPEN_PIPE_RDWR ; |
| break ; |
| |
| case SFM_READ : |
| handle = GetStdHandle (STD_INPUT_HANDLE) ; |
| psf->file.do_not_close_descriptor = 1 ; |
| break ; |
| |
| case SFM_WRITE : |
| handle = GetStdHandle (STD_OUTPUT_HANDLE) ; |
| psf->file.do_not_close_descriptor = 1 ; |
| break ; |
| |
| default : |
| error = SFE_BAD_OPEN_MODE ; |
| break ; |
| } ; |
| |
| psf->file.handle = handle ; |
| psf->filelength = 0 ; |
| |
| return error ; |
| } /* psf_set_stdio */ |
| |
| /* USE_WINDOWS_API */ void |
| psf_set_file (SF_PRIVATE *psf, int fd) |
| { HANDLE handle ; |
| intptr_t osfhandle ; |
| |
| osfhandle = _get_osfhandle (fd) ; |
| handle = (HANDLE) osfhandle ; |
| |
| psf->file.handle = handle ; |
| } /* psf_set_file */ |
| |
| /* USE_WINDOWS_API */ int |
| psf_file_valid (SF_PRIVATE *psf) |
| { if (psf->file.handle == NULL) |
| return SF_FALSE ; |
| if (psf->file.handle == INVALID_HANDLE_VALUE) |
| return SF_FALSE ; |
| return SF_TRUE ; |
| } /* psf_set_file */ |
| |
| /* USE_WINDOWS_API */ sf_count_t |
| psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence) |
| { sf_count_t new_position ; |
| LONG lDistanceToMove, lDistanceToMoveHigh ; |
| DWORD dwMoveMethod ; |
| DWORD dwResult, dwError ; |
| |
| if (psf->virtual_io) |
| return psf->vio.seek (offset, whence, psf->vio_user_data) ; |
| |
| switch (whence) |
| { case SEEK_SET : |
| offset += psf->fileoffset ; |
| dwMoveMethod = FILE_BEGIN ; |
| break ; |
| |
| case SEEK_END : |
| dwMoveMethod = FILE_END ; |
| break ; |
| |
| default : |
| dwMoveMethod = FILE_CURRENT ; |
| break ; |
| } ; |
| |
| lDistanceToMove = (DWORD) (offset & 0xFFFFFFFF) ; |
| lDistanceToMoveHigh = (DWORD) ((offset >> 32) & 0xFFFFFFFF) ; |
| |
| dwResult = SetFilePointer (psf->file.handle, lDistanceToMove, &lDistanceToMoveHigh, dwMoveMethod) ; |
| |
| if (dwResult == 0xFFFFFFFF) |
| dwError = GetLastError () ; |
| else |
| dwError = NO_ERROR ; |
| |
| if (dwError != NO_ERROR) |
| { psf_log_syserr (psf, dwError) ; |
| return -1 ; |
| } ; |
| |
| new_position = (dwResult + ((__int64) lDistanceToMoveHigh << 32)) - psf->fileoffset ; |
| |
| return new_position ; |
| } /* psf_fseek */ |
| |
| /* USE_WINDOWS_API */ sf_count_t |
| psf_fread (void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf) |
| { sf_count_t total = 0 ; |
| ssize_t count ; |
| DWORD dwNumberOfBytesRead ; |
| |
| if (psf->virtual_io) |
| return psf->vio.read (ptr, bytes*items, psf->vio_user_data) / bytes ; |
| |
| items *= bytes ; |
| |
| /* Do this check after the multiplication above. */ |
| if (items <= 0) |
| return 0 ; |
| |
| while (items > 0) |
| { /* Break the writes down to a sensible size. */ |
| count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ; |
| |
| if (ReadFile (psf->file.handle, ((char*) ptr) + total, count, &dwNumberOfBytesRead, 0) == 0) |
| { psf_log_syserr (psf, GetLastError ()) ; |
| break ; |
| } |
| else |
| count = dwNumberOfBytesRead ; |
| |
| if (count == 0) |
| break ; |
| |
| total += count ; |
| items -= count ; |
| } ; |
| |
| if (psf->is_pipe) |
| psf->pipeoffset += total ; |
| |
| return total / bytes ; |
| } /* psf_fread */ |
| |
| /* USE_WINDOWS_API */ sf_count_t |
| psf_fwrite (const void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf) |
| { sf_count_t total = 0 ; |
| ssize_t count ; |
| DWORD dwNumberOfBytesWritten ; |
| |
| if (psf->virtual_io) |
| return psf->vio.write (ptr, bytes * items, psf->vio_user_data) / bytes ; |
| |
| items *= bytes ; |
| |
| /* Do this check after the multiplication above. */ |
| if (items <= 0) |
| return 0 ; |
| |
| while (items > 0) |
| { /* Break the writes down to a sensible size. */ |
| count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ; |
| |
| if (WriteFile (psf->file.handle, ((const char*) ptr) + total, count, &dwNumberOfBytesWritten, 0) == 0) |
| { psf_log_syserr (psf, GetLastError ()) ; |
| break ; |
| } |
| else |
| count = dwNumberOfBytesWritten ; |
| |
| if (count == 0) |
| break ; |
| |
| total += count ; |
| items -= count ; |
| } ; |
| |
| if (psf->is_pipe) |
| psf->pipeoffset += total ; |
| |
| return total / bytes ; |
| } /* psf_fwrite */ |
| |
| /* USE_WINDOWS_API */ sf_count_t |
| psf_ftell (SF_PRIVATE *psf) |
| { sf_count_t pos ; |
| LONG lDistanceToMoveLow, lDistanceToMoveHigh ; |
| DWORD dwResult, dwError ; |
| |
| if (psf->virtual_io) |
| return psf->vio.tell (psf->vio_user_data) ; |
| |
| if (psf->is_pipe) |
| return psf->pipeoffset ; |
| |
| lDistanceToMoveLow = 0 ; |
| lDistanceToMoveHigh = 0 ; |
| |
| dwResult = SetFilePointer (psf->file.handle, lDistanceToMoveLow, &lDistanceToMoveHigh, FILE_CURRENT) ; |
| |
| if (dwResult == 0xFFFFFFFF) |
| dwError = GetLastError () ; |
| else |
| dwError = NO_ERROR ; |
| |
| if (dwError != NO_ERROR) |
| { psf_log_syserr (psf, dwError) ; |
| return -1 ; |
| } ; |
| |
| pos = (dwResult + ((__int64) lDistanceToMoveHigh << 32)) ; |
| |
| return pos - psf->fileoffset ; |
| } /* psf_ftell */ |
| |
| /* USE_WINDOWS_API */ static int |
| psf_close_handle (HANDLE handle) |
| { if (handle == NULL) |
| return 0 ; |
| |
| if (CloseHandle (handle) == 0) |
| return -1 ; |
| |
| return 0 ; |
| } /* psf_close_handle */ |
| |
| /* USE_WINDOWS_API */ sf_count_t |
| psf_fgets (char *buffer, sf_count_t bufsize, SF_PRIVATE *psf) |
| { sf_count_t k = 0 ; |
| sf_count_t count ; |
| DWORD dwNumberOfBytesRead ; |
| |
| while (k < bufsize - 1) |
| { if (ReadFile (psf->file.handle, &(buffer [k]), 1, &dwNumberOfBytesRead, 0) == 0) |
| { psf_log_syserr (psf, GetLastError ()) ; |
| break ; |
| } |
| else |
| { count = dwNumberOfBytesRead ; |
| /* note that we only check for '\n' not other line endings such as CRLF */ |
| if (count == 0 || buffer [k++] == '\n') |
| break ; |
| } ; |
| } ; |
| |
| buffer [k] = 0 ; |
| |
| return k ; |
| } /* psf_fgets */ |
| |
| /* USE_WINDOWS_API */ int |
| psf_is_pipe (SF_PRIVATE *psf) |
| { |
| if (psf->virtual_io) |
| return SF_FALSE ; |
| |
| if (GetFileType (psf->file.handle) == FILE_TYPE_DISK) |
| return SF_FALSE ; |
| |
| /* Default to maximum safety. */ |
| return SF_TRUE ; |
| } /* psf_is_pipe */ |
| |
| /* USE_WINDOWS_API */ sf_count_t |
| psf_get_filelen_handle (HANDLE handle) |
| { sf_count_t filelen ; |
| DWORD dwFileSizeLow, dwFileSizeHigh, dwError = NO_ERROR ; |
| |
| dwFileSizeLow = GetFileSize (handle, &dwFileSizeHigh) ; |
| |
| if (dwFileSizeLow == 0xFFFFFFFF) |
| dwError = GetLastError () ; |
| |
| if (dwError != NO_ERROR) |
| return (sf_count_t) -1 ; |
| |
| filelen = dwFileSizeLow + ((__int64) dwFileSizeHigh << 32) ; |
| |
| return filelen ; |
| } /* psf_get_filelen_handle */ |
| |
| /* USE_WINDOWS_API */ void |
| psf_fsync (SF_PRIVATE *psf) |
| { FlushFileBuffers (psf->file.handle) ; |
| } /* psf_fsync */ |
| |
| |
| /* USE_WINDOWS_API */ int |
| psf_ftruncate (SF_PRIVATE *psf, sf_count_t len) |
| { int retval = 0 ; |
| LONG lDistanceToMoveLow, lDistanceToMoveHigh ; |
| DWORD dwResult, dwError = NO_ERROR ; |
| |
| /* This implementation trashes the current file position. |
| ** should it save and restore it? what if the current position is past |
| ** the new end of file? |
| */ |
| |
| /* Returns 0 on success, non-zero on failure. */ |
| if (len < 0) |
| return 1 ; |
| |
| lDistanceToMoveLow = (DWORD) (len & 0xFFFFFFFF) ; |
| lDistanceToMoveHigh = (DWORD) ((len >> 32) & 0xFFFFFFFF) ; |
| |
| dwResult = SetFilePointer (psf->file.handle, lDistanceToMoveLow, &lDistanceToMoveHigh, FILE_BEGIN) ; |
| |
| if (dwResult == 0xFFFFFFFF) |
| dwError = GetLastError () ; |
| |
| if (dwError != NO_ERROR) |
| { retval = -1 ; |
| psf_log_syserr (psf, dwError) ; |
| } |
| else |
| { /* Note: when SetEndOfFile is used to extend a file, the contents of the |
| ** new portion of the file is undefined. This is unlike chsize(), |
| ** which guarantees that the new portion of the file will be zeroed. |
| ** Not sure if this is important or not. |
| */ |
| if (SetEndOfFile (psf->file.handle) == 0) |
| { retval = -1 ; |
| psf_log_syserr (psf, GetLastError ()) ; |
| } ; |
| } ; |
| |
| return retval ; |
| } /* psf_ftruncate */ |
| |
| |
| #else |
| /* Win32 file i/o functions implemented using Unix-style file i/o API */ |
| |
| /* Win32 has a 64 file offset seek function: |
| ** |
| ** __int64 _lseeki64 (int handle, __int64 offset, int origin) ; |
| ** |
| ** It also has a 64 bit fstat function: |
| ** |
| ** int fstati64 (int, struct _stati64) ; |
| ** |
| ** but the fscking thing doesn't work!!!!! The file size parameter returned |
| ** by this function is only valid up until more data is written at the end of |
| ** the file. That makes this function completely 100% useless. |
| */ |
| |
| #include <io.h> |
| #include <direct.h> |
| |
| /* Win32 */ int |
| psf_fopen (SF_PRIVATE *psf, const char *pathname, int open_mode) |
| { int oflag, mode ; |
| |
| switch (open_mode) |
| { case SFM_READ : |
| oflag = O_RDONLY | O_BINARY ; |
| mode = 0 ; |
| break ; |
| |
| case SFM_WRITE : |
| oflag = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY ; |
| mode = S_IRUSR | S_IWUSR | S_IRGRP ; |
| break ; |
| |
| case SFM_RDWR : |
| oflag = O_RDWR | O_CREAT | O_BINARY ; |
| mode = S_IRUSR | S_IWUSR | S_IRGRP ; |
| break ; |
| |
| default : |
| psf->error = SFE_BAD_OPEN_MODE ; |
| return -1 ; |
| break ; |
| } ; |
| |
| if (mode == 0) |
| psf->file.filedes = open (pathname, oflag) ; |
| else |
| psf->file.filedes = open (pathname, oflag, mode) ; |
| |
| if (psf->file.filedes == -1) |
| psf_log_syserr (psf, errno) ; |
| |
| return psf->file.filedes ; |
| } /* psf_fopen */ |
| |
| /* Win32 */ sf_count_t |
| psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence) |
| { sf_count_t new_position ; |
| |
| if (psf->virtual_io) |
| return psf->vio.seek (offset, whence, psf->vio_user_data) ; |
| |
| switch (whence) |
| { case SEEK_SET : |
| offset += psf->fileoffset ; |
| break ; |
| |
| case SEEK_END : |
| if (psf->file.mode == SFM_WRITE) |
| { new_position = _lseeki64 (psf->file.filedes, offset, whence) ; |
| |
| if (new_position < 0) |
| psf_log_syserr (psf, errno) ; |
| |
| return new_position - psf->fileoffset ; |
| } ; |
| |
| /* Transform SEEK_END into a SEEK_SET, ie find the file |
| ** length add the requested offset (should be <= 0) to |
| ** get the offset wrt the start of file. |
| */ |
| whence = SEEK_SET ; |
| offset = _lseeki64 (psf->file.filedes, 0, SEEK_END) + offset ; |
| break ; |
| |
| default : |
| /* No need to do anything about SEEK_CUR. */ |
| break ; |
| } ; |
| |
| /* |
| ** Bypass weird Win32-ism if necessary. |
| ** _lseeki64() returns an "invalid parameter" error if called with the |
| ** offset == 0 and whence == SEEK_CUR. |
| *** Use the _telli64() function instead. |
| */ |
| if (offset == 0 && whence == SEEK_CUR) |
| new_position = _telli64 (psf->file.filedes) ; |
| else |
| new_position = _lseeki64 (psf->file.filedes, offset, whence) ; |
| |
| if (new_position < 0) |
| psf_log_syserr (psf, errno) ; |
| |
| new_position -= psf->fileoffset ; |
| |
| return new_position ; |
| } /* psf_fseek */ |
| |
| /* Win32 */ sf_count_t |
| psf_fread (void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf) |
| { sf_count_t total = 0 ; |
| ssize_t count ; |
| |
| if (psf->virtual_io) |
| return psf->vio.read (ptr, bytes*items, psf->vio_user_data) / bytes ; |
| |
| items *= bytes ; |
| |
| /* Do this check after the multiplication above. */ |
| if (items <= 0) |
| return 0 ; |
| |
| while (items > 0) |
| { /* Break the writes down to a sensible size. */ |
| count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ; |
| |
| count = read (psf->file.filedes, ((char*) ptr) + total, (size_t) count) ; |
| |
| if (count == -1) |
| { if (errno == EINTR) |
| continue ; |
| |
| psf_log_syserr (psf, errno) ; |
| break ; |
| } ; |
| |
| if (count == 0) |
| break ; |
| |
| total += count ; |
| items -= count ; |
| } ; |
| |
| return total / bytes ; |
| } /* psf_fread */ |
| |
| /* Win32 */ sf_count_t |
| psf_fwrite (const void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf) |
| { sf_count_t total = 0 ; |
| ssize_t count ; |
| |
| if (psf->virtual_io) |
| return psf->vio.write (ptr, bytes*items, psf->vio_user_data) / bytes ; |
| |
| items *= bytes ; |
| |
| /* Do this check after the multiplication above. */ |
| if (items <= 0) |
| return 0 ; |
| |
| while (items > 0) |
| { /* Break the writes down to a sensible size. */ |
| count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : items ; |
| |
| count = write (psf->file.filedes, ((const char*) ptr) + total, count) ; |
| |
| if (count == -1) |
| { if (errno == EINTR) |
| continue ; |
| |
| psf_log_syserr (psf, errno) ; |
| break ; |
| } ; |
| |
| if (count == 0) |
| break ; |
| |
| total += count ; |
| items -= count ; |
| } ; |
| |
| return total / bytes ; |
| } /* psf_fwrite */ |
| |
| /* Win32 */ sf_count_t |
| psf_ftell (SF_PRIVATE *psf) |
| { sf_count_t pos ; |
| |
| if (psf->virtual_io) |
| return psf->vio.tell (psf->vio_user_data) ; |
| |
| pos = _telli64 (psf->file.filedes) ; |
| |
| if (pos == ((sf_count_t) -1)) |
| { psf_log_syserr (psf, errno) ; |
| return -1 ; |
| } ; |
| |
| return pos - psf->fileoffset ; |
| } /* psf_ftell */ |
| |
| /* Win32 */ int |
| psf_fclose (SF_PRIVATE *psf) |
| { int retval ; |
| |
| while ((retval = close (psf->file.filedes)) == -1 && errno == EINTR) |
| /* Do nothing. */ ; |
| |
| if (retval == -1) |
| psf_log_syserr (psf, errno) ; |
| |
| psf->file.filedes = -1 ; |
| |
| return retval ; |
| } /* psf_fclose */ |
| |
| /* Win32 */ sf_count_t |
| psf_fgets (char *buffer, sf_count_t bufsize, SF_PRIVATE *psf) |
| { sf_count_t k = 0 ; |
| sf_count_t count ; |
| |
| while (k < bufsize - 1) |
| { count = read (psf->file.filedes, &(buffer [k]), 1) ; |
| |
| if (count == -1) |
| { if (errno == EINTR) |
| continue ; |
| |
| psf_log_syserr (psf, errno) ; |
| break ; |
| } ; |
| |
| if (count == 0 || buffer [k++] == '\n') |
| break ; |
| } ; |
| |
| buffer [k] = 0 ; |
| |
| return k ; |
| } /* psf_fgets */ |
| |
| /* Win32 */ int |
| psf_is_pipe (SF_PRIVATE *psf) |
| { struct stat statbuf ; |
| |
| if (psf->virtual_io) |
| return SF_FALSE ; |
| |
| /* Not sure if this works. */ |
| if (fstat (psf->file.filedes, &statbuf) == -1) |
| { psf_log_syserr (psf, errno) ; |
| /* Default to maximum safety. */ |
| return SF_TRUE ; |
| } ; |
| |
| /* These macros are defined in Win32/unistd.h. */ |
| if (S_ISFIFO (statbuf.st_mode) || S_ISSOCK (statbuf.st_mode)) |
| return SF_TRUE ; |
| |
| return SF_FALSE ; |
| } /* psf_checkpipe */ |
| |
| /* Win32 */ sf_count_t |
| psf_get_filelen (SF_PRIVATE *psf) |
| { |
| #if 0 |
| /* |
| ** Windoze is SOOOOO FUCKED!!!!!!! |
| ** This code should work but doesn't. Why? |
| ** Code below does work. |
| */ |
| struct _stati64 statbuf ; |
| |
| if (_fstati64 (psf->file.filedes, &statbuf)) |
| { psf_log_syserr (psf, errno) ; |
| return (sf_count_t) -1 ; |
| } ; |
| |
| return statbuf.st_size ; |
| #else |
| sf_count_t current, filelen ; |
| |
| if (psf->virtual_io) |
| return psf->vio.get_filelen (psf->vio_user_data) ; |
| |
| if ((current = _telli64 (psf->file.filedes)) < 0) |
| { psf_log_syserr (psf, errno) ; |
| return (sf_count_t) -1 ; |
| } ; |
| |
| /* |
| ** Lets face it, windoze if FUBAR!!! |
| ** |
| ** For some reason, I have to call _lseeki64() TWICE to get to the |
| ** end of the file. |
| ** |
| ** This might have been avoided if windows had implemented the POSIX |
| ** standard function fsync() but NO, that would have been too easy. |
| ** |
| ** I am VERY close to saying that windoze will no longer be supported |
| ** by libsndfile and changing the license to GPL at the same time. |
| */ |
| |
| _lseeki64 (psf->file.filedes, 0, SEEK_END) ; |
| |
| if ((filelen = _lseeki64 (psf->file.filedes, 0, SEEK_END)) < 0) |
| { psf_log_syserr (psf, errno) ; |
| return (sf_count_t) -1 ; |
| } ; |
| |
| if (filelen > current) |
| _lseeki64 (psf->file.filedes, current, SEEK_SET) ; |
| |
| switch (psf->file.mode) |
| { case SFM_WRITE : |
| filelen = filelen - psf->fileoffset ; |
| break ; |
| |
| case SFM_READ : |
| if (psf->fileoffset > 0 && psf->filelength > 0) |
| filelen = psf->filelength ; |
| break ; |
| |
| case SFM_RDWR : |
| /* |
| ** Cannot open embedded files SFM_RDWR so we don't need to |
| ** subtract psf->fileoffset. We already have the answer we |
| ** need. |
| */ |
| break ; |
| |
| default : |
| filelen = 0 ; |
| } ; |
| |
| return filelen ; |
| #endif |
| } /* psf_get_filelen */ |
| |
| /* Win32 */ int |
| psf_ftruncate (SF_PRIVATE *psf, sf_count_t len) |
| { int retval ; |
| |
| /* Returns 0 on success, non-zero on failure. */ |
| if (len < 0) |
| return 1 ; |
| |
| /* The global village idiots at micorsoft decided to implement |
| ** nearly all the required 64 bit file offset functions except |
| ** for one, truncate. The fscking morons! |
| ** |
| ** This is not 64 bit file offset clean. Somone needs to clean |
| ** this up. |
| */ |
| if (len > 0x7FFFFFFF) |
| return -1 ; |
| |
| retval = chsize (psf->file.filedes, len) ; |
| |
| if (retval == -1) |
| psf_log_syserr (psf, errno) ; |
| |
| return retval ; |
| } /* psf_ftruncate */ |
| |
| |
| static void |
| psf_log_syserr (SF_PRIVATE *psf, int error) |
| { |
| /* Only log an error if no error has been set yet. */ |
| if (psf->error == 0) |
| { psf->error = SFE_SYSTEM ; |
| snprintf (psf->syserr, sizeof (psf->syserr), "System error : %s", strerror (error)) ; |
| } ; |
| |
| return ; |
| } /* psf_log_syserr */ |
| |
| #endif |
| |