• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 int
psf_copy_filename(SF_PRIVATE * psf,const char * path)80 psf_copy_filename (SF_PRIVATE *psf, const char *path)
81 {	const char *ccptr ;
82 	char *cptr ;
83 
84 	if (strlen (path) > 1 && strlen (path) - 1 >= sizeof (psf->file.path))
85 	{	psf->error = SFE_FILENAME_TOO_LONG ;
86 		return psf->error ;
87 		} ;
88 
89 	snprintf (psf->file.path, sizeof (psf->file.path), "%s", path) ;
90 	if ((ccptr = strrchr (path, '/')) || (ccptr = strrchr (path, '\\')))
91 		ccptr ++ ;
92 	else
93 		ccptr = path ;
94 
95 	snprintf (psf->file.name, sizeof (psf->file.name), "%s", ccptr) ;
96 
97 	/* Now grab the directory. */
98 	snprintf (psf->file.dir, sizeof (psf->file.dir), "%s", path) ;
99 	if ((cptr = strrchr (psf->file.dir, '/')) || (cptr = strrchr (psf->file.dir, '\\')))
100 		cptr [1] = 0 ;
101 	else
102 		psf->file.dir [0] = 0 ;
103 
104 	return 0 ;
105 } /* psf_copy_filename */
106 
107 #if (USE_WINDOWS_API == 0)
108 
109 /*------------------------------------------------------------------------------
110 ** Win32 stuff at the bottom of the file. Unix and other sensible OSes here.
111 */
112 
113 static int psf_close_fd (int fd) ;
114 static int psf_open_fd (PSF_FILE * pfile) ;
115 static sf_count_t psf_get_filelen_fd (int fd) ;
116 
117 int
psf_fopen(SF_PRIVATE * psf)118 psf_fopen (SF_PRIVATE *psf)
119 {
120 	psf->error = 0 ;
121 	psf->file.filedes = psf_open_fd (&psf->file) ;
122 
123 	if (psf->file.filedes == - SFE_BAD_OPEN_MODE)
124 	{	psf->error = SFE_BAD_OPEN_MODE ;
125 		psf->file.filedes = -1 ;
126 		return psf->error ;
127 		} ;
128 
129 	if (psf->file.filedes == -1)
130 		psf_log_syserr (psf, errno) ;
131 
132 	return psf->error ;
133 } /* psf_fopen */
134 
135 int
psf_fclose(SF_PRIVATE * psf)136 psf_fclose (SF_PRIVATE *psf)
137 {	int retval ;
138 
139 	if (psf->virtual_io)
140 		return 0 ;
141 
142 	if (psf->file.do_not_close_descriptor)
143 	{	psf->file.filedes = -1 ;
144 		return 0 ;
145 		} ;
146 
147 	if ((retval = psf_close_fd (psf->file.filedes)) == -1)
148 		psf_log_syserr (psf, errno) ;
149 
150 	psf->file.filedes = -1 ;
151 
152 	return retval ;
153 } /* psf_fclose */
154 
155 int
psf_open_rsrc(SF_PRIVATE * psf)156 psf_open_rsrc (SF_PRIVATE *psf)
157 {	size_t count ;
158 
159 	if (psf->rsrc.filedes > 0)
160 		return 0 ;
161 
162 	/* Test for MacOSX style resource fork on HPFS or HPFS+ filesystems. */
163 	count = snprintf (psf->rsrc.path, sizeof (psf->rsrc.path), "%s/..namedfork/rsrc", psf->file.path) ;
164 	psf->error = SFE_NO_ERROR ;
165 	if (count < sizeof (psf->rsrc.path))
166 	{	if ((psf->rsrc.filedes = psf_open_fd (&psf->rsrc)) >= 0)
167 		{	psf->rsrclength = psf_get_filelen_fd (psf->rsrc.filedes) ;
168 			if (psf->rsrclength > 0 || (psf->rsrc.mode & SFM_WRITE))
169 				return SFE_NO_ERROR ;
170 			psf_close_fd (psf->rsrc.filedes) ;
171 			psf->rsrc.filedes = -1 ;
172 			} ;
173 
174 		if (psf->rsrc.filedes == - SFE_BAD_OPEN_MODE)
175 		{	psf->error = SFE_BAD_OPEN_MODE ;
176 			return psf->error ;
177 			} ;
178 		} ;
179 
180 	/*
181 	** Now try for a resource fork stored as a separate file in the same
182 	** directory, but preceded with a dot underscore.
183 	*/
184 	count = snprintf (psf->rsrc.path, sizeof (psf->rsrc.path), "%s._%s", psf->file.dir, psf->file.name) ;
185 	psf->error = SFE_NO_ERROR ;
186 	if (count < sizeof (psf->rsrc.path) && (psf->rsrc.filedes = psf_open_fd (&psf->rsrc)) >= 0)
187 	{	psf->rsrclength = psf_get_filelen_fd (psf->rsrc.filedes) ;
188 		return SFE_NO_ERROR ;
189 		} ;
190 
191 	/*
192 	** Now try for a resource fork stored in a separate file in the
193 	** .AppleDouble/ directory.
194 	*/
195 	count = snprintf (psf->rsrc.path, sizeof (psf->rsrc.path), "%s.AppleDouble/%s", psf->file.dir, psf->file.name) ;
196 	psf->error = SFE_NO_ERROR ;
197 	if (count < sizeof (psf->rsrc.path))
198 	{	if ((psf->rsrc.filedes = psf_open_fd (&psf->rsrc)) >= 0)
199 		{	psf->rsrclength = psf_get_filelen_fd (psf->rsrc.filedes) ;
200 			return SFE_NO_ERROR ;
201 			} ;
202 
203 		/* No resource file found. */
204 		if (psf->rsrc.filedes == -1)
205 			psf_log_syserr (psf, errno) ;
206 		}
207 	else
208 	{	psf->error = SFE_OPEN_FAILED ;
209 		} ;
210 
211 	psf->rsrc.filedes = -1 ;
212 
213 	return psf->error ;
214 } /* psf_open_rsrc */
215 
216 sf_count_t
psf_get_filelen(SF_PRIVATE * psf)217 psf_get_filelen (SF_PRIVATE *psf)
218 {	sf_count_t	filelen ;
219 
220 	if (psf->virtual_io)
221 		return psf->vio.get_filelen (psf->vio_user_data) ;
222 
223 	filelen = psf_get_filelen_fd (psf->file.filedes) ;
224 
225 	if (filelen == -1)
226 	{	psf_log_syserr (psf, errno) ;
227 		return (sf_count_t) -1 ;
228 		} ;
229 
230 	if (filelen == -SFE_BAD_STAT_SIZE)
231 	{	psf->error = SFE_BAD_STAT_SIZE ;
232 		return (sf_count_t) -1 ;
233 		} ;
234 
235 	switch (psf->file.mode)
236 	{	case SFM_WRITE :
237 			filelen = filelen - psf->fileoffset ;
238 			break ;
239 
240 		case SFM_READ :
241 			if (psf->fileoffset > 0 && psf->filelength > 0)
242 				filelen = psf->filelength ;
243 			break ;
244 
245 		case SFM_RDWR :
246 			/*
247 			** Cannot open embedded files SFM_RDWR so we don't need to
248 			** subtract psf->fileoffset. We already have the answer we
249 			** need.
250 			*/
251 			break ;
252 
253 		default :
254 			/* Shouldn't be here, so return error. */
255 			filelen = -1 ;
256 		} ;
257 
258 	return filelen ;
259 } /* psf_get_filelen */
260 
261 int
psf_close_rsrc(SF_PRIVATE * psf)262 psf_close_rsrc (SF_PRIVATE *psf)
263 {	psf_close_fd (psf->rsrc.filedes) ;
264 	psf->rsrc.filedes = -1 ;
265 	return 0 ;
266 } /* psf_close_rsrc */
267 
268 int
psf_set_stdio(SF_PRIVATE * psf)269 psf_set_stdio (SF_PRIVATE *psf)
270 {	int	error = 0 ;
271 
272 	switch (psf->file.mode)
273 	{	case SFM_RDWR :
274 				error = SFE_OPEN_PIPE_RDWR ;
275 				break ;
276 
277 		case SFM_READ :
278 				psf->file.filedes = 0 ;
279 				break ;
280 
281 		case SFM_WRITE :
282 				psf->file.filedes = 1 ;
283 				break ;
284 
285 		default :
286 				error = SFE_BAD_OPEN_MODE ;
287 				break ;
288 		} ;
289 	psf->filelength = 0 ;
290 
291 	return error ;
292 } /* psf_set_stdio */
293 
294 void
psf_set_file(SF_PRIVATE * psf,int fd)295 psf_set_file (SF_PRIVATE *psf, int fd)
296 {	psf->file.filedes = fd ;
297 } /* psf_set_file */
298 
299 int
psf_file_valid(SF_PRIVATE * psf)300 psf_file_valid (SF_PRIVATE *psf)
301 {	return (psf->file.filedes >= 0) ? SF_TRUE : SF_FALSE ;
302 } /* psf_set_file */
303 
304 sf_count_t
psf_fseek(SF_PRIVATE * psf,sf_count_t offset,int whence)305 psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence)
306 {	sf_count_t	absolute_position ;
307 
308 	if (psf->virtual_io)
309 		return psf->vio.seek (offset, whence, psf->vio_user_data) ;
310 
311 	/* When decoding from pipes sometimes see seeks to the pipeoffset, which appears to mean do nothing. */
312 	if (psf->is_pipe)
313 	{	if (whence != SEEK_SET || offset != psf->pipeoffset)
314 			psf_log_printf (psf, "psf_fseek : pipe seek to value other than pipeoffset\n") ;
315 		return offset ;
316 		}
317 
318 	switch (whence)
319 	{	case SEEK_SET :
320 				offset += psf->fileoffset ;
321 				break ;
322 
323 		case SEEK_END :
324 				break ;
325 
326 		case SEEK_CUR :
327 				break ;
328 
329 		default :
330 				/* We really should not be here. */
331 				psf_log_printf (psf, "psf_fseek : whence is %d *****.\n", whence) ;
332 				return 0 ;
333 		} ;
334 
335 	absolute_position = lseek (psf->file.filedes, offset, whence) ;
336 
337 	if (absolute_position < 0)
338 		psf_log_syserr (psf, errno) ;
339 
340 	return absolute_position - psf->fileoffset ;
341 } /* psf_fseek */
342 
343 sf_count_t
psf_fread(void * ptr,sf_count_t bytes,sf_count_t items,SF_PRIVATE * psf)344 psf_fread (void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf)
345 {	sf_count_t total = 0 ;
346 	ssize_t	count ;
347 
348 	if (psf->virtual_io)
349 		return psf->vio.read (ptr, bytes*items, psf->vio_user_data) / bytes ;
350 
351 	items *= bytes ;
352 
353 	/* Do this check after the multiplication above. */
354 	if (items <= 0)
355 		return 0 ;
356 
357 	while (items > 0)
358 	{	/* Break the read down to a sensible size. */
359 		count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ;
360 
361 		count = read (psf->file.filedes, ((char*) ptr) + total, (size_t) count) ;
362 
363 		if (count == -1)
364 		{	if (errno == EINTR)
365 				continue ;
366 
367 			psf_log_syserr (psf, errno) ;
368 			break ;
369 			} ;
370 
371 		if (count == 0)
372 			break ;
373 
374 		total += count ;
375 		items -= count ;
376 		} ;
377 
378 	if (psf->is_pipe)
379 		psf->pipeoffset += total ;
380 
381 	return total / bytes ;
382 } /* psf_fread */
383 
384 sf_count_t
psf_fwrite(const void * ptr,sf_count_t bytes,sf_count_t items,SF_PRIVATE * psf)385 psf_fwrite (const void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf)
386 {	sf_count_t total = 0 ;
387 	ssize_t	count ;
388 
389 	if (bytes == 0 || items == 0)
390 		return 0 ;
391 
392 	if (psf->virtual_io)
393 		return psf->vio.write (ptr, bytes*items, psf->vio_user_data) / bytes ;
394 
395 	items *= bytes ;
396 
397 	/* Do this check after the multiplication above. */
398 	if (items <= 0)
399 		return 0 ;
400 
401 	while (items > 0)
402 	{	/* Break the writes down to a sensible size. */
403 		count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : items ;
404 
405 		count = write (psf->file.filedes, ((const char*) ptr) + total, count) ;
406 
407 		if (count == -1)
408 		{	if (errno == EINTR)
409 				continue ;
410 
411 			psf_log_syserr (psf, errno) ;
412 			break ;
413 			} ;
414 
415 		if (count == 0)
416 			break ;
417 
418 		total += count ;
419 		items -= count ;
420 		} ;
421 
422 	if (psf->is_pipe)
423 		psf->pipeoffset += total ;
424 
425 	return total / bytes ;
426 } /* psf_fwrite */
427 
428 sf_count_t
psf_ftell(SF_PRIVATE * psf)429 psf_ftell (SF_PRIVATE *psf)
430 {	sf_count_t pos ;
431 
432 	if (psf->virtual_io)
433 		return psf->vio.tell (psf->vio_user_data) ;
434 
435 	if (psf->is_pipe)
436 		return psf->pipeoffset ;
437 
438 	pos = lseek (psf->file.filedes, 0, SEEK_CUR) ;
439 
440 	if (pos == ((sf_count_t) -1))
441 	{	psf_log_syserr (psf, errno) ;
442 		return -1 ;
443 		} ;
444 
445 	return pos - psf->fileoffset ;
446 } /* psf_ftell */
447 
448 static int
psf_close_fd(int fd)449 psf_close_fd (int fd)
450 {	int retval ;
451 
452 	if (fd < 0)
453 		return 0 ;
454 
455 	while ((retval = close (fd)) == -1 && errno == EINTR)
456 		/* Do nothing. */ ;
457 
458 	return retval ;
459 } /* psf_close_fd */
460 
461 sf_count_t
psf_fgets(char * buffer,sf_count_t bufsize,SF_PRIVATE * psf)462 psf_fgets (char *buffer, sf_count_t bufsize, SF_PRIVATE *psf)
463 {	sf_count_t	k = 0 ;
464 	sf_count_t		count ;
465 
466 	while (k < bufsize - 1)
467 	{	count = read (psf->file.filedes, &(buffer [k]), 1) ;
468 
469 		if (count == -1)
470 		{	if (errno == EINTR)
471 				continue ;
472 
473 			psf_log_syserr (psf, errno) ;
474 			break ;
475 			} ;
476 
477 		if (count == 0 || buffer [k++] == '\n')
478 			break ;
479 		} ;
480 
481 	buffer [k] = 0 ;
482 
483 	return k ;
484 } /* psf_fgets */
485 
486 int
psf_is_pipe(SF_PRIVATE * psf)487 psf_is_pipe (SF_PRIVATE *psf)
488 {	struct stat statbuf ;
489 
490 	if (psf->virtual_io)
491 		return SF_FALSE ;
492 
493 	if (fstat (psf->file.filedes, &statbuf) == -1)
494 	{	psf_log_syserr (psf, errno) ;
495 		/* Default to maximum safety. */
496 		return SF_TRUE ;
497 		} ;
498 
499 	if (S_ISFIFO (statbuf.st_mode) || S_ISSOCK (statbuf.st_mode))
500 		return SF_TRUE ;
501 
502 	return SF_FALSE ;
503 } /* psf_is_pipe */
504 
505 static sf_count_t
psf_get_filelen_fd(int fd)506 psf_get_filelen_fd (int fd)
507 {
508 #if (SIZEOF_OFF_T == 4 && HAVE_FSTAT64)
509 	struct stat64 statbuf ;
510 
511 	if (fstat64 (fd, &statbuf) == -1)
512 		return (sf_count_t) -1 ;
513 
514 	return statbuf.st_size ;
515 #else
516 	struct stat statbuf ;
517 
518 	if (fstat (fd, &statbuf) == -1)
519 		return (sf_count_t) -1 ;
520 
521 	return statbuf.st_size ;
522 #endif
523 } /* psf_get_filelen_fd */
524 
525 int
psf_ftruncate(SF_PRIVATE * psf,sf_count_t len)526 psf_ftruncate (SF_PRIVATE *psf, sf_count_t len)
527 {	int retval ;
528 
529 	/* Returns 0 on success, non-zero on failure. */
530 	if (len < 0)
531 		return -1 ;
532 
533 	if ((sizeof (off_t) < sizeof (sf_count_t)) && len > 0x7FFFFFFF)
534 		return -1 ;
535 
536 	retval = ftruncate (psf->file.filedes, len) ;
537 
538 	if (retval == -1)
539 		psf_log_syserr (psf, errno) ;
540 
541 	return retval ;
542 } /* psf_ftruncate */
543 
544 void
psf_init_files(SF_PRIVATE * psf)545 psf_init_files (SF_PRIVATE *psf)
546 {	psf->file.filedes = -1 ;
547 	psf->rsrc.filedes = -1 ;
548 	psf->file.savedes = -1 ;
549 } /* psf_init_files */
550 
551 void
psf_use_rsrc(SF_PRIVATE * psf,int on_off)552 psf_use_rsrc (SF_PRIVATE *psf, int on_off)
553 {
554 	if (on_off)
555 	{	if (psf->file.filedes != psf->rsrc.filedes)
556 		{	psf->file.savedes = psf->file.filedes ;
557 			psf->file.filedes = psf->rsrc.filedes ;
558 			} ;
559 		}
560 	else if (psf->file.filedes == psf->rsrc.filedes)
561 		psf->file.filedes = psf->file.savedes ;
562 
563 	return ;
564 } /* psf_use_rsrc */
565 
566 static int
psf_open_fd(PSF_FILE * pfile)567 psf_open_fd (PSF_FILE * pfile)
568 {	int fd, oflag, mode ;
569 
570 	/*
571 	** Sanity check. If everything is OK, this test and the printfs will
572 	** be optimised out. This is meant to catch the problems caused by
573 	** "sfconfig.h" being included after <stdio.h>.
574 	*/
575 	if (sizeof (sf_count_t) != 8)
576 	{	puts ("\n\n*** Fatal error : sizeof (sf_count_t) != 8") ;
577 		puts ("*** This means that libsndfile was not configured correctly.\n") ;
578 		exit (1) ;
579 		} ;
580 
581 	switch (pfile->mode)
582 	{	case SFM_READ :
583 				oflag = O_RDONLY | O_BINARY ;
584 				mode = 0 ;
585 				break ;
586 
587 		case SFM_WRITE :
588 				oflag = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY ;
589 				mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ;
590 				break ;
591 
592 		case SFM_RDWR :
593 				oflag = O_RDWR | O_CREAT | O_BINARY ;
594 				mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ;
595 				break ;
596 
597 		default :
598 				return - SFE_BAD_OPEN_MODE ;
599 				break ;
600 		} ;
601 
602 	if (mode == 0)
603 		fd = open (pfile->path, oflag) ;
604 	else
605 		fd = open (pfile->path, oflag, mode) ;
606 
607 	return fd ;
608 } /* psf_open_fd */
609 
610 static void
psf_log_syserr(SF_PRIVATE * psf,int error)611 psf_log_syserr (SF_PRIVATE *psf, int error)
612 {
613 	/* Only log an error if no error has been set yet. */
614 	if (psf->error == 0)
615 	{	psf->error = SFE_SYSTEM ;
616 		snprintf (psf->syserr, sizeof (psf->syserr), "System error : %s.", strerror (error)) ;
617 		} ;
618 
619 	return ;
620 } /* psf_log_syserr */
621 
622 void
psf_fsync(SF_PRIVATE * psf)623 psf_fsync (SF_PRIVATE *psf)
624 {
625 #if HAVE_FSYNC
626 	if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
627 		fsync (psf->file.filedes) ;
628 #else
629 	psf = NULL ;
630 #endif
631 } /* psf_fsync */
632 
633 #else
634 
635 /* Win32 file i/o functions implemented using native Win32 API */
636 
637 #ifndef WINAPI_PARTITION_SYSTEM
638 #define WINAPI_PARTITION_SYSTEM 0
639 #endif
640 
641 static int psf_close_handle (HANDLE handle) ;
642 static HANDLE psf_open_handle (PSF_FILE * pfile) ;
643 static sf_count_t psf_get_filelen_handle (HANDLE handle) ;
644 
645 /* USE_WINDOWS_API */ int
psf_fopen(SF_PRIVATE * psf)646 psf_fopen (SF_PRIVATE *psf)
647 {
648 	psf->error = 0 ;
649 	psf->file.handle = psf_open_handle (&psf->file) ;
650 
651 	if (psf->file.handle == INVALID_HANDLE_VALUE)
652 		psf_log_syserr (psf, GetLastError ()) ;
653 
654 	return psf->error ;
655 } /* psf_fopen */
656 
657 /* USE_WINDOWS_API */ int
psf_fclose(SF_PRIVATE * psf)658 psf_fclose (SF_PRIVATE *psf)
659 {	int retval ;
660 
661 	if (psf->virtual_io)
662 		return 0 ;
663 
664 	if (psf->file.do_not_close_descriptor)
665 	{	psf->file.handle = INVALID_HANDLE_VALUE ;
666 		return 0 ;
667 		} ;
668 
669 	if ((retval = psf_close_handle (psf->file.handle)) == -1)
670 		psf_log_syserr (psf, GetLastError ()) ;
671 
672 	psf->file.handle = INVALID_HANDLE_VALUE ;
673 
674 	return retval ;
675 } /* psf_fclose */
676 
677 /* USE_WINDOWS_API */ int
psf_open_rsrc(SF_PRIVATE * psf)678 psf_open_rsrc (SF_PRIVATE *psf)
679 {
680 	if (psf->rsrc.handle != INVALID_HANDLE_VALUE)
681 		return 0 ;
682 
683 	/* Test for MacOSX style resource fork on HPFS or HPFS+ filesystems. */
684 	snprintf (psf->rsrc.path, sizeof (psf->rsrc.path), "%s/rsrc", psf->file.path) ;
685 	psf->error = SFE_NO_ERROR ;
686 	if ((psf->rsrc.handle = psf_open_handle (&psf->rsrc)) != INVALID_HANDLE_VALUE)
687 	{	psf->rsrclength = psf_get_filelen_handle (psf->rsrc.handle) ;
688 		return SFE_NO_ERROR ;
689 		} ;
690 
691 	/*
692 	** Now try for a resource fork stored as a separate file in the same
693 	** directory, but preceded with a dot underscore.
694 	*/
695 	snprintf (psf->rsrc.path, sizeof (psf->rsrc.path), "%s._%s", psf->file.dir, psf->file.name) ;
696 	psf->error = SFE_NO_ERROR ;
697 	if ((psf->rsrc.handle = psf_open_handle (&psf->rsrc)) != INVALID_HANDLE_VALUE)
698 	{	psf->rsrclength = psf_get_filelen_handle (psf->rsrc.handle) ;
699 		return SFE_NO_ERROR ;
700 		} ;
701 
702 	/*
703 	** Now try for a resource fork stored in a separate file in the
704 	** .AppleDouble/ directory.
705 	*/
706 	snprintf (psf->rsrc.path, sizeof (psf->rsrc.path), "%s.AppleDouble/%s", psf->file.dir, psf->file.name) ;
707 	psf->error = SFE_NO_ERROR ;
708 	if ((psf->rsrc.handle = psf_open_handle (&psf->rsrc)) != INVALID_HANDLE_VALUE)
709 	{	psf->rsrclength = psf_get_filelen_handle (psf->rsrc.handle) ;
710 		return SFE_NO_ERROR ;
711 		} ;
712 
713 	/* No resource file found. */
714 	if (psf->rsrc.handle == INVALID_HANDLE_VALUE)
715 		psf_log_syserr (psf, GetLastError ()) ;
716 
717 	return psf->error ;
718 } /* psf_open_rsrc */
719 
720 /* USE_WINDOWS_API */ sf_count_t
psf_get_filelen(SF_PRIVATE * psf)721 psf_get_filelen (SF_PRIVATE *psf)
722 {	sf_count_t	filelen ;
723 
724 	if (psf->virtual_io)
725 		return psf->vio.get_filelen (psf->vio_user_data) ;
726 
727 	filelen = psf_get_filelen_handle (psf->file.handle) ;
728 
729 	if (filelen == -1)
730 	{	psf_log_syserr (psf, errno) ;
731 		return (sf_count_t) -1 ;
732 		} ;
733 
734 	if (filelen == -SFE_BAD_STAT_SIZE)
735 	{	psf->error = SFE_BAD_STAT_SIZE ;
736 		return (sf_count_t) -1 ;
737 		} ;
738 
739 	switch (psf->file.mode)
740 	{	case SFM_WRITE :
741 			filelen = filelen - psf->fileoffset ;
742 			break ;
743 
744 		case SFM_READ :
745 			if (psf->fileoffset > 0 && psf->filelength > 0)
746 				filelen = psf->filelength ;
747 			break ;
748 
749 		case SFM_RDWR :
750 			/*
751 			** Cannot open embedded files SFM_RDWR so we don't need to
752 			** subtract psf->fileoffset. We already have the answer we
753 			** need.
754 			*/
755 			break ;
756 
757 		default :
758 			/* Shouldn't be here, so return error. */
759 			filelen = -1 ;
760 		} ;
761 
762 	return filelen ;
763 } /* psf_get_filelen */
764 
765 /* USE_WINDOWS_API */ void
psf_init_files(SF_PRIVATE * psf)766 psf_init_files (SF_PRIVATE *psf)
767 {	psf->file.handle = INVALID_HANDLE_VALUE ;
768 	psf->rsrc.handle = INVALID_HANDLE_VALUE ;
769 	psf->file.hsaved = INVALID_HANDLE_VALUE ;
770 } /* psf_init_files */
771 
772 /* USE_WINDOWS_API */ void
psf_use_rsrc(SF_PRIVATE * psf,int on_off)773 psf_use_rsrc (SF_PRIVATE *psf, int on_off)
774 {
775 	if (on_off)
776 	{	if (psf->file.handle != psf->rsrc.handle)
777 		{	psf->file.hsaved = psf->file.handle ;
778 			psf->file.handle = psf->rsrc.handle ;
779 			} ;
780 		}
781 	else if (psf->file.handle == psf->rsrc.handle)
782 		psf->file.handle = psf->file.hsaved ;
783 
784 	return ;
785 } /* psf_use_rsrc */
786 
787 /* USE_WINDOWS_API */ static HANDLE
psf_open_handle(PSF_FILE * pfile)788 psf_open_handle (PSF_FILE * pfile)
789 {	DWORD dwDesiredAccess ;
790 	DWORD dwShareMode ;
791 	DWORD dwCreationDistribution ;
792 	HANDLE handle ;
793 	LPWSTR pwszPath = NULL ;
794 
795 	switch (pfile->mode)
796 	{	case SFM_READ :
797 				dwDesiredAccess = GENERIC_READ ;
798 				dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ;
799 				dwCreationDistribution = OPEN_EXISTING ;
800 				break ;
801 
802 		case SFM_WRITE :
803 				dwDesiredAccess = GENERIC_WRITE ;
804 				dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ;
805 				dwCreationDistribution = CREATE_ALWAYS ;
806 				break ;
807 
808 		case SFM_RDWR :
809 				dwDesiredAccess = GENERIC_READ | GENERIC_WRITE ;
810 				dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ;
811 				dwCreationDistribution = OPEN_ALWAYS ;
812 				break ;
813 
814 		default :
815 				return INVALID_HANDLE_VALUE ;
816 		} ;
817 
818 	int nResult = MultiByteToWideChar (CP_UTF8, 0, pfile->path, -1, NULL, 0) ;
819 	pwszPath = malloc (nResult * sizeof (WCHAR)) ;
820 	if (!pwszPath)
821 		return INVALID_HANDLE_VALUE ;
822 
823 	int nResult2 = MultiByteToWideChar (CP_UTF8, 0, pfile->path, -1, pwszPath, nResult) ;
824 	if (nResult != nResult2)
825 	{	free (pwszPath) ;
826 		return INVALID_HANDLE_VALUE ;
827 		} ;
828 
829 #if defined (WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
830 	CREATEFILE2_EXTENDED_PARAMETERS cfParams = { 0 } ;
831 	cfParams.dwSize = sizeof (CREATEFILE2_EXTENDED_PARAMETERS) ;
832 	cfParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL ;
833 
834 	handle = CreateFile2 (pwszPath, dwDesiredAccess, dwShareMode, dwCreationDistribution, &cfParams) ;
835 #else
836 	handle = CreateFileW (
837 				pwszPath,					/* pointer to name of the file */
838 				dwDesiredAccess,			/* access (read-write) mode */
839 				dwShareMode,				/* share mode */
840 				0,							/* pointer to security attributes */
841 				dwCreationDistribution,		/* how to create */
842 				FILE_ATTRIBUTE_NORMAL,		/* file attributes (could use FILE_FLAG_SEQUENTIAL_SCAN) */
843 				NULL						/* handle to file with attributes to copy */
844 				) ;
845 #endif
846 	free (pwszPath) ;
847 
848 	return handle ;
849 } /* psf_open_handle */
850 
851 /* USE_WINDOWS_API */ static void
psf_log_syserr(SF_PRIVATE * psf,int error)852 psf_log_syserr (SF_PRIVATE *psf, int error)
853 {	LPVOID lpMsgBuf ;
854 
855 	/* Only log an error if no error has been set yet. */
856 	if (psf->error == 0)
857 	{	psf->error = SFE_SYSTEM ;
858 
859 		FormatMessage (
860 			FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
861 			NULL,
862 			error,
863 			MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
864 			(LPTSTR) &lpMsgBuf,
865 			0,
866 			NULL
867 			) ;
868 
869 		snprintf (psf->syserr, sizeof (psf->syserr), "System error : %s", (char*) lpMsgBuf) ;
870 		LocalFree (lpMsgBuf) ;
871 		} ;
872 
873 	return ;
874 } /* psf_log_syserr */
875 
876 
877 /* USE_WINDOWS_API */ int
psf_close_rsrc(SF_PRIVATE * psf)878 psf_close_rsrc (SF_PRIVATE *psf)
879 {	psf_close_handle (psf->rsrc.handle) ;
880 	psf->rsrc.handle = INVALID_HANDLE_VALUE ;
881 	return 0 ;
882 } /* psf_close_rsrc */
883 
884 
885 /* USE_WINDOWS_API */ int
psf_set_stdio(SF_PRIVATE * psf)886 psf_set_stdio (SF_PRIVATE *psf)
887 {	HANDLE	handle = INVALID_HANDLE_VALUE ;
888 	int	error = 0 ;
889 
890 	switch (psf->file.mode)
891 	{	case SFM_RDWR :
892 				error = SFE_OPEN_PIPE_RDWR ;
893 				break ;
894 
895 		case SFM_READ :
896 				handle = GetStdHandle (STD_INPUT_HANDLE) ;
897 				psf->file.do_not_close_descriptor = 1 ;
898 				break ;
899 
900 		case SFM_WRITE :
901 				handle = GetStdHandle (STD_OUTPUT_HANDLE) ;
902 				psf->file.do_not_close_descriptor = 1 ;
903 				break ;
904 
905 		default :
906 				error = SFE_BAD_OPEN_MODE ;
907 				break ;
908 		} ;
909 
910 	psf->file.handle = handle ;
911 	psf->filelength = 0 ;
912 
913 	return error ;
914 } /* psf_set_stdio */
915 
916 /* USE_WINDOWS_API */ void
psf_set_file(SF_PRIVATE * psf,int fd)917 psf_set_file (SF_PRIVATE *psf, int fd)
918 {	HANDLE handle ;
919 	intptr_t osfhandle ;
920 
921 	osfhandle = _get_osfhandle (fd) ;
922 	handle = (HANDLE) osfhandle ;
923 
924 	psf->file.handle = handle ;
925 } /* psf_set_file */
926 
927 /* USE_WINDOWS_API */ int
psf_file_valid(SF_PRIVATE * psf)928 psf_file_valid (SF_PRIVATE *psf)
929 {	if (psf->file.handle == INVALID_HANDLE_VALUE)
930 		return SF_FALSE ;
931 	return SF_TRUE ;
932 } /* psf_set_file */
933 
934 /* USE_WINDOWS_API */ sf_count_t
psf_fseek(SF_PRIVATE * psf,sf_count_t offset,int whence)935 psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence)
936 {	sf_count_t new_position ;
937 	LARGE_INTEGER liDistanceToMove, liNewFilePointer ;
938 	DWORD dwMoveMethod ;
939 	BOOL fResult ;
940 	DWORD dwError ;
941 
942 	if (psf->virtual_io)
943 		return psf->vio.seek (offset, whence, psf->vio_user_data) ;
944 
945 	switch (whence)
946 	{	case SEEK_SET :
947 				offset += psf->fileoffset ;
948 				dwMoveMethod = FILE_BEGIN ;
949 				break ;
950 
951 		case SEEK_END :
952 				dwMoveMethod = FILE_END ;
953 				break ;
954 
955 		default :
956 				dwMoveMethod = FILE_CURRENT ;
957 				break ;
958 		} ;
959 
960 	liDistanceToMove.QuadPart = offset ;
961 
962 	fResult = SetFilePointerEx (psf->file.handle, liDistanceToMove, &liNewFilePointer, dwMoveMethod) ;
963 
964 	if (fResult == FALSE)
965 		dwError = GetLastError () ;
966 	else
967 		dwError = NO_ERROR ;
968 
969 	if (dwError != NO_ERROR)
970 	{	psf_log_syserr (psf, dwError) ;
971 		return -1 ;
972 		} ;
973 
974 	new_position = liNewFilePointer.QuadPart - psf->fileoffset ;
975 
976 	return new_position ;
977 } /* psf_fseek */
978 
979 /* USE_WINDOWS_API */ sf_count_t
psf_fread(void * ptr,sf_count_t bytes,sf_count_t items,SF_PRIVATE * psf)980 psf_fread (void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf)
981 {	sf_count_t total = 0 ;
982 	ssize_t count ;
983 	DWORD dwNumberOfBytesRead ;
984 
985 	if (psf->virtual_io)
986 		return psf->vio.read (ptr, bytes*items, psf->vio_user_data) / bytes ;
987 
988 	items *= bytes ;
989 
990 	/* Do this check after the multiplication above. */
991 	if (items <= 0)
992 		return 0 ;
993 
994 	while (items > 0)
995 	{	/* Break the writes down to a sensible size. */
996 		count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ;
997 
998 		if (ReadFile (psf->file.handle, ((char*) ptr) + total, count, &dwNumberOfBytesRead, 0) == 0)
999 		{	psf_log_syserr (psf, GetLastError ()) ;
1000 			break ;
1001 			}
1002 		else
1003 			count = dwNumberOfBytesRead ;
1004 
1005 		if (count == 0)
1006 			break ;
1007 
1008 		total += count ;
1009 		items -= count ;
1010 		} ;
1011 
1012 	if (psf->is_pipe)
1013 		psf->pipeoffset += total ;
1014 
1015 	return total / bytes ;
1016 } /* psf_fread */
1017 
1018 /* USE_WINDOWS_API */ sf_count_t
psf_fwrite(const void * ptr,sf_count_t bytes,sf_count_t items,SF_PRIVATE * psf)1019 psf_fwrite (const void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf)
1020 {	sf_count_t total = 0 ;
1021 	ssize_t	count ;
1022 	DWORD dwNumberOfBytesWritten ;
1023 
1024 	if (psf->virtual_io)
1025 		return psf->vio.write (ptr, bytes * items, psf->vio_user_data) / bytes ;
1026 
1027 	items *= bytes ;
1028 
1029 	/* Do this check after the multiplication above. */
1030 	if (items <= 0)
1031 		return 0 ;
1032 
1033 	while (items > 0)
1034 	{	/* Break the writes down to a sensible size. */
1035 		count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ;
1036 
1037 		if (WriteFile (psf->file.handle, ((const char*) ptr) + total, count, &dwNumberOfBytesWritten, 0) == 0)
1038 		{	psf_log_syserr (psf, GetLastError ()) ;
1039 			break ;
1040 			}
1041 		else
1042 			count = dwNumberOfBytesWritten ;
1043 
1044 		if (count == 0)
1045 			break ;
1046 
1047 		total += count ;
1048 		items -= count ;
1049 		} ;
1050 
1051 	if (psf->is_pipe)
1052 		psf->pipeoffset += total ;
1053 
1054 	return total / bytes ;
1055 } /* psf_fwrite */
1056 
1057 /* USE_WINDOWS_API */ sf_count_t
psf_ftell(SF_PRIVATE * psf)1058 psf_ftell (SF_PRIVATE *psf)
1059 {	sf_count_t pos ;
1060 	LARGE_INTEGER liDistanceToMove, liNewFilePointer ;
1061 	BOOL fResult ;
1062 	DWORD dwError ;
1063 
1064 	if (psf->virtual_io)
1065 		return psf->vio.tell (psf->vio_user_data) ;
1066 
1067 	if (psf->is_pipe)
1068 		return psf->pipeoffset ;
1069 
1070 	liDistanceToMove.QuadPart = 0 ;
1071 
1072 	fResult = SetFilePointerEx (psf->file.handle, liDistanceToMove, &liNewFilePointer, FILE_CURRENT) ;
1073 
1074 	if (fResult == FALSE)
1075 		dwError = GetLastError () ;
1076 	else
1077 		dwError = NO_ERROR ;
1078 
1079 	if (dwError != NO_ERROR)
1080 	{	psf_log_syserr (psf, dwError) ;
1081 		return -1 ;
1082 		} ;
1083 
1084 	pos = liNewFilePointer.QuadPart ;
1085 
1086 	return pos - psf->fileoffset ;
1087 } /* psf_ftell */
1088 
1089 /* USE_WINDOWS_API */ static int
psf_close_handle(HANDLE handle)1090 psf_close_handle (HANDLE handle)
1091 {	if (handle == INVALID_HANDLE_VALUE)
1092 		return 0 ;
1093 
1094 	if (CloseHandle (handle) == 0)
1095 		return -1 ;
1096 
1097 	return 0 ;
1098 } /* psf_close_handle */
1099 
1100 /* USE_WINDOWS_API */ sf_count_t
psf_fgets(char * buffer,sf_count_t bufsize,SF_PRIVATE * psf)1101 psf_fgets (char *buffer, sf_count_t bufsize, SF_PRIVATE *psf)
1102 {	sf_count_t k = 0 ;
1103 	sf_count_t count ;
1104 	DWORD dwNumberOfBytesRead ;
1105 
1106 	while (k < bufsize - 1)
1107 	{	if (ReadFile (psf->file.handle, &(buffer [k]), 1, &dwNumberOfBytesRead, 0) == 0)
1108 		{	psf_log_syserr (psf, GetLastError ()) ;
1109 			break ;
1110 			}
1111 		else
1112 		{	count = dwNumberOfBytesRead ;
1113 			/* note that we only check for '\n' not other line endings such as CRLF */
1114 			if (count == 0 || buffer [k++] == '\n')
1115 				break ;
1116 			} ;
1117 		} ;
1118 
1119 	buffer [k] = 0 ;
1120 
1121 	return k ;
1122 } /* psf_fgets */
1123 
1124 /* USE_WINDOWS_API */ int
psf_is_pipe(SF_PRIVATE * psf)1125 psf_is_pipe (SF_PRIVATE *psf)
1126 {
1127 	if (psf->virtual_io)
1128 		return SF_FALSE ;
1129 
1130 	if (GetFileType (psf->file.handle) == FILE_TYPE_DISK)
1131 		return SF_FALSE ;
1132 
1133 	/* Default to maximum safety. */
1134 	return SF_TRUE ;
1135 } /* psf_is_pipe */
1136 
1137 /* USE_WINDOWS_API */ sf_count_t
psf_get_filelen_handle(HANDLE handle)1138 psf_get_filelen_handle (HANDLE handle)
1139 {	sf_count_t filelen ;
1140 	LARGE_INTEGER liFileSize ;
1141 	BOOL fResult ;
1142 	DWORD dwError = NO_ERROR ;
1143 
1144 	fResult = GetFileSizeEx (handle, &liFileSize) ;
1145 
1146 	if (fResult == FALSE)
1147 		dwError = GetLastError () ;
1148 
1149 	if (dwError != NO_ERROR)
1150 		return (sf_count_t) -1 ;
1151 
1152 	filelen = liFileSize.QuadPart ;
1153 
1154 	return filelen ;
1155 } /* psf_get_filelen_handle */
1156 
1157 /* USE_WINDOWS_API */ void
psf_fsync(SF_PRIVATE * psf)1158 psf_fsync (SF_PRIVATE *psf)
1159 {	FlushFileBuffers (psf->file.handle) ;
1160 } /* psf_fsync */
1161 
1162 
1163 /* USE_WINDOWS_API */ int
psf_ftruncate(SF_PRIVATE * psf,sf_count_t len)1164 psf_ftruncate (SF_PRIVATE *psf, sf_count_t len)
1165 {	int retval = 0 ;
1166 	LARGE_INTEGER liDistanceToMove ;
1167 	BOOL fResult ;
1168 	DWORD dwError = NO_ERROR ;
1169 
1170 	/* This implementation trashes the current file position.
1171 	** should it save and restore it? what if the current position is past
1172 	** the new end of file?
1173 	*/
1174 
1175 	/* Returns 0 on success, non-zero on failure. */
1176 	if (len < 0)
1177 		return 1 ;
1178 
1179 	liDistanceToMove.QuadPart = (sf_count_t) len ;
1180 
1181 	fResult = SetFilePointerEx (psf->file.handle, liDistanceToMove, NULL, FILE_BEGIN) ;
1182 
1183 	if (fResult == FALSE)
1184 		dwError = GetLastError () ;
1185 
1186 	if (dwError != NO_ERROR)
1187 	{	retval = -1 ;
1188 		psf_log_syserr (psf, dwError) ;
1189 		}
1190 	else
1191 	{	/* Note: when SetEndOfFile is used to extend a file, the contents of the
1192 		** new portion of the file is undefined. This is unlike chsize(),
1193 		** which guarantees that the new portion of the file will be zeroed.
1194 		** Not sure if this is important or not.
1195 		*/
1196 		if (SetEndOfFile (psf->file.handle) == 0)
1197 		{	retval = -1 ;
1198 			psf_log_syserr (psf, GetLastError ()) ;
1199 			} ;
1200 		} ;
1201 
1202 	return retval ;
1203 } /* psf_ftruncate */
1204 
1205 #endif
1206 
1207