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