First version of HPFS stuff.

This commit is contained in:
Semen Ustimenko 1999-12-09 19:10:13 +00:00
parent 9578442e8d
commit daabca392e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=54371
14 changed files with 5404 additions and 0 deletions

13
sbin/mount_hpfs/Makefile Normal file
View File

@ -0,0 +1,13 @@
#
# $FreeBSD$
#
PROG= mount_hpfs
SRCS= mount_hpfs.c getmntopts.c
MAN8= mount_hpfs.8
MOUNT= ${.CURDIR}/../mount
CFLAGS+= -I${.CURDIR}/../../sys -I${MOUNT} -DHPFS
.PATH: ${MOUNT}
.include <bsd.prog.mk>

View File

@ -0,0 +1,99 @@
.\"
.\" Copyright (c) 1993,1994 Christopher G. Demetriou
.\" Copyright (c) 1999 Semen Ustimenko (semenu@FreeBSD.org)
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgment:
.\" This product includes software developed by Christopher G. Demetriou.
.\" 3. The name of the author may not be used to endorse or promote products
.\" derived from this software without specific prior written permission
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd May 20, 1999
.Dt MOUNT_HPFS 8
.Os FreeBSD
.Sh NAME
.Nm mount_hpfs
.Nd mount an HPFS file system
.Sh SYNOPSIS
.Nm mount_hpfs
.Op Fl o Ar options
.Op Fl u Ar uid
.Op Fl g Ar gid
.Op Fl m Ar mask
.Pa special
.Pa node
.Sh DESCRIPTION
The
.Nm
command attaches the HPFS filesystem residing on the device
.Pa special
to the global filesystem namespace at the location
indicated by
.Pa node .
This command is normally executed by
.Xr mount 8
at boot time, but can be used by any user to mount an
HPFS file system on any directory that they own (provided,
of course, that they have appropriate access to the device that
contains the file system).
.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl u Ar uid
Set the owner of the files in the file system to
.Ar uid .
The default owner is the owner of the directory
on which the file system is being mounted.
.It Fl g Ar gid
Set the group of the files in the file system to
.Ar gid .
The default group is the group of the directory
on which the file system is being mounted.
.It Fl m Ar mask
Specify the maximum file permissions for files
in the file system.
.El
.Sh EXAMPLES
To mount an hpfs volume located in /dev/wd1s1:
.Bd -literal -offset indent
# mount_hpfs /dev/wd1s1 /mnt
.Ed
.Pp
.Sh WRITING
There is limited writing ability and it is not well-tested.
It is strongly recomended to mount readonly!
.Sh SEE ALSO
.Xr mount 2 ,
.Xr unmount 2 ,
.Xr fstab 5 ,
.Xr mount 8
.Sh HISTORY
The
.Nm
first appered in FreeBSD 3.0
.Sh AUTHOR
HPFS kernel implementation,
.Nm
and manual were written by Semen Ustimenko <semenu@FreeBSD.org>.

View File

@ -0,0 +1,284 @@
/*
* Copyright (c) 1994 Christopher G. Demetriou
* Copyright (c) 1999 Semen Ustimenko (semenu@FreeBSD.org)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Christopher G. Demetriou.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <fs/hpfs/hpfsmount.h>
#include <ctype.h>
#include <err.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
#include "mntopts.h"
static struct mntopt mopts[] = {
MOPT_STDOPTS,
{ NULL }
};
static gid_t a_gid __P((char *));
static uid_t a_uid __P((char *));
static mode_t a_mask __P((char *));
static void usage __P((void)) __dead2;
static void load_u2wtable __P((struct hpfs_args *, char *));
int
main(argc, argv)
int argc;
char **argv;
{
struct hpfs_args args;
struct stat sb;
int c, mntflags, set_gid, set_uid, set_mask,error;
int forcerw = 0;
char *dev, *dir, ndir[MAXPATHLEN+1];
#if __FreeBSD_version >= 300000
struct vfsconf vfc;
#else
struct vfsconf *vfc;
#endif
mntflags = set_gid = set_uid = set_mask = 0;
(void)memset(&args, '\0', sizeof(args));
while ((c = getopt(argc, argv, "u:g:m:o:c:W:F")) != -1) {
switch (c) {
case 'F':
forcerw=1;
break;
case 'u':
args.uid = a_uid(optarg);
set_uid = 1;
break;
case 'g':
args.gid = a_gid(optarg);
set_gid = 1;
break;
case 'm':
args.mode = a_mask(optarg);
set_mask = 1;
break;
case 'o':
getmntopts(optarg, mopts, &mntflags, 0);
break;
case 'W':
load_u2wtable(&args, optarg);
args.flags |= HPFSMNT_TABLES;
break;
case '?':
default:
usage();
break;
}
}
if (optind + 2 != argc)
usage();
if (!(mntflags & MNT_RDONLY) && !forcerw) {
warnx("Write support is BETA, you need -F flag to enable RW mount!");
exit (111);
}
dev = argv[optind];
dir = argv[optind + 1];
if (dir[0] != '/') {
warnx("\"%s\" is a relative path", dir);
if (getcwd(ndir, sizeof(ndir)) == NULL)
err(EX_OSERR, "getcwd");
strncat(ndir, "/", sizeof(ndir) - strlen(ndir) - 1);
strncat(ndir, dir, sizeof(ndir) - strlen(ndir) - 1);
dir = ndir;
warnx("using \"%s\" instead", dir);
}
args.fspec = dev;
args.export.ex_root = 65534; /* unchecked anyway on DOS fs */
if (mntflags & MNT_RDONLY)
args.export.ex_flags = MNT_EXRDONLY;
else
args.export.ex_flags = 0;
if (!set_gid || !set_uid || !set_mask) {
if (stat(dir, &sb) == -1)
err(EX_OSERR, "stat %s", dir);
if (!set_uid)
args.uid = sb.st_uid;
if (!set_gid)
args.gid = sb.st_gid;
if (!set_mask)
args.mode = sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
}
#if __FreeBSD_version >= 300000
error = getvfsbyname("hpfs", &vfc);
if(error && vfsisloadable("hpfs")) {
if(vfsload("hpfs"))
#else
vfc = getvfsbyname("hpfs");
if(!vfc && vfsisloadable("hpfs")) {
if(vfsload("hpfs"))
#endif
err(EX_OSERR, "vfsload(hpfs)");
endvfsent(); /* clear cache */
#if __FreeBSD_version >= 300000
error = getvfsbyname("hpfs", &vfc);
#else
vfc = getvfsbyname("hpfs");
#endif
}
#if __FreeBSD_version >= 300000
if (error)
#else
if (!vfc)
#endif
errx(EX_OSERR, "hpfs filesystem is not available");
#if __FreeBSD_version >= 300000
if (mount(vfc.vfc_name, dir, mntflags, &args) < 0)
#else
if (mount(vfc->vfc_index, dir, mntflags, &args) < 0)
#endif
err(EX_OSERR, "%s", dev);
exit (0);
}
gid_t
a_gid(s)
char *s;
{
struct group *gr;
char *gname;
gid_t gid;
if ((gr = getgrnam(s)) != NULL)
gid = gr->gr_gid;
else {
for (gname = s; *s && isdigit(*s); ++s);
if (!*s)
gid = atoi(gname);
else
errx(EX_NOUSER, "unknown group id: %s", gname);
}
return (gid);
}
uid_t
a_uid(s)
char *s;
{
struct passwd *pw;
char *uname;
uid_t uid;
if ((pw = getpwnam(s)) != NULL)
uid = pw->pw_uid;
else {
for (uname = s; *s && isdigit(*s); ++s);
if (!*s)
uid = atoi(uname);
else
errx(EX_NOUSER, "unknown user id: %s", uname);
}
return (uid);
}
mode_t
a_mask(s)
char *s;
{
int done, rv=0;
char *ep;
done = 0;
if (*s >= '0' && *s <= '7') {
done = 1;
rv = strtol(optarg, &ep, 8);
}
if (!done || rv < 0 || *ep)
errx(EX_USAGE, "invalid file mode: %s", s);
return (rv);
}
void
usage()
{
fprintf(stderr, "usage: mount_hpfs [-u user] [-g group] [-m mask] bdev dir\n");
exit(EX_USAGE);
}
void
load_u2wtable (pargs, name)
struct hpfs_args *pargs;
char *name;
{
FILE *f;
int i, code;
char buf[128];
char *fn;
if (*name == '/')
fn = name;
else {
snprintf(buf, sizeof(buf), "/usr/libdata/msdosfs/%s", name);
buf[127] = '\0';
fn = buf;
}
if ((f = fopen(fn, "r")) == NULL)
err(EX_NOINPUT, "%s", fn);
for (i = 0; i < 128; i++) {
if (fscanf(f, "%i", &code) != 1)
errx(EX_DATAERR, "u2w: missing item number %d", i);
/* pargs->u2w[i] = code; */
}
for (i = 0; i < 128; i++) {
if (fscanf(f, "%i", &code) != 1)
errx(EX_DATAERR, "d2u: missing item number %d", i);
pargs->d2u[i] = code;
}
for (i = 0; i < 128; i++) {
if (fscanf(f, "%i", &code) != 1)
errx(EX_DATAERR, "u2d: missing item number %d", i);
pargs->u2d[i] = code;
}
fclose(f);
}

422
sys/fs/hpfs/hpfs.h Normal file
View File

