xref: /titanic_50/usr/src/lib/libast/common/sfio/sfwr.c (revision b3700b074e637f8c6991b70754c88a2cfffb246b)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
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, char* buf, size_t n)
32 #else
33 static ssize_t sfoutput(f,buf,n)
34 Sfio_t*		f;
35 char*		buf;
36 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(Sfio_t* f, const Void_t* buf, size_t n, Sfdisc_t* disc)
126 #else
127 ssize_t sfwr(f,buf,n,disc)
128 Sfio_t*		f;
129 Void_t*		buf;
130 size_t		n;
131 Sfdisc_t*	disc;
132 #endif
133 {
134 	reg ssize_t	w;
135 	reg Sfdisc_t*	dc;
136 	reg int		local, oerrno;
137 	SFMTXDECL(f);
138 
139 	SFMTXENTER(f,(ssize_t)(-1));
140 
141 	GETLOCAL(f,local);
142 	if(!local && !(f->bits&SF_DCDOWN)) /* an external user's call */
143 	{	if(f->mode != SF_WRITE && _sfmode(f,SF_WRITE,0) < 0 )
144 			SFMTXRETURN(f, (ssize_t)(-1));
145 		if(f->next > f->data && SFSYNC(f) < 0 )
146 			SFMTXRETURN(f, (ssize_t)(-1));
147 	}
148 
149 	for(;;)
150 	{	/* stream locked by sfsetfd() */
151 		if(!(f->flags&SF_STRING) && f->file < 0)
152 			SFMTXRETURN(f,(ssize_t)0);
153 
154 		/* clear current error states */
155 		f->flags &= ~(SF_EOF|SF_ERROR);
156 
157 		dc = disc;
158 		if(f->flags&SF_STRING)	/* total required buffer */
159 			w = n + (f->next - f->data);
160 		else
161 		{	/* warn that a write is about to happen */
162 			SFDISC(f,dc,writef);
163 			if(dc && dc->exceptf && (f->flags&SF_IOCHECK) )
164 			{	reg int	rv;
165 				if(local)
166 					SETLOCAL(f);
167 				if((rv = _sfexcept(f,SF_WRITE,n,dc)) > 0)
168 					n = rv;
169 				else if(rv < 0)
170 				{	f->flags |= SF_ERROR;
171 					SFMTXRETURN(f, rv);
172 				}
173 			}
174 
175 			if(f->extent >= 0)
176 			{	/* make sure we are at the right place to write */
177 				if(f->flags&SF_APPENDWR)
178 				{	if(f->here != f->extent || (f->flags&SF_SHARE))
179 					{	f->here = SFSK(f,(Sfoff_t)0,SEEK_END,dc);
180 						f->extent = f->here;
181 					}
182 				}
183 				else if((f->flags&SF_SHARE) && !(f->flags&SF_PUBLIC))
184 					f->here = SFSK(f,f->here,SEEK_SET,dc);
185 			}
186 
187 			oerrno = errno;
188 			errno = 0;
189 
190 			if(dc && dc->writef)
191 			{	SFDCWR(f,buf,n,dc,w);
192 			}
193 			else if(SFISNULL(f))
194 				w = n;
195 			else if(f->flags&SF_WHOLE)
196 				goto do_write;
197 			else if((ssize_t)n >= _Sfpage &&
198 				!(f->flags&(SF_SHARE|SF_APPENDWR)) &&
199 				f->here == f->extent && (f->here%_Sfpage) == 0)
200 			{	if((w = sfoutput(f,(char*)buf,n)) <= 0)
201 					goto do_write;
202 			}
203 			else
204 			{
205 			do_write:
206 				if((w = syswritef(f->file,buf,n)) > 0)
207 					f->bits &= ~SF_HOLE;
208 			}
209 
210 			if(errno == 0)
211 				errno = oerrno;
212 
213 			if(w > 0)
214 			{	if(!(f->bits&SF_DCDOWN) )
215 				{	if((f->flags&(SF_APPENDWR|SF_PUBLIC)) && f->extent >= 0 )
216 						f->here = SFSK(f,(Sfoff_t)0,SEEK_CUR,dc);
217 					else	f->here += w;
218 					if(f->extent >= 0 && f->here > f->extent)
219 						f->extent = f->here;
220 				}
221 
222 				SFMTXRETURN(f, (ssize_t)w);
223 			}
224 		}
225 
226 		if(local)
227 			SETLOCAL(f);
228 		switch(_sfexcept(f,SF_WRITE,w,dc))
229 		{
230 		case SF_ECONT :
231 			goto do_continue;
232 		case SF_EDONE :
233 			w = local ? 0 : w;
234 			SFMTXRETURN(f, (ssize_t)w);
235 		case SF_EDISC :
236 			if(!local && !(f->flags&SF_STRING))
237 				goto do_continue;
238 			/* else fall thru */
239 		case SF_ESTACK :
240 			SFMTXRETURN(f, (ssize_t)(-1));
241 		}
242 
243 	do_continue:
244 		for(dc = f->disc; dc; dc = dc->disc)
245 			if(dc == disc)
246 				break;
247 		disc = dc;
248 	}
249 }
250