add support for PCFS, the MSDOS filesystem.

written by Paul Popelka (paulp@uts.amdahl.com) (patch 129)

invoke w/"options PCFS" in kernel config file.
This commit is contained in:
cgd 1993-04-09 19:37:49 +00:00
parent 6f9402e83b
commit 5cc382fc66
18 changed files with 5733 additions and 215 deletions

View File

@ -1,5 +1,32 @@
# $Header: /cvsroot/src/sys/conf/files,v 1.5 1993/04/09 19:38:32 cgd Exp $
#
ddb/db_access.c optional ddb
ddb/db_aout.c optional ddb
ddb/db_break.c optional ddb
ddb/db_command.c optional ddb
ddb/db_examine.c optional ddb
ddb/db_expr.c optional ddb
ddb/db_input.c optional ddb
ddb/db_lex.c optional ddb
ddb/db_output.c optional ddb
ddb/db_print.c optional ddb
ddb/db_run.c optional ddb
ddb/db_sym.c optional ddb
ddb/db_trap.c optional ddb
ddb/db_variables.c optional ddb
ddb/db_watch.c optional ddb
ddb/db_write_cmd.c optional ddb
isofs/isofs_bmap.c optional isofs
isofs/isofs_lookup.c optional isofs
isofs/isofs_node.c optional isofs
isofs/isofs_util.c optional isofs
isofs/isofs_vfsops.c optional isofs
isofs/isofs_vnops.c optional isofs
kern/dead_vnops.c standard
kern/fifo_vnops.c optional fifo
kern/init_main.c standard
kern/init_sysent.c standard
kern/kern__physio.c standard
kern/kern_acct.c standard
kern/kern_clock.c standard
kern/kern_descrip.c standard
@ -9,7 +36,6 @@ kern/kern_fork.c standard
kern/kern_kinfo.c standard
kern/kern_ktrace.c optional ktrace
kern/kern_malloc.c standard
kern/kern__physio.c standard
kern/kern_proc.c standard
kern/kern_prot.c standard
kern/kern_resource.c standard
@ -18,9 +44,7 @@ kern/kern_subr.c standard
kern/kern_synch.c standard
kern/kern_time.c standard
kern/kern_xxx.c standard
kern/dead_vnops.c standard
kern/spec_vnops.c standard
kern/fifo_vnops.c optional fifo
kern/subr_log.c standard
kern/subr_mcount.c optional profiling-routine
kern/subr_prf.c standard
@ -29,6 +53,7 @@ kern/subr_xxx.c standard
kern/sys_generic.c standard
kern/sys_process.c standard
kern/sys_socket.c standard
kern/sysv_shm.c optional sysvshm
kern/tty.c standard
kern/tty_compat.c standard
kern/tty_conf.c standard
@ -36,13 +61,6 @@ kern/tty_pty.c optional pty
kern/tty_ring.c standard
kern/tty_tb.c optional tb
kern/tty_tty.c standard
kern/vfs__bio.c standard
kern/vfs_cache.c standard
kern/vfs_conf.c standard
kern/vfs_lookup.c standard
kern/vfs_subr.c standard
kern/vfs_syscalls.c standard
kern/vfs_vnops.c standard
kern/uipc_domain.c standard
kern/uipc_mbuf.c standard
kern/uipc_proto.c standard
@ -50,47 +68,17 @@ kern/uipc_socket.c standard
kern/uipc_socket2.c standard
kern/uipc_syscalls.c standard
kern/uipc_usrreq.c standard
kern/sysv_shm.c optional sysvshm
vm/kern_lock.c standard
vm/vm_fault.c standard
vm/vm_glue.c standard
vm/vm_init.c standard
vm/vm_kern.c standard
vm/vm_map.c standard
vm/vm_meter.c standard
vm/vm_mmap.c standard
vm/vm_object.c standard
vm/vm_page.c standard
vm/vm_pageout.c standard
vm/vm_pager.c standard
vm/vm_swap.c standard
vm/vm_unix.c standard
vm/vm_user.c standard
vm/device_pager.c optional devpager
vm/swap_pager.c optional swappager
vm/vnode_pager.c optional vnodepager
ufs/ufs_alloc.c standard
ufs/ufs_bmap.c standard
ufs/ufs_disksubr.c standard
ufs/ufs_inode.c standard
ufs/ufs_lockf.c standard
ufs/ufs_lookup.c standard
ufs/ufs_subr.c standard
ufs/ufs_tables.c standard
ufs/ufs_vfsops.c standard
ufs/ufs_vnops.c standard
ufs/ufs_quota.c optional quota
ufs/mfs_vnops.c optional mfs
ufs/mfs_vfsops.c optional mfs
nfs/nfs_bio.c optional nfs
nfs/nfs_node.c optional nfs
nfs/nfs_serv.c optional nfs
nfs/nfs_socket.c optional nfs
nfs/nfs_srvcache.c optional nfs
nfs/nfs_subs.c optional nfs
nfs/nfs_syscalls.c optional nfs
nfs/nfs_vfsops.c optional nfs
nfs/nfs_vnops.c optional nfs
kern/vfs__bio.c standard
kern/vfs_cache.c standard
kern/vfs_conf.c standard
kern/vfs_lookup.c standard
kern/vfs_subr.c standard
kern/vfs_syscalls.c standard
kern/vfs_vnops.c standard
miscfs/fdesc/fdesc_vfsops.c optional fdesc
miscfs/fdesc/fdesc_vnops.c optional fdesc
miscfs/kernfs/kernfs_vfsops.c optional kernfs
miscfs/kernfs/kernfs_vnops.c optional kernfs
net/af.c standard
net/bpf.c optional bpfilter
net/bpf_filter.c optional bpfilter
@ -99,12 +87,26 @@ net/if_ethersubr.c optional ether
net/if_loop.c optional loop
net/if_sl.c optional sl
net/if_tun.c optional tun device-driver
net/radix.c standard
net/raw_cb.c standard
net/raw_usrreq.c standard
net/radix.c standard
net/route.c standard
net/rtsock.c standard
net/slcompress.c optional sl
netccitt/ccitt_proto.c optional ccitt
netccitt/hd_debug.c optional ccitt
netccitt/hd_input.c optional ccitt
netccitt/hd_output.c optional ccitt
netccitt/hd_subr.c optional ccitt
netccitt/hd_timer.c optional ccitt
netccitt/if_x25subr.c optional ccitt
netccitt/pk_acct.c optional ccitt
netccitt/pk_debug.c optional ccitt
netccitt/pk_input.c optional ccitt
netccitt/pk_output.c optional ccitt
netccitt/pk_subr.c optional ccitt
netccitt/pk_timer.c optional ccitt
netccitt/pk_usrreq.c optional ccitt
netimp/if_imp.c optional imp
netimp/if_imphost.c optional imp
netimp/raw_imp.c optional imp
@ -123,16 +125,6 @@ netinet/tcp_subr.c optional inet
netinet/tcp_timer.c optional inet
netinet/tcp_usrreq.c optional inet
netinet/udp_usrreq.c optional inet
netns/idp_usrreq.c optional ns
netns/ns.c optional ns
netns/ns_error.c optional ns
netns/ns_ip.c optional ns
netns/ns_input.c optional ns
netns/ns_output.c optional ns
netns/ns_pcb.c optional ns
netns/ns_proto.c optional ns
netns/spp_debug.c optional ns
netns/spp_usrreq.c optional ns
netiso/clnp_debug.c optional iso
netiso/clnp_er.c optional iso
netiso/clnp_frag.c optional iso
@ -144,6 +136,7 @@ netiso/clnp_subr.c optional iso
netiso/clnp_timer.c optional iso
netiso/cltp_usrreq.c optional iso
netiso/esis.c optional iso
netiso/if_eon.c optional eon
netiso/iso.c optional iso
netiso/iso_chksum.c optional iso
netiso/iso_pcb.c optional iso
@ -177,49 +170,64 @@ netiso/tp_trace.c optional iso
netiso/tp_trace.c optional tpip
netiso/tp_usrreq.c optional iso
netiso/tp_usrreq.c optional tpip
netiso/if_eon.c optional eon
netccitt/ccitt_proto.c optional ccitt
netccitt/hd_debug.c optional ccitt
netccitt/hd_input.c optional ccitt
netccitt/hd_output.c optional ccitt
netccitt/hd_subr.c optional ccitt
netccitt/hd_timer.c optional ccitt
netccitt/if_x25subr.c optional ccitt
netccitt/pk_acct.c optional ccitt
netccitt/pk_debug.c optional ccitt
netccitt/pk_input.c optional ccitt
netccitt/pk_output.c optional ccitt
netccitt/pk_subr.c optional ccitt
netccitt/pk_timer.c optional ccitt
netccitt/pk_usrreq.c optional ccitt
isofs/isofs_bmap.c optional isofs
isofs/isofs_lookup.c optional isofs
isofs/isofs_node.c optional isofs
isofs/isofs_util.c optional isofs
isofs/isofs_vfsops.c optional isofs
isofs/isofs_vnops.c optional isofs
ddb/db_access.c optional ddb
ddb/db_aout.c optional ddb
ddb/db_break.c optional ddb
ddb/db_command.c optional ddb
ddb/db_examine.c optional ddb
ddb/db_expr.c optional ddb
ddb/db_input.c optional ddb
ddb/db_lex.c optional ddb
ddb/db_output.c optional ddb
ddb/db_print.c optional ddb
ddb/db_run.c optional ddb
ddb/db_sym.c optional ddb
ddb/db_trap.c optional ddb
ddb/db_variables.c optional ddb
ddb/db_watch.c optional ddb
ddb/db_write_cmd.c optional ddb
scsi/scsiconf.c optional scsi
scsi/st.c optional st
scsi/sd.c optional sd
netns/idp_usrreq.c optional ns
netns/ns.c optional ns
netns/ns_error.c optional ns
netns/ns_input.c optional ns
netns/ns_ip.c optional ns
netns/ns_output.c optional ns
netns/ns_pcb.c optional ns
netns/ns_proto.c optional ns
netns/spp_debug.c optional ns
netns/spp_usrreq.c optional ns
nfs/nfs_bio.c optional nfs
nfs/nfs_node.c optional nfs
nfs/nfs_serv.c optional nfs
nfs/nfs_socket.c optional nfs
nfs/nfs_srvcache.c optional nfs
nfs/nfs_subs.c optional nfs
nfs/nfs_syscalls.c optional nfs
nfs/nfs_vfsops.c optional nfs
nfs/nfs_vnops.c optional nfs
pcfs/pcfs_conv.c optional pcfs
pcfs/pcfs_denode.c optional pcfs
pcfs/pcfs_fat.c optional pcfs
pcfs/pcfs_lookup.c optional pcfs
pcfs/pcfs_vfsops.c optional pcfs
pcfs/pcfs_vnops.c optional pcfs
scsi/cd.c optional cd
scsi/ch.c optional ch
miscfs/fdesc/fdesc_vfsops.c optional fdesc
miscfs/fdesc/fdesc_vnops.c optional fdesc
miscfs/kernfs/kernfs_vfsops.c optional kernfs
miscfs/kernfs/kernfs_vnops.c optional kernfs
scsi/scsiconf.c optional scsi
scsi/sd.c optional sd
scsi/st.c optional st
ufs/mfs_vfsops.c optional mfs
ufs/mfs_vnops.c optional mfs
ufs/ufs_alloc.c standard
ufs/ufs_bmap.c standard
ufs/ufs_disksubr.c standard
ufs/ufs_inode.c standard
ufs/ufs_lockf.c standard
ufs/ufs_lookup.c standard
ufs/ufs_quota.c optional quota
ufs/ufs_subr.c standard
ufs/ufs_tables.c standard
ufs/ufs_vfsops.c standard
ufs/ufs_vnops.c standard
vm/device_pager.c optional devpager
vm/kern_lock.c standard
vm/swap_pager.c optional swappager
vm/vm_fault.c standard
vm/vm_glue.c standard
vm/vm_init.c standard
vm/vm_kern.c standard
vm/vm_map.c standard
vm/vm_meter.c standard
vm/vm_mmap.c standard
vm/vm_object.c standard
vm/vm_page.c standard
vm/vm_pageout.c standard
vm/vm_pager.c standard
vm/vm_swap.c standard
vm/vm_unix.c standard
vm/vm_user.c standard
vm/vnode_pager.c optional vnodepager

View File