@ -0,0 +1,422 @@
/*-
* Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
/*#define HPFS_DEBUG 10*/
typedef u_int32_t lsn_t; /* Logical Sector Number */
typedef struct {
lsn_t lsn1;
lsn_t lsn2;
} rsp_t; /* Redundant Sector Pointer */
typedef struct {
u_int32_t cnt;
lsn_t lsn;
} sptr_t; /* Storage Pointer */
#define SUBLOCK 0x10
#define SUSIZE DEV_BSIZE
#define SPBLOCK 0x11
#define SPSIZE DEV_BSIZE
#define BMSIZE (4 * DEV_BSIZE)
#define HPFS_MAXFILENAME 255
#define SU_MAGIC ((u_int64_t)0xFA53E9C5F995E849)
struct sublock {
u_int64_t su_magic;
u_int8_t su_hpfsver;
u_int8_t su_fnctver;
u_int16_t unused;
lsn_t su_rootfno; /* Root Fnode */
u_int32_t su_btotal; /* Total blocks */
u_int32_t su_badbtotal; /* Bad Sectors total */
rsp_t su_bitmap;
rsp_t su_badbl;
u_long su_chkdskdate;
u_long su_dskoptdate;
u_int32_t su_dbbsz; /* Sectors in DirBlock Band */
lsn_t su_dbbstart;
lsn_t su_dbbend;
lsn_t su_dbbbitmap;
char su_volname[0x20];
lsn_t su_uidt; /* Ptr to User ID Table (8 sect) */
};
#define SP_MAGIC ((u_int64_t)0xFA5229C5F9911849)
#define SP_DIRTY 0x0001
#define SP_SPDBINUSE 0x0002
#define SP_HFINUSE 0x0004
#define SP_BADSECT 0x0008
#define SP_BADBMBL 0x0010
#define SP_FASTFRMT 0x0020
#define SP_OLDHPFS 0x0080
#define SP_IDASD 0x0100
#define SP_RDASD 0x0200
#define SP_DASD 0x0400
#define SP_MMACTIVE 0x0800
#define SP_DCEACLS 0x1000
#define SP_DSADDIRTY 0x2000
struct spblock {
u_int64_t sp_magic;
u_int16_t sp_flag;
u_int8_t sp_mmcontf;
u_int8_t unused;
lsn_t sp_hf; /* HotFix list */
u_int32_t sp_hfinuse; /* HotFixes in use */
u_int32_t sp_hfavail; /* HotFixes available */
u_int32_t sp_spdbavail; /* Spare DirBlocks available */
u_int32_t sp_spdbmax; /* Spare DirBlocks maximum */
lsn_t sp_cpi;
u_int32_t sp_cpinum;
u_int32_t sp_suchecksum;
u_int32_t sp_spchecksum;
u_int8_t reserved[0x3C];
lsn_t sp_spdb[0x65];
};
#define DE_SPECIAL 0x0001
#define DE_ACL 0x0002
#define DE_DOWN 0x0004
#define DE_END 0x0008
#define DE_EALIST 0x0010
#define DE_EPERM 0x0020
#define DE_EXPLACL 0x0040
#define DE_NEEDEA 0x0080
#define DE_RONLY 0x0100
#define DE_HIDDEN 0x0200
#define DE_SYSTEM 0x0400
#define DE_VOLLABEL 0x0800
#define DE_DIR 0x1000
#define DE_ARCHIV 0x2000
#define DE_DOWNLSN(dep) (*(lsn_t *)((caddr_t)(dep) + (dep)->de_reclen - sizeof(lsn_t)))
#define DE_NEXTDE(dep) ((struct hpfsdirent *)((caddr_t)(dep) + (dep)->de_reclen))
typedef struct hpfsdirent {
u_int16_t de_reclen;
u_int16_t de_flag;
lsn_t de_fnode;
u_long de_mtime;
u_int32_t de_size;
u_long de_atime;
u_long de_ctime;
u_int32_t de_ealen;
u_int8_t de_flexflag;
u_int8_t de_cpid;
u_int8_t de_namelen;
char de_name[1];
/* ... de_flex; */
/* lsn_t de_down; */
} hpfsdirent_t;
#define D_BSIZE (DEV_BSIZE*4)
#define D_MAGIC 0x77E40AAE
#define D_DIRENT(dbp) ((hpfsdirent_t *)((caddr_t)dbp + sizeof(dirblk_t)))
#define D_DE(dbp, deoff) ((hpfsdirent_t *)((caddr_t)dbp + sizeof(dirblk_t) + (deoff)))
typedef struct dirblk {
u_int32_t d_magic;
u_int32_t d_freeoff; /* Offset of first free byte */
u_int32_t d_chcnt; /* Change count */
lsn_t d_parent;
lsn_t d_self;
} dirblk_t;
/*
* Allocation Block (ALBLK)
*/
#define AB_HBOFFEO 0x01
#define AB_FNPARENT 0x20
#define AB_SUGGBSCH 0x40
#define AB_NODES 0x80
#define AB_ALLEAF(abp) ((alleaf_t *)((caddr_t)(abp) + sizeof(alblk_t)))
#define AB_ALNODE(abp) ((alnode_t *)((caddr_t)(abp) + sizeof(alblk_t)))
#define AB_FREEALP(abp) ((alleaf_t *)((caddr_t)(abp) + (abp)->ab_freeoff))
#define AB_FREEANP(abp) ((alnode_t *)((caddr_t)(abp) + (abp)->ab_freeoff))
#define AB_LASTALP(abp) (AB_ALLEAF(abp) + (abp)->ab_busycnt - 1)
#define AB_LASTANP(abp) (AB_ALNODE(abp) + (abp)->ab_busycnt - 1)
#define AB_ADDNREC(abp, sz, n) { \
(abp)->ab_busycnt += (n); \
(abp)->ab_freecnt -= (n); \
(abp)->ab_freeoff += (n) * (sz); \
}
#define AB_RMNREC(abp, sz, n) { \
(abp)->ab_busycnt -= (n); \
(abp)->ab_freecnt += (n); \
(abp)->ab_freeoff -= (n) * (sz);\
}
#define AB_ADDAL(abp) AB_ADDNREC(abp,sizeof(alleaf_t), 1)
#define AB_ADDAN(abp) AB_ADDNREC(abp,sizeof(alnode_t), 1)
#define AB_RMAL(abp) AB_RMNREC(abp,sizeof(alleaf_t), 1)
#define AB_RMAN(abp) AB_RMNREC(abp,sizeof(alnode_t), 1)
typedef struct alblk {
u_int8_t ab_flag;
u_int8_t ab_res[3];
u_int8_t ab_freecnt;
u_int8_t ab_busycnt;
u_int16_t ab_freeoff;
} alblk_t;
/*
* FNode
*/
#define FNODESIZE DEV_BSIZE
#define FN_MAGIC 0xF7E40AAE
struct fnode {
u_int32_t fn_magic;
u_int64_t fn_readhist;
u_int8_t fn_namelen;
char fn_name[0xF]; /* First 15 symbols or less */
lsn_t fn_parent;
sptr_t fn_extacl;
u_int16_t fn_acllen;
u_int8_t fn_extaclflag;
u_int8_t fn_histbitcount;
sptr_t fn_extea;
u_int16_t fn_ealen; /* Len of EAs in Fnode */
u_int8_t fn_exteaflag; /* EAs in exteas */
u_int8_t fn_flag;
alblk_t fn_ab;
u_int8_t fn_abd[0x60];
u_int32_t fn_size;
u_int32_t fn_reqea;
u_int8_t fn_uid[0x10];
u_int16_t fn_intoff;
u_int8_t fn_1dasdthr;
u_int8_t fn_dasdthr;
u_int32_t fn_dasdlim;
u_int32_t fn_dasdusage;
u_int8_t fn_int[0x13c];
};
#define EA_NAME(eap) ((char *)(((caddr_t)(eap)) + sizeof(struct ea)))
struct ea {
u_int8_t ea_type; /* 0 - plain val */
/* 1 - sptr to val */
/* 3 - lsn point to AlSec, cont. val */
u_int8_t ea_namelen;
u_int16_t ea_vallen;
/*u_int8_t ea_name[]; */
/*u_int8_t ea_val[]; */
};
/*
* Allocation Block Data (ALNODE)
*
* NOTE: AlNodes are used when there are too many fragments
* to represent the data in the AlBlk
*/
#define AN_SET(anp,nextoff,lsn) { \
(anp)->an_nextoff = (nextoff); \
(anp)->an_lsn = (lsn); \
}
typedef struct alnode {
u_int32_t an_nextoff; /* next node offset in blocks */
lsn_t an_lsn; /* position of AlSec structure */
} alnode_t;
/*
* Allocaion Block Data (ALLEAF)
*
* NOTE: Leaves are used to point at contiguous block of data
* (a fragment or an "extent");
*/
#define AL_SET(alp,off,len,lsn) { \
(alp)->al_off = (off); \
(alp)->al_len = (len); \
(alp)->al_lsn = (lsn); \
}
typedef struct alleaf {
u_int32_t al_off; /* offset in blocks */
u_int32_t al_len; /* len in blocks */
lsn_t al_lsn; /* phys position */
} alleaf_t;
/*
* Allocation Sector
*
* NOTE: AlSecs are not initialized before use, so they ussually
* look full of junk. Use the AlBlk tto validate the data.
*/
#define AS_MAGIC 0x37E40AAE
typedef struct alsec {
u_int32_t as_magic;
lsn_t as_self;
lsn_t as_parent;
alblk_t as_ab;
u_int8_t as_abd[0x1E0];
} alsec_t;
/*
* Code Page structures
*/
struct cpdblk {
u_int16_t b_country; /* Country code */
u_int16_t b_cpid; /* CP ID */
u_int16_t b_dbcscnt; /* Count of DBCS ranges in CP */
char b_upcase[0x80]; /* Case conversion table */
u_int16_t b_dbcsrange; /* Start/End DBCS range pairs */
};
#define CPD_MAGIC ((u_int32_t)0x894521F7)
struct cpdsec {
u_int32_t d_magic;
u_int16_t d_cpcnt; /* CP Data count */
u_int16_t d_cpfirst; /* Index of first CP Data */
u_int32_t d_checksum[3]; /* CP Data checksumms */
u_int16_t d_offset[3]; /* Offsets of CP Data blocks */
struct cpdblk d_cpdblk[3]; /* Array of CP Data Blocks */
};
struct cpiblk {
u_int16_t b_country; /* Country code */
u_int16_t b_cpid; /* CP ID */
u_int32_t b_checksum;
lsn_t b_cpdsec; /* Pointer to CP Data Sector */
u_int16_t b_vcpid; /* Volume spec. CP ID */
u_int16_t b_dbcscnt; /* Count of DBCS ranges in CP */
};
#define CPI_MAGIC ((u_int32_t)0x494521F7)
struct cpisec {
u_int32_t s_magic;
u_int32_t s_cpicnt; /* Count of CPI's in this sector */
u_int32_t s_cpifirst; /* Index of first CPI in this sector */
lsn_t s_next; /* Pointer to next CPI Sector */
struct cpiblk s_cpi[0x1F]; /* Array of CPI blocks */
};
struct hpfsmount {
struct sublock hpm_su;
struct spblock hpm_sp;
struct netexport hpm_export;
struct mount * hpm_mp;
struct vnode * hpm_devvp;
dev_t hpm_dev;
uid_t hpm_uid;
gid_t hpm_gid;
mode_t hpm_mode;
lsn_t * hpm_bmind;
struct cpdblk * hpm_cpdblk; /* Array of CP Data Blocks */
u_char hpm_u2d[0x80]; /* Unix to DOS Table*/
u_char hpm_d2u[0x80]; /* DOS to Unix Table*/
u_long hpm_bavail; /* Blocks available */
u_long hpm_dbnum; /* Data Band number */
u_int8_t * hpm_bitmap;
};
#define H_HASHED 0x0001 /* Present in hash */
#define H_PARVALID 0x0002 /* parent info is valid */
#define H_CHANGE 0x0004 /* node date was changed */
#define H_PARCHANGE 0x0008 /* parent node date was changed */
#define H_INVAL 0x0010 /* Invalid node */
struct hpfsnode {
struct lock h_lock; /* Must be first, for std vops */
#ifndef NULL_SIMPLELOCKS
struct simplelock h_interlock;
#endif
LIST_ENTRY(hpfsnode) h_hash;
struct hpfsmount *h_hpmp;
struct fnode h_fn;
struct vnode * h_vp;
struct vnode * h_devvp;
dev_t h_dev;
lsn_t h_no;
uid_t h_uid;
gid_t h_gid;
mode_t h_mode;
u_int32_t h_flag;
/* parent dir information */
u_long h_mtime;
u_long h_atime;
u_long h_ctime;
char h_name[HPFS_MAXFILENAME+1]; /* Used to speedup dirent */
int h_namelen; /* lookup */
};
/* This overlays the fid structure (see <sys/mount.h>) */
struct hpfid {
u_int16_t hpfid_len; /* Length of structure. */
u_int16_t hpfid_pad; /* Force 32-bit alignment. */
lsn_t hpfid_ino; /* File number (ino). */
int32_t hpfid_gen; /* Generation number. */
};
#if defined(HPFS_DEBUG)
#define dprintf(a) printf a
#if HPFS_DEBUG > 1
#define ddprintf(a) printf a
#else
#define ddprintf(a)
#endif
#else
#define dprintf(a)
#define ddprintf(a)
#endif
#if __FreeBSD_version >= 300000
MALLOC_DECLARE(M_HPFSMNT);
MALLOC_DECLARE(M_HPFSNO);
#endif
#define VFSTOHPFS(mp) ((struct hpfsmount *)((mp)->mnt_data))
#define VTOHP(v) ((struct hpfsnode *)((v)->v_data))
#define HPTOV(h) ((struct vnode *)((h)->h_vp))
#define FID(f) (*((lsn_t *)(f)->fid_data))
#if defined(__NetBSD__)
#define MALLOC_DEFINE(a, b, c)
#define M_HPFSMNT M_TEMP
#define M_HPFSNO M_TEMP
typedef int (vop_t) __P((void *));
#define HASHINIT(a, b, c, d) hashinit((a), (b), (c), (d))
#define bqrelse(bp) brelse(bp)
#define VOP__LOCK(a, b, c) VOP_LOCK((a), (b) ? LK_EXCLUSIVE : LK_SHARED)
#define VOP__UNLOCK(a, b, c) VOP_UNLOCK((a), 0)
#define VGET(a, b, c) vget((a), LK_EXCLUSIVE)
#define VN_LOCK(a, b, c) vn_lock((a), LK_EXCLUSIVE)
#define LOCKMGR(a, b, c, d) lockmgr((a), (b), (c))
#else /* defined(__FreeBSD__) */
#define HASHINIT(a, b, c, d) hashinit((a), (b), (d))
#define VOP__LOCK(a, b, c) VOP_LOCK((a), (b), (c))
#define VOP__UNLOCK(a, b, c) VOP_UNLOCK((a), (b), (c))
#define VGET(a, b, c) vget((a), (b), (c))
#define VN_LOCK(a, b, c) vn_lock((a), (b), (c))
#define LOCKMGR(a, b, c, d) lockmgr((a), (b), (c), (d))
#endif
extern vop_t ** hpfs_vnodeop_p;
/* Hash routines, too small to be separate header */
void hpfs_hphashinit __P((void));
struct hpfsnode *hpfs_hphashlookup __P((dev_t, lsn_t));
struct hpfsnode *hpfs_hphashget __P((dev_t, lsn_t));
struct vnode *hpfs_hphashvget __P((dev_t, lsn_t, struct proc *));
void hpfs_hphashins __P((register struct hpfsnode *));
void hpfs_hphashrem __P((register struct hpfsnode *));
extern struct lock hpfs_hphash_lock;

906
sys/fs/hpfs/hpfs_alsubr.c Normal file
View File

