1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <sys/param.h>
27 #include <sys/vnode.h>
28 #include <sys/fs/ufs_fsdir.h>
29 #include <sys/fs/ufs_fs.h>
30 #include <sys/fs/ufs_inode.h>
31 #include <sys/sysmacros.h>
32 #include <sys/promif.h>
33 #include <sys/filep.h>
34 #include <sys/salib.h>
35 #include <sys/sacache.h>
36
37 #include <sys/fs/hsfs_spec.h>
38 #include <sys/fs/hsfs_isospec.h>
39 #include <sys/fs/hsfs_node.h>
40 #include <sys/fs/hsfs_susp.h>
41 #include <sys/fs/hsfs_rrip.h>
42
43 #include "hsfs_sig.h"
44
45 #include <sys/stat.h>
46 #include <sys/bootvfs.h>
47 #include <sys/bootconf.h>
48 #include <sys/bootdebug.h>
49
50 #define hdbtodb(n) ((ISO_SECTOR_SIZE / DEV_BSIZE) * (n))
51
52 #define THE_EPOCH 1970
53 #define END_OF_TIME 2099
54
55 /* May not need this... */
56 static uint_t sua_offset = 0;
57
58 /* The root inode on an HSFS filesystem can be anywhere! */
59 static uint_t root_ino = 0; /* This is both a flag and a value */
60
61 static fileid_t *head;
62
63 /* Only got one of these...ergo, only 1 fs open at once */
64 static devid_t *devp;
65
66 struct dirinfo {
67 int loc;
68 fileid_t *fi;
69 };
70
71 struct hs_direct {
72 struct direct hs_ufs_dir;
73 struct hs_direntry hs_dir;
74 };
75
76 /*
77 * Function prototypes
78 */
79
80 static int boot_hsfs_mountroot(char *str);
81 static int boot_hsfs_unmountroot(void);
82 static int boot_hsfs_open(char *filename, int flags);
83 static int boot_hsfs_close(int fd);
84 static ssize_t boot_hsfs_read(int fd, caddr_t buf, size_t size);
85 static off_t boot_hsfs_lseek(int, off_t, int);
86 static int boot_hsfs_fstat(int fd, struct bootstat *stp);
87 static void boot_hsfs_closeall(int flag);
88 static int boot_hsfs_getdents(int fd, struct dirent *dep, unsigned size);
89
90 struct boot_fs_ops boot_hsfs_ops = {
91 "hsfs",
92 boot_hsfs_mountroot,
93 boot_hsfs_unmountroot,
94 boot_hsfs_open,
95 boot_hsfs_close,
96 boot_hsfs_read,
97 boot_hsfs_lseek,
98 boot_hsfs_fstat,
99 boot_hsfs_closeall,
100 boot_hsfs_getdents
101 };
102
103 static ino_t find(fileid_t *, char *);
104 static ino_t dlook(fileid_t *, char *);
105 static int opendir(fileid_t *, ino_t);
106 static struct hs_direct *readdir(struct dirinfo *);
107 static uint_t parse_dir(fileid_t *, int, struct hs_direct *);
108 static uint_t parse_susp(char *, uint_t *, struct hs_direct *);
109 static void hs_seti(fileid_t *, struct hs_direct *, ino_t);
110 static void hs_dodates(enum hs_vol_type, struct hs_direntry *, char *);
111 static time_t hs_date_to_gmtime(int, int, int, int);
112
113 /*
114 * There is only 1 open (mounted) device at any given time.
115 * So we can keep a single, global devp file descriptor to
116 * use to index into the di[] array. This is not true for the
117 * fi[] array. We can have more than one file open at once,
118 * so there is no global fd for the fi[].
119 * The user program must save the fd passed back from open()
120 * and use it to do subsequent read()'s.
121 */
122
123 static int
opendir(fileid_t * filep,ino_t inode)124 opendir(fileid_t *filep, ino_t inode)
125 {
126 struct hs_direct hsdep;
127 int retval;
128
129 /* Set up the saio request */
130 filep->fi_offset = 0;
131 filep->fi_blocknum = hdbtodb(inode);
132 filep->fi_count = ISO_SECTOR_SIZE;
133
134 /* Maybe the block is in the disk block cache */
135 if ((filep->fi_memp = get_bcache(filep)) == NULL) {
136 /* Not in the block cache so read it from disk */
137 if (retval = set_bcache(filep)) {
138 return (retval);
139 }
140 }
141
142 filep->fi_offset = 0;
143 filep->fi_blocknum = hdbtodb(inode);
144
145 if (inode != root_ino)
146 return (0);
147
148 if ((int)(parse_dir(filep, 0, &hsdep)) > 0) {
149 hs_seti(filep, &hsdep, inode);
150 return (0);
151 }
152 return (1);
153 }
154
155 static ino_t
find(fileid_t * filep,char * path)156 find(fileid_t *filep, char *path)
157 {
158 register char *q;
159 char c;
160 ino_t inode;
161
162 if (path == NULL || *path == '\0') {
163 printf("null path\n");
164 return (0);
165 }
166
167 if ((boothowto & RB_DEBUG) && (boothowto & RB_VERBOSE))
168 printf("find(): path=<%s>\n", path);
169
170 /* Read the ROOT directory */
171 if (opendir(filep, inode = root_ino)) {
172 printf("find(): root_ino opendir() failed!\n");
173 return ((ino_t)-1);
174 }
175
176 while (*path) {
177 while (*path == '/')
178 path++;
179 if (*(q = path) == '\0')
180 break;
181 while (*q != '/' && *q != '\0')
182 q++;
183 c = *q;
184 *q = '\0';
185
186 if ((inode = dlook(filep, path)) != 0) {
187 if (c == '\0')
188 break;
189 if (opendir(filep, inode)) {
190 printf("find(): opendir(%d) failed!\n", inode);
191 *q = c;
192 return ((ino_t)-1);
193 }
194 *q = c;
195 path = q;
196 continue;
197 } else {
198 *q = c;
199 return (0);
200 }
201 }
202 return (inode);
203 }
204
205 static fileid_t *
find_fp(int fd)206 find_fp(int fd)
207 {
208 fileid_t *filep = head;
209
210 if (fd >= 0) {
211 while ((filep = filep->fi_forw) != head)
212 if (fd == filep->fi_filedes)
213 return (filep->fi_taken ? filep : 0);
214 }
215
216 return (0);
217 }
218
219 static ino_t
dlook(fileid_t * filep,char * path)220 dlook(fileid_t *filep, char *path)
221 {
222 int dv = filep->fi_devp->di_dcookie;
223 register struct hs_direct *hsdep;
224 register struct direct *udp;
225 register struct inode *ip;
226 struct dirinfo dirp;
227 register int len;
228 ino_t in;
229
230 ip = filep->fi_inode;
231 if (path == NULL || *path == '\0')
232 return (0);
233 if ((ip->i_smode & IFMT) != IFDIR) {
234 return (0);
235 }
236 if (ip->i_size == 0) {
237 return (0);
238 }
239 len = strlen(path);
240 /* first look through the directory entry cache */
241 if (in = get_dcache(dv, path, ip->i_number)) {
242 if ((filep->fi_inode = get_icache(dv, in)) != NULL) {
243 filep->fi_offset = 0;
244 filep->fi_blocknum = hdbtodb(in);
245 return (in);
246 }
247 }
248 dirp.loc = 0;
249 dirp.fi = filep;
250 for (hsdep = readdir(&dirp); hsdep != NULL; hsdep = readdir(&dirp)) {
251 udp = &hsdep->hs_ufs_dir;
252 if (udp->d_namlen == 1 &&
253 udp->d_name[0] == '.' &&
254 udp->d_name[1] == '\0')
255 continue;
256 if (udp->d_namlen == 2 &&
257 udp->d_name[0] == '.' &&
258 udp->d_name[1] == '.' &&
259 udp->d_name[2] == '\0')
260 continue;
261 if (udp->d_namlen == len && (strcmp(path, udp->d_name) == 0)) {
262 set_dcache(dv, path, ip->i_number, udp->d_ino);
263 hs_seti(filep, hsdep, udp->d_ino);
264 filep->fi_offset = 0;
265 filep->fi_blocknum = hdbtodb(udp->d_ino);
266 /* put this entry into the cache */
267 return (udp->d_ino);
268 }
269 /* Allow "*" to print all names at that level, w/out match */
270 if (strcmp(path, "*") == 0)
271 printf("%s\n", udp->d_name);
272 }
273 return (0);
274 }
275
276 /*
277 * get next entry in a directory.
278 */
279 static struct hs_direct *
readdir(struct dirinfo * dirp)280 readdir(struct dirinfo *dirp)
281 {
282 static struct hs_direct hsdep;
283 register struct direct *udp = &hsdep.hs_ufs_dir;
284 register struct inode *ip;
285 register fileid_t *filep;
286 register daddr_t lbn;
287 register int off;
288
289 filep = dirp->fi;
290 ip = filep->fi_inode;
291 for (;;) {
292 if (dirp->loc >= ip->i_size) {
293 return (NULL);
294 }
295 off = dirp->loc & ((1 << ISO_SECTOR_SHIFT) - 1);
296 if (off == 0) {
297 lbn = hdbtodb(dirp->loc >> ISO_SECTOR_SHIFT);
298 filep->fi_blocknum = lbn + hdbtodb(ip->i_number);
299 filep->fi_count = ISO_SECTOR_SIZE;
300 /* check the block cache */
301 if ((filep->fi_memp = get_bcache(filep)) == 0)
302 if (set_bcache(filep))
303 return ((struct hs_direct *)-1);
304 }
305 dirp->loc += parse_dir(filep, off, &hsdep);
306 if (udp->d_reclen == 0 && dirp->loc <= ip->i_size) {
307 dirp->loc = roundup(dirp->loc, ISO_SECTOR_SIZE);
308 continue;
309 }
310 return (&hsdep);
311 }
312 }
313
314 /*
315 * Get the next block of data from the file. If possible, dma right into
316 * user's buffer
317 */
318 static int
getblock(fileid_t * filep,caddr_t buf,int count,int * rcount)319 getblock(fileid_t *filep, caddr_t buf, int count, int *rcount)
320 {
321 register struct inode *ip;
322 register caddr_t p;
323 register int off, size, diff;
324 register daddr_t lbn;
325 static int pos;
326 static char ind[] = "|/-\\"; /* that's entertainment? */
327 static int blks_read;
328
329 ip = filep->fi_inode;
330 p = filep->fi_memp;
331 if ((signed)filep->fi_count <= 0) {
332
333 /* find the amt left to be read in the file */
334 diff = ip->i_size - filep->fi_offset;
335 if (diff <= 0) {
336 printf("Short read\n");
337 return (-1);
338 }
339
340 /* which block (or frag) in the file do we read? */
341 lbn = hdbtodb(filep->fi_offset >> ISO_SECTOR_SHIFT);
342
343 /* which physical block on the device do we read? */
344 filep->fi_blocknum = lbn + hdbtodb(ip->i_number);
345
346 off = filep->fi_offset & ((1 << ISO_SECTOR_SHIFT) - 1);
347
348 size = sizeof (filep->fi_buf);
349 if (size > ISO_SECTOR_SIZE)
350 size = ISO_SECTOR_SIZE;
351
352 filep->fi_count = size;
353 filep->fi_memp = filep->fi_buf;
354
355 /*
356 * optimization if we are reading large blocks of data then
357 * we can go directly to user's buffer
358 */
359 *rcount = 0;
360 if (off == 0 && count >= size) {
361 filep->fi_memp = buf;
362 if (diskread(filep)) {
363 return (-1);
364 }
365 *rcount = size;
366 filep->fi_count = 0;
367 read_opt++;
368 if ((blks_read++ & 0x3) == 0)
369 printf("%c\b", ind[pos++ & 3]);
370 return (0);
371 } else
372 if (diskread(filep))
373 return (-1);
374
375 /*
376 * round and round she goes (though not on every block..
377 * - OBP's take a fair bit of time to actually print stuff)
378 */
379 if ((blks_read++ & 0x3) == 0)
380 printf("%c\b", ind[pos++ & 3]);
381
382 if (filep->fi_offset - off + size >= ip->i_size)
383 filep->fi_count = diff + off;
384 filep->fi_count -= off;
385 p = &filep->fi_memp[off];
386 }
387 filep->fi_memp = p;
388 return (0);
389 }
390
391
392 /*
393 * This is the high-level read function. It works like this.
394 * We assume that our IO device buffers up some amount of
395 * data ant that we can get a ptr to it. Thus we need
396 * to actually call the device func about filesize/blocksize times
397 * and this greatly increases our IO speed. When we already
398 * have data in the buffer, we just return that data (with bcopy() ).
399 */
400
401 static ssize_t
boot_hsfs_read(int fd,caddr_t buf,size_t count)402 boot_hsfs_read(int fd, caddr_t buf, size_t count)
403 {
404 size_t i, j;
405 struct inode *ip;
406 caddr_t n;
407 fileid_t *filep;
408 int rcount;
409
410 if (!(filep = find_fp(fd))) {
411 return (-1);
412 }
413
414 ip = filep->fi_inode;
415
416 if (filep->fi_offset + count > ip->i_size)
417 count = ip->i_size - filep->fi_offset;
418
419 /* that was easy */
420 if ((i = count) == 0)
421 return (0);
422
423 n = buf;
424 while (i > 0) {
425 /* If we need to reload the buffer, do so */
426 if ((j = filep->fi_count) == 0) {
427 getblock(filep, buf, i, &rcount);
428 i -= rcount;
429 buf += rcount;
430 filep->fi_offset += rcount;
431 } else {
432 /* else just bcopy from our buffer */
433 j = MIN(i, j);
434 bcopy(filep->fi_memp, buf, (unsigned)j);
435 buf += j;
436 filep->fi_memp += j;
437 filep->fi_offset += j;
438 filep->fi_count -= j;
439 i -= j;
440 }
441 }
442 return (buf - n);
443 }
444
445 /*
446 * This routine will open a device as it is known by the
447 * V2 OBP.
448 * Interface Defn:
449 * err = mountroot(string);
450 * err: 0 on success
451 * -1 on failure
452 * string: char string describing the properties of the device.
453 * We must not dork with any fi[]'s here. Save that for later.
454 */
455
456 static int
boot_hsfs_mountroot(char * str)457 boot_hsfs_mountroot(char *str)
458 {
459 ihandle_t h;
460 struct hs_volume *fsp;
461 char *bufp;
462
463 if ((boothowto & RB_DEBUG) && (boothowto & RB_VERBOSE))
464 printf("mountroot()\n");
465
466 /*
467 * If already mounted, just return success.
468 */
469 if (root_ino != 0) {
470 return (0);
471 }
472
473 h = prom_open(str);
474
475 if (h == 0) {
476 printf("Cannot open %s\n", str);
477 return (-1);
478 }
479
480 devp = (devid_t *)bkmem_alloc(sizeof (devid_t));
481 devp->di_taken = 1;
482 devp->di_dcookie = h;
483 devp->di_desc = (char *)bkmem_alloc(strlen(str) + 1);
484 (void) strcpy(devp->di_desc, str);
485 bzero(devp->un_fs.dummy, sizeof (devp->un_fs.dummy));
486 head = (fileid_t *)bkmem_alloc(sizeof (fileid_t));
487 head->fi_back = head->fi_forw = head;
488 head->fi_filedes = 0;
489 head->fi_taken = 0;
490
491 /* Setup read of the "superblock" */
492 bzero(head->fi_buf, sizeof (head->fi_buf));
493 head->fi_devp = devp;
494 head->fi_blocknum = hdbtodb(ISO_VOLDESC_SEC);
495 head->fi_count = ISO_SECTOR_SIZE;
496 head->fi_memp = head->fi_buf;
497 head->fi_offset = 0;
498
499 if (diskread(head)) {
500 printf("mountroot(): read super block failed!\n");
501 boot_hsfs_closeall(1);
502 return (-1);
503 }
504
505 bufp = head->fi_memp;
506 fsp = (struct hs_volume *)devp->un_fs.dummy;
507 /* Since RRIP is based on ISO9660, that's where we start */
508
509 if (ISO_DESC_TYPE(bufp) != ISO_VD_PVD ||
510 strncmp((char *)(ISO_std_id(bufp)), (char *)(ISO_ID_STRING),
511 ISO_ID_STRLEN) != 0 || ISO_STD_VER(bufp) != ISO_ID_VER) {
512 boot_hsfs_closeall(1);
513 return (-1);
514 }
515
516 /* Now we fill in the volume descriptor */
517 fsp->vol_size = ISO_VOL_SIZE(bufp);
518 fsp->lbn_size = ISO_BLK_SIZE(bufp);
519 fsp->lbn_shift = ISO_SECTOR_SHIFT;
520 fsp->lbn_secshift = ISO_SECTOR_SHIFT;
521 fsp->vol_set_size = (ushort_t)ISO_SET_SIZE(bufp);
522 fsp->vol_set_seq = (ushort_t)ISO_SET_SEQ(bufp);
523
524 /* Make sure we have a valid logical block size */
525 if (fsp->lbn_size & ~(1 << fsp->lbn_shift)) {
526 printf("%d byte logical block size invalid.\n", fsp->lbn_size);
527 boot_hsfs_closeall(1);
528 return (-1);
529 }
530
531 /* Since an HSFS root could be located anywhere on the media! */
532 root_ino = IDE_EXT_LBN(ISO_root_dir(bufp));
533
534 if ((boothowto & RB_DEBUG) && (boothowto & RB_VERBOSE)) {
535 int i;
536
537 printf("root_ino=%d\n", root_ino);
538 printf("ID=");
539 for (i = 0; i < ISO_ID_STRLEN; i++)
540 printf("%c", *(ISO_std_id(bufp)+i));
541 printf(" VS=%d\n", fsp->vol_size);
542 }
543
544 return (0);
545 }
546
547 /*
548 * Unmount the currently mounted root fs. In practice, this means
549 * closing all open files and releasing resources. All of this
550 * is done by boot_hsfs_closeall().
551 */
552
553 int
boot_hsfs_unmountroot(void)554 boot_hsfs_unmountroot(void)
555 {
556 if (root_ino == 0)
557 return (-1);
558
559 boot_hsfs_closeall(1);
560
561 return (0);
562 }
563
564 /*
565 * We allocate an fd here for use when talking
566 * to the file itself.
567 */
568
569 /*ARGSUSED*/
570 static int
boot_hsfs_open(char * filename,int flags)571 boot_hsfs_open(char *filename, int flags)
572 {
573 fileid_t *filep;
574 ino_t inode;
575 static int filedes = 1;
576
577 /* build and link a new file descriptor */
578 filep = (fileid_t *)bkmem_alloc(sizeof (fileid_t));
579 filep->fi_back = head->fi_back;
580 filep->fi_forw = head;
581 head->fi_back->fi_forw = filep;
582 head->fi_back = filep;
583
584 filep->fi_filedes = filedes++;
585 filep->fi_taken = 1;
586 filep->fi_path = (char *)bkmem_alloc(strlen(filename) + 1);
587 (void) strcpy(filep->fi_path, filename);
588 filep->fi_devp = devp; /* dev is already "mounted" */
589
590 filep->fi_inode = 0;
591
592 inode = find(filep, filename);
593 if (inode == (ino_t)0) {
594 if ((boothowto & RB_DEBUG) && (boothowto & RB_VERBOSE))
595 printf("open(%s) ENOENT\n", filename);
596 (void) boot_hsfs_close(filep->fi_filedes);
597 return (-1);
598 }
599
600 filep->fi_blocknum = hdbtodb(inode);
601 filep->fi_offset = filep->fi_count = 0;
602
603 if ((boothowto & RB_DEBUG) && (boothowto & RB_VERBOSE))
604 printf("open(%s) fd=%d\n", filename, filep->fi_filedes);
605 return (filep->fi_filedes);
606 }
607
608 /*
609 * hsfs_fstat() only supports size, mode and times at present time.
610 */
611
612 static int
boot_hsfs_fstat(int fd,struct bootstat * stp)613 boot_hsfs_fstat(int fd, struct bootstat *stp)
614 {
615 fileid_t *filep;
616 struct inode *ip;
617
618 if (!(filep = find_fp(fd)))
619 return (-1);
620
621 ip = filep->fi_inode;
622
623 stp->st_mode = 0;
624 stp->st_size = 0;
625
626 if (ip == NULL)
627 return (0);
628
629 switch (ip->i_smode & IFMT) {
630 case IFDIR:
631 stp->st_mode = S_IFDIR;
632 break;
633 case IFREG:
634 stp->st_mode = S_IFREG;
635 break;
636 default:
637 break;
638 }
639 stp->st_size = ip->i_size;
640
641 /* file times */
642 stp->st_atim.tv_sec = ip->i_atime.tv_sec;
643 stp->st_atim.tv_nsec = ip->i_atime.tv_usec * 1000;
644 stp->st_mtim.tv_sec = ip->i_mtime.tv_sec;
645 stp->st_mtim.tv_nsec = ip->i_mtime.tv_usec * 1000;
646 stp->st_ctim.tv_sec = ip->i_ctime.tv_sec;
647 stp->st_ctim.tv_nsec = ip->i_ctime.tv_usec * 1000;
648
649 return (0);
650 }
651
652 /*
653 * We don't do any IO here.
654 * We just play games with the device pointers.
655 */
656
657 /*ARGSUSED*/
658 static off_t
boot_hsfs_lseek(int fd,off_t addr,int whence)659 boot_hsfs_lseek(int fd, off_t addr, int whence)
660 {
661 fileid_t *filep;
662
663 if (!(filep = find_fp(fd)))
664 return (-1);
665
666 filep->fi_offset = addr;
667 filep->fi_blocknum = addr / DEV_BSIZE;
668 filep->fi_count = 0;
669
670 return (0);
671 }
672
673 static int
boot_hsfs_close(int fd)674 boot_hsfs_close(int fd)
675 {
676 fileid_t *filep;
677
678 if ((boothowto & RB_DEBUG) && (boothowto & RB_VERBOSE))
679 printf("close(%d)\n", fd);
680
681 if (filep = find_fp(fd)) {
682 /* Clear the ranks */
683 bkmem_free(filep->fi_path, strlen(filep->fi_path)+1);
684 filep->fi_blocknum = filep->fi_count = filep->fi_offset = 0;
685 filep->fi_memp = (caddr_t)0;
686 filep->fi_devp = 0;
687 filep->fi_taken = 0;
688
689 /* unlink and deallocate node */
690 filep->fi_forw->fi_back = filep->fi_back;
691 filep->fi_back->fi_forw = filep->fi_forw;
692 bkmem_free((char *)filep, sizeof (fileid_t));
693
694 return (0);
695 } else {
696 /* Big problem */
697 printf("\nFile descrip %d not allocated!", fd);
698 return (-1);
699 }
700 }
701
702 /* closeall is now idempotent */
703 /*ARGSUSED*/
704 static void
boot_hsfs_closeall(int flag)705 boot_hsfs_closeall(int flag)
706 {
707 fileid_t *filep = head;
708 extern int verbosemode;
709
710 if (devp == NULL) {
711 if (head)
712 prom_panic("boot_hsfs_closeall: head != NULL.\n");
713 return;
714 }
715
716 while ((filep = filep->fi_forw) != head)
717 if (filep->fi_taken)
718 if (boot_hsfs_close(filep->fi_filedes))
719 prom_panic("Filesystem may be inconsistent.\n");
720
721
722 release_cache(devp->di_dcookie);
723 (void) prom_close(devp->di_dcookie);
724 devp->di_taken = 0;
725 if (verbosemode)
726 print_cache_data();
727 bkmem_free((char *)devp, sizeof (devid_t));
728 bkmem_free((char *)head, sizeof (fileid_t));
729 root_ino = 0;
730 devp = NULL;
731 head = NULL;
732 }
733
734 static uint_t
parse_dir(fileid_t * filep,int offset,struct hs_direct * hsdep)735 parse_dir(fileid_t *filep, int offset, struct hs_direct *hsdep)
736 {
737 char *bufp = (char *)(filep->fi_memp + offset);
738 struct direct *udp = &hsdep->hs_ufs_dir;
739 struct hs_direntry *hdp = &hsdep->hs_dir;
740 uint_t ce_lbn;
741 uint_t ce_len;
742 uint_t nmlen;
743 uint_t i;
744 uchar_t c;
745 int ret_code = 0;
746
747 if ((udp->d_reclen = IDE_DIR_LEN(bufp)) == 0)
748 return (0);
749
750 hdp->ext_lbn = IDE_EXT_LBN(bufp);
751 hdp->ext_size = IDE_EXT_SIZE(bufp);
752 hs_dodates(HS_VOL_TYPE_ISO, hdp, bufp);
753 hdp->xar_len = IDE_XAR_LEN(bufp);
754 hdp->intlf_sz = IDE_INTRLV_SIZE(bufp);
755 hdp->intlf_sk = IDE_INTRLV_SKIP(bufp);
756 hdp->sym_link = NULL;
757
758 udp->d_ino = hdp->ext_lbn;
759
760 c = IDE_FLAGS(bufp);
761 if (IDE_REGULAR_FILE(c)) {
762 hdp->type = VREG;
763 hdp->mode = IFREG;
764 hdp->nlink = 1;
765 } else if (IDE_REGULAR_DIR(c)) {
766 hdp->type = VDIR;
767 hdp->mode = IFDIR;
768 hdp->nlink = 2;
769 } else {
770 printf("parse_dir(): file type=0x%x unknown.\n", c);
771 return ((uint_t)-1);
772 }
773
774 /* Some initial conditions */
775 nmlen = IDE_NAME_LEN(bufp);
776 c = *IDE_NAME(bufp);
777 /* Special Case: Current Directory */
778 if (nmlen == 1 && c == '\0') {
779 udp->d_name[0] = '.';
780 udp->d_name[1] = '\0';
781 udp->d_namlen = 1;
782 /* Special Case: Parent Directory */
783 } else if (nmlen == 1 && c == '\001') {
784 udp->d_name[0] = '.';
785 udp->d_name[1] = '.';
786 udp->d_name[2] = '\0';
787 udp->d_namlen = 2;
788 /* Other file name */
789 } else {
790 udp->d_namlen = 0;
791 for (i = 0; i < nmlen; i++) {
792 c = *(IDE_name(bufp)+i);
793 if (c == ';')
794 break;
795 else if (c == ' ')
796 continue;
797 else
798 udp->d_name[udp->d_namlen++] = c;
799 }
800 udp->d_name[udp->d_namlen] = '\0';
801 }
802 /* System Use Fields */
803 ce_len = IDE_SUA_LEN(bufp);
804 ce_lbn = 0;
805 if ((int)(ce_len) > 0) {
806 ce_lbn = parse_susp((char *)IDE_sys_use_area(bufp),
807 &ce_len, hsdep);
808 while (ce_lbn) {
809 daddr_t save_blocknum = filep->fi_blocknum;
810 daddr_t save_offset = filep->fi_offset;
811 caddr_t save_memp = filep->fi_memp;
812 uint_t save_count = filep->fi_count;
813
814 #ifdef noisy
815 print_io_req(filep, "parse_dir(): [I]");
816 #endif /* noisy */
817
818 filep->fi_blocknum = hdbtodb(ce_lbn);
819 filep->fi_offset = 0;
820 filep->fi_count = ISO_SECTOR_SIZE;
821
822 #ifdef noisy
823 print_io_req(filep, "parse_dir(): [0]");
824 #endif /* noisy */
825
826 if ((filep->fi_memp = get_bcache(filep)) == 0)
827 ret_code = set_bcache(filep);
828
829 #ifdef noisy
830 print_io_req(filep, "parse_dir(): [1]");
831 #endif /* noisy */
832
833 if (ret_code) {
834 filep->fi_blocknum = save_blocknum;
835 filep->fi_offset = save_offset;
836 filep->fi_memp = save_memp;
837 filep->fi_count = save_count;
838 printf("parse_dir(): "
839 "set_bcache() failed (%d)\n", ret_code);
840 break;
841 }
842 ce_lbn = parse_susp(filep->fi_memp, &ce_len, hsdep);
843
844 filep->fi_blocknum = save_blocknum;
845 filep->fi_offset = save_offset;
846 filep->fi_memp = save_memp;
847 filep->fi_count = save_count;
848
849 #ifdef noisy
850 print_io_req(filep, "parse_dir(): [2]");
851 #endif /* noisy */
852 }
853 }
854
855 return (udp->d_reclen);
856 }
857
858 static uint_t
parse_susp(char * bufp,uint_t * ce_len,struct hs_direct * hsdep)859 parse_susp(char *bufp, uint_t *ce_len, struct hs_direct *hsdep)
860 {
861 struct direct *udp = &hsdep->hs_ufs_dir;
862 uchar_t *susp;
863 uint_t cur_off = 0;
864 uint_t blk_len = *ce_len;
865 uint_t susp_len = 0;
866 uint_t ce_lbn = 0;
867 uint_t i;
868
869 while (cur_off < blk_len) {
870 susp = (uchar_t *)(bufp + cur_off);
871 if (susp[0] == '\0' || susp[1] == '\0')
872 break;
873 susp_len = SUF_LEN(susp);
874 if (susp_len == 0)
875 break;
876 for (i = 0; i < hsfs_num_sig; i++) {
877 if (strncmp(hsfs_sig_tab[i],
878 (char *)susp, SUF_SIG_LEN) == 0) {
879 #ifdef noisy
880 if ((boothowto & RB_DEBUG) &&
881 (boothowto & RB_VERBOSE))
882 printf(" SUSP_%c%c %d\n",
883 susp[0], susp[1], susp_len);
884 #endif /* noisy */
885 switch (i) {
886 case SUSP_SP_IX:
887 if (CHECK_BYTES_OK(susp)) {
888 sua_offset =
889 SP_SUA_OFFSET(susp);
890 #ifdef lint
891 /* this may not be needed */
892 i = (int)sua_offset;
893 #endif /* lint */
894 }
895 break;
896
897 case SUSP_CE_IX:
898 ce_lbn = CE_BLK_LOC(susp);
899 *ce_len = CE_CONT_LEN(susp);
900 #ifdef noisy
901 if ((boothowto & RB_DEBUG) &&
902 (boothowto & RB_VERBOSE))
903 printf("parse_susp(): "
904 "CE: ce_lbn = %d "
905 "ce_len=%d\n",
906 ce_lbn, *ce_len);
907 #endif /* noisy */
908 break;
909
910 case SUSP_ST_IX:
911 printf("parse_susp(): ST: returning "
912 "%d\n", ce_lbn);
913 return (ce_lbn);
914
915 case RRIP_SL_IX:
916 #ifdef noisy
917 if ((boothowto & RB_DEBUG) &&
918 (boothowto & RB_VERBOSE))
919 printf("parse_susp(): "
920 "******* SL *******\n");
921 #endif /* noisy */
922 break;
923
924 case RRIP_RR_IX:
925 break;
926
927 case RRIP_NM_IX:
928 if (!RRIP_NAME_FLAGS(susp)) {
929 udp->d_namlen =
930 RRIP_NAME_LEN(susp);
931 bcopy((char *)RRIP_name(susp),
932 (char *)udp->d_name,
933 udp->d_namlen);
934 udp->d_name
935 [udp->d_namlen] = '\0';
936 }
937 break;
938 }
939 cur_off += susp_len;
940 break;
941 }
942 }
943 if (i > hsfs_num_sig) {
944 printf("parse_susp(): Bad SUSP\n");
945 cur_off = blk_len;
946 break;
947 }
948 }
949 return (ce_lbn);
950 }
951
952 static void
hs_seti(fileid_t * filep,struct hs_direct * hsdep,ino_t inode)953 hs_seti(fileid_t *filep, struct hs_direct *hsdep, ino_t inode)
954 {
955 register struct inode *ip;
956 int dv = filep->fi_devp->di_dcookie;
957
958 /* Try the inode cache first */
959 if ((filep->fi_inode = get_icache(dv, inode)) != NULL)
960 return;
961
962 filep->fi_inode = (struct inode *)bkmem_alloc(sizeof (struct inode));
963 ip = filep->fi_inode;
964 bzero((char *)ip, sizeof (struct inode));
965 ip->i_size = hsdep->hs_dir.ext_size;
966 ip->i_smode = hsdep->hs_dir.mode;
967 ip->i_number = inode;
968 ip->i_atime.tv_sec = hsdep->hs_dir.adate.tv_sec;
969 ip->i_atime.tv_usec = hsdep->hs_dir.adate.tv_usec;
970 ip->i_ctime.tv_sec = hsdep->hs_dir.cdate.tv_sec;
971 ip->i_ctime.tv_usec = hsdep->hs_dir.cdate.tv_usec;
972 ip->i_mtime.tv_sec = hsdep->hs_dir.mdate.tv_sec;
973 ip->i_mtime.tv_usec = hsdep->hs_dir.mdate.tv_usec;
974 set_icache(dv, inode, ip, sizeof (struct inode));
975 }
976
977 #ifdef noisy
978 static void
print_io_req(fileid_t * filep,char * str)979 print_io_req(fileid_t *filep, char *str)
980 {
981 printf("%s o=%d b=%d c=%d m=%x\n",
982 str,
983 filep->fi_offset,
984 filep->fi_blocknum,
985 filep->fi_count,
986 (uint_t)filep->fi_memp);
987 }
988 #endif /* noisy */
989
990 static int
boot_hsfs_getdents(int fd,struct dirent * dep,unsigned size)991 boot_hsfs_getdents(int fd, struct dirent *dep, unsigned size)
992 {
993 /*
994 * Read directory entries from the file open on "fd" into the
995 * "size"-byte buffer at "dep" until the buffer is exhausted
996 * or we reach EOF on the directory. Returns the number of
997 * entries read.
998 */
999 int n;
1000 int cnt = 0;
1001 struct dirinfo dir;
1002 struct hs_direct *hdp;
1003 unsigned long oldoff, oldblok;
1004
1005 #define SLOP (sizeof (struct dirent) - offsetof(struct dirent, d_name[1]))
1006
1007 if (!(dir.fi = find_fp(fd)) ||
1008 ((dir.fi->fi_inode->i_smode & IFMT) != IFDIR)) {
1009 /*
1010 * Bogus file descriptor, bail out now!
1011 */
1012 return (-1);
1013 }
1014
1015 oldoff = dir.loc = dir.fi->fi_offset;
1016 oldblok = dir.fi->fi_blocknum;
1017
1018 for (hdp = readdir(&dir); hdp; hdp = readdir(&dir)) {
1019 /*
1020 * Compute name length and break loop if there's not
1021 * enough space in the output buffer for the next
1022 * entry.
1023 *
1024 * NOTE: "SLOP" is the number of bytes inserted into the dirent
1025 * struct's "d_name" field by the compiler to preserve
1026 * alignment.
1027 */
1028 n = strlen(hdp->hs_ufs_dir.d_name);
1029 n = roundup((sizeof (struct dirent) + ((n > SLOP) ? n : 0)),
1030 sizeof (off_t));
1031
1032 if (n > size) {
1033 dir.fi->fi_blocknum = oldblok;
1034 dir.fi->fi_offset = oldoff;
1035 break;
1036 }
1037
1038 oldblok = dir.fi->fi_blocknum;
1039 oldoff = dir.loc;
1040 size -= n;
1041 cnt += 1;
1042
1043 (void) strcpy(dep->d_name, hdp->hs_ufs_dir.d_name);
1044 dep->d_ino = hdp->hs_ufs_dir.d_ino;
1045 dep->d_off = dir.loc;
1046 dep->d_reclen = (unsigned short)n;
1047
1048 dep = (struct dirent *)((char *)dep + n);
1049 }
1050
1051 #undef SLOP
1052
1053 return (cnt);
1054 }
1055
1056 static void
hs_dodates(enum hs_vol_type type,struct hs_direntry * hdp,char * bufp)1057 hs_dodates(enum hs_vol_type type, struct hs_direntry *hdp, char *bufp)
1058 {
1059 if (type == HS_VOL_TYPE_HS) {
1060 hs_parse_dirdate(HDE_cdate(bufp), &hdp->cdate);
1061 hs_parse_dirdate(HDE_cdate(bufp), &hdp->adate);
1062 hs_parse_dirdate(HDE_cdate(bufp), &hdp->mdate);
1063 } else if (type == HS_VOL_TYPE_ISO) {
1064 hs_parse_dirdate(IDE_cdate(bufp), &hdp->cdate);
1065 hs_parse_dirdate(IDE_cdate(bufp), &hdp->adate);
1066 hs_parse_dirdate(IDE_cdate(bufp), &hdp->mdate);
1067 } else
1068 prom_panic("hs_dodates: bad volume type");
1069 }
1070
1071 /*
1072 * hs_parse_dirdate
1073 *
1074 * Parse the short 'directory-format' date into a Unix timeval.
1075 * This is the date format used in Directory Entries.
1076 *
1077 * If the date is not representable, make something up.
1078 */
1079 void
hs_parse_dirdate(uchar_t * dp,struct timeval * tvp)1080 hs_parse_dirdate(uchar_t *dp, struct timeval *tvp)
1081 {
1082 int year, month, day, hour, minute, sec, gmtoff;
1083
1084 year = HDE_DATE_YEAR(dp);
1085 month = HDE_DATE_MONTH(dp);
1086 day = HDE_DATE_DAY(dp);
1087 hour = HDE_DATE_HOUR(dp);
1088 minute = HDE_DATE_MIN(dp);
1089 sec = HDE_DATE_SEC(dp);
1090 gmtoff = HDE_DATE_GMTOFF(dp);
1091
1092 tvp->tv_usec = 0;
1093 if (year < THE_EPOCH) {
1094 tvp->tv_sec = 0;
1095 } else {
1096 tvp->tv_sec = hs_date_to_gmtime(year, month, day, gmtoff);
1097 if (tvp->tv_sec != -1) {
1098 tvp->tv_sec += ((hour * 60) + minute) * 60 + sec;
1099 }
1100 }
1101
1102 return;
1103
1104 }
1105
1106 /*
1107 * hs_parse_longdate
1108 *
1109 * Parse the long 'user-oriented' date into a Unix timeval.
1110 * This is the date format used in the Volume Descriptor.
1111 *
1112 * If the date is not representable, make something up.
1113 */
1114 void
hs_parse_longdate(uchar_t * dp,struct timeval * tvp)1115 hs_parse_longdate(uchar_t *dp, struct timeval *tvp)
1116 {
1117 int year, month, day, hour, minute, sec, gmtoff;
1118
1119 year = HSV_DATE_YEAR(dp);
1120 month = HSV_DATE_MONTH(dp);
1121 day = HSV_DATE_DAY(dp);
1122 hour = HSV_DATE_HOUR(dp);
1123 minute = HSV_DATE_MIN(dp);
1124 sec = HSV_DATE_SEC(dp);
1125 gmtoff = HSV_DATE_GMTOFF(dp);
1126
1127 tvp->tv_usec = 0;
1128 if (year < THE_EPOCH) {
1129 tvp->tv_sec = 0;
1130 } else {
1131 tvp->tv_sec = hs_date_to_gmtime(year, month, day, gmtoff);
1132 if (tvp->tv_sec != -1) {
1133 tvp->tv_sec += ((hour * 60) + minute) * 60 + sec;
1134 tvp->tv_usec = HSV_DATE_HSEC(dp) * 10000;
1135 }
1136 }
1137
1138 }
1139
1140 /* cumulative number of seconds per month, non-leap and leap-year versions */
1141 static time_t cum_sec[] = {
1142 0x0, 0x28de80, 0x4dc880, 0x76a700, 0x9e3400, 0xc71280,
1143 0xee9f80, 0x1177e00, 0x1405c80, 0x167e980, 0x190c800, 0x1b85500
1144 };
1145 static time_t cum_sec_leap[] = {
1146 0x0, 0x28de80, 0x4f1a00, 0x77f880, 0x9f8580, 0xc86400,
1147 0xeff100, 0x118cf80, 0x141ae00, 0x1693b00, 0x1921980, 0x1b9a680
1148 };
1149 #define SEC_PER_DAY 0x15180
1150 #define SEC_PER_YEAR 0x1e13380
1151
1152 /*
1153 * hs_date_to_gmtime
1154 *
1155 * Convert year(1970-2099)/month(1-12)/day(1-31) to seconds-since-1970/1/1.
1156 *
1157 * Returns -1 if the date is out of range.
1158 */
1159 static time_t
hs_date_to_gmtime(int year,int mon,int day,int gmtoff)1160 hs_date_to_gmtime(int year, int mon, int day, int gmtoff)
1161 {
1162 time_t sum;
1163 time_t *cp;
1164 int y;
1165
1166 if ((year < THE_EPOCH) || (year > END_OF_TIME) ||
1167 (mon < 1) || (mon > 12) ||
1168 (day < 1) || (day > 31))
1169 return (-1);
1170
1171 /*
1172 * Figure seconds until this year and correct for leap years.
1173 * Note: 2000 is a leap year but not 2100.
1174 */
1175 y = year - THE_EPOCH;
1176 sum = y * SEC_PER_YEAR;
1177 sum += ((y + 1) / 4) * SEC_PER_DAY;
1178 /*
1179 * Point to the correct table for this year and
1180 * add in seconds until this month.
1181 */
1182 cp = ((y + 2) % 4) ? cum_sec : cum_sec_leap;
1183 sum += cp[mon - 1];
1184 /*
1185 * Add in seconds until 0:00 of this day.
1186 * (days-per-month validation is not done here)
1187 */
1188 sum += (day - 1) * SEC_PER_DAY;
1189 sum -= (gmtoff * 15 * 60);
1190 return (sum);
1191 }
1192