xref: /titanic_50/usr/src/lib/libast/common/sfio/sfwrite.c (revision ff3124eff995e6cd8ebd8c6543648e0670920034)
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 data out to the file system
25 **
26 **	Written by Kiem-Phong Vo.
27 */
28 
29 #if __STD_C
30 ssize_t sfwrite(reg Sfio_t* f, const Void_t* buf, reg size_t n)
31 #else
32 ssize_t sfwrite(f,buf,n)
33 reg Sfio_t*	f;	/* write to this stream. 	*/
34 Void_t*		buf;	/* buffer to be written.	*/
35 reg size_t	n;	/* number of bytes. 		*/
36 #endif
37 {
38 	reg uchar	*s, *begs, *next;
39 	reg ssize_t	w;
40 	reg int		local;
41 
42 	SFMTXSTART(f, (ssize_t)(-1));
43 
44 	GETLOCAL(f,local);
45 
46 	if(!buf)
47 		SFMTXRETURN(f, (ssize_t)(n == 0 ? 0 : -1) );
48 
49 	/* release peek lock */
50 	if(f->mode&SF_PEEK)
51 	{	if(!(f->mode&SF_WRITE) && (f->flags&SF_RDWR) != SF_RDWR)
52 			SFMTXRETURN(f, (ssize_t)(-1));
53 
54 		if((uchar*)buf != f->next &&
55 		   (!f->rsrv || f->rsrv->data != (uchar*)buf) )
56 			SFMTXRETURN(f, (ssize_t)(-1));
57 
58 		f->mode &= ~SF_PEEK;
59 
60 		if(f->mode&SF_PKRD)
61 		{	/* read past peeked data */
62 			char		buf[16];
63 			reg ssize_t	r;
64 
65 			for(w = n; w > 0; )
66 			{	if((r = w) > sizeof(buf))
67 					r = sizeof(buf);
68 				if((r = sysreadf(f->file,buf,r)) <= 0)
69 				{	n -= w;
70 					break;
71 				}
72 				else	w -= r;
73 			}
74 
75 			f->mode &= ~SF_PKRD;
76 			f->endb = f->data + n;
77 			f->here += n;
78 		}
79 
80 		if((f->mode&SF_READ) && f->proc)
81 			f->next += n;
82 	}
83 
84 	s = begs = (uchar*)buf;
85 	for(;; f->mode &= ~SF_LOCK)
86 	{	/* check stream mode */
87 		if(SFMODE(f,local) != SF_WRITE && _sfmode(f,SF_WRITE,local) < 0 )
88 		{	w = s > begs ? s-begs : -1;
89 			SFMTXRETURN(f,w);
90 		}
91 
92 		SFLOCK(f,local);
93 
94 		w = f->endb - f->next;
95 
96 		if(s == f->next) /* after sfreserve */
97 		{	if(w > (ssize_t)n)
98 				w = (ssize_t)n;
99 			f->next = (s += w);
100 			n -= w;
101 			break;
102 		}
103 
104 		/* attempt to create space in buffer */
105 		if(w == 0 || ((f->flags&SF_WHOLE) && w < (ssize_t)n) )
106 		{	if(f->flags&SF_STRING) /* extend buffer */
107 			{	(void)SFWR(f, s, n-w, f->disc);
108 				if((w = f->endb - f->next) < (ssize_t)n)
109 				{	if(!(f->flags&SF_STRING)) /* maybe sftmp */
110 					{	if(f->next > f->data)
111 							goto fls_buf;
112 					}
113 					else if(w == 0)
114 						break;
115 				}
116 			}
117 			else if(f->next > f->data)
118 			{ fls_buf:
119 				(void)SFFLSBUF(f, -1);
120 				if((w = f->endb - f->next) < (ssize_t)n &&
121 				   (f->flags&SF_WHOLE) && f->next > f->data )
122 						break;
123 			}
124 		}
125 
126 		if(!(f->flags&SF_STRING) && f->next == f->data &&
127 		   (((f->flags&SF_WHOLE) && w <= n) || SFDIRECT(f,n)) )
128 		{	/* bypass buffering */
129 			if((w = SFWR(f,s,n,f->disc)) <= 0 )
130 				break;
131 		}
132 		else
133 		{	if(w > (ssize_t)n)
134 				w = (ssize_t)n;
135 			if(w <= 0) /* no forward progress possible */
136 				break;
137 			memcpy(f->next, s, w);
138 			f->next += w;
139 		}
140 
141 		s += w;
142 		if((n -= w) <= 0)
143 			break;
144 	}
145 
146 	/* always flush buffer for share streams */
147 	if(f->extent < 0 && (f->flags&SF_SHARE) && !(f->flags&SF_PUBLIC) )
148 		(void)SFFLSBUF(f,-1);
149 
150 	/* check to see if buffer should be flushed */
151 	else if(n == 0 && (f->flags&SF_LINE) && !(f->flags&SF_STRING))
152 	{	if((ssize_t)(n = f->next-f->data) > (w = s-begs))
153 			n = w;
154 		if(n > 0 && n < HIFORLINE)
155 		{	for(next = f->next-1; n > 0; --n, --next)
156 			{	if(*next == '\n')
157 				{	n = HIFORLINE;
158 					break;
159 				}
160 			}
161 		}
162 		if(n >= HIFORLINE)
163 			(void)SFFLSBUF(f,-1);
164 	}
165 
166 	SFOPEN(f,local);
167 
168 	w = s-begs;
169 	SFMTXRETURN(f,w);
170 }
171