@ -0,0 +1,906 @@
/*-
* Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/namei.h>
#include <sys/malloc.h>
#include <sys/buf.h>
#include <fs/hpfs/hpfs.h>
#include <fs/hpfs/hpfs_subr.h>
#define AE_DONE 0 /* Nothing to change */
#define AE_SPLIT 2 /* Split was done, ranp is valid */
int hpfs_addextentr (struct hpfsmount *, lsn_t, alleaf_t *,
alnode_t *, u_long *);
int hpfs_allocalsec (struct hpfsmount *, lsn_t, struct buf **);
int hpfs_alblk2alsec (struct hpfsmount *, alblk_t *, alsec_t **,
struct buf **);
int hpfs_splitalsec (struct hpfsmount *, alsec_t *, alsec_t **,
struct buf **);
int hpfs_concatalsec (struct hpfsmount *, alsec_t *, alsec_t *,
alnode_t *);
/*
* Map file offset to disk offset. hpfsnode have to be locked.
*/
int
hpfs_hpbmap(hp, bn, bnp, runp)
struct hpfsnode *hp;
daddr_t bn;
daddr_t *bnp;
int *runp;
{
struct buf *bp;
alblk_t * abp;
alleaf_t *alp;
alnode_t *anp;
int error, i;
dprintf(("hpfs_hpbmap(0x%x, 0x%x): ",hp->h_no, bn));
bp = NULL;
abp = &hp->h_fn.fn_ab;
alp = (alleaf_t *)&hp->h_fn.fn_abd;
anp = (alnode_t *)&hp->h_fn.fn_abd;
dive:
if (abp->ab_flag & AB_NODES) {
for (i=0; i<abp->ab_busycnt; i++, anp++) {
dprintf(("[0x%x,0x%x] ",anp->an_nextoff,anp->an_lsn));
if (bn < anp->an_nextoff) {
alsec_t *asp;
dprintf(("< found | "));
if (bp)
brelse(bp);
error = bread(hp->h_devvp, anp->an_lsn,
DEV_BSIZE, NOCRED, &bp);
if (error) {
printf("hpfs_hpbmap: bread error\n");
brelse(bp);
return (error);
}
asp = (alsec_t *) bp->b_data;
if (asp->as_magic != AS_MAGIC) {
brelse(bp);
printf("hpfs_hpbmap: "
"MAGIC DOESN'T MATCH");
return (EINVAL);
}
abp = &asp->as_ab;
alp = (alleaf_t *)&asp->as_abd;
anp = (alnode_t *)&asp->as_abd;
goto dive;
}
}
} else {
for (i=0; i<abp->ab_busycnt; i++, alp++) {
dprintf(("[0x%x,0x%x,0x%x] ",
alp->al_off,alp->al_len,alp->al_lsn));
if ((bn >= alp->al_off) &&
(!alp->al_len || (bn < alp->al_off + alp->al_len))) {
dprintf(("found, "));
*bnp = bn - alp->al_off + alp->al_lsn;
dprintf((" 0x%x ", *bnp));
if (runp != NULL) {
if (alp->al_len)
*runp = alp->al_off - 1 +
alp->al_len - bn;
else
*runp = 3; /* XXX */
dprintf((" 0x%x cont", *runp));
}
if (bp)
brelse(bp);
dprintf(("\n"));
return (0);
}
}
}
dprintf(("END, notfound\n"));
if (bp)
brelse(bp);
dprintf(("hpfs_hpbmap: offset too big\n"));
return (EFBIG);
}
/*
* Find place and preinitialize AlSec structure
* AlBlk is initialized to contain AlLeafs.
*/
int
hpfs_allocalsec (
struct hpfsmount *hpmp,
lsn_t parlsn,
struct buf **bpp)
{
alsec_t * asp;
struct buf * bp;
lsn_t lsn;
int error;
*bpp = NULL;
error = hpfs_bmfblookup(hpmp, &lsn);
if (error) {
printf("hpfs_allocalsec: CAN'T ALLOC SPACE FOR AlSec\n");
return (error);
}
error = hpfs_bmmarkbusy(hpmp, lsn, 1);
if (error)
return (error);
bp = getblk(hpmp->hpm_devvp, lsn, DEV_BSIZE, 0, 0);
clrbuf(bp);
/* Fill AlSec info */
asp = (alsec_t *) bp->b_data;
asp->as_magic = AS_MAGIC;
asp->as_self = lsn;
asp->as_parent = parlsn;
/* Fill AlBlk */
asp->as_ab.ab_flag = 0;
asp->as_ab.ab_busycnt = 0;
asp->as_ab.ab_freecnt = 0x28;
asp->as_ab.ab_freeoff = sizeof(alblk_t);
*bpp = bp;
return (0);
}
/*
* Split AlSec structure into new allocated:
* allocate new AlSec; then move second half of asp's entries in
* into it; set proper flags.
*
* IF AlSec CONTAINS AlNodes, THEN YOU ALMOST EVERYTIME HAVE TO
* FIX LAST AlNode in OLD AlSec (NEXTOFF TO BE 0xFFFFFFFF).
* TOGETHER WITH FIXING ALL CHILDREN'S AlSecs (THEY HAVE GOT NEW PARENT).
*/
int
hpfs_splitalsec (
struct hpfsmount *hpmp,
alsec_t *asp,
alsec_t **naspp,
struct buf **nbpp)
{
alsec_t *nasp;
struct buf *nbp;
alblk_t *abp;
alblk_t *nabp;
int error, n1, n2, sz;
error = hpfs_allocalsec(hpmp, asp->as_parent, &nbp);
if (error)
return (error);
nasp = (alsec_t *)nbp->b_data;
nabp = &nasp->as_ab;
abp = &asp->as_ab;
n1 = (abp->ab_busycnt + 1) / 2;
n2 = (abp->ab_busycnt - n1);
sz = (abp->ab_flag & AB_NODES) ? sizeof(alnode_t) : sizeof(alleaf_t);
bcopy((caddr_t)abp + sizeof(alblk_t) + n1 * sz,
(caddr_t)nabp + sizeof(alblk_t), n2 * sz);
nabp->ab_flag = abp->ab_flag;
nabp->ab_busycnt = n2;
nabp->ab_freecnt = (0x1e0 / sz - n2);
nabp->ab_freeoff += n2 * sz;
abp->ab_busycnt -= n1;
abp->ab_freecnt += n1;
abp->ab_freeoff -= n1 * sz;
*naspp = nasp;
*nbpp = nbp;
return (0);
}
/*
* Try to concatenate two AlSec's
*
* Moves all entries from AlSec corresponding (as1p, aanp[1]) into
* corresponding aanp[0] one. If not enought space, then return ENOSPC.
*
* WARNING! YOU HAVE TO FIX aanp VALUES YOURSELF LATER:
* aanp[0].an_nextoff = aanp[1].an_nextoff;
*/
int
hpfs_concatalsec (
struct hpfsmount *hpmp,
alsec_t *as0p,
alsec_t *as1p,
alnode_t *aanp)
{
alblk_t *ab0p;
alblk_t *ab1p;
int sz;
dprintf(("hpfs_concatalsec: AlSecs at 0x%x and 0x%x \n",
as0p->as_self,as1p->as_self));
ab0p = &as0p->as_ab;
ab1p = &as1p->as_ab;
sz = (ab0p->ab_flag & AB_NODES) ? sizeof(alnode_t) : sizeof(alleaf_t);
if (ab0p->ab_freecnt > ab1p->ab_busycnt) {
/*
* Concatenate AlSecs
*/
if (ab0p->ab_flag & AB_NODES)
AB_LASTANP(ab0p)->an_nextoff = aanp[0].an_nextoff;
bcopy (AB_ALNODE(ab1p), AB_FREEANP(ab0p),
ab1p->ab_busycnt * sz);
AB_ADDNREC(ab0p, sz, ab1p->ab_busycnt);
return (0);
} else {
/* Not enought space to concatenate */
return (ENOSPC);
}
}
/*
* Transform AlBlk structure into new allocated
* AlSec.
*
* DOESN'T SET AlSec'S PARENT LSN.
*/
int
hpfs_alblk2alsec (
struct hpfsmount *hpmp,
alblk_t *abp,
alsec_t **naspp,
struct buf **nbpp)
{
alsec_t *nasp;
alblk_t *nabp;
struct buf *nbp;
int error, sz;
error = hpfs_allocalsec(hpmp, 0, &nbp);
if (error)
return (error);
nasp = (alsec_t *)nbp->b_data;
nabp = &nasp->as_ab;
sz = (abp->ab_flag & AB_NODES) ? sizeof(alnode_t) : sizeof(alleaf_t);
bcopy (abp, nabp, sizeof(alblk_t) + sz * abp->ab_busycnt);
nabp->ab_freecnt = 0x1e0 / sz - nabp->ab_busycnt;
*naspp = nasp;
*nbpp = nbp;
return (0);
}
/*
* Allocate len blocks and concatenate them to file.
* If we hadn't found contignous run of len blocks, concatenate
* as much as we can, and return.
*
*/
int
hpfs_addextent (
struct hpfsmount *hpmp,
struct hpfsnode *hp,
u_long len)
{
alblk_t *rabp;
alnode_t ranp[2];
alleaf_t al;
int error;
u_long pf;
/*
* We don't know for now start lsn of block
*/
al.al_lsn = ~0;
al.al_len = len;
al.al_off = (hp->h_fn.fn_size + DEV_BSIZE - 1) >> DEV_BSHIFT;
rabp = &hp->h_fn.fn_ab;
/* Init AlBlk if this is first extent */
if (al.al_off == 0) {
lsn_t nlsn;
u_long nlen;
dprintf(("hpfs_addextent: init AlBlk in root\n"));
rabp->ab_busycnt = 0;
rabp->ab_freecnt = 0x8;
rabp->ab_freeoff = sizeof(alblk_t);
rabp->ab_flag = 0;
error = hpfs_bmlookup (hpmp, 0, hp->h_no + 1, al.al_len, &nlsn, &nlen);
if (error)
return (error);
error = hpfs_bmmarkbusy(hpmp, nlsn, nlen);
if (error)
return (error);
dprintf(("hpfs_addextent: new: 0x%x 0x%lx, ", nlsn, nlen));
AL_SET(AB_FREEALP(rabp), al.al_off, nlen, nlsn);
AB_ADDAL(rabp);
al.al_off += nlen;
al.al_len -= nlen;
}
retry:
dprintf(("hpfs_addextent: AlBlk: [0x%x, 0x%x, 0x%x] need: 0x%x\n",
rabp->ab_freecnt, rabp->ab_busycnt, rabp->ab_flag, al.al_len));
while ((al.al_len) && (rabp->ab_freecnt > 0)) {
if (rabp->ab_flag & AB_NODES) {
alnode_t *anp;
/*
* This is level containing AlNodes, so try to
* insert recursively into last entry.
*/
anp = AB_LASTANP(rabp);
dprintf(("hpfs_addextent: AlNode: [0x%x,0x%x] \n",
anp->an_nextoff,anp->an_lsn));
/*
* Try to insert...
*/
error = hpfs_addextentr (hpmp, anp->an_lsn, &al, ranp, &pf);
if (error) {
printf("hpfs_addextent: FAILED %d\n",error);
return (error);
}
switch (pf) {
case AE_SPLIT:
dprintf(("hpfs_addextent: successful (split)\n"));
/*
* Then hpfs_addextentr has split tree below, now
* we need to fix this level. Particulary:
* fix last AlNode and add another one.
*/
bcopy(ranp, AB_LASTANP(rabp), sizeof(alnode_t) * 2);
AB_ADDAN(rabp);
break;
default:
case AE_DONE:
dprintf(("hpfs_addextent: successful\n"));
break;
}
} else {
alleaf_t *alp;
alp = AB_LASTALP(rabp);
dprintf(("hpfs_addextent: AlLeaf: [0x%x,0x%x,0x%x] \n",
alp->al_off,alp->al_len,alp->al_lsn));
/* Check if we trying to add in right place */
if (alp->al_off + alp->al_len == al.al_off) {
lsn_t nlsn;
u_long nlen;
/*
* Search bitmap for block begining from
* alp->al_lsn + alp->al_len and long of ralp->al_len
*/
error = hpfs_bmlookup (hpmp, 0,
alp->al_lsn + alp->al_len, al.al_len, &nlsn, &nlen);
if (error)
return (error);
error = hpfs_bmmarkbusy(hpmp, nlsn, nlen);
if (error)
return (error);
dprintf(("hpfs_addextent: new: 0x%x 0x%lx, ", nlsn, nlen));
if (alp->al_lsn + alp->al_len == nlsn) {
dprintf(("extended existed leaf\n"));
alp->al_len += nlen;
} else {
dprintf(("created new leaf\n"));
AL_SET(AB_FREEALP(rabp), al.al_off, nlen, nlsn);
AB_ADDAL(rabp);
}
al.al_off += nlen;
al.al_len -= nlen;
} else {
printf("hpfs_addextent: INTERNAL INCONSISTENCE\n");
return (EINVAL);
}
}
}
/*
* Move AlBlk contain to new AlSec (it will fit more
* entries) if overflowed (no more free entries).
*/
if (rabp->ab_freecnt <= 0) {
struct buf *nbp;
alsec_t * nrasp;
dprintf(("hpfs_addextent: overflow, convt\n"));
/*
* Convert AlBlk to new AlSec, it will set
* AB_FNPARENT also.
*/
rabp->ab_flag |= AB_FNPARENT;
error = hpfs_alblk2alsec (hpmp, rabp, &nrasp, &nbp);
if (error) {
printf("hpfs_addextent: CAN'T CONVT\n");
return (error);
}
nrasp->as_parent = hp->h_no;
/*
* Scan all childrens (if exist), set new parent and
* clean their AB_FNPARENT flag.
*/
if (rabp->ab_flag & AB_NODES) {
int i;
alsec_t * asp;
alnode_t * anp;
struct buf * bp;
anp = AB_ALNODE(rabp);
for (i=0; i<rabp->ab_busycnt; i++) {
error = hpfs_breadalsec(hpmp, anp->an_lsn, &bp);
if (error)
return (error);
asp = (alsec_t *)bp->b_data;
asp->as_ab.ab_flag &= ~AB_FNPARENT;
asp->as_parent = nrasp->as_self;
bdwrite(bp);
anp ++;
}
}
/* Convert AlBlk to contain AlNodes */
rabp->ab_flag = AB_NODES;
rabp->ab_busycnt = 0;
rabp->ab_freecnt = 0xC;
rabp->ab_freeoff = sizeof(alblk_t);
/* Add AlNode for new allocated AlSec */
AN_SET(AB_FREEANP(rabp), ~0, nrasp->as_self);
AB_ADDAN(rabp);
bdwrite(nbp);
}
if (al.al_len) {
dprintf(("hpfs_addextent: root retry\n"));
goto retry;
}
return (0);
}
/*
* Descent down to the end of tree, then search for
* ralp->len contignous run begining from last run's end and
* concatenate new block! If we can't find one, then...
*/
int
hpfs_addextentr (
struct hpfsmount *hpmp, /* Mix info */
lsn_t rlsn, /* LSN containing AlSec */
alleaf_t *ralp, /* AlLeaf to insert */
alnode_t *ranp, /* New AlNodes' values */
u_long *resp) /* Mix returning info */
{
struct buf *rbp;
alsec_t *rasp;
alblk_t *rabp;
alleaf_t *alp;
alnode_t *anp;
int error;
u_long pf;
u_long wb;
*resp = 0;
dprintf(("hpfs_addextentr: AlSec at 0x%x\n", rlsn));
error = hpfs_breadalsec(hpmp, rlsn, &rbp);
if (error)
return (error);
rasp = (alsec_t *)rbp->b_data;
rabp = &rasp->as_ab;
wb = 0;
dprintf(("hpfs_addextentr: AlBlk: [0x%x, 0x%x, 0x%x]\n",
rabp->ab_freecnt, rabp->ab_busycnt, rabp->ab_flag));
while ((ralp->al_len) && (rabp->ab_freecnt > 0)) {
if (rabp->ab_flag & AB_NODES) {
/*
* This is level containing AlNodes, so try to
* insert recursively into last entry.
*/
anp = AB_LASTANP(rabp);
dprintf(("hpfs_addextentr: AlNode: [0x%x,0x%x] \n",
anp->an_nextoff,anp->an_lsn));
/*
* Try to insert...
*/
error = hpfs_addextentr (hpmp, anp->an_lsn, ralp, ranp, &pf);
if (error) {
printf("hpfs_addextentr: FAILED %d\n",error);
goto fail;
}
switch (pf) {
case AE_SPLIT:
dprintf(("hpfs_addextentr: successful (split)\n"));
/*
* Then hpfs_addextentr has split tree below, now
* we need to fix this level. Particulary:
* fix last AlNode and add another one.
*/
bcopy(ranp, AB_LASTANP(rabp), sizeof(alnode_t) * 2);
AB_ADDAN(rabp);
wb = 1;
break;
default:
case AE_DONE:
dprintf(("hpfs_addextentr: successful\n"));
break;
}
} else {
alp = AB_LASTALP(rabp);
dprintf(("hpfs_addextentr: AlLeaf: [0x%x,0x%x,0x%x] \n",
alp->al_off,alp->al_len,alp->al_lsn));
/* Check if we trying to add in right place */
if (alp->al_off + alp->al_len == ralp->al_off) {
lsn_t nlsn;
u_long nlen;
/*
* Search bitmap for block begining from
* alp->al_lsn + alp->al_len and long of ralp->al_len
*/
error = hpfs_bmlookup (hpmp, 0,
alp->al_lsn + alp->al_len, ralp->al_len, &nlsn, &nlen);
if (error)
goto fail;
error = hpfs_bmmarkbusy(hpmp, nlsn, nlen);
if (error)
goto fail;
dprintf(("hpfs_addextentr: new: 0x%x 0x%lx, ", nlsn, nlen));
/*
* If ending of existed entry fits the
* begining of the extent being added,
* then we add concatenate two extents.
*/
if (alp->al_lsn + alp->al_len == nlsn) {
dprintf(("concat\n"));
alp->al_len += nlen;
} else {
dprintf(("created new leaf\n"));
AL_SET(AB_FREEALP(rabp), ralp->al_off, nlen, nlsn);
AB_ADDAL(rabp);
}
ralp->al_len -= nlen;
ralp->al_off += nlen;
} else {
printf("hpfs_addextentr: INTERNAL INCONSISTENCE\n");
error = (EINVAL);
goto fail;
}
}
}
/*
* Split AlBlk if overflowed.
*/
if (rabp->ab_freecnt <= 0) {
struct buf *nbp;
alsec_t * nrasp;
dprintf(("hpfs_addextentr: overflow, split\n"));
error = hpfs_splitalsec (hpmp, rasp, &nrasp, &nbp);
if (error) {
printf("hpfs_addextent: CAN'T SPLIT\n");
goto fail;
}
if (rabp->ab_flag & AB_NODES) {
int i;
alsec_t * asp;
alnode_t * anp;
struct buf * bp;
ranp[0].an_nextoff =
AB_LASTANP(&rasp->as_ab)->an_nextoff;
/* We need to set left subtree's last entry
* offset to 0xFFFFFFFF for OS/2 to be able
* to read our files. It treats absence of
* 0xFFFFFFFF as error.
*/
AB_LASTANP(&rasp->as_ab)->an_nextoff = ~0;
/* We need to fix new allocated AlSec's
* children, becouse their parent has changed.
*/
anp = AB_ALNODE(&nrasp->as_ab);
for (i=0; i<nrasp->as_ab.ab_busycnt; i++) {
error = hpfs_breadalsec(hpmp, anp->an_lsn, &bp);
if (error) {
brelse(nbp);
goto fail;
}
asp = (alsec_t *)bp->b_data;
asp->as_parent = nrasp->as_self;
bdwrite(bp);
anp ++;
}
} else {
ranp[0].an_nextoff =
AB_ALLEAF(&nrasp->as_ab)->al_off;
}
ranp[0].an_lsn = rasp->as_self;
ranp[1].an_nextoff = ~0;
ranp[1].an_lsn = nrasp->as_self;
bdwrite(nbp);
*resp = AE_SPLIT;
wb = 1;
}
if (wb)
bdwrite (rbp);
else
brelse(rbp);
return (0);
fail:
brelse(rbp);
return (error);
}
/*
* Recursive routine walking down the b-tree and deallocating all
* extents above bn. Returns *resp != 0 if alblk was totally
* deallocated and may be freed. Tries to keep b-tree.
*
* (XXXX) NOTE! THIS ROUTINE WILL NEVER DECREMENT DEPTH OF
* THE TREE.
*/
int
hpfs_truncatealblk (
struct hpfsmount *hpmp,
alblk_t *abp,
lsn_t bn,
int *resp)
{
int error;
alleaf_t *alp;
alnode_t *anp;
alsec_t *asp;
struct buf *bp;
dprintf(("hpfs_truncatealblk: AlBlk: [0x%x,0x%x, 0x%x]\n",
abp->ab_freecnt, abp->ab_busycnt, abp->ab_flag));
if (abp->ab_flag & AB_NODES) {
/*
* Scan array of AlNodes backward,
* diving in recursion if needed
*/
anp = AB_LASTANP(abp);
while (abp->ab_busycnt && (bn <= anp->an_nextoff)) {
dprintf(("hpfs_truncatealblk: AlNode: [0x%x,0x%x] \n",
anp->an_nextoff,anp->an_lsn));
error = hpfs_breadalsec(hpmp, anp->an_lsn, &bp);
if (error)
return (error);
asp = (alsec_t *)bp->b_data;
error = hpfs_truncatealblk (hpmp,
&asp->as_ab, bn, resp);
if (error) {
brelse(bp);
return (error);
}
if (*resp) {
brelse (bp);
error = hpfs_bmmarkfree(hpmp,
anp->an_lsn, 1);
if (error)
return (error);
AB_RMAN(abp);
anp --;
} else {
/*
* We have deallocated some entries, some space
* migth been freed, then try to concat two
* last AlSec.
*/
anp->an_nextoff = ~0;
if (abp->ab_busycnt >= 2) {
alsec_t *as0p;
struct buf *b0p;
error = hpfs_breadalsec(hpmp,
(anp-1)->an_lsn, &b0p);
if (error)
return (error);
as0p = (alsec_t *)b0p->b_data;
error = hpfs_concatalsec(hpmp,
as0p, asp, anp - 1);
if (error == ENOSPC) {
/* Not enought space */
brelse (b0p);
bdwrite (bp);
} else if (error == 0) {
/* All OK */
(anp-1)->an_nextoff = anp->an_nextoff;
bdwrite (b0p);
brelse (bp);
error = hpfs_bmmarkfree(hpmp,
anp->an_lsn, 1);
if (error)
return (error);
AB_RMAN(abp);
} else {
/* True error */
brelse (b0p);
brelse (bp);
return (error);
}
} else {
/* Nowhere to concatenate */
bdwrite (bp);
}
/* There can not be any more entries
* over greater bn, becouse last AlSec
* wasn't freed totally. So go out.
*/
break;
}
}
if (abp->ab_busycnt == 0)
*resp = 1;
else
*resp = 0;
} else {
/*
* Scan array of AlLeafs backward,
* free all above bn.
*/
alp = AB_LASTALP(abp);
while (abp->ab_busycnt && (bn < alp->al_off + alp->al_len)){
dprintf(("hpfs_truncatealblk: AlLeaf: [0x%x,0x%x,0x%x] \n",
alp->al_off,alp->al_len,alp->al_lsn));
if (bn <= alp->al_off) {
error = hpfs_bmmarkfree(hpmp, alp->al_lsn,
alp->al_len);
if (error)
return (error);
AB_RMAL(abp);
alp --;
} else if ((bn > alp->al_off) &&
(bn < alp->al_off + alp->al_len)){
error = hpfs_bmmarkfree(hpmp,
alp->al_lsn + bn - alp->al_off,
alp->al_len - bn + alp->al_off);
if (error)
return (error);
alp->al_len = bn - alp->al_off;
break;
} else
break;
}
}
/* Signal parent deallocation, if need */
if (abp->ab_busycnt == 0)
*resp = 1;
else
*resp = 0;
return (0);
}

