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 77static void psf_log_syserr (SF_PRIVATE *psf, int error) ; 78 79int 80psf_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 113static int psf_close_fd (int fd) ; 114static int psf_open_fd (PSF_FILE * pfile) ; 115static sf_count_t psf_get_filelen_fd (int fd) ; 116 117int 118psf_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 135int 136psf_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 155int 156psf_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 216sf_count_t 217psf_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 261int 262psf_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 268int 269psf_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 294void 295psf_set_file (SF_PRIVATE *psf, int fd) 296{ psf->file.filedes = fd ; 297} /* psf_set_file */ 298 299int 300psf_file_valid (SF_PRIVATE *psf) 301{ return (psf->file.filedes >= 0) ? SF_TRUE : SF_FALSE ; 302} /* psf_set_file */ 303 304sf_count_t 305psf_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 343sf_count_t 344psf_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 384sf_count_t 385psf_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 428sf_count_t 429psf_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 448static int 449psf_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 461sf_count_t 462psf_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 486int 487psf_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 505static sf_count_t 506psf_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 525int 526psf_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 544void 545psf_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 551void 552psf_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 566static int 567psf_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 610static void 611psf_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 622void 623psf_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 641static int psf_close_handle (HANDLE handle) ; 642static HANDLE psf_open_handle (PSF_FILE * pfile) ; 643static sf_count_t psf_get_filelen_handle (HANDLE handle) ; 644 645/* USE_WINDOWS_API */ int 646psf_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 658psf_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 678psf_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 721psf_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 766psf_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 773psf_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 788psf_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 852psf_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 878psf_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 886psf_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 917psf_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 928psf_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 935psf_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 980psf_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 1019psf_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 1058psf_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 1090psf_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 1101psf_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 1125psf_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 1138psf_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 1158psf_fsync (SF_PRIVATE *psf) 1159{ FlushFileBuffers (psf->file.handle) ; 1160} /* psf_fsync */ 1161 1162 1163/* USE_WINDOWS_API */ int 1164psf_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