xref: /titanic_44/usr/src/lib/libast/common/sfio/sfwr.c (revision 4a6ec905b96eb96a398c346f59e034a90ce8ad37)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *           Copyright (c) 1985-2007 AT&T Knowledge Ventures            *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                      by AT&T Knowledge Ventures                      *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                   Phong Vo <kpv@research.att.com>                    *
20 *                                                                      *
21 ***********************************************************************/
22 #include	"sfhdr.h"
23 
24 /*	Write with discipline.
25 **
26 **	Written by Kiem-Phong Vo.
27 */
28 
29 /* hole preserving writes */
30 #if __STD_C
31 static ssize_t sfoutput(Sfio_t* f, reg char* buf, reg size_t n)
32 #else
33 static ssize_t sfoutput(f,buf,n)
34 Sfio_t*		f;
35 reg char*	buf;
36 reg size_t	n;
37 #endif
38 {	reg char	*sp, *wbuf, *endbuf;
39 	reg ssize_t	s, w, wr;
40 
41 	s = w = 0;
42 	wbuf = buf;
43 	endbuf = buf+n;
44 	while(n > 0)
45 	{	if((ssize_t)n < _Sfpage) /* no hole possible */
46 		{	buf += n;
47 			s = n = 0;
48 		}
49 		else while((ssize_t)n >= _Sfpage)
50 		{	/* see if a hole of 0's starts here */
51 			sp = buf+1;
52 			if(buf[0] == 0 && buf[_Sfpage-1] == 0)
53 			{	/* check byte at a time until int-aligned */
54 				while(((ulong)sp)%sizeof(int))
55 				{	if(*sp != 0)
56 						goto chk_hole;
57 					sp += 1;
58 				}
59 
60 				/* check using int to speed up */
61 				while(sp < endbuf)
62 				{	if(*((int*)sp) != 0)
63 						goto chk_hole;
64 					sp += sizeof(int);
65 				}
66 
67 				/* check the remaining bytes */
68 				if(sp > endbuf)
69 				{	sp -= sizeof(int);
70 					while(sp < endbuf)
71 					{	if(*sp != 0)
72 							goto chk_hole;
73 						sp += 1;
74 					}
75 				}
76 			}
77 
78 		chk_hole:
79 			if((s = sp-buf) >= _Sfpage) /* found a hole */
80 				break;
81 
82 			/* skip a dirty page */
83 			n -= _Sfpage;
84 			buf += _Sfpage;
85 		}
86 
87 		/* write out current dirty pages */
88 		if(buf > wbuf)
89 		{	if((ssize_t)n < _Sfpage)
90 			{	buf = endbuf;
91 				n = s = 0;
92 			}
93 			if((wr = syswritef(f->file,wbuf,buf-wbuf)) > 0)
94 			{	w += wr;
95 				f->bits &= ~SF_HOLE;
96 			}
97 			if(wr != (buf-wbuf))
98 				break;
99 			wbuf = buf;
100 		}
101 
102 		/* seek to a rounded boundary within the hole */
103 		if(s >= _Sfpage)
104 		{	s = (s/_Sfpage)*_Sfpage;
105 			if(SFSK(f,(Sfoff_t)s,SEEK_CUR,NIL(Sfdisc_t*)) < 0)
106 				break;
107 			w += s;
108 			n -= s;
109 			wbuf = (buf += s);
110 			f->bits |= SF_HOLE;
111 
112 			if(n > 0)
113 			{	/* next page must be dirty */
114 				s = (ssize_t)n <= _Sfpage ? 1 : _Sfpage;
115 				buf += s;
116 				n -= s;
117 			}
118 		}
119 	}
120 
121 	return w > 0 ? w : -1;
122 }
123 
124 #if __STD_C
125 ssize_t sfwr(reg Sfio_t* f, reg const Void_t* buf, reg size_t n, reg Sfdisc_t* disc)
126 #else
127 ssize_t sfwr(f,buf,n,disc)
128 reg Sfio_t*	f;
129 reg Void_t*	buf;
130 reg size_t	n;
131 reg Sfdisc_t*	disc;
132 #endif
133 {
134 	reg ssize_t	w;
135 	reg Sfdisc_t*	dc;
136 	reg int		local, oerrno;
137 
138 	SFMTXSTART(f,(ssize_t)(-1));
139 
140 	GETLOCAL(f,local);
141 	if(!local && !(f->bits&SF_DCDOWN)) /* an external user's call */
142 	{	if(f->mode != SF_WRITE && _sfmode(f,SF_WRITE,0) < 0 )
143 			SFMTXRETURN(f, (ssize_t)(-1));
144 		if(f->next > f->data && SFSYNC(f) < 0 )
145 			SFMTXRETURN(f, (ssize_t)(-1));
146 	}
147 
148 	for(;;)
149 	{	/* stream locked by sfsetfd() */
150 		if(!(f->flags&SF_STRING) && f->file < 0)
151 			SFMTXRETURN(f,(ssize_t)0);
152 
153 		/* clear current error states */
154 		f->flags &= ~(SF_EOF|SF_ERROR);
155 
156 		dc = disc;
157 		if(f->flags&SF_STRING)	/* total required buffer */
158 			w = n + (f->next - f->data);
159 		else
160 		{	/* warn that a write is about to happen */
161 			SFDISC(f,dc,writef);
162 			if(dc && dc->exceptf && (f->flags&SF_IOCHECK) )
163 			{	reg int	rv;
164 				if(local)
165 					SETLOCAL(f);
166 				if((rv = _sfexcept(f,SF_WRITE,n,dc)) > 0)
167 					n = rv;
168 				else if(rv < 0)
169 				{	f->flags |= SF_ERROR;
170 					SFMTXRETURN(f, rv);
171 				}
172 			}
173 
174 			if(f->extent >= 0)
175 			{	/* make sure we are at the right place to write */
176 				if(f->flags&SF_APPENDWR)
177 				{	if(f->here != f->extent || (f->flags&SF_SHARE))
178 					{	f->here = SFSK(f,(Sfoff_t)0,SEEK_END,dc);
179 						f->extent = f->here;
180 					}
181 				}
182 				else if((f->flags&SF_SHARE) && !(f->flags&SF_PUBLIC))
183 					f->here = SFSK(f,f->here,SEEK_SET,dc);
184 			}
185 
186 			oerrno = errno;
187 			errno = 0;
188 
189 			if(dc && dc->writef)
190 			{	SFDCWR(f,buf,n,dc,w);
191 			}
192 			else if(SFISNULL(f))
193 				w = n;
194 			else if(f->flags&SF_WHOLE)
195 				goto do_write;
196 			else if((ssize_t)n >= _Sfpage &&
197 				!(f->flags&(SF_SHARE|SF_APPENDWR)) &&
198 				f->here == f->extent && (f->here%_Sfpage) == 0)
199 			{	if((w = sfoutput(f,(char*)buf,n)) <= 0)
200 					goto do_write;
201 			}
202 			else
203 			{
204 			do_write:
205 				if((w = syswritef(f->file,buf,n)) > 0)
206 					f->bits &= ~SF_HOLE;
207 			}
208 
209 			if(errno == 0)
210 				errno = oerrno;
211 
212 			if(w > 0)
213 			{	if(!(f->bits&SF_DCDOWN) )
214 				{	if((f->flags&(SF_APPENDWR|SF_PUBLIC)) && f->extent >= 0 )
215 						f->here = SFSK(f,(Sfoff_t)0,SEEK_CUR,dc);
216 					else	f->here += w;
217 					if(f->extent >= 0 && f->here > f->extent)
218 						f->extent = f->here;
219 				}
220 
221 				SFMTXRETURN(f, (ssize_t)w);
222 			}
223 		}
224 
225 		if(local)
226 			SETLOCAL(f);
227 		switch(_sfexcept(f,SF_WRITE,w,dc))
228 		{
229 		case SF_ECONT :
230 			goto do_continue;
231 		case SF_EDONE :
232 			w = local ? 0 : w;
233 			SFMTXRETURN(f, (ssize_t)w);
234 		case SF_EDISC :
235 			if(!local && !(f->flags&SF_STRING))
236 				goto do_continue;
237 			/* else fall thru */
238 		case SF_ESTACK :
239 			SFMTXRETURN(f, (ssize_t)(-1));
240 		}
241 
242 	do_continue:
243 		for(dc = f->disc; dc; dc = dc->disc)
244 			if(dc == disc)
245 				break;
246 		disc = dc;
247 	}
248 }
249