173
sys/fs/hpfs/hpfs_hash.c Normal file
View File

@ -0,0 +1,173 @@
/*
* Copyright (c) 1982, 1986, 1989, 1991, 1993, 1995
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ufs_ihash.c 8.7 (Berkeley) 5/17/95
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <fs/hpfs/hpfs.h>
MALLOC_DEFINE(M_HPFSHASH, "HPFS hash", "HPFS node hash tables");
/*
* Structures associated with hpfsnode cacheing.
*/
static LIST_HEAD(hphashhead, hpfsnode) *hpfs_hphashtbl;
static u_long hpfs_hphash; /* size of hash table - 1 */
#define HPNOHASH(dev, lsn) (&hpfs_hphashtbl[(minor(dev) + (lsn)) & hpfs_hphash])
#ifndef NULL_SIMPLELOCKS
static struct simplelock hpfs_hphash_slock;
#endif
struct lock hpfs_hphash_lock;
/*
* Initialize inode hash table.
*/
void
hpfs_hphashinit()
{
lockinit (&hpfs_hphash_lock, PINOD, "hpfs_hphashlock", 0, 0);
hpfs_hphashtbl = HASHINIT(desiredvnodes, M_HPFSHASH, M_WAITOK,
&hpfs_hphash);
simple_lock_init(&hpfs_hphash_slock);
}
/*
* Use the device/inum pair to find the incore inode, and return a pointer
* to it. If it is in core, return it, even if it is locked.
*/
struct hpfsnode *
hpfs_hphashlookup(dev, ino)
dev_t dev;
lsn_t ino;
{
struct hpfsnode *hp;
simple_lock(&hpfs_hphash_slock);
for (hp = HPNOHASH(dev, ino)->lh_first; hp; hp = hp->h_hash.le_next)
if (ino == hp->h_no && dev == hp->h_dev)
break;
simple_unlock(&hpfs_hphash_slock);
return (hp);
}
#if 0
struct hpfsnode *
hpfs_hphashget(dev, ino)
dev_t dev;
lsn_t ino;
{
struct hpfsnode *hp;
loop:
simple_lock(&hpfs_hphash_slock);
for (hp = HPNOHASH(dev, ino)->lh_first; hp; hp = hp->h_hash.le_next) {
if (ino == hp->h_no && dev == hp->h_dev) {
LOCKMGR(&hp->h_intlock, LK_EXCLUSIVE | LK_INTERLOCK, &hpfs_hphash_slock, NULL);
return (hp);
}
}
simple_unlock(&hpfs_hphash_slock);
return (hp);
}
#endif
struct vnode *
hpfs_hphashvget(dev, ino, p)
dev_t dev;
lsn_t ino;
struct proc *p;
{
struct hpfsnode *hp;
struct vnode *vp;
loop:
simple_lock(&hpfs_hphash_slock);
for (hp = HPNOHASH(dev, ino)->lh_first; hp; hp = hp->h_hash.le_next) {
if (ino == hp->h_no && dev == hp->h_dev) {
vp = HPTOV(hp);
simple_lock (&vp->v_interlock);
simple_unlock (&hpfs_hphash_slock);
if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p))
goto loop;
return (vp);
}
}
simple_unlock(&hpfs_hphash_slock);
return (NULLVP);
}
/*
* Insert the hpfsnode into the hash table.
*/
void
hpfs_hphashins(hp)
struct hpfsnode *hp;
{
struct hphashhead *hpp;
simple_lock(&hpfs_hphash_slock);
hpp = HPNOHASH(hp->h_dev, hp->h_no);
hp->h_flag |= H_HASHED;
LIST_INSERT_HEAD(hpp, hp, h_hash);
simple_unlock(&hpfs_hphash_slock);
}
/*
* Remove the inode from the hash table.
*/
void
hpfs_hphashrem(hp)
struct hpfsnode *hp;
{
simple_lock(&hpfs_hphash_slock);
if (hp->h_flag & H_HASHED) {
hp->h_flag &= ~H_HASHED;
LIST_REMOVE(hp, h_hash);
#ifdef DIAGNOSTIC
hp->h_hash.le_next = NULL;
hp->h_hash.le_prev = NULL;
#endif
}
simple_unlock(&hpfs_hphash_slock);
}

