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:
parent
6f9402e83b
commit
5cc382fc66
220
sys/conf/files
220
sys/conf/files
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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 */
|
||||
};
|
|
@ -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) */
|
|
@ -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) */
|
|
@ -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) */
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -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(());
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue