xref: /386bsd/usr/src/kernel/isofs/isofs_vnops.c (revision dc8b130e)
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 		/*
303 		 * if a directory, fake inode number on extent, otherwise
304 		 * make unique with entry offset
305 		 */
306 		if(ep->flags[0] & 2)
307 			dirent.d_fileno = iso_lblktosize(imp, isonum_733 (ep->extent));
308 		else
309 			dirent.d_fileno = iso_lblktosize(imp, isonum_733 (ep->extent))
310 				+ entryoffsetinblock;
311 
312 		dirent.d_namlen = isonum_711 (ep->name_len);
313 
314 		if (reclen < sizeof (struct iso_directory_record)
315 		    + dirent.d_namlen)
316 			/* illegal entry, stop */
317 			break;
318 
319 		/*
320 		 *
321 		 */
322 		switch (ep->name[0]) {
323 			case 0:
324 				dirent.d_name[0] = '.';
325 				dirent.d_namlen = 1;
326 				break;
327 			case 1:
328 				dirent.d_name[0] = '.';
329 				dirent.d_name[1] = '.';
330 				dirent.d_namlen = 2;
331 				break;
332 			default:
333 				switch ( imp->iso_ftype ) {
334 					case ISO_FTYPE_RRIP:
335 						isofs_rrip_getname( ep, dirent.d_name, &dirent.d_namlen );
336 					break;
337 					case ISO_FTYPE_9660:
338 						isofntrans(ep->name, dirent.d_namlen, dirent.d_name, &dirent.d_namlen);
339 					break;
340 					default:
341 					break;
342 				}
343 				break;
344 		}
345 
346 		dirent.d_name[dirent.d_namlen] = 0;
347 		dirent.d_reclen = DIRSIZ (&dirent);
348 
349 		if (uio->uio_resid < dirent.d_reclen)
350 			break;
351 
352 		if (error = uiomove (&dirent, dirent.d_reclen, uio))
353 			break;
354 
355 		iso_offset += reclen;
356 		entryoffsetinblock += reclen;
357 	}
358 
359 	if (bp)
360 		brelse (bp);
361 
362 	if (end_flag || (VTOI(vp)->i_size - iso_offset) <= 0)
363 		*eofflagp = 1;
364 	else
365 		*eofflagp = 0;
366 
367 	uio->uio_offset = iso_offset;
368 
369 	return (error);
370 }
371 
372 /*
373  * Return target name of a symbolic link
374  */
375 typedef struct iso_directory_record ISODIR;
376 typedef struct iso_node             ISONODE;
377 typedef struct iso_mnt              ISOMNT;
isofs_readlink(vp,uio,cred)378 int isofs_readlink(vp, uio, cred)
379 struct vnode *vp;
380 struct uio   *uio;
381 struct ucred *cred;
382 {
383         ISONODE *ip;
384         ISODIR  *dirp;
385         ISOMNT  *imp;
386         struct  buf *bp;
387         int     symlen;
388         int     error, rv;
389 
390         ip  = VTOI( vp );
391 #ifdef nope
392         char    symname[NAME_MAX];
393         imp = ip->i_mnt;
394 /*printf("readlink mode %x ", ip->inode.iso_mode);*/
395         /*
396          * Get parents directory record block that this inode included.
397          */
398         error = bread(  imp->im_devvp,
399                         (daddr_t)(( ip->iso_parent_ext + (ip->iso_parent >> 11 ) )
400                         * imp->im_bsize / DEV_BSIZE ),
401                         imp->im_bsize,
402                         NOCRED,
403                         &bp );
404         if ( error ) {
405                 return( EINVAL );
406         }
407 
408         /*
409          * Setup the directory pointer for this inode
410          */
411 
412         dirp = (ISODIR *)(bp->b_un.b_addr + ( ip->iso_parent & 0x7ff ) );
413 #ifdef DEBUG
414         printf("lbn=%d[base=%d,off=%d,bsize=%d,DEV_BSIZE=%d], dirp= %08x, b_addr=%08x, offset=%08x(%08x)\n",
415                                 (daddr_t)(( ip->iso_parent_ext + (ip->iso_parent >> 12 ) ) * imp->im_bsize / DEV_BSIZE ),
416                                 ip->iso_parent_ext,
417                                 (ip->iso_parent >> 11 ),
418                                 imp->im_bsize,
419                                 DEV_BSIZE,
420                                 dirp,
421                                 bp->b_un.b_addr,
422                                 ip->iso_parent,
423                                 ip->iso_parent & 0x7ff );
424 #endif
425 
426         /*
427          * Just make sure, we have a right one....
428          *   1: Check not cross boundary on block
429          *   2: Check number of inode
430          */
431         if ( (ip->iso_parent & 0x7ff) + isonum_711( dirp->length ) >=
432                                                 imp->im_bsize )         {
433                 brelse ( bp );
434                 return( EINVAL );
435         }
436         /*if ( isonum_733(dirp->extent) != ip->i_number ) {
437                 brelse ( bp );
438                 return( EINVAL );
439         }*/
440 
441         /*
442          * Ok, we just gathering a Symbolick name in SL record.
443          */
444         rv = isofs_rrip_getsymname(vp, dirp, symname, &symlen);
445 	brelse (bp);
446 
447         if (rv == 0)
448                 return( EINVAL );
449 
450         /*
451          * return with the Symbolic name to caller's.
452          */
453         return ( uiomove( symname, symlen, uio ) );
454 #else
455 if(ip->iso_sl == 0)
456 	return(EINVAL);
457 else
458         return ( uiomove( ip->iso_sl, ip->iso_sl_len, uio ) );
459 #endif
460 }
461 
462 /*
463  * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
464  * done. If a buffer has been saved in anticipation of a CREATE, delete it.
465  */
466 /* ARGSUSED */
467 isofs_abortop(ndp)
468 	struct nameidata *ndp;
469 {
470 
471 	if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF)
472 		FREE(ndp->ni_pnbuf, M_NAMEI);
473 	return (0);
474 }
475 
476 /*
477  * Lock an inode.
478  */
479 isofs_lock(vp)
480 	struct vnode *vp;
481 {
482 	register struct iso_node *ip = VTOI(vp);
483 
484 	ISO_ILOCK(ip);
485 	return (0);
486 }
487 
488 /*
489  * Unlock an inode.
490  */
491 isofs_unlock(vp)
492 	struct vnode *vp;
493 {
494 	register struct iso_node *ip = VTOI(vp);
495 
496 	if (!(ip->i_flag & ILOCKED))
497 		panic("isofs_unlock NOT LOCKED");
498 	ISO_IUNLOCK(ip);
499 	return (0);
500 }
501 
502 /*
503  * Check for a locked inode.
504  */
505 isofs_islocked(vp)
506 	struct vnode *vp;
507 {
508 
509 	if (VTOI(vp)->i_flag & ILOCKED)
510 		return (1);
511 	return (0);
512 }
513 
514 /*
515  * Calculate the logical to physical mapping if not done already,
516  * then call the device strategy routine.
517  */
518 
isofs_strategy(bp)519 isofs_strategy(bp)
520 	register struct buf *bp;
521 {
522 	register struct iso_node *ip = VTOI(bp->b_vp);
523 	struct vnode *vp;
524 	int error;
525 
526 	if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR)
527 		panic("isofs_strategy: spec");
528 	if (bp->b_blkno == bp->b_lblkno) {
529 		if (error = iso_bmap(ip, bp->b_lblkno, &bp->b_blkno))
530 			return (error);
531 		if ((long)bp->b_blkno == -1)
532 			clrbuf(bp);
533 	}
534 	if ((long)bp->b_blkno == -1) {
535 		biodone(bp);
536 		return (0);
537 	}
538 	vp = ip->i_devvp;
539 	bp->b_dev = vp->v_rdev;
540 	(*(vp->v_op->vop_strategy))(bp);
541 	return (0);
542 }
543 
544 /*
545  * Print out the contents of an inode.
546  */
547 isofs_print(vp)
548 	struct vnode *vp;
549 {
550 	printf ("tag VT_ISOFS, isofs vnode\n");
551 }
552 
553 extern int _ENODEV_ (), nullop();
554 
555 /*
556  * Global vfs data structures for isofs
557  */
558 struct vnodeops isofs_vnodeops = {
559 	isofs_lookup,		/* lookup */
560 	(void *)_ENODEV_,	/* create */
561 	(void *)_ENODEV_,	/* mknod */
562 	isofs_open,		/* open */
563 	isofs_close,		/* close */
564 	isofs_access,		/* access */
565 	isofs_getattr,		/* getattr */
566 	(void *)_ENODEV_,		/* setattr */
567 	isofs_read,		/* read */
568 	(void *)_ENODEV_,		/* write */
569 	isofs_ioctl,		/* ioctl */
570 	isofs_select,		/* select */
571 	isofs_mmap,		/* mmap */
572 	(void *)nullop,		/* fsync */
573 	isofs_seek,		/* seek */
574 	(void *)_ENODEV_,		/* remove */
575 	(void *)_ENODEV_,		/* link */
576 	(void *)_ENODEV_,		/* rename */
577 	(void *)_ENODEV_,		/* mkdir */
578 	(void *)_ENODEV_,		/* rmdir */
579 	(void *)_ENODEV_,		/* symlink */
580 	isofs_readdir,		/* readdir */
581 	isofs_readlink,		/* readlink */
582 	isofs_abortop,		/* abortop */
583 	isofs_inactive,		/* inactive */
584 	isofs_reclaim,		/* reclaim */
585 	isofs_lock,		/* lock */
586 	isofs_unlock,		/* unlock */
587 	(void *)_ENODEV_,		/* bmap */
588 	isofs_strategy,		/* strategy */
589 	isofs_print,		/* print */
590 	isofs_islocked,		/* islocked */
591 	(void *)_ENODEV_,		/* advlock */
592 };
593 
594 struct vnodeops spec_isonodeops = {
595 	spec_lookup,		/* lookup */
596 	spec_create,		/* create */
597 	spec_mknod,		/* mknod */
598 	spec_open,		/* open */
599 	spec_close,	/* close */
600 	isofs_access,		/* access */
601 	isofs_getattr,		/* getattr */
602 	(void *)nullop,		/* setattr -- XXX not enodev so writable*/
603 	spec_read,		/* read */
604 	spec_write,		/* write */
605 	spec_ioctl,		/* ioctl */
606 	spec_select,		/* select */
607 	spec_mmap,		/* mmap */
608 	spec_fsync,		/* fsync */
609 	spec_seek,		/* seek */
610 	spec_remove,		/* remove */
611 	spec_link,		/* link */
612 	spec_rename,		/* rename */
613 	spec_mkdir,		/* mkdir */
614 	spec_rmdir,		/* rmdir */
615 	spec_symlink,		/* symlink */
616 	spec_readdir,		/* readdir */
617 	spec_readlink,		/* readlink */
618 	spec_abortop,		/* abortop */
619 	isofs_inactive,		/* inactive */
620 	isofs_reclaim,		/* reclaim */
621 	isofs_lock,		/* lock */
622 	isofs_unlock,		/* unlock */
623 	spec_bmap,		/* bmap */
624 	spec_strategy,		/* strategy */
625 	isofs_print,		/* print */
626 	isofs_islocked,		/* islocked */
627 	spec_advlock,		/* advlock */
628 };
629