fclose.c revision 266692
1/* 2 * Copyright (c) 2000-2002, 2004 Proofpoint, Inc. and its suppliers. 3 * All rights reserved. 4 * Copyright (c) 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Chris Torek. 9 * 10 * By using this file, you agree to the terms and conditions set 11 * forth in the LICENSE file which can be found at the top level of 12 * the sendmail distribution. 13 */ 14 15#include <sm/gen.h> 16SM_RCSID("@(#)$Id: fclose.c,v 1.45 2013-11-22 20:51:42 ca Exp $") 17#include <errno.h> 18#include <stdlib.h> 19#include <sm/time.h> 20#include <setjmp.h> 21#include <sm/io.h> 22#include <sm/assert.h> 23#include <sm/heap.h> 24#include <sm/signal.h> 25#include <sm/conf.h> 26#include <sm/clock.h> 27#include "local.h" 28 29static void closealrm __P((int)); 30static jmp_buf CloseTimeOut; 31 32/* 33** CLOSEALRM -- handler when timeout activated for sm_io_close() 34** 35** Returns flow of control to where setjmp(CloseTimeOut) was set. 36** 37** Parameters: 38** sig -- unused 39** 40** Returns: 41** does not return 42** 43** Side Effects: 44** returns flow of control to setjmp(CloseTimeOut). 45** 46** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 47** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 48** DOING. 49*/ 50 51/* ARGSUSED0 */ 52static void 53closealrm(sig) 54 int sig; 55{ 56 longjmp(CloseTimeOut, 1); 57} 58 59/* 60** SM_IO_CLOSE -- close a file handle/pointer 61** 62** Parameters: 63** fp -- file pointer to be closed 64** timeout -- maximum time allowed to perform the close (millisecs) 65** 66** Returns: 67** 0 on success 68** -1 on failure and sets errno 69** 70** Side Effects: 71** file pointer 'fp' will no longer be valid. 72*/ 73 74int 75sm_io_close(fp, timeout) 76 register SM_FILE_T *fp; 77 int SM_NONVOLATILE timeout; 78{ 79 register int SM_NONVOLATILE r; 80 SM_EVENT *evt = NULL; 81 82 if (fp == NULL) 83 { 84 errno = EBADF; 85 return SM_IO_EOF; 86 } 87 88 SM_REQUIRE_ISA(fp, SmFileMagic); 89 90 /* XXX this won't be reached if above macro is active */ 91 if (fp->sm_magic == NULL) 92 { 93 /* not open! */ 94 errno = EBADF; 95 return SM_IO_EOF; 96 } 97 if (fp->f_close == NULL) 98 { 99 /* no close function! */ 100 errno = ENODEV; 101 return SM_IO_EOF; 102 } 103 if (fp->f_dup_cnt > 0) 104 { 105 /* decrement file pointer open count */ 106 fp->f_dup_cnt--; 107 return 0; 108 } 109 110 /* Okay, this is where we set the timeout. */ 111 if (timeout == SM_TIME_DEFAULT) 112 timeout = fp->f_timeout; 113 if (timeout == SM_TIME_IMMEDIATE) 114 { 115 errno = EAGAIN; 116 return -1; 117 } 118 119 /* No more duplicates of file pointer. Flush buffer and close */ 120 r = fp->f_flags & SMWR ? sm_flush(fp, (int *) &timeout) : 0; 121 122 /* sm_flush() has updated to.it_value for the time it's used */ 123 if (timeout != SM_TIME_FOREVER) 124 { 125 if (setjmp(CloseTimeOut) != 0) 126 { 127 errno = EAGAIN; 128 return SM_IO_EOF; 129 } 130 evt = sm_seteventm(timeout, closealrm, 0); 131 } 132 if ((*fp->f_close)(fp) < 0) 133 r = SM_IO_EOF; 134 135 /* We're back. So undo our timeout and handler */ 136 if (evt != NULL) 137 sm_clrevent(evt); 138 if (fp->f_flags & SMMBF) 139 { 140 sm_free((char *)fp->f_bf.smb_base); 141 fp->f_bf.smb_base = NULL; 142 } 143 if (HASUB(fp)) 144 FREEUB(fp); 145 fp->f_flags = 0; /* clear flags */ 146 fp->sm_magic = NULL; /* Release this SM_FILE_T for reuse. */ 147 fp->f_r = fp->f_w = 0; /* Mess up if reaccessed. */ 148 return r; 149} 150