43
sys/fs/hpfs/hpfs_ioctl.h Normal file
View File

@ -0,0 +1,43 @@
/*-
* Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _HPFS_IOCTL_H_
#define _HPFS_IOCTL_H_
#include <sys/ioccom.h>
struct hpfs_rdea {
u_long ea_no;
u_long ea_sz;
void * ea_data;
};
#define HPFSIOCGEANUM _IOR('H', 0, u_long) /* Get EA number */
#define HPFSIOCGEASZ _IOWR('H', 1, u_long) /* Get EA size */
#define HPFSIOCRDEA _IOWR('H', 2, struct hpfs_rdea) /* Read EA */
#endif

212
sys/fs/hpfs/hpfs_lookup.c Normal file
View File

@ -0,0 +1,212 @@
/*-
* Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/namei.h>
#include <sys/malloc.h>
#include <sys/buf.h>
#include <fs/hpfs/hpfs.h>
#include <fs/hpfs/hpfsmount.h>
#include <fs/hpfs/hpfs_subr.h>
int hpfs_removedirent (struct hpfsmount *, lsn_t, char *, int, int *);
/*
* This routine traverse the b+ tree representing directory
* looking for file named 'name'. Returns buf struct and hpfsdirent
* pointer. Calling routine is supposed to brelse buffer.
* name is supposed in Unix encodeing.
*/
int
hpfs_genlookupbyname (
struct hpfsnode *dhp,
char *name,
int namelen,
struct buf **bpp,
struct hpfsdirent **depp)
{
struct hpfsmount *hpmp = dhp->h_hpmp;
struct buf *bp;
struct dirblk *dp;
struct hpfsdirent *dep;
lsn_t lsn;
int error, res;
dprintf(("hpfs_genlookupbyname(0x%x, %s (%d)): \n",
dhp->h_no, name, namelen));
lsn = ((alleaf_t *)dhp->h_fn.fn_abd)->al_lsn;
dive:
error = hpfs_breaddirblk (hpmp, lsn, &bp);
if (error)
return (error);
dp = (struct dirblk *) bp->b_data;
dep = D_DIRENT(dp);
while(!(dep->de_flag & DE_END)) {
dprintf(("no: 0x%x, size: %d, name: %2d:%.*s, flag: 0x%x\n",
dep->de_fnode, dep->de_size, dep->de_namelen,
dep->de_namelen, dep->de_name, dep->de_flag));
res = hpfs_cmpfname(hpmp, name, namelen,
dep->de_name, dep->de_namelen, dep->de_cpid);
if (res == 0) {
*bpp = bp;
*depp = dep;
return (0);
} else if (res < 0)
break;
dep = (hpfsdirent_t *)(((caddr_t)dep) + dep->de_reclen);
}
if (dep->de_flag & DE_DOWN) {
lsn = DE_DOWNLSN(dep);
brelse(bp);
goto dive;
}
brelse(bp);
return (ENOENT);
}
int
hpfs_makefnode (
struct vnode * dvp,
struct vnode ** vpp,
struct componentname *cnp,
struct vattr *vap)
{
#ifdef HPFS_DEBUG
register struct hpfsnode *dhp = VTOHP(dvp);
dprintf(("hpfs_makefnode(0x%x, %s, %ld): \n",
dhp->h_no, cnp->cn_nameptr, cnp->cn_namelen));
#endif
return (EOPNOTSUPP);
}
int
hpfs_removedirent (
struct hpfsmount *hpmp,
lsn_t lsn,
char *name,
int namelen,
int *retp)
{
#if 0
struct buf *bp;
dirblk_t *dbp;
struct hpfsdirent *dep;
int deoff;
int error, ret;
dprintf(("hpfs_removedirent(0x%x, %.*s, %d): \n",
lsn, namelen, name, namelen));
error = hpfs_breaddirblk (hpmp, lsn, &bp);
if (error)
return (error);
dbp = (dirblk_t *) bp->b_data;
deoff = sizeof(dirblk_t);
dep = DB_DIRENT(dbp);
while(!(dep->de_flag & DE_END)) {
dprintf(("no: 0x%x, size: %d, name: %2d:%.*s, flag: 0x%x\n",
dep->de_fnode, dep->de_size, dep->de_namelen,
dep->de_namelen, dep->de_name, dep->de_flag));
res = hpfs_cmpfname(hpmp, name, namelen,
dep->de_name, dep->de_namelen, dep->de_cpid);
if (res == 0) {
if (dep->de_flag & DE_DOWN) {
/*XXXXXX*/
} else {
/* XXX we can copy less */
bcopy (DE_NEXTDE(dep), dep, DB_BSIZE - deoff - dep->de_reclen);
dbp->d_freeoff -= dep->de_reclen;
*retp = 0;
}
bdwrite (bp);
return (0);
} else if (res < 0)
break;
deoff += dep->de_reclen;
dep = DB_NEXTDE(dep);
}
if (dep->de_flag & DE_DOWN) {
error = hpfs_removede (hpmp, DE_DOWNLSN(dep), name, namelen, &ret);
if (error) {
brelse (bp);
return (error);
}
if (ret == 0) {
if (deoff > sizeof (dirblk_t)) {
} else if (deoff + dep->de_reclen < dbp->db_freeoff) {
}
}
} else {
error = ENOENT;
}
brelse (bp);
return (error);
#endif
return (EOPNOTSUPP);
}
int
hpfs_removefnode (
struct vnode * dvp,
struct vnode * vp,
struct componentname *cnp)
{
#ifdef HPFS_DEBUG
register struct hpfsnode *dhp = VTOHP(dvp);
register struct hpfsnode *hp = VTOHP(vp);
dprintf(("hpfs_removefnode(0x%x, 0x%x, %s, %ld): \n",
dhp->h_no, hp->h_no, cnp->cn_nameptr, cnp->cn_namelen));
#endif
return (EOPNOTSUPP);
}

861
sys/fs/hpfs/hpfs_subr.c Normal file
View File

