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

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_portable.c,v 8.23 1999/10/11 23:37:26 ca Exp $";
  14. #endif /* ! lint */
  15. #include <unistd.h>
  16. #include <fcntl.h>
  17. #include <sys/types.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <sys/uio.h>
  21. #include <errno.h>
  22. # include <stdio.h>
  23. #ifndef BF_STANDALONE
  24. # include "sendmail.h"
  25. #endif /* ! BF_STANDALONE */
  26. #include "bf_portable.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. /* List of currently-open buffered files */
  57. struct bf *bflist = NULL;
  58. FILE *
  59. bfopen(filename, fmode, bsize, flags)
  60. char *filename;
  61. int fmode;
  62. size_t bsize;
  63. long flags;
  64. {
  65. struct bf *bfp;
  66. FILE *retval;
  67. int fd, l;
  68. fd = OPEN(filename, O_RDWR | O_CREAT | O_TRUNC, fmode, flags);
  69. if (fd == -1)
  70. {
  71. /* errno is set implicitly by open */
  72. return NULL;
  73. }
  74. retval = fdopen(fd, "w+");
  75. /* If failure, return immediately */
  76. if (retval == NULL)
  77. {
  78. /* errno is set implicitly by fdopen */
  79. return NULL;
  80. }
  81. /* Allocate memory */
  82. bfp = (struct bf *)malloc(sizeof(struct bf));
  83. if (bfp == NULL)
  84. {
  85. (void) fclose(retval);
  86. /* don't care about errors */
  87. (void) unlink(filename);
  88. errno = ENOMEM;
  89. return NULL;
  90. }
  91. if (tTd(58, 8))
  92. dprintf("bfopen(%s): malloced %ldn",
  93. filename, (long) sizeof(struct bf));
  94. l = strlen(filename) + 1;
  95. bfp->bf_filename = (char *)malloc(l);
  96. if (bfp->bf_filename == NULL)
  97. {
  98. free(bfp);
  99. (void) fclose(retval);
  100. /* don't care about errors */
  101. (void) unlink(filename);
  102. errno = ENOMEM;
  103. return NULL;
  104. }
  105. (void) strlcpy(bfp->bf_filename, filename, l);
  106. /* Fill in the other fields, then add it to the list */
  107. bfp->bf_key = retval;
  108. bfp->bf_committed = 0;
  109. bfp->bf_refcount = 1;
  110. bfinsert(bfp);
  111. /* Whew. Nothing bad happened. We're okay. */
  112. return retval;
  113. }
  114. /*
  115. **  BFDUP -- increase refcount on buffered file
  116. **
  117. ** Parameters:
  118. ** fp -- FILE * to "duplicate"
  119. **
  120. ** Returns:
  121. ** fp with increased refcount
  122. */
  123. FILE *
  124. bfdup(fp)
  125. FILE *fp;
  126. {
  127. struct bf *bfp;
  128. /* Get associated bf structure */
  129. bfp = bflookup(fp);
  130. if (bfp == NULL)
  131. return NULL;
  132. /* Increase the refcount */
  133. bfp->bf_refcount++;
  134. return fp;
  135. }
  136. /*
  137. **  BFCOMMIT -- "commits" the buffered file
  138. **
  139. ** Parameters:
  140. ** fp -- FILE * to commit to disk
  141. **
  142. ** Returns:
  143. ** 0 on success, -1 on error
  144. **
  145. ** Side Effects:
  146. ** Forces the given FILE * to be written to disk if it is not
  147. ** already, and ensures that it will be kept after closing. If
  148. ** fp is not a buffered file, this is a no-op.
  149. **
  150. ** Sets errno:
  151. ** any value of errno specified by open()
  152. ** any value of errno specified by write()
  153. ** any value of errno specified by lseek()
  154. */
  155. int
  156. bfcommit(fp)
  157. FILE *fp;
  158. {
  159. struct bf *bfp;
  160. /* Get associated bf structure */
  161. bfp = bflookup(fp);
  162. /* If called on a normal FILE *, noop */
  163. if (bfp != NULL)
  164. bfp->bf_committed = TRUE;
  165. return 0;
  166. }
  167. /*
  168. **  BFREWIND -- rewinds the FILE *
  169. **
  170. ** Parameters:
  171. ** fp -- FILE * to rewind
  172. **
  173. ** Returns:
  174. ** 0 on success, -1 on error
  175. **
  176. ** Side Effects:
  177. ** rewinds the FILE * and puts it into read mode. Normally one
  178. ** would bfopen() a file, write to it, then bfrewind() and
  179. ** fread(). If fp is not a buffered file, this is equivalent to
  180. ** rewind().
  181. **
  182. ** Sets errno:
  183. ** any value of errno specified by fseek()
  184. */
  185. int
  186. bfrewind(fp)
  187. FILE *fp;
  188. {
  189. int err;
  190. /* check to see if there is an error on the stream */
  191. err = ferror(fp);
  192. (void) fflush(fp);
  193. /*
  194. **  Clear error if tried to fflush()
  195. **  a read-only file pointer and
  196. **  there wasn't a previous error.
  197. */
  198. if (err == 0)
  199. clearerr(fp);
  200. /* errno is set implicitly by fseek() before return */
  201. return fseek(fp, 0, SEEK_SET);
  202. }
  203. /*
  204. **  BFTRUNCATE -- rewinds and truncates the FILE *
  205. **
  206. ** Parameters:
  207. ** fp -- FILE * to truncate
  208. **
  209. ** Returns:
  210. ** 0 on success, -1 on error
  211. **
  212. ** Side Effects:
  213. ** rewinds the FILE *, truncates it to zero length, and puts it
  214. ** into write mode. If fp is not a buffered file, this is
  215. ** equivalent to a rewind() and then an ftruncate(fileno(fp), 0).
  216. **
  217. ** Sets errno:
  218. ** any value of errno specified by fseek()
  219. ** any value of errno specified by ftruncate()
  220. */
  221. int
  222. bftruncate(fp)
  223. FILE *fp;
  224. {
  225. int ret;
  226. if (bfrewind(fp) == -1)
  227. {
  228. /* errno is set implicitly by bfrewind() */
  229. return -1;
  230. }
  231. #if NOFTRUNCATE
  232. /* XXX */
  233. errno = EINVAL;
  234. ret = -1;
  235. #else /* NOFTRUNCATE */
  236. /* errno is set implicitly by ftruncate() before return */
  237. ret = ftruncate(fileno(fp), 0);
  238. #endif /* NOFTRUNCATE */
  239. return ret;
  240. }
  241. /*
  242. **  BFCLOSE -- close a buffered file
  243. **
  244. ** Parameters:
  245. ** fp -- FILE * to close
  246. **
  247. ** Returns:
  248. ** 0 on success, EOF on failure
  249. **
  250. ** Side Effects:
  251. ** Closes fp. If fp is a buffered file, unlink it if it has not
  252. ** already been committed. If fp is not a buffered file, this is
  253. ** equivalent to fclose().
  254. **
  255. ** Sets errno:
  256. ** any value of errno specified by fclose()
  257. */
  258. int
  259. bfclose(fp)
  260. FILE *fp;
  261. {
  262. int retval;
  263. struct bf *bfp = NULL;
  264. /* Get associated bf structure */
  265. bfp = bflookup(fp);
  266. /* Decrement and check refcount */
  267. if (bfp != NULL && --bfp->bf_refcount > 0)
  268. return 0;
  269. /* If bf, get bf structure and remove from list */
  270. if (bfp != NULL)
  271. bfp = bfdelete(fp);
  272. if (fclose(fp) == EOF)
  273. {
  274. if (tTd(58, 8))
  275. dprintf("bfclose: fclose failedn");
  276. /* errno is set implicitly by fclose() */
  277. return -1;
  278. }
  279. if (bfp == NULL)
  280. return 0;
  281. /* Success unless we determine otherwise in next block */
  282. retval = 0;
  283. if (bfp != NULL)
  284. {
  285. /* Might have to unlink; certainly will have to deallocate */
  286. if (!bfp->bf_committed)
  287. retval = unlink(bfp->bf_filename);
  288. free(bfp->bf_filename);
  289. free(bfp);
  290. if (tTd(58, 8))
  291. dprintf("bfclose: freed %ldn",
  292. (long) sizeof(struct bf));
  293. }
  294. else
  295. {
  296. if (tTd(58, 8))
  297. dprintf("bfclose: bfp was NULLn");
  298. }
  299. return retval;
  300. }
  301. /*
  302. **  BFTEST -- test if a FILE * is a buffered file
  303. **
  304. ** Parameters:
  305. ** fp -- FILE * to test
  306. **
  307. ** Returns:
  308. ** TRUE if fp is a buffered file, FALSE otherwise.
  309. **
  310. ** Side Effects:
  311. ** none.
  312. **
  313. ** Sets errno:
  314. ** never.
  315. */
  316. bool
  317. bftest(fp)
  318. FILE *fp;
  319. {
  320. return (bflookup(fp) != NULL);
  321. }
  322. /*
  323. **  BFINSERT -- insert item in linking list
  324. **
  325. ** Parameters:
  326. ** datum -- item to insert
  327. **
  328. ** Returns:
  329. ** none.
  330. **
  331. ** Side Effects:
  332. ** none.
  333. **
  334. ** Sets errno:
  335. ** never.
  336. */
  337. void
  338. bfinsert(datum)
  339. struct bf *datum;
  340. {
  341. datum->bf_cdr = bflist;
  342. bflist = datum;
  343. }
  344. /*
  345. **  BFLOOKUP -- lookup FILE * in list
  346. **
  347. ** Parameters:
  348. ** fp -- FILE * to lookup
  349. **
  350. ** Returns:
  351. ** bf struct for the FILE *, NULL if not found
  352. **
  353. ** Side Effects:
  354. ** none.
  355. **
  356. ** Sets errno:
  357. ** never.
  358. */
  359. struct bf *
  360. bflookup(key)
  361. FILE *key;
  362. {
  363. struct bf *t;
  364. for (t = bflist; t != NULL; t = t->bf_cdr)
  365. {
  366. if (t->bf_key == key)
  367. {
  368. return t;
  369. }
  370. }
  371. /* If we got this far, we didn't find it */
  372. return NULL;
  373. }
  374. /*
  375. **  BFDELETE -- delete a FILE * in list
  376. **
  377. ** Parameters:
  378. ** fp -- FILE * to delete
  379. **
  380. ** Returns:
  381. ** bf struct for deleted FILE *, NULL if not found,
  382. **
  383. ** Side Effects:
  384. ** none.
  385. **
  386. ** Sets errno:
  387. ** never.
  388. */
  389. struct bf *
  390. bfdelete(key)
  391. FILE *key;
  392. {
  393. struct bf *t, *u;
  394. if (bflist == NULL)
  395. return NULL;
  396. /* if first element, special case */
  397. if (bflist->bf_key == key)
  398. {
  399. u = bflist;
  400. bflist = bflist->bf_cdr;
  401. return u;
  402. }
  403. for (t = bflist; t->bf_cdr != NULL; t = t->bf_cdr)
  404. {
  405. if (t->bf_cdr->bf_key == key)
  406. {
  407. u = t->bf_cdr;
  408. t->bf_cdr = u->bf_cdr;
  409. return u;
  410. }
  411. }
  412. /* If we got this far, we didn't find it */
  413. return NULL;
  414. }