xref: /original-bsd/sys/stand/ufs.c (revision 3705696b)
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.1 (Berkeley) 06/11/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_long		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
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, itod(fs, inumber)), fs->fs_bsize, buf, &rsize);
90 	if (rc)
91 		goto out;
92 	if (rsize != fs->fs_bsize) {
93 		rc = EIO;
94 		goto out;
95 	}
96 
97 	{
98 		register struct dinode *dp;
99 
100 		dp = (struct dinode *)buf;
101 		fp->f_di = dp[itoo(fs, inumber)];
102 	}
103 
104 	/*
105 	 * Clear out the old buffers
106 	 */
107 	{
108 		register int level;
109 
110 		for (level = 0; level < NIADDR; level++)
111 			fp->f_blkno[level] = -1;
112 		fp->f_buf_blkno = -1;
113 	}
114 out:
115 	free(buf, fs->fs_bsize);
116 	return (0);
117 }
118 
119 /*
120  * Given an offset in a file, find the disk block number that
121  * contains that block.
122  */
123 static int
124 block_map(f, file_block, disk_block_p)
125 	struct open_file *f;
126 	daddr_t file_block;
127 	daddr_t *disk_block_p;	/* out */
128 {
129 	register struct file *fp = (struct file *)f->f_fsdata;
130 	register struct fs *fs = fp->f_fs;
131 	int level;
132 	int idx;
133 	daddr_t ind_block_num;
134 	daddr_t *ind_p;
135 	int rc;
136 
137 	/*
138 	 * Index structure of an inode:
139 	 *
140 	 * di_db[0..NDADDR-1]	hold block numbers for blocks
141 	 *			0..NDADDR-1
142 	 *
143 	 * di_ib[0]		index block 0 is the single indirect block
144 	 *			holds block numbers for blocks
145 	 *			NDADDR .. NDADDR + NINDIR(fs)-1
146 	 *
147 	 * di_ib[1]		index block 1 is the double indirect block
148 	 *			holds block numbers for INDEX blocks for blocks
149 	 *			NDADDR + NINDIR(fs) ..
150 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
151 	 *
152 	 * di_ib[2]		index block 2 is the triple indirect block
153 	 *			holds block numbers for double-indirect
154 	 *			blocks for blocks
155 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
156 	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2
157 	 *				+ NINDIR(fs)**3 - 1
158 	 */
159 
160 	if (file_block < NDADDR) {
161 		/* Direct block. */
162 		*disk_block_p = fp->f_di.di_db[file_block];
163 		return (0);
164 	}
165 
166 	file_block -= NDADDR;
167 
168 	/*
169 	 * nindir[0] = NINDIR
170 	 * nindir[1] = NINDIR**2
171 	 * nindir[2] = NINDIR**3
172 	 *	etc
173 	 */
174 	for (level = 0; level < NIADDR; level++) {
175 		if (file_block < fp->f_nindir[level])
176 			break;
177 		file_block -= fp->f_nindir[level];
178 	}
179 	if (level == NIADDR) {
180 		/* Block number too high */
181 		return (EFBIG);
182 	}
183 
184 	ind_block_num = fp->f_di.di_ib[level];
185 
186 	for (; level >= 0; level--) {
187 		if (ind_block_num == 0) {
188 			*disk_block_p = 0;	/* missing */
189 			return (0);
190 		}
191 
192 		if (fp->f_blkno[level] != ind_block_num) {
193 			if (fp->f_blk[level] == (char *)0)
194 				fp->f_blk[level] =
195 					alloc(fs->fs_bsize);
196 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
197 				fsbtodb(fp->f_fs, ind_block_num),
198 				fs->fs_bsize,
199 				fp->f_blk[level],
200 				&fp->f_blksize[level]);
201 			if (rc)
202 				return (rc);
203 			if (fp->f_blksize[level] != fs->fs_bsize)
204 				return (EIO);
205 			fp->f_blkno[level] = ind_block_num;
206 		}
207 
208 		ind_p = (daddr_t *)fp->f_blk[level];
209 
210 		if (level > 0) {
211 			idx = file_block / fp->f_nindir[level - 1];
212 			file_block %= fp->f_nindir[level - 1];
213 		} else
214 			idx = file_block;
215 
216 		ind_block_num = ind_p[idx];
217 	}
218 
219 	*disk_block_p = ind_block_num;
220 
221 	return (0);
222 }
223 
224 /*
225  * Read a portion of a file into an internal buffer.  Return
226  * the location in the buffer and the amount in the buffer.
227  */
228 static int
229 buf_read_file(f, buf_p, size_p)
230 	struct open_file *f;
231 	char **buf_p;		/* out */
232 	u_int *size_p;		/* out */
233 {
234 	register struct file *fp = (struct file *)f->f_fsdata;
235 	register struct fs *fs = fp->f_fs;
236 	long off;
237 	register daddr_t file_block;
238 	daddr_t	disk_block;
239 	long block_size;
240 	int rc;
241 
242 	off = blkoff(fs, fp->f_seekp);
243 	file_block = lblkno(fs, fp->f_seekp);
244 	block_size = dblksize(fs, &fp->f_di, file_block);
245 
246 	if (file_block != fp->f_buf_blkno) {
247 		rc = block_map(f, file_block, &disk_block);
248 		if (rc)
249 			return (rc);
250 
251 		if (fp->f_buf == (char *)0)
252 			fp->f_buf = alloc(fs->fs_bsize);
253 
254 		if (disk_block == 0) {
255 			bzero(fp->f_buf, block_size);
256 			fp->f_buf_size = block_size;
257 		} else {
258 			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
259 				fsbtodb(fs, disk_block),
260 				block_size, fp->f_buf, &fp->f_buf_size);
261 			if (rc)
262 				return (rc);
263 		}
264 
265 		fp->f_buf_blkno = file_block;
266 	}
267 
268 	/*
269 	 * Return address of byte in buffer corresponding to
270 	 * offset, and size of remainder of buffer after that
271 	 * byte.
272 	 */
273 	*buf_p = fp->f_buf + off;
274 	*size_p = block_size - off;
275 
276 	/*
277 	 * But truncate buffer at end of file.
278 	 */
279 	if (*size_p > fp->f_di.di_size - fp->f_seekp)
280 		*size_p = fp->f_di.di_size - fp->f_seekp;
281 
282 	return (0);
283 }
284 
285 /*
286  * Search a directory for a name and return its
287  * i_number.
288  */
289 static int
290 search_directory(name, f, inumber_p)
291 	char *name;
292 	struct open_file *f;
293 	ino_t *inumber_p;		/* out */
294 {
295 	register struct file *fp = (struct file *)f->f_fsdata;
296 	register struct direct *dp;
297 	struct direct *edp;
298 	char *buf;
299 	u_int buf_size;
300 	int namlen, length;
301 	int rc;
302 
303 	length = strlen(name);
304 
305 	fp->f_seekp = 0;
306 	while (fp->f_seekp < fp->f_di.di_size) {
307 		rc = buf_read_file(f, &buf, &buf_size);
308 		if (rc)
309 			return (rc);
310 
311 		dp = (struct direct *)buf;
312 		edp = (struct direct *)(buf + buf_size);
313 		while (dp < edp) {
314 			if (dp->d_ino == (ino_t)0)
315 				goto next;
316 #if BYTE_ORDER == LITTLE_ENDIAN
317 			if (fp->f_fs->fs_maxsymlinklen <= 0)
318 				namlen = dp->d_type;
319 			else
320 #endif
321 				namlen = dp->d_namlen;
322 			if (namlen == length &&
323 			    !strcmp(name, dp->d_name)) {
324 				/* found entry */
325 				*inumber_p = dp->d_ino;
326 				return (0);
327 			}
328 		next:
329 			dp = (struct direct *)((char *)dp + dp->d_reclen);
330 		}
331 		fp->f_seekp += buf_size;
332 	}
333 	return (ENOENT);
334 }
335 
336 /*
337  * Open a file.
338  */
339 int
340 ufs_open(path, f)
341 	char *path;
342 	struct open_file *f;
343 {
344 	register char *cp, *ncp;
345 	register int c;
346 	ino_t inumber, parent_inumber;
347 	int nlinks = 0;
348 	struct file *fp;
349 	struct fs *fs;
350 	int rc;
351 	u_int buf_size;
352 #if 0
353 	char namebuf[MAXPATHLEN+1];
354 #endif
355 
356 	/* allocate file system specific data structure */
357 	fp = alloc(sizeof(struct file));
358 	bzero(fp, sizeof(struct file));
359 	f->f_fsdata = (void *)fp;
360 
361 	/* allocate space and read super block */
362 	fs = alloc(SBSIZE);
363 	fp->f_fs = fs;
364 	rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
365 		SBLOCK, SBSIZE, (char *)fs, &buf_size);
366 	if (rc)
367 		goto out;
368 
369 	if (buf_size != SBSIZE || fs->fs_magic != FS_MAGIC ||
370 	    fs->fs_bsize > MAXBSIZE || fs->fs_bsize < sizeof(struct fs)) {
371 		rc = EINVAL;
372 		goto out;
373 	}
374 
375 	/*
376 	 * Calculate indirect block levels.
377 	 */
378 	{
379 		register int mult;
380 		register int level;
381 
382 		mult = 1;
383 		for (level = 0; level < NIADDR; level++) {
384 			mult *= NINDIR(fs);
385 			fp->f_nindir[level] = mult;
386 		}
387 	}
388 
389 	inumber = ROOTINO;
390 	if ((rc = read_inode(inumber, f)) != 0)
391 		goto out;
392 
393 	cp = path;
394 	while (*cp) {
395 
396 		/*
397 		 * Remove extra separators
398 		 */
399 		while (*cp == '/')
400 			cp++;
401 		if (*cp == '\0')
402 			break;
403 
404 		/*
405 		 * Check that current node is a directory.
406 		 */
407 		if ((fp->f_di.di_mode & IFMT) != IFDIR) {
408 			rc = ENOTDIR;
409 			goto out;
410 		}
411 
412 		/*
413 		 * Get next component of path name.
414 		 */
415 		{
416 			register int len = 0;
417 
418 			ncp = cp;
419 			while ((c = *cp) != '\0' && c != '/') {
420 				if (++len > MAXNAMLEN) {
421 					rc = ENOENT;
422 					goto out;
423 				}
424 				cp++;
425 			}
426 			*cp = '\0';
427 		}
428 
429 		/*
430 		 * Look up component in current directory.
431 		 * Save directory inumber in case we find a
432 		 * symbolic link.
433 		 */
434 		parent_inumber = inumber;
435 		rc = search_directory(ncp, f, &inumber);
436 		*cp = c;
437 		if (rc)
438 			goto out;
439 
440 		/*
441 		 * Open next component.
442 		 */
443 		if ((rc = read_inode(inumber, f)) != 0)
444 			goto out;
445 
446 #if 0
447 		/*
448 		 * Check for symbolic link.
449 		 */
450 		if ((fp->i_mode & IFMT) == IFLNK) {
451 			int link_len = fp->f_di.di_size;
452 			int len;
453 
454 			len = strlen(cp) + 1;
455 
456 			if (fp->f_di.di_size >= MAXPATHLEN - 1 ||
457 			    ++nlinks > MAXSYMLINKS) {
458 				rc = ENOENT;
459 				goto out;
460 			}
461 
462 			strcpy(&namebuf[link_len], cp);
463 
464 			if ((fp->i_flags & IC_FASTLINK) != 0) {
465 				bcopy(fp->i_symlink, namebuf, (unsigned) link_len);
466 			} else {
467 				/*
468 				 * Read file for symbolic link
469 				 */
470 				char *buf;
471 				u_int buf_size;
472 				daddr_t	disk_block;
473 				register struct fs *fs = fp->f_fs;
474 
475 				(void) block_map(f, (daddr_t)0, &disk_block);
476 				rc = device_read(&fp->f_dev,
477 						 fsbtodb(fs, disk_block),
478 						 blksize(fs, fp, 0),
479 						 &buf, &buf_size);
480 				if (rc)
481 					goto out;
482 
483 				bcopy((char *)buf, namebuf, (unsigned)link_len);
484 				free(buf, buf_size);
485 			}
486 
487 			/*
488 			 * If relative pathname, restart at parent directory.
489 			 * If absolute pathname, restart at root.
490 			 */
491 			cp = namebuf;
492 			if (*cp != '/')
493 				inumber = parent_inumber;
494 			else
495 				inumber = (ino_t)ROOTINO;
496 
497 			if ((rc = read_inode(inumber, fp)) != 0)
498 				goto out;
499 		}
500 #endif
501 	}
502 
503 	/*
504 	 * Found terminal component.
505 	 */
506 	rc = 0;
507 out:
508 	if (rc)
509 		free(fp, sizeof(struct file));
510 	return (rc);
511 }
512 
513 int
514 ufs_close(f)
515 	struct open_file *f;
516 {
517 	register struct file *fp = (struct file *)f->f_fsdata;
518 	int level;
519 
520 	f->f_fsdata = (void *)0;
521 	if (fp == (struct file *)0)
522 		return (0);
523 
524 	for (level = 0; level < NIADDR; level++) {
525 		if (fp->f_blk[level])
526 			free(fp->f_blk[level], fp->f_fs->fs_bsize);
527 	}
528 	if (fp->f_buf)
529 		free(fp->f_buf, fp->f_fs->fs_bsize);
530 	free(fp->f_fs, SBSIZE);
531 	free(fp, sizeof(struct file));
532 	return (0);
533 }
534 
535 /*
536  * Copy a portion of a file into kernel memory.
537  * Cross block boundaries when necessary.
538  */
539 int
540 ufs_read(f, start, size, resid)
541 	struct open_file *f;
542 	char *start;
543 	u_int size;
544 	u_int *resid;	/* out */
545 {
546 	register struct file *fp = (struct file *)f->f_fsdata;
547 	register u_int csize;
548 	char *buf;
549 	u_int buf_size;
550 	int rc = 0;
551 
552 	while (size != 0) {
553 		if (fp->f_seekp >= fp->f_di.di_size)
554 			break;
555 
556 		rc = buf_read_file(f, &buf, &buf_size);
557 		if (rc)
558 			break;
559 
560 		csize = size;
561 		if (csize > buf_size)
562 			csize = buf_size;
563 
564 		bcopy(buf, start, csize);
565 
566 		fp->f_seekp += csize;
567 		start += csize;
568 		size -= csize;
569 	}
570 	if (resid)
571 		*resid = size;
572 	return (rc);
573 }
574 
575 /*
576  * Not implemented.
577  */
578 int
579 ufs_write(f, start, size, resid)
580 	struct open_file *f;
581 	char *start;
582 	u_int size;
583 	u_int *resid;	/* out */
584 {
585 
586 	return (EROFS);
587 }
588 
589 off_t
590 ufs_seek(f, offset, where)
591 	struct open_file *f;
592 	off_t offset;
593 	int where;
594 {
595 	register struct file *fp = (struct file *)f->f_fsdata;
596 
597 	switch (where) {
598 	case SEEK_SET:
599 		fp->f_seekp = offset;
600 		break;
601 	case SEEK_CUR:
602 		fp->f_seekp += offset;
603 		break;
604 	case SEEK_END:
605 		fp->f_seekp = fp->f_di.di_size - offset;
606 		break;
607 	default:
608 		return (-1);
609 	}
610 	return (fp->f_seekp);
611 }
612 
613 int
614 ufs_stat(f, sb)
615 	struct open_file *f;
616 	struct stat *sb;
617 {
618 	register struct file *fp = (struct file *)f->f_fsdata;
619 
620 	/* only important stuff */
621 	sb->st_mode = fp->f_di.di_mode;
622 	sb->st_uid = fp->f_di.di_uid;
623 	sb->st_gid = fp->f_di.di_gid;
624 	sb->st_size = fp->f_di.di_size;
625 	return (0);
626 }
627