1 /*
2 ** Copyright (C) 2002-2014 Erik de Castro Lopo <erikd@mega-nerd.com>
3 ** Copyright (C) 2003 Ross Bencina <rbencina@iprimus.com.au>
4 **
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.
9 **
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.
14 **
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.
18 */
19 
20 /*
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.
28 */
29 
30 /*
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.
33 */
34 
35 #include "sfconfig.h"
36 
37 #if USE_WINDOWS_API
38 
39 /* Don't include rarely used headers, speed up build */
40 #define WIN32_LEAN_AND_MEAN
41 
42 #include <windows.h>
43 #endif
44 
45 #include <stdio.h>
46 #include <stdlib.h>
47 
48 #if HAVE_UNISTD_H
49 #include <unistd.h>
50 #else
51 #include <io.h>
52 #endif
53 
54 #if (HAVE_DECL_S_IRGRP == 0)
55 #include <sf_unistd.h>
56 #endif
57 
58 #include <string.h>
59 #include <fcntl.h>
60 #include <errno.h>
61 #include <sys/stat.h>
62 
63 #include "sndfile.h"
64 #include "common.h"
65 
66 #define	SENSIBLE_SIZE	(0x40000000)
67 
68 /*
69 **	Neat solution to the Win32/OS2 binary file flage requirement.
70 **	If O_BINARY isn't already defined by the inclusion of the system
71 **	headers, set it to zero.
72 */
73 #ifndef O_BINARY
74 #define O_BINARY 0
75 #endif
76 
77 static void psf_log_syserr (SF_PRIVATE *psf, int error) ;
78 
79 #if (USE_WINDOWS_API == 0)
80 
81 /*------------------------------------------------------------------------------
82 ** Win32 stuff at the bottom of the file. Unix and other sensible OSes here.
83 */
84 
85 static int psf_close_fd (int fd) ;
86 static int psf_open_fd (PSF_FILE * pfile) ;
87 static sf_count_t psf_get_filelen_fd (int fd) ;
88 
89 int
psf_fopen(SF_PRIVATE * psf)90 psf_fopen (SF_PRIVATE *psf)
91 {
92 	psf->error = 0 ;
93 	psf->file.filedes = psf_open_fd (&psf->file) ;
94 
95 	if (psf->file.filedes == - SFE_BAD_OPEN_MODE)
96 	{	psf->error = SFE_BAD_OPEN_MODE ;
97 		psf->file.filedes = -1 ;
98 		return psf->error ;
99 		} ;
100 
101 	if (psf->file.filedes == -1)
102 		psf_log_syserr (psf, errno) ;
103 
104 	return psf->error ;
105 } /* psf_fopen */
106 
107 int
psf_fclose(SF_PRIVATE * psf)108 psf_fclose (SF_PRIVATE *psf)
109 {	int retval ;
110 
111 	if (psf->virtual_io)
112 		return 0 ;
113 
114 	if (psf->file.do_not_close_descriptor)
115 	{	psf->file.filedes = -1 ;
116 		return 0 ;
117 		} ;
118 
119 	if ((retval = psf_close_fd (psf->file.filedes)) == -1)
120 		psf_log_syserr (psf, errno) ;
121 
122 	psf->file.filedes = -1 ;
123 
124 	return retval ;
125 } /* psf_fclose */
126 
127 int
psf_open_rsrc(SF_PRIVATE * psf)128 psf_open_rsrc (SF_PRIVATE *psf)
129 {	size_t count ;
130 
131 	if (psf->rsrc.filedes > 0)
132 		return 0 ;
133 
134 	/* Test for MacOSX style resource fork on HPFS or HPFS+ filesystems. */
135 	count = snprintf (psf->rsrc.path.c, sizeof (psf->rsrc.path.c), "%s/..namedfork/rsrc", psf->file.path.c) ;
136 	psf->error = SFE_NO_ERROR ;
137 	if (count < sizeof (psf->rsrc.path.c))
138 	{	if ((psf->rsrc.filedes = psf_open_fd (&psf->rsrc)) >= 0)
139 		{	psf->rsrclength = psf_get_filelen_fd (psf->rsrc.filedes) ;
140 			if (psf->rsrclength > 0 || (psf->rsrc.mode & SFM_WRITE))
141 				return SFE_NO_ERROR ;
142 			psf_close_fd (psf->rsrc.filedes) ;
143 			psf->rsrc.filedes = -1 ;
144 			} ;
145 
146 		if (psf->rsrc.filedes == - SFE_BAD_OPEN_MODE)
147 		{	psf->error = SFE_BAD_OPEN_MODE ;
148 			return psf->error ;
149 			} ;
150 		} ;
151 
152 	/*
153 	** Now try for a resource fork stored as a separate file in the same
154 	** directory, but preceded with a dot underscore.
155 	*/
156 	count = snprintf (psf->rsrc.path.c, sizeof (psf->rsrc.path.c), "%s._%s", psf->file.dir.c, psf->file.name.c) ;
157 	psf->error = SFE_NO_ERROR ;
158 	if (count < sizeof (psf->rsrc.path.c) && (psf->rsrc.filedes = psf_open_fd (&psf->rsrc)) >= 0)
159 	{	psf->rsrclength = psf_get_filelen_fd (psf->rsrc.filedes) ;
160 		return SFE_NO_ERROR ;
161 		} ;
162 
163 	/*
164 	** Now try for a resource fork stored in a separate file in the
165 	** .AppleDouble/ directory.
166 	*/
167 	count = snprintf (psf->rsrc.path.c, sizeof (psf->rsrc.path.c), "%s.AppleDouble/%s", psf->file.dir.c, psf->file.name.c) ;
168 	psf->error = SFE_NO_ERROR ;
169 	if (count < sizeof (psf->rsrc.path.c))
170 	{	if ((psf->rsrc.filedes = psf_open_fd (&psf->rsrc)) >= 0)
171 		{	psf->rsrclength = psf_get_filelen_fd (psf->rsrc.filedes) ;
172 			return SFE_NO_ERROR ;
173 			} ;
174 
175 		/* No resource file found. */
176 		if (psf->rsrc.filedes == -1)
177 			psf_log_syserr (psf, errno) ;
178 		}
179 	else
180 	{	psf->error = SFE_OPEN_FAILED ;
181 		} ;
182 
183 	psf->rsrc.filedes = -1 ;
184 
185 	return psf->error ;
186 } /* psf_open_rsrc */
187 
188 sf_count_t
psf_get_filelen(SF_PRIVATE * psf)189 psf_get_filelen (SF_PRIVATE *psf)
190 {	sf_count_t	filelen ;
191 
192 	if (psf->virtual_io)
193 		return psf->vio.get_filelen (psf->vio_user_data) ;
194 
195 	filelen = psf_get_filelen_fd (psf->file.filedes) ;
196 
197 	if (filelen == -1)
198 	{	psf_log_syserr (psf, errno) ;
199 		return (sf_count_t) -1 ;
200 		} ;
201 
202 	if (filelen == -SFE_BAD_STAT_SIZE)
203 	{	psf->error = SFE_BAD_STAT_SIZE ;
204 		return (sf_count_t) -1 ;
205 		} ;
206 
207 	switch (psf->file.mode)
208 	{	case SFM_WRITE :
209 			filelen = filelen - psf->fileoffset ;
210 			break ;
211 
212 		case SFM_READ :
213 			if (psf->fileoffset > 0 && psf->filelength > 0)
214 				filelen = psf->filelength ;
215 			break ;
216 
217 		case SFM_RDWR :
218 			/*
219 			** Cannot open embedded files SFM_RDWR so we don't need to
220 			** subtract psf->fileoffset. We already have the answer we
221 			** need.
222 			*/
223 			break ;
224 
225 		default :
226 			/* Shouldn't be here, so return error. */
227 			filelen = -1 ;
228 		} ;
229 
230 	return filelen ;
231 } /* psf_get_filelen */
232 
233 int
psf_close_rsrc(SF_PRIVATE * psf)234 psf_close_rsrc (SF_PRIVATE *psf)
235 {	psf_close_fd (psf->rsrc.filedes) ;
236 	psf->rsrc.filedes = -1 ;
237 	return 0 ;
238 } /* psf_close_rsrc */
239 
240 int
psf_set_stdio(SF_PRIVATE * psf)241 psf_set_stdio (SF_PRIVATE *psf)
242 {	int	error = 0 ;
243 
244 	switch (psf->file.mode)
245 	{	case SFM_RDWR :
246 				error = SFE_OPEN_PIPE_RDWR ;
247 				break ;
248 
249 		case SFM_READ :
250 				psf->file.filedes = 0 ;
251 				break ;
252 
253 		case SFM_WRITE :
254 				psf->file.filedes = 1 ;
255 				break ;
256 
257 		default :
258 				error = SFE_BAD_OPEN_MODE ;
259 				break ;
260 		} ;
261 	psf->filelength = 0 ;
262 
263 	return error ;
264 } /* psf_set_stdio */
265 
266 void
psf_set_file(SF_PRIVATE * psf,int fd)267 psf_set_file (SF_PRIVATE *psf, int fd)
268 {	psf->file.filedes = fd ;
269 } /* psf_set_file */
270 
271 int
psf_file_valid(SF_PRIVATE * psf)272 psf_file_valid (SF_PRIVATE *psf)
273 {	return (psf->file.filedes >= 0) ? SF_TRUE : SF_FALSE ;
274 } /* psf_set_file */
275 
276 sf_count_t
psf_fseek(SF_PRIVATE * psf,sf_count_t offset,int whence)277 psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence)
278 {	sf_count_t	absolute_position ;
279 
280 	if (psf->virtual_io)
281 		return psf->vio.seek (offset, whence, psf->vio_user_data) ;
282 
283 	/* When decoding from pipes sometimes see seeks to the pipeoffset, which appears to mean do nothing. */
284 	if (psf->is_pipe)
285 	{	if (whence != SEEK_SET || offset != psf->pipeoffset)
286 			psf_log_printf (psf, "psf_fseek : pipe seek to value other than pipeoffset\n") ;
287 		return offset ;
288 		}
289 
290 	switch (whence)
291 	{	case SEEK_SET :
292 				offset += psf->fileoffset ;
293 				break ;
294 
295 		case SEEK_END :
296 				break ;
297 
298 		case SEEK_CUR :
299 				break ;
300 
301 		default :
302 				/* We really should not be here. */
303 				psf_log_printf (psf, "psf_fseek : whence is %d *****.\n", whence) ;
304 				return 0 ;
305 		} ;
306 
307 	absolute_position = lseek (psf->file.filedes, offset, whence) ;
308 
309 	if (absolute_position < 0)
310 		psf_log_syserr (psf, errno) ;
311 
312 	return absolute_position - psf->fileoffset ;
313 } /* psf_fseek */
314 
315 sf_count_t
psf_fread(void * ptr,sf_count_t bytes,sf_count_t items,SF_PRIVATE * psf)316 psf_fread (void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf)
317 {	sf_count_t total = 0 ;
318 	ssize_t	count ;
319 
320 	if (psf->virtual_io)
321 		return psf->vio.read (ptr, bytes*items, psf->vio_user_data) / bytes ;
322 
323 	items *= bytes ;
324 
325 	/* Do this check after the multiplication above. */
326 	if (items <= 0)
327 		return 0 ;
328 
329 	while (items > 0)
330 	{	/* Break the read down to a sensible size. */
331 		count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ;
332 
333 		count = read (psf->file.filedes, ((char*) ptr) + total, (size_t) count) ;
334 
335 		if (count == -1)
336 		{	if (errno == EINTR)
337 				continue ;
338 
339 			psf_log_syserr (psf, errno) ;
340 			break ;
341 			} ;
342 
343 		if (count == 0)
344 			break ;
345 
346 		total += count ;
347 		items -= count ;
348 		} ;
349 
350 	if (psf->is_pipe)
351 		psf->pipeoffset += total ;
352 
353 	return total / bytes ;
354 } /* psf_fread */
355 
356 sf_count_t
psf_fwrite(const void * ptr,sf_count_t bytes,sf_count_t items,SF_PRIVATE * psf)357 psf_fwrite (const void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf)
358 {	sf_count_t total = 0 ;
359 	ssize_t	count ;
360 
361 	if (bytes == 0 || items == 0)
362 		return 0 ;
363 
364 	if (psf->virtual_io)
365 		return psf->vio.write (ptr, bytes*items, psf->vio_user_data) / bytes ;
366 
367 	items *= bytes ;
368 
369 	/* Do this check after the multiplication above. */
370 	if (items <= 0)
371 		return 0 ;
372 
373 	while (items > 0)
374 	{	/* Break the writes down to a sensible size. */
375 		count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : items ;
376 
377 		count = write (psf->file.filedes, ((const char*) ptr) + total, count) ;
378 
379 		if (count == -1)
380 		{	if (errno == EINTR)
381 				continue ;
382 
383 			psf_log_syserr (psf, errno) ;
384 			break ;
385 			} ;
386 
387 		if (count == 0)
388 			break ;
389 
390 		total += count ;
391 		items -= count ;
392 		} ;
393 
394 	if (psf->is_pipe)
395 		psf->pipeoffset += total ;
396 
397 	return total / bytes ;
398 } /* psf_fwrite */
399 
400 sf_count_t
psf_ftell(SF_PRIVATE * psf)401 psf_ftell (SF_PRIVATE *psf)
402 {	sf_count_t pos ;
403 
404 	if (psf->virtual_io)
405 		return psf->vio.tell (psf->vio_user_data) ;
406 
407 	if (psf->is_pipe)
408 		return psf->pipeoffset ;
409 
410 	pos = lseek (psf->file.filedes, 0, SEEK_CUR) ;
411 
412 	if (pos == ((sf_count_t) -1))
413 	{	psf_log_syserr (psf, errno) ;
414 		return -1 ;
415 		} ;
416 
417 	return pos - psf->fileoffset ;
418 } /* psf_ftell */
419 
420 static int
psf_close_fd(int fd)421 psf_close_fd (int fd)
422 {	int retval ;
423 
424 	if (fd < 0)
425 		return 0 ;
426 
427 	while ((retval = close (fd)) == -1 && errno == EINTR)
428 		/* Do nothing. */ ;
429 
430 	return retval ;
431 } /* psf_close_fd */
432 
433 sf_count_t
psf_fgets(char * buffer,sf_count_t bufsize,SF_PRIVATE * psf)434 psf_fgets (char *buffer, sf_count_t bufsize, SF_PRIVATE *psf)
435 {	sf_count_t	k = 0 ;
436 	sf_count_t		count ;
437 
438 	while (k < bufsize - 1)
439 	{	count = read (psf->file.filedes, &(buffer [k]), 1) ;
440 
441 		if (count == -1)
442 		{	if (errno == EINTR)
443 				continue ;
444 
445 			psf_log_syserr (psf, errno) ;
446 			break ;
447 			} ;
448 
449 		if (count == 0 || buffer [k++] == '\n')
450 			break ;
451 		} ;
452 
453 	buffer [k] = 0 ;
454 
455 	return k ;
456 } /* psf_fgets */
457 
458 int
psf_is_pipe(SF_PRIVATE * psf)459 psf_is_pipe (SF_PRIVATE *psf)
460 {	struct stat statbuf ;
461 
462 	if (psf->virtual_io)
463 		return SF_FALSE ;
464 
465 	if (fstat (psf->file.filedes, &statbuf) == -1)
466 	{	psf_log_syserr (psf, errno) ;
467 		/* Default to maximum safety. */
468 		return SF_TRUE ;
469 		} ;
470 
471 	if (S_ISFIFO (statbuf.st_mode) || S_ISSOCK (statbuf.st_mode))
472 		return SF_TRUE ;
473 
474 	return SF_FALSE ;
475 } /* psf_is_pipe */
476 
477 static sf_count_t
psf_get_filelen_fd(int fd)478 psf_get_filelen_fd (int fd)
479 {
480 #if (SIZEOF_OFF_T == 4 && SIZEOF_SF_COUNT_T == 8 && HAVE_FSTAT64)
481 	struct stat64 statbuf ;
482 
483 	if (fstat64 (fd, &statbuf) == -1)
484 		return (sf_count_t) -1 ;
485 
486 	return statbuf.st_size ;
487 #else
488 	struct stat statbuf ;
489 
490 	if (fstat (fd, &statbuf) == -1)
491 		return (sf_count_t) -1 ;
492 
493 	return statbuf.st_size ;
494 #endif
495 } /* psf_get_filelen_fd */
496 
497 int
psf_ftruncate(SF_PRIVATE * psf,sf_count_t len)498 psf_ftruncate (SF_PRIVATE *psf, sf_count_t len)
499 {	int retval ;
500 
501 	/* Returns 0 on success, non-zero on failure. */
502 	if (len < 0)
503 		return -1 ;
504 
505 	if ((sizeof (off_t) < sizeof (sf_count_t)) && len > 0x7FFFFFFF)
506 		return -1 ;
507 
508 	retval = ftruncate (psf->file.filedes, len) ;
509 
510 	if (retval == -1)
511 		psf_log_syserr (psf, errno) ;
512 
513 	return retval ;
514 } /* psf_ftruncate */
515 
516 void
psf_init_files(SF_PRIVATE * psf)517 psf_init_files (SF_PRIVATE *psf)
518 {	psf->file.filedes = -1 ;
519 	psf->rsrc.filedes = -1 ;
520 	psf->file.savedes = -1 ;
521 } /* psf_init_files */
522 
523 void
psf_use_rsrc(SF_PRIVATE * psf,int on_off)524 psf_use_rsrc (SF_PRIVATE *psf, int on_off)
525 {
526 	if (on_off)
527 	{	if (psf->file.filedes != psf->rsrc.filedes)
528 		{	psf->file.savedes = psf->file.filedes ;
529 			psf->file.filedes = psf->rsrc.filedes ;
530 			} ;
531 		}
532 	else if (psf->file.filedes == psf->rsrc.filedes)
533 		psf->file.filedes = psf->file.savedes ;
534 
535 	return ;
536 } /* psf_use_rsrc */
537 
538 static int
psf_open_fd(PSF_FILE * pfile)539 psf_open_fd (PSF_FILE * pfile)
540 {	int fd, oflag, mode ;
541 
542 	/*
543 	** Sanity check. If everything is OK, this test and the printfs will
544 	** be optimised out. This is meant to catch the problems caused by
545 	** "sfconfig.h" being included after <stdio.h>.
546 	*/
547 	if (sizeof (sf_count_t) != 8)
548 	{	puts ("\n\n*** Fatal error : sizeof (sf_count_t) != 8") ;
549 		puts ("*** This means that libsndfile was not configured correctly.\n") ;
550 		exit (1) ;
551 		} ;
552 
553 	switch (pfile->mode)
554 	{	case SFM_READ :
555 				oflag = O_RDONLY | O_BINARY ;
556 				mode = 0 ;
557 				break ;
558 
559 		case SFM_WRITE :
560 				oflag = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY ;
561 				mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ;
562 				break ;
563 
564 		case SFM_RDWR :
565 				oflag = O_RDWR | O_CREAT | O_BINARY ;
566 				mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ;
567 				break ;
568 
569 		default :
570 				return - SFE_BAD_OPEN_MODE ;
571 				break ;
572 		} ;
573 
574 	if (mode == 0)
575 		fd = open (pfile->path.c, oflag) ;
576 	else
577 		fd = open (pfile->path.c, oflag, mode) ;
578 
579 	return fd ;
580 } /* psf_open_fd */
581 
582 static void
psf_log_syserr(SF_PRIVATE * psf,int error)583 psf_log_syserr (SF_PRIVATE *psf, int error)
584 {
585 	/* Only log an error if no error has been set yet. */
586 	if (psf->error == 0)
587 	{	psf->error = SFE_SYSTEM ;
588 		snprintf (psf->syserr, sizeof (psf->syserr), "System error : %s.", strerror (error)) ;
589 		} ;
590 
591 	return ;
592 } /* psf_log_syserr */
593 
594 void
psf_fsync(SF_PRIVATE * psf)595 psf_fsync (SF_PRIVATE *psf)
596 {
597 #if HAVE_FSYNC
598 	if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
599 		fsync (psf->file.filedes) ;
600 #else
601 	psf = NULL ;
602 #endif
603 } /* psf_fsync */
604 
605 #elif	USE_WINDOWS_API
606 
607 /* Win32 file i/o functions implemented using native Win32 API */
608 
609 #ifndef WINAPI_PARTITION_SYSTEM
610 #define WINAPI_PARTITION_SYSTEM 0
611 #endif
612 
613 static int psf_close_handle (HANDLE handle) ;
614 static HANDLE psf_open_handle (PSF_FILE * pfile) ;
615 static sf_count_t psf_get_filelen_handle (HANDLE handle) ;
616 
617 /* USE_WINDOWS_API */ int
psf_fopen(SF_PRIVATE * psf)618 psf_fopen (SF_PRIVATE *psf)
619 {
620 	psf->error = 0 ;
621 	psf->file.handle = psf_open_handle (&psf->file) ;
622 
623 	if (psf->file.handle == NULL)
624 		psf_log_syserr (psf, GetLastError ()) ;
625 
626 	return psf->error ;
627 } /* psf_fopen */
628 
629 /* USE_WINDOWS_API */ int
psf_fclose(SF_PRIVATE * psf)630 psf_fclose (SF_PRIVATE *psf)
631 {	int retval ;
632 
633 	if (psf->virtual_io)
634 		return 0 ;
635 
636 	if (psf->file.do_not_close_descriptor)
637 	{	psf->file.handle = NULL ;
638 		return 0 ;
639 		} ;
640 
641 	if ((retval = psf_close_handle (psf->file.handle)) == -1)
642 		psf_log_syserr (psf, GetLastError ()) ;
643 
644 	psf->file.handle = NULL ;
645 
646 	return retval ;
647 } /* psf_fclose */
648 
649 /* USE_WINDOWS_API */ int
psf_open_rsrc(SF_PRIVATE * psf)650 psf_open_rsrc (SF_PRIVATE *psf)
651 {
652 	if (psf->rsrc.handle != NULL)
653 		return 0 ;
654 
655 	/* Test for MacOSX style resource fork on HPFS or HPFS+ filesystems. */
656 	snprintf (psf->rsrc.path.c, sizeof (psf->rsrc.path.c), "%s/rsrc", psf->file.path.c) ;
657 	psf->error = SFE_NO_ERROR ;
658 	if ((psf->rsrc.handle = psf_open_handle (&psf->rsrc)) != NULL)
659 	{	psf->rsrclength = psf_get_filelen_handle (psf->rsrc.handle) ;
660 		return SFE_NO_ERROR ;
661 		} ;
662 
663 	/*
664 	** Now try for a resource fork stored as a separate file in the same
665 	** directory, but preceded with a dot underscore.
666 	*/
667 	snprintf (psf->rsrc.path.c, sizeof (psf->rsrc.path.c), "%s._%s", psf->file.dir.c, psf->file.name.c) ;
668 	psf->error = SFE_NO_ERROR ;
669 	if ((psf->rsrc.handle = psf_open_handle (&psf->rsrc)) != NULL)
670 	{	psf->rsrclength = psf_get_filelen_handle (psf->rsrc.handle) ;
671 		return SFE_NO_ERROR ;
672 		} ;
673 
674 	/*
675 	** Now try for a resource fork stored in a separate file in the
676 	** .AppleDouble/ directory.
677 	*/
678 	snprintf (psf->rsrc.path.c, sizeof (psf->rsrc.path.c), "%s.AppleDouble/%s", psf->file.dir.c, psf->file.name.c) ;
679 	psf->error = SFE_NO_ERROR ;
680 	if ((psf->rsrc.handle = psf_open_handle (&psf->rsrc)) != NULL)
681 	{	psf->rsrclength = psf_get_filelen_handle (psf->rsrc.handle) ;
682 		return SFE_NO_ERROR ;
683 		} ;
684 
685 	/* No resource file found. */
686 	if (psf->rsrc.handle == NULL)
687 		psf_log_syserr (psf, GetLastError ()) ;
688 
689 	psf->rsrc.handle = NULL ;
690 
691 	return psf->error ;
692 } /* psf_open_rsrc */
693 
694 /* USE_WINDOWS_API */ sf_count_t
psf_get_filelen(SF_PRIVATE * psf)695 psf_get_filelen (SF_PRIVATE *psf)
696 {	sf_count_t	filelen ;
697 
698 	if (psf->virtual_io)
699 		return psf->vio.get_filelen (psf->vio_user_data) ;
700 
701 	filelen = psf_get_filelen_handle (psf->file.handle) ;
702 
703 	if (filelen == -1)
704 	{	psf_log_syserr (psf, errno) ;
705 		return (sf_count_t) -1 ;
706 		} ;
707 
708 	if (filelen == -SFE_BAD_STAT_SIZE)
709 	{	psf->error = SFE_BAD_STAT_SIZE ;
710 		return (sf_count_t) -1 ;
711 		} ;
712 
713 	switch (psf->file.mode)
714 	{	case SFM_WRITE :
715 			filelen = filelen - psf->fileoffset ;
716 			break ;
717 
718 		case SFM_READ :
719 			if (psf->fileoffset > 0 && psf->filelength > 0)
720 				filelen = psf->filelength ;
721 			break ;
722 
723 		case SFM_RDWR :
724 			/*
725 			** Cannot open embedded files SFM_RDWR so we don't need to
726 			** subtract psf->fileoffset. We already have the answer we
727 			** need.
728 			*/
729 			break ;
730 
731 		default :
732 			/* Shouldn't be here, so return error. */
733 			filelen = -1 ;
734 		} ;
735 
736 	return filelen ;
737 } /* psf_get_filelen */
738 
739 /* USE_WINDOWS_API */ void
psf_init_files(SF_PRIVATE * psf)740 psf_init_files (SF_PRIVATE *psf)
741 {	psf->file.handle = NULL ;
742 	psf->rsrc.handle = NULL ;
743 	psf->file.hsaved = NULL ;
744 } /* psf_init_files */
745 
746 /* USE_WINDOWS_API */ void
psf_use_rsrc(SF_PRIVATE * psf,int on_off)747 psf_use_rsrc (SF_PRIVATE *psf, int on_off)
748 {
749 	if (on_off)
750 	{	if (psf->file.handle != psf->rsrc.handle)
751 		{	psf->file.hsaved = psf->file.handle ;
752 			psf->file.handle = psf->rsrc.handle ;
753 			} ;
754 		}
755 	else if (psf->file.handle == psf->rsrc.handle)
756 		psf->file.handle = psf->file.hsaved ;
757 
758 	return ;
759 } /* psf_use_rsrc */
760 
761 /* USE_WINDOWS_API */ static HANDLE
psf_open_handle(PSF_FILE * pfile)762 psf_open_handle (PSF_FILE * pfile)
763 {	DWORD dwDesiredAccess ;
764 	DWORD dwShareMode ;
765 	DWORD dwCreationDistribution ;
766 	HANDLE handle ;
767 
768 	switch (pfile->mode)
769 	{	case SFM_READ :
770 				dwDesiredAccess = GENERIC_READ ;
771 				dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ;
772 				dwCreationDistribution = OPEN_EXISTING ;
773 				break ;
774 
775 		case SFM_WRITE :
776 				dwDesiredAccess = GENERIC_WRITE ;
777 				dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ;
778 				dwCreationDistribution = CREATE_ALWAYS ;
779 				break ;
780 
781 		case SFM_RDWR :
782 				dwDesiredAccess = GENERIC_READ | GENERIC_WRITE ;
783 				dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ;
784 				dwCreationDistribution = OPEN_ALWAYS ;
785 				break ;
786 
787 		default :
788 				return NULL ;
789 		} ;
790 
791 #if defined (WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
792 	if (!pfile->use_wchar)
793 		return NULL ;
794 
795 	CREATEFILE2_EXTENDED_PARAMETERS cfParams = { 0 } ;
796 	cfParams.dwSize = sizeof (CREATEFILE2_EXTENDED_PARAMETERS) ;
797 	cfParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL ;
798 
799 	handle = CreateFile2 (pfile->path.wc, dwDesiredAccess, dwShareMode, dwCreationDistribution, &cfParams) ;
800 
801 	if (handle == INVALID_HANDLE_VALUE)
802 		return NULL ;
803 
804 	return handle ;
805 #else
806 	if (pfile->use_wchar)
807 		handle = CreateFileW (
808 					pfile->path.wc,				/* pointer to name of the file */
809 					dwDesiredAccess,			/* access (read-write) mode */
810 					dwShareMode,				/* share mode */
811 					0,							/* pointer to security attributes */
812 					dwCreationDistribution,		/* how to create */
813 					FILE_ATTRIBUTE_NORMAL,		/* file attributes (could use FILE_FLAG_SEQUENTIAL_SCAN) */
814 					NULL						/* handle to file with attributes to copy */
815 					) ;
816 	else
817 		handle = CreateFileA (
818 					pfile->path.c,				/* pointer to name of the file */
819 					dwDesiredAccess,			/* access (read-write) mode */
820 					dwShareMode,				/* share mode */
821 					0,							/* pointer to security attributes */
822 					dwCreationDistribution,		/* how to create */
823 					FILE_ATTRIBUTE_NORMAL,		/* file attributes (could use FILE_FLAG_SEQUENTIAL_SCAN) */
824 					NULL						/* handle to file with attributes to copy */
825 					) ;
826 
827 	if (handle == INVALID_HANDLE_VALUE)
828 		return NULL ;
829 
830 	return handle ;
831 #endif
832 } /* psf_open_handle */
833 
834 /* USE_WINDOWS_API */ static void
psf_log_syserr(SF_PRIVATE * psf,int error)835 psf_log_syserr (SF_PRIVATE *psf, int error)
836 {	LPVOID lpMsgBuf ;
837 
838 	/* Only log an error if no error has been set yet. */
839 	if (psf->error == 0)
840 	{	psf->error = SFE_SYSTEM ;
841 
842 		FormatMessage (
843 			FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
844 			NULL,
845 			error,
846 			MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
847 			(LPTSTR) &lpMsgBuf,
848 			0,
849 			NULL
850 			) ;
851 
852 		snprintf (psf->syserr, sizeof (psf->syserr), "System error : %s", (char*) lpMsgBuf) ;
853 		LocalFree (lpMsgBuf) ;
854 		} ;
855 
856 	return ;
857 } /* psf_log_syserr */
858 
859 
860 /* USE_WINDOWS_API */ int
psf_close_rsrc(SF_PRIVATE * psf)861 psf_close_rsrc (SF_PRIVATE *psf)
862 {	psf_close_handle (psf->rsrc.handle) ;
863 	psf->rsrc.handle = NULL ;
864 	return 0 ;
865 } /* psf_close_rsrc */
866 
867 
868 /* USE_WINDOWS_API */ int
psf_set_stdio(SF_PRIVATE * psf)869 psf_set_stdio (SF_PRIVATE *psf)
870 {	HANDLE	handle = NULL ;
871 	int	error = 0 ;
872 
873 	switch (psf->file.mode)
874 	{	case SFM_RDWR :
875 				error = SFE_OPEN_PIPE_RDWR ;
876 				break ;
877 
878 		case SFM_READ :
879 				handle = GetStdHandle (STD_INPUT_HANDLE) ;
880 				psf->file.do_not_close_descriptor = 1 ;
881 				break ;
882 
883 		case SFM_WRITE :
884 				handle = GetStdHandle (STD_OUTPUT_HANDLE) ;
885 				psf->file.do_not_close_descriptor = 1 ;
886 				break ;
887 
888 		default :
889 				error = SFE_BAD_OPEN_MODE ;
890 				break ;
891 		} ;
892 
893 	psf->file.handle = handle ;
894 	psf->filelength = 0 ;
895 
896 	return error ;
897 } /* psf_set_stdio */
898 
899 /* USE_WINDOWS_API */ void
psf_set_file(SF_PRIVATE * psf,int fd)900 psf_set_file (SF_PRIVATE *psf, int fd)
901 {	HANDLE handle ;
902 	intptr_t osfhandle ;
903 
904 	osfhandle = _get_osfhandle (fd) ;
905 	handle = (HANDLE) osfhandle ;
906 
907 	psf->file.handle = handle ;
908 } /* psf_set_file */
909 
910 /* USE_WINDOWS_API */ int
psf_file_valid(SF_PRIVATE * psf)911 psf_file_valid (SF_PRIVATE *psf)
912 {	if (psf->file.handle == NULL)
913 		return SF_FALSE ;
914 	if (psf->file.handle == INVALID_HANDLE_VALUE)
915 		return SF_FALSE ;
916 	return SF_TRUE ;
917 } /* psf_set_file */
918 
919 /* USE_WINDOWS_API */ sf_count_t
psf_fseek(SF_PRIVATE * psf,sf_count_t offset,int whence)920 psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence)
921 {	sf_count_t new_position ;
922 	LARGE_INTEGER liDistanceToMove, liNewFilePointer ;
923 	DWORD dwMoveMethod ;
924 	BOOL fResult ;
925 	DWORD dwError ;
926 
927 	if (psf->virtual_io)
928 		return psf->vio.seek (offset, whence, psf->vio_user_data) ;
929 
930 	switch (whence)
931 	{	case SEEK_SET :
932 				offset += psf->fileoffset ;
933 				dwMoveMethod = FILE_BEGIN ;
934 				break ;
935 
936 		case SEEK_END :
937 				dwMoveMethod = FILE_END ;
938 				break ;
939 
940 		default :
941 				dwMoveMethod = FILE_CURRENT ;
942 				break ;
943 		} ;
944 
945 	liDistanceToMove.QuadPart = offset ;
946 
947 	fResult = SetFilePointerEx (psf->file.handle, liDistanceToMove, &liNewFilePointer, dwMoveMethod) ;
948 
949 	if (fResult == FALSE)
950 		dwError = GetLastError () ;
951 	else
952 		dwError = NO_ERROR ;
953 
954 	if (dwError != NO_ERROR)
955 	{	psf_log_syserr (psf, dwError) ;
956 		return -1 ;
957 		} ;
958 
959 	new_position = liNewFilePointer.QuadPart - psf->fileoffset ;
960 
961 	return new_position ;
962 } /* psf_fseek */
963 
964 /* USE_WINDOWS_API */ sf_count_t
psf_fread(void * ptr,sf_count_t bytes,sf_count_t items,SF_PRIVATE * psf)965 psf_fread (void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf)
966 {	sf_count_t total = 0 ;
967 	ssize_t count ;
968 	DWORD dwNumberOfBytesRead ;
969 
970 	if (psf->virtual_io)
971 		return psf->vio.read (ptr, bytes*items, psf->vio_user_data) / bytes ;
972 
973 	items *= bytes ;
974 
975 	/* Do this check after the multiplication above. */
976 	if (items <= 0)
977 		return 0 ;
978 
979 	while (items > 0)
980 	{	/* Break the writes down to a sensible size. */
981 		count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ;
982 
983 		if (ReadFile (psf->file.handle, ((char*) ptr) + total, count, &dwNumberOfBytesRead, 0) == 0)
984 		{	psf_log_syserr (psf, GetLastError ()) ;
985 			break ;
986 			}
987 		else
988 			count = dwNumberOfBytesRead ;
989 
990 		if (count == 0)
991 			break ;
992 
993 		total += count ;
994 		items -= count ;
995 		} ;
996 
997 	if (psf->is_pipe)
998 		psf->pipeoffset += total ;
999 
1000 	return total / bytes ;
1001 } /* psf_fread */
1002 
1003 /* USE_WINDOWS_API */ sf_count_t
psf_fwrite(const void * ptr,sf_count_t bytes,sf_count_t items,SF_PRIVATE * psf)1004 psf_fwrite (const void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf)
1005 {	sf_count_t total = 0 ;
1006 	ssize_t	count ;
1007 	DWORD dwNumberOfBytesWritten ;
1008 
1009 	if (psf->virtual_io)
1010 		return psf->vio.write (ptr, bytes * items, psf->vio_user_data) / bytes ;
1011 
1012 	items *= bytes ;
1013 
1014 	/* Do this check after the multiplication above. */
1015 	if (items <= 0)
1016 		return 0 ;
1017 
1018 	while (items > 0)
1019 	{	/* Break the writes down to a sensible size. */
1020 		count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ;
1021 
1022 		if (WriteFile (psf->file.handle, ((const char*) ptr) + total, count, &dwNumberOfBytesWritten, 0) == 0)
1023 		{	psf_log_syserr (psf, GetLastError ()) ;
1024 			break ;
1025 			}
1026 		else
1027 			count = dwNumberOfBytesWritten ;
1028 
1029 		if (count == 0)
1030 			break ;
1031 
1032 		total += count ;
1033 		items -= count ;
1034 		} ;
1035 
1036 	if (psf->is_pipe)
1037 		psf->pipeoffset += total ;
1038 
1039 	return total / bytes ;
1040 } /* psf_fwrite */
1041 
1042 /* USE_WINDOWS_API */ sf_count_t
psf_ftell(SF_PRIVATE * psf)1043 psf_ftell (SF_PRIVATE *psf)
1044 {	sf_count_t pos ;
1045 	LARGE_INTEGER liDistanceToMove, liNewFilePointer ;
1046 	BOOL fResult ;
1047 	DWORD dwError ;
1048 
1049 	if (psf->virtual_io)
1050 		return psf->vio.tell (psf->vio_user_data) ;
1051 
1052 	if (psf->is_pipe)
1053 		return psf->pipeoffset ;
1054 
1055 	liDistanceToMove.QuadPart = 0 ;
1056 
1057 	fResult = SetFilePointerEx (psf->file.handle, liDistanceToMove, &liNewFilePointer, FILE_CURRENT) ;
1058 
1059 	if (fResult == FALSE)
1060 		dwError = GetLastError () ;
1061 	else
1062 		dwError = NO_ERROR ;
1063 
1064 	if (dwError != NO_ERROR)
1065 	{	psf_log_syserr (psf, dwError) ;
1066 		return -1 ;
1067 		} ;
1068 
1069 	pos = liNewFilePointer.QuadPart ;
1070 
1071 	return pos - psf->fileoffset ;
1072 } /* psf_ftell */
1073 
1074 /* USE_WINDOWS_API */ static int
psf_close_handle(HANDLE handle)1075 psf_close_handle (HANDLE handle)
1076 {	if (handle == NULL)
1077 		return 0 ;
1078 
1079 	if (CloseHandle (handle) == 0)
1080 		return -1 ;
1081 
1082 	return 0 ;
1083 } /* psf_close_handle */
1084 
1085 /* USE_WINDOWS_API */ sf_count_t
psf_fgets(char * buffer,sf_count_t bufsize,SF_PRIVATE * psf)1086 psf_fgets (char *buffer, sf_count_t bufsize, SF_PRIVATE *psf)
1087 {	sf_count_t k = 0 ;
1088 	sf_count_t count ;
1089 	DWORD dwNumberOfBytesRead ;
1090 
1091 	while (k < bufsize - 1)
1092 	{	if (ReadFile (psf->file.handle, &(buffer [k]), 1, &dwNumberOfBytesRead, 0) == 0)
1093 		{	psf_log_syserr (psf, GetLastError ()) ;
1094 			break ;
1095 			}
1096 		else
1097 		{	count = dwNumberOfBytesRead ;
1098 			/* note that we only check for '\n' not other line endings such as CRLF */
1099 			if (count == 0 || buffer [k++] == '\n')
1100 				break ;
1101 			} ;
1102 		} ;
1103 
1104 	buffer [k] = 0 ;
1105 
1106 	return k ;
1107 } /* psf_fgets */
1108 
1109 /* USE_WINDOWS_API */ int
psf_is_pipe(SF_PRIVATE * psf)1110 psf_is_pipe (SF_PRIVATE *psf)
1111 {
1112 	if (psf->virtual_io)
1113 		return SF_FALSE ;
1114 
1115 	if (GetFileType (psf->file.handle) == FILE_TYPE_DISK)
1116 		return SF_FALSE ;
1117 
1118 	/* Default to maximum safety. */
1119 	return SF_TRUE ;
1120 } /* psf_is_pipe */
1121 
1122 /* USE_WINDOWS_API */ sf_count_t
psf_get_filelen_handle(HANDLE handle)1123 psf_get_filelen_handle (HANDLE handle)
1124 {	sf_count_t filelen ;
1125 	LARGE_INTEGER liFileSize ;
1126 	BOOL fResult ;
1127 	DWORD dwError = NO_ERROR ;
1128 
1129 	fResult = GetFileSizeEx (handle, &liFileSize) ;
1130 
1131 	if (fResult == FALSE)
1132 		dwError = GetLastError () ;
1133 
1134 	if (dwError != NO_ERROR)
1135 		return (sf_count_t) -1 ;
1136 
1137 	filelen = liFileSize.QuadPart ;
1138 
1139 	return filelen ;
1140 } /* psf_get_filelen_handle */
1141 
1142 /* USE_WINDOWS_API */ void
psf_fsync(SF_PRIVATE * psf)1143 psf_fsync (SF_PRIVATE *psf)
1144 {	FlushFileBuffers (psf->file.handle) ;
1145 } /* psf_fsync */
1146 
1147 
1148 /* USE_WINDOWS_API */ int
psf_ftruncate(SF_PRIVATE * psf,sf_count_t len)1149 psf_ftruncate (SF_PRIVATE *psf, sf_count_t len)
1150 {	int retval = 0 ;
1151 	LARGE_INTEGER liDistanceToMove ;
1152 	BOOL fResult ;
1153 	DWORD dwError = NO_ERROR ;
1154 
1155 	/* This implementation trashes the current file position.
1156 	** should it save and restore it? what if the current position is past
1157 	** the new end of file?
1158 	*/
1159 
1160 	/* Returns 0 on success, non-zero on failure. */
1161 	if (len < 0)
1162 		return 1 ;
1163 
1164 	liDistanceToMove.QuadPart = (sf_count_t) len ;
1165 
1166 	fResult = SetFilePointerEx (psf->file.handle, liDistanceToMove, NULL, FILE_BEGIN) ;
1167 
1168 	if (fResult == FALSE)
1169 		dwError = GetLastError () ;
1170 
1171 	if (dwError != NO_ERROR)
1172 	{	retval = -1 ;
1173 		psf_log_syserr (psf, dwError) ;
1174 		}
1175 	else
1176 	{	/* Note: when SetEndOfFile is used to extend a file, the contents of the
1177 		** new portion of the file is undefined. This is unlike chsize(),
1178 		** which guarantees that the new portion of the file will be zeroed.
1179 		** Not sure if this is important or not.
1180 		*/
1181 		if (SetEndOfFile (psf->file.handle) == 0)
1182 		{	retval = -1 ;
1183 			psf_log_syserr (psf, GetLastError ()) ;
1184 			} ;
1185 		} ;
1186 
1187 	return retval ;
1188 } /* psf_ftruncate */
1189 
1190 
1191 #else
1192 /* Win32 file i/o functions implemented using Unix-style file i/o API */
1193 
1194 /* Win32 has a 64 file offset seek function:
1195 **
1196 **		__int64 _lseeki64 (int handle, __int64 offset, int origin) ;
1197 **
1198 ** It also has a 64 bit fstat function:
1199 **
1200 **		int fstati64 (int, struct _stati64) ;
1201 **
1202 ** but the fscking thing doesn't work!!!!! The file size parameter returned
1203 ** by this function is only valid up until more data is written at the end of
1204 ** the file. That makes this function completely 100% useless.
1205 */
1206 
1207 #include <io.h>
1208 #include <direct.h>
1209 
1210 /* Win32 */ int
psf_fopen(SF_PRIVATE * psf,const char * pathname,int open_mode)1211 psf_fopen (SF_PRIVATE *psf, const char *pathname, int open_mode)
1212 {	int oflag, mode ;
1213 
1214 	switch (open_mode)
1215 	{	case SFM_READ :
1216 				oflag = O_RDONLY | O_BINARY ;
1217 				mode = 0 ;
1218 				break ;
1219 
1220 		case SFM_WRITE :
1221 				oflag = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY ;
1222 				mode = S_IRUSR | S_IWUSR | S_IRGRP ;
1223 				break ;
1224 
1225 		case SFM_RDWR :
1226 				oflag = O_RDWR | O_CREAT | O_BINARY ;
1227 				mode = S_IRUSR | S_IWUSR | S_IRGRP ;
1228 				break ;
1229 
1230 		default :
1231 				psf->error = SFE_BAD_OPEN_MODE ;
1232 				return -1 ;
1233 				break ;
1234 		} ;
1235 
1236 	if (mode == 0)
1237 		psf->file.filedes = open (pathname, oflag) ;
1238 	else
1239 		psf->file.filedes = open (pathname, oflag, mode) ;
1240 
1241 	if (psf->file.filedes == -1)
1242 		psf_log_syserr (psf, errno) ;
1243 
1244 	return psf->file.filedes ;
1245 } /* psf_fopen */
1246 
1247 /* Win32 */ sf_count_t
psf_fseek(SF_PRIVATE * psf,sf_count_t offset,int whence)1248 psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence)
1249 {	sf_count_t	new_position ;
1250 
1251 	if (psf->virtual_io)
1252 		return psf->vio.seek (offset, whence, psf->vio_user_data) ;
1253 
1254 	switch (whence)
1255 	{	case SEEK_SET :
1256 				offset += psf->fileoffset ;
1257 				break ;
1258 
1259 		case SEEK_END :
1260 				if (psf->file.mode == SFM_WRITE)
1261 				{	new_position = _lseeki64 (psf->file.filedes, offset, whence) ;
1262 
1263 					if (new_position < 0)
1264 						psf_log_syserr (psf, errno) ;
1265 
1266 					return new_position - psf->fileoffset ;
1267 					} ;
1268 
1269 				/* Transform SEEK_END into a SEEK_SET, ie find the file
1270 				** length add the requested offset (should be <= 0) to
1271 				** get the offset wrt the start of file.
1272 				*/
1273 				whence = SEEK_SET ;
1274 				offset = _lseeki64 (psf->file.filedes, 0, SEEK_END) + offset ;
1275 				break ;
1276 
1277 		default :
1278 				/* No need to do anything about SEEK_CUR. */
1279 				break ;
1280 		} ;
1281 
1282 	/*
1283 	** Bypass weird Win32-ism if necessary.
1284 	** _lseeki64() returns an "invalid parameter" error if called with the
1285 	** offset == 0 and whence == SEEK_CUR.
1286 	*** Use the _telli64() function instead.
1287 	*/
1288 	if (offset == 0 && whence == SEEK_CUR)
1289 		new_position = _telli64 (psf->file.filedes) ;
1290 	else
1291 		new_position = _lseeki64 (psf->file.filedes, offset, whence) ;
1292 
1293 	if (new_position < 0)
1294 		psf_log_syserr (psf, errno) ;
1295 
1296 	new_position -= psf->fileoffset ;
1297 
1298 	return new_position ;
1299 } /* psf_fseek */
1300 
1301 /* Win32 */ sf_count_t
psf_fread(void * ptr,sf_count_t bytes,sf_count_t items,SF_PRIVATE * psf)1302 psf_fread (void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf)
1303 {	sf_count_t total = 0 ;
1304 	ssize_t	count ;
1305 
1306 	if (psf->virtual_io)
1307 		return psf->vio.read (ptr, bytes*items, psf->vio_user_data) / bytes ;
1308 
1309 	items *= bytes ;
1310 
1311 	/* Do this check after the multiplication above. */
1312 	if (items <= 0)
1313 		return 0 ;
1314 
1315 	while (items > 0)
1316 	{	/* Break the writes down to a sensible size. */
1317 		count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ;
1318 
1319 		count = read (psf->file.filedes, ((char*) ptr) + total, (size_t) count) ;
1320 
1321 		if (count == -1)
1322 		{	if (errno == EINTR)
1323 				continue ;
1324 
1325 			psf_log_syserr (psf, errno) ;
1326 			break ;
1327 			} ;
1328 
1329 		if (count == 0)
1330 			break ;
1331 
1332 		total += count ;
1333 		items -= count ;
1334 		} ;
1335 
1336 	return total / bytes ;
1337 } /* psf_fread */
1338 
1339 /* Win32 */ sf_count_t
psf_fwrite(const void * ptr,sf_count_t bytes,sf_count_t items,SF_PRIVATE * psf)1340 psf_fwrite (const void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf)
1341 {	sf_count_t total = 0 ;
1342 	ssize_t	count ;
1343 
1344 	if (psf->virtual_io)
1345 		return psf->vio.write (ptr, bytes*items, psf->vio_user_data) / bytes ;
1346 
1347 	items *= bytes ;
1348 
1349 	/* Do this check after the multiplication above. */
1350 	if (items <= 0)
1351 		return 0 ;
1352 
1353 	while (items > 0)
1354 	{	/* Break the writes down to a sensible size. */
1355 		count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : items ;
1356 
1357 		count = write (psf->file.filedes, ((const char*) ptr) + total, count) ;
1358 
1359 		if (count == -1)
1360 		{	if (errno == EINTR)
1361 				continue ;
1362 
1363 			psf_log_syserr (psf, errno) ;
1364 			break ;
1365 			} ;
1366 
1367 		if (count == 0)
1368 			break ;
1369 
1370 		total += count ;
1371 		items -= count ;
1372 		} ;
1373 
1374 	return total / bytes ;
1375 } /* psf_fwrite */
1376 
1377 /* Win32 */ sf_count_t
psf_ftell(SF_PRIVATE * psf)1378 psf_ftell (SF_PRIVATE *psf)
1379 {	sf_count_t pos ;
1380 
1381 	if (psf->virtual_io)
1382 		return psf->vio.tell (psf->vio_user_data) ;
1383 
1384 	pos = _telli64 (psf->file.filedes) ;
1385 
1386 	if (pos == ((sf_count_t) -1))
1387 	{	psf_log_syserr (psf, errno) ;
1388 		return -1 ;
1389 		} ;
1390 
1391 	return pos - psf->fileoffset ;
1392 } /* psf_ftell */
1393 
1394 /* Win32 */ int
psf_fclose(SF_PRIVATE * psf)1395 psf_fclose (SF_PRIVATE *psf)
1396 {	int retval ;
1397 
1398 	while ((retval = close (psf->file.filedes)) == -1 && errno == EINTR)
1399 		/* Do nothing. */ ;
1400 
1401 	if (retval == -1)
1402 		psf_log_syserr (psf, errno) ;
1403 
1404 	psf->file.filedes = -1 ;
1405 
1406 	return retval ;
1407 } /* psf_fclose */
1408 
1409 /* Win32 */ sf_count_t
psf_fgets(char * buffer,sf_count_t bufsize,SF_PRIVATE * psf)1410 psf_fgets (char *buffer, sf_count_t bufsize, SF_PRIVATE *psf)
1411 {	sf_count_t	k = 0 ;
1412 	sf_count_t	count ;
1413 
1414 	while (k < bufsize - 1)
1415 	{	count = read (psf->file.filedes, &(buffer [k]), 1) ;
1416 
1417 		if (count == -1)
1418 		{	if (errno == EINTR)
1419 				continue ;
1420 
1421 			psf_log_syserr (psf, errno) ;
1422 			break ;
1423 			} ;
1424 
1425 		if (count == 0 || buffer [k++] == '\n')
1426 			break ;
1427 		} ;
1428 
1429 	buffer [k] = 0 ;
1430 
1431 	return k ;
1432 } /* psf_fgets */
1433 
1434 /* Win32 */ int
psf_is_pipe(SF_PRIVATE * psf)1435 psf_is_pipe (SF_PRIVATE *psf)
1436 {	struct stat statbuf ;
1437 
1438 	if (psf->virtual_io)
1439 		return SF_FALSE ;
1440 
1441 	/* Not sure if this works. */
1442 	if (fstat (psf->file.filedes, &statbuf) == -1)
1443 	{	psf_log_syserr (psf, errno) ;
1444 		/* Default to maximum safety. */
1445 		return SF_TRUE ;
1446 		} ;
1447 
1448 	/* These macros are defined in Win32/unistd.h. */
1449 	if (S_ISFIFO (statbuf.st_mode) || S_ISSOCK (statbuf.st_mode))
1450 		return SF_TRUE ;
1451 
1452 	return SF_FALSE ;
1453 } /* psf_checkpipe */
1454 
1455 /* Win32 */ sf_count_t
psf_get_filelen(SF_PRIVATE * psf)1456 psf_get_filelen (SF_PRIVATE *psf)
1457 {
1458 #if 0
1459 	/*
1460 	** Windoze is SOOOOO FUCKED!!!!!!!
1461 	** This code should work but doesn't. Why?
1462 	** Code below does work.
1463 	*/
1464 	struct _stati64 statbuf ;
1465 
1466 	if (_fstati64 (psf->file.filedes, &statbuf))
1467 	{	psf_log_syserr (psf, errno) ;
1468 		return (sf_count_t) -1 ;
1469 		} ;
1470 
1471 	return statbuf.st_size ;
1472 #else
1473 	sf_count_t current, filelen ;
1474 
1475 	if (psf->virtual_io)
1476 		return psf->vio.get_filelen (psf->vio_user_data) ;
1477 
1478 	if ((current = _telli64 (psf->file.filedes)) < 0)
1479 	{	psf_log_syserr (psf, errno) ;
1480 		return (sf_count_t) -1 ;
1481 		} ;
1482 
1483 	/*
1484 	** Lets face it, windoze if FUBAR!!!
1485 	**
1486 	** For some reason, I have to call _lseeki64() TWICE to get to the
1487 	** end of the file.
1488 	**
1489 	** This might have been avoided if windows had implemented the POSIX
1490 	** standard function fsync() but NO, that would have been too easy.
1491 	**
1492 	** I am VERY close to saying that windoze will no longer be supported
1493 	** by libsndfile and changing the license to GPL at the same time.
1494 	*/
1495 
1496 	_lseeki64 (psf->file.filedes, 0, SEEK_END) ;
1497 
1498 	if ((filelen = _lseeki64 (psf->file.filedes, 0, SEEK_END)) < 0)
1499 	{	psf_log_syserr (psf, errno) ;
1500 		return (sf_count_t) -1 ;
1501 		} ;
1502 
1503 	if (filelen > current)
1504 		_lseeki64 (psf->file.filedes, current, SEEK_SET) ;
1505 
1506 	switch (psf->file.mode)
1507 	{	case SFM_WRITE :
1508 			filelen = filelen - psf->fileoffset ;
1509 			break ;
1510 
1511 		case SFM_READ :
1512 			if (psf->fileoffset > 0 && psf->filelength > 0)
1513 				filelen = psf->filelength ;
1514 			break ;
1515 
1516 		case SFM_RDWR :
1517 			/*
1518 			** Cannot open embedded files SFM_RDWR so we don't need to
1519 			** subtract psf->fileoffset. We already have the answer we
1520 			** need.
1521 			*/
1522 			break ;
1523 
1524 		default :
1525 			filelen = 0 ;
1526 		} ;
1527 
1528 	return filelen ;
1529 #endif
1530 } /* psf_get_filelen */
1531 
1532 /* Win32 */ int
psf_ftruncate(SF_PRIVATE * psf,sf_count_t len)1533 psf_ftruncate (SF_PRIVATE *psf, sf_count_t len)
1534 {	int retval ;
1535 
1536 	/* Returns 0 on success, non-zero on failure. */
1537 	if (len < 0)
1538 		return 1 ;
1539 
1540 	/* The global village idiots at micorsoft decided to implement
1541 	** nearly all the required 64 bit file offset functions except
1542 	** for one, truncate. The fscking morons!
1543 	**
1544 	** This is not 64 bit file offset clean. Somone needs to clean
1545 	** this up.
1546 	*/
1547 	if (len > 0x7FFFFFFF)
1548 		return -1 ;
1549 
1550 	retval = chsize (psf->file.filedes, len) ;
1551 
1552 	if (retval == -1)
1553 		psf_log_syserr (psf, errno) ;
1554 
1555 	return retval ;
1556 } /* psf_ftruncate */
1557 
1558 
1559 static void
psf_log_syserr(SF_PRIVATE * psf,int error)1560 psf_log_syserr (SF_PRIVATE *psf, int error)
1561 {
1562 	/* Only log an error if no error has been set yet. */
1563 	if (psf->error == 0)
1564 	{	psf->error = SFE_SYSTEM ;
1565 		snprintf (psf->syserr, sizeof (psf->syserr), "System error : %s", strerror (error)) ;
1566 		} ;
1567 
1568 	return ;
1569 } /* psf_log_syserr */
1570 
1571 #endif
1572 
1573