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