@ -1,5 +1,32 @@
# $Header: /cvsroot/src/sys/conf/Attic/files.oldconf,v 1.5 1993/04/09 19:38:32 cgd Exp $
#
ddb/db_access.c optional ddb
ddb/db_aout.c optional ddb
ddb/db_break.c optional ddb
ddb/db_command.c optional ddb
ddb/db_examine.c optional ddb
ddb/db_expr.c optional ddb
ddb/db_input.c optional ddb
ddb/db_lex.c optional ddb
ddb/db_output.c optional ddb
ddb/db_print.c optional ddb
ddb/db_run.c optional ddb
ddb/db_sym.c optional ddb
ddb/db_trap.c optional ddb
ddb/db_variables.c optional ddb
ddb/db_watch.c optional ddb
ddb/db_write_cmd.c optional ddb
isofs/isofs_bmap.c optional isofs
isofs/isofs_lookup.c optional isofs
isofs/isofs_node.c optional isofs
isofs/isofs_util.c optional isofs
isofs/isofs_vfsops.c optional isofs
isofs/isofs_vnops.c optional isofs
kern/dead_vnops.c standard
kern/fifo_vnops.c optional fifo
kern/init_main.c standard
kern/init_sysent.c standard
kern/kern__physio.c standard
kern/kern_acct.c standard
kern/kern_clock.c standard
kern/kern_descrip.c standard
@ -9,7 +36,6 @@ kern/kern_fork.c standard
kern/kern_kinfo.c standard
kern/kern_ktrace.c optional ktrace
kern/kern_malloc.c standard
kern/kern__physio.c standard
kern/kern_proc.c standard
kern/kern_prot.c standard
kern/kern_resource.c standard
@ -18,9 +44,7 @@ kern/kern_subr.c standard
kern/kern_synch.c standard
kern/kern_time.c standard
kern/kern_xxx.c standard
kern/dead_vnops.c standard
kern/spec_vnops.c standard
kern/fifo_vnops.c optional fifo
kern/subr_log.c standard
kern/subr_mcount.c optional profiling-routine
kern/subr_prf.c standard
@ -29,6 +53,7 @@ kern/subr_xxx.c standard
kern/sys_generic.c standard
kern/sys_process.c standard
kern/sys_socket.c standard
kern/sysv_shm.c optional sysvshm
kern/tty.c standard
kern/tty_compat.c standard
kern/tty_conf.c standard
@ -36,13 +61,6 @@ kern/tty_pty.c optional pty
kern/tty_ring.c standard
kern/tty_tb.c optional tb
kern/tty_tty.c standard
kern/vfs__bio.c standard
kern/vfs_cache.c standard
kern/vfs_conf.c standard
kern/vfs_lookup.c standard
kern/vfs_subr.c standard
kern/vfs_syscalls.c standard
kern/vfs_vnops.c standard
kern/uipc_domain.c standard
kern/uipc_mbuf.c standard
kern/uipc_proto.c standard
@ -50,47 +68,17 @@ kern/uipc_socket.c standard
kern/uipc_socket2.c standard
kern/uipc_syscalls.c standard
kern/uipc_usrreq.c standard
kern/sysv_shm.c optional sysvshm
vm/kern_lock.c standard
vm/vm_fault.c standard
vm/vm_glue.c standard
vm/vm_init.c standard
vm/vm_kern.c standard
vm/vm_map.c standard
vm/vm_meter.c standard
vm/vm_mmap.c standard
vm/vm_object.c standard
vm/vm_page.c standard
vm/vm_pageout.c standard
vm/vm_pager.c standard
vm/vm_swap.c standard
vm/vm_unix.c standard
vm/vm_user.c standard
vm/device_pager.c optional devpager
vm/swap_pager.c optional swappager
vm/vnode_pager.c optional vnodepager
ufs/ufs_alloc.c standard
ufs/ufs_bmap.c standard
ufs/ufs_disksubr.c standard
ufs/ufs_inode.c standard
ufs/ufs_lockf.c standard
ufs/ufs_lookup.c standard
ufs/ufs_subr.c standard
ufs/ufs_tables.c standard
ufs/ufs_vfsops.c standard
ufs/ufs_vnops.c standard
ufs/ufs_quota.c optional quota
ufs/mfs_vnops.c optional mfs
ufs/mfs_vfsops.c optional mfs
nfs/nfs_bio.c optional nfs
nfs/nfs_node.c optional nfs
nfs/nfs_serv.c optional nfs
nfs/nfs_socket.c optional nfs
nfs/nfs_srvcache.c optional nfs
nfs/nfs_subs.c optional nfs
nfs/nfs_syscalls.c optional nfs
nfs/nfs_vfsops.c optional nfs
nfs/nfs_vnops.c optional nfs
kern/vfs__bio.c standard
kern/vfs_cache.c standard
kern/vfs_conf.c standard
kern/vfs_lookup.c standard
kern/vfs_subr.c standard
kern/vfs_syscalls.c standard
kern/vfs_vnops.c standard
miscfs/fdesc/fdesc_vfsops.c optional fdesc
miscfs/fdesc/fdesc_vnops.c optional fdesc
miscfs/kernfs/kernfs_vfsops.c optional kernfs
miscfs/kernfs/kernfs_vnops.c optional kernfs
net/af.c standard
net/bpf.c optional bpfilter
net/bpf_filter.c optional bpfilter
@ -99,12 +87,26 @@ net/if_ethersubr.c optional ether
net/if_loop.c optional loop
net/if_sl.c optional sl
net/if_tun.c optional tun device-driver
net/radix.c standard
net/raw_cb.c standard
net/raw_usrreq.c standard
net/radix.c standard
net/route.c standard
net/rtsock.c standard
net/slcompress.c optional sl
netccitt/ccitt_proto.c optional ccitt
netccitt/hd_debug.c optional ccitt
netccitt/hd_input.c optional ccitt
netccitt/hd_output.c optional ccitt
netccitt/hd_subr.c optional ccitt
netccitt/hd_timer.c optional ccitt
netccitt/if_x25subr.c optional ccitt
netccitt/pk_acct.c optional ccitt
netccitt/pk_debug.c optional ccitt
netccitt/pk_input.c optional ccitt
netccitt/pk_output.c optional ccitt
netccitt/pk_subr.c optional ccitt
netccitt/pk_timer.c optional ccitt
netccitt/pk_usrreq.c optional ccitt
netimp/if_imp.c optional imp
netimp/if_imphost.c optional imp
netimp/raw_imp.c optional imp
@ -123,16 +125,6 @@ netinet/tcp_subr.c optional inet
netinet/tcp_timer.c optional inet
netinet/tcp_usrreq.c optional inet
netinet/udp_usrreq.c optional inet
netns/idp_usrreq.c optional ns
netns/ns.c optional ns
netns/ns_error.c optional ns
netns/ns_ip.c optional ns
netns/ns_input.c optional ns
netns/ns_output.c optional ns
netns/ns_pcb.c optional ns
netns/ns_proto.c optional ns
netns/spp_debug.c optional ns
netns/spp_usrreq.c optional ns
netiso/clnp_debug.c optional iso
netiso/clnp_er.c optional iso
netiso/clnp_frag.c optional iso
@ -144,6 +136,7 @@ netiso/clnp_subr.c optional iso
netiso/clnp_timer.c optional iso
netiso/cltp_usrreq.c optional iso
netiso/esis.c optional iso
netiso/if_eon.c optional eon
netiso/iso.c optional iso
netiso/iso_chksum.c optional iso
netiso/iso_pcb.c optional iso
@ -177,49 +170,64 @@ netiso/tp_trace.c optional iso
netiso/tp_trace.c optional tpip
netiso/tp_usrreq.c optional iso
netiso/tp_usrreq.c optional tpip
netiso/if_eon.c optional eon
netccitt/ccitt_proto.c optional ccitt
netccitt/hd_debug.c optional ccitt
netccitt/hd_input.c optional ccitt
netccitt/hd_output.c optional ccitt
netccitt/hd_subr.c optional ccitt
netccitt/hd_timer.c optional ccitt
netccitt/if_x25subr.c optional ccitt
netccitt/pk_acct.c optional ccitt
netccitt/pk_debug.c optional ccitt
netccitt/pk_input.c optional ccitt
netccitt/pk_output.c optional ccitt
netccitt/pk_subr.c optional ccitt
netccitt/pk_timer.c optional ccitt
netccitt/pk_usrreq.c optional ccitt
isofs/isofs_bmap.c optional isofs
isofs/isofs_lookup.c optional isofs
isofs/isofs_node.c optional isofs
isofs/isofs_util.c optional isofs
isofs/isofs_vfsops.c optional isofs
isofs/isofs_vnops.c optional isofs
ddb/db_access.c optional ddb
ddb/db_aout.c optional ddb
ddb/db_break.c optional ddb
ddb/db_command.c optional ddb
ddb/db_examine.c optional ddb
ddb/db_expr.c optional ddb
ddb/db_input.c optional ddb
ddb/db_lex.c optional ddb
ddb/db_output.c optional ddb
ddb/db_print.c optional ddb
ddb/db_run.c optional ddb
ddb/db_sym.c optional ddb
ddb/db_trap.c optional ddb
ddb/db_variables.c optional ddb
ddb/db_watch.c optional ddb
ddb/db_write_cmd.c optional ddb
scsi/scsiconf.c optional scsi
scsi/st.c optional st
scsi/sd.c optional sd
netns/idp_usrreq.c optional ns
netns/ns.c optional ns
netns/ns_error.c optional ns
netns/ns_input.c optional ns
netns/ns_ip.c optional ns
netns/ns_output.c optional ns
netns/ns_pcb.c optional ns
netns/ns_proto.c optional ns
netns/spp_debug.c optional ns
netns/spp_usrreq.c optional ns
nfs/nfs_bio.c optional nfs
nfs/nfs_node.c optional nfs
nfs/nfs_serv.c optional nfs
nfs/nfs_socket.c optional nfs
nfs/nfs_srvcache.c optional nfs
nfs/nfs_subs.c optional nfs
nfs/nfs_syscalls.c optional nfs
nfs/nfs_vfsops.c optional nfs
nfs/nfs_vnops.c optional nfs
pcfs/pcfs_conv.c optional pcfs
pcfs/pcfs_denode.c optional pcfs
pcfs/pcfs_fat.c optional pcfs
pcfs/pcfs_lookup.c optional pcfs
pcfs/pcfs_vfsops.c optional pcfs
pcfs/pcfs_vnops.c optional pcfs
scsi/cd.c optional cd
scsi/ch.c optional ch
miscfs/fdesc/fdesc_vfsops.c optional fdesc
miscfs/fdesc/fdesc_vnops.c optional fdesc
miscfs/kernfs/kernfs_vfsops.c optional kernfs
miscfs/kernfs/kernfs_vnops.c optional kernfs
scsi/scsiconf.c optional scsi
scsi/sd.c optional sd
scsi/st.c optional st
ufs/mfs_vfsops.c optional mfs
ufs/mfs_vnops.c optional mfs
ufs/ufs_alloc.c standard
ufs/ufs_bmap.c standard
ufs/ufs_disksubr.c standard
ufs/ufs_inode.c standard
ufs/ufs_lockf.c standard
ufs/ufs_lookup.c standard
ufs/ufs_quota.c optional quota
ufs/ufs_subr.c standard
ufs/ufs_tables.c standard
ufs/ufs_vfsops.c standard
ufs/ufs_vnops.c standard
vm/device_pager.c optional devpager
vm/kern_lock.c standard
vm/swap_pager.c optional swappager
vm/vm_fault.c standard
vm/vm_glue.c standard
vm/vm_init.c standard
vm/vm_kern.c standard
vm/vm_map.c standard
vm/vm_meter.c standard
vm/vm_mmap.c standard
vm/vm_object.c standard
vm/vm_page.c standard
vm/vm_pageout.c standard
vm/vm_pager.c standard
vm/vm_swap.c standard
vm/vm_unix.c standard
vm/vm_user.c standard
vm/vnode_pager.c optional vnodepager

View File

