xref: /original-bsd/sys/stand/ufs.c (revision 35b834a5)
1 /*-
2  * Copyright (c) 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * The Mach Operating System project at Carnegie-Mellon University.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)ufs.c	8.2 (Berkeley) 11/30/93
11  *
12  *
13  * Copyright (c) 1990, 1991 Carnegie Mellon University
14  * All Rights Reserved.
15  *
16  * Author: David Golub
17  *
18  * Permission to use, copy, modify and distribute this software and its
19  * documentation is hereby granted, provided that both the copyright
20  * notice and this permission notice appear in all copies of the
21  * software, derivative works or modified versions, and any portions
22  * thereof, and that both notices appear in supporting documentation.
23  *
24  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
25  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
26  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
27  *
28  * Carnegie Mellon requests users of this software to return to
29  *
30  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
31  *  School of Computer Science
32  *  Carnegie Mellon University
33  *  Pittsburgh PA 15213-3890
34  *
35  * any improvements or extensions that they make and grant Carnegie the
36  * rights to redistribute these changes.
37  */
38 
39 /*
40  *	Stand-alone file reading package.
41  */
42 
43 #include <sys/param.h>
44 #include <sys/time.h>
45 #include <ufs/ffs/fs.h>
46 #include <ufs/ufs/dinode.h>
47 #include <ufs/ufs/dir.h>
48 #include <stand/stand.h>
49 
50 /*
51  * In-core open file.
52  */
53 struct file {
54 	off_t		f_seekp;	/* seek pointer */
55 	struct fs	*f_fs;		/* pointer to super-block */
56 	struct dinode	f_di;		/* copy of on-disk inode */
57 	int		f_nindir[NIADDR];
58 					/* number of blocks mapped by
59 					   indirect block at level i */
60 	char		*f_blk[NIADDR];	/* buffer for indirect block at
61 					   level i */
62 	u_int		f_blksize[NIADDR];
63 					/* size of buffer */
64 	daddr_t		f_blkno[NIADDR];/* disk address of block in buffer */
65 	char		*f_buf;		/* buffer for data block */
66 	u_int		f_buf_size;	/* size of data block */
67 	daddr_t		f_buf_blkno;	/* block number of data block */
68 };
69 
70 /*
71  * Read a new inode into a file structure.
72  */
73 static int
read_inode(inumber,f)74 read_inode(inumber, f)
75 	ino_t inumber;
76 	struct open_file *f;
77 {
78 	register struct file *fp = (struct file *)f->f_fsdata;
79 	register struct fs *fs = fp->f_fs;
80 	char *buf;
81 	u_int rsize;
82 	int rc;
83 
84 	/*
85 	 * Read inode and save it.
86 	 */
87 	buf = alloc(fs->fs_bsize);
88 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
89 		fsbtodb(fs, ino_to_fsba(fs, inumber)), fs->fs_bsize,
90 		buf, &rsize);
91 	if (rc)
92 		goto out;
93 	if (rsize != fs->fs_bsize) {
94 		rc = EIO;
95 		goto out;
96 	}
97 
98 	{
99 		register struct dinode *dp;
100 
101 		dp = (struct dinode *)buf;
102 		fp->f_di = dp[ino_to_fsbo(fs, inumber)];
103 	}
104 
105 	/*
106 	 * Clear out the old buffers
107 	 */
108 	{
109 		register int level;
110 
111 		for (level = 0; level < NIADDR; level++)
112 			fp->f_blkno[level] = -1;
113 		fp->f_buf_blkno = -1;
114 	}
115 out:
116 	free(buf, fs->fs_bsize);
117 	return (0);
118 }
119 
120 /*
121  * Given an offset in a file, find the disk block number that
122  * contains that block.
123  */
124 static int
block_map(f,file_block,disk_block_p)125 block_map(f, file_block, disk_block_p)
126 	struct open_file *f;
127 	daddr_t file_block;
128 	daddr_t *disk_block_p;	/* out */
129 {
130 	register struct file *fp = (struct file *)f->f_fsdata;
131 	register struct fs *fs = fp->f_fs;
132 	int level;
133 	int idx;
134 	daddr_t ind_block_num;
135 	daddr_t *ind_p;
136 	int rc;
137 
138 	/*
139 	 * Index structure of an inode:
140 	 *
141 	 * di_db[0..NDADDR-1]	hold block numbers for blocks
142 	 *			0..NDADDR-1
143 	 *
144 	 * di_ib[0]		index block 0 is the single indirect block
145 	 *			holds block numbers for blocks
146 	 *			NDADDR .. NDADDR + NINDIR(fs)-1
147 	 *
148 	 * di_ib[1]		index block 1 is the double indirect block
149 	 *			holds block numbers for INDEX blocks for blocks
150 	 *			NDADDR + NINDIR(fs) ..
151 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
152 	 *
153 	 * di_ib[2]		index block 2 is the triple indirect block
154 	 *			holds block numbers for double-indirect
155 	 *			blocks for blocks
156 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
157 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2
158 	 *				+ NINDIR(fs)**3 - 1
159 	 */
160 
161 	if (file_block < NDADDR) {
162 		/* Direct block. */
163 		*disk_block_p = fp->f_di.di_db[file_block];
164 		return (0);
165 	}
166 
167 	file_block -= NDADDR;
168 
169 	/*
170 	 * nindir[0] = NINDIR
171 	 * nindir[1] = NINDIR**2
172 	 * nindir[2] = NINDIR**3
173 	 *	etc
174 	 */
175 	for (level = 0; level < NIADDR; level++) {
176 		if (file_block < fp->f_nindir[level])
177 			break;
178 		file_block -= fp->f_nindir[level];
179 	}
180 	if (level == NIADDR) {
181 		/* Block number too high */
182 		return (EFBIG);
183 	}
184 
185 	ind_block_num = fp->f_di.di_ib[level];
186 
187 	for (; level >= 0; level--) {
188 		if (ind_block_num == 0) {
189 			*disk_block_p = 0;	/* missing */
190 			return (0);
191 		}
192 
193 		if (fp->f_blkno[level] != ind_block_num) {
194 			if (fp->f_blk[level] == (char *)0)
195 				fp->f_blk[level] =
196 					alloc(fs->fs_bsize);
197 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
198 				fsbtodb(fp->f_fs, ind_block_num),
199 				fs->fs_bsize,
200 				fp->f_blk[level],
201 				&fp->f_blksize[level]);
202 			if (rc)
203 				return (rc);
204 			if (fp->f_blksize[level] != fs->fs_bsize)
205 				return (EIO);
206 			fp->f_blkno[level] = ind_block_num;
207 		}
208 
209 		ind_p = (daddr_t *)fp->f_blk[level];
210 
211 		if (level > 0) {
212 			idx = file_block / fp->f_nindir[level - 1];
213 			file_block %= fp->f_nindir[level - 1];
214 		} else
215 			idx = file_block;
216 
217 		ind_block_num = ind_p[idx];
218 	}
219 
220 	*disk_block_p = ind_block_num;
221 
222 	return (0);
223 }
224 
225 /*
226  * Read a portion of a file into an internal buffer.  Return
227  * the location in the buffer and the amount in the buffer.
228  */
229 static int
buf_read_file(f,buf_p,size_p)230 buf_read_file(f, buf_p, size_p)
231 	struct open_file *f;
232 	char **buf_p;		/* out */
233 	u_int *size_p;		/* out */
234 {
235 	register struct file *fp = (struct file *)f->f_fsdata;
236 	register struct fs *fs = fp->f_fs;
237 	long off;
238 	register daddr_t file_block;
239 	daddr_t	disk_block;
240 	long block_size;
241 	int rc;
242 
243 	off = blkoff(fs, fp->f_seekp);
244 	file_block = lblkno(fs, fp->f_seekp);
245 	block_size = dblksize(fs, &fp->f_di, file_block);
246 
247 	if (file_block != fp->f_buf_blkno) {
248 		rc = block_map(f, file_block, &disk_block);
249 		if (rc)
250 			return (rc);
251 
252 		if (fp->f_buf == (char *)0)
253 			fp->f_buf = alloc(fs->fs_bsize);
254 
255 		if (disk_block == 0) {
256 			bzero(fp->f_buf, block_size);
257 			fp->f_buf_size = block_size;
258 		} else {
259 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
260 				fsbtodb(fs, disk_block),
261 				block_size, fp->f_buf, &fp->f_buf_size);
262 			if (rc)
263 				return (rc);
264 		}
265 
266 		fp->f_buf_blkno = file_block;
267 	}
268 
269 	/*
270 	 * Return address of byte in buffer corresponding to
271 	 * offset, and size of remainder of buffer after that
272 	 * byte.
273 	 */
274 	*buf_p = fp->f_buf + off;
275 	*size_p = block_size - off;
276 
277 	/*
278 	 * But truncate buffer at end of file.
279 	 */
280 	if (*size_p > fp->f_di.di_size - fp->f_seekp)
281 		*size_p = fp->f_di.di_size - fp->f_seekp;
282 
283 	return (0);
284 }
285 
286 /*
287  * Search a directory for a name and return its
288  * i_number.
289  */
290 static int
search_directory(name,f,inumber_p)291 search_directory(name, f, inumber_p)
292 	char *name;
293 	struct open_file *f;
294 	ino_t *inumber_p;		/* out */
295 {
296 	register struct file *fp = (struct file *)f->f_fsdata;
297 	register struct direct *dp;
298 	struct direct *edp;
299 	char *buf;
300 	u_int buf_size;
301 	int namlen, length;
302 	int rc;
303 
304 	length = strlen(name);
305 
306 	fp->f_seekp = 0;
307 	while (fp->f_seekp < fp->f_di.di_size) {
308 		rc = buf_read_file(f, &buf, &buf_size);
309 		if (rc)
310 			return (rc);
311 
312 		dp = (struct direct *)buf;
313 		edp = (struct direct *)(buf + buf_size);
314 		while (dp < edp) {
315 			if (dp->d_ino == (ino_t)0)
316 				goto next;
317 #if BYTE_ORDER == LITTLE_ENDIAN
318 			if (fp->f_fs->fs_maxsymlinklen <= 0)
319 				namlen = dp->d_type;
320 			else
321 #endif
322 				namlen = dp->d_namlen;
323 			if (namlen == length &&
324 			    !strcmp(name, dp->d_name)) {
325 				/* found entry */
326 				*inumber_p = dp->d_ino;
327 				return (0);
328 			}
329 		next:
330 			dp = (struct direct *)((char *)dp + dp->d_reclen);
331 		}
332 		fp->f_seekp += buf_size;
333 	}
334 	return (ENOENT);
335 }
336 
337 /*
338  * Open a file.
339  */
340 int
ufs_open(path,f)341 ufs_open(path, f)
342 	char *path;
343 	struct open_file *f;
344 {
345 	register char *cp, *ncp;
346 	register int c;
347 	ino_t inumber, parent_inumber;
348 	int nlinks = 0;
349 	struct file *fp;
350 	struct fs *fs;
351 	int rc;
352 	u_int buf_size;
353 #if 0
354 	char namebuf[MAXPATHLEN+1];
355 #endif
356 
357 	/* allocate file system specific data structure */
358 	fp = alloc(sizeof(struct file));
359 	bzero(fp, sizeof(struct file));
360 	f->f_fsdata = (void *)fp;
361 
362 	/* allocate space and read super block */
363 	fs = alloc(SBSIZE);
364 	fp->f_fs = fs;
365 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
366 		SBLOCK, SBSIZE, (char *)fs, &buf_size);
367 	if (rc)
368 		goto out;
369 
370 	if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC ||
371 	    fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
372 		rc = EINVAL;
373 		goto out;
374 	}
375 
376 	/*
377 	 * Calculate indirect block levels.
378 	 */
379 	{
380 		register int mult;
381 		register int level;
382 
383 		mult = 1;
384 		for (level = 0; level < NIADDR; level++) {
385 			mult *= NINDIR(fs);
386 			fp->f_nindir[level] = mult;
387 		}
388 	}
389 
390 	inumber = ROOTINO;
391 	if ((rc = read_inode(inumber, f)) != 0)
392 		goto out;
393 
394 	cp = path;
395 	while (*cp) {
396 
397 		/*
398 		 * Remove extra separators
399 		 */
400 		while (*cp == '/')
401 			cp++;
402 		if (*cp == '\0')
403 			break;
404 
405 		/*
406 		 * Check that current node is a directory.
407 		 */
408 		if ((fp->f_di.di_mode & IFMT) != IFDIR) {
409 			rc = ENOTDIR;
410 			goto out;
411 		}
412 
413 		/*
414 		 * Get next component of path name.
415 		 */
416 		{
417 			register int len = 0;
418 
419 			ncp = cp;
420 			while ((c = *cp) != '\0' && c != '/') {
421 				if (++len > MAXNAMLEN) {
422 					rc = ENOENT;
423 					goto out;
424 				}
425 				cp++;
426 			}
427 			*cp = '\0';
428 		}
429 
430 		/*
431 		 * Look up component in current directory.
432 		 * Save directory inumber in case we find a
433 		 * symbolic link.
434 		 */
435 		parent_inumber = inumber;
436 		rc = search_directory(ncp, f, &inumber);
437 		*cp = c;
438 		if (rc)
439 			goto out;
440 
441 		/*
442 		 * Open next component.
443 		 */
444 		if ((rc = read_inode(inumber, f)) != 0)
445 			goto out;
446 
447 #if 0
448 		/*
449 		 * Check for symbolic link.
450 		 */
451 		if ((fp->i_mode & IFMT) == IFLNK) {
452 			int link_len = fp->f_di.di_size;
453 			int len;
454 
455 			len = strlen(cp) + 1;
456 
457 			if (fp->f_di.di_size >= MAXPATHLEN - 1 ||
458 			    ++nlinks > MAXSYMLINKS) {
459 				rc = ENOENT;
460 				goto out;
461 			}
462 
463 			strcpy(&namebuf[link_len], cp);
464 
465 			if ((fp->i_flags & IC_FASTLINK) != 0) {
466 				bcopy(fp->i_symlink, namebuf, (unsigned) link_len);
467 			} else {
468 				/*
469 				 * Read file for symbolic link
470 				 */
471 				char *buf;
472 				u_int buf_size;
473 				daddr_t	disk_block;
474 				register struct fs *fs = fp->f_fs;
475 
476 				(void) block_map(f, (daddr_t)0, &disk_block);
477 				rc = device_read(&fp->f_dev,
478 						 fsbtodb(fs, disk_block),
479 						 blksize(fs, fp, 0),
480 						 &buf, &buf_size);
481 				if (rc)
482 					goto out;
483 
484 				bcopy((char *)buf, namebuf, (unsigned)link_len);
485 				free(buf, buf_size);
486 			}
487 
488 			/*
489 			 * If relative pathname, restart at parent directory.
490 			 * If absolute pathname, restart at root.
491 			 */
492 			cp = namebuf;
493 			if (*cp != '/')
494 				inumber = parent_inumber;
495 			else
496 				inumber = (ino_t)ROOTINO;
497 
498 			if ((rc = read_inode(inumber, fp)) != 0)
499 				goto out;
500 		}
501 #endif
502 	}
503 
504 	/*
505 	 * Found terminal component.
506 	 */
507 	rc = 0;
508 out:
509 	if (rc)
510 		free(fp, sizeof(struct file));
511 	return (rc);
512 }
513 
514 int
ufs_close(f)515 ufs_close(f)
516 	struct open_file *f;
517 {
518 	register struct file *fp = (struct file *)f->f_fsdata;
519 	int level;
520 
521 	f->f_fsdata = (void *)0;
522 	if (fp == (struct file *)0)
523 		return (0);
524 
525 	for (level = 0; level < NIADDR; level++) {
526 		if (fp->f_blk[level])
527 			free(fp->f_blk[level], fp->f_fs->fs_bsize);
528 	}
529 	if (fp->f_buf)
530 		free(fp->f_buf, fp->f_fs->fs_bsize);
531 	free(fp->f_fs, SBSIZE);
532 	free(fp, sizeof(struct file));
533 	return (0);
534 }
535 
536 /*
537  * Copy a portion of a file into kernel memory.
538  * Cross block boundaries when necessary.
539  */
540 int
ufs_read(f,start,size,resid)541 ufs_read(f, start, size, resid)
542 	struct open_file *f;
543 	char *start;
544 	u_int size;
545 	u_int *resid;	/* out */
546 {
547 	register struct file *fp = (struct file *)f->f_fsdata;
548 	register u_int csize;
549 	char *buf;
550 	u_int buf_size;
551 	int rc = 0;
552 
553 	while (size != 0) {
554 		if (fp->f_seekp >= fp->f_di.di_size)
555 			break;
556 
557 		rc = buf_read_file(f, &buf, &buf_size);
558 		if (rc)
559 			break;
560 
561 		csize = size;
562 		if (csize > buf_size)
563 			csize = buf_size;
564 
565 		bcopy(buf, start, csize);
566 
567 		fp->f_seekp += csize;
568 		start += csize;
569 		size -= csize;
570 	}
571 	if (resid)
572 		*resid = size;
573 	return (rc);
574 }
575 
576 /*
577  * Not implemented.
578  */
579 int
ufs_write(f,start,size,resid)580 ufs_write(f, start, size, resid)
581 	struct open_file *f;
582 	char *start;
583 	u_int size;
584 	u_int *resid;	/* out */
585 {
586 
587 	return (EROFS);
588 }
589 
590 off_t
ufs_seek(f,offset,where)591 ufs_seek(f, offset, where)
592 	struct open_file *f;
593 	off_t offset;
594 	int where;
595 {
596 	register struct file *fp = (struct file *)f->f_fsdata;
597 
598 	switch (where) {
599 	case SEEK_SET:
600 		fp->f_seekp = offset;
601 		break;
602 	case SEEK_CUR:
603 		fp->f_seekp += offset;
604 		break;
605 	case SEEK_END:
606 		fp->f_seekp = fp->f_di.di_size - offset;
607 		break;
608 	default:
609 		return (-1);
610 	}
611 	return (fp->f_seekp);
612 }
613 
614 int
ufs_stat(f,sb)615 ufs_stat(f, sb)
616 	struct open_file *f;
617 	struct stat *sb;
618 {
619 	register struct file *fp = (struct file *)f->f_fsdata;
620 
621 	/* only important stuff */
622 	sb->st_mode = fp->f_di.di_mode;
623 	sb->st_uid = fp->f_di.di_uid;
624 	sb->st_gid = fp->f_di.di_gid;
625 	sb->st_size = fp->f_di.di_size;
626 	return (0);
627 }
628