summaryrefslogtreecommitdiff
path: root/libdiskfs/diskfs.h
diff options
context:
space:
mode:
Diffstat (limited to 'libdiskfs/diskfs.h')
-rw-r--r--libdiskfs/diskfs.h937
1 files changed, 937 insertions, 0 deletions
diff --git a/libdiskfs/diskfs.h b/libdiskfs/diskfs.h
new file mode 100644
index 00000000..e8974a11
--- /dev/null
+++ b/libdiskfs/diskfs.h
@@ -0,0 +1,937 @@
+/* Definitions for fileserver helper functions
+ Copyright (C) 1994, 95, 96, 97, 98, 99 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef _HURD_DISKFS
+#define _HURD_DISKFS
+
+#include <assert.h>
+#include <unistd.h>
+#include <rwlock.h>
+#include <hurd/ports.h>
+#include <hurd/fshelp.h>
+#include <hurd/iohelp.h>
+#include <idvec.h>
+
+/* Each user port referring to a file points to one of these
+ (with the aid of the ports library). */
+struct protid
+{
+ struct port_info pi; /* libports info block */
+
+ /* User identification */
+ struct iouser *user;
+
+ /* Object this refers to */
+ struct peropen *po;
+
+ /* Shared memory I/O information. */
+ memory_object_t shared_object;
+ struct shared_io *mapped;
+};
+
+/* One of these is created for each node opened by dir_pathtrans. */
+struct peropen
+{
+ int filepointer;
+ int lock_status;
+ int refcnt;
+ int openstat;
+
+ struct node *np;
+
+ /* The parent of the translator's root node. */
+ mach_port_t root_parent;
+
+ /* If this node is in a shadow tree, the parent of its root. */
+ mach_port_t shadow_root_parent;
+ /* If in a shadow tree, its root node in this translator. */
+ struct node *shadow_root;
+};
+
+/* A unique one of these exists for each node currently in use (and
+ possibly for some not currently in use, but with links) in the
+ filesystem. */
+struct node
+{
+ struct node *next, **prevp;
+
+ struct disknode *dn;
+
+ struct stat dn_stat;
+
+ /* Stat has been modified if one of the following four fields
+ is nonzero. Also, if one of the dn_set_?time fields is nonzero,
+ the appropriate dn_stat.st_?time field needs to be updated. */
+ int dn_set_ctime;
+ int dn_set_atime;
+ int dn_set_mtime;
+ int dn_stat_dirty;
+
+ struct mutex lock;
+
+ int references; /* hard references */
+ int light_references; /* light references */
+
+ mach_port_t sockaddr; /* address for S_IFSOCK shortcut */
+
+ int owner;
+
+ struct transbox transbox;
+
+ struct lock_box userlock;
+
+ struct conch conch;
+
+ struct modreq *dirmod_reqs;
+
+ struct modreq *filemod_reqs;
+
+ off_t allocsize;
+
+ int cache_id;
+
+ int author_tracks_uid;
+};
+
+/* Possibly lookup types for diskfs_lookup call */
+enum lookup_type
+{
+ LOOKUP,
+ CREATE,
+ REMOVE,
+ RENAME,
+};
+
+/* Pending directory and file modification request */
+struct modreq
+{
+ mach_port_t port;
+ struct modreq *next;
+};
+
+
+/* Special flag for diskfs_lookup. */
+#define SPEC_DOTDOT 0x10000000
+
+struct argp; /* opaque in this file */
+struct argp_child; /* opaque in this file */
+struct store; /* opaque in this file */
+struct store_parsed; /* opaque in this file */
+
+/* Declarations of variables the library sets. */
+
+extern mach_port_t diskfs_default_pager; /* send right */
+extern auth_t diskfs_auth_server_port; /* send right */
+
+/* The io_identity identity port for the filesystem. */
+extern mach_port_t diskfs_fsys_identity;
+
+/* The command line diskfs was started, set by the default argument parser.
+ If you don't use it, set this yourself. This is only used for bootstrap
+ file systems, to give the procserver. */
+extern char **diskfs_argv;
+
+/* When this is a bootstrap filesystem, the command line options passed from
+ the kernel. If not a bootstrap filesystem, it is 0, so it can be used to
+ distinguish between the two cases. */
+extern char *diskfs_boot_flags;
+
+/* Hold this lock while do fsys level operations. Innocuous users can just
+ hold a reader lock, and anyone who's going to do nasty things that would
+ screw anyone else should hold a writer lock. */
+extern struct rwlock diskfs_fsys_lock;
+
+extern volatile struct mapped_time_value *diskfs_mtime;
+
+/* True iff we should do every operation synchronously. It
+ is the format-specific code's responsibility to keep allocation
+ information permanently in sync if this is set; the rest will
+ be done by format independent code. */
+extern int diskfs_synchronous;
+
+extern spin_lock_t diskfs_node_refcnt_lock;
+
+extern int pager_port_type;
+
+/* Whether the filesystem is currently writable or not. */
+extern int diskfs_readonly;
+
+
+struct pager;
+
+/* Port classes we manage */
+extern struct port_class *diskfs_protid_class;
+extern struct port_class *diskfs_control_class;
+extern struct port_class *diskfs_execboot_class;
+extern struct port_class *diskfs_initboot_class;
+extern struct port_class *diskfs_shutdown_notification_class;
+
+extern struct port_bucket *diskfs_port_bucket;
+
+
+
+/* Declarations of things the user must or may define. */
+
+/* The user must define this type. This should hold information
+ between calls to diskfs_lookup and diskfs_dir{enter,rewrite,rename}
+ so that those calls work as described below. */
+struct dirstat;
+
+/* The user must define this variable; it should be the size in bytes
+ of a struct dirstat. */
+extern size_t diskfs_dirstat_size;
+
+/* The user must define this variable; it is the maximum number of
+ links to any one file. The implementation of dir_rename does not know
+ how to succeed if this is only one; on such formats you need to
+ reimplement dir_rename yourself. */
+extern int diskfs_link_max;
+
+/* The user must define this variable; it is the maximum length of
+ a single pathname component (i.e. file name within directory).
+ The filesystem code does not use this for anything, but it is
+ returned to user queries for _PC_NAME_MAX. */
+extern int diskfs_name_max;
+
+/* The user must define this variable; it is the maximum number of
+ symlinks to be traversed within a single call to dir_pathtrans.
+ If this is exceeded, dir_pathtrans will return ELOOP. */
+extern int diskfs_maxsymlinks;
+
+/* This variable is defined by diskfs; the suer should set it if
+ the filesystem media cannot be made writeable. */
+extern int diskfs_hard_readonly;
+
+/* The user must define this variable. Set this to be the node
+ of root of the filesystem. */
+extern struct node *diskfs_root_node;
+
+/* The user must define this variable. Set this to the name of the
+ filesystem server. */
+extern char *diskfs_server_name;
+
+/* The user must define this variables. Set this to be the server
+ version number. */
+extern char *diskfs_server_version;
+
+/* The user may define this variable. Set this to be any additional
+ version specification that should be printed for --version. */
+extern char *diskfs_extra_version;
+
+/* The user may define this variable. This should be nonzero iff the
+ filesystem format supports shortcutting symlink translation.
+ The library guarantees that users will not be able to read or write
+ the contents of the node directly, and the library will only do so
+ if the symlink hook functions return EINVAL or are not defined.
+ The library knows that the dn_stat.st_size field is the length of
+ the symlink, even if the hook functions are used. */
+int diskfs_shortcut_symlink;
+
+/* The user may define this variable. This should be nonzero iff the
+ filesystem format supports shortcutting chrdev translation. */
+int diskfs_shortcut_chrdev;
+
+/* The user may define this variable. This should be nonzero iff the
+ filesystem format supports shortcutting blkdev translation. */
+int diskfs_shortcut_blkdev;
+
+/* The user may define this variable. This should be nonzero iff the
+ filesystem format supports shortcutting fifo translation. */
+int diskfs_shortcut_fifo;
+
+/* The user may define this variable. This should be nonzero iff the
+ filesystem format supports shortcutting ifsock translation. */
+int diskfs_shortcut_ifsock;
+
+/* The user may define this variable, otherwise it has a default value of 30.
+ diskfs_set_sync_interval is called with this value when the first diskfs
+ thread is started up (in diskfs_spawn_first_threa). */
+extern int diskfs_default_sync_interval;
+
+/* The user must define this variable, which should be a string that somehow
+ identifies the particular disk this filesystem is interpreting. It is
+ generally only used to print messages or to distinguish instances of the
+ same filesystem type from one another. If this filesystem accesses no
+ external media, then define this to be 0. */
+extern char *diskfs_disk_name;
+
+/* The user must define this function. Set *STATFSBUF with
+ appropriate values to reflect the current state of the filesystem. */
+error_t diskfs_set_statfs (fsys_statfsbuf_t *statfsbuf);
+
+/* The user must define this function. Lookup in directory DP (which
+ is locked) the name NAME. TYPE will either be LOOKUP, CREATE,
+ RENAME, or REMOVE. CRED identifies the user making the call.
+
+ If the name is found, return zero, and (if NP is nonzero) set *NP
+ to point to the node for it, locked. If the name is not found,
+ return ENOENT, and (if NP is nonzero) set *NP to zero. If NP is
+ zero, then the node found must not be locked, even transitorily.
+ Lookups for REMOVE and RENAME (which must often check permissions
+ on the node being found) will always set NP.
+
+ If DS is nonzero then:
+ For LOOKUP: set *DS to be ignored by diskfs_drop_dirstat.
+ For CREATE: on success, set *DS to be ignored by diskfs_drop_dirstat.
+ on failure, set *DS for a future call to diskfs_direnter.
+ For RENAME: on success, set *DS for a future call to diskfs_dirrewrite.
+ on failure, set *DS for a future call to diskfs_direnter.
+ For REMOVE: on success, set *DS for a future call to diskfs_dirremove.
+ on failure, set *DS to be ignored by diskfs_drop_dirstat.
+ The caller of this function guarantees that if DS is nonzero, then
+ either the appropriate call listed above or diskfs_drop_dirstat will
+ be called with DS before the directory DP is unlocked, and guarantees
+ that no lookup calls will be made on this directory between this
+ lookup and the use (or descruction) of *DS.
+
+ If you use the library's versions of diskfs_rename_dir,
+ diskfs_clear_directory, and diskfs_init_dir, then lookups for `..'
+ might have the flag SPEC_DOTDOT or'd in. This has the following special
+ meaning:
+ For LOOKUP: DP should be unlocked and its reference dropped before
+ returning.
+ For RENAME and REMOVE: The node being found (*NP) is already held
+ locked, so don't lock it or add a reference to it.
+ (SPEC_DOTDOT will not be given with CREATE.)
+
+ Return ENOENT if NAME isn't in the directory.
+ Return EAGAIN if NAME refers to the `..' of this filesystem's root.
+ Return EIO if appropriate.
+*/
+error_t diskfs_lookup_hard (struct node *dp,
+ const char *name, enum lookup_type type,
+ struct node **np, struct dirstat *ds,
+ struct protid *cred);
+
+/* The user must define this function. Add NP to directory DP
+ under the name NAME. This will only be called after an
+ unsuccessful call to diskfs_lookup of type CREATE or RENAME; DP
+ has been locked continuously since that call and DS is as that call
+ set it, NP is locked. CRED identifies the user responsible
+ for the call (to be used only to validate directory growth). */
+error_t diskfs_direnter_hard (struct node *dp, const char *name,
+ struct node *np, struct dirstat *ds,
+ struct protid *cred);
+
+/* The user must define this function. This will only be called after
+ a successful call to diskfs_lookup of type RENAME; this call should change
+ the name found in directory DP to point to node NP instead of its previous
+ referent. DP has been locked continuously since the call to diskfs_lookup
+ and DS is as that call set it; NP is locked. */
+error_t diskfs_dirrewrite_hard (struct node *dp, struct node *np,
+ struct dirstat *ds);
+
+/* The user must define this function. This will only be called after a
+ successful call to diskfs_lookup of type REMOVE; this call should remove
+ the name found from the directory DS. DP has been locked continuously since
+ the call to diskfs_lookup and DS is as that call set it. */
+error_t diskfs_dirremove_hard (struct node *dp, struct dirstat *ds);
+
+/* The user must define this function. Initialize DS such that
+ diskfs_drop_dirstat will ignore it. */
+void diskfs_null_dirstat (struct dirstat *ds);
+
+/* The user must define this function. DS has been set by a previous
+ call to diskfs_lookup on directory DP; this function is
+ guaranteed to be called if none of
+ diskfs_dir{enter,rename,rewrite} is, and should free any state
+ retained by a struct dirstat. DP has been locked continuously since
+ the call to diskfs_lookup. */
+error_t diskfs_drop_dirstat (struct node *dp, struct dirstat *ds);
+
+/* The user must define this function. Return N directory entries
+ starting at ENTRY from locked directory node DP. Fill *DATA with
+ the entries; that pointer currently points to *DATACNT bytes. If
+ it isn't big enough, vm_allocate into *DATA. Set *DATACNT with the
+ total size used. Fill AMT with the number of entries copied.
+ Regardless, never copy more than BUFSIZ bytes. If BUFSIZ is 0,
+ then there is no limit on *DATACNT; if N is -1, then there is no limit
+ on AMT. */
+error_t diskfs_get_directs (struct node *dp, int entry, int n,
+ char **data, u_int *datacnt,
+ vm_size_t bufsiz, int *amt);
+
+/* The user must define this function. For locked node NP (for which
+ diskfs_node_translated is true) look up the name of its translator.
+ Store the name into newly malloced storage; set *NAMELEN to the
+ total length. */
+error_t diskfs_get_translator (struct node *np, char **namep, u_int *namelen);
+
+/* The user must define this function. For locked node NP, set
+ the name of the translating program to be NAME, length NAMELEN. CRED
+ identifies the user responsible for the call. */
+error_t diskfs_set_translator (struct node *np,
+ const char *name, u_int namelen,
+ struct protid *cred);
+
+/* The user must define this function. Truncate locked node NP to be SIZE
+ bytes long. (If NP is already less than or equal to SIZE bytes
+ long, do nothing.) If this is a symlink (and diskfs_shortcut_symlink
+ is set) then this should clear the symlink, even if
+ diskfs_create_symlink_hook stores the link target elsewhere. */
+error_t diskfs_truncate (struct node *np, off_t size);
+
+/* The user must define this function. Grow the disk allocated to locked node
+ NP to be at least SIZE bytes, and set NP->allocsize to the actual
+ allocated size. (If the allocated size is already SIZE bytes, do
+ nothing.) CRED identifies the user responsible for the call. */
+error_t diskfs_grow (struct node *np, off_t size, struct protid *cred);
+
+/* The user must define this function. Write to disk (synchronously
+ iff WAIT is nonzero) from format-specific buffers any non-paged
+ metadata. If CLEAN is nonzero, then after this is written the
+ filesystem will be absolutely clean, and the non-paged metadata can
+ so indicate. */
+error_t diskfs_set_hypermetadata (int wait, int clean);
+
+/* The user must define this function. Allocate a new node to be of
+ mode MODE in locked directory DP (don't actually set the mode or
+ modify the dir, that will be done by the caller); the user
+ responsible for the request can be identified with CRED. Set *NP
+ to be the newly allocated node. */
+error_t diskfs_alloc_node (struct node *dp, mode_t mode, struct node **np);
+
+/* Free node NP; the on disk copy has already been synced with
+ diskfs_node_update (where NP->dn_stat.st_mode was 0). It's
+ mode used to be MODE. */
+void diskfs_free_node (struct node *np, mode_t mode);
+
+/* Node NP has no more references; free local state, including *NP
+ if it isn't to be retained. diskfs_node_refcnt_lock is held. */
+void diskfs_node_norefs (struct node *np);
+
+/* The user must define this function. Node NP has some light
+ references, but has just lost its last hard references. Take steps
+ so that if any light references can be freed, they are. NP is locked
+ as is the pager refcount lock. This function will be called after
+ diskfs_lost_hardrefs. */
+void diskfs_try_dropping_softrefs (struct node *np);
+
+/* The user must define this funcction. Node NP has some light
+ references but has just lost its last hard reference. NP is locked. */
+void diskfs_lost_hardrefs (struct node *np);
+
+/* The user must define this function. Node NP has just acquired
+ a hard reference where it had none previously. It is thus now
+ OK again to have light references without real users. NP is
+ locked. */
+void diskfs_new_hardrefs (struct node *np);
+
+/* The user must define this function. Return non-zero if locked
+ directory DP is empty. If the user does not redefine
+ diskfs_clear_directory and diskfs_init_directory, then `empty'
+ means `possesses entries labelled . and .. only'. CRED
+ identifies the user making the call (if this user can't search
+ the directory, then this routine should fail). */
+int diskfs_dirempty (struct node *dp, struct protid *cred);
+
+/* The user may define this function. Return 0 if NP's mode can be
+ changed to MODE; otherwise return an error code. It must always be
+ possible to clear the mode; diskfs will not ask for permission
+ before doing so. */
+error_t diskfs_validate_mode_change (struct node *np, mode_t mode);
+
+/* The user may define this function. Return 0 if NP's owner can be
+ changed to UID; otherwise return an error code. */
+error_t diskfs_validate_owner_change (struct node *np, uid_t uid);
+
+/* The user may define this function. Return 0 if NP's group can be
+ changed to GID; otherwise return an error code. */
+error_t diskfs_validate_group_change (struct node *np, gid_t gid);
+
+/* The user may define this function. Return 0 if NP's author can be
+ changed to AUTHOR; otherwise return an error code. */
+error_t diskfs_validate_author_change (struct node *np, uid_t author);
+
+/* The user may define this function. Return 0 if NP's flags can be
+ changed to FLAGS; otherwise return an error code. It must always
+ be possible to clear the flags. */
+error_t diskfs_validate_flags_change (struct node *np, int flags);
+
+/* The user may define this function. Return 0 if NP's rdev can be
+ changed to RDEV; otherwise return an error code. */
+error_t diskfs_validate_rdev_change (struct node *np, dev_t rdev);
+
+/* The user must define this function. Sync the info in NP->dn_stat
+ and any associated format-specific information to disk. If WAIT is true,
+ then return only after the physicial media has been completely updated. */
+void diskfs_write_disknode (struct node *np, int wait);
+
+/* The user must define this function. Sync the file contents and all
+ associated meta data of file NP to disk (generally this will involve
+ calling diskfs_node_update for much of the metadata). If WAIT is true,
+ then return only after the physical media has been completely updated. */
+void diskfs_file_update (struct node *np, int wait);
+
+/* The user must define this function. For each active node, call
+ FUN. The node is to be locked around the call to FUN. If FUN
+ returns non-zero for any node, then immediately stop, and return
+ that value. */
+error_t diskfs_node_iterate (error_t (*fun)(struct node *));
+
+/* The user must define this function. Sync all the pagers and any
+ data belonging on disk except for the hypermetadata. If WAIT is true,
+ then return only after the physicial media has been completely updated. */
+void diskfs_sync_everything (int wait);
+
+/* Shutdown all pagers; this is done when the filesystem is exiting and is
+ irreversable. */
+void diskfs_shutdown_pager ();
+
+/* The user must define this function. Return a memory object port (send
+ right) for the file contents of NP. PROT is the maximum allowable
+ access. On errors, return MACH_PORT_NULL and set errno. */
+mach_port_t diskfs_get_filemap (struct node *np, vm_prot_t prot);
+
+/* The user must define this function. Return true if there are pager
+ ports exported that might be in use by users. If this returns false, then
+ further pager creation is also blocked. */
+int diskfs_pager_users ();
+
+/* Return the bitwise or of the maximum prot parameter (the second arg to
+ diskfs_get_filemap) for all active user pagers. */
+vm_prot_t diskfs_max_user_pager_prot ();
+
+/* The user must define this function. Return a `struct pager *' suitable
+ for use as an argument to diskfs_register_memory_fault_area that
+ refers to the pager returned by diskfs_get_filemap for node NP.
+ NP is locked. */
+struct pager *diskfs_get_filemap_pager_struct (struct node *np);
+
+/* The user may define this function. It is called when the disk has been
+ changed from read-only to read-write mode or vice-versa. READONLY is the
+ new state (which is also reflected in DISKFS_READONLY). This function is
+ also called during initial startup if the filesystem is to be writable. */
+void diskfs_readonly_changed (int readonly);
+
+/* The user must define this function. It must invalidate all cached global
+ state, and re-read it as necessary from disk, without writing anything.
+ It is always called with DISKFS_READONLY true. diskfs_node_reload is
+ subsequently called on all active nodes, so this call needn't re-read any
+ node-specific data. */
+error_t diskfs_reload_global_state ();
+
+/* The user must define this function. It must re-read all data specific to
+ NODE from disk, without writing anything. It is always called with
+ DISKFS_READONLY true. */
+error_t diskfs_node_reload (struct node *node);
+
+/* If this function is nonzero (and diskfs_shortcut_symlink is set) it
+ is called to set a symlink. If it returns EINVAL or isn't set,
+ then the normal method (writing the contents into the file data) is
+ used. If it returns any other error, it is returned to the user. */
+error_t (*diskfs_create_symlink_hook)(struct node *np, const char *target);
+
+/* If this function is nonzero (and diskfs_shortcut_symlink is set) it
+ is called to read the contents of a symlink. If it returns EINVAL or
+ isn't set, then the normal method (reading from the file data) is
+ used. If it returns any other error, it is returned to the user. */
+error_t (*diskfs_read_symlink_hook)(struct node *np, char *target);
+
+/* The library exports the following functions for general use */
+
+/* Call this after arguments have been parsed to initialize the library.
+ You must call this before calling any other diskfs functions, and after
+ parsing diskfs options. */
+error_t diskfs_init_diskfs (void);
+
+/* Call this once the filesystem is fully initialized, to advertise the new
+ filesystem control port to our parent filesystem. If BOOTSTRAP is set,
+ the diskfs will call fsys_startup on that port as appropriate and return
+ the REALNODE returned in that call; otherwise we return MACH_PORT_NULL.
+ FLAGS specifies how to open REALNODE (from the O_* set). */
+mach_port_t diskfs_startup_diskfs (mach_port_t bootstrap, int flags);
+
+/* Call this after all format-specific initialization is done (except
+ for setting diskfs_root_node); at this point the pagers should be
+ ready to go. */
+void diskfs_spawn_first_thread (void);
+
+/* Once diskfs_root_node is set, call this if we are a bootstrap
+ filesystem. If you call this, then the library will call
+ diskfs_init_completed once it has a valid proc and auth port. */
+void diskfs_start_bootstrap ();
+
+/* Node NP now has no more references; clean all state. The
+ _diskfs_node_refcnt_lock must be held, and will be released
+ upon return. NP must be locked. */
+void diskfs_drop_node (struct node *np);
+
+/* Set on disk fields from NP->dn_stat; update ctime, atime, and mtime
+ if necessary. If WAIT is true, then return only after the physical
+ media has been completely updated. */
+void diskfs_node_update (struct node *np, int wait);
+
+/* Add a hard reference to a node. If there were no hard
+ references previously, then the node cannot be locked
+ (because you must hold a hard reference to hold the lock). */
+void diskfs_nref (struct node *np);
+
+/* Unlock node NP and release a hard reference; if this is the last
+ hard reference and there are no links to the file then request
+ soft references to be dropped. */
+void diskfs_nput (struct node *np);
+
+/* Release a hard reference on NP. If NP is locked by anyone, then
+ this cannot be the last hard reference (because you must hold a
+ hard reference in order to hold the lock). If this is the last
+ hard reference and there are no links, then request soft references
+ to be dropped. */
+void diskfs_nrele (struct node *np);
+
+/* Add a light reference to a node. */
+void diskfs_nref_light (struct node *np);
+
+/* Unlock node NP and release a light reference */
+void diskfs_nput_light (struct node *np);
+
+/* Release a light reference on NP. If NP is locked by anyone, then
+ this cannot be the last reference (because you must hold a
+ hard reference in order to hold the lock). */
+void diskfs_nrele_light (struct node *np);
+
+/* Reading and writing of files. this is called by other filesystem
+ routines and handles extension of files automatically. NP is the
+ node to be read or written, and must be locked. DATA will be
+ written or filled. OFF identifies where in thi fel the I/O is to
+ take place (-1 is not allowed). AMT is the size of DATA and tells
+ how much to copy. DIR is 1 for writing and 0 for reading. CRED is
+ the user doing the access (only used to validate attempted file
+ extension). For reads, *AMTREAD is filled with the amount actually
+ read. */
+error_t
+diskfs_node_rdwr (struct node *np, char *data, off_t off,
+ size_t amt, int dir, struct protid *cred,
+ size_t *amtread);
+
+
+/* Send notifications to users who have requested them with
+ dir_notice_changes for directory DP. The type of modification and
+ affected name are TYPE and NAME respectively. This should be
+ called by diskfs_direnter, diskfs_dirremove, and diskfs_dirrewrite,
+ and anything else that changes the directory, after the change is
+ fully completed. */
+void
+diskfs_notice_dirchange (struct node *dp, enum dir_changed_type type,
+ const char *name);
+
+/* Send notifications to users who have requested them with
+ file_notice_changes for file NP. The type of modification is TYPE.
+ START and END identify the affected region of the file's data.
+ This should be called after the change is fully completed. */
+void
+diskfs_notice_filechange (struct node *np, enum file_changed_type type,
+ off_t start, off_t end);
+
+/* Create a new node structure with DS as its physical disknode.
+ The new node will have one hard reference and no light references. */
+struct node *diskfs_make_node (struct disknode *dn);
+
+
+/* The library also exports the following functions; they are not generally
+ useful unless you are redefining other functions the library provides. */
+
+/* Lookup in directory DP (which is locked) the name NAME. TYPE will
+ either be LOOKUP, CREATE, RENAME, or REMOVE. CRED identifies the
+ user making the call.
+
+ NAME will have leading and trailing slashes stripped. It is an
+ error if there are internal slashes. NAME will be modified in
+ place if there are slashes in it; it is therefore an error to
+ specify a constant NAME which contains slashes.
+
+ If the name is found, return zero, and (if NP is nonzero) set *NP
+ to point to the node for it, locked. If the name is not found,
+ return ENOENT, and (if NP is nonzero) set *NP to zero. If NP is
+ zero, then the node found must not be locked, even transitorily.
+ Lookups for REMOVE and RENAME (which must often check permissions
+ on the node being found) will always set NP.
+
+ If DS is nonzero then:
+ For LOOKUP: set *DS to be ignored by diskfs_drop_dirstat.
+ For CREATE: on success, set *DS to be ignored by diskfs_drop_dirstat.
+ on failure, set *DS for a future call to diskfs_direnter.
+ For RENAME: on success, set *DS for a future call to diskfs_dirrewrite.
+ on failure, set *DS for a future call to diskfs_direnter.
+ For REMOVE: on success, set *DS for a future call to diskfs_dirremove.
+ on failure, set *DS to be ignored by diskfs_drop_dirstat.
+ The caller of this function guarantees that if DS is nonzero, then
+ either the appropriate call listed above or diskfs_drop_dirstat will
+ be called with DS before the directory DP is unlocked, and guarantees
+ that no lookup calls will be made on this directory between this
+ lookup and the use (or descruction) of *DS.
+
+ If you use the library's versions of diskfs_rename_dir,
+ diskfs_clear_directory, and diskfs_init_dir, then lookups for `..'
+ might have the flag SPEC_DOTDOT or'd in. This has the following special
+ meaning:
+ For LOOKUP: DP should be unlocked and its reference dropped before
+ returning.
+ For RENAME and REMOVE: The node being found (*NP) is already held
+ locked, so don't lock it or add a reference to it.
+ (SPEC_DOTDOT will not be given with CREATE.)
+
+ Return ENOTDIR if DP is not a directory.
+ Return EACCES if CRED isn't allowed to search DP.
+ Return EACCES if completing the operation will require writing
+ the directory and diskfs_checkdirmod won't allow the modification.
+ Return ENOENT if NAME isn't in the directory.
+ Return EAGAIN if NAME refers to the `..' of this filesystem's root.
+ Return EIO if appropriate.
+
+ This function is a wrapper for diskfs_lookup_hard.
+*/
+error_t diskfs_lookup (struct node *dp,
+ char *name, enum lookup_type type,
+ struct node **np, struct dirstat *ds,
+ struct protid *cred);
+
+/* Add NP to directory DP under the name NAME. This will only be
+ called after an unsuccessful call to diskfs_lookup of type CREATE
+ or RENAME; DP has been locked continuously since that call and DS
+ is as that call set it, NP is locked. CRED identifies the user
+ responsible for the call (to be used only to validate directory
+ growth). This function is a wrapper for diskfs_direnter_hard. */
+error_t
+diskfs_direnter (struct node *dp, const char *name, struct node *np,
+ struct dirstat *ds, struct protid *cred);
+
+/* This will only be called after a successful call to diskfs_lookup
+ of type RENAME; this call should change the name found in directory
+ DP to point to node NP instead of its previous referent, OLDNP. DP
+ has been locked continuously since the call to diskfs_lookup and DS
+ is as that call set it; NP is locked. This routine should call
+ diskfs_notice_dirchange if DP->dirmod_reqs is nonzero. NAME is the
+ name of OLDNP inside DP; it is this reference which is being
+ rewritten. This function is a wrapper for diskfs_dirrewrite_hard. */
+error_t diskfs_dirrewrite (struct node *dp, struct node *oldnp,
+ struct node *np, const char *name,
+ struct dirstat *ds);
+
+/* This will only be called after a successful call to diskfs_lookup
+ of type REMOVE; this call should remove the name found from the
+ directory DS. DP has been locked continuously since the call to
+ diskfs_lookup and DS is as that call set it. This routine should
+ call diskfs_notice_dirchange if DP->dirmod_reqs is nonzero. This
+ function is a wrapper for diskfs_dirremove_hard. The entry being
+ removed has name NAME and refers to NP. */
+error_t diskfs_dirremove (struct node *dp, struct node *np,
+ const char *name, struct dirstat *ds);
+
+/* Return the node corresponding to CACHE_ID in *NPP. */
+error_t diskfs_cached_lookup (int cache_id, struct node **npp);
+
+/* Create a new node. Give it MODE; if that includes IFDIR, also
+ initialize `.' and `..' in the new directory. Return the node in NPP.
+ CRED identifies the user responsible for the call. If NAME is nonzero,
+ then link the new node into DIR with name NAME; DS is the result of a
+ prior diskfs_lookup for creation (and DIR has been held locked since).
+ DIR must always be provided as at least a hint for disk allocation
+ strategies. */
+error_t
+diskfs_create_node (struct node *dir, const char *name, mode_t mode,
+ struct node **newnode, struct protid *cred,
+ struct dirstat *ds);
+
+/* Create and return a protid for an existing peropen PO in CRED,
+ referring to user USER. The node PO->np must be locked. */
+error_t diskfs_create_protid (struct peropen *po, struct iouser *user,
+ struct protid **cred);
+
+/* Build and return in CRED a protid which has no user identification, for
+ peropen PO. The node PO->np must be locked. */
+error_t diskfs_start_protid (struct peropen *po, struct protid **cred);
+
+/* Finish building protid CRED started with diskfs_start_protid;
+ the user to install is USER. */
+void diskfs_finish_protid (struct protid *cred, struct iouser *user);
+
+/* Create and return a new peropen structure on node NP with open
+ flags FLAGS. The initial values for the root_parent, shadow_root, and
+ shadow_root_parent fields are copied from CONTEXT if it's non-zero,
+ otherwise zerod. */
+struct peropen *diskfs_make_peropen (struct node *np, int flags,
+ struct peropen *context);
+
+/* Called when a protid CRED has no more references. (Because references\
+ to protids are maintained by the port management library, this is
+ installed in the clean routines list.) The ports library will
+ free the structure for us. */
+void diskfs_protid_rele (void *arg);
+
+/* Decrement the reference count on a peropen structure. */
+void diskfs_release_peropen (struct peropen *po);
+
+/* Node NP has just been found in DIR with NAME. If NP is null, that
+ means that this name has been confirmed as absent in the directory. */
+void diskfs_enter_lookup_cache (struct node *dir, struct node *np,
+ const char *name);
+
+/* Purge all references in the cache to NP as a node inside
+ directory DP. */
+void diskfs_purge_lookup_cache (struct node *dp, struct node *np);
+
+/* Scan the cache looking for NAME inside DIR. If we don't know
+ anything entry at all, then return 0. If the entry is confirmed to
+ not exist, then return -1. Otherwise, return NP for the entry, with
+ a newly allocated reference. */
+struct node *diskfs_check_lookup_cache (struct node *dir, const char *name);
+
+/* Rename directory node FNP (whose parent is FDP, and which has name
+ FROMNAME in that directory) to have name TONAME inside directory
+ TDP. None of these nodes are locked, and none should be locked
+ upon return. This routine is serialized, so it doesn't have to be
+ reentrant. Directories will never be renamed except by this
+ routine. FROMCRED and TOCRED are the users responsible for
+ FDP/FNP and TDP respectively. This routine assumes the usual
+ convention where `.' and `..' are represented by ordinary links;
+ if that is not true for your format, you have to redefine this
+ function.*/
+error_t
+diskfs_rename_dir (struct node *fdp, struct node *fnp, const char *fromname,
+ struct node *tdp, const char *toname,
+ struct protid *fromcred, struct protid *tocred);
+
+/* Clear the `.' and `..' entries from directory DP. Its parent is
+ PDP, and the user responsible for this is identified by CRED. Both
+ directories must be locked. This routine assumes the usual
+ convention where `.' and `..' are represented by ordinary links; if
+ that is not true for your format, you have to redefine this
+ function. */
+error_t diskfs_clear_directory (struct node *dp, struct node *pdp,
+ struct protid *cred);
+
+/* Locked node DP is a new directory; add whatever links are necessary
+ to give it structure; its parent is the (locked) node PDP.
+ This routine may not call diskfs_lookup on PDP. The new directory
+ must be clear within the meaning of diskfs_dirempty. This routine
+ assumes the usual convention where `.' and `..' are represented by
+ ordinary links; if that is not true for your format, you have to
+ redefine this function. CRED identifies the user making the call. */
+error_t
+diskfs_init_dir (struct node *dp, struct node *pdp, struct protid *cred);
+
+/* If NP->dn_set_ctime is set, then modify NP->dn_stat.st_ctime
+ appropriately; do the analogous operation for atime and mtime as well. */
+void diskfs_set_node_times (struct node *np);
+
+/* Shutdown the filesystem; flags are as for fsys_shutdown. */
+error_t diskfs_shutdown (int flags);
+
+/* Change an active filesystem between read-only and writable modes, setting
+ the global variable DISKFS_READONLY to reflect the current mode. If an
+ error is returned, nothing will have changed. DISKFS_FSYS_LOCK should be
+ held while calling this routine. */
+error_t diskfs_set_readonly (int readonly);
+
+/* Re-read all incore data structures from disk. This will only work if
+ DISKFS_READONLY is true. DISKFS_FSYS_LOCK should be held while calling
+ this routine. */
+error_t diskfs_remount ();
+
+/* Called by S_fsys_startup for execserver bootstrap. The execserver
+ is able to function without a real node, hence this fraud. Arguments
+ are all as for fsys_startup in <hurd/fsys.defs>. */
+error_t diskfs_execboot_fsys_startup (mach_port_t port, int flags,
+ mach_port_t ctl, mach_port_t *real,
+ mach_msg_type_name_t *realpoly);
+
+/* Establish a thread to sync the filesystem every INTERVAL seconds, or
+ never, if INTERVAL is zero. If an error occurs creating the thread, it is
+ returned, otherwise 0. Subsequent calls will create a new thread and
+ (eventually) get rid of the old one; the old thread won't do any more
+ syncs, regardless. */
+error_t diskfs_set_sync_interval (int interval);
+
+/* Parse and execute the runtime options in ARGZ & ARGZ_LEN. EINVAL is
+ returned if some option is unrecognized. The default definition of this
+ routine will parse them using DISKFS_RUNTIME_ARGP, which see. */
+error_t diskfs_set_options (const char *argz, size_t argz_len);
+
+/* Append to the malloced string *ARGZ of length *ARGZ_LEN a NUL-separated
+ list of the arguments to this translator. The default definition of this
+ routine simply calls diskfs_append_std_options. */
+error_t diskfs_append_args (char **argz, unsigned *argz_len);
+
+/* If this is defined or set to an argp structure, it will be used by the
+ default diskfs_set_options to handle runtime option parsing. The default
+ definition is initialized to a pointer to DISKFS_STD_RUNTIME_ARGP. */
+extern struct argp *diskfs_runtime_argp;
+
+/* An argp for the standard diskfs runtime options. The default definition
+ of DISKFS_RUNTIME_ARGP points to this, although if the user redefines
+ that, he may chain this onto his argp as well. */
+extern const struct argp diskfs_std_runtime_argp;
+
+/* An argp structure for the standard diskfs command line arguments. The
+ user may call argp_parse on this to parse the command line, chain it onto
+ the end of his own argp structure, or ignore it completely. */
+extern const struct argp diskfs_startup_argp;
+
+/* An argp structure for the standard diskfs command line arguments plus a
+ store specification. The address of a location in which to return the
+ resulting struct store_parsed structure should be passed as the input
+ argument to argp_parse; see the declaration for STORE_ARGP in
+ <hurd/store.h> for more information. */
+extern const struct argp diskfs_store_startup_argp;
+
+/* *Appends* to ARGZ & ARGZ_LEN '\0'-separated options describing the standard
+ diskfs option state (note that unlike diskfs_get_options, ARGZ & ARGZ_LEN
+ must already have a sane value). */
+error_t diskfs_append_std_options (char **argz, unsigned *argz_len);
+
+/* Demultiplex incoming messages on ports created by libdiskfs. */
+int diskfs_demuxer (mach_msg_header_t *, mach_msg_header_t *);
+
+/* Check if the filesystem is readonly before an operation that
+ writes it. Return 1 if readonly, zero otherwise. */
+int diskfs_check_readonly (void);
+
+/* The diskfs library provides functions to demultiplex the fs, io,
+ fsys, interrupt, and notify interfaces. All the server routines
+ have the prefix `diskfs_S_'; `in' arguments of type file_t or io_t
+ appear as `struct protid *' to the stub. */
+
+
+/* All-in-one initialization function for diskfs filesystems using
+ libstore. This parses arguments using STARTUP_ARGP (defaulting to
+ diskfs_store_startup_argp if it's null; note that the ARGP_IN_ORDER
+ flag is always used); it calls diskfs_init_diskfs; it opens the
+ store with store_parsed_open, and sets diskfs_hard_readonly and
+ diskfs_readonly if the store is unwritable; it calls
+ diskfs_spawn_first_thread; finally, it returns the store and its
+ description in *STORE and *STORE_PARSED, and the bootstrap port in
+ *BOOTSTRAP. The caller should pass *BOOTSTRAP to
+ diskfs_startup_diskfs after setting diskfs_root_node.
+ (See <argp.h> and <hurd/store.h>.)
+
+ This call cannot return failure; if it encounters a fatal problem,
+ it prints a diagnostic on stderr (or the console) and exits the
+ program. */
+struct store *diskfs_init_main (struct argp *startup_argp,
+ int argc, char **argv,
+ struct store_parsed **store_parsed,
+ mach_port_t *bootstrap);
+
+/* The following are optional convenience routines and global variable, which
+ can be used by any user program that uses a mach device to hold the
+ underlying filesystem. */
+
+/* Make errors go somewhere reasonable. */
+void diskfs_console_stdio ();
+
+#endif /* hurd/diskfs.h */