@ -63,6 +63,10 @@ extern struct vfsops nfs_vfsops;
extern struct vfsops mfs_vfsops;
#endif
#ifdef PCFS
extern struct vfsops pcfs_vfsops;
#endif
#ifdef ISOFS
extern struct vfsops isofs_vfsops;
#endif
@ -88,7 +92,11 @@ struct vfsops *vfssw[] = {
#else
(struct vfsops *)0,
#endif
(struct vfsops *)0, /* 4 = MOUNT_MSDOS */
#ifdef PCFS
&pcfs_vfsops, /* 4 = MOUNT_MSDOS */
#else
(struct vfsops *)0,
#endif
#ifdef ISOFS
&isofs_vfsops, /* 5 = MOUNT_ISOFS */
#else

73
sys/pcfs/bootsect.h Normal file
View File

@ -0,0 +1,73 @@
/*
* Written by Paul Popelka (paulp@uts.amdahl.com)
*
* You can do anything you want with this software,
* just don't say you wrote it,
* and don't remove this notice.
*
* This software is provided "as is".
*
* The author supplies this software to be publicly
* redistributed on the understanding that the author
* is not responsible for the correct functioning of
* this software in any circumstances and is not liable
* for any damages caused by this software.
*
* October 1992
*
* $Header: /cvsroot/src/sys/pcfs/Attic/bootsect.h,v 1.1 1993/04/09 19:37:49 cgd Exp $
*
*/
/*
* Format of a boot sector. This is the first sector
* on a DOS floppy disk or the fist sector of a partition
* on a hard disk. But, it is not the first sector of
* a partitioned hard disk.
*/
struct bootsector33 {
char bsJump[3]; /* jump instruction E9xxxx or EBxx90 */
char bsOemName[8]; /* OEM name and version */
char bsBPB[19]; /* BIOS parameter block */
char bsDriveNumber; /* drive number (0x80) */
char bsBootCode[474]; /* pad so structure is 512 bytes long */
u_short bsBootSectSig;
#define BOOTSIG 0xaa55
};
struct bootsector50 {
char bsJump[3]; /* jump instruction E9xxxx or EBxx90 */
char bsOemName[8]; /* OEM name and version */
char bsBPB[25]; /* BIOS parameter block */
char bsDriveNumber; /* drive number (0x80) */
char bsReserved1; /* reserved */
char bsBootSignature; /* extended boot signature (0x29) */
#define EXBOOTSIG 0x29
char bsVolumeID[4]; /* volume ID number */
char bsVolumeLabel[11]; /* volume label */
char bsFileSysType[8]; /* file system type (FAT12 or FAT16) */
char bsBootCode[448]; /* pad so structure is 512 bytes long */
u_short bsBootSectSig;
#define BOOTSIG 0xaa55
};
union bootsector {
struct bootsector33 bs33;
struct bootsector50 bs50;
};
/*
* Shorthand for fields in the bpb.
*/
#define bsBytesPerSec bsBPB.bpbBytesPerSec
#define bsSectPerClust bsBPB.bpbSectPerClust
#define bsResSectors bsBPB.bpbResSectors
#define bsFATS bsBPB.bpbFATS
#define bsRootDirEnts bsBPB.bpbRootDirEnts
#define bsSectors bsBPB.bpbSectors
#define bsMedia bsBPB.bpbMedia
#define bsFATsecs bsBPB.bpbFATsecs
#define bsSectPerTrack bsBPB.bpbSectPerTrack
#define bsHeads bsBPB.bpbHeads
#define bsHiddenSecs bsBPB.bpbHiddenSecs
#define bsHugeSectors bsBPB.bpbHugeSectors

111
sys/pcfs/bpb.h Normal file
View File

@ -0,0 +1,111 @@
/*
* Written by Paul Popelka (paulp@uts.amdahl.com)
*
* You can do anything you want with this software,
* just don't say you wrote it,
* and don't remove this notice.
*
* This software is provided "as is".
*
* The author supplies this software to be publicly
* redistributed on the understanding that the author
* is not responsible for the correct functioning of
* this software in any circumstances and is not liable
* for any damages caused by this software.
*
* October 1992
*
* $Header: /cvsroot/src/sys/pcfs/Attic/bpb.h,v 1.1 1993/04/09 19:37:53 cgd Exp $
*
*/
/*
* BIOS Parameter Block (BPB) for DOS 3.3
*/
struct bpb33 {
u_short bpbBytesPerSec; /* bytes per sector */
u_char bpbSecPerClust; /* sectors per cluster */
u_short bpbResSectors; /* number of reserved sectors */
u_char bpbFATs; /* number of FATs */
u_short bpbRootDirEnts; /* number of root directory entries */
u_short bpbSectors; /* total number of sectors */
u_char bpbMedia; /* media descriptor */
u_short bpbFATsecs; /* number of sectors per FAT */
u_short bpbSecPerTrack; /* sectors per track */
u_short bpbHeads; /* number of heads */
u_short bpbHiddenSecs; /* number of hidden sectors */
};
/*
* BPB for DOS 5.0
* The difference is bpbHiddenSecs is a short for DOS 3.3,
* and bpbHugeSectors is not in the 3.3 bpb.
*/
struct bpb50 {
u_short bpbBytesPerSec; /* bytes per sector */
u_char bpbSecPerClust; /* sectors per cluster */
u_short bpbResSectors; /* number of reserved sectors */
u_char bpbFATs; /* number of FATs */
u_short bpbRootDirEnts; /* number of root directory entries */
u_short bpbSectors; /* total number of sectors */
u_char bpbMedia; /* media descriptor */
u_short bpbFATsecs; /* number of sectors per FAT */
u_short bpbSecPerTrack; /* sectors per track */
u_short bpbHeads; /* number of heads */
u_long bpbHiddenSecs; /* number of hidden sectors */
u_long bpbHugeSectors; /* number of sectrs if bpbSectors == 0 */
};
/*
* The following structures represent how the bpb's look
* on disk. shorts and longs are just character arrays
* of the appropriate length. This is because the compiler
* forces shorts and longs to align on word or halfword
* boundaries.
*/
#include <machine/endian.h>
#if BYTE_ORDER == LITTLE_ENDIAN
#define getushort(x) *((u_short *)(x))
#define getulong(x) *((u_long *)(x))
#define putushort(p, v) (*((u_short *)(p)) = (v))
#define putulong(p, v) (*((u_long *)(p)) = (v))
#else
#endif
/*
* BIOS Parameter Block (BPB) for DOS 3.3
*/
struct byte_bpb33 {
char bpbBytesPerSec[2]; /* bytes per sector */
char bpbSecPerClust; /* sectors per cluster */
char bpbResSectors[2]; /* number of reserved sectors */
char bpbFATs; /* number of FATs */
char bpbRootDirEnts[2]; /* number of root directory entries */
char bpbSectors[2]; /* total number of sectors */
char bpbMedia; /* media descriptor */
char bpbFATsecs[2]; /* number of sectors per FAT */
char bpbSecPerTrack[2]; /* sectors per track */
char bpbHeads[2]; /* number of heads */
char bpbHiddenSecs[2]; /* number of hidden sectors */
};
/*
* BPB for DOS 5.0
* The difference is bpbHiddenSecs is a short for DOS 3.3,
* and bpbHugeSectors is not in the 3.3 bpb.
*/
struct byte_bpb50 {
char bpbBytesPerSec[2]; /* bytes per sector */
char bpbSecPerClust; /* sectors per cluster */
char bpbResSectors[2]; /* number of reserved sectors */
char bpbFATs; /* number of FATs */
char bpbRootDirEnts[2]; /* number of root directory entries */
char bpbSectors[2]; /* total number of sectors */
char bpbMedia; /* media descriptor */
char bpbFATsecs[2]; /* number of sectors per FAT */
char bpbSecPerTrack[2]; /* sectors per track */
char bpbHeads[2]; /* number of heads */
char bpbHiddenSecs[4]; /* number of hidden sectors */
char bpbHugeSectors[4]; /* number of sectrs if bpbSectors == 0 */
};

249
sys/pcfs/denode.h Normal file
View File

@ -0,0 +1,249 @@
/*
* Written by Paul Popelka (paulp@uts.amdahl.com)
*
* You can do anything you want with this software,
* just don't say you wrote it,
* and don't remove this notice.
*
* This software is provided "as is".
*
* The author supplies this software to be publicly
* redistributed on the understanding that the author
* is not responsible for the correct functioning of
* this software in any circumstances and is not liable
* for any damages caused by this software.
*
* October 1992
*
* $Header: /cvsroot/src/sys/pcfs/Attic/denode.h,v 1.1 1993/04/09 19:37:55 cgd Exp $
*
*/
/*
* This is the pc filesystem specific portion of the
* vnode structure.
* To describe a file uniquely the de_dirclust, de_diroffset,
* and de_de.deStartCluster fields are used. de_dirclust
* contains the cluster number of the directory cluster containing
* the entry for a file or directory. de_diroffset is the
* index into the cluster for the entry describing a file
* or directory. de_de.deStartCluster is the number of the
* first cluster of the file or directory. Now to describe the
* quirks of the pc filesystem.
* - Clusters 0 and 1 are reserved.
* - The first allocatable cluster is 2.
* - The root directory is of fixed size and all blocks that
* make it up are contiguous.
* - Cluster 0 refers to the root directory when it is found
* in the startcluster field of a directory entry that points
* to another directory.
* - Cluster 0 implies a 0 length file when found in the start
* cluster field of a directory entry that points to a file.
* - You can't use the cluster number 0 to derive
* the address of the root directory.
* - Multiple directory entries can point to a directory.
* The entry in the parent directory points to a child
* directory. Any directories in the child directory contain
* a ".." entry that points back to the child. The child
* directory itself contains a "." entry that points to
* itself.
* - The root directory does not contain a "." or ".." entry.
* - Directory entries for directories are never changed once
* they are created (except when removed). The size stays
* 0, and the last modification time is never changed. This
* is because so many directory entries can point to the physical
* clusters that make up a directory. It would lead to an update
* nightmare.
* - The length field in a directory entry pointing to a directory
* contains 0 (always). The only way to find the end of a directory
* is to follow the cluster chain until the "last cluster"
* marker is found.
* My extensions to make this house of cards work. These apply
* only to the in memory copy of the directory entry.
* - A reference count for each denode will be kept since dos doesn't
* keep such things.
*/
/* Internal pseudo-offset for (nonexistent) directory entry for the root dir
* in the root dir */
#define PCFSROOT_OFS 0x1fffffff
/*
* The fat cache structure.
* fc_fsrcn is the filesystem relative cluster number
* that corresponds to the file relative cluster number
* in this structure (fc_frcn).
*/
struct fatcache {
u_short fc_frcn; /* file relative cluster number */
u_short fc_fsrcn; /* filesystem relative cluster number */
};
/*
* The fat entry cache as it stands helps make extending
* files a "quick" operation by avoiding having to scan
* the fat to discover the last cluster of the file.
* The cache also helps sequential reads by remembering
* the last cluster read from the file. This also prevents
* us from having to rescan the fat to find the next cluster
* to read. This cache is probably pretty worthless if a
* file is opened by multiple processes.
*/
#define FC_SIZE 2 /* number of entries in the cache */
#define FC_LASTMAP 0 /* entry the last call to pcbmap() resolved to */
#define FC_LASTFC 1 /* entry for the last cluster in the file */
#define FCE_EMPTY 0xffff /* doesn't represent an actual cluster # */
/*
* Set a slot in the fat cache.
*/
#define fc_setcache(dep, slot, frcn, fsrcn) \
(dep)->de_fc[slot].fc_frcn = frcn; \
(dep)->de_fc[slot].fc_fsrcn = fsrcn;
/*
* This is the in memory variant of a dos directory
* entry. It is usually contained within a vnode.
*/
struct denode {
struct denode *de_chain[2]; /* hash chain ptrs */
struct vnode *de_vnode; /* addr of vnode we are part of */
struct vnode *de_devvp; /* vnode of blk dev we live on */
u_long de_flag; /* flag bits */
dev_t de_dev; /* device where direntry lives */
u_long de_dirclust; /* cluster of the directory file
* containing this entry */
u_long de_diroffset; /* ordinal of this entry in the
* directory */
long de_refcnt; /* reference count */
struct pcfsmount *de_pmp; /* addr of our mount struct */
struct lockf *de_lockf; /* byte level lock list */
long de_spare0; /* current lock holder */
long de_spare1; /* lock wanter */
struct direntry de_de; /* the actual directory entry */
struct fatcache de_fc[FC_SIZE]; /* fat cache */
};
/*
* Values for the de_flag field of the denode.
*/
#define DELOCKED 0x0001 /* directory entry is locked */
#define DEWANT 0x0002 /* someone wants this de */
#define DERENAME 0x0004 /* de is being renamed */
#define DEUPD 0x0008 /* file has been modified */
#define DESHLOCK 0x0010 /* file has shared lock */
#define DEEXLOCK 0x0020 /* file has exclusive lock */
#define DELWAIT 0x0040 /* someone waiting on file lock */
#define DEMOD 0x0080 /* denode wants to be written back
* to disk */
/*
* Shorthand macros used to reference fields in the direntry
* contained in the denode structure.
*/
#define de_Name de_de.deName
#define de_Extension de_de.deExtension
#define de_Attributes de_de.deAttributes
#define de_Reserved de_de.deReserved
#define de_Time de_de.deTime
#define de_Date de_de.deDate
#define de_StartCluster de_de.deStartCluster
#define de_FileSize de_de.deFileSize
#define de_forw de_chain[0]
#define de_back de_chain[1]
#if defined(KERNEL)
#define VTODE(vp) ((struct denode *)(vp)->v_data)
#define DETOV(de) ((de)->de_vnode)
#define DELOCK(de) delock(de)
#define DEUNLOCK(de) deunlock(de)
#define DEUPDAT(dep, t, waitfor) \
if (dep->de_flag & DEUPD) \
(void) deupdat(dep, t, waitfor);
#define DETIMES(dep, t) \
if (dep->de_flag & DEUPD) { \
(dep)->de_flag |= DEMOD; \
unix2dostime(t, (union dosdate *)&dep->de_Date, \
(union dostime *)&dep->de_Time); \
(dep)->de_flag &= ~DEUPD; \
}
/*
* This overlays the fid sturcture (see mount.h)
*/
struct defid {
u_short defid_len; /* length of structure */
u_short defid_pad; /* force long alignment */
u_long defid_dirclust; /* cluster this dir entry came from */
u_long defid_dirofs; /* index of entry within the cluster */
/* u_long defid_gen; /* generation number */
};
/*
* Prototypes for PCFS vnode operations
*/
int pcfs_lookup __P((struct vnode *vp, struct nameidata *ndp, struct proc *p));
int pcfs_create __P((struct nameidata *ndp, struct vattr *vap, struct proc *p));
int pcfs_mknod __P((struct nameidata *ndp, struct vattr *vap, struct ucred *cred,
struct proc *p));
int pcfs_open __P((struct vnode *vp, int mode, struct ucred *cred,
struct proc *p));
int pcfs_close __P((struct vnode *vp, int fflag, struct ucred *cred,
struct proc *p));
int pcfs_access __P((struct vnode *vp, int mode, struct ucred *cred,
struct proc *p));
int pcfs_getattr __P((struct vnode *vp, struct vattr *vap, struct ucred *cred,
struct proc *p));
int pcfs_setattr __P((struct vnode *vp, struct vattr *vap, struct ucred *cred,
struct proc *p));
int pcfs_read __P((struct vnode *vp, struct uio *uio, int ioflag,
struct ucred *cred));
int pcfs_write __P((struct vnode *vp, struct uio *uio, int ioflag,
struct ucred *cred));
int pcfs_ioctl __P((struct vnode *vp, int command, caddr_t data, int fflag,
struct ucred *cred, struct proc *p));
int pcfs_select __P((struct vnode *vp, int which, int fflags, struct ucred *cred,
struct proc *p));
int pcfs_mmap __P((struct vnode *vp, int fflags, struct ucred *cred,
struct proc *p));
int pcfs_fsync __P((struct vnode *vp, int fflags, struct ucred *cred,
int waitfor, struct proc *p));
int pcfs_seek __P((struct vnode *vp, off_t oldoff, off_t newoff,
struct ucred *cred));
int pcfs_remove __P((struct nameidata *ndp, struct proc *p));
int pcfs_link __P((struct vnode *vp, struct nameidata *ndp, struct proc *p));
int pcfs_rename __P((struct nameidata *fndp, struct nameidata *tdnp,
struct proc *p));
int pcfs_mkdir __P((struct nameidata *ndp, struct vattr *vap, struct proc *p));
int pcfs_rmdir __P((struct nameidata *ndp, struct proc *p));
int pcfs_symlink __P((struct nameidata *ndp, struct vattr *vap, char *target,
struct proc *p));
int pcfs_readdir __P((struct vnode *vp, struct uio *uio, struct ucred *cred,
int *eofflagp));
int pcfs_readlink __P((struct vnode *vp, struct uio *uio, struct ucred *cred));
int pcfs_abortop __P((struct nameidata *ndp));
int pcfs_inactive __P((struct vnode *vp, struct proc *p));
int pcfs_reclaim __P((struct vnode *vp));
int pcfs_lock __P((struct vnode *vp));
int pcfs_unlock __P((struct vnode *vp));
int pcfs_bmap __P((struct vnode *vp, daddr_t bn, struct vnode **vpp,
daddr_t *bnp));
int pcfs_strategy __P((struct buf *bp));
int pcfs_print __P((struct vnode *vp));
int pcfs_islocked __P((struct vnode *vp));
int pcfs_advlock __P((struct vnode *vp, caddr_t id, int op, struct flock *fl,
int flags));
/*
* Internal service routine prototypes.
*/
int deget __P((struct pcfsmount *pmp, u_long dirclust, u_long diroffset,
struct direntry *direntptr, struct denode **depp));
#endif /* defined(KERNEL) */

97
sys/pcfs/direntry.h Normal file
View File

@ -0,0 +1,97 @@
/*
* Written by Paul Popelka (paulp@uts.amdahl.com)
*
* You can do anything you want with this software,
* just don't say you wrote it,
* and don't remove this notice.
*
* This software is provided "as is".
*
* The author supplies this software to be publicly
* redistributed on the understanding that the author
* is not responsible for the correct functioning of
* this software in any circumstances and is not liable
* for any damages caused by this software.
*
* October 1992
*
* $Header: /cvsroot/src/sys/pcfs/Attic/direntry.h,v 1.1 1993/04/09 19:37:57 cgd Exp $
*
*/
/*
* Structure of a dos directory entry.
*/
struct direntry {
u_char deName[8]; /* filename, blank filled */
#define SLOT_EMPTY 0x00 /* slot has never been used */
#define SLOT_E5 0x05 /* the real value is 0xe5 */
#define SLOT_DELETED 0xe5 /* file in this slot deleted */
u_char deExtension[3]; /* extension, blank filled */
u_char deAttributes; /* file attributes */
#define ATTR_NORMAL 0x00 /* normal file */
#define ATTR_READONLY 0x01 /* file is readonly */
#define ATTR_HIDDEN 0x02 /* file is hidden */
#define ATTR_SYSTEM 0x04 /* file is a system file */
#define ATTR_VOLUME 0x08 /* entry is a volume label */
#define ATTR_DIRECTORY 0x10 /* entry is a directory name */
#define ATTR_ARCHIVE 0x20 /* file is new or modified */
char deReserved[10]; /* reserved */
u_short deTime; /* create/last update time */
u_short deDate; /* create/last update date */
u_short deStartCluster; /* starting cluster of file */
u_long deFileSize; /* size of file in bytes */
};
/*
* This is the format of the contents of the deTime
* field in the direntry structure.
*/
struct DOStime {
u_short
dt_2seconds:5, /* seconds divided by 2 */
dt_minutes:6, /* minutes */
dt_hours:5; /* hours */
};
/*
* This is the format of the contents of the deDate
* field in the direntry structure.
*/
struct DOSdate {
u_short
dd_day:5, /* day of month */
dd_month:4, /* month */
dd_year:7; /* years since 1980 */
};
union dostime {
struct DOStime dts;
u_short dti;
};
union dosdate {
struct DOSdate dds;
u_short ddi;
};
/*
* The following defines are used to rename fields in
* the ufs_specific structure in the nameidata structure
* in namei.h
*/
#define ni_pcfs ni_ufs
#define pcfs_count ufs_count
#define pcfs_offset ufs_offset
#define pcfs_cluster ufs_ino
#if defined(KERNEL)
void unix2dostime __P((struct timeval *tvp,
union dosdate *ddp,
union dostime *dtp));
void dos2unixtime __P((union dosdate *ddp,
union dostime *dtp,
struct timeval *tvp));
int dos2unixfn __P((u_char dn[11], u_char *un));
void unix2dosfn __P((u_char *un, u_char dn[11], int unlen));
#endif /* defined(KERNEL) */

68
sys/pcfs/fat.h Normal file
View File

@ -0,0 +1,68 @@
/*
* Written by Paul Popelka (paulp@uts.amdahl.com)
*
* You can do anything you want with this software,
* just don't say you wrote it,
* and don't remove this notice.
*
* This software is provided "as is".
*
* The author supplies this software to be publicly
* redistributed on the understanding that the author
* is not responsible for the correct functioning of
* this software in any circumstances and is not liable
* for any damages caused by this software.
*
* October 1992
*
* $Header: /cvsroot/src/sys/pcfs/Attic/fat.h,v 1.1 1993/04/09 19:38:00 cgd Exp $
*
*/
/*
* Some useful cluster numbers.
*/
#define PCFSROOT 0 /* cluster 0 means the root dir */
#define CLUST_FREE 0 /* cluster 0 also means a free cluster */
#define PCFSFREE CLUST_FREE
#define CLUST_FIRST 2 /* first legal cluster number */
#define CLUST_RSRVS 0xfff0 /* start of reserved cluster range */
#define CLUST_RSRVE 0xfff6 /* end of reserved cluster range */
#define CLUST_BAD 0xfff7 /* a cluster with a defect */
#define CLUST_EOFS 0xfff8 /* start of eof cluster range */
#define CLUST_EOFE 0xffff /* end of eof cluster range */
#define FAT12_MASK 0x0fff /* mask for 12 bit cluster numbers */
#define FAT16_MASK 0xffff /* mask for 16 bit cluster numbers */
/*
* Return true if filesystem uses 12 bit fats.
* Microsoft Programmer's Reference says if the
* maximum cluster number in a filesystem is greater
* than 4086 then we've got a 16 bit fat filesystem.
*/
#define FAT12(pmp) (pmp->pm_maxcluster <= 4086)
#define FAT16(pmp) (pmp->pm_maxcluster > 4086)
#define PCFSEOF(cn) (((cn) & 0xfff8) == 0xfff8)
/*
* These are the values for the function argument to
* the function fatentry().
*/
#define FAT_GET 0x0001 /* get a fat entry */
#define FAT_SET 0x0002 /* set a fat entry */
#define FAT_GET_AND_SET (FAT_GET | FAT_SET)
#if defined(KERNEL)
int pcbmap __P((struct denode *dep,
u_long findcn,
daddr_t *bnp,
u_long *cnp));
int clusterfree __P((struct pcfsmount *pmp, u_long cn, u_long *oldcnp));
int clusteralloc __P((struct pcfsmount *pmp, u_long *retcluster,
u_long fillwith));
int fatentry __P((int function, struct pcfsmount *pmp,
u_long cluster, u_long *oldcontents, u_long newcontents));
int freeclusterchain __P((struct pcfsmount *pmp, u_long startchain));
#endif /* defined(KERNEL) */

368
sys/pcfs/pcfs_conv.c Normal file
View File

@ -0,0 +1,368 @@
/*
* Written by Paul Popelka (paulp@uts.amdahl.com)
*
* You can do anything you want with this software,
* just don't say you wrote it,
* and don't remove this notice.
*
* This software is provided "as is".
*
* The author supplies this software to be publicly
* redistributed on the understanding that the author
* is not responsible for the correct functioning of
* this software in any circumstances and is not liable
* for any damages caused by this software.
*
* October 1992
*
* $Header: /cvsroot/src/sys/pcfs/Attic/pcfs_conv.c,v 1.1 1993/04/09 19:38:02 cgd Exp $
*
*/
/*
* System include files.
*/
#include "param.h"
#include "time.h"
#include "kernel.h" /* defines tz */
/*
* PCFS include files.
*/
#include "direntry.h"
/*
* Days in each month in a regular year.
*/
u_short regyear[] = {
31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31
};
/*
* Days in each month in a leap year.
*/
u_short leapyear[] = {
31, 29, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31
};
/*
* Variables used to remember parts of the last time
* conversion. Maybe we can avoid a full conversion.
*/
u_long lasttime;
u_long lastday;
union dosdate lastddate;
union dostime lastdtime;
/*
* Convert the unix version of time to dos's idea of time
* to be used in file timestamps.
* The passed in unix time is assumed to be in GMT.
*/
void
unix2dostime(tvp, ddp, dtp)
struct timeval *tvp;
union dosdate *ddp;
union dostime *dtp;
{
u_long days;
u_long inc;
u_long year;
u_long month;
u_short *months;
/*
* If the time from the last conversion is the same
* as now, then skip the computations and use the
* saved result.
*/
if (lasttime != tvp->tv_sec) {
lasttime = tvp->tv_sec - (tz.tz_minuteswest * 60)
/* +- daylight savings time correction */;
lastdtime.dts.dt_2seconds = (lasttime % 60) >> 1;
lastdtime.dts.dt_minutes = (lasttime / 60) % 60;
lastdtime.dts.dt_hours = (lasttime / (60 * 60)) % 24;
/*
* If the number of days since 1970 is the same as the
* last time we did the computation then skip all this
* leap year and month stuff.
*/
days = lasttime / (24 * 60 * 60);
if (days != lastday) {
lastday = days;
for (year = 1970; ; year++) {
inc = year & 0x03 ? 365 : 366;
if (days < inc) break;
days -= inc;
}
months = year & 0x03 ? regyear : leapyear;
for (month = 0; month < 12; month++) {
if (days < months[month]) break;
days -= months[month];
}
lastddate.dds.dd_day = days + 1;
lastddate.dds.dd_month = month+1;
/*
* Remember dos's idea of time is relative to 1980.
* unix's is relative to 1970. If somehow we get a
* time before 1980 then don't give totally crazy
* results.
*/
lastddate.dds.dd_year = year < 1980 ? 0 : year - 1980;
}
}
dtp->dti = lastdtime.dti;
ddp->ddi = lastddate.ddi;
}
/*
* The number of seconds between Jan 1, 1970 and
* Jan 1, 1980.
* In that interval there were 8 regular years and
* 2 leap years.
*/
#define SECONDSTO1980 (((8 * 365) + (2 * 366)) * (24 * 60 * 60))
union dosdate lastdosdate;
u_long lastseconds;
/*
* Convert from dos' idea of time to unix'.
* This will probably only be called from the
* stat(), and fstat() system calls
* and so probably need not be too efficient.
*/
void
dos2unixtime(ddp, dtp, tvp)
union dosdate *ddp;
union dostime *dtp;
struct timeval *tvp;
{
u_long seconds;
u_long month;
u_long yr;
u_long days;
u_short *months;
seconds = (dtp->dts.dt_2seconds << 1) +
(dtp->dts.dt_minutes * 60) +
(dtp->dts.dt_hours * 60 * 60);
/*
* If the year, month, and day from the last conversion
* are the same then use the saved value.
*/
if (lastdosdate.ddi != ddp->ddi) {
lastdosdate.ddi = ddp->ddi;
days = 0;
for (yr = 0; yr < ddp->dds.dd_year; yr++) {
days += yr & 0x03 ? 365 : 366;
}
months = yr & 0x03 ? regyear : leapyear;
/*
* Prevent going from 0 to 0xffffffff in the following
* loop.
*/
if (ddp->dds.dd_month == 0) {
printf("dos2unixtime(): month value out of range (%d)\n",
ddp->dds.dd_month);
ddp->dds.dd_month = 1;
}
for (month = 0; month < ddp->dds.dd_month-1; month++) {
days += months[month];
}
days += ddp->dds.dd_day - 1;
lastseconds = (days * 24 * 60 * 60) + SECONDSTO1980;
}
tvp->tv_sec = seconds + lastseconds + (tz.tz_minuteswest * 60)
/* -+ daylight savings time correction */;
tvp->tv_usec = 0;
}
/*
* Cheezy macros to do case detection and conversion
* for the ascii character set. DOESN'T work for ebcdic.
*/
#define isupper(c) (c >= 'A' && c <= 'Z')
#define islower(c) (c >= 'a' && c <= 'z')
#define toupper(c) (c & ~' ')
#define tolower(c) (c | ' ')
/*
* DOS filenames are made of 2 parts, the name part and
* the extension part. The name part is 8 characters
* long and the extension part is 3 characters long. They
* may contain trailing blanks if the name or extension
* are not long enough to fill their respective fields.
*/
/*
* Convert a DOS filename to a unix filename.
* And, return the number of characters in the
* resulting unix filename excluding the terminating
* null.
*/
int
dos2unixfn(dn, un)
u_char dn[11];
u_char *un;
{
int i;
int ni;
int ei;
int thislong = 0;
u_char c;
u_char *origun = un;
/*
* Find the last character in the name portion
* of the dos filename.
*/
for (ni = 7; ni >= 0; ni--)
if (dn[ni] != ' ') break;
/*
* Find the last character in the extension
* portion of the filename.
*/
for (ei = 10; ei >= 8; ei--)
if (dn[ei] != ' ') break;
/*
* Copy the name portion into the unix filename
* string.
* NOTE: DOS filenames are usually kept in upper
* case. To make it more unixy we convert all
* DOS filenames to lower case. Some may like
* this, some may not.
*/
for (i = 0; i <= ni; i++) {
c = dn[i];
*un++ = isupper(c) ? tolower(c) : c;
thislong++;
}
/*
* Now, if there is an extension then put in a period
* and copy in the extension.
*/
if (ei >= 8) {
*un++ = '.';
thislong++;
for (i = 8; i <= ei; i++) {
c = dn[i];
*un++ = isupper(c) ? tolower(c) : c;
thislong++;
}
}
*un++ = 0;
/*
* If first char of the filename is SLOT_E5 (0x05), then
* the real first char of the filename should be 0xe5.
* But, they couldn't just have a 0xe5 mean 0xe5 because
* that is used to mean a freed directory slot.
* Another dos quirk.
*/
if (*origun == SLOT_E5)
*origun = 0xe5;
return thislong;
}
/*
* Convert a unix filename to a DOS filename.
* This function does not ensure that valid
* characters for a dos filename are supplied.
*/
void
unix2dosfn(un, dn, unlen)
u_char *un;
u_char dn[11];
int unlen;
{
int i;
u_char c;
/*
* Fill the dos filename string with blanks.
* These are DOS's pad characters.
*/
for (i = 0; i <= 10; i++)
dn[i] = ' ';
/*
* The filenames "." and ".." are handled specially,
* since they don't follow dos filename rules.
*/
if (un[0] == '.' && un[1] == '\0') {
dn[0] = '.';
return;
}
if (un[0] == '.' && un[1] == '.' && un[2] == '\0') {
dn[0] = '.';
dn[1] = '.';
return;
}
/*
* Copy the unix filename into the dos filename string
* upto the end of string, a '.', or 8 characters.
* Whichever happens first stops us.
* This forms the name portion of the dos filename.
* Fold to upper case.
*/
for (i = 0; i <= 7 && unlen && (c = *un) && c != '.'; i++) {
dn[i] = islower(c) ? toupper(c) : c;
un++;
unlen--;
}
/*
* If the first char of the filename is 0xe5, then translate
* it to 0x05. This is because 0xe5 is the marker for a
* deleted directory slot. I guess this means you can't
* have filenames that start with 0x05. I suppose we should
* check for this and doing something about it.
*/
if (dn[0] == SLOT_DELETED)
dn[0] = SLOT_E5;
/*
* Strip any further characters up to a '.' or the
* end of the string.
*/
while (unlen && (c = *un) && c != '.') {
un++;
unlen--;
}
/*
* If we stopped on a '.', then get past it.
*/
if (c == '.') un++;
/*
* Copy in the extension part of the name, if any.
* Force to upper case.
* Note that the extension is allowed to contain '.'s.
* Filenames in this form are probably inaccessable
* under dos.
*/
for (i = 8; i <= 10 && unlen && (c = *un); i++) {
dn[i] = islower(c) ? toupper(c) : c;
un++;
unlen--;
}
}
/*
* Get rid of these macros before someone discovers
* we are using such hideous things.
*/
#undef isupper
#undef islower
#undef toupper
#undef tolower

622
sys/pcfs/pcfs_denode.c Normal file
View File

@ -0,0 +1,622 @@
/*
* Written by Paul Popelka (paulp@uts.amdahl.com)
*
* You can do anything you want with this software,
* just don't say you wrote it,
* and don't reoove this notice.
*
* This software is provided "as is".
*
* The authop supplies this software to be publicly
* redistributed on the understanding that the author
* is not responsible for the correct functioning of
* this software in any circumstances and is not liable
* for any damages caused by this software.
*
* October 1992
*
* $Header: /cvsroot/src/sys/pcfs/Attic/pcfs_denode.c,v 1.1 1993/04/09 19:38:04 cgd Exp $
*
*/
#include "param.h"
#include "systm.h"
#include "mount.h"
#include "proc.h"
#include "buf.h"
#include "vnode.h"
#include "kernel.h" /* defines "time" */
#include "bpb.h"
#include "pcfsmount.h"
#include "direntry.h"
#include "denode.h"
#include "fat.h"
#define DEHSZ 512
#if ((DEHSZ & (DEHSZ-1)) == 0)
#define DEHASH(dev, deno) (((dev)+(deno)+((deno)>>16))&(DEHSZ-1))
#else
#define DEHASH(dev, deno) (((dev)+(deno)+((deno)>>16))%DEHSZ)
#endif /* ((DEHSZ & (DEHSZ-1)) == 0) */
union dehead {
union dehead *deh_head[2];
struct denode *deh_chain[2];
} dehead[DEHSZ];
pcfs_init()
{
int i;
union dehead *deh;
if (VN_MAXPRIVATE < sizeof(struct denode))
panic("pcfs_init: vnode too small");
for (i = DEHSZ, deh = dehead; --i >= 0; deh++) {
deh->deh_head[0] = deh;
deh->deh_head[1] = deh;
}
}
/*
* If deget() succeeds it returns with the gotten denode
* locked().
* pmp - address of pcfsmount structure of the filesystem
* containing the denode of interest. The pm_dev field
* and the address of the pcfsmount structure are used.
* dirclust - which cluster bp contains, if dirclust is 0
* (root directory) diroffset is relative to the beginning
* of the root directory, otherwise it is cluster relative.
* diroffset - offset past begin of cluster of denode we
* want
* direntptr - address of the direntry structure of interest.
* direntptr is NULL, the block is read if necessary.
* depp - returns the address of the gotten denode.
*/
int
deget (pmp, dirclust, diroffset, direntptr, depp)
struct pcfsmount *pmp; /* so we know the maj/min number */
u_long dirclust; /* cluster this dir entry came from */
u_long diroffset; /* index of entry within the cluster */
struct direntry *direntptr;
struct denode **depp; /* returns the addr of the gotten denode*/
{
int error;
dev_t dev = pmp->pm_dev;
union dehead *deh;
struct mount *mntp = pmp->pm_mountp;
extern struct vnodeops pcfs_vnodeops;
struct denode *ldep;
struct vnode *nvp;
struct buf *bp;
#if defined(PCFSDEBUG)
printf("deget(pmp %08x, dirclust %d, diroffset %x, direntptr %x, depp %08x)\n",
pmp, dirclust, diroffset, direntptr, depp);
#endif /* defined(PCFSDEBUG) */
/* If dir entry is given and refers to a directory, convert to
* canonical form
*/
if (direntptr && (direntptr->deAttributes & ATTR_DIRECTORY)) {
dirclust = direntptr->deStartCluster;
if (dirclust == PCFSROOT)
diroffset = PCFSROOT_OFS;
else
diroffset = 0;
}
/*
* See if the denode is in the denode cache. Use the location of
* the directory entry to compute the hash value.
* For subdir use address of "." entry.
* for root dir use cluster PCFSROOT, offset PCFSROOT_OFS
*
* NOTE: The check for de_refcnt > 0 below insures the denode
* being examined does not represent an unlinked but
* still open file. These files are not to be accessible
* even when the directory entry that represented the
* file happens to be reused while the deleted file is still
* open.
*/
deh = &dehead[DEHASH(dev, dirclust + diroffset)];
loop:
for (ldep = deh->deh_chain[0]; ldep != (struct denode *)deh;
ldep = ldep->de_forw) {
if (dev != ldep->de_dev || ldep->de_refcnt == 0)
continue;
if (dirclust != ldep->de_dirclust
|| diroffset != ldep->de_diroffset)
continue;
if (ldep->de_flag & DELOCKED) {
/* should we brelse() the passed buf hdr to
* avoid some potential deadlock? */
ldep->de_flag |= DEWANT;
sleep((caddr_t)ldep, PINOD);
goto loop;
}
if (vget(DETOV(ldep)))
goto loop;
*depp = ldep;
return 0;
}
/*
* Directory entry was not in cache, have to create
* a vnode and copy it from the passed disk buffer.
*/
/* getnewvnode() does a VREF() on the vnode */
if (error = getnewvnode(VT_PCFS, mntp, &pcfs_vnodeops, &nvp)) {
*depp = 0;
return error;
}
ldep = VTODE(nvp);
ldep->de_vnode = nvp;
ldep->de_flag = 0;
ldep->de_devvp = 0;
ldep->de_lockf = 0;
ldep->de_dev = dev;
fc_purge(ldep, 0); /* init the fat cache for this denode */
/*
* Insert the denode into the hash queue and lock the
* denode so it can't be accessed until we've read it
* in and have done what we need to it.
*/
insque(ldep, deh);
DELOCK(ldep);
/*
* Copy the directory entry into the denode area of the
* vnode.
*/
if (dirclust == PCFSROOT && diroffset == PCFSROOT_OFS) {
/* Directory entry for the root directory.
* There isn't one, so we manufacture one.
* We should probably rummage through the root directory and
* find a label entry (if it exists), and then use the time
* and date from that entry as the time and date for the
* root denode.
*/
ldep->de_Attributes = ATTR_DIRECTORY;
ldep->de_StartCluster = PCFSROOT;
ldep->de_FileSize = pmp->pm_rootdirsize;
/* fill in time and date so that dos2unixtime() doesn't
* spit up when called from pcfs_getattr() with root denode */
ldep->de_Time = 0x0000; /* 00:00:00 */
ldep->de_Date = (0 << 9) | (1 << 5) | (1 << 0);
/* Jan 1, 1980 */
/* leave the other fields as garbage */
}
else {
bp = NULL;
if (!direntptr) {
error = readep(pmp, dirclust, diroffset, &bp,
&direntptr);
if (error)
return error;
}
ldep->de_de = *direntptr;
if (bp)
brelse (bp);
}
/*
* Fill in a few fields of the vnode and finish filling
* in the denode. Then return the address of the found
* denode.
*/
ldep->de_pmp = pmp;
ldep->de_devvp = pmp->pm_devvp;
ldep->de_refcnt = 1;
ldep->de_dirclust = dirclust;
ldep->de_diroffset = diroffset;
if (ldep->de_Attributes & ATTR_DIRECTORY) {
/*
* Since DOS directory entries that describe directories
* have 0 in the filesize field, we take this opportunity
* to find out the length of the directory and plug it
* into the denode structure.
*/
u_long size;
nvp->v_type = VDIR;
if (ldep->de_StartCluster == PCFSROOT)
nvp->v_flag |= VROOT;
else {
error = pcbmap(ldep, 0xffff, 0, &size);
if (error == E2BIG) {
ldep->de_FileSize = size << pmp->pm_cnshift;
error = 0;
}
else
printf("deget(): pcbmap returned %d\n", error);
}
}
else
nvp->v_type = VREG;
VREF(ldep->de_devvp);
*depp = ldep;
return 0;
}
void
deput(dep)
struct denode *dep;
{
if ((dep->de_flag & DELOCKED) == 0)
panic("deput: denode not locked");
DEUNLOCK(dep);
vrele(DETOV(dep));
}
int
deupdat(dep, tp, waitfor)
struct denode *dep;
struct timeval *tp;
int waitfor;
{
int error;
daddr_t bn;
int diro;
struct buf *bp;
struct direntry *dirp;
struct pcfsmount *pmp = dep->de_pmp;
struct vnode *vp = DETOV(dep);
#if defined(PCFSDEBUG)
printf("deupdat(): dep %08x\n", dep);
#endif /* defined(PCFSDEBUG) */
/*
* If the update bit is off, or this denode is from
* a readonly filesystem, or this denode is for a
* directory, or the denode represents an open but
* unlinked file then don't do anything. DOS directory
* entries that describe a directory do not ever
* get updated. This is the way dos treats them.
*/
if ((dep->de_flag & DEUPD) == 0 ||
vp->v_mount->mnt_flag & MNT_RDONLY ||
dep->de_Attributes & ATTR_DIRECTORY ||
dep->de_refcnt <= 0)
return 0;
/*
* Read in the cluster containing the directory entry
* we want to update.
*/
if (error = readde(dep, &bp, &dirp))
return error;
/*
* Put the passed in time into the directory entry.
*/
unix2dostime(&time, (union dosdate *)&dep->de_Date,
(union dostime *)&dep->de_Time);
dep->de_flag &= ~DEUPD;
/*
* Copy the directory entry out of the denode into
* the cluster it came from.
*/
*dirp = dep->de_de; /* structure copy */
/*
* Write the cluster back to disk. If they asked
* for us to wait for the write to complete, then
* use bwrite() otherwise use bdwrite().
*/
error = 0; /* note that error is 0 from above, but ... */
if (waitfor)
error = bwrite(bp);
else
bdwrite(bp);
return error;
}
/*
* Truncate the file described by dep to the length
* specified by length.
*/
int
detrunc(dep, length, flags)
struct denode *dep;
u_long length;
int flags;
{
int error;
int allerror;
u_long eofentry;
u_long chaintofree;
daddr_t bn;
int boff;
int isadir = dep->de_Attributes & ATTR_DIRECTORY;
struct buf *bp;
struct pcfsmount *pmp = dep->de_pmp;
#if defined(PCFSDEBUG)
printf("detrunc(): file %s, length %d, flags %d\n", dep->de_Name, length, flags);
#endif /* defined(PCFSDEBUG) */
/*
* Disallow attempts to truncate the root directory
* since it is of fixed size. That's just the way
* dos filesystems are. We use the VROOT bit in the
* vnode because checking for the directory bit and
* a startcluster of 0 in the denode is not adequate
* to recognize the root directory at this point in
* a file or directory's life.
*/
if (DETOV(dep)->v_flag & VROOT) {
printf("detrunc(): can't truncate root directory, clust %d, offset %d\n",
dep->de_dirclust, dep->de_diroffset);
return EINVAL;
}
vnode_pager_setsize(DETOV(dep), length);
if (dep->de_FileSize <= length) {
dep->de_flag |= DEUPD;
error = deupdat(dep, &time, 1);
#if defined(PCFSDEBUG)
printf("detrunc(): file is shorter return point, errno %d\n", error);
#endif /* defined(PCFSDEBUG) */
return error;
}
/*
* If the desired length is 0 then remember the starting
* cluster of the file and set the StartCluster field in
* the directory entry to 0. If the desired length is
* not zero, then get the number of the last cluster in
* the shortened file. Then get the number of the first
* cluster in the part of the file that is to be freed.
* Then set the next cluster pointer in the last cluster
* of the file to CLUST_EOFE.
*/
if (length == 0) {
chaintofree = dep->de_StartCluster;
dep->de_StartCluster = 0;
eofentry = ~0;
} else {
error = pcbmap(dep, (length-1) >> pmp->pm_cnshift,
0, &eofentry);
if (error) {
#if defined(PCFSDEBUG)
printf("detrunc(): pcbmap fails %d\n", error);
#endif /* defined(PCFSDEBUG) */
return error;
}
}
fc_purge(dep, (length + pmp->pm_crbomask) >> pmp->pm_cnshift);
/*
* If the new length is not a multiple of the cluster size
* then we must zero the tail end of the new last cluster in case
* it becomes part of the file again because of a seek.
*/
if ((boff = length & pmp->pm_crbomask) != 0) {
/* should read from file vnode or
* filesystem vnode depending on if file or dir */
if (isadir) {
bn = cntobn(pmp, eofentry);
error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,
NOCRED, &bp);
} else {
bn = (length-1) >> pmp->pm_cnshift;
error = bread(DETOV(dep), bn, pmp->pm_bpcluster,
NOCRED, &bp);
}
if (error) {
#if defined(PCFSDEBUG)
printf("detrunc(): bread fails %d\n", error);
#endif /* defined(PCFSDEBUG) */
return error;
}
vnode_pager_uncache(DETOV(dep)); /* what's this for? */
/* is this the right
* place for it? */
bzero(bp->b_un.b_addr + boff, pmp->pm_bpcluster - boff);
if (flags & IO_SYNC)
bwrite(bp);
else
bdwrite(bp);
}
/*
* Write out the updated directory entry. Even
* if the update fails we free the trailing clusters.
*/
dep->de_FileSize = length;
dep->de_flag |= DEUPD;
vinvalbuf(DETOV(dep), length > 0);
allerror = deupdat(dep, &time, MNT_WAIT);
#if defined(PCFSDEBUG)
printf("detrunc(): allerror %d, eofentry %d\n",
allerror, eofentry);
#endif /* defined(PCFSDEBUG) */
/*
* If we need to break the cluster chain for the file
* then do it now.
*/
if (eofentry != ~0) {
error = fatentry(FAT_GET_AND_SET, pmp, eofentry,
&chaintofree, CLUST_EOFE);
if (error) {
#if defined(PCFSDEBUG)
printf("detrunc(): fatentry errors %d\n", error);
#endif /* defined(PCFSDEBUG) */
return error;
}
fc_setcache(dep, FC_LASTFC, (length - 1) >> pmp->pm_cnshift,
eofentry);
}
/*
* Now free the clusters removed from the file because
* of the truncation.
*/
if (chaintofree != 0 && !PCFSEOF(chaintofree))
freeclusterchain(pmp, chaintofree);
return allerror;
}
/*
* Move a denode to its correct hash queue after
* the file it represents has been moved to a new
* directory.
*/
reinsert(dep)
struct denode *dep;
{
struct pcfsmount *pmp = dep->de_pmp;
union dehead *deh;
/*
* Fix up the denode cache. If the denode is
* for a directory, there is nothing to do since the
* hash is based on the starting cluster of the directory
* file and that hasn't changed. If for a file the hash
* is based on the location
* of the directory entry, so we must remove it from the
* cache and re-enter it with the hash based on the new
* location of the directory entry.
*/
if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
remque(dep);
deh = &dehead[DEHASH(pmp->pm_dev,
dep->de_dirclust + dep->de_diroffset)];
insque(dep, deh);
}
}
int pcfs_prtactive; /* print reclaims of active vnodes */
int
pcfs_reclaim(vp)
struct vnode *vp;
{
struct denode *dep = VTODE(vp);
int i;
#if defined(PCFSDEBUG)
printf("pcfs_reclaim(): dep %08x, file %s, refcnt %d\n",
dep, dep->de_Name, dep->de_refcnt);
#endif /* defined(PCFSDEBUG) */
if (pcfs_prtactive && vp->v_usecount != 0)
vprint("pcfs_reclaim(): pushing active", vp);
/*
* Remove the denode from the denode hash chain we
* are in.
*/
remque(dep);
dep->de_forw = dep;
dep->de_back = dep;
cache_purge(vp);
/*
* Indicate that one less file on the filesystem is open.
*/
if (dep->de_devvp) {
vrele(dep->de_devvp);
dep->de_devvp = 0;
}
dep->de_flag = 0;
return 0;
}
int
pcfs_inactive(vp, p)
struct vnode *vp;
struct proc *p;
{
struct denode *dep = VTODE(vp);
int error = 0;
#if defined(PCFSDEBUG)
printf("pcfs_inactive(): dep %08x, de_Name[0] %x\n", dep, dep->de_Name[0]);
#endif /* defined(PCFSDEBUG) */
if (pcfs_prtactive && vp->v_usecount != 0)
vprint("pcfs_inactive(): pushing active", vp);
/*
* Get rid of denodes related to stale file handles.
* Hmmm, what does this really do?
*/
if (dep->de_Name[0] == SLOT_DELETED) {
if ((vp->v_flag & VXLOCK) == 0)
vgone(vp);
return 0;
}
/*
* If the file has been deleted and it is on a read/write
* filesystem, then truncate the file, and mark the directory
* slot as empty. (This may not be necessary for the dos
* filesystem.
*/
#if defined(PCFSDEBUG)
printf("pcfs_inactive(): dep %08x, refcnt %d, mntflag %x, MNT_RDONLY %x\n",
dep, dep->de_refcnt, vp->v_mount->mnt_flag, MNT_RDONLY);
#endif /* defined(PCFSDEBUG) */
DELOCK(dep);
if (dep->de_refcnt <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
error = detrunc(dep, (u_long)0, 0);
dep->de_flag |= DEUPD;
dep->de_Name[0] = SLOT_DELETED;
}
DEUPDAT(dep, &time, 0);
DEUNLOCK(dep);
dep->de_flag = 0;
/*
* If we are done with the denode, then reclaim
* it so that it can be reused now.
*/
#if defined(PCFSDEBUG)
printf("pcfs_inactive(): v_usecount %d, de_Name[0] %x\n", vp->v_usecount,
dep->de_Name[0]);
#endif /* defined(PCFSDEBUG) */
if (vp->v_usecount == 0 && dep->de_Name[0] == SLOT_DELETED)
vgone(vp);
return error;
}
int
delock(dep)
struct denode *dep;
{
while (dep->de_flag & DELOCKED) {
dep->de_flag |= DEWANT;
if (dep->de_spare0 == curproc->p_pid)
panic("delock: locking against myself");
dep->de_spare1 = curproc->p_pid;
(void) sleep((caddr_t)dep, PINOD);
}
dep->de_spare1 = 0;
dep->de_spare0 = curproc->p_pid;
dep->de_flag |= DELOCKED;
return 0;
}
int
deunlock(dep)
struct denode *dep;
{
if ((dep->de_flag & DELOCKED) == 0)
vprint("deunlock: found unlocked denode", DETOV(dep));
dep->de_spare0 = 0;
dep->de_flag &= ~DELOCKED;
if (dep->de_flag & DEWANT) {
dep->de_flag &= ~DEWANT;
wakeup((caddr_t)dep);
}
return 0;
}

