Home | History | Annotate | Line # | Download | only in libsa
ustarfs.c revision 1.8.4.1
      1  1.8.4.1  thorpej /*	$NetBSD: ustarfs.c,v 1.8.4.1 1999/07/01 23:43:49 thorpej Exp $	*/
      2      1.1     ross 
      3      1.1     ross /* [Notice revision 2.2]
      4      1.1     ross  * Copyright (c) 1997, 1998 Avalon Computer Systems, Inc.
      5      1.1     ross  * All rights reserved.
      6      1.1     ross  *
      7      1.1     ross  * Author: Ross Harvey
      8      1.1     ross  *
      9      1.1     ross  * Redistribution and use in source and binary forms, with or without
     10      1.1     ross  * modification, are permitted provided that the following conditions
     11      1.1     ross  * are met:
     12      1.1     ross  * 1. Redistributions of source code must retain the above copyright and
     13      1.1     ross  *    author notice, this list of conditions, and the following disclaimer.
     14      1.1     ross  * 2. Redistributions in binary form must reproduce the above copyright
     15      1.1     ross  *    notice, this list of conditions and the following disclaimer in the
     16      1.1     ross  *    documentation and/or other materials provided with the distribution.
     17      1.1     ross  * 3. Neither the name of Avalon Computer Systems, Inc. nor the names of
     18      1.1     ross  *    its contributors may be used to endorse or promote products derived
     19      1.1     ross  *    from this software without specific prior written permission.
     20      1.1     ross  * 4. This copyright will be assigned to The NetBSD Foundation on
     21      1.1     ross  *    1/1/2000 unless these terms (including possibly the assignment
     22      1.1     ross  *    date) are updated in writing by Avalon prior to the latest specified
     23      1.1     ross  *    assignment date.
     24      1.1     ross  *
     25      1.1     ross  * THIS SOFTWARE IS PROVIDED BY AVALON COMPUTER SYSTEMS, INC. AND CONTRIBUTORS
     26      1.1     ross  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     27      1.1     ross  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     28      1.1     ross  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL AVALON OR THE CONTRIBUTORS
     29      1.1     ross  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     30      1.1     ross  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     31      1.1     ross  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     32      1.1     ross  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     33      1.1     ross  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     34      1.1     ross  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     35      1.1     ross  * POSSIBILITY OF SUCH DAMAGE.
     36      1.1     ross  */
     37      1.1     ross 
     38      1.1     ross 
     39      1.1     ross /*
     40      1.1     ross  ******************************* USTAR FS *******************************
     41      1.1     ross  */
     42      1.1     ross 
     43      1.1     ross /*
     44      1.1     ross  * Implement an ROFS with an 8K boot area followed by ustar-format data.
     45      1.1     ross  * The point: minimal FS overhead, and it's easy (well, `possible') to
     46      1.1     ross  * split files over multiple volumes.
     47      1.1     ross  *
     48      1.1     ross  * XXX - TODO LIST
     49      1.1     ross  * --- - ---- ----
     50      1.1     ross  * XXX - tag volume numbers and verify that the correct volume is
     51      1.1     ross  *       inserted after volume swaps.
     52      1.1     ross  *
     53      1.1     ross  * XXX - stop hardwiring FS metadata for floppies...embed it in a file,
     54      1.1     ross  * 	 file name, or something. (Remember __SYMDEF? :-)
     55      1.1     ross  *
     56      1.8      cgd  * XXX Does not currently implement:
     57      1.8      cgd  * XXX
     58      1.8      cgd  * XXX LIBSA_NO_FS_CLOSE
     59      1.8      cgd  * XXX LIBSA_NO_FS_SEEK
     60      1.8      cgd  * XXX LIBSA_NO_FS_WRITE
     61      1.8      cgd  * XXX LIBSA_NO_FS_SYMLINK (does this even make sense?)
     62      1.8      cgd  * XXX LIBSA_FS_SINGLECOMPONENT
     63      1.1     ross  */
     64      1.1     ross 
     65      1.5     matt #ifdef _STANDALONE
     66      1.1     ross #include <lib/libkern/libkern.h>
     67      1.5     matt #else
     68      1.5     matt #include <string.h>
     69      1.5     matt #endif
     70      1.1     ross #include "stand.h"
     71      1.1     ross #include "ustarfs.h"
     72      1.1     ross 
     73      1.2     ross #define	BBSIZE	8192
     74      1.1     ross #define	USTAR_NAME_BLOCK 512
     75      1.1     ross 
     76      1.2     ross /*
     77      1.2     ross  * Virtual offset: relative to start of ustar archive
     78      1.2     ross  * Logical offset: volume-relative
     79      1.2     ross  * Physical offset: the usual meaning
     80      1.2     ross  */
     81      1.2     ross 
     82      1.2     ross /* virtual offset to volume number */
     83      1.2     ross 
     84      1.2     ross #define	vda2vn(_v,_volsize) ((_v) / (_volsize))
     85      1.2     ross 
     86      1.2     ross /* conversions between the three different levels of disk addresses */
     87      1.2     ross 
     88      1.2     ross #define	vda2lda(_v,_volsize) ((_v) % (_volsize))
     89      1.2     ross #define	lda2vda(_v,_volsize,_volnumber) ((_v) + (_volsize) * (_volnumber))
     90      1.2     ross 
     91      1.2     ross #define	lda2pda(_lda) ((_lda) + ustarfs_mode_offset)
     92      1.2     ross #define	pda2lda(_pda) ((_pda) - ustarfs_mode_offset)
     93      1.2     ross /*
     94      1.2     ross  * Change this to off_t if you want to support big volumes. If we only use
     95      1.2     ross  * ustarfs on floppies it can stay int for libsa code density.
     96      1.2     ross  *
     97      1.2     ross  * It needs to be signed.
     98      1.2     ross  */
     99      1.2     ross typedef	int ustoffs;
    100      1.2     ross 
    101      1.1     ross typedef struct ustar_struct {
    102      1.1     ross 	char	ust_name[100],
    103      1.1     ross 		ust_mode[8],
    104      1.1     ross 		ust_uid[8],
    105      1.1     ross 		ust_gid[8],
    106      1.1     ross 		ust_size[12],
    107      1.1     ross 		ust_misc[12 + 8 + 1 + 100],
    108      1.1     ross 		ust_magic[6];
    109      1.1     ross 	/* there is more, but we don't care */
    110      1.1     ross } ustar_t;
    111      1.1     ross 
    112      1.1     ross /*
    113      1.1     ross  * We buffer one even cylindar of data...it's actually only really one
    114      1.1     ross  * cyl on a 1.44M floppy, but on other devices it's fast enough with any
    115      1.1     ross  * kind of block buffering, so we optimize for the slowest device.
    116      1.1     ross  */
    117      1.1     ross 
    118      1.1     ross typedef struct ust_active_struct {
    119      1.1     ross 	ustar_t	uas_active;
    120      1.1     ross 	char	uas_1cyl[18 * 2 * 512];
    121      1.2     ross 	ustoffs	uas_volsize;		/* XXX this is hardwired now */
    122      1.2     ross 	ustoffs	uas_windowbase;		/* relative to volume 0 */
    123      1.2     ross 	ustoffs	uas_filestart;		/* relative to volume 0 */
    124      1.2     ross 	ustoffs	uas_fseek;		/* relative to file */
    125      1.2     ross 	ustoffs	uas_filesize;		/* relative to volume 0 */
    126      1.1     ross 	int	uas_init_window;	/* data present in window */
    127      1.1     ross 	int	uas_init_fs;		/* ust FS actually found */
    128      1.2     ross 	int	uas_volzerosig;		/* ID volume 0 by signature */
    129      1.2     ross 	int	uas_offset;		/* amount of cylinder below lba 0 */
    130      1.1     ross } ust_active_t;
    131      1.1     ross 
    132      1.3     ross static const char formatid[] = "USTARFS",
    133      1.3     ross 		  metaname[] = "USTAR.volsize.";
    134      1.1     ross 
    135      1.1     ross static int ustarfs_mode_offset = BBSIZE;
    136      1.1     ross 
    137      1.2     ross static int checksig __P((ust_active_t *));
    138      1.3     ross static int convert __P((const char *, int, int));
    139      1.2     ross static int get_volume __P((struct open_file *, int));
    140      1.3     ross static void setwindow(ust_active_t *, ustoffs, ustoffs);
    141      1.3     ross static int ustarfs_cylinder_read __P((struct open_file *, ustoffs, int));
    142      1.1     ross static void ustarfs_sscanf __P((const char *, const char *, int *));
    143      1.2     ross static int read512block __P((struct open_file *, ustoffs, char block[512]));
    144      1.1     ross 
    145      1.1     ross static int
    146      1.1     ross convert(f, base, fw)
    147      1.1     ross 	const char *f;
    148      1.1     ross 	int base, fw;
    149      1.1     ross {
    150      1.1     ross 	int	i, c, result = 0;
    151      1.1     ross 
    152      1.1     ross 	while(fw > 0 && *f == ' ') {
    153      1.1     ross 		--fw;
    154      1.1     ross 		++f;
    155      1.1     ross 	}
    156      1.1     ross 	for(i = 0; i < fw; ++i) {
    157      1.1     ross 		c = f[i];
    158      1.1     ross 		if ('0' <= c && c < '0' + base) {
    159      1.1     ross 			c -= '0';
    160      1.1     ross 			result = result * base + c;
    161      1.1     ross 		} else	break;
    162      1.1     ross 	}
    163      1.1     ross 	return result;
    164      1.1     ross }
    165      1.1     ross 
    166      1.1     ross static void
    167      1.1     ross ustarfs_sscanf(s,f,xi)
    168      1.1     ross 	const char *s,*f;
    169      1.1     ross 	int *xi;
    170      1.1     ross {
    171      1.1     ross 	*xi = convert(s, 8, convert(f + 1, 10, 99));
    172      1.1     ross }
    173      1.1     ross 
    174      1.1     ross static int
    175      1.3     ross ustarfs_cylinder_read(f, seek2, forcelabel)
    176      1.1     ross 	struct open_file *f;
    177      1.2     ross 	ustoffs seek2;
    178      1.1     ross {
    179      1.4      bad 	int e = 0;	/* XXX work around gcc warning */
    180      1.3     ross 	ustoffs	lda;
    181      1.3     ross 	char *xferbase;
    182      1.1     ross 	ust_active_t *ustf;
    183      1.3     ross 	size_t	xferrqst, xfercount;
    184      1.1     ross 
    185      1.1     ross 	ustf = f->f_fsdata;
    186      1.3     ross 	xferrqst = sizeof ustf->uas_1cyl;
    187      1.3     ross 	xferbase = ustf->uas_1cyl;
    188      1.3     ross 	lda = pda2lda(seek2);
    189      1.3     ross 	if (lda < 0) {
    190      1.3     ross 		lda = -lda;
    191      1.3     ross 		ustf->uas_offset = lda;
    192      1.3     ross 		/*
    193      1.3     ross 		 * don't read the label unless we have to. (Preserve
    194      1.3     ross 		 * sequential block access so tape boot works.)
    195      1.3     ross 		 */
    196      1.3     ross 		if (!forcelabel) {
    197      1.3     ross 			memset(xferbase, 0, lda);
    198      1.3     ross 			xferrqst -= lda;
    199      1.3     ross 			xferbase += lda;
    200      1.3     ross 			seek2    += lda;
    201      1.3     ross 		}
    202      1.3     ross 	} else
    203      1.3     ross 		ustf->uas_offset = 0;
    204      1.3     ross 	while(xferrqst > 0) {
    205  1.8.4.1  thorpej #if !defined(LIBSA_NO_TWIDDLE)
    206  1.8.4.1  thorpej 		twiddle();
    207  1.8.4.1  thorpej #endif
    208      1.8      cgd 		e = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, seek2 / 512,
    209      1.3     ross 			xferrqst, xferbase, &xfercount);
    210      1.3     ross 		if (e)
    211      1.3     ross 			break;
    212      1.3     ross 		if (xfercount != xferrqst)
    213      1.3     ross 			printf("Warning, unexpected short transfer %d/%d\n",
    214      1.3     ross 				(int)xfercount, (int)xferrqst);
    215      1.3     ross 		xferrqst -= xfercount;
    216      1.3     ross 		xferbase += xfercount;
    217      1.2     ross 	}
    218      1.1     ross 	return e;
    219      1.1     ross }
    220      1.1     ross 
    221      1.1     ross static int
    222      1.2     ross checksig(ustf)
    223      1.2     ross 	ust_active_t *ustf;
    224      1.2     ross {
    225      1.2     ross 	int	i, rcs;
    226      1.2     ross 
    227      1.2     ross 	for(i = rcs = 0; i < sizeof ustf->uas_1cyl; ++i)
    228      1.2     ross 		rcs += ustf->uas_1cyl[i];
    229      1.2     ross 	return rcs;
    230      1.2     ross }
    231      1.2     ross 
    232      1.2     ross static int
    233      1.3     ross get_volume(f, vn)
    234      1.1     ross 	struct open_file *f;
    235      1.2     ross 	int vn;
    236      1.2     ross {
    237      1.2     ross 	int	e, needvolume, havevolume;
    238      1.2     ross 	ust_active_t *ustf;
    239      1.2     ross 
    240      1.2     ross 	ustf = f->f_fsdata;
    241      1.2     ross 	havevolume = vda2vn(ustf->uas_windowbase, ustf->uas_volsize);
    242      1.2     ross 	needvolume = vn;
    243      1.2     ross 	while(havevolume != needvolume) {
    244      1.2     ross 		printf("\nPlease ");
    245      1.2     ross 		if (havevolume >= 0)
    246      1.2     ross 			printf("remove disk %d, ", havevolume + 1);
    247      1.2     ross 		printf("insert disk %d, and type return...",
    248      1.2     ross 			needvolume + 1);
    249      1.2     ross 		getchar();
    250      1.2     ross 		printf("\n");
    251      1.3     ross 		e = ustarfs_cylinder_read(f, 0, 1);
    252      1.6       he 		if (e)		/* Try again on error, needed on i386 */
    253      1.6       he 			e = ustarfs_cylinder_read(f, 0, 1);
    254      1.2     ross 		if (e)
    255      1.2     ross 			return e;
    256      1.2     ross 		if(strncmp(formatid, ustf->uas_1cyl, strlen(formatid))) {
    257      1.2     ross 			/* no magic, might be OK if we want volume 0 */
    258      1.2     ross 			if (ustf->uas_volzerosig == checksig(ustf)) {
    259      1.2     ross 				havevolume = 0;
    260      1.2     ross 				continue;
    261      1.2     ross 			}
    262      1.2     ross 			printf("Disk is not from the volume set?!\n");
    263      1.2     ross 			havevolume = -2;
    264      1.2     ross 			continue;
    265      1.2     ross 		}
    266      1.2     ross 		ustarfs_sscanf(ustf->uas_1cyl + strlen(formatid), "%9o",
    267      1.2     ross 			&havevolume);
    268      1.2     ross 		--havevolume;
    269      1.2     ross 	}
    270      1.2     ross 	return 0;
    271      1.2     ross }
    272      1.2     ross 
    273      1.3     ross static void
    274      1.3     ross setwindow(ust_active_t *ustf, ustoffs pda, ustoffs vda)
    275      1.3     ross {
    276      1.3     ross 	ustf->uas_windowbase = lda2vda(pda2lda(pda), ustf->uas_volsize,
    277      1.3     ross 					vda2vn(vda, ustf->uas_volsize))
    278      1.3     ross 			     + ustf->uas_offset;
    279      1.3     ross 	ustf->uas_init_window = 1;
    280      1.3     ross }
    281      1.3     ross 
    282      1.2     ross static int
    283      1.2     ross read512block(f, vda, block)
    284      1.2     ross 	struct open_file *f;
    285      1.2     ross 	ustoffs vda;
    286      1.1     ross 	char block[512];
    287      1.1     ross {
    288      1.3     ross 	ustoffs pda;
    289      1.1     ross 	ssize_t	e;
    290      1.2     ross 	int	dienow;
    291      1.1     ross 	ust_active_t *ustf;
    292      1.1     ross 
    293      1.2     ross 	dienow = 0;
    294      1.1     ross 	ustf = f->f_fsdata;
    295      1.2     ross 
    296      1.2     ross 	if (!ustf->uas_init_window
    297      1.2     ross 	&&   ustf->uas_windowbase == 0) {
    298      1.2     ross 		/*
    299      1.2     ross 		 * The algorithm doesn't require this, but without it we would
    300      1.2     ross 		 * need some trick to get the cylinder zero signature computed.
    301      1.2     ross 		 * That signature is used to identify volume zero, which we
    302      1.2     ross 		 * don't give a USTARFS label to. (It's platform-dependent.)
    303      1.2     ross 		 */
    304      1.3     ross 		e = ustarfs_cylinder_read(f, 0, 0);
    305      1.2     ross 		if (e)
    306      1.2     ross 			return e;
    307      1.2     ross 		ustf->uas_volzerosig = checksig(ustf);
    308      1.3     ross 		setwindow(ustf, 0, 0);
    309      1.2     ross 	}
    310      1.2     ross 	/*
    311      1.2     ross 	 * if (vda in window)
    312      1.2     ross 	 * 	copy out and return data
    313      1.2     ross 	 * if (vda is on some other disk)
    314      1.2     ross 	 * 	do disk swap
    315      1.2     ross 	 * get physical disk address
    316      1.2     ross 	 * round down to cylinder boundary
    317      1.2     ross 	 * read cylindar
    318      1.2     ross 	 * set window (in vda space) and try again
    319      1.2     ross 	 * [ there is an implicit assumption that windowbase always identifies
    320      1.2     ross 	 *    the current volume, even if initwindow == 0. This way, a
    321      1.2     ross 	 *    windowbase of 0 causes the initial volume to be disk 0 ]
    322      1.2     ross 	 */
    323      1.1     ross tryagain:
    324      1.1     ross 	if(ustf->uas_init_window
    325      1.2     ross 	&& ustf->uas_windowbase <= vda && vda <
    326      1.2     ross 	   ustf->uas_windowbase + sizeof ustf->uas_1cyl - ustf->uas_offset) {
    327      1.2     ross 		memcpy(block, ustf->uas_1cyl
    328      1.2     ross 				+ (vda - ustf->uas_windowbase)
    329      1.2     ross 				+ ustf->uas_offset, 512);
    330      1.1     ross 		return 0;
    331      1.1     ross 	}
    332      1.1     ross 	if (dienow++)
    333      1.1     ross 		panic("ustarfs read512block");
    334      1.2     ross 	ustf->uas_init_window = 0;
    335      1.2     ross 	e = get_volume(f, vda2vn(vda, ustf->uas_volsize));
    336      1.2     ross 	if (e)
    337      1.2     ross 		return e;
    338      1.2     ross 	pda = lda2pda(vda2lda(vda, ustf->uas_volsize));
    339      1.2     ross 	pda-= pda % sizeof ustf->uas_1cyl;
    340      1.3     ross 	e = ustarfs_cylinder_read(f, pda, 0);
    341      1.1     ross 	if (e)
    342      1.1     ross 		return e;
    343      1.3     ross 	setwindow(ustf, pda, vda);
    344      1.1     ross 	goto tryagain;
    345      1.1     ross }
    346      1.1     ross 
    347      1.1     ross int
    348      1.1     ross ustarfs_open(path, f)
    349      1.1     ross 	char *path;
    350      1.1     ross 	struct open_file *f;
    351      1.1     ross 
    352      1.1     ross {
    353      1.1     ross 	ust_active_t *ustf;
    354      1.2     ross 	ustoffs offset;
    355      1.1     ross 	char	block[512];
    356      1.1     ross 	int	filesize;
    357      1.1     ross 	int	e, e2;
    358      1.3     ross 	int	newvolblocks;
    359      1.1     ross 
    360      1.1     ross 	if (*path == '/')
    361      1.1     ross 		++path;
    362      1.1     ross 	e = EINVAL;
    363      1.1     ross 	f->f_fsdata = ustf = alloc(sizeof *ustf);
    364      1.1     ross 	memset(ustf, 0, sizeof *ustf);
    365      1.2     ross 	offset = 0;
    366      1.3     ross 	/* default to 2880 sector floppy */
    367      1.3     ross 	ustf->uas_volsize = 80 * 2 * 18 * 512 - lda2pda(0);
    368      1.1     ross 	ustf->uas_fseek = 0;
    369      1.1     ross 	for(;;) {
    370      1.1     ross 		ustf->uas_filestart = offset;
    371      1.1     ross 		e2 = read512block(f, offset, block);
    372      1.1     ross 		if (e2) {
    373      1.1     ross 			e = e2;
    374      1.1     ross 			break;
    375      1.1     ross 		}
    376      1.1     ross 		memcpy(&ustf->uas_active, block, sizeof ustf->uas_active);
    377      1.1     ross 		if(strncmp(ustf->uas_active.ust_magic, "ustar", 5))
    378      1.1     ross 			break;
    379      1.1     ross 		e = ENOENT;	/* it must be an actual ustarfs */
    380      1.1     ross 		ustf->uas_init_fs = 1;
    381      1.3     ross 		/* if volume metadata is found, use it */
    382      1.3     ross 		if(strncmp(ustf->uas_active.ust_name, metaname,
    383      1.3     ross 		    strlen(metaname)) == 0) {
    384      1.3     ross 			ustarfs_sscanf(ustf->uas_active.ust_name
    385      1.3     ross 				+ strlen(metaname), "%99o", &newvolblocks);
    386      1.3     ross 			ustf->uas_volsize = newvolblocks * 512
    387      1.3     ross 					  - lda2pda(0);
    388      1.3     ross 		}
    389      1.1     ross 		ustarfs_sscanf(ustf->uas_active.ust_size,"%12o",&filesize);
    390      1.1     ross 		if(strncmp(ustf->uas_active.ust_name, path,
    391      1.1     ross 		    sizeof ustf->uas_active.ust_name) == 0) {
    392      1.1     ross 			ustf->uas_filesize = filesize;
    393      1.1     ross 			e = 0;
    394      1.1     ross 			break;
    395      1.1     ross 		}
    396      1.1     ross 		offset += USTAR_NAME_BLOCK + filesize;
    397      1.1     ross 		filesize %= 512;
    398      1.1     ross 		if (filesize)
    399      1.1     ross 			offset += 512 - filesize;
    400      1.1     ross 	}
    401      1.1     ross 	if (e) {
    402      1.1     ross 		free(ustf, sizeof *ustf);
    403      1.1     ross 		f->f_fsdata = 0;
    404      1.1     ross 	}
    405      1.1     ross 	return e;
    406      1.1     ross }
    407      1.1     ross 
    408      1.8      cgd #ifndef LIBSA_NO_FS_WRITE
    409      1.1     ross int
    410      1.1     ross ustarfs_write(f, start, size, resid)
    411      1.1     ross 	struct open_file *f;
    412      1.1     ross 	void *start;
    413      1.1     ross 	size_t size;
    414      1.1     ross 	size_t *resid;
    415      1.1     ross {
    416      1.1     ross 	return (EROFS);
    417      1.1     ross }
    418      1.8      cgd #endif /* !LIBSA_NO_FS_WRITE */
    419      1.1     ross 
    420      1.8      cgd #ifndef LIBSA_NO_FS_SEEK
    421      1.1     ross off_t
    422      1.1     ross ustarfs_seek(f, offs, whence)
    423      1.1     ross 	struct open_file *f;
    424      1.1     ross 	off_t offs;
    425      1.1     ross 	int whence;
    426      1.1     ross {
    427      1.1     ross 	ust_active_t *ustf;
    428      1.1     ross 
    429      1.1     ross 	ustf = f->f_fsdata;
    430      1.1     ross 	switch (whence) {
    431      1.1     ross 	    case SEEK_SET:
    432      1.1     ross 		ustf->uas_fseek = offs;
    433      1.1     ross 		break;
    434      1.1     ross 	    case SEEK_CUR:
    435      1.1     ross 		ustf->uas_fseek += offs;
    436      1.1     ross 		break;
    437      1.1     ross 	    case SEEK_END:
    438      1.1     ross 		ustf->uas_fseek = ustf->uas_filesize - offs;
    439      1.1     ross 		break;
    440      1.1     ross 	    default:
    441      1.1     ross 		return -1;
    442      1.1     ross 	}
    443      1.1     ross 	return ustf->uas_fseek;
    444      1.1     ross }
    445      1.8      cgd #endif /* !LIBSA_NO_FS_CLOSE */
    446      1.1     ross 
    447      1.1     ross int
    448      1.1     ross ustarfs_read(f, start, size, resid)
    449      1.1     ross 	struct open_file *f;
    450      1.1     ross 	void *start;
    451      1.1     ross 	size_t size;
    452      1.1     ross 	size_t *resid;
    453      1.1     ross {
    454      1.1     ross 	ust_active_t *ustf;
    455      1.1     ross 	int	e;
    456      1.1     ross 	char	*space512;
    457      1.1     ross 	int	blkoffs,
    458      1.1     ross 		readoffs,
    459      1.1     ross 		bufferoffset;
    460      1.1     ross 	size_t	seg;
    461      1.1     ross 	int	infile,
    462      1.1     ross 		inbuffer;
    463      1.1     ross 
    464      1.1     ross 	e = 0;
    465      1.1     ross 	space512 = alloc(512);
    466      1.1     ross 	ustf = f->f_fsdata;
    467      1.1     ross 	while(size != 0) {
    468      1.1     ross 		if (ustf->uas_fseek >= ustf->uas_filesize)
    469      1.1     ross 			break;
    470      1.1     ross 		bufferoffset = ustf->uas_fseek % 512;
    471      1.1     ross 		blkoffs  = ustf->uas_fseek - bufferoffset;
    472      1.1     ross 		readoffs = ustf->uas_filestart + 512 + blkoffs;
    473      1.1     ross 		e = read512block(f, readoffs, space512);
    474      1.1     ross 		if (e)
    475      1.1     ross 			break;
    476      1.1     ross 		seg = size;
    477      1.1     ross 		inbuffer = 512 - bufferoffset;
    478      1.1     ross 		if (inbuffer < seg)
    479      1.1     ross 			seg = inbuffer;
    480      1.1     ross 		infile = ustf->uas_filesize - ustf->uas_fseek;
    481      1.1     ross 		if (infile < seg)
    482      1.1     ross 			seg = infile;
    483      1.1     ross 		memcpy(start, space512 + bufferoffset, seg);
    484      1.1     ross 		ustf->uas_fseek += seg;
    485      1.7      dbj 		start = (caddr_t)start + seg;
    486      1.1     ross 		size  -= seg;
    487      1.1     ross 	}
    488      1.1     ross 	if (resid)
    489      1.1     ross 		*resid = size;
    490      1.1     ross 	free(space512, 512);
    491      1.1     ross 	return e;
    492      1.1     ross }
    493      1.1     ross 
    494      1.1     ross int
    495      1.1     ross ustarfs_stat(f, sb)
    496      1.1     ross 	struct open_file *f;
    497      1.1     ross 	struct stat *sb;
    498      1.1     ross {
    499      1.1     ross 	int	mode, uid, gid;
    500      1.1     ross 	ust_active_t *ustf;
    501      1.1     ross 
    502      1.1     ross 	if (f == NULL)
    503      1.1     ross 		return EINVAL;
    504      1.1     ross 	ustf = f->f_fsdata;
    505      1.1     ross 	memset(sb, 0, sizeof *sb);
    506      1.1     ross 	ustarfs_sscanf(ustf->uas_active.ust_mode, "%8o", &mode);
    507      1.1     ross 	ustarfs_sscanf(ustf->uas_active.ust_uid, "%8o", &uid);
    508      1.1     ross 	ustarfs_sscanf(ustf->uas_active.ust_gid, "%8o", &gid);
    509      1.1     ross 	sb->st_mode = mode;
    510      1.1     ross 	sb->st_uid  = uid;
    511      1.1     ross 	sb->st_gid  = gid;
    512      1.1     ross 	sb->st_size = ustf->uas_filesize;
    513      1.1     ross 	return 0;
    514      1.1     ross }
    515      1.1     ross 
    516      1.8      cgd #ifndef LIBSA_NO_FS_CLOSE
    517      1.1     ross int
    518      1.1     ross ustarfs_close(f)
    519      1.1     ross 	struct open_file *f;
    520      1.1     ross {
    521      1.1     ross 	if (f == NULL || f->f_fsdata == NULL)
    522      1.1     ross 		return EINVAL;
    523      1.1     ross 	free(f->f_fsdata, sizeof(ust_active_t));
    524      1.1     ross 	f->f_fsdata = 0;
    525      1.1     ross 	return 0;
    526      1.1     ross }
    527      1.8      cgd #endif /* !LIBSA_NO_FS_CLOSE */
    528