1*0a6a1f1dSLionel Sambuc /* $NetBSD: ustarfs.c,v 1.35 2014/03/20 03:13:18 christos Exp $ */
258a2b000SEvgeniy Ivanov
358a2b000SEvgeniy Ivanov /* [Notice revision 2.2]
458a2b000SEvgeniy Ivanov * Copyright (c) 1997, 1998 Avalon Computer Systems, Inc.
558a2b000SEvgeniy Ivanov * All rights reserved.
658a2b000SEvgeniy Ivanov *
758a2b000SEvgeniy Ivanov * Author: Ross Harvey
858a2b000SEvgeniy Ivanov *
958a2b000SEvgeniy Ivanov * Redistribution and use in source and binary forms, with or without
1058a2b000SEvgeniy Ivanov * modification, are permitted provided that the following conditions
1158a2b000SEvgeniy Ivanov * are met:
1258a2b000SEvgeniy Ivanov * 1. Redistributions of source code must retain the above copyright and
1358a2b000SEvgeniy Ivanov * author notice, this list of conditions, and the following disclaimer.
1458a2b000SEvgeniy Ivanov * 2. Redistributions in binary form must reproduce the above copyright
1558a2b000SEvgeniy Ivanov * notice, this list of conditions and the following disclaimer in the
1658a2b000SEvgeniy Ivanov * documentation and/or other materials provided with the distribution.
1758a2b000SEvgeniy Ivanov * 3. Neither the name of Avalon Computer Systems, Inc. nor the names of
1858a2b000SEvgeniy Ivanov * its contributors may be used to endorse or promote products derived
1958a2b000SEvgeniy Ivanov * from this software without specific prior written permission.
2058a2b000SEvgeniy Ivanov * 4. This copyright will be assigned to The NetBSD Foundation on
2158a2b000SEvgeniy Ivanov * 1/1/2000 unless these terms (including possibly the assignment
2258a2b000SEvgeniy Ivanov * date) are updated in writing by Avalon prior to the latest specified
2358a2b000SEvgeniy Ivanov * assignment date.
2458a2b000SEvgeniy Ivanov *
2558a2b000SEvgeniy Ivanov * THIS SOFTWARE IS PROVIDED BY AVALON COMPUTER SYSTEMS, INC. AND CONTRIBUTORS
2658a2b000SEvgeniy Ivanov * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2758a2b000SEvgeniy Ivanov * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2858a2b000SEvgeniy Ivanov * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AVALON OR THE CONTRIBUTORS
2958a2b000SEvgeniy Ivanov * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
3058a2b000SEvgeniy Ivanov * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
3158a2b000SEvgeniy Ivanov * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3258a2b000SEvgeniy Ivanov * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3358a2b000SEvgeniy Ivanov * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3458a2b000SEvgeniy Ivanov * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3558a2b000SEvgeniy Ivanov * POSSIBILITY OF SUCH DAMAGE.
3658a2b000SEvgeniy Ivanov */
3758a2b000SEvgeniy Ivanov
3858a2b000SEvgeniy Ivanov
3958a2b000SEvgeniy Ivanov /*
4058a2b000SEvgeniy Ivanov ******************************* USTAR FS *******************************
4158a2b000SEvgeniy Ivanov */
4258a2b000SEvgeniy Ivanov
4358a2b000SEvgeniy Ivanov /*
4458a2b000SEvgeniy Ivanov * Implement an ROFS with an 8K boot area followed by ustar-format data.
4558a2b000SEvgeniy Ivanov * The point: minimal FS overhead, and it's easy (well, `possible') to
4658a2b000SEvgeniy Ivanov * split files over multiple volumes.
4758a2b000SEvgeniy Ivanov *
4858a2b000SEvgeniy Ivanov * XXX - TODO LIST
4958a2b000SEvgeniy Ivanov * --- - ---- ----
5058a2b000SEvgeniy Ivanov * XXX - tag volume numbers and verify that the correct volume is
5158a2b000SEvgeniy Ivanov * inserted after volume swaps.
5258a2b000SEvgeniy Ivanov *
5358a2b000SEvgeniy Ivanov * XXX - stop hardwiring FS metadata for floppies...embed it in a file,
5458a2b000SEvgeniy Ivanov * file name, or something. (Remember __SYMDEF? :-)
5558a2b000SEvgeniy Ivanov *
5658a2b000SEvgeniy Ivanov * XXX Does not currently implement:
5758a2b000SEvgeniy Ivanov * XXX
5858a2b000SEvgeniy Ivanov * XXX LIBSA_NO_FS_CLOSE
5958a2b000SEvgeniy Ivanov * XXX LIBSA_NO_FS_SEEK
6058a2b000SEvgeniy Ivanov * XXX LIBSA_NO_FS_WRITE
6158a2b000SEvgeniy Ivanov * XXX LIBSA_NO_FS_SYMLINK (does this even make sense?)
6258a2b000SEvgeniy Ivanov * XXX LIBSA_FS_SINGLECOMPONENT
6358a2b000SEvgeniy Ivanov */
6458a2b000SEvgeniy Ivanov
6558a2b000SEvgeniy Ivanov #ifdef _STANDALONE
6658a2b000SEvgeniy Ivanov #include <lib/libkern/libkern.h>
6758a2b000SEvgeniy Ivanov #else
6858a2b000SEvgeniy Ivanov #include <string.h>
6958a2b000SEvgeniy Ivanov #endif
7058a2b000SEvgeniy Ivanov #include "stand.h"
7158a2b000SEvgeniy Ivanov #include "ustarfs.h"
7258a2b000SEvgeniy Ivanov
7358a2b000SEvgeniy Ivanov #define BBSIZE 8192
7458a2b000SEvgeniy Ivanov #define USTAR_NAME_BLOCK 512
7558a2b000SEvgeniy Ivanov
7658a2b000SEvgeniy Ivanov /*
7758a2b000SEvgeniy Ivanov * Virtual offset: relative to start of ustar archive
7858a2b000SEvgeniy Ivanov * Logical offset: volume-relative
7958a2b000SEvgeniy Ivanov * Physical offset: the usual meaning
8058a2b000SEvgeniy Ivanov */
8158a2b000SEvgeniy Ivanov
8258a2b000SEvgeniy Ivanov /* virtual offset to volume number */
8358a2b000SEvgeniy Ivanov
8458a2b000SEvgeniy Ivanov #define vda2vn(_v,_volsize) ((_v) / (_volsize))
8558a2b000SEvgeniy Ivanov
8658a2b000SEvgeniy Ivanov /* conversions between the three different levels of disk addresses */
8758a2b000SEvgeniy Ivanov
8858a2b000SEvgeniy Ivanov #define vda2lda(_v,_volsize) ((_v) % (_volsize))
8958a2b000SEvgeniy Ivanov #define lda2vda(_v,_volsize,_volnumber) ((_v) + (_volsize) * (_volnumber))
9058a2b000SEvgeniy Ivanov
9158a2b000SEvgeniy Ivanov #define lda2pda(_lda) ((_lda) + ustarfs_mode_offset)
9258a2b000SEvgeniy Ivanov #define pda2lda(_pda) ((_pda) - ustarfs_mode_offset)
9358a2b000SEvgeniy Ivanov /*
9458a2b000SEvgeniy Ivanov * Change this to off_t if you want to support big volumes. If we only use
9558a2b000SEvgeniy Ivanov * ustarfs on floppies it can stay int for libsa code density.
9658a2b000SEvgeniy Ivanov *
9758a2b000SEvgeniy Ivanov * It needs to be signed.
9858a2b000SEvgeniy Ivanov */
9958a2b000SEvgeniy Ivanov typedef int ustoffs;
10058a2b000SEvgeniy Ivanov
10158a2b000SEvgeniy Ivanov typedef struct ustar_struct {
10258a2b000SEvgeniy Ivanov char ust_name[100],
10358a2b000SEvgeniy Ivanov ust_mode[8],
10458a2b000SEvgeniy Ivanov ust_uid[8],
10558a2b000SEvgeniy Ivanov ust_gid[8],
10658a2b000SEvgeniy Ivanov ust_size[12],
10758a2b000SEvgeniy Ivanov ust_misc[12 + 8 + 1 + 100],
10858a2b000SEvgeniy Ivanov ust_magic[6],
10958a2b000SEvgeniy Ivanov /* there is more, but we don't care */
11058a2b000SEvgeniy Ivanov ust_pad[1]; /* make it aligned */
11158a2b000SEvgeniy Ivanov } ustar_t;
11258a2b000SEvgeniy Ivanov
11358a2b000SEvgeniy Ivanov /*
11458a2b000SEvgeniy Ivanov * We buffer one even cylinder of data...it's actually only really one
11558a2b000SEvgeniy Ivanov * cyl on a 1.44M floppy, but on other devices it's fast enough with any
11658a2b000SEvgeniy Ivanov * kind of block buffering, so we optimize for the slowest device.
11758a2b000SEvgeniy Ivanov */
11858a2b000SEvgeniy Ivanov
11958a2b000SEvgeniy Ivanov #ifndef USTAR_SECT_PER_CYL
12058a2b000SEvgeniy Ivanov #define USTAR_SECT_PER_CYL (18 * 2)
12158a2b000SEvgeniy Ivanov #endif
12258a2b000SEvgeniy Ivanov
12358a2b000SEvgeniy Ivanov typedef struct ust_active_struct {
12458a2b000SEvgeniy Ivanov ustar_t uas_active;
12558a2b000SEvgeniy Ivanov char uas_1cyl[USTAR_SECT_PER_CYL * 512];
12658a2b000SEvgeniy Ivanov ustoffs uas_volsize; /* XXX this is hardwired now */
12758a2b000SEvgeniy Ivanov ustoffs uas_windowbase; /* relative to volume 0 */
12858a2b000SEvgeniy Ivanov ustoffs uas_filestart; /* relative to volume 0 */
12958a2b000SEvgeniy Ivanov ustoffs uas_fseek; /* relative to file */
13058a2b000SEvgeniy Ivanov ustoffs uas_filesize; /* relative to volume 0 */
13158a2b000SEvgeniy Ivanov int uas_init_window; /* data present in window */
13258a2b000SEvgeniy Ivanov int uas_init_fs; /* ust FS actually found */
13358a2b000SEvgeniy Ivanov int uas_volzerosig; /* ID volume 0 by signature */
13458a2b000SEvgeniy Ivanov int uas_sigdone; /* did sig already */
13558a2b000SEvgeniy Ivanov int uas_offset; /* amount of cylinder below lba 0 */
13658a2b000SEvgeniy Ivanov } ust_active_t;
13758a2b000SEvgeniy Ivanov
13858a2b000SEvgeniy Ivanov static const char formatid[] = "USTARFS",
13958a2b000SEvgeniy Ivanov metaname[] = "USTAR.volsize.";
14058a2b000SEvgeniy Ivanov
14158a2b000SEvgeniy Ivanov static const int ustarfs_mode_offset = BBSIZE;
14258a2b000SEvgeniy Ivanov
14358a2b000SEvgeniy Ivanov static int checksig(ust_active_t *);
14458a2b000SEvgeniy Ivanov static int convert(const char *, int, int);
14558a2b000SEvgeniy Ivanov static int get_volume(struct open_file *, int);
14658a2b000SEvgeniy Ivanov static void setwindow(ust_active_t *, ustoffs, ustoffs);
14758a2b000SEvgeniy Ivanov static int real_fs_cylinder_read(struct open_file *, ustoffs, int);
14858a2b000SEvgeniy Ivanov static int ustarfs_cylinder_read(struct open_file *, ustoffs, int);
14958a2b000SEvgeniy Ivanov static void ustarfs_sscanf(const char *, const char *, int *);
15058a2b000SEvgeniy Ivanov static int read512block(struct open_file *, ustoffs, char block[512]);
15158a2b000SEvgeniy Ivanov static int init_volzero_sig(struct open_file *);
15258a2b000SEvgeniy Ivanov
15358a2b000SEvgeniy Ivanov #ifdef HAVE_CHANGEDISK_HOOK
15458a2b000SEvgeniy Ivanov /*
15558a2b000SEvgeniy Ivanov * Called when the next volume is prompted.
15658a2b000SEvgeniy Ivanov * Machine dependent code can eject the medium etc.
15758a2b000SEvgeniy Ivanov * The new medium must be ready when this hook returns.
15858a2b000SEvgeniy Ivanov */
15958a2b000SEvgeniy Ivanov void changedisk_hook(struct open_file *);
16058a2b000SEvgeniy Ivanov #endif
16158a2b000SEvgeniy Ivanov
16258a2b000SEvgeniy Ivanov static int
convert(const char * f,int base,int fw)16358a2b000SEvgeniy Ivanov convert(const char *f, int base, int fw)
16458a2b000SEvgeniy Ivanov {
16558a2b000SEvgeniy Ivanov int i, c, result = 0;
16658a2b000SEvgeniy Ivanov
16758a2b000SEvgeniy Ivanov while(fw > 0 && *f == ' ') {
16858a2b000SEvgeniy Ivanov --fw;
16958a2b000SEvgeniy Ivanov ++f;
17058a2b000SEvgeniy Ivanov }
17158a2b000SEvgeniy Ivanov for(i = 0; i < fw; ++i) {
17258a2b000SEvgeniy Ivanov c = f[i];
17358a2b000SEvgeniy Ivanov if ('0' <= c && c < '0' + base) {
17458a2b000SEvgeniy Ivanov c -= '0';
17558a2b000SEvgeniy Ivanov result = result * base + c;
17658a2b000SEvgeniy Ivanov } else break;
17758a2b000SEvgeniy Ivanov }
17858a2b000SEvgeniy Ivanov return result;
17958a2b000SEvgeniy Ivanov }
18058a2b000SEvgeniy Ivanov
18158a2b000SEvgeniy Ivanov static void
ustarfs_sscanf(const char * s,const char * f,int * xi)18258a2b000SEvgeniy Ivanov ustarfs_sscanf(const char *s, const char *f, int *xi)
18358a2b000SEvgeniy Ivanov {
18458a2b000SEvgeniy Ivanov
18558a2b000SEvgeniy Ivanov *xi = convert(s, 8, convert(f + 1, 10, 99));
18658a2b000SEvgeniy Ivanov }
18758a2b000SEvgeniy Ivanov
18858a2b000SEvgeniy Ivanov static int
ustarfs_cylinder_read(struct open_file * f,ustoffs seek2,int forcelabel)18958a2b000SEvgeniy Ivanov ustarfs_cylinder_read(struct open_file *f, ustoffs seek2, int forcelabel)
19058a2b000SEvgeniy Ivanov {
19158a2b000SEvgeniy Ivanov int i, e;
19258a2b000SEvgeniy Ivanov
19358a2b000SEvgeniy Ivanov for (i = 0; i < 3; ++i) {
19458a2b000SEvgeniy Ivanov e = real_fs_cylinder_read(f, seek2, forcelabel);
19558a2b000SEvgeniy Ivanov if (e == 0)
19658a2b000SEvgeniy Ivanov return 0;
19758a2b000SEvgeniy Ivanov }
19858a2b000SEvgeniy Ivanov return e;
19958a2b000SEvgeniy Ivanov }
20058a2b000SEvgeniy Ivanov
20158a2b000SEvgeniy Ivanov static int
real_fs_cylinder_read(struct open_file * f,ustoffs seek2,int forcelabel)20258a2b000SEvgeniy Ivanov real_fs_cylinder_read(struct open_file *f, ustoffs seek2, int forcelabel)
20358a2b000SEvgeniy Ivanov {
20458a2b000SEvgeniy Ivanov int i;
20558a2b000SEvgeniy Ivanov int e = 0; /* XXX work around gcc warning */
20658a2b000SEvgeniy Ivanov ustoffs lda;
20758a2b000SEvgeniy Ivanov char *xferbase;
20858a2b000SEvgeniy Ivanov ust_active_t *ustf;
20958a2b000SEvgeniy Ivanov size_t xferrqst, xfercount;
21058a2b000SEvgeniy Ivanov
21158a2b000SEvgeniy Ivanov ustf = f->f_fsdata;
21258a2b000SEvgeniy Ivanov xferrqst = sizeof ustf->uas_1cyl;
21358a2b000SEvgeniy Ivanov xferbase = ustf->uas_1cyl;
21458a2b000SEvgeniy Ivanov lda = pda2lda(seek2);
21558a2b000SEvgeniy Ivanov if (lda < 0) {
21658a2b000SEvgeniy Ivanov lda = -lda;
21758a2b000SEvgeniy Ivanov ustf->uas_offset = lda;
21858a2b000SEvgeniy Ivanov /*
21958a2b000SEvgeniy Ivanov * don't read the label unless we have to. (Preserve
22058a2b000SEvgeniy Ivanov * sequential block access so tape boot works.)
22158a2b000SEvgeniy Ivanov */
22258a2b000SEvgeniy Ivanov if (!forcelabel) {
22358a2b000SEvgeniy Ivanov memset(xferbase, 0, lda);
22458a2b000SEvgeniy Ivanov xferrqst -= lda;
22558a2b000SEvgeniy Ivanov xferbase += lda;
22658a2b000SEvgeniy Ivanov seek2 += lda;
22758a2b000SEvgeniy Ivanov }
22858a2b000SEvgeniy Ivanov } else {
22958a2b000SEvgeniy Ivanov ustf->uas_offset = 0;
23058a2b000SEvgeniy Ivanov }
23158a2b000SEvgeniy Ivanov while(xferrqst > 0) {
23258a2b000SEvgeniy Ivanov #if !defined(LIBSA_NO_TWIDDLE)
23358a2b000SEvgeniy Ivanov twiddle();
23458a2b000SEvgeniy Ivanov #endif
23558a2b000SEvgeniy Ivanov for (i = 0; i < 3; ++i) {
23658a2b000SEvgeniy Ivanov e = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
23758a2b000SEvgeniy Ivanov seek2 / 512, xferrqst, xferbase, &xfercount);
23858a2b000SEvgeniy Ivanov if (e == 0)
23958a2b000SEvgeniy Ivanov break;
24058a2b000SEvgeniy Ivanov printf("@");
24158a2b000SEvgeniy Ivanov }
24258a2b000SEvgeniy Ivanov if (e)
24358a2b000SEvgeniy Ivanov break;
24458a2b000SEvgeniy Ivanov if (xfercount != xferrqst)
24558a2b000SEvgeniy Ivanov printf("Warning, unexpected short transfer %d/%d\n",
24658a2b000SEvgeniy Ivanov (int)xfercount, (int)xferrqst);
24758a2b000SEvgeniy Ivanov xferrqst -= xfercount;
24858a2b000SEvgeniy Ivanov xferbase += xfercount;
24958a2b000SEvgeniy Ivanov seek2 += xfercount;
25058a2b000SEvgeniy Ivanov }
25158a2b000SEvgeniy Ivanov return e;
25258a2b000SEvgeniy Ivanov }
25358a2b000SEvgeniy Ivanov
25458a2b000SEvgeniy Ivanov static int
checksig(ust_active_t * ustf)25558a2b000SEvgeniy Ivanov checksig(ust_active_t *ustf)
25658a2b000SEvgeniy Ivanov {
25758a2b000SEvgeniy Ivanov int i, rcs;
25858a2b000SEvgeniy Ivanov
25958a2b000SEvgeniy Ivanov for(i = rcs = 0; i < (int)(sizeof ustf->uas_1cyl); ++i)
26058a2b000SEvgeniy Ivanov rcs += ustf->uas_1cyl[i];
26158a2b000SEvgeniy Ivanov return rcs;
26258a2b000SEvgeniy Ivanov }
26358a2b000SEvgeniy Ivanov
26458a2b000SEvgeniy Ivanov static int
get_volume(struct open_file * f,int vn)26558a2b000SEvgeniy Ivanov get_volume(struct open_file *f, int vn)
26658a2b000SEvgeniy Ivanov {
26758a2b000SEvgeniy Ivanov int e, needvolume, havevolume;
26858a2b000SEvgeniy Ivanov ust_active_t *ustf;
26958a2b000SEvgeniy Ivanov
27058a2b000SEvgeniy Ivanov ustf = f->f_fsdata;
27158a2b000SEvgeniy Ivanov havevolume = vda2vn(ustf->uas_windowbase, ustf->uas_volsize);
27258a2b000SEvgeniy Ivanov needvolume = vn;
27358a2b000SEvgeniy Ivanov while(havevolume != needvolume) {
27458a2b000SEvgeniy Ivanov printf("\nPlease ");
27558a2b000SEvgeniy Ivanov if (havevolume >= 0)
27658a2b000SEvgeniy Ivanov printf("remove disk %d, ", havevolume + 1);
27758a2b000SEvgeniy Ivanov printf("insert disk %d, and press return...",
27858a2b000SEvgeniy Ivanov needvolume + 1);
27958a2b000SEvgeniy Ivanov #ifdef HAVE_CHANGEDISK_HOOK
28058a2b000SEvgeniy Ivanov changedisk_hook(f);
28158a2b000SEvgeniy Ivanov #else
28258a2b000SEvgeniy Ivanov for (;;) {
28358a2b000SEvgeniy Ivanov int c = getchar();
28458a2b000SEvgeniy Ivanov if ((c == '\n') || (c == '\r'))
28558a2b000SEvgeniy Ivanov break;
28658a2b000SEvgeniy Ivanov }
28758a2b000SEvgeniy Ivanov #endif
28858a2b000SEvgeniy Ivanov printf("\n");
28958a2b000SEvgeniy Ivanov e = ustarfs_cylinder_read(f, 0, needvolume != 0);
29058a2b000SEvgeniy Ivanov if (e)
29158a2b000SEvgeniy Ivanov return e;
29258a2b000SEvgeniy Ivanov if(strncmp(formatid, ustf->uas_1cyl, strlen(formatid))) {
29358a2b000SEvgeniy Ivanov /* no magic, might be OK if we want volume 0 */
29458a2b000SEvgeniy Ivanov if (ustf->uas_volzerosig == checksig(ustf)) {
29558a2b000SEvgeniy Ivanov havevolume = 0;
29658a2b000SEvgeniy Ivanov continue;
29758a2b000SEvgeniy Ivanov }
29858a2b000SEvgeniy Ivanov printf("Disk is not from the volume set?!\n");
29958a2b000SEvgeniy Ivanov havevolume = -2;
30058a2b000SEvgeniy Ivanov continue;
30158a2b000SEvgeniy Ivanov }
30258a2b000SEvgeniy Ivanov ustarfs_sscanf(ustf->uas_1cyl + strlen(formatid), "%9o",
30358a2b000SEvgeniy Ivanov &havevolume);
30458a2b000SEvgeniy Ivanov --havevolume;
30558a2b000SEvgeniy Ivanov }
30658a2b000SEvgeniy Ivanov return 0;
30758a2b000SEvgeniy Ivanov }
30858a2b000SEvgeniy Ivanov
30958a2b000SEvgeniy Ivanov static void
setwindow(ust_active_t * ustf,ustoffs pda,ustoffs vda)31058a2b000SEvgeniy Ivanov setwindow(ust_active_t *ustf, ustoffs pda, ustoffs vda)
31158a2b000SEvgeniy Ivanov {
31258a2b000SEvgeniy Ivanov ustf->uas_windowbase = lda2vda(pda2lda(pda), ustf->uas_volsize,
31358a2b000SEvgeniy Ivanov vda2vn(vda, ustf->uas_volsize))
31458a2b000SEvgeniy Ivanov + ustf->uas_offset;
31558a2b000SEvgeniy Ivanov ustf->uas_init_window = 1;
31658a2b000SEvgeniy Ivanov }
31758a2b000SEvgeniy Ivanov
31858a2b000SEvgeniy Ivanov static int
read512block(struct open_file * f,ustoffs vda,char block[512])31958a2b000SEvgeniy Ivanov read512block(struct open_file *f, ustoffs vda, char block[512])
32058a2b000SEvgeniy Ivanov {
32158a2b000SEvgeniy Ivanov ustoffs pda;
32258a2b000SEvgeniy Ivanov ssize_t e;
32358a2b000SEvgeniy Ivanov int dienow;
32458a2b000SEvgeniy Ivanov ust_active_t *ustf;
32558a2b000SEvgeniy Ivanov
32658a2b000SEvgeniy Ivanov dienow = 0;
32758a2b000SEvgeniy Ivanov ustf = f->f_fsdata;
32858a2b000SEvgeniy Ivanov
32958a2b000SEvgeniy Ivanov /*
33058a2b000SEvgeniy Ivanov * if (vda in window)
33158a2b000SEvgeniy Ivanov * copy out and return data
33258a2b000SEvgeniy Ivanov * if (vda is on some other disk)
33358a2b000SEvgeniy Ivanov * do disk swap
33458a2b000SEvgeniy Ivanov * get physical disk address
33558a2b000SEvgeniy Ivanov * round down to cylinder boundary
33658a2b000SEvgeniy Ivanov * read cylinder
33758a2b000SEvgeniy Ivanov * set window (in vda space) and try again
33858a2b000SEvgeniy Ivanov * [ there is an implicit assumption that windowbase always identifies
33958a2b000SEvgeniy Ivanov * the current volume, even if initwindow == 0. This way, a
34058a2b000SEvgeniy Ivanov * windowbase of 0 causes the initial volume to be disk 0 ]
34158a2b000SEvgeniy Ivanov */
34258a2b000SEvgeniy Ivanov tryagain:
34358a2b000SEvgeniy Ivanov if(ustf->uas_init_window
34458a2b000SEvgeniy Ivanov && ustf->uas_windowbase <= vda && vda <
34558a2b000SEvgeniy Ivanov ustf->uas_windowbase +
34658a2b000SEvgeniy Ivanov (int)(sizeof ustf->uas_1cyl) - ustf->uas_offset) {
34758a2b000SEvgeniy Ivanov memcpy(block, ustf->uas_1cyl
34858a2b000SEvgeniy Ivanov + (vda - ustf->uas_windowbase)
34958a2b000SEvgeniy Ivanov + ustf->uas_offset, 512);
35058a2b000SEvgeniy Ivanov return 0;
35158a2b000SEvgeniy Ivanov }
35258a2b000SEvgeniy Ivanov if (dienow++)
35358a2b000SEvgeniy Ivanov panic("ustarfs read512block");
35458a2b000SEvgeniy Ivanov ustf->uas_init_window = 0;
35558a2b000SEvgeniy Ivanov e = get_volume(f, vda2vn(vda, ustf->uas_volsize));
35658a2b000SEvgeniy Ivanov if (e)
35758a2b000SEvgeniy Ivanov return e;
35858a2b000SEvgeniy Ivanov pda = lda2pda(vda2lda(vda, ustf->uas_volsize));
35958a2b000SEvgeniy Ivanov pda-= pda % sizeof ustf->uas_1cyl;
36058a2b000SEvgeniy Ivanov e = ustarfs_cylinder_read(f, pda, 0);
36158a2b000SEvgeniy Ivanov if (e)
36258a2b000SEvgeniy Ivanov return e;
36358a2b000SEvgeniy Ivanov setwindow(ustf, pda, vda);
36458a2b000SEvgeniy Ivanov goto tryagain;
36558a2b000SEvgeniy Ivanov }
36658a2b000SEvgeniy Ivanov
36758a2b000SEvgeniy Ivanov static int
init_volzero_sig(struct open_file * f)36858a2b000SEvgeniy Ivanov init_volzero_sig(struct open_file *f)
36958a2b000SEvgeniy Ivanov {
37058a2b000SEvgeniy Ivanov int e;
37158a2b000SEvgeniy Ivanov ust_active_t *ustf;
37258a2b000SEvgeniy Ivanov
37358a2b000SEvgeniy Ivanov ustf = f->f_fsdata;
37458a2b000SEvgeniy Ivanov if (!ustf->uas_sigdone) {
37558a2b000SEvgeniy Ivanov e = ustarfs_cylinder_read(f, 0, 0);
37658a2b000SEvgeniy Ivanov if (e)
37758a2b000SEvgeniy Ivanov return e;
37858a2b000SEvgeniy Ivanov ustf->uas_volzerosig = checksig(ustf);
37958a2b000SEvgeniy Ivanov setwindow(ustf, 0, 0);
38058a2b000SEvgeniy Ivanov }
38158a2b000SEvgeniy Ivanov return 0;
38258a2b000SEvgeniy Ivanov }
38358a2b000SEvgeniy Ivanov
38458a2b000SEvgeniy Ivanov __compactcall int
ustarfs_open(const char * path,struct open_file * f)38558a2b000SEvgeniy Ivanov ustarfs_open(const char *path, struct open_file *f)
38658a2b000SEvgeniy Ivanov {
38758a2b000SEvgeniy Ivanov ust_active_t *ustf;
38858a2b000SEvgeniy Ivanov ustoffs offset;
38958a2b000SEvgeniy Ivanov char block[512];
39058a2b000SEvgeniy Ivanov int filesize;
39158a2b000SEvgeniy Ivanov int e, e2;
39258a2b000SEvgeniy Ivanov int newvolblocks;
39358a2b000SEvgeniy Ivanov
39458a2b000SEvgeniy Ivanov if (*path == '/')
39558a2b000SEvgeniy Ivanov ++path;
39658a2b000SEvgeniy Ivanov f->f_fsdata = ustf = alloc(sizeof *ustf);
39758a2b000SEvgeniy Ivanov memset(ustf, 0, sizeof *ustf);
39858a2b000SEvgeniy Ivanov offset = 0;
39958a2b000SEvgeniy Ivanov /* default to 2880 sector floppy */
40058a2b000SEvgeniy Ivanov ustf->uas_volsize = 80 * 2 * 18 * 512 - lda2pda(0);
40158a2b000SEvgeniy Ivanov ustf->uas_fseek = 0;
40258a2b000SEvgeniy Ivanov e = init_volzero_sig(f);
40358a2b000SEvgeniy Ivanov if (e)
40458a2b000SEvgeniy Ivanov return e;
40558a2b000SEvgeniy Ivanov e2 = EINVAL;
40658a2b000SEvgeniy Ivanov for(;;) {
40758a2b000SEvgeniy Ivanov ustf->uas_filestart = offset;
40858a2b000SEvgeniy Ivanov e = read512block(f, offset, block);
40958a2b000SEvgeniy Ivanov if (e)
41058a2b000SEvgeniy Ivanov break;
41158a2b000SEvgeniy Ivanov memcpy(&ustf->uas_active, block, sizeof ustf->uas_active);
41258a2b000SEvgeniy Ivanov if(strncmp(ustf->uas_active.ust_magic, "ustar", 5)) {
41358a2b000SEvgeniy Ivanov e = e2;
41458a2b000SEvgeniy Ivanov break;
41558a2b000SEvgeniy Ivanov }
41658a2b000SEvgeniy Ivanov e2 = ENOENT; /* it must be an actual ustarfs */
41758a2b000SEvgeniy Ivanov ustf->uas_init_fs = 1;
41858a2b000SEvgeniy Ivanov /* if volume metadata is found, use it */
41958a2b000SEvgeniy Ivanov if(strncmp(ustf->uas_active.ust_name, metaname,
42058a2b000SEvgeniy Ivanov strlen(metaname)) == 0) {
42158a2b000SEvgeniy Ivanov ustarfs_sscanf(ustf->uas_active.ust_name
42258a2b000SEvgeniy Ivanov + strlen(metaname), "%99o", &newvolblocks);
42358a2b000SEvgeniy Ivanov ustf->uas_volsize = newvolblocks * 512
42458a2b000SEvgeniy Ivanov - lda2pda(0);
42558a2b000SEvgeniy Ivanov }
42658a2b000SEvgeniy Ivanov ustarfs_sscanf(ustf->uas_active.ust_size,"%12o",&filesize);
42758a2b000SEvgeniy Ivanov if(strncmp(ustf->uas_active.ust_name, path,
42858a2b000SEvgeniy Ivanov sizeof ustf->uas_active.ust_name) == 0) {
42958a2b000SEvgeniy Ivanov ustf->uas_filesize = filesize;
43058a2b000SEvgeniy Ivanov break;
43158a2b000SEvgeniy Ivanov }
43258a2b000SEvgeniy Ivanov offset += USTAR_NAME_BLOCK + filesize;
43358a2b000SEvgeniy Ivanov filesize %= 512;
43458a2b000SEvgeniy Ivanov if (filesize)
43558a2b000SEvgeniy Ivanov offset += 512 - filesize;
43658a2b000SEvgeniy Ivanov }
43758a2b000SEvgeniy Ivanov if (e) {
43858a2b000SEvgeniy Ivanov dealloc(ustf, sizeof *ustf);
43958a2b000SEvgeniy Ivanov f->f_fsdata = 0;
44058a2b000SEvgeniy Ivanov }
44158a2b000SEvgeniy Ivanov return e;
44258a2b000SEvgeniy Ivanov }
44358a2b000SEvgeniy Ivanov
44458a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_WRITE
44558a2b000SEvgeniy Ivanov __compactcall int
ustarfs_write(struct open_file * f,void * start,size_t size,size_t * resid)44658a2b000SEvgeniy Ivanov ustarfs_write(struct open_file *f, void *start, size_t size, size_t *resid)
44758a2b000SEvgeniy Ivanov {
44858a2b000SEvgeniy Ivanov
44958a2b000SEvgeniy Ivanov return EROFS;
45058a2b000SEvgeniy Ivanov }
45158a2b000SEvgeniy Ivanov #endif /* !LIBSA_NO_FS_WRITE */
45258a2b000SEvgeniy Ivanov
45358a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_SEEK
45458a2b000SEvgeniy Ivanov __compactcall off_t
ustarfs_seek(struct open_file * f,off_t offs,int whence)45558a2b000SEvgeniy Ivanov ustarfs_seek(struct open_file *f, off_t offs, int whence)
45658a2b000SEvgeniy Ivanov {
45758a2b000SEvgeniy Ivanov ust_active_t *ustf;
45858a2b000SEvgeniy Ivanov
45958a2b000SEvgeniy Ivanov ustf = f->f_fsdata;
46058a2b000SEvgeniy Ivanov switch (whence) {
46158a2b000SEvgeniy Ivanov case SEEK_SET:
46258a2b000SEvgeniy Ivanov ustf->uas_fseek = offs;
46358a2b000SEvgeniy Ivanov break;
46458a2b000SEvgeniy Ivanov case SEEK_CUR:
46558a2b000SEvgeniy Ivanov ustf->uas_fseek += offs;
46658a2b000SEvgeniy Ivanov break;
46758a2b000SEvgeniy Ivanov case SEEK_END:
46858a2b000SEvgeniy Ivanov ustf->uas_fseek = ustf->uas_filesize - offs;
46958a2b000SEvgeniy Ivanov break;
47058a2b000SEvgeniy Ivanov default:
47158a2b000SEvgeniy Ivanov return -1;
47258a2b000SEvgeniy Ivanov }
47358a2b000SEvgeniy Ivanov return ustf->uas_fseek;
47458a2b000SEvgeniy Ivanov }
47558a2b000SEvgeniy Ivanov #endif /* !LIBSA_NO_FS_SEEK */
47658a2b000SEvgeniy Ivanov
47758a2b000SEvgeniy Ivanov __compactcall int
ustarfs_read(struct open_file * f,void * start,size_t size,size_t * resid)47858a2b000SEvgeniy Ivanov ustarfs_read(struct open_file *f, void *start, size_t size, size_t *resid)
47958a2b000SEvgeniy Ivanov {
48058a2b000SEvgeniy Ivanov ust_active_t *ustf;
48158a2b000SEvgeniy Ivanov int e;
48258a2b000SEvgeniy Ivanov char *space512;
48358a2b000SEvgeniy Ivanov int blkoffs;
48458a2b000SEvgeniy Ivanov int readoffs;
48558a2b000SEvgeniy Ivanov int bufferoffset;
48658a2b000SEvgeniy Ivanov size_t seg;
48758a2b000SEvgeniy Ivanov size_t infile;
48858a2b000SEvgeniy Ivanov size_t inbuffer;
48958a2b000SEvgeniy Ivanov
49058a2b000SEvgeniy Ivanov e = 0;
49158a2b000SEvgeniy Ivanov space512 = alloc(512);
49258a2b000SEvgeniy Ivanov ustf = f->f_fsdata;
49358a2b000SEvgeniy Ivanov while(size != 0) {
49458a2b000SEvgeniy Ivanov if (ustf->uas_fseek >= ustf->uas_filesize)
49558a2b000SEvgeniy Ivanov break;
49658a2b000SEvgeniy Ivanov bufferoffset = ustf->uas_fseek % 512;
49758a2b000SEvgeniy Ivanov blkoffs = ustf->uas_fseek - bufferoffset;
49858a2b000SEvgeniy Ivanov readoffs = ustf->uas_filestart + 512 + blkoffs;
49958a2b000SEvgeniy Ivanov e = read512block(f, readoffs, space512);
50058a2b000SEvgeniy Ivanov if (e)
50158a2b000SEvgeniy Ivanov break;
50258a2b000SEvgeniy Ivanov seg = size;
50358a2b000SEvgeniy Ivanov inbuffer = 512 - bufferoffset;
50458a2b000SEvgeniy Ivanov if (inbuffer < seg)
50558a2b000SEvgeniy Ivanov seg = inbuffer;
50658a2b000SEvgeniy Ivanov infile = ustf->uas_filesize - ustf->uas_fseek;
50758a2b000SEvgeniy Ivanov if (infile < seg)
50858a2b000SEvgeniy Ivanov seg = infile;
50958a2b000SEvgeniy Ivanov memcpy(start, space512 + bufferoffset, seg);
51058a2b000SEvgeniy Ivanov ustf->uas_fseek += seg;
51158a2b000SEvgeniy Ivanov start = (char *)start + seg;
51258a2b000SEvgeniy Ivanov size -= seg;
51358a2b000SEvgeniy Ivanov }
51458a2b000SEvgeniy Ivanov if (resid)
51558a2b000SEvgeniy Ivanov *resid = size;
51658a2b000SEvgeniy Ivanov dealloc(space512, 512);
51758a2b000SEvgeniy Ivanov return e;
51858a2b000SEvgeniy Ivanov }
51958a2b000SEvgeniy Ivanov
52058a2b000SEvgeniy Ivanov __compactcall int
ustarfs_stat(struct open_file * f,struct stat * sb)52158a2b000SEvgeniy Ivanov ustarfs_stat(struct open_file *f, struct stat *sb)
52258a2b000SEvgeniy Ivanov {
52358a2b000SEvgeniy Ivanov int mode, uid, gid;
52458a2b000SEvgeniy Ivanov ust_active_t *ustf;
52558a2b000SEvgeniy Ivanov
52658a2b000SEvgeniy Ivanov if (f == NULL)
52758a2b000SEvgeniy Ivanov return EINVAL;
52858a2b000SEvgeniy Ivanov ustf = f->f_fsdata;
52958a2b000SEvgeniy Ivanov memset(sb, 0, sizeof *sb);
53058a2b000SEvgeniy Ivanov ustarfs_sscanf(ustf->uas_active.ust_mode, "%8o", &mode);
53158a2b000SEvgeniy Ivanov ustarfs_sscanf(ustf->uas_active.ust_uid, "%8o", &uid);
53258a2b000SEvgeniy Ivanov ustarfs_sscanf(ustf->uas_active.ust_gid, "%8o", &gid);
53358a2b000SEvgeniy Ivanov sb->st_mode = mode;
53458a2b000SEvgeniy Ivanov sb->st_uid = uid;
53558a2b000SEvgeniy Ivanov sb->st_gid = gid;
53658a2b000SEvgeniy Ivanov sb->st_size = ustf->uas_filesize;
53758a2b000SEvgeniy Ivanov return 0;
53858a2b000SEvgeniy Ivanov }
53958a2b000SEvgeniy Ivanov
54058a2b000SEvgeniy Ivanov
54158a2b000SEvgeniy Ivanov #if defined(LIBSA_ENABLE_LS_OP)
542*0a6a1f1dSLionel Sambuc #include "ls.h"
54358a2b000SEvgeniy Ivanov __compactcall void
ustarfs_ls(struct open_file * f,const char * pattern)544*0a6a1f1dSLionel Sambuc ustarfs_ls(struct open_file *f, const char *pattern)
54558a2b000SEvgeniy Ivanov {
546*0a6a1f1dSLionel Sambuc lsunsup("ustarfs");
54758a2b000SEvgeniy Ivanov return;
54858a2b000SEvgeniy Ivanov }
549*0a6a1f1dSLionel Sambuc #if defined(__minix) && defined(LIBSA_ENABLE_LOAD_MODS_OP)
550*0a6a1f1dSLionel Sambuc __compactcall void
ustarfs_load_mods(struct open_file * f,const char * pattern,void (* funcp)(char *),char * path)551*0a6a1f1dSLionel Sambuc ustarfs_load_mods(struct open_file *f, const char *pattern,
552*0a6a1f1dSLionel Sambuc void (*funcp)(char *), char *path)
553*0a6a1f1dSLionel Sambuc {
554*0a6a1f1dSLionel Sambuc load_modsunsup("ustarfs");
555*0a6a1f1dSLionel Sambuc }
556*0a6a1f1dSLionel Sambuc #endif /* defined(__minix) && defined(LIBSA_ENABLE_LOAD_MODS_OP) */
55758a2b000SEvgeniy Ivanov #endif
55858a2b000SEvgeniy Ivanov
55958a2b000SEvgeniy Ivanov #ifndef LIBSA_NO_FS_CLOSE
56058a2b000SEvgeniy Ivanov __compactcall int
ustarfs_close(struct open_file * f)56158a2b000SEvgeniy Ivanov ustarfs_close(struct open_file *f)
56258a2b000SEvgeniy Ivanov {
56358a2b000SEvgeniy Ivanov if (f == NULL || f->f_fsdata == NULL)
56458a2b000SEvgeniy Ivanov return EINVAL;
56558a2b000SEvgeniy Ivanov dealloc(f->f_fsdata, sizeof(ust_active_t));
56658a2b000SEvgeniy Ivanov f->f_fsdata = 0;
56758a2b000SEvgeniy Ivanov return 0;
56858a2b000SEvgeniy Ivanov }
56958a2b000SEvgeniy Ivanov #endif /* !LIBSA_NO_FS_CLOSE */
570