718
sys/pcfs/pcfs_fat.c Normal file
View File

@ -0,0 +1,718 @@
/*
* Written by Paul Popelka (paulp@uts.amdahl.com)
*
* You can do anything you want with this software,
* just don't say you wrote it,
* and don't remove this notice.
*
* This software is provided "as is".
*
* The author supplies this software to be publicly
* redistributed on the understanding that the author
* is not responsible for the correct functioning of
* this software in any circumstances and is not liable
* for any damages caused by this software.
*
* October 1992
*
* $Header: /cvsroot/src/sys/pcfs/Attic/pcfs_fat.c,v 1.1 1993/04/09 19:38:06 cgd Exp $
*
*/
/*
* kernel include files.
*/
#include "param.h"
#include "systm.h"
#include "buf.h"
#include "file.h"
#include "namei.h"
#include "mount.h" /* to define statfs structure */
#include "vnode.h" /* to define vattr structure */
#include "errno.h"
/*
* pcfs include files.
*/
#include "bpb.h"
#include "pcfsmount.h"
#include "direntry.h"
#include "denode.h"
#include "fat.h"
/*
* Fat cache stats.
*/
int fc_fileextends; /* # of file extends */
int fc_lfcempty; /* # of time last file cluster cache entry
* was empty */
int fc_bmapcalls; /* # of times pcbmap was called */
#define LMMAX 20
int fc_lmdistance[LMMAX]; /* counters for how far off the last cluster
* mapped entry was. */
int fc_largedistance; /* off by more than LMMAX */
/* Byte offset in FAT on filesystem pmp, cluster cn */
#define FATOFS(pmp, cn) (FAT12(pmp) ? (cn) * 3 / 2 : (cn) * 2)
static void fatblock (pmp, ofs, bnp, sizep, bop)
struct pcfsmount *pmp;
u_long ofs;
u_long *bnp;
u_long *sizep;
u_long *bop;
{
u_long bn, size;
bn = ofs / pmp->pm_fatblocksize * pmp->pm_fatblocksec;
size = min (pmp->pm_fatblocksec, pmp->pm_FATsecs - bn)
* pmp->pm_BytesPerSec;
bn += pmp->pm_fatblk;
if (bnp)
*bnp = bn;
if (sizep)
*sizep = size;
if (bop)
*bop = ofs % pmp->pm_fatblocksize;
}
/*
* Map the logical cluster number of a file into
* a physical disk sector that is filesystem relative.
* dep - address of denode representing the file of interest
* findcn - file relative cluster whose filesystem relative
* cluster number and/or block number are/is to be found
* bnp - address of where to place the file system relative
* block number. If this pointer is null then don't return
* this quantity.
* cnp - address of where to place the file system relative
* cluster number. If this pointer is null then don't return
* this quantity.
* NOTE:
* Either bnp or cnp must be non-null.
* This function has one side effect. If the requested
* file relative cluster is beyond the end of file, then
* the actual number of clusters in the file is returned
* in *cnp. This is useful for determining how long a
* directory is. If cnp is null, nothing is returned.
*/
int
pcbmap(dep, findcn, bnp, cnp)
struct denode *dep;
u_long findcn; /* file relative cluster to get */
daddr_t *bnp; /* returned filesys relative blk number */
u_long *cnp; /* returned cluster number */
{
int error;
u_long i;
u_long cn;
u_long prevcn;
u_long byteoffset;
u_long bn;
u_long bo;
struct buf *bp = NULL;
u_long bp_bn = -1;
struct pcfsmount *pmp = dep->de_pmp;
u_long bsize;
int fat12 = FAT12(pmp); /* 12 bit fat */
fc_bmapcalls++;
/*
* If they don't give us someplace to return a value
* then don't bother doing anything.
*/
if (bnp == NULL && cnp == NULL)
return 0;
cn = dep->de_StartCluster;
/*
* The "file" that makes up the root directory is contiguous,
* permanently allocated, of fixed size, and is not made up
* of clusters. If the cluster number is beyond the end of
* the root directory, then return the number of clusters in
* the file.
*/
if (cn == PCFSROOT) {
if (dep->de_Attributes & ATTR_DIRECTORY) {
if (findcn * pmp->pm_SectPerClust > pmp->pm_rootdirsize) {
if (cnp)
*cnp = pmp->pm_rootdirsize / pmp->pm_SectPerClust;
return E2BIG;
}
if (bnp)
*bnp = pmp->pm_rootdirblk + (findcn * pmp->pm_SectPerClust);
if (cnp)
*cnp = PCFSROOT;
return 0;
}
else { /* just an empty file */
if (cnp)
*cnp = 0;
return E2BIG;
}
}
/*
* Rummage around in the fat cache, maybe we can avoid
* tromping thru every fat entry for the file.
* And, keep track of how far off the cache was from
* where we wanted to be.
*/
i = 0;
fc_lookup(dep, findcn, &i, &cn);
if ((bn = findcn - i) >= LMMAX)
fc_largedistance++;
else
fc_lmdistance[bn]++;
/*
* Handle all other files or directories the normal way.
*/
for (; i < findcn; i++) {
if (PCFSEOF(cn))
goto hiteof;
byteoffset = FATOFS(pmp, cn);
fatblock(pmp, byteoffset, &bn, &bsize, &bo);
if (bn != bp_bn) {
if (bp)
brelse(bp);
error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
if (error)
return error;
bp_bn = bn;
}
prevcn = cn;
cn = getushort(&bp->b_un.b_addr[bo]);
if (fat12) {
if (prevcn & 1)
cn >>= 4;
cn &= 0x0fff;
/*
* Force the special cluster numbers in the range
* 0x0ff0-0x0fff to be the same as for 16 bit cluster
* numbers to let the rest of pcfs think it is always
* dealing with 16 bit fats.
*/
if ((cn & 0x0ff0) == 0x0ff0)
cn |= 0xf000;
}
}
if (!PCFSEOF(cn)) {
if (bp)
brelse(bp);
if (bnp)
*bnp = cntobn(pmp, cn);
if (cnp)
*cnp = cn;
fc_setcache(dep, FC_LASTMAP, i, cn);
return 0;
}
hiteof:;
if (cnp)
*cnp = i;
if (bp)
brelse(bp);
/* update last file cluster entry in the fat cache */
fc_setcache(dep, FC_LASTFC, i-1, prevcn);
return E2BIG;
}
/*
* Find the closest entry in the fat cache to the
* cluster we are looking for.
*/
fc_lookup(dep, findcn, frcnp, fsrcnp)
struct denode *dep;
u_long findcn;
u_long *frcnp;
u_long *fsrcnp;
{
int i;
u_long cn;
struct fatcache *closest = 0;
for (i = 0; i < FC_SIZE; i++) {
cn = dep->de_fc[i].fc_frcn;
if (cn != FCE_EMPTY && cn <= findcn) {
if (closest == 0 || cn > closest->fc_frcn)
closest = &dep->de_fc[i];
}
}
if (closest) {
*frcnp = closest->fc_frcn;
*fsrcnp = closest->fc_fsrcn;
}
}
/*
* Purge the fat cache in denode dep of all entries
* relating to file relative cluster frcn and beyond.
*/
fc_purge(dep, frcn)
struct denode *dep;
u_int frcn;
{
int i;
struct fatcache *fcp;
fcp = dep->de_fc;
for (i = 0; i < FC_SIZE; i++, fcp++) {
if (fcp->fc_frcn != FCE_EMPTY && fcp->fc_frcn >= frcn)
fcp->fc_frcn = FCE_EMPTY;
}
}
/*
* Once the first fat is updated the other copies of
* the fat must also be updated. This function does
* this.
* pmp - pcfsmount structure for filesystem to update
* bp - addr of modified fat block
* fatbn - block number relative to begin of filesystem
* of the modified fat block.
*/
void
updateotherfats(pmp, bp, fatbn)
struct pcfsmount *pmp;
struct buf *bp;
u_long fatbn;
{
int i;
struct buf *bpn;
#if defined(PCFSDEBUG)
printf("updateotherfats(pmp %08x, bp %08x, fatbn %d)\n",
pmp, bp, fatbn);
#endif /* defined(PCFSDEBUG) */
/*
* Now copy the block(s) of the modified fat to the other
* copies of the fat and write them out. This is faster
* than reading in the other fats and then writing them
* back out. This could tie up the fat for quite a while.
* Preventing others from accessing it. To prevent us
* from going after the fat quite so much we use delayed
* writes, unless they specfied "synchronous" when the
* filesystem was mounted. If synch is asked for then
* use bwrite()'s and really slow things down.
*/
for (i = 1; i < pmp->pm_FATs; i++) {
fatbn += pmp->pm_FATsecs;
/* getblk() never fails */
bpn = getblk(pmp->pm_devvp, fatbn, bp->b_bcount);
bcopy(bp->b_un.b_addr, bpn->b_un.b_addr,
bp->b_bcount);
if (pmp->pm_waitonfat)
bwrite(bpn);
else
bdwrite(bpn);
}
}
/*
* Updating entries in 12 bit fats is a pain in the butt.
*
* The following picture shows where nibbles go when
* moving from a 12 bit cluster number into the appropriate
* bytes in the FAT.
*
* byte m byte m+1 byte m+2
* +----+----+ +----+----+ +----+----+
* | 0 1 | | 2 3 | | 4 5 | FAT bytes
* +----+----+ +----+----+ +----+----+
*
* +----+----+----+ +----+----+----+
* | 3 0 1 | | 4 5 2 |
* +----+----+----+ +----+----+----+
* cluster n cluster n+1
*
* Where n is even.
* m = n + (n >> 2)
*
* (Function no longer used)
*/
extern inline void
usemap_alloc (struct pcfsmount *pmp, u_long cn)
{
pmp->pm_inusemap[cn / 8] |= 1 << (cn % 8);
pmp->pm_freeclustercount--;
/* This assumes that the lowest available cluster was allocated */
pmp->pm_lookhere = cn + 1;
}
extern inline void
usemap_free (struct pcfsmount *pmp, u_long cn)
{
pmp->pm_freeclustercount++;
pmp->pm_inusemap[cn / 8] &= ~(1 << (cn % 8));
if (pmp->pm_lookhere > cn)
pmp->pm_lookhere = cn;
}
int
clusterfree(pmp, cluster, oldcnp)
struct pcfsmount *pmp;
u_long cluster;
u_long *oldcnp;
{
int error;
u_long oldcn;
error = fatentry(FAT_GET_AND_SET, pmp, cluster, &oldcn, PCFSFREE);
if (error == 0) {
/*
* If the cluster was successfully marked free, then update the count of
* free clusters, and turn off the "allocated" bit in the
* "in use" cluster bit map.
*/
usemap_free(pmp, cluster);
if (oldcnp)
*oldcnp = oldcn;
}
return error;
}
/*
* Get or Set or 'Get and Set' the cluster'th entry in the
* fat.
* function - whether to get or set a fat entry
* pmp - address of the pcfsmount structure for the
* filesystem whose fat is to be manipulated.
* cluster - which cluster is of interest
* oldcontents - address of a word that is to receive
* the contents of the cluster'th entry if this is
* a get function
* newcontents - the new value to be written into the
* cluster'th element of the fat if this is a set
* function.
*
* This function can also be used to free a cluster
* by setting the fat entry for a cluster to 0.
*
* All copies of the fat are updated if this is a set
* function.
* NOTE:
* If fatentry() marks a cluster as free it does not
* update the inusemap in the pcfsmount structure.
* This is left to the caller.
*/
int
fatentry(function, pmp, cn, oldcontents, newcontents)
int function;
struct pcfsmount *pmp;
u_long cn;
u_long *oldcontents;
u_long newcontents;
{
int error;
u_long readcn;
u_long bn, bo, bsize, byteoffset;
struct buf *bp;
/*printf("fatentry(func %d, pmp %08x, clust %d, oldcon %08x, newcon %d)\n",
function, pmp, cluster, oldcontents, newcontents);*/
#ifdef DIAGNOSTIC
/*
* Be sure they asked us to do something.
*/
if ((function & (FAT_SET | FAT_GET)) == 0) {
printf("fatentry(): function code doesn't specify get or set\n");
return EINVAL;
}
/*
* If they asked us to return a cluster number
* but didn't tell us where to put it, give them
* an error.
*/
if ((function & FAT_GET) && oldcontents == NULL) {
printf("fatentry(): get function with no place to put result\n");
return EINVAL;
}
#endif
/*
* Be sure the requested cluster is in the filesystem.
*/
if (cn < CLUST_FIRST || cn > pmp->pm_maxcluster)
return EINVAL;
byteoffset = FATOFS(pmp, cn);
fatblock(pmp, byteoffset, &bn, &bsize, &bo);
error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
if (function & FAT_GET) {
readcn = getushort(&bp->b_un.b_addr[bo]);
if (FAT12(pmp)) {
if (cn & 1)
readcn >>= 4;
readcn &= 0x0fff;
/* map certain 12 bit fat entries to 16 bit */
if ((readcn & 0x0ff0) == 0x0ff0)
readcn |= 0xf000;
}
*oldcontents = readcn;
}
if (function & FAT_SET) {
if (FAT12(pmp)) {
readcn = getushort(&bp->b_un.b_addr[bo]);
if (cn & 1) {
readcn &= 0x000f;
readcn |= (newcontents << 4);
}
else {
readcn &= 0xf000;
readcn |= (newcontents << 0);
}
putushort(&bp->b_un.b_addr[bo], readcn);
}
else
putushort(&bp->b_un.b_addr[bo], newcontents);
updateotherfats(pmp, bp, bn);
/*
* Write out the first fat last.
*/
if (pmp->pm_waitonfat)
bwrite(bp);
else
bdwrite(bp);
bp = NULL;
pmp->pm_fmod++;
}
if (bp)
brelse(bp);
return 0;
}
/*
* Allocate a free cluster.
* pmp -
* retcluster - put the allocated cluster's number here.
* fillwith - put this value into the fat entry for the
* allocated cluster.
*/
int
clusteralloc(pmp, retcluster, fillwith)
struct pcfsmount *pmp;
u_long *retcluster;
u_long fillwith;
{
int error;
u_long cn;
u_long idx, max_idx, bit, map;
max_idx = pmp->pm_maxcluster / 8;
for (idx = pmp->pm_lookhere / 8; idx <= max_idx; idx++) {
map = pmp->pm_inusemap[idx];
if (map != 0xff) {
for (bit = 0; bit < 8; bit++) {
if ((map & (1 << bit)) == 0) {
cn = idx * 8 + bit;
goto found_one;
}
}
}
}
return ENOSPC;
found_one:;
error = fatentry(FAT_SET, pmp, cn, 0, fillwith);
if (error == 0) {
usemap_alloc(pmp, cn);
*retcluster = cn;
}
#if defined(PCFSDEBUG)
printf("clusteralloc(): allocated cluster %d\n", cn);
#endif /* defined(PCFSDEBUG) */
return error;
}
/*
* Free a chain of clusters.
* pmp - address of the pcfs mount structure for the
* filesystem containing the cluster chain to be freed.
* startcluster - number of the 1st cluster in the chain
* of clusters to be freed.
*/
int
freeclusterchain(pmp, startcluster)
struct pcfsmount *pmp;
u_long startcluster;
{
u_long nextcluster;
int error = 0;
while (startcluster >= CLUST_FIRST && startcluster <= pmp->pm_maxcluster) {
error = clusterfree(pmp, startcluster, &nextcluster);
if (error) {
printf("freeclusterchain(): free failed, cluster %d\n",
startcluster);
break;
}
startcluster = nextcluster;
}
return error;
}
/*
* Read in fat blocks looking for free clusters.
* For every free cluster found turn off its
* corresponding bit in the pm_inusemap.
*/
int
fillinusemap(pmp)
struct pcfsmount *pmp;
{
struct buf *bp = NULL;
u_long cn, readcn;
int error;
int fat12 = FAT12(pmp);
u_long bn, bo, bsize, byteoffset;
/*
* Mark all clusters in use, we mark the free ones in the
* fat scan loop further down.
*/
for (cn = 0; cn < (pmp->pm_maxcluster >> 3) + 1; cn++)
pmp->pm_inusemap[cn] = 0xff;
/*
* Figure how many free clusters are in the filesystem
* by ripping thougth the fat counting the number of
* entries whose content is zero. These represent free
* clusters.
*/
pmp->pm_freeclustercount = 0;
pmp->pm_lookhere = pmp->pm_maxcluster + 1;
for (cn = CLUST_FIRST; cn <= pmp->pm_maxcluster; cn++) {
byteoffset = FATOFS(pmp, cn);
bo = byteoffset % pmp->pm_fatblocksize;
if (!bo || !bp) {
/* Read new FAT block */
if (bp)
brelse(bp);
fatblock(pmp, byteoffset, &bn, &bsize, NULL);
error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
if (error)
return error;
}
readcn = getushort(&bp->b_un.b_addr[bo]);
if (fat12) {
if (cn & 1)
readcn >>= 4;
readcn &= 0x0fff;
}
if (readcn == 0)
usemap_free(pmp, cn);
}
brelse(bp);
return 0;
}
/*
* Allocate a new cluster and chain it onto the end of the
* file.
* dep - the file to extend
* bpp - where to return the address of the buf header for the
* new file block
* ncp - where to put cluster number of the newly allocated file block
* If this pointer is 0, do not return the cluster number.
*
* NOTE:
* This function is not responsible for turning on the DEUPD
* bit if the de_flag field of the denode and it does not
* change the de_FileSize field. This is left for the caller
* to do.
*/
int
extendfile(dep, bpp, ncp)
struct denode *dep;
struct buf **bpp;
u_int *ncp;
{
int error = 0;
u_long frcn;
u_long cn;
struct pcfsmount *pmp = dep->de_pmp;
/*
* Don't try to extend the root directory
*/
if (DETOV(dep)->v_flag & VROOT) {
printf("extendfile(): attempt to extend root directory\n");
return ENOSPC;
}
/*
* If the "file's last cluster" cache entry is empty,
* and the file is not empty,
* then fill the cache entry by calling pcbmap().
*/
fc_fileextends++;
if (dep->de_fc[FC_LASTFC].fc_frcn == FCE_EMPTY &&
dep->de_StartCluster != 0) {
fc_lfcempty++;
error = pcbmap(dep, 0xffff, 0, &cn);
/* we expect it to return E2BIG */
if (error != E2BIG)
return error;
error = 0;
}
/*
* Allocate another cluster and chain onto the end of the file.
* If the file is empty we make de_StartCluster point to the
* new block. Note that de_StartCluster being 0 is sufficient
* to be sure the file is empty since we exclude attempts to
* extend the root directory above, and the root dir is the
* only file with a startcluster of 0 that has blocks allocated
* (sort of).
*/
if (error = clusteralloc(pmp, &cn, CLUST_EOFE))
return error;
if (dep->de_StartCluster == 0) {
dep->de_StartCluster = cn;
frcn = 0;
} else {
error = fatentry(FAT_SET, pmp, dep->de_fc[FC_LASTFC].fc_fsrcn,
0, cn);
if (error) {
clusterfree(pmp, cn, NULL);
return error;
}
frcn = dep->de_fc[FC_LASTFC].fc_frcn + 1;
}
/*
* Update the "last cluster of the file" entry in the denode's
* fat cache.
*/
fc_setcache(dep, FC_LASTFC, frcn, cn);
/*
* Get the buf header for the new block of the file.
*/
if (dep->de_Attributes & ATTR_DIRECTORY) {
*bpp = getblk(pmp->pm_devvp, cntobn(pmp, cn),
pmp->pm_bpcluster);
} else {
*bpp = getblk(DETOV(dep), frcn,
pmp->pm_bpcluster);
}
clrbuf(*bpp);
/*
* Give them the filesystem relative cluster number
* if they want it.
*/
if (ncp)
*ncp = cn;
return 0;
}

729
sys/pcfs/pcfs_lookup.c Normal file
View File

@ -0,0 +1,729 @@
/*
* Written by Paul Popelka (paulp@uts.amdahl.com)
*
* You can do anything you want with this software,
* just don't say you wrote it,
* and don't remove this notice.
*
* This software is provided "as is".
*
* The author supplies this software to be publicly
* redistributed on the understanding that the author
* is not responsible for the correct functioning of
* this software in any circumstances and is not liable
* for any damages caused by this software.
*
* October 1992
*
* $Header: /cvsroot/src/sys/pcfs/Attic/pcfs_lookup.c,v 1.1 1993/04/09 19:38:08 cgd Exp $
*
*/
#include "param.h"
#include "namei.h"
#include "buf.h"
#include "vnode.h"
#include "mount.h"
#include "bpb.h"
#include "direntry.h"
#include "denode.h"
#include "pcfsmount.h"
#include "fat.h"
/*
* When we search a directory the blocks containing directory
* entries are read and examined. The directory entries
* contain information that would normally be in the inode
* of a unix filesystem. This means that some of a directory's
* contents may also be in memory resident denodes (sort of
* an inode). This can cause problems if we are searching
* while some other process is modifying a directory. To
* prevent one process from accessing incompletely modified
* directory information we depend upon being the soul owner
* of a directory block. bread/brelse provide this service.
* This being the case, when a process modifies a directory
* it must first acquire the disk block that contains the
* directory entry to be modified. Then update the disk
* block and the denode, and then write the disk block out
* to disk. This way disk blocks containing directory
* entries and in memory denode's will be in synch.
*/
int
pcfs_lookup(vdp, ndp, p)
struct vnode *vdp; /* vnode of directory to search */
struct nameidata *ndp;
struct proc *p;
{
daddr_t bn;
int flag;
int error;
int lockparent;
int wantparent;
int slotstatus;
#define NONE 0
#define FOUND 1
int slotoffset;
int slotcluster;
int frcn;
u_long cluster;
int rootreloff;
int diroff;
int isadir; /* ~0 if found direntry is a directory */
u_long scn; /* starting cluster number */
struct denode *dp;
struct denode *pdp;
struct denode *tdp;
struct pcfsmount *pmp;
struct buf *bp = 0;
struct direntry *dep;
u_char dosfilename[12];
#if defined(PCFSDEBUG)
printf("pcfs_lookup(): looking for %s\n", ndp->ni_ptr);
#endif /* defined(PCFSDEBUG) */
ndp->ni_dvp = vdp;
ndp->ni_vp = NULL;
dp = VTODE(vdp);
pmp = dp->de_pmp;
lockparent = ndp->ni_nameiop & LOCKPARENT;
flag = ndp->ni_nameiop & OPMASK;
wantparent = ndp->ni_nameiop & (LOCKPARENT | WANTPARENT);
#if defined(PCFSDEBUG)
printf("pcfs_lookup(): vdp %08x, dp %08x, Attr %02x\n",
vdp, dp, dp->de_Attributes);
#endif /* defined(PCFSDEBUG) */
/*
* Be sure vdp is a directory. Since dos filesystems
* don't have the concept of execute permission anybody
* can search a directory.
*/
if ((dp->de_Attributes & ATTR_DIRECTORY) == 0)
return ENOTDIR;
/*
* See if the component of the pathname we are looking for
* is in the directory cache. If so then do a few things
* and return.
*/
if (error = cache_lookup(ndp)) {
int vpid;
if (error == ENOENT)
return error;
#ifdef PARANOID
if (vdp == ndp->ni_rdir && ndp->ni_isdotdot)
panic("pcfs_lookup: .. thru root");
#endif /* PARANOID */
pdp = dp;
vdp = ndp->ni_vp;
dp = VTODE(vdp);
vpid = vdp->v_id;
if (pdp == dp) {
VREF(vdp);
error = 0;
} else if (ndp->ni_isdotdot) {
DEUNLOCK(pdp);
error = vget(vdp);
if (!error && lockparent && *ndp->ni_next == '\0')
DELOCK(pdp);
} else {
error = vget(vdp);
if (!lockparent || error || *ndp->ni_next != '\0')
DEUNLOCK(pdp);
}
if (!error) {
if (vpid == vdp->v_id) {
#if defined(PCFSDEBUG)
printf("pcfs_lookup(): cache hit, vnode %08x, file %s\n", vdp, dp->de_Name);
#endif /* defined(PCFSDEBUG) */
return 0;
}
deput(dp);
if (lockparent && pdp != dp && *ndp->ni_next == '\0')
DEUNLOCK(pdp);
}
DELOCK(pdp);
dp = pdp;
vdp = DETOV(dp);
ndp->ni_vp = NULL;
}
/*
* If they are going after the . or .. entry in the
* root directory, they won't find it. DOS filesystems
* don't have them in the root directory. So, we fake it.
* deget() is in on this scam too.
*/
if ((vdp->v_flag & VROOT) && ndp->ni_ptr[0] == '.' &&
(ndp->ni_namelen == 1 ||
(ndp->ni_namelen == 2 && ndp->ni_ptr[1] == '.'))) {
isadir = ATTR_DIRECTORY;
scn = PCFSROOT;
#if defined(PCFSDEBUG)
printf("pcfs_lookup(): looking for . or .. in root directory\n");
#endif /* defined(PCFSDEBUG) */
cluster == PCFSROOT;
diroff = PCFSROOT_OFS;
goto foundroot;
}
/*
* Don't search for free slots unless we are creating
* a filename and we are at the end of the pathname.
*/
slotstatus = FOUND;
if ((flag == CREATE || flag == RENAME) && *ndp->ni_next == '\0') {
slotstatus = NONE;
slotoffset = -1;
}
unix2dosfn((u_char *)ndp->ni_ptr, dosfilename, ndp->ni_namelen);
dosfilename[11] = 0;
#if defined(PCFSDEBUG)
printf("pcfs_lookup(): dos version of filename %s, length %d\n",
dosfilename, ndp->ni_namelen);
#endif /* defined(PCFSDEBUG) */
/*
* Search the directory pointed at by vdp for the
* name pointed at by ndp->ni_ptr.
*/
tdp = NULL;
/*
* The outer loop ranges over the clusters that make
* up the directory. Note that the root directory is
* different from all other directories. It has a
* fixed number of blocks that are not part of the
* pool of allocatable clusters. So, we treat it a
* little differently.
* The root directory starts at "cluster" 0.
*/
rootreloff = 0;
for (frcn = 0; ; frcn++) {
if (error = pcbmap(dp, frcn, &bn, &cluster)) {
if (error == E2BIG)
break;
return error;
}
if (error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED, &bp))
return error;
for (diroff = 0; diroff < pmp->pm_depclust; diroff++) {
dep = (struct direntry *)bp->b_un.b_addr + diroff;
/*
* If the slot is empty and we are still looking for
* an empty then remember this one. If the slot is
* not empty then check to see if it matches what we
* are looking for. If the slot has never been filled
* with anything, then the remainder of the directory
* has never been used, so there is no point in searching
* it.
*/
if (dep->deName[0] == SLOT_EMPTY ||
dep->deName[0] == SLOT_DELETED) {
if (slotstatus != FOUND) {
slotstatus = FOUND;
if (cluster == PCFSROOT)
slotoffset = rootreloff;
else
slotoffset = diroff;
slotcluster = cluster;
}
if (dep->deName[0] == SLOT_EMPTY) {
brelse(bp);
goto notfound;
}
} else {
/* Ignore volume labels (anywhere, not just
* the root directory). */
if ((dep->deAttributes & ATTR_VOLUME) == 0 &&
bcmp(dosfilename, dep->deName, 11) == 0) {
#if defined(PCFSDEBUG)
printf("pcfs_lookup(): match diroff %d, rootreloff %d\n", diroff, rootreloff);
#endif /* defined(PCFSDEBUG) */
/*
* Remember where this directory entry came from
* for whoever did this lookup.
* If this is the root directory we are interested
* in the offset relative to the beginning of the
* directory (not the beginning of the cluster).
*/
if (cluster == PCFSROOT)
diroff = rootreloff;
ndp->ni_pcfs.pcfs_offset = diroff;
ndp->ni_pcfs.pcfs_cluster = cluster;
goto found;
}
}
rootreloff++;
} /* for (diroff = 0; .... */
/*
* Release the buffer holding the directory cluster
* just searched.
*/
brelse(bp);
} /* for (frcn = 0; ; frcn++) */
notfound:;
/*
* We hold no disk buffers at this point.
*/
/*
* If we get here we didn't find the entry we were looking
* for. But that's ok if we are creating or renaming and
* are at the end of the pathname and the directory hasn't
* been removed.
*/
#if defined(PCFSDEBUG)
printf("pcfs_lookup(): flag %d, refcnt %d, slotstatus %d\n",
flag, dp->de_refcnt, slotstatus);
printf(" slotoffset %d, slotcluster %d\n",
slotoffset, slotcluster);
#endif /* defined(PCFSDEBUG) */
if ((flag == CREATE || flag == RENAME) &&
*ndp->ni_next == '\0' && dp->de_refcnt != 0) {
if (slotstatus == NONE) {
ndp->ni_pcfs.pcfs_offset = 0;
ndp->ni_pcfs.pcfs_cluster = 0;
ndp->ni_pcfs.pcfs_count = 0;
} else {
#if defined(PCFSDEBUG)
printf("pcfs_lookup(): saving empty slot location\n");
#endif /* defined(PCFSDEBUG) */
ndp->ni_pcfs.pcfs_offset = slotoffset;
ndp->ni_pcfs.pcfs_cluster = slotcluster;
ndp->ni_pcfs.pcfs_count = 1;
}
/* dp->de_flag |= DEUPD; /* never update dos directories */
ndp->ni_nameiop |= SAVENAME;
if (!lockparent) /* leave searched dir locked? */
DEUNLOCK(dp);
}
/*
* Insert name in cache as non-existant if not
* trying to create it.
*/
if (ndp->ni_makeentry && flag != CREATE)
cache_enter(ndp);
return ENOENT;
found:;
/*
* NOTE: We still have the buffer with matched
* directory entry at this point.
*/
isadir = dep->deAttributes & ATTR_DIRECTORY;
scn = dep->deStartCluster;
foundroot:;
/*
* If we entered at foundroot, then we are looking
* for the . or .. entry of the filesystems root
* directory. isadir and scn were setup before
* jumping here. And, bp is null. There is no buf header.
*/
/*
* If deleting and at the end of the path, then
* if we matched on "." then don't deget() we would
* probably panic(). Otherwise deget() the directory
* entry.
*/
if (flag == DELETE && ndp->ni_next == '\0') {
if (dp->de_StartCluster == scn &&
isadir) { /* "." */
VREF(vdp);
ndp->ni_vp = vdp;
if (bp) brelse(bp);
return 0;
}
error = deget(pmp, cluster, diroff, dep, &tdp);
if (error) {
if (bp) brelse(bp);
return error;
}
ndp->ni_vp = DETOV(tdp);
if (!lockparent)
DEUNLOCK(dp);
if (bp) brelse(bp);
return 0;
}
/*
* If renaming.
*/
if (flag == RENAME && wantparent && *ndp->ni_next == '\0') {
if (dp->de_StartCluster == scn &&
isadir) {
if (bp) brelse(bp);
return EISDIR;
}
error = deget(pmp, cluster, diroff, dep, &tdp);
if (error) {
if (bp) brelse(bp);
return error;
}
ndp->ni_vp = DETOV(tdp);
ndp->ni_nameiop |= SAVENAME;
if (!lockparent)
DEUNLOCK(dp);
if (bp) brelse(bp);
return 0;
}
/*
* ?
*/
pdp = dp;
if (ndp->ni_isdotdot) {
DEUNLOCK(pdp);
error = deget(pmp, cluster, diroff, dep, &tdp);
if (error) {
DELOCK(pdp);
if (bp) brelse(bp);
return error;
}
if (lockparent && *ndp->ni_next == '\0')
DELOCK(pdp);
ndp->ni_vp = DETOV(tdp);
} else if (dp->de_StartCluster == scn &&
isadir) { /* "." */
VREF(vdp);
ndp->ni_vp = vdp;
} else {
error = deget(pmp, cluster, diroff, dep, &tdp);
if (error) {
if (bp) brelse(bp);
return error;
}
if (!lockparent || *ndp->ni_next != '\0')
DEUNLOCK(pdp);
ndp->ni_vp = DETOV(tdp);
}
if (bp) brelse(bp);
/*
* Insert name in cache if wanted.
*/
if (ndp->ni_makeentry)
cache_enter(ndp);
return 0;
}
/*
* dep - directory to copy into the directory
* ndp - nameidata structure containing info on
* where to put the directory entry in the directory.
* depp - return the address of the denode for the
* created directory entry if depp != 0
*/
int
createde(dep, ndp, depp)
struct denode *dep;
struct nameidata *ndp;
struct denode **depp;
{
int bn;
int error;
u_long dirclust, diroffset;
struct direntry *ndep;
struct denode *ddep = VTODE(ndp->ni_dvp); /* directory to add to */
struct pcfsmount *pmp = dep->de_pmp;
struct buf *bp;
#if defined(PCFSDEBUG)
printf("createde(dep %08x, ndp %08x, depp %08x)\n", dep, ndp, depp);
#endif /* defined(PCFSDEBUG) */
/*
* If no space left in the directory then allocate
* another cluster and chain it onto the end of the
* file. There is one exception to this. That is,
* if the root directory has no more space it can NOT
* be expanded. extendfile() checks for and fails attempts to
* extend the root directory. We just return an error
* in that case.
*/
if (ndp->ni_pcfs.pcfs_count == 0) {
if (error = extendfile(ddep, &bp, &dirclust))
return error;
ndep = (struct direntry *)bp->b_un.b_addr;
/*
* Let caller know where we put the directory entry.
*/
ndp->ni_pcfs.pcfs_cluster = dirclust;
ndp->ni_pcfs.pcfs_offset = diroffset = 0;
}
else {
/*
* There is space in the existing directory. So,
* we just read in the cluster with space. Copy
* the new directory entry in. Then write it to
* disk.
* NOTE: DOS directories do not get smaller as
* clusters are emptied.
*/
dirclust = ndp->ni_pcfs.pcfs_cluster;
diroffset = ndp->ni_pcfs.pcfs_offset;
error = readep(pmp, dirclust, diroffset, &bp, &ndep);
if (error)
return error;
}
*ndep = dep->de_de;
/*
* If they want us to return with the denode gotten.
*/
if (depp) {
error = deget(pmp, dirclust, diroffset, ndep, depp);
if (error)
return error;
}
if (error = bwrite(bp))
/*deput()?*/
return error;
return 0;
}
/*
* Read in a directory entry and mark it as being deleted.
*/
int
markdeleted(pmp, dirclust, diroffset)
struct pcfsmount *pmp;
u_long dirclust;
u_long diroffset;
{
int error;
struct direntry *ep;
struct buf *bp;
error = readep(pmp, dirclust, diroffset, &bp, &ep);
if (error)
return error;
ep->deName[0] = SLOT_DELETED;
return bwrite(bp);
}
/*
* Remove a directory entry.
* At this point the file represented by the directory
* entry to be removed is still full length until no
* one has it open. When the file no longer being
* used pcfs_inactive() is called and will truncate
* the file to 0 length. When the vnode containing
* the denode is needed for some other purpose by
* VFS it will call pcfs_reclaim() which will remove
* the denode from the denode cache.
*/
int
removede(ndp)
struct nameidata *ndp;
{
struct denode *dep = VTODE(ndp->ni_vp); /* the file being removed */
struct pcfsmount *pmp = dep->de_pmp;
int error;
#if defined(PCFSDEBUG)
/*printf("removede(): filename %s\n", dep->de_Name);
printf("rmde(): dep %08x, ndpcluster %d, ndpoffset %d\n",
dep, ndp->ni_pcfs.pcfs_cluster, ndp->ni_pcfs.pcfs_offset);*/
#endif /* defined(PCFSDEBUG) */
/*
* Read the directory block containing the directory
* entry we are to make free. The nameidata structure
* holds the cluster number and directory entry index
* number of the entry to free.
*/
error = markdeleted(pmp, ndp->ni_pcfs.pcfs_cluster,
ndp->ni_pcfs.pcfs_offset);
dep->de_refcnt--;
return error;
}
/*
* Be sure a directory is empty except for "." and "..".
* Return 1 if empty, return 0 if not empty or error.
*/
int
dosdirempty(dep)
struct denode *dep;
{
int dei;
int error;
u_long cn;
daddr_t bn;
struct buf *bp;
struct pcfsmount *pmp = dep->de_pmp;
struct direntry *dentp;
/*
* Since the filesize field in directory entries for a directory
* is zero, we just have to feel our way through the directory
* until we hit end of file.
*/
for (cn = 0;; cn++) {
error = pcbmap(dep, cn, &bn, 0);
if (error == E2BIG)
return 1; /* it's empty */
error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED,
&bp);
if (error)
return error;
dentp = (struct direntry *)bp->b_un.b_addr;
for (dei = 0; dei < pmp->pm_depclust; dei++) {
if (dentp->deName[0] != SLOT_DELETED) {
/*
* In dos directories an entry whose name starts with SLOT_EMPTY (0)
* starts the beginning of the unused part of the directory, so we
* can just return that it is empty.
*/
if (dentp->deName[0] == SLOT_EMPTY) {
brelse(bp);
return 1;
}
/*
* Any names other than "." and ".." in a directory mean
* it is not empty.
*/
if (bcmp(dentp->deName, ". ", 11) &&
bcmp(dentp->deName, ".. ", 11)) {
brelse(bp);
#if defined(PCFSDEBUG)
printf("dosdirempty(): entry %d found %02x, %02x\n", dei, dentp->deName[0],
dentp->deName[1]);
#endif /* defined(PCFSDEBUG) */
return 0; /* not empty */
}
}
dentp++;
}
brelse(bp);
}
/*NOTREACHED*/
}
/*
* Check to see if the directory described by target is
* in some subdirectory of source. This prevents something
* like the following from succeeding and leaving a bunch
* or files and directories orphaned.
* mv /a/b/c /a/b/c/d/e/f
* Where c and f are directories.
* source - the inode for /a/b/c
* target - the inode for /a/b/c/d/e/f
* Returns 0 if target is NOT a subdirectory of source.
* Otherwise returns a non-zero error number.
* The target inode is always unlocked on return.
*/
int
doscheckpath(source, target)
struct denode *source;
struct denode *target;
{
daddr_t scn;
struct denode dummy;
struct pcfsmount *pmp;
struct direntry *ep;
struct denode *dep;
struct buf *bp = NULL;
int error = 0;
dep = target;
if ((target->de_Attributes & ATTR_DIRECTORY) == 0 ||
(source->de_Attributes & ATTR_DIRECTORY) == 0) {
error = ENOTDIR;
goto out;
}
if (dep->de_StartCluster == source->de_StartCluster) {
error = EEXIST;
goto out;
}
if (dep->de_StartCluster == PCFSROOT)
goto out;
for (;;) {
if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
error = ENOTDIR;
goto out;
}
pmp = dep->de_pmp;
scn = dep->de_StartCluster;
error = bread(pmp->pm_devvp, cntobn(pmp, scn),
pmp->pm_bpcluster, NOCRED, &bp);
if (error) {
break;
}
ep = (struct direntry *)bp->b_un.b_addr + 1;
if ((ep->deAttributes & ATTR_DIRECTORY) == 0 ||
bcmp(ep->deName, ".. ", 11) != 0) {
error = ENOTDIR;
break;
}
if (ep->deStartCluster == source->de_StartCluster) {
error = EINVAL;
break;
}
if (ep->deStartCluster == PCFSROOT)
break;
deput(dep);
/* NOTE: deget() clears dep on error */
error = deget(pmp, ep->deStartCluster, 0, ep, &dep);
brelse(bp);
bp = NULL;
if (error)
break;
}
out:;
if (bp)
brelse(bp);
if (error == ENOTDIR)
printf("doscheckpath(): .. not a directory?\n");
if (dep != NULL)
deput(dep);
return error;
}
/*
* Read in the disk block containing the directory entry
* (dirclu, dirofs) and return the address of the buf header,
* and the address of the directory entry within the block.
*/
int
readep(pmp, dirclu, dirofs, bpp, epp)
struct pcfsmount *pmp;
u_long dirclu, dirofs;
struct buf **bpp;
struct direntry **epp;
{
int error;
daddr_t bn;
bn = detobn(pmp, dirclu, dirofs);
if (error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED, bpp)) {
*bpp = NULL;
return error;
}
if (epp)
*epp = bptoep(pmp, *bpp, dirofs);
return 0;
}
/*
* Read in the disk block containing the directory entry
* dep came from and return the address of the buf header,
* and the address of the directory entry within the block.
*/
int
readde(dep, bpp, epp)
struct denode *dep;
struct buf **bpp;
struct direntry **epp;
{
return readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset,
bpp, epp);
}

