Previous section.
Protocols for Interworking: XNFS, Version 3W
Copyright © 1998 The Open Group
Semantic Difference Summary for File Access
Introduction
Many of the entries described in the X/Open System Interfaces and Headers Specification (see reference XSH) and the X/Open Commands and Utilities Specification (see reference XCU)
are directly or indirectly concerned with accessing files
stored on the system's file system.
When documenting those utilities and functions the assumption was made that
files being accessed would reside on the local file system of the
system, and that all local file system semantics would be supported.
Users or applications using an XCU utility or XSH function
could therefore rely on described behaviour
and error codes being returned as described in that XPG entry.
When XPG-compliant systems are linked together using XNFS protocols,
files on remote systems may be accessible to a process running on
a local system, without the process being aware that files are remote.
In fact, because XNFS provides transparent access to remote
files, it is not possible for a process to distinguish between
local and remote files before they are used.
Due to the nature
of the way XNFS works, there are some semantic differences between
operations on local files and equivalent operations on remote files.
This appendix gives a summary of these semantic differences.
Together with
Open-System Interface Semantics over XNFS
and
Open System Utilities Semantics over XNFS
this appendix specifies differences that can occur when using
a given utility or function with a file on a remote file system.
XNFS describes a number of new errors which may occur when CAE
applications issue XSH function calls which refer to XNFS file
systems.
One error, which occurs when a file handle is rejected as
invalid by the XNFS server, is represented by a new error code,
[ESTALE].
All other errors discussed in this specification are
represented by existing XSH error codes; thus the set of possible
interpretations for each of these codes is extended when XNFS is being used.
It should be noted that the X/Open Commands and Utilities Specification (see reference XCU) explicitly
allows implementors to define additional error codes, and does not
define which error should be reported when multiple errors occur during
a single operation.
Notwithstanding this, the XNFS specification
defines only one new error code, [ESTALE], and implementors of XNFS are
strongly discouraged from introducing additional error codes which are
specific to XNFS.
See also the description of NFSERR_STALE in
stat
.
There are not many areas in which semantic differences manifest themselves.
The following list summarises differences which are common to many system
interface functions or utilities.
Specific differences that are not
common to several functions or utilities are discussed in the
description of that function or utility in
Open-System Interface Semantics over XNFS
and
Open System Utilities Semantics over XNFS
respectively.
Special File Access
A process may create, rename, unlink, and get the
attributes of a special file that is located on a
remote file system. A process may also
fattach()
a STREAMS file descriptor to a remote file. If a
process opens a remote special file, a local device will
be used instead of the (possibly desired) remote
device. This includes the FIFO special file type, support
for which is not mandated in the XNFS specification.
If a process opens a remote special file, the local
device that is used will be the local device that
corresponds to the major and minor numbers associated
with the remote special file. If there is no local
device corresponding to this major and minor number
pair, the operation will fail. For example, if
pax
is used to extract files from a tape,
pax
must be run on the host that owns the tape drive.
A process may be unable to create a remote special
file, either because the server doesn't support
special files at all ([EOPNOTSUPP]), or because the server
doesn't support the requested special file type
([EINVAL]).
See also
Special Files
for semantic differences that can arise when accessing special
files with Version 2 of the NFS protocol.
UID Mapping by Server
Access to a file located on a remote file system can be denied,
even in the case that the file permissions do not
themselves restrict access.
When the server exports a file system,
the following attributes can be specified which control access to the
file system:
-
The server will treat requests from a client process with an unknown
user ID as having the user ID that is specified in the "AnonMapping="
ExportedFileSystem attribute.
(See the discussion of the "AnonMapping=" ExportedFileSystem
attribute in
ExportedFileSystem
.)
-
The server can deny access by privileged user from specified hosts.
Should the server receive a request for file access from a
process with an effective user ID of 0 on a denied host,
the request will be processed.
However, the value
specified in the "AnonMapping=" ExportedFileSystem attribute will be
used instead of the effective user ID of the process.
(See the discussion of the "AnonMapping=" and
"Root=" ExportedFileSystem attributes in
ExportedFileSystem
.)
If such a mapping occurs and thus causes the server to deny access to a file,
the error [EACCES] will be returned to the process.
In the case that the server denies access by a privileged user, the semantics
of those file access functions that require appropriate privileges may not be
available to the calling process, the error [EPERM] will be returned to the
process in these cases.
For access to regular files using Version 3 of the NFS
protocol, restrictions due to user ID mapping are
enforced at the time the file is opened, except
when a stale entry in the access cache causes the call to
succeed. (See
Attribute and Access Caching
for a discussion of the access cache.) With Version 2, the client need not
enforce the restrictions at the time the file is
opened. If the process is able to open the file,
the client will generally enforce the restrictions
when the process tries to read or write the file. Because
of data caching, though, the client need not enforce
the restrictions until it has tried to read from or
write to the server. (See
Delayed Write Errors
for a discussion of delayed write errors.)
Reads or writes may also fail if, for example, the
permissions on the file are changed after the file
was opened, as described in
File Accessibility Changed after Open
Operations that require directory updates, such as
mkdir(),
link(),
remove()
and
mknod(),
will reflect access restrictions immediately for both versions
of the NFS protocol.
Because of privilege restrictions, it may be difficult
to perform system administration tasks from an
XNFS client. For example,
cron
jobs may need to be run on the server, even if the relevant files are
exported by the server. Other tasks, such as restoring or
installing files using
pax,
may only be possible on the server as well.
Execution of Set-user-ID Programs
Execution semantics of a program
having the set-user-ID mode bit
are different over NFS (see exec in the X/Open System Interfaces and Headers Specification (see reference XSH)).
When an NFS file system is mounted by a client, the "SetUID="
mount attribute determines whether normal set-user-ID execution semantics
are in effect.
If the attribute is "False", execution of such a program over NFS will
still occur.
However, the effective user ID will not be reassigned to the
owner of the program, and will remain equal to the user ID of the process.
(See the discussion
of the "SetUID=" MountedFileSystem attribute in
MountedFileSystem
.)
During execution, such a program may be denied an operation
such as
open(),
read()
or
write(),
because it is not running with the
effective user ID with which it was designed to run.
In this case an [EACCES] or an [EPERM] error may be
generated depending upon the type of operation being performed.
Attribute and Access Caching
There are several semantic differences that occur due
to attribute and access caching on the client. These
differences occur when information in the client's
cache does not match the information that is on the
server. Since these caches are updated frequently,
there is only a small window of time in which this
information can differ. If the attribute and access
caches are disabled through the "AttribCaching="
MountedFileSystem
attribute, or if the client does not
implement these caches, these problems no longer exist.
(See the "AttribCaching=", "ACRegMin=" and
"ACRegMax="
MountedFileSystem
attributes in
MountedFileSystem
.)
Information in a client's attribute and access caches becomes inaccurate when
the attributes of a file on the server are changed.
When such changes are made from a client, that
client's attribute and access caches are
updated immediately in order to maintain a
consistent view of the server's file system.
However, when a process running on the server or on a client changes
the attributes of a file, these results may not be
immediately noticeable to other clients.
The attribute cache contains information about files on the server,
including:
-
The mode of a file
-
The user ID and group ID of a file
-
The number of bytes in a file
-
The access times associated with a file
The access cache contains the results of previous
NFSPROC3_ACCESS calls. On a per-file, per-user basis,
it records which access modes are known to succeed,
known to fail, or indeterminate.
Functions such as
stat()
may return incorrect information if the client's attribute cache is
inaccurate. Other operations that are based on
information in the client's attribute or access caches
may behave incorrectly if the information in the caches
is inaccurate. Examples of this are given below.
Denial of Access
Access to a file on the server may be denied because
the attributes in the client caches are more
restrictive than the attributes on the server. If a
privilege has just been allowed on the server, and the
client's caches still record this privilege as being
"off", functions such as
open()
may fail on the client.
If the attributes in the client caches are less
restrictive than the attributes on the server,
functions such as
open()
may succeed, but functions like
read()
or
write()
may fail.
Operations Using File's Byte Count
File operations that rely on the byte count of a file
may function incorrectly if the byte count stored in
the attribute cache is inaccurate. For example, a
write()
to a file that was opened with the O_APPEND
flag set may result in the overwriting of data that
was appended to that file by a process executing on
another XNFS client. Record locking operations (see
File and Record Locking
)
where
l_whence
is set to SEEK_END may also fail to behave as intended.
File Times
Programs that use file access and modification times
may behave incorrectly. For example,
make
may fail to
rebuild a target because of stale information about the
source's modification time.
File Accessibility Changed after Open
A process may be denied further access to an open file
if the file is located on a remote file system.
There are two reasons for this given below.
File Attributes Changed after Open
The attributes of the file could be changed after the file
was opened.
As part of the stateless behaviour of NFS, the server does not maintain
information regarding files that are open by processes on client
systems.
Therefore, each time a client process issues a request to access a
file, the request is validated.
It is possible
that the attributes of a file can change in between requests from a
client process, thus denying further access to a file that had been
previously accessible.
In this case functions such as
read()
and
write(),
or derived functions such as
fread(),
fgets(),
etc. may fail with [EACCES].
In the XSI specifications, it is stated that the effect of calling
chmod()
to change the access permissions of an open file is implementation-dependent.
With NFS, the semantics of chmod()
are different, in that effects are immediate and can cause
further access to an open file to be denied or allowed in a manner different
to access to a local file.
The two additional cases where access is allowed by NFS are:
-
Once a file handle has been established, the owner of the file is allowed to
access it regardless of the permission settings associated with the file.
-
Once a file handle has been established and a user has permission to execute
a file, then that user is also granted permission to read the data from the
file.
File Deleted after Open
The file could be deleted by a process on the server, or on another
client.
Another function of the stateless behaviour of NFS is that
the server cannot prevent the deletion of a file
that is open by a process on a client system and is not
open by a process on the server.
When this occurs, the next client request which refers to the file will
be rejected with the XNFS-specific error [ESTALE], indicating
that the file handle
no longer refers to a valid file system object.
An XNFS client
implementation may return a code for [ESTALE] as the reason for the failure
of the XSI call, or may translate it into some other error code.
In addition to file operations such as
remove(),
read()
and
stat(),
and operations on directories, such as
rmdir(),
may fail with [ESTALE]. As described in
Error Handling
,
record locking operations may fail in a manner that is
implementation-dependent.
If a file is deleted while a process on the server has
the file open, client requests using that file may
fail with [ESTALE]. Alternatively, the server may
continue granting access to the file as long as one or more
processes on the server have the file open.
As discussed in
Implicit File Access
,
it is possible for a function to fail with [ESTALE] even
if it does not take a file handle or filename as an
argument. For example, if a system's user
database resides on a remote file,
getpwuid()
will pass along errors that it receives accessing the database file.
No Protection for In-Use Executables
If an executable file stored on an XNFS server is being executed
on a client system, there
is no mechanism that prevents the file from being
deleted, truncated, or overwritten (for example, via
remove(),
fopen(),
truncate()
or
write()).
The execution of the program may be terminated if this occurs.
The error [ETXTBSY] is never returned by a function operating on a
a remote file over NFS.
Nonetheless, it is possible for calls such as
truncate()
or
write()
to fail because an executable file is being executed on the server.
This XNFS Specification
does not specify which error code is returned in this case.
Transparent Rename or Unlink While Open
If a file on the server is open by a process running on
a client, and the file is deleted by the same or a
different process on that client (for example, using
remove()
or
unlink()),
the client will rename the file to a
temporary file. Any process that has this file
open can continue using it. When the last process on
the client to have this file open closes it, the
client issues a request to the server to delete the
temporary file. If a process on the client attempts to
remove the temporary file, the client may remove it,
ignore the request, or rename the file to a different
temporary file. Should the client fail before removing
the temporary file, the temporary file may remain
indefinitely. It is common practice to have an entry
in the XNFS server's
crontab
database to regularly delete these lingering temporary files.
The client's request to delete the temporary file may not
be processed on the server if
the server fails and the "RetrySemantics=" attribute of the
mounted file system is
Soft.
(See the discussion of "RetrySemantics=" in
MountedFileSystem
.)
This XNFS specificationdoes not specify how a client generates
the name for the temporary file described in this
section. Nonetheless, it is common practice for
the client to pick a name starting with a period (.)
in the same directory as the original file. The presence
of this file can cause attempts to remove the directory
(for example,
rmdir()
or "rm -rf") to fail.
Data Caching
The following semantic differences may occur due to the
buffer cache mechanisms.
Delayed Write Errors
Errors that occur when writing data to the file server will not
necessarily be returned through
write().
Calls to write() may put data into the
client's buffer cache and return without error.
The error may occur later when the buffer cache is flushed to the server.
The buffer cache may be flushed in response to a call
from the process, for example,
sync()
or
close(),
or it may be flushed asynchronously. If the cache is
flushed in response to a call from the process, the call will
return the error. If the buffer cache is flushed
asynchronously, the error will be reflected by a
subsequent call to
fsync()
or
close().
Some systems may reflect the error at a subsequent
write(),
but application writers must not depend on this behavior.
The
sync()
call may fail silently because
sync()
only schedules writes. The actual writes may happen after
sync()
has returned.
Some routines, such as
fgetpos(),
may cause a
write()
to occur as a side effect. These writes are also
potentially subject to delayed write errors.
Read of Old Data
The information in the buffer cache may be inaccurate and not
reflect the latest changes to a file.
Therefore, the
read() function may not get the latest contents of a file.
Similarly, functions that invoke
read(),
such as
fscanf()
or
fgets(),
need not return the latest
contents of a file, even when the referenced I/O
stream is unbuffered.
Atomicity of Transfer
When a file is being read or written by several processes on different
systems, the operations of the caches on the server and clients
will affect the atomicity of data reading and writing.
No assumption can be made that common submultiples for all the cache
sizes or alignments will exist.
Consequently, it is impossible to guarantee that any
arbitrary multi-byte read or write will be atomic.
File Time Updates
If a client is able to satisfy a read or write request
without contacting the server, the client need not
update one or more of the corresponding file times
(st_mtime, st_ctime, and st_atime). This applies to
explicit reads and writes and to implicit reads and
writes, such as those from mapped files and the
exec
family of functions.
For write requests, programs can force st_mtime and
st_ctime to be updated by forcing the writes to the
server, for example with
fsync().
There is no corresponding
mechanism for forcing st_atime to be updated. In
particular, the functions
fstat()
and
stat()
cannot be used to force the update of file times
for either reads or writes.
Directory Caching
There are two semantic differences concerning the client's directory caching
mechanism.
These differences occur when the information in the
directory cache does not reflect the server's directories.
As with attribute caching, the information in this cache is refreshed
frequently from the server.
However, there is a window of time in which the
information in this cache can be inaccurate.
If this caching mechanism is disabled through the "AttribCaching=False"
MountedFileSystem attribute, these semantic differences no longer
exist.
(See the discussions of the "AttribCaching=", "ACDirMin="
and "ACDirMax" MountedFileSystem attributes in
MountedFileSystem
.)
The following semantic differences can be noted:
-
It is possible that a client may still record an entry
of a file that has just been deleted on the server.
Attempts on the client to create a new file with the
same name, for example, using
creat()
or
link(),
may fail, typically with [EEXIST]. Attempts to remove an
otherwise empty directory may fail, typically with
[EEXIST] or
-
The result of a process that modifies the contents of a directory may not
be immediately noticeable to other clients.
For example, calls to
open()
or
stat()
may fail, even if the file exists on the server. Functions such as
tmpnam()
may return a filename that is already in use on the server.
Time Skew
A process cannot rely on the access times of a remote file
to be correct.
The access times associated with a remote file will
relate to the system clock on the server system rather than to that
of the client system which last updated the remote file.
A comparison of
these access times with the
local system clock or the access times of a local file may not be of value.
The reasons for this are:
-
The system clocks on the server and client may not be synchronised.
-
The client and server systems
may each have a different notion of system date and
time; for instance, they may be in different time zones.
-
The attribute cache may be holding inaccurate information concerning
the times of a file.
As a result, programs whose behavior depends on file
times may behave differently or incorrectly in an
XNFS environment. For example, if a file has been
modified recently, the ls command may display the file's
date and time using the format for a modification time
in the future. The make command may mistakenly
conclude that a particular target is (or is not) out of
date with respect to its sources. The
pax
command may function incorrectly with the
-u
option.
This XNFS specification does not specify whether the routines
utime()
and
utimes()
use the client time or server time
when a null time pointer is used, that is, when
setting the file times to the current time.
Server or Network-Induced Delays
When a client makes a request to the server, the
client expects a response within a certain time limit.
(See the discussion of the "NFSTimeOut=" MountedFileSystem attribute in
MountedFileSystem
.)
Should a response not occur within
this time limit, the client may react in two ways,
depending upon values of certain mount attributes:
-
The client may reissue the request repeatedly until either the server
responds, or the maximum number of retries is reached.
Should this maximum number of retries be reached, the
client has detected a server failure and returns an
error to the process.
(See the discussions of the "RetrySemantics="
and "NFSRetransmissions=" MountedFileSystem attributes in
MountedFileSystem
.)
-
The client may reissue the request repeatedly until the
the server reponds.
(See the discussions of the "RetrySemantics="
and "NFSRetransmissions=" MountedFileSystem attributes in
MountedFileSystem
.)
This behaviour may cause a function which is waiting for the server's
response to not return to the calling process for an arbitrary
duration of time.
The effect on the process is that it will sleep until the server responds.
When a process issues a
stat() of a remote NFS mounted object, or of
a directory containing a remote NFS mounted object,
a server request is generated.
This may cause a delay if the server does not respond.
Interruption of Function Calls
A signal may be posted to a process that is making a
request that involves an NFS file. For example, a
user may wish to interrupt a request that is taking a
long time to complete. If the file system was mounted
with the "Intr=" attribute set to "True" (see
MountedFileSystem
),
the pending NFS operation will be
cancelled and the signal will be processed.
Otherwise the NFS operation will be retried as described in
Server or Network-Induced Delays
,
and the signal will not be processed
until the NFS operation succeeds or the retry
limit is reached. This behavior applies to any operation
that must contact the server, even functions that are
not documented as potentially failing with [EINTR]
(for example,
stat(),
readlink()).
File and Record Locking
File and record locking allows all or part of a file to
be locked by calling
fcntl()
(using F_SETLK or F_SETLKW) or
lockf().
There are several semantic differences regarding file
and record locking over XNFS.
Availability of Locking
For file and record locking to be available, the client
and server must support the NLM protocol, typically by
running the XNFS lock server. This XNFS specification does not
specify any mechanism whereby a client can determine
whether a server provides locking services, nor does it
define the effects of issuing locking calls when the
server does not provide these services.
F_GETLK l_pid
The structure
flock
that is returned from an F_GETLK
command contains the process ID (l_pid) of the
process that is holding the lock. When this is a process
that is accessing a file on a remote machine, this
process ID is provided as a unique identifier for the
process holding the lock, but it is not necessarily the
same as the process ID of that process. This XNFS specification
does not specify a mechanism for identifying which
machine the process is running on.
Signals
If a process receives a signal while attempting to
acquire or release a remote lock, the call may return
with the error [EINTR], even for non-blocking locks
(fcntl() with F_SETLK or
lockf()
with F_TLOCK).
If this happens, the process cannot determine whether its
request succeeded. If the process exits, the
client operating system will release the lock if
necessary. If the process catches the signal and
resumes processing, the process should either resubmit
the lock request, or it should explicitly unlock the
region it had tried to lock.
Memory-Mapped Files
Under some circumstances it is possible for cooperating
processes to inadvertently defeat file and record
locking by mapping all or part of the file into memory
with
mmap().
For this reason,
mmap()
may fail if all or part of the file is locked, and attempts to
acquire a lock may fail if all or part of the file is mapped
into memory. Applications can reduce the chances of
running into these restrictions by always locking the
entire file, or by locking regions that correspond to
whole pages on the client.
Error Handling
Suppose a process tries to acquire a lock. Due to
limitations in Version 3 of the NLM protocol, the
client is unable to distinguish unrecoverable errors
from the case where another process already has a
conflicting lock. Examples of unrecoverable
errors include:
-
after the process had opened the file, the file was
deleted by a process on the server or on a different client.
-
the process requested an exclusive lock, the
server has the file system mounted read-only, and the
server implementation requires a read-write file system
for an exclusive lock.
This XNFS specification does not define the behavior of the
client under these circumstances.
Network Heterogeneity
There are several differences that occur because XNFS can connect
heterogeneous environments.
Local Execution of a Remote Program
It is possible that a
binary file residing on the server may be incompatible for
execution on a client.
For example, it may have been compiled for
a different type of machine, or a different X/Open-compliant
operating system.
An attempt to execute such a program, for example, via
popen()
or
system(),
or from the shell, will usually fail.
A program residing on the server which is compatible for execution with a
client may be incompatible in other ways.
For example, it may
include references to local resources which are not accessible
on all systems, or have been compiled for a different version of the
operating system which uses a slightly different binary interface.
In this case the failure mode cannot be predicted.
This XNFS specification does not specify any mechanism for determining the
compatibility of a binary program with a particular system, nor
the ways in which incompatibilities may manifest themselves.
Use of Remote Input Files with Varying Formats
Several utilities, for example tabs,
as well as several functions, for example getpwuid(),
process files that are in a predefined format.
Since
there is no standard defining the format for some of these input files,
different implementations may use different formats for the same input file.
Incompatibilities may arise when a utility or function is used with a
remote input file having a different format than expected.
Architectural Dependencies
Some utilities may use input files that have a format which is
dependent upon the underlying architecture of the system.
For example, a utility which uses a binary file may not
operate correctly with a binary file from a foreign architecture.
Any utility which operates on binary object files
and executable files such as
ar and
cc
will not operate correctly with a binary file from a foreign system.
Some algorithms, for example the computation of a file's checksum using
sum, may be dependent upon the architecture of the machine.
Therefore, computing the checksum of two identical files residing on two
different machines having different architectures may yield
two different values.
Output Displayed in Conventions of Local System
Utilities which report information about files and/or file systems will
behave consistently when viewed from a single system.
However, the results of some of these utilities
that are executed on different systems may differ.
For instance, the execution of df
on two different systems
may compute the free space of the same mounted file system differently.
The output from the
nm
or
od
utilities on two different systems may be formatted differently when run on
the same object file. In many cases, though, the
utility provides a mechanism for generating output in a
portable fashion, such as the
-P
option to
df
and
nm,
or the
-t
option to
od.
Filesize Differences
A system need not support native 64-bit file sizes to
support the NFS Version 3 protocol. This lets 32-bit
clients interoperate with 64-bit servers and vice-versa,
with certain restrictions.
If a program is running on a 64-bit client, calls to
routines such as
write()
or
truncate()
will fail if the
program tries to create a file that is larger than that which
the server supports. Record locking operations (see
File and Record Locking
)
will fail if the program tries to lock a
region of the file that the server cannot support. The
failure status in these cases is typically [EFBIG].
If a program is running on a 32-bit client, routines
such as
stat()
may return an incorrect size for a file.
If a file is too big for the client to handle, the
client may handle requests for the file in one of two ways:
-
Deny access to the file. That is, calls to
open()
or
fopen()
will fail if the file exists and is too big
for the client to handle. If the file is small enough
initially and then grown too big, for example, by a process on
the server, the call to
open()
or
fopen()
will succeed,
but attempts to read or write the file will fail after
the client determines that the file has become too big.
-
Allow access to the first part of the file.
That is, the program will be allowed to read or write
the file up to the 32-bit limit, but not beyond.
Characters in File Names
A server may have an implementation-specific set of
characters that it does not allow in file names.
If a program on the client uses one of these characters
in a file name, for example in a
creat()
or
mkdir()
call, it may get back the error [EACCES]. Functions that
expect the name of an existing file, for example,
stat(),
may fail with [EACCES] or [ENOENT]. Note that the contents
of a symbolic link for the
symlink()
function are not subject to any character restrictions.
Some server implementations do not preserve character
case when creating an object in a file system. That
is, they may map all the characters in the name to
either lower or upper case. Also, even if they
preserve case when creating an object, some server
implementations may ignore case distinctions for
lookup operations. For example, an attempt to create the
file "Makefile" may instead create the file
"MAKEFILE". Even if the server creates the file using the name
"Makefile", attempts to reference "makefile" or
"MakeFILE" may all reference the first file "Makefile".
Server Access Control
The server may use an access model other than the
traditional UNIX mode bits, for example, Access Control
Lists.
In this case the mode bits reported by the client need
not accurately represent the permissions on a file.
This inaccuracy can cause several problems, as
discussed below. Some systems implement an additional
protocol to avoid these problems. The details of that
protocol are not covered by this XNFS specification and
may vary from vendor to vendor.
If the client and server are connected using Version 2
of the NFS protocol, the client relies on the mode bits
to determine whether a given process has access to a
given file. If the mode bits are sufficiently
inaccurate, the client may deny access to a process
even though the request would succeed on the server.
That is, calls to
open()
or
fopen()
may fail on the client when they would succeed on the server.
Conversely, the client may grant access based on the
mode bits, only to have the request denied by the
server. That is, the
open()
call may succeed, but calls to
read()
or
write()
may fail, or there may be delayed write errors as described in
Delayed Write Errors
.
If the client incorrectly grants a process access to a
file and can satisfy read requests from its cache, the
process may successfully read or execute the file,
bypassing the restrictions on the server. It is also
possible for an unauthorized process to read a
directory in this manner. A similar security breach is
possible for writes to a file: if the client
incorrectly grants access to an unauthorized process
while a second, authorized, process is writing to the
file, the first process may successfully update the
file on the server. Unauthorized directory updates such as
mkdir(),
rmdir(),
rename()
and
remove()
should always fail.
If the client is using Version 3 of the NFS protocol,
the mode bit information may still be incorrect.
Nonetheless, the client's access decisions should be
consistent with the server's, after allowing for
caching issues as described in
Attribute and Access Caching
.
(With NFS Version 3, the client can ask the server whether a
particular access request should be granted.)
This greatly reduces the probability that a process
will incorrectly granted or denied an operation by the client.
Server Support for File Times
Not all server implementations let the client set the
times for a file (st_atime, st_mtime). Those that do
need not support a fine enough clock granularity to
fully support interfaces like
utime()
or
utimes().
For example, they may support a resolution in milliseconds
or in minutes. This means that attempts to set a
file's times, for example with
touch()
or
utimes(),
need not change the file times at all, or the file
times may change to values different than those requested.
Special Files
The encoding of major and minor device numbers is not
specified by Version 2 of the NFS protocol, so
different implementations may use different encodings.
This means that the major and minor device numbers of a
special file may have different values, depending on
where the file is referenced from. Functions such as
open()
may behave in an unintended manner under these circumstances.
Bounds checking on the server can cause
mknod()
to fail, particularly if the client and server are
communicating using Version 2 of the NFS protocol and
they disagree on the encoding of the major and minor
device numbers.
User and Group ID Database Consistency
It is necessary to maintain a consistent user ID to
username mapping across the collection of XNFS servers
and clients. The group ID to group name mapping should
be consistent as well. If these databases are not
consistently maintained, programs such as
ls
may report different owning users or groups depending
on where the program is run. Also, access restriction
mechanisms need not function as intended. Access which
should be denied may be allowed, and conversely access
which should be allowed may be denied.
In some cases the server may limit the user or group ID
values to a subset of the values that are possible on
the client. In this case, of course, it is impossible
to have consistent user and group ID mappings.
Routines such as
chown()
will fail with [EINVAL] when an unsupported user or group ID is used.
Access to Read-Only File Systems
Operations which attempt to write to or modify a remote read-only
file system will fail and may return the error [EROFS].
This will occur if the
file system was exported with the ExportedFileSystem "Mode=" attribute
set to "ReadOnly", or if the the file system was mounted with the
MountedFileSystem "Mode=" attribute set to "ReadOnly".
(See the discussions of the "Mode=" attribute in both
ExportedFileSystem
and
MountedFileSystem
.)
For access using Version 3 of the NFS protocol,
the failure will occur when the file is opened for
writing, unless a stale entry in the client access cache
(see
Attribute and Access Caching
)
causes the call to succeed. With Version 2, the call
open(),
fopen(),
etc. will fail if the
client has mounted the file system read-only, but
the call may succeed if the client has mounted the
file system read-write and the server has exported it
read-only. If the process is able to open the
file for writing, attempts to write to a regular file
(for example,
write(),
writev())
will generally fail, though data
caching can delay these failures, as described in
Delayed Write Errors
.
Directory operations on a read-only file system, for example,
rmdir(),
unlink(),
creat(),
mknod(),
will fail immediately for both versions of the NFS protocol.
Writes to special files are not subject to read-only
restrictions, as they do not require updates to the
file system on the server.
An attempt to obtain an exclusive record lock on a
file in a read-only file system may fail. As described in
Error Handling
,
the request may fail in an implementation-dependent manner.
Group Ownership of Created Files
When the "GrpID=" attribute of the MountedFileSystem object is set to True,
the group owner of a newly created file is always set to the group owner of
the directory containing that file.
This may differ from the semantics applied to a locally created
file where the group owner may be set to the effective
group ID of the calling process.
This semantic difference affects functions such as
open()
and
creat(),
as well as operations such as I/O redirection from the shell.
Consistency of Limits
The limit on the maximum number of simultaneous supplementary group IDs per
process is allowed to vary between systems and XNFS does not impose any
restrictions on the number of group IDs which are used to determine
accessibility to a remote file.
However, the server may impose a lower
maximum number than the client and may reject requests from the client which
contain more than the maximum number of supplementary groups allowed by
the server.
A similar problem exists with other limits, such as the
maximum number of characters in a filename, or the
maximum number of hard links to a file. These limits
may vary between different file systems, and Version 2
of the NFS protocol does not provide a mechanism for
this information to be made available to a client. The
limits provided from a call to
pathconf()
need not accurately reflect the limit imposed by the server's
file system. This may cause file access requests to be
rejected by the server or for files to be inaccessible
from the client.
Symbolic Links
If the server does not support symbolic links, an
attempt to create one with
symlink()
will fail with [EOPNOTSUPP]. Also, calls to
readlink()
may fail with [EOPNOTSUPP] instead of [EINVAL].
The server treats the contents of a symbolic link as an
opaque object, and the XNFS specification does not
define a format for symbolic links. This means that a
readlink()
call may return a string that does not look
like a path name. It also means that the client may be
unable to resolve the symbolic link, causing routines
that involve path names (open(),
remove(),
mkdir(),
stat(),
etc.) to fail if the link is part of the given path.
A client resolves a symbolic link using its own namespace,
not the server's namespace. For example, a client will interpret
a link to "/bin/sh" as referring to the client's /bin/sh,
even if the link was created on the server.
Similarly, a link to "../new_dir/some_file" may take
the client to a local file or a completely different
server if it appears in the top directory of a mounted
file system (see
MountedFileSystem
for an explanation of mounted file systems).
Interrupted Root File System Service
A client's root file system may be accessed using the
NFS protocol. Diskless clients usually operate in this
manner, and an individual process may change its root
file system to a remote file system using the
chroot()
call. If service for the root file system is
interrupted, service for other file systems may be
interrupted as well. For example, if the server for a
diskless client's root file system crashes, the client
may be unable to access any file systems, even file
systems that are served by a different server, until
the crashed server resumes operation.
Implicit File Access
Several functions in the X/Open System Interfaces and Headers Specification (see reference XSH)
access files even though they do not
take a stream handle, file descriptor or path name as
an argument. For example,
getpwnam()
and
getgrnam()
use the system's user and group databases,
respectively. If the databases are implemented as remote files,
either through individual mounts or because the
client is diskless, the operations performed by these
functions are subject to the semantic differences
described in this appendix.
Other functions may access files other than those
specified in the argument list. For example,
ttyname()
and
getcwd()
may use calls to
stat()
to find a desired file or directory. It is possible that some of
these calls to
stat()
will inadvertently refer to remote files or directories. Calls to
system()
may result in references to remote files, depending on the
contents of environment variables such as PATH and ENV.
These references to remote files are subject to the
semantic differences described in this appendix.
Multiple Hosts
Software that was written for a local file system
environment may make uniqueness assumptions, for
example, it may assume that process identifiers are unique.
These assumptions need not be true in an XNFS environment.
Process Identifiers
A common approach for generating a unique filename,
particularly in shell scripts, is to append the
process's process identifier to an
application-dependent prefix. This approach can
fail if two processes, each with the same identifier on a
different host, attempt to create a unique file in
a shared directory. The X/Open System Interfaces and Headers Specification (see reference XSH)
provides several functions, for example,
mkstemp(),
that can avoid this uniqueness problem.
Shell scripts must rely on ad-hoc mechanisms for
generating unique files, such as including the
host name in the file name.
Unique Daemons
Some system facilities, such as the
crontab
facility or printer spoolers, may assume the existence of a
single daemon that is started during system
initialization. If the files that the daemon uses are shared using
the NFS protocol, the daemon may behave in an
unintended manner. For example, if the
crontab
database is accessible from more than one system, the same
command may be executed concurrently on different hosts,
even if this was not the user's intent.
Why not acquire a nicely bound hard copy?
Click here to return to the publication details or order a copy
of this publication.