[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5. Files

A file is traditionally thought of as a quantity of disk storage. In the Hurd, files are an extension of the I/O interface, but they do not necessarily correspond to disk storage.

Every file in the Hurd is represented by a port, which is connected to the server that manages the file. When a client wants to operate on a file, it makes RPC requests via a file port to its server process, which is commonly called a translator.

5.1 Translators  Extending the Hurd filesystem hierarchy.
5.2 Trivfs Library  Implementing single-file translators.
5.3 Fshelp Library  Miscellaneous generic filesystem routines.
5.4 File Interface  File ports implement the file interface.
5.5 Filesystem Interface  Translator control interface.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.1 Translators

The Hurd filesystem allows you to set translators on any file or directory that you own. A translator is any Hurd server which provides the basic filesystem interface. Translated nodes are somewhat like a cross between Unix symbolic links and mount points.

Whenever a program tries to access the contents of a translated node, the filesystem server redirects the request to the appropriate translator (starting it if necessary). Then, the new translator services the client's request. The GNU C library makes this behaviour seamless from the client's perspective, so that standard Unix programs behave correctly under the Hurd.

Translators run with the privileges of the translated node's owner, so they cannot be used to compromise the security of the system. This also means that any user can write their own translators, and provide other users with arbitrary filesystem-structured data, regardless of the data's actual source. Other chapters in this manual describe existing translators, and how you can modify them or write your own.

The standard Hurd filesystem servers are constantly evolving to provide innovative features that users want. Here are a few examples of existing translators:

This section focuses on the generic programs that you need to understand in order to use existing translators. Many other parts of this manual describe how you can write your own translators.

5.1.1 Invoking settrans  Declaring how a node should be translated.
5.1.2 Invoking showtrans  Displaying how nodes are translated.
5.1.3 Invoking mount  Unix-compatible active filesystem translators.
5.1.4 Invoking fsysopts  Modifying translation parameters at runtime.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.1.1 Invoking settrans

The settrans program allows you to set a translator on a file or directory. By default, the passive translator is set (see the `--passive' option).

The settrans program has the following synopsis:

 
settrans [option]... node [translator arg...]

where translator is the absolute filename of the new translator program. Each arg is passed to translator when it starts. If translator is not specified, then settrans clears the existing translator rather than setting a new one.

settrans accepts the following options:

`-a'
`--active'
Set node's active translator. Active translators are started immediately and are not persistent: if the system is rebooted then they are lost.

`-c'
`--create'
Create node as a zero-length file if it doesn't already exist.

`-L'
`--dereference'
If node is already translated, stack the new translator on top of it (rather than replacing the existing translator).

`--help'
Display a brief usage message, then exit.

`-p'
`--passive'
Set node's passive translator. Passive translators are only activated by the underlying filesystem when clients try to use the node, and they shut down automatically after they are no longer active in order to conserve system resources.

Passive translators are stored on the underlying filesystem media, and so they persist between system reboots. Not all filesystems support passive translators, due to limitations in their underlying media. Consult the filesystem-specific documentation to see if they are supported.

If you are setting the passive translator, and node already has an active translator, then the following options apply:

`-g'
`--goaway'
Tell the active translator to go away. In this case, the following additional options apply:

`-f'
`--force'
If the active translator doesn't go away, then force it.

`-S'
`--nosync'
Don't flush its contents to disk before terminating.

`-R'
`--recursive'
Shut down all of the active translator's children, too.

`-k'
`--keep-active'
Leave the existing active translator running. The new translator will not be started unless the active translator has stopped.

`-P'
`--pause'
When starting an active translator, prompt and wait for a newline on standard input before completing the startup handshake. This is useful when debugging a translator, as it gives you time to start the debugger.

`-t sec'
`--timeout=sec'
If the translator does not start up in sec seconds (the default is 60), then return an error; if sec is 0, then never timeout.

`--version'
Output program version information and exit.

`-x'
`--exclusive'
Only set the translator if there is none already.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.1.2 Invoking showtrans

The showtrans program allows you to show the passive translator setting on a file system node.

The showtrans program has the following synopsis:

 
showtrans [option]... file...

showtrans accepts the following options:

-p
--prefix
Always display filename: before translators.

-P
--no-prefix
Never display filename: before translators.
-s
--silent
No output; useful when checking error status.
-t
--translated
Only display files that have translators.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.1.3 Invoking mount


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.1.4 Invoking fsysopts

The fsysopts program allows you to retrieve or set command line options for running translator filesys.

The fsysopts program has the following synopsis:

 
fsysopts [option...] filesys [fs_option...]

fsysopts accepts the following options:

-L
--dereference
If filesys is a symbolic link, follow it.

-R
--recursive
Pass these options to any child translators.

The legal values for fs_option depends on filesys, but some common ones are:

--readonly
--writable
--remount
--sync[=interval]
--nosync

If no options are supplied, filesys' current options are printed.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2 Trivfs Library

Certain translators do not need to be very complex, because they represent a single file rather than an entire directory hierarchy. The trivfs library, which is declared in <hurd/trivfs.h>, does most of the work of implementing this kind of translator. This library requires the iohelp and ports libraries.

5.2.1 Trivfs Startup  Writing a simple trivfs-based translator.
5.2.2 Trivfs Callbacks  Mandatory user-defined trivfs functions.
5.2.3 Trivfs Options  Optional user-defined trivfs functions.
5.2.4 Trivfs Ports  Managing control and protid ports.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.1 Trivfs Startup

In order to use the trivfs library, you will need to define the appropriate callbacks (see section 5.2.2 Trivfs Callbacks). As with all Hurd servers, your trivfs-based translator should first parse any command-line options, in case the user is just asking for help. Trivfs uses argp (see section `Argp' in The GNU C Library Reference Manual) for parsing command-line arguments.

Your translator should redefine the following functions and variables as necessary, and then call argp_parse with the relevant arguments:

Variable: extern struct argp * trivfs_runtime_argp
If this is defined or set to an argp structure, it will be used by the default trivfs_set_options to handle runtime options parsing. Redefining this is the normal way to add option parsing to a trivfs program.

Function: error_t trivfs_set_options (struct trivfs_control *fsys, char *argz, size_t argz_len)
Set runtime options for fsys to argz and argz_len. The default definition for this routine simply uses trivfs_runtime_argp (supplying fsys as the argp input field).

Function: error_t trivfs_append_args (struct trivfs_control *fsys, 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.

After your translator parses its command-line arguments, it should fetch its bootstrap port by using task_get_bootstrap_port. If this port is MACH_PORT_NULL, then your program wasn't started as a translator. Otherwise, you can use the bootstrap port to create a new control structure (and advertise its port) with trivfs_startup:

Function: error_t trivfs_startup (mach_port_t bootstrap, int flags, struct port_class *control_class, struct port_bucket *control_bucket, struct port_class *protid_class, struct port_bucket *protid_bucket, struct trivfs_control **control)
Function: error_t trivfs_create_control (mach_port_t bootstrap, struct port_class *control_class, struct port_bucket *control_bucket, struct port_class *protid_class, struct port_bucket *protid_bucket, struct trivfs_control **control)
trivfs_startup creates a new trivfs control port, advertises it to the underlying node bootstrap with fsys_startup, returning the results of this call, and places its control structure in *control. trivfs_create_control does the same thing, except it doesn't advertise the control port to the underlying node. control_class and control_bucket are passed to libports to create the control port, and protid_class and protid_bucket are used when creating ports representing opens of this node; any of these may be zero, in which case an appropriate port class/bucket is created. If control is non-null, the trivfs control port is returned in it. flags (a bitmask of the appropriate O_* constants) specifies how to open the underlying node.

If you did not supply zeros as the class and bucket arguments to trivfs_startup, you will probably need to use the trivfs port management functions (see section 5.2.4 Trivfs Ports).

Once you have successfully called trivfs_startup, and have a pointer to the control structure stored in, say, the fsys variable, you are ready to call one of the ports_manage_port_operations_* functions using fsys->pi.bucket and trivfs_demuxer. This will handle any incoming filesystem requests, invoking your callbacks when necessary.

Function: int trivfs_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
Demultiplex incoming libports messages on trivfs ports.

The following functions are not usually necessary, but they allow you to use the trivfs library even when it is not possible to turn message-handling over to trivfs_demuxer and libports:

Function: struct trivfs_control * trivfs_begin_using_control (mach_port_t port)
Function: struct trivfs_protid * trivfs_begin_using_protid (mach_port_t port)
These functions can be used as intran functions for a MiG port type to have the stubs called with either the control or protid pointer.

Function: void trivfs_end_using_control (struct trivfs_control *port)
Function: void trivfs_end_using_protid (struct trivfs_protid *port)
These can be used as `destructor' functions for a MiG port type, to have the stubs called with the control or protid pointer.

Function: error_t trivfs_open (struct trivfs_control *fsys, struct iouser *user, unsigned flags, mach_port_t realnode, struct trivfs_protid **cred)
Return a new protid (that is, a port representing an open of this node) pointing to a new peropen in cred, with realnode as the underlying node reference, with the given identity, and open flags in flags. cntl is the trivfs control object.

Function: error_t trivfs_protid_dup (struct trivfs_protid *cred, struct trivfs_protid **dup)
Return a duplicate of cred in dup, sharing the same peropen and hook. A non-null protid hook indicates that trivfs_peropen_create_hook created this protid (see section 5.2.3 Trivfs Options).

Function: error_t trivfs_set_atime (struct trivfs_control *cntl)
Function: error_t trivfs_set_mtime (struct trivfs_control *cntl)
Call these to set atime or mtime for the node to the current time.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.2 Trivfs Callbacks

Like several other Hurd libraries, libtrivfs requires that you define a number of application-specific callback functions and configuration variables. You must define the following variables and functions:

Variable: extern int trivfs_fstype
Variable: extern int trivfs_fsid
These variables are returned in the st_fstype and st_fsid fields of struct stat. trivfs_fstype should be chosen from the FSTYPE_* constants found in <hurd/hurd_types.h>.

Variable: extern int trivfs_allow_open
Set this to some bitwise OR combination of O_READ, O_WRITE, and O_EXEC; trivfs will only allow opens of the specified modes.

Variable: extern int trivfs_support_read
Variable: extern int trivfs_support_write
Variable: extern int trivfs_support_exec
Set these to nonzero if trivfs should allow read, write, or execute of the file. These variables are necessary because trivfs_allow_open is used only to validate opens, not actual operations.

Function: void trivfs_modify_stat (struct trivfs_protid *cred, struct stat *stbuf)
This should modify a struct stat (as returned from the underlying node) for presentation to callers of io_stat. It is permissible for this function to do nothing, but it must still be defined.

Function: error_t trivfs_goaway (struct trivfs_control *cntl, int flags)
This function is called when someone wants the filesystem cntl to go away. flags are from the set FSYS_GOAWAY_* found in <hurd/hurd_types.h>.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.3 Trivfs Options

The functions and variables described in this subsection already have default definitions in libtrivfs, so you are not forced to define them; rather, they may be redefined on a case-by-case basis.

Variable: extern struct port_class * trivfs_protid_portclasses []
Variable: extern int trivfs_protid_nportclasses
Variable: extern struct port_class * trivfs_cntl_portclasses []
Variable: extern int trivfs_cntl_nportclasses
If you define these, they should be vectors (and the associated sizes) of port classes that will be translated into control and protid pointers for passing to RPCs, in addition to those passed to or created by trivfs_create_control (or trivfs_startup), which will automatically be recognized.

Variable: error_t (*trivfs_check_open_hook) (struct trivfs_control *cntl, struct iouser *user, int flags)
If this variable is non-zero, it will be called every time an open happens. user and flags are from the open; cntl identifies the node being opened. This call need not check permissions on the underlying node. This call can block as necessary, unless O_NONBLOCK is set in flags. Any desired error can be returned, which will be reflected to the user and will prevent the open from succeeding.

Variable: error_t (*trivfs_protid_create_hook) (struct trivfs_protid *prot)
Variable: error_t (*trivfs_peropen_create_hook) (struct trivfs_peropen *perop)
If these variables are non-zero, they will be called every time a new protid or peropen structure is created and initialized.

Variable: void (*trivfs_protid_destroy_hook) (struct trivfs_protid *prot)
Variable: void (*trivfs_peropen_destroy_hook) (struct trivfs_peropen *perop)
If these variables is non-zero, they will be called every time a protid or peropen structure is about to be destroyed.

Variable: error_t (*trivfs_getroot_hook) (struct trivfs_control *cntl, mach_port_t reply_port, mach_msg_type_name_t reply_port_type, mach_port_t dotdot, uid_t *uids, u_int nuids, uid_t *gids, u_int ngids, int flags, retry_type *do_retry, char *retry_name, mach_port_t *node, mach_msg_type_name_t *node_type)
If this variable is set, it will be called by trivfs_S_fsys_getroot before any other processing takes place. If the return value is EAGAIN, normal trivfs getroot processing continues, otherwise the RPC returns with that return value.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.2.4 Trivfs Ports

If you choose to allocate your own trivfs port classes and buckets, the following functions may come in handy:

Function: error_t trivfs_add_port_bucket (struct port_bucket **bucket)
Add the port bucket *bucket to the list of dynamically- allocated port buckets; if *bucket is zero, an attempt is made to allocate a new port bucket, which is then stored in *bucket.

Function: void trivfs_remove_port_bucket (struct port_bucket *bucket)
Remove the previously added dynamic port bucket bucket, freeing it if it was allocated by trivfs_add_port_bucket.

Function: error_t trivfs_add_control_port_class (struct port_class **class)
Function: error_t trivfs_add_protid_port_class (struct port_class **class)
Add the port class *class to the list of control or protid port classes recognized by trivfs; if *class is zero, an attempt is made to allocate a new port class, which is stored in *class.

Function: void trivfs_remove_control_port_class (struct port_class *class)
Function: void trivfs_remove_protid_port_class (struct port_class *class)
Remove the previously added dynamic control or protid port class class, freeing it if it was allocated by trivfs_add_control_port_class or trivfs_add_protid_port_class.

Even if you do not use the above allocation functions, you may still be able to use the default trivfs cleanroutines:

Function: void trivfs_clean_cntl (void *port)
Function: void trivfs_clean_protid (void *port)
These functions should be installed as libports cleanroutines for control port classes and protid port classes, respectively.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.3 Fshelp Library

The fshelp library implements various things that are useful to most implementors of the file protocol. It presumes that you are using the iohelp library as well. libfshelp is divided into separate facilities which may be used independently. These functions are declared in <hurd/fshelp.h>.

5.3.1 Passive Translator Linkage  Invoking passive translators.
5.3.2 Active Translator Linkage  Managing active translators.
5.3.3 Fshelp Locking  Implementing file locking.
5.3.4 Fshelp Permissions  Standard file access permission policies.
5.3.5 Fshelp Misc  Useful standalone routines.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.3.1 Passive Translator Linkage

These routines are self-contained and start passive translators, returning the control port. They do not require multithreading or the ports library.

Typedef: typedef error_t (*fshelp_open_fn_t) (int flags, file_t *node, mach_msg_type_name_t *node_type)
A callback used by the translator starting functions. Given some open flags, opens the appropriate file, and returns the node port.

Function: error_t fshelp_start_translator_long (fshelp_open_fn_t underlying_open_fn, char *name, char *argz, int argz_len, mach_port_t *fds, mach_msg_type_name_t fds_type, int fds_len, mach_port_t *ports, mach_msg_type_name_t ports_type, int ports_len, int *ints, int ints_len, int timeout, fsys_t *control)
Start a passive translator name with arguments argz (length argz_len). Initialize the initports to ports (length ports_len), the initints to ints (length ints_len), and the file descriptor table to fds (length fds_len). Return the control port in *control. If the translator doesn't respond or die in timeout milliseconds (if timeout is greater than zero), return an appropriate error. If the translator dies before responding, return EDIED.

Function: error_t fshelp_start_translator (fshelp_open_fn_t underlying_open_fn, char *name, char *argz, int argz_len, int timeout, fsys_t *control)
Same as fshelp_start_translator_long, except the initports and ints are copied from our own state, fd[2] is copied from our own stderr, and the other fds are cleared. For full-service filesystems, it is almost always wrong to use fshelp_start_translator, because the current working directory of the translator will not then be as normally expected. (Current working directories of passive translators should be the directory they were found in.) In fact, full-service filesystems should usually start passive translators as a side-effect of calling fshelp_fetch_root (see section 5.3.2 Active Translator Linkage).


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.3.2 Active Translator Linkage

These routines implement the linkage to active translators needed by any filesystem which supports them. They require the threads library and use the passive translator routines above, but they don't require the ports library at all.

This interface is complex, because creating the ports and state necessary for start_translator_long is expensive. The caller to fshelp_fetch_root should not need to create them on every call, since usually there will be an existing active translator.

Function: void fshelp_transbox_init (struct transbox *transbox, struct mutex *lock, void *cookie)
Initialize a transbox, which contains state information for active translators.

Typedef: typedef error_t (*fshelp_fetch_root_callback1_t) (void *cookie1, void *cookie2, uid_t *uid, gid_t *gid, char **argz, size_t *argz_len)
This routine is called by fshelp_fetch_root to fetch more information. Return the owner and group of the underlying translated file in *uid and *gid; point *argz at the entire passive translator specification for the file (setting *argz_len to the length). If there is no passive translator, then return ENOENT. cookie1 is the cookie passed in fshelp_transbox_init. cookie2 is the cookie passed in the call to fshelp_fetch_root.

Typedef: typedef error_t (*fshelp_fetch_root_callback2_t) (void *cookie1, void *cookie2, int flags, mach_port_t *underlying, mach_msg_type_name_t *underlying_type)
This routine is called by fshelp_fetch_root to fetch more information. Return an unauthenticated node for the file itself in *underlying and *underlying_type (opened with flags). cookie1 is the cookie passed in fshelp_transbox_init. cookie2 is the cookie passed in the call to fshelp_fetch_root.

Function: error_t fshelp_fetch_root (struct transbox *transbox, void *cookie, file_t dotdot, struct iouser *user, int flags, fshelp_fetch_root_callback1_t callback1, fshelp_fetch_root_callback2_t callback2, retry_type *retry, char *retryname, mach_port_t *root)
Fetch the root from transbox. dotdot is an unauthenticated port for the directory in which we are looking; user specifies the ids of the user responsible for the call. flags are as for dir_lookup (but O_CREAT and O_EXCL are not meaningful and are ignored). The transbox lock (as set by fshelp_transbox_init) must be held before the call, and will be held upon return, but may be released during the operation of the call.

Function: int fshelp_translated (struct transbox *box)
Return true if and only if there is an active translator on this box.

Function: error_t fshelp_set_active (struct transbox *box, fsys_t newactive, int excl)
Atomically replace the existing active translator port for this box with newactive. If excl is non-zero then don't modify an existing active transbox; return EBUSY instead.

Function: error_t fshelp_fetch_control (struct transbox *box, mach_port_t *control)
Fetch the control port to make a request on it. It's a bad idea to use fsys_getroot with the result; use fshelp_fetch_root instead.

Function: void fshelp_drop_transbox (struct transbox *box)
Clean transbox state so that deallocation or reuse is possible.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.3.3 Fshelp Locking

The flock call is in flux, as the current Hurd interface (as of version 0.2) is not suitable for implementing the POSIX record-locking semantics.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.3.4 Fshelp Permissions

These functions are designed to aid with user permission checking. It is a good idea to use these routines rather than to roll your own, so that Hurd users see consistent handling of file and directory permission bits.

Function: error_t fshelp_isowner (struct stat *st, struct iouser *user)
Check to see whether user should be considered the owner of the file identified by st. If so, return zero; otherwise return an appropriate error code.

Function: error_t fshelp_access (struct stat *st, int op, struct iouser *user)
Check to see whether the user user can operate on the file identified by st. op is one of S_IREAD, S_IWRITE, and S_IEXEC. If the access is permitted, return zero; otherwise return an appropriate error code.

Function: error_t fshelp_checkdirmod (struct stat *dir, struct stat *st, struct iouser *user)
Check to see whether user is allowed to modify dir with respect to existing file st. If there is no existing file, then st should be set to zero. If the access is permissible, return zero; otherwise return an appropriate error code.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.3.5 Fshelp Misc

The following functions are completely standalone:

Function: error_t fshelp_delegate_translation (char *server_name, mach_port_t requestor, char **argv)
Try to hand off responsibility from a translator to the server located on the node server_name. requestor is the translator's bootstrap port, and argv is the command line. If server_name is null, then a name is concocted by prepending _servers to argv[0] .

Function: error_t fshelp_exec_reauth (int suid, uid_t uid, int sgid, gid_t gid, auth_t auth, error_t (*get_file_ids) (struct idvec *uids, struct idvec *gids), mach_port_t *ports, mach_msg_type_number_t num_ports, mach_port_t *fds, mach_msg_type_number_t num_fds, int *secure)
If suid or sgid is true, adds uid and/or gid respectively to the authentication in ports[INIT_PORT_AUTH], and replaces it with the result. All the other ports in ports and fds are then reauthenticated, using any privileges available through auth. If the auth port in ports[INIT_PORT_AUTH] is bogus, and get_file_ids is non-null, it is called to get a list of uids and gids from the file to use as a replacement. If secure is non-null and any added ids are new, then the variable it points to is set to nonzero, otherwise zero. If either the uid or gid case fails, then the other may still apply.

Function: error_t fshelp_get_identity (struct port_bucket *bucket, ino_t fileno, mach_port_t *pt)
Return an identity port in *pt for the node numbered fileno, suitable for returning from io_identity; exactly one send right must be created from the returned value. fileno should be the same value returned as the fileno out-parameter in io_identity, and in the enclosing directory (except for mount points), and in the st_ino stat field. bucket should be a libports port bucket; fshelp requires the caller to make sure port operations (for no-senders notifications) are used.

Function: error_t fshelp_return_malloced_buffer (char *buf, size_t len, char **rbuf, mach_msg_type_number_t *rlen)
Put data from the malloced buffer buf, len bytes long, into rbuf (which is rlen bytes long), suitable for returning from an RPC. If len is greater than zero, buf is freed, regardless of whether an error is returned or not.

Function: error_t fshelp_set_options (struct argp *argp, int flags, char *argz, size_t argz_len, void *input)
Invoke argp_parse in the standard way, with data from argz and argz_len.

Function: void fshelp_touch (struct stat *st, unsigned what, volatile struct mapped_time_value *maptime)
Change the stat times of node as indicated by what to the current time. what is a bitmask of one or more of the TOUCH_ATIME, TOUCH_MTIME, and TOUCH_CTIME constants.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.4 File Interface

This section documents the interface for operating on files.

5.4.1 File Overview  Basic concepts for the file interface.
5.4.2 Changing Status  Changing the owner (etc.) of a file.
5.4.3 Program Execution  Executing files.
5.4.4 File Locking  Implementing the flock call.
5.4.5 File Frobbing  Other active calls on files.
5.4.6 Opening Files  Looking up files in directories.
5.4.7 Modifying Directories  Creating and deleting nodes.
5.4.8 Notifications  File and directory change callbacks.
5.4.9 File Translators  How to set and get translators.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.4.1 File Overview

The file interface is a superset of the I/O interface (see section 4.3 I/O Interface). Servers which provide the file interface are required to support the I/O interface as well. All objects reachable in the filesystem are expected to provide the file interface, even if they do not contain data. (The trivfs library makes it easy to do so for ordinary sorts of cases. See section 5.2 Trivfs Library.)

The interface definitions for the file interface are found in <hurd/fs.defs>.

Files have various pieces of status information which are returned by io_stat (see section 4.3.5 Information Queries). Most of this status information can be directly changed by various calls in the file interface; some of it should vary implicitly as the contents of the file change.

Many of these calls have general rules associated with them describing how security and privilege should operate. The diskfs library (see section 8.5 Diskfs Library) implements these rules for stored filesystems. These rules have also been implemented in the fshelp library (see section 5.3 Fshelp Library). Trivfs-based servers generally have no need to implement these rules at all.

In special cases, there may be a reason to implement a different security check from that specified here, or to implement a call to do something slightly different. But such cases must be carefully considered; make sure that you will not confuse innocent user programs through excessive cleverness.

If some operation cannot be implemented (for example, chauthor over FTP), then the call should return EOPNOTSUPP. If it is merely difficult to implement a call, it is much better to figure out a way to implement it as a series of operations rather than to return errors to the user.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.4.2 Changing Status

There are several RPCs available for users to change much of the status information associated with a file. (The information is returned by the io_stat RPC; see 4.3.5 Information Queries.)

All these operations are restricted to root and the owner of the file. When attempted by another user, they should return EPERM.

The file_chown RPC changes the owner and group of the file. Only root should be able to change the owner, and changing the group to a group the caller is not in should also be prohibited. Violating either of these conditions should return EPERM.

The file_chauthor RPC changes the author of the file. It should be legitimate to change the author to any value without restriction.

The file_chmod RPC changes the file permission mode bits.

The file_chflags RPC changes the flags of the file. It should be legitimate to change the flags to any value without restriction. No standard meanings have been assigned to the flags yet, but we intend to do so. Do not assume that the flags format we choose will map identically to that of some existing filesystem format.

The file_utimes RPC changes the atime and mtime of the file. Making this call must cause the ctime to be updated as well, even if no actual change to either the mtime or the atime occurs.

The file_set_size RPC is special; not only does it change the status word specifying the size of the file, but it also changes the actual contents of the file. If the file size is being reduced it should release secondary storage associated with the previous contents of the file. If the file is being extended, the new region added to the file must be zero-filled. Unlike the other RPCs in this section, file_set_size should be permitted to any user who is allowed to write the file.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.4.3 Program Execution

Execution of programs on the Hurd is done through fileservers with the file_exec RPC. The fileserver is expected to verify that the user is allowed to execute the file, make whatever modifications to the ports are necessary for setuid execution, and then invoke the standard execserver found on `/servers/exec'.

This section specifically addresses what fileservers are expected to do, with minimal attention to the other parts of the process. See section 13. Running Programs, for more general information.

The file must be opened for execution; if it is not, EBADF should be returned. In addition, at least one of the execute bits must be on. A failure of this check should result in EACCES---not ENOEXEC. It is not proper for the fileserver ever to respond to the file_exec RPC with ENOEXEC.

If either the setuid or setgid bits are set, the server needs to construct a new authentication handle with the additional new ID's. Then all the ports passed to file_exec need to be reauthenticated with the new handle. If the fileserver is unable to make the new authentication handle (for example, because it is not running as root) it is not acceptable to return an error; in such a case the server should simply silently fail to implement the setuid/setgid semantics.

If the setuid/setgid transformation adds a new uid or gid to the user's authentication handle that was not previously present (as opposed to merely reordering them), then the EXEC_SECURE and EXEC_NEWTASK flags should both be added in the call to exec_exec.

The server then needs to open a new port onto the executed file which will not share any file pointers with the port the user passed in, opened with O_READ. Finally, all the information (mutated appropriately for setuid/setgid) should be sent to the execserver with exec_exec. Whatever error code exec_exec returns should returned to the caller of file_exec.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.4.4 File Locking

The flock call is in flux, as the current Hurd interface (as of version 0.2) is not suitable for implementing the POSIX record-locking semantics.

You should ignore the file_lock and file_lock_stat calls until the new record-locking interface is implemented.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.4.5 File Frobbing

FIXME: Other active calls on files

file_sync

file_getfh

file_getlinknode

file_check_access

These manipulate meta-information:

file_reparent

file_statfs

file_syncfs

file_getcontrol

file_get_storage_info

file_get_fs_options


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.4.6 Opening Files

FIXME: Looking up files in directories

dir_lookup

dir_readdir


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.4.7 Modifying Directories

Function: kern_return_t dir_mkfile (file_t directory, int flags, mode_t mode, mach_port_t *newnode)
Create a new file in directory without linking it into the filesystem. You still must have write permission on the specified directory, even though it will not actually be written.

The function returns a port to the new file in *newnode. Flags are the same as for dir_lookup, but O_CREAT and O_TRUNC are assumed even if not specified.

Function: kern_return_t dir_mkdir (file_t directory, char *name, mode_t mode)
Create a new directory named name in directory with permission specified by mode.

Function: kern_return_t dir_rmdir (file_t directory, char *name)
Remove the directory named name from directory.

Function: kern_return_t dir_unlink (file_t directory, char *name)
Remove the non-directory node name from directory.

Function: kern_return_t dir_link (file_t directory, file_t file, char *name, int excl)
Create a hard link in directory. If excl is set and name already exists in directory, then this function will fail. If excl is not set and name already exists the old file named name will be unlinked. If directory and file are not on the same filesystem, then dir_link might fail with EXDEV.

Function: kern_return_t dir_rename (file_t olddirectory, char *oldname, file_t newdirectory, char *newname, int excl)
Move the node oldname in olddirectory to the node newname in newdirectory. If excl is set and newname already exists in newdirectory, then this function will fail. If excl is not set and newname already exists, the old file named newname will be unlinked. If olddirectory and newdirectory are not on the same filesystem, then dir_rename might fail with EXDEV.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.4.8 Notifications

FIXME: File and directory change callbacks

File change notifications are not yet implemented, but directory notifications are.

file_notice_changes

dir_notice_changes


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.4.9 File Translators

FIXME: How to set and get translators

file_set_translator

file_get_translator

file_get_translator_cntl


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

5.5 Filesystem Interface

The filesystem interface (described in <hurd/fsys.defs>) is supported by translator control ports.

FIXME: finish


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Alfred M. Szmidt on January, 22 2005 using texi2html