642
sys/pcfs/pcfs_vfsops.c Normal file
View File

@ -0,0 +1,642 @@
/*
* Written by Paul Popelka (paulp@uts.amdahl.com)
*
* You can do anything you want with this software,
* just don't say you wrote it,
* and don't remove this notice.
*
* This software is provided "as is".
*
* The author supplies this software to be publicly
* redistributed on the understanding that the author
* is not responsible for the correct functioning of
* this software in any circumstances and is not liable
* for any damages caused by this software.
*
* October 1992
*
* $Header: /cvsroot/src/sys/pcfs/Attic/pcfs_vfsops.c,v 1.1 1993/04/09 19:38:10 cgd Exp $
*
* April 6, 1992
*
* Changed MOUNT_PCFS to MOUNT_MSDOS, this whole package should be renamed
* to msdosfs, but I did not have the time to do it. Some one please do
* this and resubmit it to the patchkit!
* Rodney W. Grimes
*
*/
#include "param.h"
#include "systm.h"
#include "namei.h"
#include "proc.h"
#include "kernel.h"
#include "vnode.h"
#include "specdev.h" /* defines v_rdev */
#include "mount.h"
#include "buf.h"
#include "file.h"
#include "malloc.h"
#include "bpb.h"
#include "bootsect.h"
#include "direntry.h"
#include "denode.h"
#include "pcfsmount.h"
#include "fat.h"
int pcfsdoforce = 0; /* 1 = force unmount */
/*
* mp -
* path - addr in user space of mount point (ie /usr or whatever)
* data - addr in user space of mount params including the
* name of the block special file to treat as a filesystem.
* ndp -
* p -
*/
int
pcfs_mount(mp, path, data, ndp, p)
struct mount *mp;
char *path;
caddr_t data;
struct nameidata *ndp;
struct proc *p;
{
struct vnode *devvp; /* vnode for blk device to mount */
struct pcfs_args args; /* will hold data from mount request */
struct pcfsmount *pmp; /* pcfs specific mount control block */
int error;
u_int size;
/*
* Copy in the args for the mount request.
*/
if (error = copyin(data, (caddr_t)&args, sizeof(struct pcfs_args)))
return error;
/*
* Check to see if they want it to be an exportable
* filesystem via nfs. And, if they do, should it
* be read only, and what uid is root to be mapped
* to.
*/
if ((args.exflags & MNT_EXPORTED) || (mp->mnt_flag & MNT_EXPORTED)) {
if (args.exflags & MNT_EXPORTED)
mp->mnt_flag |= MNT_EXPORTED;
else
mp->mnt_flag &= ~MNT_EXPORTED;
if (args.exflags & MNT_EXRDONLY)
mp->mnt_flag |= MNT_EXRDONLY;
else
mp->mnt_flag &= ~MNT_EXRDONLY;
mp->mnt_exroot = args.exroot;
}
/*
* If they just want to update then be sure we can
* do what is asked. Can't change a filesystem from
* read/write to read only. Why?
* And if they've supplied a new device file name then we
* continue, otherwise return.
*/
if (mp->mnt_flag & MNT_UPDATE) {
pmp = (struct pcfsmount *)mp->mnt_data;
if (pmp->pm_ronly && (mp->mnt_flag & MNT_RDONLY) == 0)
pmp->pm_ronly = 0;
if (args.fspec == 0)
return 0;
}
/*
* Now, lookup the name of the block device this
* mount or name update request is to apply to.
*/
ndp->ni_nameiop = LOOKUP | FOLLOW;
ndp->ni_segflg = UIO_USERSPACE;
ndp->ni_dirp = args.fspec;
if (error = namei(ndp, p))
return error;
/*
* Be sure they've given us a block device to treat
* as a filesystem. And, that its major number is
* within the bdevsw table.
*/
devvp = ndp->ni_vp;
if (devvp->v_type != VBLK) {
vrele(devvp); /* namei() acquires this? */
return ENOTBLK;
}
if (major(devvp->v_rdev) >= nblkdev) {
vrele(devvp);
return ENXIO;
}
/*
* If this is an update, then make sure the vnode
* for the block special device is the same as the
* one our filesystem is in.
*/
if (mp->mnt_flag & MNT_UPDATE) {
if (devvp != pmp->pm_devvp)
error = EINVAL;
else
vrele(devvp);
} else {
/*
* Well, it's not an update, it's a real mount request.
* Time to get dirty.
*/
error = mountpcfs(devvp, mp, p);
}
if (error) {
vrele(devvp);
return error;
}
/*
* Copy in the name of the directory the filesystem
* is to be mounted on.
* Then copy in the name of the block special file
* representing the filesystem being mounted.
* And we clear the remainder of the character strings
* to be tidy.
* Then, we try to fill in the filesystem stats structure
* as best we can with whatever applies from a dos file
* system.
*/
pmp = (struct pcfsmount *)mp->mnt_data;
copyinstr(path, (caddr_t)mp->mnt_stat.f_mntonname,
sizeof(mp->mnt_stat.f_mntonname)-1, &size);
bzero(mp->mnt_stat.f_mntonname + size,
sizeof(mp->mnt_stat.f_mntonname) - size);
copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN-1, &size);
bzero(mp->mnt_stat.f_mntfromname + size,
MNAMELEN - size);
(void)pcfs_statfs(mp, &mp->mnt_stat, p);
#if defined(PCFSDEBUG)
printf("pcfs_mount(): mp %x, pmp %x, inusemap %x\n", mp, pmp, pmp->pm_inusemap);
#endif /* defined(PCFSDEBUG) */
return 0;
}
int
mountpcfs(devvp, mp, p)
struct vnode *devvp;
struct mount *mp;
struct proc *p;
{
int i;
int bpc;
int bit;
int error = 0;
int needclose;
int ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
dev_t dev = devvp->v_rdev;
union bootsector *bsp;
struct pcfsmount *pmp;
struct buf *bp0 = NULL;
struct byte_bpb33 *b33;
struct byte_bpb50 *b50;
/*
* Multiple mounts of the same block special file
* aren't allowed. Make sure no one else has the
* special file open. And flush any old buffers
* from this filesystem. Presumably this prevents
* us from running into buffers that are the wrong
* blocksize.
* NOTE: mountedon() is a part of the ufs filesystem.
* If the ufs filesystem is not gen'ed into the system
* we will get an unresolved reference.
*/
if (error = mountedon(devvp)) {
return error;
}
if (vcount(devvp) > 1)
return EBUSY;
vinvalbuf(devvp, 1);
/*
* Now open the block special file.
*/
if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p))
return error;
needclose = 1;
#if defined(HDSUPPORT)
/*
* Put this in when we support reading dos filesystems
* from partitioned harddisks.
*/
if (VOP_IOCTL(devvp, DIOCGPART, &pcfspart, FREAD, NOCRED, p) == 0) {
}
#endif /* defined(HDSUPPORT) */
/*
* Read the boot sector of the filesystem, and then
* check the boot signature. If not a dos boot sector
* then error out. We could also add some checking on
* the bsOemName field. So far I've seen the following
* values:
* "IBM 3.3"
* "MSDOS3.3"
* "MSDOS5.0"
*/
if (error = bread(devvp, 0, 512, NOCRED, &bp0))
goto error_exit;
bp0->b_flags |= B_AGE;
bsp = (union bootsector *)bp0->b_un.b_addr;
b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB;
b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB;
if (bsp->bs50.bsBootSectSig != BOOTSIG) {
error = EINVAL;
goto error_exit;
}
pmp = malloc(sizeof *pmp, M_PCFSMNT, M_WAITOK);
pmp->pm_inusemap = NULL;
pmp->pm_mountp = mp;
/*
* Compute several useful quantities from the bpb in
* the bootsector. Copy in the dos 5 variant of the
* bpb then fix up the fields that are different between
* dos 5 and dos 3.3.
*/
pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
pmp->pm_SectPerClust = b50->bpbSecPerClust;
pmp->pm_ResSectors = getushort(b50->bpbResSectors);
pmp->pm_FATs = b50->bpbFATs;
pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
pmp->pm_Sectors = getushort(b50->bpbSectors);
pmp->pm_Media = b50->bpbMedia;
pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
pmp->pm_Heads = getushort(b50->bpbHeads);
if (pmp->pm_Sectors == 0) {
pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
} else {
pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
pmp->pm_HugeSectors = pmp->pm_Sectors;
}
pmp->pm_fatblk = pmp->pm_ResSectors;
pmp->pm_rootdirblk = pmp->pm_fatblk +
(pmp->pm_FATs * pmp->pm_FATsecs);
pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry))
/
pmp->pm_BytesPerSec; /* in sectors */
pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
pmp->pm_SectPerClust;
pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1;
pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec;
if (FAT12(pmp))
/* This will usually be a floppy disk.
* This size makes sure that one fat entry will not be split
* across multiple blocks. */
pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
else
/* This will usually be a hard disk.
* Reading or writing one block should be quite fast. */
pmp->pm_fatblocksize = MAXBSIZE;
pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec;
if ((pmp->pm_rootdirsize % pmp->pm_SectPerClust) != 0)
printf("mountpcfs(): root directory is not a multiple of the clustersize in length\n");
/*
* Compute mask and shift value for isolating cluster relative
* byte offsets and cluster numbers from a file offset.
*/
bpc = pmp->pm_SectPerClust * pmp->pm_BytesPerSec;
pmp->pm_bpcluster = bpc;
pmp->pm_depclust = bpc/sizeof(struct direntry);
pmp->pm_crbomask = bpc - 1;
if (bpc == 0) {
error = EINVAL;
goto error_exit;
}
bit = 1;
for (i = 0; i < 32; i++) {
if (bit & bpc) {
if (bit ^ bpc) {
error = EINVAL;
goto error_exit;
}
pmp->pm_cnshift = i;
break;
}
bit <<= 1;
}
pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */
pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */
/*
* Release the bootsector buffer.
*/
brelse(bp0);
bp0 = NULL;
/*
* Allocate memory for the bitmap of allocated clusters,
* and then fill it in.
*/
pmp->pm_inusemap = malloc((pmp->pm_maxcluster >> 3) + 1,
M_PCFSFAT, M_WAITOK);
/*
* fillinusemap() needs pm_devvp.
*/
pmp->pm_dev = dev;
pmp->pm_devvp = devvp;
/*
* Have the inuse map filled in.
*/
error = fillinusemap(pmp);
if (error)
goto error_exit;
/*
* If they want fat updates to be synchronous then let
* them suffer the performance degradation in exchange
* for the on disk copy of the fat being correct just
* about all the time. I suppose this would be a good
* thing to turn on if the kernel is still flakey.
*/
pmp->pm_waitonfat = mp->mnt_flag & MNT_SYNCHRONOUS;
/*
* Finish up.
*/
pmp->pm_ronly = ronly;
if (ronly == 0)
pmp->pm_fmod = 1;
mp->mnt_data = (qaddr_t)pmp;
mp->mnt_stat.f_fsid.val[0] = (long)dev;
mp->mnt_stat.f_fsid.val[1] = MOUNT_MSDOS;
mp->mnt_flag |= MNT_LOCAL;
#if defined(QUOTA)
/*
* If we ever do quotas for DOS filesystems this would
* be a place to fill in the info in the pcfsmount
* structure.
* You dolt, quotas on dos filesystems make no sense
* because files have no owners on dos filesystems.
* of course there is some empty space in the directory
* entry where we could put uid's and gid's.
*/
#endif /* defined(QUOTA) */
devvp->v_specflags |= SI_MOUNTEDON;
return 0;
error_exit:;
if (bp0)
brelse(bp0);
if (needclose)
(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE,
NOCRED, p);
if (pmp) {
if (pmp->pm_inusemap)
free((caddr_t)pmp->pm_inusemap, M_PCFSFAT);
free((caddr_t)pmp, M_PCFSMNT);
mp->mnt_data = (qaddr_t)0;
}
return error;
}
int
pcfs_start(mp, flags, p)
struct mount *mp;
int flags;
struct proc *p;
{
return 0;
}
/*
* Unmount the filesystem described by mp.
*/
int
pcfs_unmount(mp, mntflags, p)
struct mount *mp;
int mntflags;
struct proc *p;
{
int flags = 0;
int error;
struct pcfsmount *pmp = (struct pcfsmount *)mp->mnt_data;
struct vnode *vp = pmp->pm_devvp;
if (mntflags & MNT_FORCE) {
if (!pcfsdoforce)
return EINVAL;
flags |= FORCECLOSE;
}
mntflushbuf(mp, 0);
if (mntinvalbuf(mp))
return EBUSY;
#if defined(QUOTA)
#endif /* defined(QUOTA) */
if (error = vflush(mp, NULLVP, flags))
return error;
pmp->pm_devvp->v_specflags &= ~SI_MOUNTEDON;
#if defined(PCFSDEBUG)
printf("pcfs_umount(): just before calling VOP_CLOSE()\n");
printf("flag %08x, usecount %d, writecount %d, holdcnt %d\n",
vp->v_flag, vp->v_usecount, vp->v_writecount, vp->v_holdcnt);
printf("lastr %d, id %d, mount %08x, op %08x\n",
vp->v_lastr, vp->v_id, vp->v_mount, vp->v_op);
printf("freef %08x, freeb %08x, mountf %08x, mountb %08x\n",
vp->v_freef, vp->v_freeb, vp->v_mountf, vp->v_mountb);
printf("cleanblkhd %08x, dirtyblkhd %08x, numoutput %d, type %d\n",
vp->v_cleanblkhd, vp->v_dirtyblkhd, vp->v_numoutput, vp->v_type);
printf("union %08x, tag %d, data[0] %08x, data[1] %08x\n",
vp->v_socket, vp->v_tag, vp->v_data[0], vp->v_data[1]);
#endif /* defined(PCFSDEBUG) */
error = VOP_CLOSE(pmp->pm_devvp, pmp->pm_ronly ? FREAD : FREAD|FWRITE,
NOCRED, p);
vrele(pmp->pm_devvp);
free((caddr_t)pmp->pm_inusemap, M_PCFSFAT);
free((caddr_t)pmp, M_PCFSMNT);
mp->mnt_data = (qaddr_t)0;
mp->mnt_flag &= ~MNT_LOCAL;
return error;
}
int
pcfs_root(mp, vpp)
struct mount *mp;
struct vnode **vpp;
{
struct denode *ndep;
struct pcfsmount *pmp = (struct pcfsmount *)(mp->mnt_data);
int error;
error = deget(pmp, PCFSROOT, PCFSROOT_OFS, NULL, &ndep);
#if defined(PCFSDEBUG)
printf("pcfs_root(); mp %08x, pmp %08x, ndep %08x, vp %08x\n",
mp, pmp, ndep, DETOV(ndep));
#endif /* defined(PCFSDEBUG) */
if (error == 0)
*vpp = DETOV(ndep);
return error;
}
int
pcfs_quotactl(mp, cmds, uid, arg, p)
struct mount *mp;
int cmds;
uid_t uid;
caddr_t arg;
struct proc *p;
{
#if defined(QUOTA)
#else
return EOPNOTSUPP;
#endif /* defined(QUOTA) */
}
int
pcfs_statfs(mp, sbp, p)
struct mount *mp;
struct statfs *sbp;
struct proc *p;
{
struct pcfsmount *pmp = (struct pcfsmount *)mp->mnt_data;
/*
* Fill in the stat block.
*/
sbp->f_type = MOUNT_MSDOS;
sbp->f_fsize = pmp->pm_bpcluster;
sbp->f_bsize = pmp->pm_bpcluster;
sbp->f_blocks = pmp->pm_nmbrofclusters;
sbp->f_bfree = pmp->pm_freeclustercount;
sbp->f_bavail = pmp->pm_freeclustercount;
sbp->f_files = pmp->pm_RootDirEnts;
sbp->f_ffree = 0; /* what to put in here? */
/*
* Copy the mounted on and mounted from names into
* the passed in stat block, if it is not the one
* in the mount structure.
*/
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);
}
return 0;
}
int
pcfs_sync(mp, waitfor)
struct mount *mp;
int waitfor;
{
struct vnode *vp;
struct denode *dep;
struct pcfsmount *pmp;
int error;
int allerror = 0;
pmp = (struct pcfsmount *)mp->mnt_data;
/*
* If we ever switch to not updating all of the fats
* all the time, this would be the place to update them
* from the first one.
*/
if (pmp->pm_fmod) {
if (pmp->pm_ronly) {
printf("pcfs_sync(): writing to readonly filesystem\n");
return EINVAL;
} else {
/* update fats here */
}
}
/*
* Go thru in memory denodes and write them out along
* with unwritten file blocks.
*/
loop:
for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
if (vp->v_mount != mp) /* not ours anymore */
goto loop;
if (VOP_ISLOCKED(vp)) /* file is busy */
continue;
dep = VTODE(vp);
if ((dep->de_flag & DEUPD) == 0 && vp->v_dirtyblkhd == NULL)
continue;
if (vget(vp)) /* not there anymore? */
goto loop;
if (vp->v_dirtyblkhd) /* flush dirty file blocks */
vflushbuf(vp, 0);
if ((dep->de_flag & DEUPD) &&
(error = deupdat(dep, &time, 0)))
allerror = error;
vput(vp); /* done with this one */
}
/*
* Flush filesystem control info.
*/
vflushbuf(pmp->pm_devvp, waitfor == MNT_WAIT ? B_SYNC : 0);
return allerror;
}
int
pcfs_fhtovp (mp, fhp, vpp)
struct mount *mp;
struct fid *fhp;
struct vnode **vpp;
{
struct pcfsmount *pmp = (struct pcfsmount *)mp->mnt_data;
struct defid *defhp = (struct defid *)fhp;
struct denode *dep;
int error;
error = deget (pmp, defhp->defid_dirclust, defhp->defid_dirofs,
NULL, &dep);
if (error)
return (error);
*vpp = DETOV (dep);
return (0);
}
int
pcfs_vptofh (vp, fhp)
struct vnode *vp;
struct fid *fhp;
{
struct denode *dep = VTODE(vp);
struct defid *defhp = (struct defid *)fhp;
defhp->defid_len = sizeof(struct defid);
defhp->defid_dirclust = dep->de_dirclust;
defhp->defid_dirofs = dep->de_diroffset;
/* defhp->defid_gen = ip->i_gen; */
return (0);
}
struct vfsops pcfs_vfsops = {
pcfs_mount,
pcfs_start,
pcfs_unmount,
pcfs_root,
pcfs_quotactl,
pcfs_statfs,
pcfs_sync,
pcfs_fhtovp,
pcfs_vptofh,
pcfs_init
};