@ -0,0 +1,861 @@
/*-
* Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/proc.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/namei.h>
#include <sys/malloc.h>
#include <sys/buf.h>
#include <fs/hpfs/hpfs.h>
#include <fs/hpfs/hpfsmount.h>
#include <fs/hpfs/hpfs_subr.h>
u_long
hpfs_checksum(
u_int8_t *object,
int size)
{
register int i;
u_long csum=0L;
for (i=0; i < size; i++) {
csum += (u_long) *object++;
csum = (csum << 7) + (csum >> (25));
}
return (csum);
}
void
hpfs_bmdeinit(
struct hpfsmount *hpmp)
{
struct buf *bp;
int i;
dprintf(("hpmp_bmdeinit: "));
if (!(hpmp->hpm_mp->mnt_flag & MNT_RDONLY)) {
/*
* Write down BitMap.
*/
for (i=0; i<hpmp->hpm_dbnum; i++) {
dprintf(("[%d: 0x%x] ", i, hpmp->hpm_bmind[i]));
bp = getblk(hpmp->hpm_devvp, hpmp->hpm_bmind[i],
BMSIZE, 0, 0);
clrbuf(bp);
bcopy(hpmp->hpm_bitmap + BMSIZE * i, bp->b_data,
BMSIZE);
bwrite(bp);
}
}
FREE(hpmp->hpm_bitmap,M_HPFSMNT);
FREE(hpmp->hpm_bmind,M_HPFSMNT);
dprintf(("\n"));
}
/*
* Initialize BitMap management, includes calculation of
* available blocks number.
*/
int
hpfs_bminit(
struct hpfsmount *hpmp)
{
struct buf *bp;
int error, i, k;
u_long dbavail;
dprintf(("hpfs_bminit: "));
hpmp->hpm_dbnum = (hpmp->hpm_su.su_btotal + 0x3FFF) / 0x4000;
dprintf(("0x%lx data bands, ", hpmp->hpm_dbnum));
MALLOC(hpmp->hpm_bmind, lsn_t *, hpmp->hpm_dbnum * sizeof(lsn_t),
M_HPFSMNT, M_WAITOK);
MALLOC(hpmp->hpm_bitmap, u_int8_t *, hpmp->hpm_dbnum * BMSIZE,
M_HPFSMNT, M_WAITOK);
error = bread(hpmp->hpm_devvp, hpmp->hpm_su.su_bitmap.lsn1,
((hpmp->hpm_dbnum + 0x7F) & ~(0x7F)) << 2, NOCRED, &bp);
if (error) {
brelse(bp);
FREE(hpmp->hpm_bitmap, M_HPFSMNT);
FREE(hpmp->hpm_bmind, M_HPFSMNT);
dprintf((" error %d\n", error));
return (error);
}
bcopy(bp->b_data, hpmp->hpm_bmind, hpmp->hpm_dbnum * sizeof(lsn_t));
brelse(bp);
/*
* Read in all BitMap
*/
for (i=0; i<hpmp->hpm_dbnum; i++) {
dprintf(("[%d: 0x%x] ", i, hpmp->hpm_bmind[i]));
error = bread(hpmp->hpm_devvp, hpmp->hpm_bmind[i],
BMSIZE, NOCRED, &bp);
if (error) {
brelse(bp);
FREE(hpmp->hpm_bitmap, M_HPFSMNT);
FREE(hpmp->hpm_bmind, M_HPFSMNT);
dprintf((" error %d\n", error));
return (error);
}
bcopy(bp->b_data, hpmp->hpm_bitmap + BMSIZE * i, BMSIZE);
brelse(bp);
}
/*
* Look througth BitMap and count free bits
*/
dbavail = 0;
for (i=0; i < hpmp->hpm_su.su_btotal >> 5; i++) {
register u_int32_t mask;
for (k=0, mask=1; k < 32; k++, mask<<=1)
if(((u_int32_t *)hpmp->hpm_bitmap)[i] & mask)
dbavail ++;
}
hpmp->hpm_bavail = dbavail;
return (0);
}
int
hpfs_cmpfname (
struct hpfsmount *hpmp,
char * uname,
int ulen,
char * dname,
int dlen,
u_int16_t cp)
{
register int i, res;
for (i = 0; i < ulen && i < dlen; i++) {
res = hpfs_toupper(hpmp, hpfs_u2d(hpmp, uname[i]), cp) -
hpfs_toupper(hpmp, dname[i], cp);
if (res)
return res;
}
return (ulen - dlen);
}
int
hpfs_cpstrnnicmp (
struct hpfsmount *hpmp,
char * str1,
int str1len,
u_int16_t str1cp,
char * str2,
int str2len,
u_int16_t str2cp)
{
int i, res;
for (i = 0; i < str1len && i < str2len; i++) {
res = (int)hpfs_toupper(hpmp, ((u_char *)str1)[i], str1cp) -
(int)hpfs_toupper(hpmp, ((u_char *)str2)[i], str2cp);
if (res)
return res;
}
return (str1len - str2len);
}
int
hpfs_cpload (
struct hpfsmount *hpmp,
struct cpiblk *cpibp,
struct cpdblk *cpdbp)
{
struct buf *bp;
struct cpdsec * cpdsp;
int error, i;
error = bread(hpmp->hpm_devvp, cpibp->b_cpdsec, DEV_BSIZE, NOCRED, &bp);
if (error) {
brelse(bp);
return (error);
}
cpdsp = (struct cpdsec *)bp->b_data;
for (i=cpdsp->d_cpfirst; i<cpdsp->d_cpcnt; i++) {
if (cpdsp->d_cpdblk[i].b_cpid == cpibp->b_cpid) {
bcopy(cpdsp->d_cpdblk + i, cpdbp,
sizeof(struct cpdblk));
brelse(bp);
return (0);
}
}
brelse(bp);
return (ENOENT);
}
/*
* Initialize Code Page information management.
* Load all copdepages in memory.
*/
int
hpfs_cpinit (
struct hpfsmount *hpmp,
struct hpfs_args *argsp)
{
struct buf *bp;
int error, i;
lsn_t lsn;
int cpicnt;
struct cpisec * cpisp;
struct cpiblk * cpibp;
struct cpdblk * cpdbp;
dprintf(("hpfs_cpinit: \n"));
if (argsp->flags & HPFSMNT_TABLES) {
bcopy(argsp->d2u, hpmp->hpm_d2u, sizeof(u_char) * 0x80);
bcopy(argsp->u2d, hpmp->hpm_u2d, sizeof(u_char) * 0x80);
} else {
for (i=0x0; i<0x80;i++) {
hpmp->hpm_d2u[i] = i + 0x80;
hpmp->hpm_u2d[i] = i + 0x80;
}
}
cpicnt = hpmp->hpm_sp.sp_cpinum;
MALLOC(hpmp->hpm_cpdblk, struct cpdblk *,
cpicnt * sizeof(struct cpdblk), M_HPFSMNT, M_WAITOK);
cpdbp = hpmp->hpm_cpdblk;
lsn = hpmp->hpm_sp.sp_cpi;
while (cpicnt > 0) {
error = bread(hpmp->hpm_devvp, lsn, DEV_BSIZE, NOCRED, &bp);
if (error) {
brelse(bp);
return (error);
}
cpisp = (struct cpisec *)bp->b_data;
cpibp = cpisp->s_cpi;
for (i=0; i<cpisp->s_cpicnt; i++, cpicnt --, cpdbp++, cpibp++) {
dprintf(("hpfs_cpinit: Country: %d, CP: %d (%d)\n",
cpibp->b_country, cpibp->b_cpid,
cpibp->b_vcpid));
error = hpfs_cpload(hpmp, cpibp, cpdbp);
if (error) {
brelse(bp);
return (error);
}
}
lsn = cpisp->s_next;
brelse(bp);
}
return (0);
}
int
hpfs_cpdeinit (
struct hpfsmount *hpmp)
{
dprintf(("hpmp_cpdeinit: "));
FREE(hpmp->hpm_cpdblk,M_HPFSMNT);
return (0);
}
/*
* Lookup for a run of blocks.
*/
int
hpfs_bmlookup (
struct hpfsmount *hpmp,
u_long flags, /* 1 means we want right len blocks in run, not less */
lsn_t lsn, /* We want near this one */
u_long len, /* We want such long */
lsn_t *lsnp, /* We got here */
u_long *lenp) /* We got this long */
{
u_int32_t * bitmap;
register u_int32_t mask;
int i,k;
int cband, vcband;
u_int bandsz;
int count;
dprintf(("hpfs_bmlookup: lsn: 0x%x, len 0x%lx | Step1\n", lsn, len));
if (lsn > hpmp->hpm_su.su_btotal) {
printf("hpfs_bmlookup: OUT OF VOLUME\n");
return ENOSPC;
}
if (len > hpmp->hpm_bavail) {
printf("hpfs_bmlookup: OUT OF SPACE\n");
return ENOSPC;
}
i = lsn >> 5;
k = lsn & 0x1F;
mask = 1 << k;
bitmap = (u_int32_t *)hpmp->hpm_bitmap + i;
if (*bitmap & mask) {
*lsnp = lsn;
*lenp = 0;
for (; k < 32; k++, mask<<=1) {
if (*bitmap & mask)
(*lenp) ++;
else {
if (flags & 1)
goto step2;
else
return (0);
}
if (*lenp == len)
return (0);
}
bitmap++;
i++;
for (; i < hpmp->hpm_su.su_btotal >> 5; i++, bitmap++) {
for (k=0, mask=1; k < 32; k++, mask<<=1) {
if (*bitmap & mask)
(*lenp) ++;
else {
if (flags & 1)
goto step2;
else
return (0);
}
if (*lenp == len)
return (0);
}
}
return (0);
}
step2:
/*
* Lookup all bands begining from cband, lookup for first block
*/
cband = (lsn >> 14);
dprintf(("hpfs_bmlookup: Step2: band 0x%x (0x%lx)\n",
cband, hpmp->hpm_dbnum));
for (vcband = 0; vcband < hpmp->hpm_dbnum; vcband ++, cband++) {
cband = cband % hpmp->hpm_dbnum;
bandsz = min (hpmp->hpm_su.su_btotal - (cband << 14), 0x4000);
dprintf(("hpfs_bmlookup: band: %d, sz: 0x%x\n", cband, bandsz));
bitmap = (u_int32_t *)hpmp->hpm_bitmap + (cband << 9);
*lsnp = cband << 14;
*lenp = 0;
count = 0;
for (i=0; i < bandsz >> 5; i++, bitmap++) {
for (k=0, mask=1; k < 32; k++, mask<<=1) {
if (*bitmap & mask) {
if (count) {
(*lenp) ++;
} else {
count = 1;
*lsnp = (cband << 14) + (i << 5) + k;
*lenp = 1;
}
} else {
if ((*lenp) && !(flags & 1)) {
return (0);
} else {
count = 0;
}
}
if (*lenp == len)
return (0);
}
}
if (cband == hpmp->hpm_dbnum - 1) {
if ((*lenp) && !(flags & 1)) {
return (0);
} else {
count = 0;
}
}
}
return (ENOSPC);
}
/*
* Lookup a single free block. XXX Need locking on BitMap operations
* VERY STUPID ROUTINE!!!
*/
int
hpfs_bmfblookup (
struct hpfsmount *hpmp,
lsn_t *lp)
{
u_int32_t * bitmap;
int i,k;
dprintf(("hpfs_bmfblookup: "));
bitmap = (u_int32_t *)hpmp->hpm_bitmap;
for (i=0; i < hpmp->hpm_su.su_btotal >> 5; i++, bitmap++) {
k = ffs(*bitmap);
if (k) {
*lp = (i << 5) + k - 1;
dprintf((" found: 0x%x\n",*lp));
return (0);
}
}
return (ENOSPC);
}
/*
* Mark contignous block of blocks.
*/
int
hpfs_bmmark (
struct hpfsmount *hpmp,
lsn_t bn,
u_long bl,
int state)
{
u_int32_t * bitmap;
int i, didprint = 0;
dprintf(("hpfs_bmmark(0x%x, 0x%lx, %d): \n",bn,bl, state));
if ((bn > hpmp->hpm_su.su_btotal) || (bn+bl > hpmp->hpm_su.su_btotal)) {
printf("hpfs_bmmark: MARKING OUT OF VOLUME\n");
return 0;
}
bitmap = (u_int32_t *)hpmp->hpm_bitmap;
bitmap += bn >> 5;
while (bl > 0) {
for (i = bn & 0x1F; (i < 0x20) && (bl > 0) ; i++, bl--) {
if (state) {
if ( *bitmap & (1 << i)) {
if (!didprint) {
printf("hpfs_bmmark: ALREADY FREE\n");
didprint = 1;
}
} else
hpmp->hpm_bavail++;
*bitmap |= (1 << i);
} else {
if ((~(*bitmap)) & (1 << i)) {
if (!didprint) {
printf("hpfs_bmmark: ALREADY BUSY\n");
didprint = 1;
}
} else
hpmp->hpm_bavail--;
*bitmap &= ~(1 << i);
}
}
bn = 0;
bitmap++;
}
return (0);
}
int
hpfs_validateparent (
struct hpfsnode *hp)
{
struct hpfsnode *dhp;
struct vnode *dvp;
struct hpfsmount *hpmp = hp->h_hpmp;
struct buf *bp;
struct dirblk *dp;
struct hpfsdirent *dep;
lsn_t lsn, olsn;
int level, error;
dprintf(("hpfs_validatetimes(0x%x): [parent: 0x%x] ",
hp->h_no, hp->h_fn.fn_parent));
if (hp->h_no == hp->h_fn.fn_parent) {
dhp = hp;
} else {
error = VFS_VGET(hpmp->hpm_mp, hp->h_fn.fn_parent, &dvp);
if (error)
return (error);
dhp = VTOHP(dvp);
}
lsn = ((alleaf_t *)dhp->h_fn.fn_abd)->al_lsn;
olsn = 0;
level = 1;
bp = NULL;
dive:
dprintf(("[dive 0x%x] ", lsn));
if (bp != NULL)
brelse(bp);
error = bread(dhp->h_devvp, lsn, D_BSIZE, NOCRED, &bp);
if (error)
goto failed;
dp = (struct dirblk *) bp->b_data;
if (dp->d_magic != D_MAGIC) {
printf("hpfs_validatetimes: magic doesn't match\n");
error = EINVAL;
goto failed;
}
dep = D_DIRENT(dp);
if (olsn) {
dprintf(("[restore 0x%x] ", olsn));
while(!(dep->de_flag & DE_END) ) {
if((dep->de_flag & DE_DOWN) &&
(olsn == DE_DOWNLSN(dep)))
break;
dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
}
if((dep->de_flag & DE_DOWN) && (olsn == DE_DOWNLSN(dep))) {
if (dep->de_flag & DE_END)
goto blockdone;
if (hp->h_no == dep->de_fnode) {
dprintf(("[found] "));
goto readdone;
}
dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
} else {
printf("hpfs_validatetimes: ERROR! oLSN not found\n");
error = EINVAL;
goto failed;
}
}
olsn = 0;
while(!(dep->de_flag & DE_END)) {
if(dep->de_flag & DE_DOWN) {
lsn = DE_DOWNLSN(dep);
level++;
goto dive;
}
if (hp->h_no == dep->de_fnode) {
dprintf(("[found] "));
goto readdone;
}
dep = (hpfsdirent_t *)((caddr_t)dep + dep->de_reclen);
}
if(dep->de_flag & DE_DOWN) {
dprintf(("[enddive] "));
lsn = DE_DOWNLSN(dep);
level++;
goto dive;
}
blockdone:
dprintf(("[EOB] "));
olsn = lsn;
lsn = dp->d_parent;
level--;
dprintf(("[level %d] ", level));
if (level > 0)
goto dive; /* undive really */
goto failed;
readdone:
bcopy(dep->de_name,hp->h_name,dep->de_namelen);
hp->h_name[dep->de_namelen] = '\0';
hp->h_namelen = dep->de_namelen;
hp->h_ctime = dep->de_ctime;
hp->h_atime = dep->de_atime;
hp->h_mtime = dep->de_mtime;
hp->h_flag |= H_PARVALID;
dprintf(("[readdone]"));
failed:
dprintf(("\n"));
if (bp != NULL)
brelse(bp);
if (hp != dhp)
vput(dvp);
return (error);
}
struct timespec
hpfstimetounix (
u_long hptime)
{
struct timespec t;
t.tv_nsec = 0;
t.tv_sec = hptime;
return t;
}
/*
* Write down changes done to parent dir, these are only times for now.
* hpfsnode have to be locked.
*/
int
hpfs_updateparent (
struct hpfsnode *hp)
{
struct hpfsnode *dhp;
struct vnode *dvp;
struct hpfsdirent *dep;
struct buf * bp;
int error;
dprintf(("hpfs_updateparent(0x%x): \n", hp->h_no));
if (!(hp->h_flag & H_PARCHANGE))
return (0);
if (!(hp->h_flag & H_PARVALID)) {
error = hpfs_validateparent (hp);
if (error)
return (error);
}
if (hp->h_no == hp->h_fn.fn_parent) {
dhp = hp;
} else {
error = VFS_VGET(hp->h_hpmp->hpm_mp, hp->h_fn.fn_parent,
&dvp);
if (error)
return (error);
dhp = VTOHP(dvp);
}
error = hpfs_genlookupbyname (dhp, hp->h_name, hp->h_namelen,
&bp, &dep);
if (error) {
goto failed;
}
dep->de_atime = hp->h_atime;
dep->de_mtime = hp->h_mtime;
dep->de_size = hp->h_fn.fn_size;
bdwrite (bp);
hp->h_flag &= ~H_PARCHANGE;
error = 0;
failed:
if (hp != dhp)
vput(dvp);
return (0);
}
/*
* Write down on disk changes done to fnode. hpfsnode have to be locked.
*/
int
hpfs_update (
struct hpfsnode *hp)
{
struct buf * bp;
dprintf(("hpfs_update(0x%x): \n", hp->h_no));
if (!(hp->h_flag & H_CHANGE))
return (0);
bp = getblk(hp->h_devvp, hp->h_no, FNODESIZE, 0, 0);
clrbuf(bp);
bcopy (&hp->h_fn, bp->b_data, sizeof(struct fnode));
bdwrite (bp);
hp->h_flag &= ~H_CHANGE;
if (hp->h_flag & H_PARCHANGE)
return (hpfs_updateparent(hp));
return (0);
}
/*
* Truncate file to specifed size. hpfsnode have to be locked.
*/
int
hpfs_truncate (
struct hpfsnode *hp,
u_long size)
{
struct hpfsmount *hpmp = hp->h_hpmp;
lsn_t newblen, oldblen;
int error, pf;
dprintf(("hpfs_truncate(0x%x, 0x%x -> 0x%lx): ",
hp->h_no, hp->h_fn.fn_size, size));
newblen = (size + DEV_BSIZE - 1) >> DEV_BSHIFT;
oldblen = (hp->h_fn.fn_size + DEV_BSIZE - 1) >> DEV_BSHIFT;
dprintf(("blen: 0x%x -> 0x%x\n", oldblen, newblen));
error = hpfs_truncatealblk (hpmp, &hp->h_fn.fn_ab, newblen, &pf);
if (error)
return (error);
if (pf) {
hp->h_fn.fn_ab.ab_flag = 0;
hp->h_fn.fn_ab.ab_freecnt = 0x8;
hp->h_fn.fn_ab.ab_busycnt = 0x0;
hp->h_fn.fn_ab.ab_freeoff = sizeof(alblk_t);
}
hp->h_fn.fn_size = size;
hp->h_flag |= (H_CHANGE | H_PARCHANGE);
dprintf(("hpfs_truncate: successful\n"));
return (0);
}
/*
* Enlarge file to specifed size. hpfsnode have to be locked.
*/
int
hpfs_extend (
struct hpfsnode *hp,
u_long size)
{
struct hpfsmount *hpmp = hp->h_hpmp;
lsn_t newblen, oldblen;
int error;
dprintf(("hpfs_extend(0x%x, 0x%x -> 0x%lx): ",
hp->h_no, hp->h_fn.fn_size, size));
if (hpmp->hpm_bavail < 0x10)
return (ENOSPC);
newblen = (size + DEV_BSIZE - 1) >> DEV_BSHIFT;
oldblen = (hp->h_fn.fn_size + DEV_BSIZE - 1) >> DEV_BSHIFT;
dprintf(("blen: 0x%x -> 0x%x\n", oldblen, newblen));
error = hpfs_addextent(hpmp, hp, newblen - oldblen);
if (error) {
printf("hpfs_extend: FAILED TO ADD EXTENT %d\n", error);
return (error);
}
hp->h_fn.fn_size = size;
hp->h_flag |= (H_CHANGE | H_PARCHANGE);
dprintf(("hpfs_extend: successful\n"));
return (0);
}
/*
* Read AlSec structure, and check if magic is valid.
* You don't need to brelse buf on error.
*/
int
hpfs_breadstruct (
struct hpfsmount *hpmp,
lsn_t lsn,
u_int len,
u_int32_t magic,
struct buf **bpp)
{
struct buf *bp;
u_int32_t *mp;
int error;
dprintf(("hpfs_breadstruct: reading at 0x%x\n", lsn));
*bpp = NULL;
error = bread(hpmp->hpm_devvp, lsn, len, NOCRED, &bp);
if (error) {
brelse(bp);
return (error);
}
mp = (u_int32_t *) bp->b_data;
if (*mp != magic) {
brelse(bp);
printf("hpfs_breadstruct: MAGIC DOESN'T MATCH (0x%08x != 0x%08x)\n",
*mp, magic);
return (EINVAL);
}
*bpp = bp;
return (0);
}

