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