xref: /original-bsd/sys/ufs/ufs/ufs_readwrite.c (revision 9aff7250)
1 /*-
2  * Copyright (c) 1993 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)ufs_readwrite.c	8.5 (Berkeley) 01/11/94
8  */
9 
10 #ifdef LFS_READWRITE
11 #define	BLKSIZE(a, b, c)	blksize(a)
12 #define	FS			struct lfs
13 #define	I_FS			i_lfs
14 #define	READ			lfs_read
15 #define	READ_S			"lfs_read"
16 #define	WRITE			lfs_write
17 #define	WRITE_S			"lfs_write"
18 #define	fs_bsize		lfs_bsize
19 #define	fs_maxfilesize		lfs_maxfilesize
20 #else
21 #define	BLKSIZE(a, b, c)	blksize(a, b, c)
22 #define	FS			struct fs
23 #define	I_FS			i_fs
24 #define	READ			ffs_read
25 #define	READ_S			"ffs_read"
26 #define	WRITE			ffs_write
27 #define	WRITE_S			"ffs_write"
28 #endif
29 
30 /*
31  * Vnode op for reading.
32  */
33 /* ARGSUSED */
34 READ(ap)
35 	struct vop_read_args /* {
36 		struct vnode *a_vp;
37 		struct uio *a_uio;
38 		int a_ioflag;
39 		struct ucred *a_cred;
40 	} */ *ap;
41 {
42 	register struct vnode *vp;
43 	register struct inode *ip;
44 	register struct uio *uio;
45 	register FS *fs;
46 	struct buf *bp;
47 	daddr_t lbn, nextlbn;
48 	off_t bytesinfile;
49 	long size, xfersize, blkoffset;
50 	int nextsize, error;
51 	u_short mode;
52 
53 	vp = ap->a_vp;
54 	ip = VTOI(vp);
55 	mode = ip->i_mode;
56 	uio = ap->a_uio;
57 
58 #ifdef DIAGNOSTIC
59 	if (uio->uio_rw != UIO_READ)
60 		panic("%s: mode", READ_S);
61 
62 	if (vp->v_type == VLNK) {
63 		if ((int)ip->i_size < vp->v_mount->mnt_maxsymlinklen)
64 			panic("%s: short symlink", READ_S);
65 	} else if (vp->v_type != VREG && vp->v_type != VDIR)
66 		panic("%s: type %d", READ_S, vp->v_type);
67 #endif
68 	fs = ip->I_FS;
69 	if ((u_quad_t)uio->uio_offset > fs->fs_maxfilesize)
70 		return (EFBIG);
71 
72 	for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
73 		if ((bytesinfile = ip->i_size - uio->uio_offset) <= 0)
74 			break;
75 		lbn = lblkno(fs, uio->uio_offset);
76 		nextlbn = lbn + 1;
77 		size = BLKSIZE(fs, ip, lbn);
78 		blkoffset = blkoff(fs, uio->uio_offset);
79 		xfersize = fs->fs_bsize - blkoffset;
80 		if (uio->uio_resid < xfersize)
81 			xfersize = uio->uio_resid;
82 		if (bytesinfile < xfersize)
83 			xfersize = bytesinfile;
84 
85 #ifdef LFS_READWRITE
86 		(void)lfs_check(vp, lbn);
87 		error = cluster_read(vp, ip->i_size, lbn, size, NOCRED, &bp);
88 #else
89 		if (lblktosize(fs, nextlbn) > ip->i_size) {
90 			error = bread(vp, lbn, size, NOCRED, &bp);
91 		} else {
92 			if (doclusterread) {
93 				error = cluster_read(vp,
94 				    ip->i_size, lbn, size, NOCRED, &bp);
95 			} else if (lbn - 1 == vp->v_lastr) {
96 				nextsize = BLKSIZE(fs, ip, nextlbn);
97 				error = breadn(vp, lbn,
98 				    size, &nextlbn, &nextsize, 1, NOCRED, &bp);
99 			} else {
100 				error = bread(vp, lbn, size, NOCRED, &bp);
101 			}
102 		}
103 #endif
104 		if (error)
105 			break;
106 		vp->v_lastr = lbn;
107 
108 		/*
109 		 * We should only get non-zero b_resid when an I/O error
110 		 * has occurred, which should cause us to break above.
111 		 * However, if the short read did not cause an error,
112 		 * then we want to ensure that we do not uiomove bad
113 		 * or uninitialized data.
114 		 */
115 		size -= bp->b_resid;
116 		if (size < xfersize) {
117 			if (size == 0)
118 				break;
119 			xfersize = size;
120 		}
121 		if (error =
122 		    uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio))
123 			break;
124 
125 		if (S_ISREG(mode) && (xfersize + blkoffset == fs->fs_bsize ||
126 		    uio->uio_offset == ip->i_size))
127 			bp->b_flags |= B_AGE;
128 		brelse(bp);
129 	}
130 	if (bp != NULL)
131 		brelse(bp);
132 	ip->i_flag |= IN_ACCESS;
133 	return (error);
134 }
135 
136 /*
137  * Vnode op for writing.
138  */
139 WRITE(ap)
140 	struct vop_write_args /* {
141 		struct vnode *a_vp;
142 		struct uio *a_uio;
143 		int a_ioflag;
144 		struct ucred *a_cred;
145 	} */ *ap;
146 {
147 	register struct vnode *vp;
148 	register struct uio *uio;
149 	register struct inode *ip;
150 	register FS *fs;
151 	struct buf *bp;
152 	struct proc *p;
153 	daddr_t lbn;
154 	off_t osize;
155 	int blkoffset, error, flags, ioflag, resid, size, xfersize;
156 
157 	ioflag = ap->a_ioflag;
158 	uio = ap->a_uio;
159 	vp = ap->a_vp;
160 	ip = VTOI(vp);
161 
162 #ifdef DIAGNOSTIC
163 	if (uio->uio_rw != UIO_WRITE)
164 		panic("%s: mode", WRITE_S);
165 #endif
166 
167 	switch (vp->v_type) {
168 	case VREG:
169 		if (ioflag & IO_APPEND)
170 			uio->uio_offset = ip->i_size;
171 		if ((ip->i_flags & APPEND) && uio->uio_offset != ip->i_size)
172 			return (EPERM);
173 		/* FALLTHROUGH */
174 	case VLNK:
175 		break;
176 	case VDIR:
177 		if ((ioflag & IO_SYNC) == 0)
178 			panic("%s: nonsync dir write", WRITE_S);
179 		break;
180 	default:
181 		panic("%s: type", WRITE_S);
182 	}
183 
184 	fs = ip->I_FS;
185 	if (uio->uio_offset < 0 ||
186 	    (u_quad_t)uio->uio_offset + uio->uio_resid > fs->fs_maxfilesize)
187 		return (EFBIG);
188 	/*
189 	 * Maybe this should be above the vnode op call, but so long as
190 	 * file servers have no limits, I don't think it matters.
191 	 */
192 	p = uio->uio_procp;
193 	if (vp->v_type == VREG && p &&
194 	    uio->uio_offset + uio->uio_resid >
195 	    p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
196 		psignal(p, SIGXFSZ);
197 		return (EFBIG);
198 	}
199 
200 	resid = uio->uio_resid;
201 	osize = ip->i_size;
202 	flags = ioflag & IO_SYNC ? B_SYNC : 0;
203 
204 	for (error = 0; uio->uio_resid > 0;) {
205 		lbn = lblkno(fs, uio->uio_offset);
206 		blkoffset = blkoff(fs, uio->uio_offset);
207 		xfersize = fs->fs_bsize - blkoffset;
208 		if (uio->uio_resid < xfersize)
209 			xfersize = uio->uio_resid;
210 #ifdef LFS_READWRITE
211 		(void)lfs_check(vp, lbn);
212 		error = lfs_balloc(vp, xfersize, lbn, &bp);
213 #else
214 		if (fs->fs_bsize > xfersize)
215 			flags |= B_CLRBUF;
216 		else
217 			flags &= ~B_CLRBUF;
218 
219 		error = ffs_balloc(ip,
220 		    lbn, blkoffset + xfersize, ap->a_cred, &bp, flags);
221 #endif
222 		if (error)
223 			break;
224 		if (uio->uio_offset + xfersize > ip->i_size) {
225 			ip->i_size = uio->uio_offset + xfersize;
226 			vnode_pager_setsize(vp, (u_long)ip->i_size);
227 		}
228 		(void)vnode_pager_uncache(vp);
229 
230 		size = BLKSIZE(fs, ip, lbn) - bp->b_resid;
231 		if (size < xfersize)
232 			xfersize = size;
233 
234 		error =
235 		    uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio);
236 #ifdef LFS_READWRITE
237 		(void)VOP_BWRITE(bp);
238 #else
239 		if (ioflag & IO_SYNC)
240 			(void)bwrite(bp);
241 		else if (xfersize + blkoffset == fs->fs_bsize)
242 			if (doclusterwrite)
243 				cluster_write(bp, ip->i_size);
244 			else {
245 				bp->b_flags |= B_AGE;
246 				bawrite(bp);
247 			}
248 		else
249 			bdwrite(bp);
250 #endif
251 		if (error || xfersize == 0)
252 			break;
253 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
254 	}
255 	/*
256 	 * If we successfully wrote any data, and we are not the superuser
257 	 * we clear the setuid and setgid bits as a precaution against
258 	 * tampering.
259 	 */
260 	if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0)
261 		ip->i_mode &= ~(ISUID | ISGID);
262 	if (error) {
263 		if (ioflag & IO_UNIT) {
264 			(void)VOP_TRUNCATE(vp, osize,
265 			    ioflag & IO_SYNC, ap->a_cred, uio->uio_procp);
266 			uio->uio_offset -= resid - uio->uio_resid;
267 			uio->uio_resid = resid;
268 		}
269 	} else if (resid > uio->uio_resid && (ioflag & IO_SYNC))
270 		error = VOP_UPDATE(vp, &time, &time, 1);
271 	return (error);
272 }
273