87
sys/fs/hpfs/hpfs_subr.h Normal file
View File

@ -0,0 +1,87 @@
/*-
* Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#define hpfs_bmmarkfree(hpmp, bn,bl) hpfs_bmmark(hpmp, bn, bl, 1)
#define hpfs_bmmarkbusy(hpmp, bn,bl) hpfs_bmmark(hpmp, bn, bl, 0)
u_long hpfs_checksum (u_int8_t *, int);
int hpfs_bminit (struct hpfsmount *);
void hpfs_bmdeinit (struct hpfsmount *);
int hpfs_bmfblookup (struct hpfsmount *, lsn_t *);
int hpfs_bmmark (struct hpfsmount *, lsn_t, u_long, int);
int hpfs_bmlookup (struct hpfsmount *, u_long, lsn_t, u_long,
lsn_t *, u_long *);
struct hpfs_args;
int hpfs_cpinit (struct hpfsmount *, struct hpfs_args *);
int hpfs_cpdeinit (struct hpfsmount *);
int hpfs_cpload (struct hpfsmount *, struct cpiblk *,
struct cpdblk *);
int hpfs_cpstrnnicmp (struct hpfsmount *, char *, int, u_int16_t,
char *, int, u_int16_t);
int hpfs_cmpfname (struct hpfsmount *, char *, int,
char *, int, u_int16_t);
/* XXX Need unsigned conversion? */
#define hpfs_u2d(hpmp, c) ((((u_char)(c))&0x80)?(hpmp->hpm_u2d[((u_char)(c))&0x7F]):((u_char)(c)))
#define hpfs_d2u(hpmp, c) ((((u_char)(c))&0x80)?(hpmp->hpm_d2u[((u_char)(c))&0x7F]):((u_char)(c)))
#define hpfs_toupper(hpmp, c, cp) ((((u_char)(c))&0x80) ? ((u_char)((hpmp)->hpm_cpdblk[(cp)].b_upcase[((u_char)(c))&0x7F])) : ((((u_char)(c)) >= 'a' && ((u_char)(c)) <='z')?(((u_char)(c))-'a'+'A'):((u_char)(c))))
int hpfs_truncate (struct hpfsnode *, u_long);
int hpfs_extend (struct hpfsnode *, u_long);
int hpfs_updateparent (struct hpfsnode *);
int hpfs_update (struct hpfsnode *);
int hpfs_validateparent (struct hpfsnode *);
struct timespec hpfstimetounix (u_long);
int hpfs_genlookupbyname (struct hpfsnode *, char *, int,
struct buf **, struct hpfsdirent **);
int hpfs_makefnode (struct vnode *, struct vnode **,
struct componentname *, struct vattr *);
int hpfs_removefnode (struct vnode *, struct vnode *,
struct componentname *);
int hpfs_breadstruct (struct hpfsmount *, lsn_t, u_int, u_int32_t,
struct buf **);
#define hpfs_breadalsec(hpmp, lsn, bpp) \
hpfs_breadstruct(hpmp, lsn, DEV_BSIZE, AS_MAGIC, bpp)
#define hpfs_breaddirblk(hpmp, lsn, bpp) \
hpfs_breadstruct(hpmp, lsn, D_BSIZE, D_MAGIC, bpp)
#if 0
#define hpfs_hplock(hp, p) LOCKMGR(&(hp)->h_intlock, LK_EXCLUSIVE, (p))
#define hpfs_hpunlock(hp, p) LOCKMGR(&(hp)->h_intlock, LK_RELEASE, (p))
#endif
int hpfs_hpbmap (struct hpfsnode *, daddr_t, daddr_t *, int *);
int hpfs_truncatealblk (struct hpfsmount *, alblk_t *, lsn_t,int *);
int hpfs_addextent (struct hpfsmount *, struct hpfsnode *, u_long);

770
sys/fs/hpfs/hpfs_vfsops.c Normal file
View File

