bf_torek.c
上传用户:xu_441
上传日期:2007-01-04
资源大小:1640k
文件大小:15k
源码类别:

Email客户端

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (c) 1999 Sendmail, Inc. and its suppliers.
  3.  * All rights reserved.
  4.  *
  5.  * By using this file, you agree to the terms and conditions set
  6.  * forth in the LICENSE file which can be found at the top level of
  7.  * the sendmail distribution.
  8.  *
  9.  * Contributed by Exactis.com, Inc.
  10.  *
  11.  */
  12. #ifndef lint
  13. static char id[] = "@(#)$Id: bf_torek.c,v 8.19 1999/10/11 23:37:26 ca Exp $";
  14. #endif /* ! lint */
  15. #include <sys/types.h>
  16. #include <sys/uio.h>
  17. #include <fcntl.h>
  18. #include <unistd.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <errno.h>
  22. #include <stdio.h>
  23. #ifndef BF_STANDALONE
  24. # include "sendmail.h"
  25. #endif /* ! BF_STANDALONE */
  26. #include "bf_torek.h"
  27. #include "bf.h"
  28. /*
  29. **  BFOPEN -- create a new buffered file
  30. **
  31. ** Parameters:
  32. ** filename -- the file's name
  33. ** fmode -- what mode the file should be created as
  34. ** bsize -- amount of buffer space to allocate (may be 0)
  35. ** flags -- if running under sendmail, passed directly to safeopen
  36. **
  37. ** Returns:
  38. ** a FILE * which may then be used with stdio functions, or NULL
  39. ** on failure. FILE * is opened for writing (mode "w+").
  40. **
  41. ** Side Effects:
  42. ** none.
  43. **
  44. ** Sets errno:
  45. ** ENOMEM -- out of memory
  46. ** ENOENT -- illegal empty filename specified
  47. ** any value of errno specified by open()
  48. ** any value of errno specified by fdopen()
  49. ** any value of errno specified by funopen()
  50. */
  51. #ifdef BF_STANDALONE
  52. # define OPEN(fn, omode, cmode, sff) open(fn, omode, cmode)
  53. #else /* BF_STANDALONE */
  54. # define OPEN(fn, omode, cmode, sff) safeopen(fn, omode, cmode, sff)
  55. #endif /* BF_STANDALONE */
  56. FILE *
  57. bfopen(filename, fmode, bsize, flags)
  58. char *filename;
  59. int fmode;
  60. size_t bsize;
  61. long flags;
  62. {
  63. struct bf *bfp;
  64. FILE *retval;
  65. int save_errno, l;
  66. struct stat st;
  67. /* Sanity checks */
  68. /* Empty filename string */
  69. if (*filename == '')
  70. {
  71. errno = ENOENT;
  72. return NULL;
  73. }
  74. if (stat(filename, &st) == 0)
  75. {
  76. /* file already exists on disk */
  77. errno = EEXIST;
  78. return NULL;
  79. }
  80. /* Allocate memory */
  81. bfp = (struct bf *)malloc(sizeof(struct bf));
  82. if (bfp == NULL)
  83. {
  84. errno = ENOMEM;
  85. return NULL;
  86. }
  87. /* A zero bsize is valid, just don't allocate memory */
  88. if (bsize > 0)
  89. {
  90. bfp->bf_buf = (char *)malloc(bsize);
  91. if (bfp->bf_buf == NULL)
  92. {
  93. free(bfp);
  94. errno = ENOMEM;
  95. return NULL;
  96. }
  97. }
  98. else
  99. bfp->bf_buf = NULL;
  100. /* Nearly home free, just set all the parameters now */
  101. bfp->bf_committed = FALSE;
  102. bfp->bf_ondisk = FALSE;
  103. bfp->bf_refcount = 1;
  104. bfp->bf_flags = flags;
  105. bfp->bf_bufsize = bsize;
  106. bfp->bf_buffilled = 0;
  107. l = strlen(filename) + 1;
  108. bfp->bf_filename = (char *)malloc(l);
  109. if (bfp->bf_filename == NULL)
  110. {
  111. free(bfp);
  112. if (bfp->bf_buf != NULL)
  113. free(bfp->bf_buf);
  114. errno = ENOMEM;
  115. return NULL;
  116. }
  117. (void) strlcpy(bfp->bf_filename, filename, l);
  118. bfp->bf_filemode = fmode;
  119. bfp->bf_offset = 0;
  120. bfp->bf_size = 0;
  121. if (tTd(58, 8))
  122. dprintf("bfopen(%s, %d)n", filename, bsize);
  123. /* The big test: will funopen accept it? */
  124. retval = funopen((void *)bfp, _bfread, _bfwrite, _bfseek, _bfclose);
  125. if (retval == NULL)
  126. {
  127. /* Just in case free() sets errno */
  128. save_errno = errno;
  129. free(bfp);
  130. free(bfp->bf_filename);
  131. if (bfp->bf_buf != NULL)
  132. free(bfp->bf_buf);
  133. errno = save_errno;
  134. return NULL;
  135. }
  136. else
  137. {
  138. /* Success */
  139. return retval;
  140. }
  141. }
  142. /*
  143. **  BFDUP -- increase refcount on buffered file
  144. **
  145. ** Parameters:
  146. ** fp -- FILE * to "duplicate"
  147. **
  148. ** Returns:
  149. ** If file is memory buffered, fp with increased refcount
  150. ** If file is on disk, NULL (need to use link())
  151. */
  152. FILE *
  153. bfdup(fp)
  154. FILE *fp;
  155. {
  156. struct bf *bfp;
  157. /* If called on a normal FILE *, noop */
  158. if (!bftest(fp))
  159. return NULL;
  160. /* Get associated bf structure */
  161. bfp = (struct bf *)fp->_cookie;
  162. /* Increase ref count */
  163. bfp->bf_refcount++;
  164. return fp;
  165. }
  166. /*
  167. **  BFCOMMIT -- "commits" the buffered file
  168. **
  169. ** Parameters:
  170. ** fp -- FILE * to commit to disk
  171. **
  172. ** Returns:
  173. ** 0 on success, -1 on error
  174. **
  175. ** Side Effects:
  176. ** Forces the given FILE * to be written to disk if it is not
  177. ** already, and ensures that it will be kept after closing. If
  178. ** fp is not a buffered file, this is a no-op.
  179. **
  180. ** Sets errno:
  181. ** any value of errno specified by open()
  182. ** any value of errno specified by write()
  183. ** any value of errno specified by lseek()
  184. */
  185. int
  186. bfcommit(fp)
  187. FILE *fp;
  188. {
  189. struct bf *bfp;
  190. int retval;
  191. int byteswritten;
  192. /* If called on a normal FILE *, noop */
  193. if (!bftest(fp))
  194. return 0;
  195. /* Get associated bf structure */
  196. bfp = (struct bf *)fp->_cookie;
  197. /* If already committed, noop */
  198. if (bfp->bf_committed)
  199. return 0;
  200. /* Do we need to open a file? */
  201. if (!bfp->bf_ondisk)
  202. {
  203. struct stat st;
  204. if (tTd(58, 8))
  205. dprintf("bfcommit(%s): to diskn", bfp->bf_filename);
  206. if (stat(bfp->bf_filename, &st) == 0)
  207. {
  208. errno = EEXIST;
  209. return -1;
  210. }
  211. retval = OPEN(bfp->bf_filename, O_RDWR | O_CREAT | O_TRUNC,
  212.       bfp->bf_filemode, bfp->bf_flags);
  213. /* Couldn't create file: failure */
  214. if (retval < 0)
  215. {
  216. /* errno is set implicitly by open() */
  217. return -1;
  218. }
  219. bfp->bf_disk_fd = retval;
  220. bfp->bf_ondisk = TRUE;
  221. }
  222. /* Write out the contents of our buffer, if we have any */
  223. if (bfp->bf_buffilled > 0)
  224. {
  225. byteswritten = 0;
  226. if (lseek(bfp->bf_disk_fd, 0, SEEK_SET) < 0)
  227. {
  228. /* errno is set implicitly by lseek() */
  229. return -1;
  230. }
  231. while (byteswritten < bfp->bf_buffilled)
  232. {
  233. retval = write(bfp->bf_disk_fd,
  234.        bfp->bf_buf + byteswritten,
  235.        bfp->bf_buffilled - byteswritten);
  236. if (retval < 0)
  237. {
  238. /* errno is set implicitly by write() */
  239. return -1;
  240. }
  241. else
  242. byteswritten += retval;
  243. }
  244. }
  245. bfp->bf_committed = TRUE;
  246. /* Invalidate buf; all goes to file now */
  247. bfp->bf_buffilled = 0;
  248. if (bfp->bf_bufsize > 0)
  249. {
  250. /* Don't need buffer anymore; free it */
  251. bfp->bf_bufsize = 0;
  252. free(bfp->bf_buf);
  253. }
  254. return 0;
  255. }
  256. /*
  257. **  BFREWIND -- rewinds the FILE *
  258. **
  259. ** Parameters:
  260. ** fp -- FILE * to rewind
  261. **
  262. ** Returns:
  263. ** 0 on success, -1 on error
  264. **
  265. ** Side Effects:
  266. ** rewinds the FILE * and puts it into read mode. Normally one
  267. ** would bfopen() a file, write to it, then bfrewind() and
  268. ** fread(). If fp is not a buffered file, this is equivalent to
  269. ** rewind().
  270. **
  271. ** Sets errno:
  272. ** any value of errno specified by fseek()
  273. */
  274. int
  275. bfrewind(fp)
  276. FILE *fp;
  277. {
  278. int err;
  279. /* check to see if there is an error on the stream */
  280. err = ferror(fp);
  281. (void) fflush(fp);
  282. /*
  283. **  Clear error if tried to fflush()
  284. **  a read-only file pointer and
  285. **  there wasn't a previous error.
  286. */
  287. if (err == 0)
  288. clearerr(fp);
  289. /* errno is set implicitly by fseek() before return */
  290. return fseek(fp, 0, SEEK_SET);
  291. }
  292. /*
  293. **  BFTRUNCATE -- rewinds and truncates the FILE *
  294. **
  295. ** Parameters:
  296. ** fp -- FILE * to truncate
  297. **
  298. ** Returns:
  299. ** 0 on success, -1 on error
  300. **
  301. ** Side Effects:
  302. ** rewinds the FILE *, truncates it to zero length, and puts it
  303. ** into write mode. If fp is not a buffered file, this is
  304. ** equivalent to a rewind() and then an ftruncate(fileno(fp), 0).
  305. **
  306. ** Sets errno:
  307. ** any value of errno specified by fseek()
  308. ** any value of errno specified by ftruncate()
  309. */
  310. int
  311. bftruncate(fp)
  312. FILE *fp;
  313. {
  314. struct bf *bfp;
  315. if (bfrewind(fp) < 0)
  316. return -1;
  317. if (bftest(fp))
  318. {
  319. /* Get bf structure */
  320. bfp = (struct bf *)fp->_cookie;
  321. bfp->bf_buffilled = 0;
  322. bfp->bf_size = 0;
  323. /* Need to zero the buffer */
  324. if (bfp->bf_bufsize > 0)
  325. memset(bfp->bf_buf, '', bfp->bf_bufsize);
  326. if (bfp->bf_ondisk)
  327. return ftruncate(bfp->bf_disk_fd, 0);
  328. else
  329. return 0;
  330. }
  331. else
  332. return ftruncate(fileno(fp), 0);
  333. }
  334. /*
  335. **  BFCLOSE -- close a buffered file
  336. **
  337. ** Parameters:
  338. ** fp -- FILE * to close
  339. **
  340. ** Returns:
  341. ** 0 on success, EOF on failure
  342. **
  343. ** Side Effects:
  344. ** Closes fp. If fp is a buffered file, unlink it if it has not
  345. ** already been committed. If fp is not a buffered file, this is
  346. ** equivalent to fclose().
  347. **
  348. ** Sets errno:
  349. ** any value of errno specified by fclose()
  350. */
  351. int
  352. bfclose(fp)
  353. FILE *fp;
  354. {
  355. struct bf *bfp;
  356. /* If called on a normal FILE *, call fclose() on it */
  357. if (!bftest(fp))
  358. return fclose(fp);
  359. /* Cast cookie back to correct type */
  360. bfp = (struct bf *)fp->_cookie;
  361. /* Check reference count to see if we actually want to close */
  362. if (bfp != NULL && --bfp->bf_refcount > 0)
  363. return 0;
  364. /*
  365. **  In this implementation, just call fclose--the _bfclose
  366. **  routine will be called by that
  367. */
  368. return fclose(fp);
  369. }
  370. /*
  371. **  BFTEST -- test if a FILE * is a buffered file
  372. **
  373. ** Parameters:
  374. ** fp -- FILE * to test
  375. **
  376. ** Returns:
  377. ** TRUE if fp is a buffered file, FALSE otherwise.
  378. **
  379. ** Side Effects:
  380. ** none.
  381. **
  382. ** Sets errno:
  383. ** never.
  384. */
  385. bool
  386. bftest(fp)
  387. FILE *fp;
  388. {
  389. /*
  390. **  Check to see if our special I/O routines are installed
  391. **  in this file structure
  392. */
  393. return ((fp->_close == _bfclose) &&
  394. (fp->_read == _bfread) &&
  395. (fp->_seek == _bfseek) &&
  396. (fp->_write == _bfwrite));
  397. }
  398. /*
  399. **  _BFCLOSE -- close a buffered file
  400. **
  401. ** Parameters:
  402. ** cookie -- cookie of file to close
  403. **
  404. ** Returns:
  405. ** 0 to indicate success
  406. **
  407. ** Side Effects:
  408. ** deletes backing file, frees memory.
  409. **
  410. ** Sets errno:
  411. ** never.
  412. */
  413. int
  414. _bfclose(cookie)
  415. void *cookie;
  416. {
  417. struct bf *bfp;
  418. /* Cast cookie back to correct type */
  419. bfp = (struct bf *)cookie;
  420. /* Need to clean up the file */
  421. if (bfp->bf_ondisk && !bfp->bf_committed)
  422. unlink(bfp->bf_filename);
  423. /* Need to free the buffer */
  424. if (bfp->bf_bufsize > 0)
  425. free(bfp->bf_buf);
  426. /* Finally, free the structure */
  427. free(bfp);
  428. return 0;
  429. }
  430. /*
  431. **  _BFREAD -- read a buffered file
  432. **
  433. ** Parameters:
  434. ** cookie -- cookie of file to read
  435. ** buf -- buffer to fill
  436. ** nbytes -- how many bytes to read
  437. **
  438. ** Returns:
  439. ** number of bytes read or -1 indicate failure
  440. **
  441. ** Side Effects:
  442. ** none.
  443. **
  444. */
  445. int
  446. _bfread(cookie, buf, nbytes)
  447. void *cookie;
  448. char *buf;
  449. int nbytes;
  450. {
  451. struct bf *bfp;
  452. int count = 0; /* Number of bytes put in buf so far */
  453. int retval;
  454. /* Cast cookie back to correct type */
  455. bfp = (struct bf *)cookie;
  456. if (bfp->bf_offset < bfp->bf_buffilled)
  457. {
  458. /* Need to grab some from buffer */
  459. count = nbytes;
  460. if ((bfp->bf_offset + count) > bfp->bf_buffilled)
  461. count = bfp->bf_buffilled - bfp->bf_offset;
  462. memcpy(buf, bfp->bf_buf + bfp->bf_offset, count);
  463. }
  464. if ((bfp->bf_offset + nbytes) > bfp->bf_buffilled)
  465. {
  466. /* Need to grab some from file */
  467. if (!bfp->bf_ondisk)
  468. {
  469. /* Oops, the file doesn't exist. EOF. */
  470. goto finished;
  471. }
  472. /* Catch a read() on an earlier failed write to disk */
  473. if (bfp->bf_disk_fd < 0)
  474. {
  475. errno = EIO;
  476. return -1;
  477. }
  478. if (lseek(bfp->bf_disk_fd,
  479.   bfp->bf_offset + count, SEEK_SET) < 0)
  480. {
  481. if ((errno == EINVAL) || (errno == ESPIPE))
  482. {
  483. /*
  484. **  stdio won't be expecting these
  485. **  errnos from read()! Change them
  486. **  into something it can understand.
  487. */
  488. errno = EIO;
  489. }
  490. return -1;
  491. }
  492. while (count < nbytes)
  493. {
  494. retval = read(bfp->bf_disk_fd,
  495.       buf + count,
  496.       nbytes - count);
  497. if (retval < 0)
  498. {
  499. /* errno is set implicitly by read() */
  500. return -1;
  501. }
  502. else if (retval == 0)
  503. goto finished;
  504. else
  505. count += retval;
  506. }
  507. }
  508. finished:
  509. bfp->bf_offset += count;
  510. return count;
  511. }
  512. /*
  513. **  _BFSEEK -- seek to a position in a buffered file
  514. **
  515. ** Parameters:
  516. ** cookie -- cookie of file to seek
  517. ** offset -- position to seek to
  518. ** whence -- how to seek
  519. **
  520. ** Returns:
  521. ** new file offset or -1 indicate failure
  522. **
  523. ** Side Effects:
  524. ** none.
  525. **
  526. */
  527. fpos_t
  528. _bfseek(cookie, offset, whence)
  529. void *cookie;
  530. fpos_t offset;
  531. int whence;
  532. {
  533. struct bf *bfp;
  534. /* Cast cookie back to correct type */
  535. bfp = (struct bf *)cookie;
  536. switch (whence)
  537. {
  538. case SEEK_SET:
  539. bfp->bf_offset = offset;
  540. break;
  541. case SEEK_CUR:
  542. bfp->bf_offset += offset;
  543. break;
  544. case SEEK_END:
  545. bfp->bf_offset = bfp->bf_size + offset;
  546. break;
  547. default:
  548. errno = EINVAL;
  549. return -1;
  550. }
  551. return bfp->bf_offset;
  552. }
  553. /*
  554. **  _BFWRITE -- write to a buffered file
  555. **
  556. ** Parameters:
  557. ** cookie -- cookie of file to write
  558. ** buf -- data buffer
  559. ** nbytes -- how many bytes to write
  560. **
  561. ** Returns:
  562. ** number of bytes written or -1 indicate failure
  563. **
  564. ** Side Effects:
  565. ** may create backing file if over memory limit for file.
  566. **
  567. */
  568. int
  569. _bfwrite(cookie, buf, nbytes)
  570. void *cookie;
  571. const char *buf;
  572. int nbytes;
  573. {
  574. struct bf *bfp;
  575. int count = 0; /* Number of bytes written so far */
  576. int retval;
  577. /* Cast cookie back to correct type */
  578. bfp = (struct bf *)cookie;
  579. /* If committed, go straight to disk */
  580. if (bfp->bf_committed)
  581. {
  582. if (lseek(bfp->bf_disk_fd, bfp->bf_offset, SEEK_SET) < 0)
  583. {
  584. if ((errno == EINVAL) || (errno == ESPIPE))
  585. {
  586. /*
  587. **  stdio won't be expecting these
  588. **  errnos from write()! Change them
  589. **  into something it can understand.
  590. */
  591. errno = EIO;
  592. }
  593. return -1;
  594. }
  595. count = write(bfp->bf_disk_fd, buf, nbytes);
  596. if (count < 0)
  597. {
  598. /* errno is set implicitly by write() */
  599. return -1;
  600. }
  601. goto finished;
  602. }
  603. if (bfp->bf_offset < bfp->bf_bufsize)
  604. {
  605. /* Need to put some in buffer */
  606. count = nbytes;
  607. if ((bfp->bf_offset + count) > bfp->bf_bufsize)
  608. count = bfp->bf_bufsize - bfp->bf_offset;
  609. memcpy(bfp->bf_buf + bfp->bf_offset, buf, count);
  610. if ((bfp->bf_offset + count) > bfp->bf_buffilled)
  611. bfp->bf_buffilled = bfp->bf_offset + count;
  612. }
  613. if ((bfp->bf_offset + nbytes) > bfp->bf_bufsize)
  614. {
  615. /* Need to put some in file */
  616. if (!bfp->bf_ondisk)
  617. {
  618. /* Oops, the file doesn't exist. */
  619. if (tTd(58, 8))
  620. dprintf("_bfwrite(%s): to diskn",
  621. bfp->bf_filename);
  622. retval = OPEN(bfp->bf_filename,
  623.       O_RDWR | O_CREAT | O_TRUNC,
  624.       bfp->bf_filemode, bfp->bf_flags);
  625. /* Couldn't create file: failure */
  626. if (retval < 0)
  627. {
  628. /*
  629. **  stdio may not be expecting these
  630. **  errnos from write()! Change to
  631. **  something which it can understand.
  632. **  Note that ENOSPC and EDQUOT are saved
  633. **  because they are actually valid for
  634. **  write().
  635. */
  636. if (!((errno == ENOSPC) || (errno == EDQUOT)))
  637. errno = EIO;
  638. return -1;
  639. }
  640. bfp->bf_disk_fd = retval;
  641. bfp->bf_ondisk = TRUE;
  642. }
  643. /* Catch a write() on an earlier failed write to disk */
  644. if (bfp->bf_ondisk && bfp->bf_disk_fd < 0)
  645. {
  646. errno = EIO;
  647. return -1;
  648. }
  649. if (lseek(bfp->bf_disk_fd,
  650.   bfp->bf_offset + count, SEEK_SET) < 0)
  651. {
  652. if ((errno == EINVAL) || (errno == ESPIPE))
  653. {
  654. /*
  655. **  stdio won't be expecting these
  656. **  errnos from write()! Change them into
  657. **  something which it can understand.
  658. */
  659. errno = EIO;
  660. }
  661. return -1;
  662. }
  663. while (count < nbytes)
  664. {
  665. retval = write(bfp->bf_disk_fd, buf + count,
  666.        nbytes - count);
  667. if (retval < 0)
  668. {
  669. /* errno is set implicitly by write() */
  670. return -1;
  671. }
  672. else
  673. count += retval;
  674. }
  675. }
  676. finished:
  677. bfp->bf_offset += count;
  678. if (bfp->bf_offset > bfp->bf_size)
  679. bfp->bf_size = bfp->bf_offset;
  680. return count;
  681. }