file_io.c
上传用户:shw771010
上传日期:2022-01-05
资源大小:991k
文件大小:35k
源码类别:

Audio

开发平台:

Unix_Linux

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