@ -0,0 +1,770 @@
/*-
* Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/namei.h>
#include <sys/conf.h>
#include <sys/proc.h>
#include <sys/kernel.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/buf.h>
#include <sys/fcntl.h>
#include <sys/malloc.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
#if defined(__NetBSD__)
#include <vm/vm_prot.h>
#endif
#include <vm/vm_page.h>
#include <vm/vm_object.h>
#include <vm/vm_extern.h>
#if defined(__NetBSD__)
#include <miscfs/specfs/specdev.h>
#endif
#include <fs/hpfs/hpfs.h>
#include <fs/hpfs/hpfsmount.h>
#include <fs/hpfs/hpfs_subr.h>
#if defined(__FreeBSD__)
MALLOC_DEFINE(M_HPFSMNT, "HPFS mount", "HPFS mount structure");
MALLOC_DEFINE(M_HPFSNO, "HPFS node", "HPFS node structure");
#endif
static int hpfs_root __P((struct mount *, struct vnode **));
static int hpfs_statfs __P((struct mount *, struct statfs *,
struct proc *));
static int hpfs_unmount __P((struct mount *, int, struct proc *));
static int hpfs_vget __P((struct mount *mp, ino_t ino,
struct vnode **vpp));
static int hpfs_mountfs __P((register struct vnode *, struct mount *,
struct hpfs_args *, struct proc *));
static int hpfs_vptofh __P((struct vnode *, struct fid *));
static int hpfs_fhtovp __P((struct mount *, struct fid *,
struct vnode **));
#if !defined(__FreeBSD__)
static int hpfs_quotactl __P((struct mount *, int, uid_t, caddr_t,
struct proc *));
static int hpfs_start __P((struct mount *, int, struct proc *));
static int hpfs_sync __P((struct mount *, int, struct ucred *,
struct proc *));
#endif
#if defined(__FreeBSD__)
struct sockaddr;
static int hpfs_mount __P((struct mount *, char *, caddr_t,
struct nameidata *, struct proc *));
static int hpfs_init __P((struct vfsconf *));
static int hpfs_checkexp __P((struct mount *, struct sockaddr *,
int *, struct ucred **));
#else /* defined(__NetBSD__) */
static int hpfs_mount __P((struct mount *, const char *, void *,
struct nameidata *, struct proc *));
static void hpfs_init __P((void));
static int hpfs_mountroot __P((void));
static int hpfs_sysctl __P((int *, u_int, void *, size_t *, void *,
size_t, struct proc *));
static int hpfs_checkexp __P((struct mount *, struct mbuf *,
int *, struct ucred **));
#endif
/*ARGSUSED*/
static int
hpfs_checkexp(mp, nam, exflagsp, credanonp)
#if defined(__FreeBSD__)
register struct mount *mp;
struct sockaddr *nam;
int *exflagsp;
struct ucred **credanonp;
#else /* defined(__NetBSD__) */
register struct mount *mp;
struct mbuf *nam;
int *exflagsp;
struct ucred **credanonp;
#endif
{
register struct netcred *np;
register struct hpfsmount *hpm = VFSTOHPFS(mp);
/*
* Get the export permission structure for this <mp, client> tuple.
*/
np = vfs_export_lookup(mp, &hpm->hpm_export, nam);
if (np == NULL)
return (EACCES);
*exflagsp = np->netc_exflags;
*credanonp = &np->netc_anon;
return (0);
}
#if !defined(__FreeBSD__)
/*ARGSUSED*/
static int
hpfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
int *name;
u_int namelen;
void *oldp;
size_t *oldlenp;
void *newp;
size_t newlen;
struct proc *p;
{
return (EINVAL);
}
static int
hpfs_mountroot()
{
return (EINVAL);
}
#endif
#if defined(__FreeBSD__)
static int
hpfs_init (
struct vfsconf *vcp )
#else /* defined(__NetBSD__) */
static void
hpfs_init ()
#endif
{
dprintf(("hpfs_init():\n"));
hpfs_hphashinit();
#if defined(__FreeBSD__)
return 0;
#endif
}
static int
hpfs_mount (
struct mount *mp,
#if defined(__FreeBSD__)
char *path,
caddr_t data,
#else /* defined(__NetBSD__) */
const char *path,
void *data,
#endif
struct nameidata *ndp,
struct proc *p )
{
u_int size;
int err = 0;
struct vnode *devvp;
struct hpfs_args args;
struct hpfsmount *hpmp = 0;
dprintf(("hpfs_mount():\n"));
/*
***
* Mounting non-root file system or updating a file system
***
*/
/* copy in user arguments*/
err = copyin(data, (caddr_t)&args, sizeof (struct hpfs_args));
if (err)
goto error_1; /* can't get arguments*/
/*
* If updating, check whether changing from read-only to
* read/write; if there is no device name, that's all we do.
*/
if (mp->mnt_flag & MNT_UPDATE) {
dprintf(("hpfs_mount: MNT_UPDATE: "));
hpmp = VFSTOHPFS(mp);
if (args.fspec == 0) {
dprintf(("export 0x%x\n",args.export.ex_flags));
err = vfs_export(mp, &hpmp->hpm_export, &args.export);
if (err) {
printf("hpfs_mount: vfs_export failed %d\n",
err);
}
goto success;
} else {
dprintf(("name [FAILED]\n"));
err = EINVAL;
goto success;
}
dprintf(("\n"));
}
/*
* Not an update, or updating the name: look up the name
* and verify that it refers to a sensible block device.
*/
NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
err = namei(ndp);
if (err) {
/* can't get devvp!*/
goto error_1;
}
devvp = ndp->ni_vp;
#if defined(__FreeBSD__)
if (!vn_isdisk(devvp)) {
err = ENOTBLK;
goto error_2;
}
#else /* defined(__NetBSD__) */
if (devvp->v_type != VBLK) {
err = ENOTBLK;
goto error_2;
}
if (major(devvp->v_rdev) >= nblkdev) {
err = ENXIO;
goto error_2;
}
#endif
/*
********************
* NEW MOUNT
********************
*/
/*
* Since this is a new mount, we want the names for
* the device and the mount point copied in. If an
* error occurs, the mountpoint is discarded by the
* upper level code.
*/
/* Save "last mounted on" info for mount point (NULL pad)*/
copyinstr( path, /* mount point*/
mp->mnt_stat.f_mntonname, /* save area*/
MNAMELEN - 1, /* max size*/
&size); /* real size*/
bzero( mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
/* Save "mounted from" info for mount point (NULL pad)*/
copyinstr( args.fspec, /* device name*/
mp->mnt_stat.f_mntfromname, /* save area*/
MNAMELEN - 1, /* max size*/
&size); /* real size*/
bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
err = hpfs_mountfs(devvp, mp, &args, p);
if (err)
goto error_2;
/*
* Initialize FS stat information in mount struct; uses both
* mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname
*
* This code is common to root and non-root mounts
*/
(void)VFS_STATFS(mp, &mp->mnt_stat, p);
goto success;
error_2: /* error with devvp held*/
/* release devvp before failing*/
vrele(devvp);
error_1: /* no state to back out*/
success:
return( err);
}
/*
* Common code for mount and mountroot
*/
int
hpfs_mountfs(devvp, mp, argsp, p)
register struct vnode *devvp;
struct mount *mp;
struct hpfs_args *argsp;
struct proc *p;
{
int error, ncount, ronly;
struct sublock *sup;
struct spblock *spp;
struct hpfsmount *hpmp;
struct buf *bp = NULL;
struct vnode *vp;
dev_t dev = devvp->v_rdev;
dprintf(("hpfs_mountfs():\n"));
/*
* Disallow multiple mounts of the same device.
* Disallow mounting of a device that is currently in use
* (except for root, which might share swap device for miniroot).
* Flush out any old buffers remaining from a previous use.
*/
error = vfs_mountedon(devvp);
if (error)
return (error);
ncount = vcount(devvp);
#if defined(__FreeBSD__)
if (devvp->v_object)
ncount -= 1;
#endif
if (ncount > 1 && devvp != rootvp)
return (EBUSY);
#if defined(__FreeBSD__)
VN_LOCK(devvp, LK_EXCLUSIVE | LK_RETRY, p);
error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
VOP__UNLOCK(devvp, 0, p);
#else
error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
#endif
if (error)
return (error);
ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
VN_LOCK(devvp, LK_EXCLUSIVE | LK_RETRY, p);
error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
VOP__UNLOCK(devvp, 0, p);
if (error)
return (error);
/*
* Do actual mount
*/
hpmp = malloc(sizeof(struct hpfsmount), M_HPFSMNT, M_WAITOK);
bzero(hpmp, sizeof(struct hpfsmount));
/* Read in SuperBlock */
error = bread(devvp, SUBLOCK, SUSIZE, NOCRED, &bp);
if (error)
goto failed;
bcopy(bp->b_data, &hpmp->hpm_su, sizeof(struct sublock));
brelse(bp); bp = NULL;
/* Read in SpareBlock */
error = bread(devvp, SPBLOCK, SPSIZE, NOCRED, &bp);
if (error)
goto failed;
bcopy(bp->b_data, &hpmp->hpm_sp, sizeof(struct spblock));
brelse(bp); bp = NULL;
sup = &hpmp->hpm_su;
spp = &hpmp->hpm_sp;
/* Check magic */
if (sup->su_magic != SU_MAGIC) {
printf("hpfs_mountfs: SuperBlock MAGIC DOESN'T MATCH\n");
error = EINVAL;
goto failed;
}
if (spp->sp_magic != SP_MAGIC) {
printf("hpfs_mountfs: SpareBlock MAGIC DOESN'T MATCH\n");
error = EINVAL;
goto failed;
}
mp->mnt_data = (qaddr_t)hpmp;
hpmp->hpm_devvp = devvp;
hpmp->hpm_dev = devvp->v_rdev;
hpmp->hpm_mp = mp;
hpmp->hpm_uid = argsp->uid;
hpmp->hpm_gid = argsp->gid;
hpmp->hpm_mode = argsp->mode;
error = hpfs_bminit(hpmp);
if (error)
goto failed;
error = hpfs_cpinit(hpmp, argsp);
if (error) {
hpfs_bmdeinit(hpmp);
goto failed;
}
error = hpfs_root(mp, &vp);
if (error) {
hpfs_cpdeinit(hpmp);
hpfs_bmdeinit(hpmp);
goto failed;
}
vput(vp);
#if defined(__FreeBSD__)
mp->mnt_stat.f_fsid.val[0] = (long)dev2udev(dev);
mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
#else
mp->mnt_stat.f_fsid.val[0] = (long)dev;
mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_HPFS);
#endif
mp->mnt_maxsymlinklen = 0;
mp->mnt_flag |= MNT_LOCAL;
devvp->v_specmountpoint = mp;
return (0);
failed:
if (bp)
brelse (bp);
mp->mnt_data = (qaddr_t)NULL;
#if defined(__FreeBSD__)
devvp->v_specmountpoint = NULL;
#else
devvp->v_specflags &= ~SI_MOUNTEDON;
#endif
(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
return (error);
}
#if !defined(__FreeBSD__)
static int
hpfs_start (
struct mount *mp,
int flags,
struct proc *p )
{
return (0);
}
#endif
static int
hpfs_unmount(
struct mount *mp,
int mntflags,
struct proc *p)
{
int error, flags, ronly;
register struct hpfsmount *hpmp = VFSTOHPFS(mp);
dprintf(("hpfs_unmount():\n"));
ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
flags = 0;
if(mntflags & MNT_FORCE)
flags |= FORCECLOSE;
dprintf(("hpfs_unmount: vflushing...\n"));
error = vflush(mp,NULLVP,flags);
if (error) {
printf("hpfs_unmount: vflush failed: %d\n",error);
return (error);
}
#if defined(__FreeBSD__)
hpmp->hpm_devvp->v_specmountpoint = NULL;
#else
hpmp->hpm_devvp->v_specflags &= ~SI_MOUNTEDON;
#endif
vinvalbuf(hpmp->hpm_devvp, V_SAVE, NOCRED, p, 0, 0);
error = VOP_CLOSE(hpmp->hpm_devvp, ronly ? FREAD : FREAD|FWRITE,
NOCRED, p);
vrele(hpmp->hpm_devvp);
dprintf(("hpfs_umount: freeing memory...\n"));
hpfs_cpdeinit(hpmp);
hpfs_bmdeinit(hpmp);
mp->mnt_data = (qaddr_t)0;
mp->mnt_flag &= ~MNT_LOCAL;
FREE(hpmp, M_HPFSMNT);
return (0);
}
static int
hpfs_root(
struct mount *mp,
struct vnode **vpp )
{
int error = 0;
struct hpfsmount *hpmp = VFSTOHPFS(mp);
dprintf(("hpfs_root():\n"));
error = VFS_VGET(mp, (ino_t)hpmp->hpm_su.su_rootfno, vpp);
if(error) {
printf("hpfs_root: VFS_VGET failed: %d\n",error);
return (error);
}
return (error);
}
static int
hpfs_statfs(
struct mount *mp,
struct statfs *sbp,
struct proc *p)
{
struct hpfsmount *hpmp = VFSTOHPFS(mp);
dprintf(("hpfs_statfs(): HPFS%d.%d\n",
hpmp->hpm_su.su_hpfsver, hpmp->hpm_su.su_fnctver));
#if defined(__FreeBSD__)
sbp->f_type = mp->mnt_vfc->vfc_typenum;
#else /* defined(__NetBSD__) */
sbp->f_type = 0;
#endif
sbp->f_bsize = DEV_BSIZE;
sbp->f_iosize = DEV_BSIZE;
sbp->f_blocks = hpmp->hpm_su.su_btotal;
sbp->f_bfree = sbp->f_bavail = hpmp->hpm_bavail;
sbp->f_ffree = 0;
sbp->f_files = 0;
if (sbp != &mp->mnt_stat) {
bcopy((caddr_t)mp->mnt_stat.f_mntonname,
(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
}
sbp->f_flags = mp->mnt_flag;
return (0);
}
#if !defined(__FreeBSD__)
static int
hpfs_sync (
struct mount *mp,
int waitfor,
struct ucred *cred,
struct proc *p)
{
return (0);
}
static int
hpfs_quotactl (
struct mount *mp,
int cmds,
uid_t uid,
caddr_t arg,
struct proc *p)
{
printf("hpfs_quotactl():\n");
return (EOPNOTSUPP);
}
#endif
/*ARGSUSED*/
static int
hpfs_fhtovp(
struct mount *mp,
struct fid *fhp,
struct vnode **vpp)
{
struct vnode *nvp;
struct hpfid *hpfhp = (struct hpfid *)fhp;
int error;
if ((error = VFS_VGET(mp, hpfhp->hpfid_ino, &nvp)) != 0) {
*vpp = NULLVP;
return (error);
}
/* XXX as unlink/rmdir/mkdir/creat are not currently possible
* with HPFS, we don't need to check anything else for now */
*vpp = nvp;
return (0);
}
static int
hpfs_vptofh(
struct vnode *vp,
struct fid *fhp)
{
register struct hpfsnode *hpp;
register struct hpfid *hpfhp;
hpp = VTOHP(vp);
hpfhp = (struct hpfid *)fhp;
hpfhp->hpfid_len = sizeof(struct hpfid);
hpfhp->hpfid_ino = hpp->h_no;
/* hpfhp->hpfid_gen = hpp->h_gen; */
return (0);
}
static int
hpfs_vget(
struct mount *mp,
ino_t ino,
struct vnode **vpp)
{
struct hpfsmount *hpmp = VFSTOHPFS(mp);
struct vnode *vp;
struct hpfsnode *hp;
struct buf *bp;
struct proc *p = curproc; /* XXX */
int error;
dprintf(("hpfs_vget(0x%x): ",ino));
*vpp = NULL;
hp = NULL;
vp = NULL;
if ((*vpp = hpfs_hphashvget(hpmp->hpm_dev, ino, p)) != NULL) {
dprintf(("hashed\n"));
return (0);
}
/*
* We have to lock node creation for a while,
* but then we have to call getnewvnode(),
* this may cause hpfs_reclaim() to be called,
* this may need to VOP_VGET() parent dir for
* update reasons, and if parent is not in
* hash, we have to lock node creation...
* To solve this, we MALLOC, getnewvnode and init while
* not locked (probability of node appearence
* at that time is little, and anyway - we'll
* check for it).
*/
MALLOC(hp, struct hpfsnode *, sizeof(struct hpfsnode),
M_HPFSNO, M_WAITOK);
error = getnewvnode(VT_HPFS, hpmp->hpm_mp, hpfs_vnodeop_p, &vp);
if (error) {
printf("hpfs_vget: can't get new vnode\n");
FREE(hp, M_HPFSNO);
return (error);
}
dprintf(("prenew "));
vp->v_data = hp;
if (ino == (ino_t)hpmp->hpm_su.su_rootfno)
vp->v_flag |= VROOT;
simple_lock_init(&hp->h_interlock);
lockinit(&hp->h_lock, PINOD, "hpnode", 0, 0);
hp->h_flag = H_INVAL;
hp->h_vp = vp;
hp->h_hpmp = hpmp;
hp->h_no = ino;
hp->h_dev = hpmp->hpm_dev;
hp->h_uid = hpmp->hpm_uid;
hp->h_gid = hpmp->hpm_uid;
hp->h_mode = hpmp->hpm_mode;
hp->h_devvp = hpmp->hpm_devvp;
VREF(hp->h_devvp);
error = VN_LOCK(vp, LK_EXCLUSIVE, p);
if (error) {
vput(vp);
return (error);
}
do {
if ((*vpp = hpfs_hphashvget(hpmp->hpm_dev, ino, p)) != NULL) {
dprintf(("hashed2\n"));
vput(vp);
return (0);
}
} while(LOCKMGR(&hpfs_hphash_lock,LK_EXCLUSIVE|LK_SLEEPFAIL,NULL,NULL));
hpfs_hphashins(hp);
LOCKMGR(&hpfs_hphash_lock, LK_RELEASE, NULL, NULL);
error = bread(hpmp->hpm_devvp, ino, FNODESIZE, NOCRED, &bp);
if (error) {
printf("hpfs_vget: can't read ino %d\n",ino);
vput(vp);
return (error);
}
bcopy(bp->b_data, &hp->h_fn, sizeof(struct fnode));
brelse(bp);
if (hp->h_fn.fn_magic != FN_MAGIC) {
printf("hpfs_vget: MAGIC DOESN'T MATCH\n");
vput(vp);
return (EINVAL);
}
vp->v_type = hp->h_fn.fn_flag ? VDIR:VREG;
hp->h_flag &= ~H_INVAL;
*vpp = vp;
return (0);
}
#if defined(__FreeBSD__)
static struct vfsops hpfs_vfsops = {
hpfs_mount,
vfs_stdstart,
hpfs_unmount,
hpfs_root,
vfs_stdquotactl,
hpfs_statfs,
vfs_stdsync,
hpfs_vget,
hpfs_fhtovp,
hpfs_checkexp,
hpfs_vptofh,
hpfs_init,
NULL
};
VFS_SET(hpfs_vfsops, hpfs, 0);
#else /* defined(__NetBSD__) */
extern struct vnodeopv_desc hpfs_vnodeop_opv_desc;
struct vnodeopv_desc *hpfs_vnodeopv_descs[] = {
&hpfs_vnodeop_opv_desc,
NULL,
};
struct vfsops hpfs_vfsops = {
MOUNT_HPFS,
hpfs_mount,
hpfs_start,
hpfs_unmount,
hpfs_root,
hpfs_quotactl,
hpfs_statfs,
hpfs_sync,
hpfs_vget,
hpfs_fhtovp,
hpfs_vptofh,
hpfs_init,
hpfs_sysctl,
hpfs_mountroot,
hpfs_checkexp,
hpfs_vnodeopv_descs,
};
#endif

1480
sys/fs/hpfs/hpfs_vnops.c Normal file

File diff suppressed because it is too large Load Diff

39
sys/fs/hpfs/hpfsmount.h Normal file
View File

@ -0,0 +1,39 @@
/*-
* Copyright (c) 1998, 1999 Semen Ustimenko (semenu@FreeBSD.org)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#define HPFSMNT_TABLES 0x0001
struct hpfs_args {
char *fspec; /* block special device to mount */
struct export_args export; /* network export information */
uid_t uid; /* uid that owns hpfs files */
gid_t gid; /* gid that owns hpfs files */
mode_t mode; /* mask to be applied for hpfs perms */
u_long flags; /* additional flags */
u_char d2u[0x80];
u_char u2d[0x80];
};

15
sys/modules/hpfs/Makefile Normal file
View File

@ -0,0 +1,15 @@
# $FreeBSD$
.PATH: ${.CURDIR}/../../fs/hpfs
KMOD= hpfs
SRCS= hpfs_vfsops.c hpfs_vnops.c hpfs_hash.c hpfs_subr.c hpfs_lookup.c \
hpfs_alsubr.c opt_vmpage.h
NOMAN=
VFS_KLD=
CFLAGS+= -DHPFS
CLEANFILES= opt_vmpage.h
opt_vmpage.h:
touch ${.TARGET}
.include <bsd.kmod.mk>