1659
sys/pcfs/pcfs_vnops.c Normal file

File diff suppressed because it is too large Load Diff

143
sys/pcfs/pcfsmount.h Normal file
View File

@ -0,0 +1,143 @@
/*
* Written by Paul Popelka (paulp@uts.amdahl.com)
*
* You can do anything you want with this software,
* just don't say you wrote it,
* and don't remove this notice.
*
* This software is provided "as is".
*
* The author supplies this software to be publicly
* redistributed on the understanding that the author
* is not responsible for the correct functioning of
* this software in any circumstances and is not liable
* for any damages caused by this software.
*
* October 1992
*
* $Header: /cvsroot/src/sys/pcfs/Attic/pcfsmount.h,v 1.1 1993/04/09 19:38:16 cgd Exp $
*
*/
/*
* Layout of the mount control block for a msdos
* file system.
*/
struct pcfsmount {
struct mount *pm_mountp; /* vfs mount struct for this fs */
dev_t pm_dev; /* block special device mounted */
struct vnode *pm_devvp; /* vnode for block device mntd */
struct bpb50 pm_bpb; /* BIOS parameter blk for this fs */
u_long pm_fatblk; /* block # of first FAT */
u_long pm_rootdirblk; /* block # of root directory */
u_long pm_rootdirsize; /* size in blocks (not clusters) */
u_long pm_firstcluster; /* block number of first cluster */
u_long pm_nmbrofclusters; /* # of clusters in filesystem */
u_long pm_maxcluster; /* maximum cluster number */
u_long pm_freeclustercount; /* number of free clusters */
u_long pm_lookhere; /* start free cluster search here */
u_long pm_bnshift; /* shift file offset right this
* amount to get a block number */
u_long pm_brbomask; /* and a file offset with this
* mask to get block rel offset */
u_long pm_cnshift; /* shift file offset right this
* amount to get a cluster number */
u_long pm_crbomask; /* and a file offset with this
* mask to get cluster rel offset */
u_long pm_bpcluster; /* bytes per cluster */
u_long pm_depclust; /* directory entries per cluster */
u_long pm_fmod; /* ~0 if fs is modified, this can
* rollover to 0 */
u_long pm_fatblocksize; /* size of fat blocks in bytes */
u_long pm_fatblocksec; /* size of fat blocks in sectors */
u_long pm_fatsize; /* size of fat in bytes */
u_char *pm_inusemap; /* ptr to bitmap of in-use clusters */
char pm_ronly; /* read only if non-zero */
char pm_waitonfat; /* wait for writes of the fat to complt,
* when 0 use bdwrite, else use bwrite */
};
/*
* How to compute pm_cnshift and pm_crbomask.
*
* pm_crbomask = (pm_SectPerClust * pm_BytesPerSect) - 1
* if (bytesperclust == 0) return EBADBLKSZ;
* bit = 1;
* for (i = 0; i < 32; i++) {
* if (bit & bytesperclust) {
* if (bit ^ bytesperclust) return EBADBLKSZ;
* pm_cnshift = i;
* break;
* }
* bit <<= 1;
* }
*/
/*
* Shorthand for fields in the bpb contained in
* the pcfsmount structure.
*/
#define pm_BytesPerSec pm_bpb.bpbBytesPerSec
#define pm_SectPerClust pm_bpb.bpbSecPerClust
#define pm_ResSectors pm_bpb.bpbResSectors
#define pm_FATs pm_bpb.bpbFATs
#define pm_RootDirEnts pm_bpb.bpbRootDirEnts
#define pm_Sectors pm_bpb.bpbSectors
#define pm_Media pm_bpb.bpbMedia
#define pm_FATsecs pm_bpb.bpbFATsecs
#define pm_SecPerTrack pm_bpb.bpbSecPerTrack
#define pm_Heads pm_bpb.bpbHeads
#define pm_HiddenSects pm_bpb.bpbHiddenSecs
#define pm_HugeSectors pm_bpb.bpbHugeSectors
/*
* Map a cluster number into a filesystem relative
* block number.
*/
#define cntobn(pmp, cn) \
((((cn)-CLUST_FIRST) * (pmp)->pm_SectPerClust) + (pmp)->pm_firstcluster)
/*
* Map a filesystem relative block number back into
* a cluster number.
*/
#define bntocn(pmp, bn) \
((((bn) - pmp->pm_firstcluster)/ (pmp)->pm_SectPerClust) + CLUST_FIRST)
/*
* Calculate block number for directory entry in root dir, offset dirofs
*/
#define roottobn(pmp, dirofs) \
(((dirofs) / (pmp)->pm_depclust) * (pmp)->pm_SectPerClust \
+ (pmp)->pm_rootdirblk)
/*
* Calculate block number for directory entry at cluster dirclu, offset dirofs
*/
#define detobn(pmp, dirclu, dirofs) \
((dirclu) == PCFSROOT \
? roottobn((pmp), (dirofs)) \
: cntobn((pmp), (dirclu)))
/*
* Convert pointer to buffer -> pointer to direntry
*/
#define bptoep(pmp, bp, dirofs) \
((struct direntry *)((bp)->b_un.b_addr) \
+ (dirofs) % (pmp)->pm_depclust)
/*
* Prototypes for PCFS virtual filesystem operations
*/
int pcfs_mount __P((struct mount *mp, char *path, caddr_t data,
struct nameidata *ndp, struct proc *p));
int pcfs_start __P((struct mount *mp, int flags, struct proc *p));
int pcfs_unmount __P((struct mount *mp, int mntflags, struct proc *p));
int pcfs_root __P((struct mount *mp, struct vnode **vpp));
int pcfs_quotactl __P((struct mount *mp, int cmds, int uid, /* should be uid_t */
caddr_t arg, struct proc *p));
int pcfs_statfs __P((struct mount *mp, struct statfs *sbp, struct proc *p));
int pcfs_sync __P((struct mount *mp, int waitfor));
int pcfs_fhtovp __P((struct mount *mp, struct fid *fhp, struct vnode **vpp));
int pcfs_vptofh __P((struct vnode *vp, struct fid *fhp));
int pcfs_init __P(());

