furnace/extern/libsndfile-modified/src/file_io.c
tildearrow 061991fe60 desubmodulize libsndfile - PLEASE READ
it appears a one-character typo in the cmake_minimum_required line prevents it from compiling under CMake 4.0.
in order to fix that, I had to take this thing out of submodules...

it is recommended to do this after you pull;

git submodule deinit extern/libsndfile
2025-04-02 15:09:53 -05:00

1207 lines
27 KiB
C

/*
** Copyright (C) 2002-2014 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"
#if USE_WINDOWS_API
/* Don't include rarely used headers, speed up build */
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#else
#include <io.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) ;
int
psf_copy_filename (SF_PRIVATE *psf, const char *path)
{ const char *ccptr ;
char *cptr ;
if (strlen (path) > 1 && strlen (path) - 1 >= sizeof (psf->file.path))
{ psf->error = SFE_FILENAME_TOO_LONG ;
return psf->error ;
} ;
snprintf (psf->file.path, sizeof (psf->file.path), "%s", path) ;
if ((ccptr = strrchr (path, '/')) || (ccptr = strrchr (path, '\\')))
ccptr ++ ;
else
ccptr = path ;
snprintf (psf->file.name, sizeof (psf->file.name), "%s", ccptr) ;
/* Now grab the directory. */
snprintf (psf->file.dir, sizeof (psf->file.dir), "%s", path) ;
if ((cptr = strrchr (psf->file.dir, '/')) || (cptr = strrchr (psf->file.dir, '\\')))
cptr [1] = 0 ;
else
psf->file.dir [0] = 0 ;
return 0 ;
} /* psf_copy_filename */
#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)
{ size_t count ;
if (psf->rsrc.filedes > 0)
return 0 ;
/* Test for MacOSX style resource fork on HPFS or HPFS+ filesystems. */
count = snprintf (psf->rsrc.path, sizeof (psf->rsrc.path), "%s/..namedfork/rsrc", psf->file.path) ;
psf->error = SFE_NO_ERROR ;
if (count < sizeof (psf->rsrc.path))
{ 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.
*/
count = snprintf (psf->rsrc.path, sizeof (psf->rsrc.path), "%s._%s", psf->file.dir, psf->file.name) ;
psf->error = SFE_NO_ERROR ;
if (count < sizeof (psf->rsrc.path) && (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.
*/
count = snprintf (psf->rsrc.path, sizeof (psf->rsrc.path), "%s.AppleDouble/%s", psf->file.dir, psf->file.name) ;
psf->error = SFE_NO_ERROR ;
if (count < sizeof (psf->rsrc.path))
{ 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) ;
}
else
{ psf->error = SFE_OPEN_FAILED ;
} ;
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 absolute_position ;
if (psf->virtual_io)
return psf->vio.seek (offset, whence, psf->vio_user_data) ;
/* When decoding from pipes sometimes see seeks to the pipeoffset, which appears to mean do nothing. */
if (psf->is_pipe)
{ if (whence != SEEK_SET || offset != psf->pipeoffset)
psf_log_printf (psf, "psf_fseek : pipe seek to value other than pipeoffset\n") ;
return offset ;
}
switch (whence)
{ case SEEK_SET :
offset += psf->fileoffset ;
break ;
case SEEK_END :
break ;
case SEEK_CUR :
break ;
default :
/* We really should not be here. */
psf_log_printf (psf, "psf_fseek : whence is %d *****.\n", whence) ;
return 0 ;
} ;
absolute_position = lseek (psf->file.filedes, offset, whence) ;
if (absolute_position < 0)
psf_log_syserr (psf, errno) ;
return absolute_position - psf->fileoffset ;
} /* 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 (bytes == 0 || items == 0)
return 0 ;
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)
{
#if (SIZEOF_OFF_T == 4 && HAVE_FSTAT64)
struct stat64 statbuf ;
if (fstat64 (fd, &statbuf) == -1)
return (sf_count_t) -1 ;
return statbuf.st_size ;
#else
struct stat statbuf ;
if (fstat (fd, &statbuf) == -1)
return (sf_count_t) -1 ;
return statbuf.st_size ;
#endif
} /* 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 (sf_count_t) != 8)
{ puts ("\n\n*** Fatal error : sizeof (sf_count_t) != 8") ;
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_IWGRP | S_IROTH | S_IWOTH ;
break ;
case SFM_RDWR :
oflag = O_RDWR | O_CREAT | O_BINARY ;
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ;
break ;
default :
return - SFE_BAD_OPEN_MODE ;
break ;
} ;
if (mode == 0)
fd = open (pfile->path, oflag) ;
else
fd = open (pfile->path, 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 */
#else
/* Win32 file i/o functions implemented using native Win32 API */
#ifndef WINAPI_PARTITION_SYSTEM
#define WINAPI_PARTITION_SYSTEM 0
#endif
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 == INVALID_HANDLE_VALUE)
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 = INVALID_HANDLE_VALUE ;
return 0 ;
} ;
if ((retval = psf_close_handle (psf->file.handle)) == -1)
psf_log_syserr (psf, GetLastError ()) ;
psf->file.handle = INVALID_HANDLE_VALUE ;
return retval ;
} /* psf_fclose */
/* USE_WINDOWS_API */ int
psf_open_rsrc (SF_PRIVATE *psf)
{
if (psf->rsrc.handle != INVALID_HANDLE_VALUE)
return 0 ;
/* Test for MacOSX style resource fork on HPFS or HPFS+ filesystems. */
snprintf (psf->rsrc.path, sizeof (psf->rsrc.path), "%s/rsrc", psf->file.path) ;
psf->error = SFE_NO_ERROR ;
if ((psf->rsrc.handle = psf_open_handle (&psf->rsrc)) != INVALID_HANDLE_VALUE)
{ 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, sizeof (psf->rsrc.path), "%s._%s", psf->file.dir, psf->file.name) ;
psf->error = SFE_NO_ERROR ;
if ((psf->rsrc.handle = psf_open_handle (&psf->rsrc)) != INVALID_HANDLE_VALUE)
{ 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, sizeof (psf->rsrc.path), "%s.AppleDouble/%s", psf->file.dir, psf->file.name) ;
psf->error = SFE_NO_ERROR ;
if ((psf->rsrc.handle = psf_open_handle (&psf->rsrc)) != INVALID_HANDLE_VALUE)
{ psf->rsrclength = psf_get_filelen_handle (psf->rsrc.handle) ;
return SFE_NO_ERROR ;
} ;
/* No resource file found. */
if (psf->rsrc.handle == INVALID_HANDLE_VALUE)
psf_log_syserr (psf, GetLastError ()) ;
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 = INVALID_HANDLE_VALUE ;
psf->rsrc.handle = INVALID_HANDLE_VALUE ;
psf->file.hsaved = INVALID_HANDLE_VALUE ;
} /* 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 ;
LPWSTR pwszPath = NULL ;
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 INVALID_HANDLE_VALUE ;
} ;
int nResult = MultiByteToWideChar (CP_UTF8, 0, pfile->path, -1, NULL, 0) ;
pwszPath = malloc (nResult * sizeof (WCHAR)) ;
if (!pwszPath)
return INVALID_HANDLE_VALUE ;
int nResult2 = MultiByteToWideChar (CP_UTF8, 0, pfile->path, -1, pwszPath, nResult) ;
if (nResult != nResult2)
{ free (pwszPath) ;
return INVALID_HANDLE_VALUE ;
} ;
#if defined (WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
CREATEFILE2_EXTENDED_PARAMETERS cfParams = { 0 } ;
cfParams.dwSize = sizeof (CREATEFILE2_EXTENDED_PARAMETERS) ;
cfParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL ;
handle = CreateFile2 (pwszPath, dwDesiredAccess, dwShareMode, dwCreationDistribution, &cfParams) ;
#else
handle = CreateFileW (
pwszPath, /* 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 */
) ;
#endif
free (pwszPath) ;
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 = INVALID_HANDLE_VALUE ;
return 0 ;
} /* psf_close_rsrc */
/* USE_WINDOWS_API */ int
psf_set_stdio (SF_PRIVATE *psf)
{ HANDLE handle = INVALID_HANDLE_VALUE ;
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 == 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 ;
LARGE_INTEGER liDistanceToMove, liNewFilePointer ;
DWORD dwMoveMethod ;
BOOL fResult ;
DWORD 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 ;
} ;
liDistanceToMove.QuadPart = offset ;
fResult = SetFilePointerEx (psf->file.handle, liDistanceToMove, &liNewFilePointer, dwMoveMethod) ;
if (fResult == FALSE)
dwError = GetLastError () ;
else
dwError = NO_ERROR ;
if (dwError != NO_ERROR)
{ psf_log_syserr (psf, dwError) ;
return -1 ;
} ;
new_position = liNewFilePointer.QuadPart - 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 ;
LARGE_INTEGER liDistanceToMove, liNewFilePointer ;
BOOL fResult ;
DWORD dwError ;
if (psf->virtual_io)
return psf->vio.tell (psf->vio_user_data) ;
if (psf->is_pipe)
return psf->pipeoffset ;
liDistanceToMove.QuadPart = 0 ;
fResult = SetFilePointerEx (psf->file.handle, liDistanceToMove, &liNewFilePointer, FILE_CURRENT) ;
if (fResult == FALSE)
dwError = GetLastError () ;
else
dwError = NO_ERROR ;
if (dwError != NO_ERROR)
{ psf_log_syserr (psf, dwError) ;
return -1 ;
} ;
pos = liNewFilePointer.QuadPart ;
return pos - psf->fileoffset ;
} /* psf_ftell */
/* USE_WINDOWS_API */ static int
psf_close_handle (HANDLE handle)
{ if (handle == INVALID_HANDLE_VALUE)
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 ;
LARGE_INTEGER liFileSize ;
BOOL fResult ;
DWORD dwError = NO_ERROR ;
fResult = GetFileSizeEx (handle, &liFileSize) ;
if (fResult == FALSE)
dwError = GetLastError () ;
if (dwError != NO_ERROR)
return (sf_count_t) -1 ;
filelen = liFileSize.QuadPart ;
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 ;
LARGE_INTEGER liDistanceToMove ;
BOOL fResult ;
DWORD 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 ;
liDistanceToMove.QuadPart = (sf_count_t) len ;
fResult = SetFilePointerEx (psf->file.handle, liDistanceToMove, NULL, FILE_BEGIN) ;
if (fResult == FALSE)
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 */
#endif