xref: /386bsd/usr/src/kernel/isofs/isofs_vnops.c (revision a2142627)
1 /*
2  *	$Id: $
3  */
4 #include "sys/param.h"
5 #include "systm.h"
6 #include "kernel.h"
7 #include "sys/file.h"
8 #include "sys/stat.h"
9 #include "sys/errno.h"
10 #include "buf.h"
11 #include "proc.h"
12 #include "resourcevar.h"
13 #include "sys/mount.h"
14 #include "uio.h"
15 #include "namei.h"
16 #include "vnode.h"
17 #include "specdev.h"
18 #include "fifo.h"
19 #include "malloc.h"
20 #include "sys/dir.h"
21 #include "prototypes.h"
22 
23 #include "iso.h"
24 #include "isofs_node.h"
25 #include "iso_rrip.h"
26 
27 /*
28  * Open called.
29  *
30  * Nothing to do.
31  */
32 /* ARGSUSED */
33 isofs_open(vp, mode, cred, p)
34 	struct vnode *vp;
35 	int mode;
36 	struct ucred *cred;
37 	struct proc *p;
38 {
39 	return (0);
40 }
41 
42 /*
43  * Close called
44  *
45  * Update the times on the inode on writeable file systems.
46  */
47 /* ARGSUSED */
48 isofs_close(vp, fflag, cred, p)
49 	struct vnode *vp;
50 	int fflag;
51 	struct ucred *cred;
52 	struct proc *p;
53 {
54 	return (0);
55 }
56 
57 /*
58  * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
59  * The mode is shifted to select the owner/group/other fields. The
60  * super user is granted all permissions.
61  */
62 isofs_access(vp, mode, cred, p)
63 	struct vnode *vp;
64 	register int mode;
65 	struct ucred *cred;
66 	struct proc *p;
67 {
68 	return (0);
69 }
70 
71 /* ARGSUSED */
72 isofs_getattr(vp, vap, cred, p)
73 	struct vnode *vp;
74 	register struct vattr *vap;
75 	struct ucred *cred;
76 	struct proc *p;
77 {
78 	register struct iso_node *ip = VTOI(vp);
79 	int i;
80 
81 	vap->va_fsid = ip->i_dev;
82 	vap->va_fileid = ip->i_number;
83 	/*if (vp->v_type == VDIR)
84 		vap->va_nlink = 2;
85 	else
86 		vap->va_nlink = 1; */
87 
88 	vap->va_nlink = ip->inode.iso_links;
89 	vap->va_mode = ip->inode.iso_mode;
90 /*printf("getattr mode %x ", vap->va_mode);*/
91 	vap->va_uid  = ip->inode.iso_uid;
92 	vap->va_gid  = ip->inode.iso_gid;
93 	vap->va_atime= ip->inode.iso_atime;
94 	vap->va_mtime= ip->inode.iso_mtime;
95 	vap->va_ctime= ip->inode.iso_ctime;
96 
97 	vap->va_rdev = ip->inode.iso_dev;
98 	vap->va_size = ip->i_size;
99 	vap->va_size_rsv = 0;
100 	vap->va_flags = 0;
101 	vap->va_gen = 1;
102 	vap->va_blocksize = ip->i_mnt->logical_block_size;
103 	vap->va_bytes = ip->i_size;
104 	vap->va_bytes_rsv = 0;
105 	vap->va_type = vp->v_type;
106 	return (0);
107 }
108 
109 /*
110  * Vnode op for reading.
111  */
112 /* ARGSUSED */
113 isofs_read(vp, uio, ioflag, cred)
114 	struct vnode *vp;
115 	register struct uio *uio;
116 	int ioflag;
117 	struct ucred *cred;
118 {
119 	register struct iso_node *ip = VTOI(vp);
120 	register struct iso_mnt *imp;
121 	struct buf *bp;
122 	daddr_t lbn, bn, rablock;
123 	int size, diff, error = 0;
124 	long n, on, type;
125 
126 #ifdef DIAGNOSTICx
127 	if (uio->uio_rw != UIO_READ)
128 		panic("isofs_read mode");
129 	type = ip->i_mode & IFMT;
130 	if (type != IFDIR && type != IFREG && type != IFLNK)
131 		panic("isofs_read type");
132 #endif
133 	if (uio->uio_resid == 0)
134 		return (0);
135 	if (uio->uio_offset < 0)
136 		return (EINVAL);
137 	ip->i_flag |= IACC;
138 	imp = ip->i_mnt;
139 	do {
140 		lbn = iso_lblkno(imp, uio->uio_offset);
141 		on = iso_blkoff(imp, uio->uio_offset);
142 		n = min((unsigned)(imp->im_bsize - on), uio->uio_resid);
143 		diff = ip->i_size - uio->uio_offset;
144 		if (diff <= 0)
145 			return (0);
146 		if (diff < n)
147 			n = diff;
148 		size = iso_blksize(imp, ip, lbn);
149 		rablock = lbn + 1;
150 		if (vp->v_lastr + 1 == lbn &&
151 		    iso_lblktosize(imp, rablock) < ip->i_size)
152 			error = breada(ITOV(ip), lbn, size, rablock,
153 				iso_blksize(imp, ip, rablock), NOCRED, &bp);
154 		else
155 			error = bread(ITOV(ip), lbn, size, NOCRED, &bp);
156 		vp->v_lastr = lbn;
157 		n = min(n, size - bp->b_resid);
158 		if (error) {
159 			brelse(bp);
160 			return (error);
161 		}
162 
163 		error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
164 		if (n + on == imp->im_bsize || uio->uio_offset == ip->i_size)
165 			bp->b_flags |= B_AGE;
166 		brelse(bp);
167 	} while (error == 0 && uio->uio_resid > 0 && n != 0);
168 	return (error);
169 }
170 
171 /* ARGSUSED */
172 isofs_ioctl(vp, com, data, fflag, cred, p)
173 	struct vnode *vp;
174 	int com;
175 	caddr_t data;
176 	int fflag;
177 	struct ucred *cred;
178 	struct proc *p;
179 {
180 	return (ENOTTY);
181 }
182 
183 /* ARGSUSED */
184 isofs_select(vp, which, fflags, cred, p)
185 	struct vnode *vp;
186 	int which, fflags;
187 	struct ucred *cred;
188 	struct proc *p;
189 {
190 
191 	/*
192 	 * We should really check to see if I/O is possible.
193 	 */
194 	return (1);
195 }
196 
197 /*
198  * Mmap a file
199  *
200  * NB Currently unsupported.
201  */
202 /* ARGSUSED */
203 isofs_mmap(vp, fflags, cred, p)
204 	struct vnode *vp;
205 	int fflags;
206 	struct ucred *cred;
207 	struct proc *p;
208 {
209 
210 	return (EINVAL);
211 }
212 
213 /*
214  * Seek on a file
215  *
216  * Nothing to do, so just return.
217  */
218 /* ARGSUSED */
219 isofs_seek(vp, oldoff, newoff, cred)
220 	struct vnode *vp;
221 	off_t oldoff, newoff;
222 	struct ucred *cred;
223 {
224 
225 	return (0);
226 }
227 
228 /*
229  * Vnode op for readdir
230  */
231 isofs_readdir(vp, uio, cred, eofflagp)
232 	struct vnode *vp;
233 	register struct uio *uio;
234 	struct ucred *cred;
235 	int *eofflagp;
236 {
237 	struct dirent dirent;
238 	int iso_offset;
239 	int entryoffsetinblock;
240 	int error = 0;
241 	int endsearch;
242 	struct iso_directory_record *ep;
243 	int reclen;
244 	struct iso_mnt *imp;
245 	struct iso_node *ip;
246 	struct buf *bp = NULL;
247 	int i;
248 	int end_flag = 0;
249 	ISO_RRIP_ANALYZE ana;
250 
251 	ip = VTOI (vp);
252 	imp = ip->i_mnt;
253 
254 	iso_offset = uio->uio_offset;
255 
256 	entryoffsetinblock = iso_blkoff(imp, iso_offset);
257 	if (entryoffsetinblock != 0) {
258 		if (error = iso_blkatoff(ip, iso_offset, (char **)0, &bp))
259 			return (error);
260 	}
261 
262 	endsearch = ip->i_size;
263 
264 	while (iso_offset < endsearch && uio->uio_resid > 0) {
265 		/*
266 		 * If offset is on a block boundary,
267 		 * read the next directory block.
268 		 * Release previous if it exists.
269 		 */
270 
271 		if (iso_blkoff(imp, iso_offset) == 0) {
272 			if (bp != NULL)
273 				brelse(bp);
274 			if (error = iso_blkatoff(ip, iso_offset,
275 						 (char **)0, &bp))
276 				return (error);
277 			entryoffsetinblock = 0;
278 		}
279 		/*
280 		 * Get pointer to next entry.
281 		 */
282 
283 		ep = (struct iso_directory_record *)
284 			(bp->b_un.b_addr + entryoffsetinblock);
285 
286 		reclen = isonum_711 (ep->length);
287 		if (reclen == 0) {
288 			/* skip to next block, if any */
289 			iso_offset = roundup (iso_offset,
290 					      imp->logical_block_size);
291 			continue;
292 		}
293 
294 		if (reclen < sizeof (struct iso_directory_record))
295 			/* illegal entry, stop */
296 			break;
297 
298 /* 10 Aug 92*/	if (entryoffsetinblock + reclen -1 >= imp->logical_block_size)
299 			/* illegal directory, so stop looking */
300 			break;
301 
302 		dirent.d_fileno = iso_lblktosize(imp, isonum_733 (ep->extent))
303 				+ entryoffsetinblock;
304 		dirent.d_namlen = isonum_711 (ep->name_len);
305 
306 		if (reclen < sizeof (struct iso_directory_record)
307 		    + dirent.d_namlen)
308 			/* illegal entry, stop */
309 			break;
310 
311 		/*
312 		 *
313 		 */
314 		switch (ep->name[0]) {
315 			case 0:
316 				dirent.d_name[0] = '.';
317 				dirent.d_namlen = 1;
318 				break;
319 			case 1:
320 				dirent.d_name[0] = '.';
321 				dirent.d_name[1] = '.';
322 				dirent.d_namlen = 2;
323 				break;
324 			default:
325 				switch ( imp->iso_ftype ) {
326 					case ISO_FTYPE_RRIP:
327 						isofs_rrip_getname( ep, dirent.d_name, &dirent.d_namlen );
328 					break;
329 					case ISO_FTYPE_9660:
330 						isofntrans(ep->name, dirent.d_namlen, dirent.d_name, &dirent.d_namlen);
331 					break;
332 					default:
333 					break;
334 				}
335 				break;
336 		}
337 
338 		dirent.d_name[dirent.d_namlen] = 0;
339 		dirent.d_reclen = DIRSIZ (&dirent);
340 
341 		if (uio->uio_resid < dirent.d_reclen)
342 			break;
343 
344 		if (error = uiomove (&dirent, dirent.d_reclen, uio))
345 			break;
346 
347 		iso_offset += reclen;
348 		entryoffsetinblock += reclen;
349 	}
350 
351 	if (bp)
352 		brelse (bp);
353 
354 	if (end_flag || (VTOI(vp)->i_size - iso_offset) <= 0)
355 		*eofflagp = 1;
356 	else
357 		*eofflagp = 0;
358 
359 	uio->uio_offset = iso_offset;
360 
361 	return (error);
362 }
363 
364 /*
365  * Return target name of a symbolic link
366  */
367 typedef struct iso_directory_record ISODIR;
368 typedef struct iso_node             ISONODE;
369 typedef struct iso_mnt              ISOMNT;
370 int isofs_readlink(vp, uio, cred)
371 struct vnode *vp;
372 struct uio   *uio;
373 struct ucred *cred;
374 {
375         ISONODE *ip;
376         ISODIR  *dirp;
377         ISOMNT  *imp;
378         struct  buf *bp;
379         int     symlen;
380         int     error, rv;
381         char    symname[NAME_MAX];
382 
383         ip  = VTOI( vp );
384         imp = ip->i_mnt;
385 /*printf("readlink mode %x ", ip->inode.iso_mode);*/
386         /*
387          * Get parents directory record block that this inode included.
388          */
389         error = bread(  imp->im_devvp,
390                         (daddr_t)(( ip->iso_parent_ext + (ip->iso_parent >> 11 ) )
391                         * imp->im_bsize / DEV_BSIZE ),
392                         imp->im_bsize,
393                         NOCRED,
394                         &bp );
395         if ( error ) {
396                 return( EINVAL );
397         }
398 
399         /*
400          * Setup the directory pointer for this inode
401          */
402 
403         dirp = (ISODIR *)(bp->b_un.b_addr + ( ip->iso_parent & 0x7ff ) );
404 #ifdef DEBUG
405         printf("lbn=%d[base=%d,off=%d,bsize=%d,DEV_BSIZE=%d], dirp= %08x, b_addr=%08x, offset=%08x(%08x)\n",
406                                 (daddr_t)(( ip->iso_parent_ext + (ip->iso_parent >> 12 ) ) * imp->im_bsize / DEV_BSIZE ),
407                                 ip->iso_parent_ext,
408                                 (ip->iso_parent >> 11 ),
409                                 imp->im_bsize,
410                                 DEV_BSIZE,
411                                 dirp,
412                                 bp->b_un.b_addr,
413                                 ip->iso_parent,
414                                 ip->iso_parent & 0x7ff );
415 #endif
416 
417         /*
418          * Just make sure, we have a right one....
419          *   1: Check not cross boundary on block
420          *   2: Check number of inode
421          */
422         if ( (ip->iso_parent & 0x7ff) + isonum_711( dirp->length ) >=
423                                                 imp->im_bsize )         {
424                 brelse ( bp );
425                 return( EINVAL );
426         }
427         /*if ( isonum_733(dirp->extent) != ip->i_number ) {
428                 brelse ( bp );
429                 return( EINVAL );
430         }*/
431 
432         /*
433          * Ok, we just gathering a Symbolick name in SL record.
434          */
435         rv = isofs_rrip_getsymname(vp, dirp, symname, &symlen);
436 	brelse (bp);
437 
438         if (rv == 0)
439                 return( EINVAL );
440 
441         /*
442          * return with the Symbolic name to caller's.
443          */
444         return ( uiomove( symname, symlen, uio ) );
445 }
446 
447 /*
448  * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
449  * done. If a buffer has been saved in anticipation of a CREATE, delete it.
450  */
451 /* ARGSUSED */
452 isofs_abortop(ndp)
453 	struct nameidata *ndp;
454 {
455 
456 	if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF)
457 		FREE(ndp->ni_pnbuf, M_NAMEI);
458 	return (0);
459 }
460 
461 /*
462  * Lock an inode.
463  */
464 isofs_lock(vp)
465 	struct vnode *vp;
466 {
467 	register struct iso_node *ip = VTOI(vp);
468 
469 	ISO_ILOCK(ip);
470 	return (0);
471 }
472 
473 /*
474  * Unlock an inode.
475  */
476 isofs_unlock(vp)
477 	struct vnode *vp;
478 {
479 	register struct iso_node *ip = VTOI(vp);
480 
481 	if (!(ip->i_flag & ILOCKED))
482 		panic("isofs_unlock NOT LOCKED");
483 	ISO_IUNLOCK(ip);
484 	return (0);
485 }
486 
487 /*
488  * Check for a locked inode.
489  */
490 isofs_islocked(vp)
491 	struct vnode *vp;
492 {
493 
494 	if (VTOI(vp)->i_flag & ILOCKED)
495 		return (1);
496 	return (0);
497 }
498 
499 /*
500  * Calculate the logical to physical mapping if not done already,
501  * then call the device strategy routine.
502  */
503 
504 isofs_strategy(bp)
505 	register struct buf *bp;
506 {
507 	register struct iso_node *ip = VTOI(bp->b_vp);
508 	struct vnode *vp;
509 	int error;
510 
511 	if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR)
512 		panic("isofs_strategy: spec");
513 	if (bp->b_blkno == bp->b_lblkno) {
514 		if (error = iso_bmap(ip, bp->b_lblkno, &bp->b_blkno))
515 			return (error);
516 		if ((long)bp->b_blkno == -1)
517 			clrbuf(bp);
518 	}
519 	if ((long)bp->b_blkno == -1) {
520 		biodone(bp);
521 		return (0);
522 	}
523 	vp = ip->i_devvp;
524 	bp->b_dev = vp->v_rdev;
525 	(*(vp->v_op->vop_strategy))(bp);
526 	return (0);
527 }
528 
529 /*
530  * Print out the contents of an inode.
531  */
532 isofs_print(vp)
533 	struct vnode *vp;
534 {
535 	printf ("tag VT_ISOFS, isofs vnode\n");
536 }
537 
538 extern int _ENODEV_ (), nullop();
539 
540 /*
541  * Global vfs data structures for isofs
542  */
543 struct vnodeops isofs_vnodeops = {
544 	isofs_lookup,		/* lookup */
545 	(void *)_ENODEV_,	/* create */
546 	(void *)_ENODEV_,	/* mknod */
547 	isofs_open,		/* open */
548 	isofs_close,		/* close */
549 	isofs_access,		/* access */
550 	isofs_getattr,		/* getattr */
551 	(void *)_ENODEV_,		/* setattr */
552 	isofs_read,		/* read */
553 	(void *)_ENODEV_,		/* write */
554 	isofs_ioctl,		/* ioctl */
555 	isofs_select,		/* select */
556 	isofs_mmap,		/* mmap */
557 	(void *)nullop,		/* fsync */
558 	isofs_seek,		/* seek */
559 	(void *)_ENODEV_,		/* remove */
560 	(void *)_ENODEV_,		/* link */
561 	(void *)_ENODEV_,		/* rename */
562 	(void *)_ENODEV_,		/* mkdir */
563 	(void *)_ENODEV_,		/* rmdir */
564 	(void *)_ENODEV_,		/* symlink */
565 	isofs_readdir,		/* readdir */
566 	isofs_readlink,		/* readlink */
567 	isofs_abortop,		/* abortop */
568 	isofs_inactive,		/* inactive */
569 	isofs_reclaim,		/* reclaim */
570 	isofs_lock,		/* lock */
571 	isofs_unlock,		/* unlock */
572 	(void *)_ENODEV_,		/* bmap */
573 	isofs_strategy,		/* strategy */
574 	isofs_print,		/* print */
575 	isofs_islocked,		/* islocked */
576 	(void *)_ENODEV_,		/* advlock */
577 };
578 
579 struct vnodeops spec_isonodeops = {
580 	spec_lookup,		/* lookup */
581 	spec_create,		/* create */
582 	spec_mknod,		/* mknod */
583 	spec_open,		/* open */
584 	spec_close,	/* close */
585 	isofs_access,		/* access */
586 	isofs_getattr,		/* getattr */
587 	(void *)nullop,		/* setattr -- XXX not enodev so writable*/
588 	spec_read,		/* read */
589 	spec_write,		/* write */
590 	spec_ioctl,		/* ioctl */
591 	spec_select,		/* select */
592 	spec_mmap,		/* mmap */
593 	spec_fsync,		/* fsync */
594 	spec_seek,		/* seek */
595 	spec_remove,		/* remove */
596 	spec_link,		/* link */
597 	spec_rename,		/* rename */
598 	spec_mkdir,		/* mkdir */
599 	spec_rmdir,		/* rmdir */
600 	spec_symlink,		/* symlink */
601 	spec_readdir,		/* readdir */
602 	spec_readlink,		/* readlink */
603 	spec_abortop,		/* abortop */
604 	isofs_inactive,		/* inactive */
605 	isofs_reclaim,		/* reclaim */
606 	isofs_lock,		/* lock */
607 	isofs_unlock,		/* unlock */
608 	spec_bmap,		/* bmap */
609 	spec_strategy,		/* strategy */
610 	isofs_print,		/* print */
611 	isofs_islocked,		/* islocked */
612 	spec_advlock,		/* advlock */
613 };
614