View File

@ -91,7 +91,9 @@
#define M_PROC 41 /* Proc structures */
#define M_SUBPROC 42 /* Proc sub-structures */
#define M_TEMP 49 /* misc temporary data buffers */
#define M_LAST 50
#define M_PCFSMNT 50 /* PCFS mount structure */
#define M_PCFSFAT 51 /* PCFS fat table */
#define M_LAST 52
#define INITKMEMNAMES { \
"free", /* 0 M_FREE */ \
@ -139,6 +141,8 @@
"subproc", /* 42 M_PROC */ \
0, 0, 0, 0, 0, 0, \
"temp", /* 49 M_TEMP */ \
"PCFS mount", /* 50 M_PCFSMNT */ \
"PCFS fat", /* 51 M_PCFSFAT */ \
}
struct kmemstats {

View File

@ -264,6 +264,17 @@ struct nfs_args {
#define NFSMNT_LOCKBITS (NFSMNT_SCKLOCK | NFSMNT_WANTSCK)
#endif NFS
#ifdef PCFS
/*
* Arguments to mount MSDOS filesystems.
*/
struct pcfs_args {
char *fspec; /* blocks special holding the fs to mount */
int exflags; /* mount flags */
uid_t exroot; /* mapping for root uid */
};
#endif /* PCFS */
#ifdef KERNEL
/*
* exported vnode operations

View File

@ -53,7 +53,7 @@ enum vtype { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO, VBAD };
* These are for the benefit of external programs only (e.g., pstat)
* and should NEVER be inspected inside the kernel.
*/
enum vtagtype { VT_NON, VT_UFS, VT_NFS, VT_MFS };
enum vtagtype { VT_NON, VT_UFS, VT_NFS, VT_MFS, VT_PCFS };
/*
* This defines the maximum size of the private data area