NFS Class
Properties Methods Events Config Settings Errors
This class is used to create a Network File System (NFS) server based on NFS version 4.1.
Syntax
NFS
Remarks
This component provides a simple way to create a Network File System (NFS) server, enabling NFS clients the ability to access and share files seamlessly across a network.
Getting Started
To begin, call StartListening to start listening for incoming connections. The class will listen on the interface defined by LocalHost and LocalPort. For example:
Component.LocalHost = "localhost";
Component.LocalPort = 2049; // default
Component.StartListening();
while (Component.Listening) {
Component.DoEvents();
}
StopListening may be called to stop listening for incoming connections. Shutdown may be called to stop listening for incoming connections and disconnect all existing connections.
Handling Connections
Once listening, the class can accept (or reject) incoming connections. Incoming connection details are first available through the ConnectionRequest event. Here, the connection's originating address and port can be queried. By default, the class will only accept connections originating from the local host, but this behavior can be overridden within this event (see note below for clarification).
Once a connection is complete, the Connected event will fire. Note that this event will fire if a connection succeeds or fails. If successful, the event will fire with a StatusCode of 0. A non-zero value indicates the connection was unsuccessful, and the Description parameter will contain relevant details.
After a successful connection, relevant connection-specific details will be available within the Connections collection. Each connection will be assigned a unique ConnectionId which may be used to access these details.
To manually disconnect a connected client call the Disconnect method and pass the ConnectionId. After a connection has disconnected, the Disconnected event will fire. In the case a connection ends and an error is encountered, the StatusCode and Description parameters will contain relevant details regarding the error. Once disconnected, the connection will be removed from the Connections collection.
Note: The class is designed for use on single-user machines only. For use in other contexts, additional security should be handled by the user. As a result, the class will only accept incoming connections originating from the the local host by default, as indicated by the AllowedClients config (127.0.0.1). This behavior may be overridden by modifying the AllowedClients config, or manually accepting a connection in ConnectionRequest.
Handling Events
File and folder operations are serviced through the events listed below. In addition to the connection-related events discussed in the previous section, the following events may fire while the class is listening:
Event | Usage |
Access | Fires when a client verifies its access permissions for an object. |
Chmod | Fires when a client attempts to modify the permission bits of an object. |
Chown | Fires when a client attempts to modify an object's owner attribute, group attribute, or both. |
Close | Fires when a client requests the closure of a previously opened file. |
Commit | Fires upon when a client attempts to flush any uncommitted file data from a previous Write operation to stable storage. |
CreateLink | Fires when a client attempts to create a symbolic link or hard link |
GetAttr | Fires when a client requests attributes for an object (such as the owner, group, or mode attributes). |
Lock | Fires when a client attempts to create or test a byte-range lock for a file. |
Lookup | Fires when the class needs to determine the existence of an object in the current directory. |
MkDir | Fires when a client attempts to create a new directory. |
Open | Fires when a client attempts to create or open a file. |
Read | Fires when a client attempts to read any part of a file. |
ReadDir | Fires when a client attempts to list the contents of a directory. |
ReadLink | Fires when a client attempts to read data associated with a symbolic link |
Rename | Fires when a client attempts to rename or move an object. |
RmDir | Fires when a client attempts to remove a directory. |
Truncate | Fires when a client attempts to modify a file's size attribute. |
Unlink | Fires when a client attempts to unlink (or delete) a file. |
Unlock | Fires when a client attempts to release a lock. |
UTime | Fires when a client attempts to change a file's last access time, last modification time, or both. |
Write | Fires when a client attempts to write data to a file. |
Many of the listed events expose a Result parameter, which communicates the operation's success (or failure) to the class and connection. This parameter is always 0 (NFS4_OK) when relevant events fire. If the event, or operation, cannot be handled successfully, this parameter should be set to a non-zero value. Possible Result codes and their descriptions are defined in RFC 7530 section 13.
For more information on how to handle each of these events, please refer to the event's documentation.
Property List
The following is the full list of the properties of the class with short descriptions. Click on the links for further details.
Connections | This property includes a collection of connected clients. |
Listening | This property indicates whether the class is listening for incoming connections. |
LocalHost | This property includes the name of the local host or user-assigned IP interface through which connections are initiated or accepted. |
LocalPort | The TCP port in the local host where the class listens. |
Method List
The following is the full list of the methods of the class with short descriptions. Click on the links for further details.
Config | Sets or retrieves a configuration setting. |
Disconnect | This method disconnects the specified client. |
DoEvents | This method processes events from the internal message queue. |
FillDir | This method fills the buffer with information about a directory entry. |
Shutdown | This method shuts down the server. |
StartListening | This method starts listening for incoming connections. |
StopListening | This method stops listening for new connections. |
Event List
The following is the full list of the events fired by the class with short descriptions. Click on the links for further details.
Access | This event fires when a client verifies their access permissions for an object. |
Chmod | This event fires when a client attempts to modify the permission bits of an object. |
Chown | This event fires when a client attempts to modify an object's owner attribute, group attribute, or both. |
Close | This event fires when a client requests the closure of a previously opened file. |
Commit | This event fires when a client attempts to flush any uncommitted file data from a previous Write operation to stable storage. |
Connected | This event fires immediately after a connection completes (or fails). |
ConnectionRequest | This event fires when a connection request comes from a remote host. |
CreateLink | This event fires when a client attempts to create a symbolic link or hard link. |
Disconnected | This event fires when a connection is closed. |
Error | This event fires information about errors during data delivery. |
GetAttr | This event fires when a client requests attributes for an object (such as the owner, group, or mode attributes). |
Lock | This event fires when a client attempts to create or test a byte-range lock for a file. |
Log | This event fires once for each log message. |
Lookup | This event fires when the class needs to determine the existence of an object in the current directory. |
MkDir | This event fires when a client attempts to create a new directory. |
Open | This event fires when a client attempts to create or open a file. |
Read | This event fires when a client attempts to read any part of a file. |
ReadDir | This event fires when a client attempts to list the contents of a directory. |
ReadLink | This event fires when a client attempts to read data associated with a symbolic link. |
Rename | This event fires when a client attempts to rename or move an object. |
RmDir | This event fires when a client attempts to remove a directory. |
Truncate | This event fires when a client attempts to modify a file's size attribute. |
Unlink | This event fires when a client attempts to unlink (or delete) a file. |
Unlock | This event fires when a client attempts to release a lock. |
UTime | This event fires when a client attempts to change a file's last access time, last modification time, or both. |
Write | This event fires when a client attempts to write data to a file. |
Config Settings
The following is a list of config settings for the class with short descriptions. Click on the links for further details.
AllowedClients | A comma-separated list of host names or IP addresses that can access the class. |
BindExclusively | Whether or not the class considers a local port reserved for exclusive use. |
BlockedClients | A comma-separated list of host names or IP addresses that cannot access the class. |
ConnectionUID | The unique connectionId for a connection. |
DefaultConnectionTimeout | The inactivity timeout applied to the SSL handshake. |
InBufferSize | The size in bytes of the incoming queue of the socket. |
KeepAliveInterval | The retry interval, in milliseconds, to be used when a TCP keep-alive packet is sent and no response is received. |
KeepAliveRetryCount | The number of keep-alive packets to be sent before the remotehost is considered disconnected. |
KeepAliveTime | The inactivity time in milliseconds before a TCP keep-alive packet is sent. |
LogLevel | Specifies the level of detail that is logged. |
MaxConnections | The maximum number of connections available. |
MaxReadTime | The maximum time spent reading data from each connection. |
MountingPoint | A path to an empty directory to mount the NFS server to. |
OutBufferSize | The size in bytes of the outgoing queue of the socket. |
SelectWaitMillis | The length of time in milliseconds the class will wait when DoEvents is called if there are no events to process. |
SpaceAvail | Specifies the amount of space available on the server, in bytes. |
SpaceUsed | Specifies the amount of space used by the current filesystem object, in bytes. |
UseIOCP | Whether to use the completion port I/O model. |
UseIPv6 | Whether to use IPv6. |
UseWindowsMessages | Whether to use the WSAAsyncSelect I/O model. |
BuildInfo | Information about the product's build. |
LicenseInfo | Information about the current license. |
Connections Property (NFS Class)
This property includes a collection of connected clients.
Syntax
CBFSConnectList<CBFSConnectNFSConnection>* GetConnections();
int cbfsconnect_nfs_getnfsconnectioncount(void* lpObj);
char* cbfsconnect_nfs_getnfsconnectionauxgids(void* lpObj, int connectionid);
int cbfsconnect_nfs_getnfsconnectionconnected(void* lpObj, int connectionid);
char* cbfsconnect_nfs_getnfsconnectioncurrentfile(void* lpObj, int connectionid);
int cbfsconnect_nfs_getnfsconnectiongid(void* lpObj, int connectionid);
char* cbfsconnect_nfs_getnfsconnectionremotehost(void* lpObj, int connectionid);
int cbfsconnect_nfs_getnfsconnectionremoteport(void* lpObj, int connectionid);
int cbfsconnect_nfs_getnfsconnectionuid(void* lpObj, int connectionid);
int GetNFSConnectionCount(); QString GetNFSConnectionAuxGIDs(int iConnectionId); bool GetNFSConnectionConnected(int iConnectionId); QString GetNFSConnectionCurrentFile(int iConnectionId); int GetNFSConnectionGID(int iConnectionId); QString GetNFSConnectionRemoteHost(int iConnectionId); int GetNFSConnectionRemotePort(int iConnectionId); int GetNFSConnectionUID(int iConnectionId);
Remarks
This property includes a collection of connected clients. All connections may be managed using this property. Each connection is described by different fields of the NFSConnection type.
The collection is a hash-table type of collection, in which the ConnectionId string is used as the key to the desired connection. You may acquire the key for a given connection through the Connected event.
This property is read-only.
Data Type
Listening Property (NFS Class)
This property indicates whether the class is listening for incoming connections.
Syntax
ANSI (Cross Platform) int GetListening(); Unicode (Windows) BOOL GetListening();
int cbfsconnect_nfs_getlistening(void* lpObj);
bool GetListening();
Default Value
FALSE
Remarks
This property indicates whether the class is listening for incoming connections on the interface identified by LocalHost and LocalPort.
Upon the successful return of StartListening or StopListening, this property will be adjusted accordingly.
This property is read-only and not available at design time.
Data Type
Boolean
LocalHost Property (NFS Class)
This property includes the name of the local host or user-assigned IP interface through which connections are initiated or accepted.
Syntax
ANSI (Cross Platform) char* GetLocalHost();
int SetLocalHost(const char* lpszLocalHost); Unicode (Windows) LPWSTR GetLocalHost();
INT SetLocalHost(LPCWSTR lpszLocalHost);
char* cbfsconnect_nfs_getlocalhost(void* lpObj);
int cbfsconnect_nfs_setlocalhost(void* lpObj, const char* lpszLocalHost);
QString GetLocalHost();
int SetLocalHost(QString qsLocalHost);
Default Value
""
Remarks
The LocalHost property contains the name of the local host as obtained by the gethostname() system call, or if the user has assigned an IP address, the value of that address.
In multihomed hosts (machines with more than one IP interface) setting LocalHost to the IP address of an interface will make the class initiate connections (or accept in the case of server classs) only through that interface. It is recommended to provide an IP address rather than a hostname when setting this property to ensure the desired interface is used.
If the class is connected, the LocalHost property shows the IP address of the interface through which the connection is made in internet dotted format (aaa.bbb.ccc.ddd). In most cases, this is the address of the local host, except for multihomed hosts (machines with more than one IP interface).
Note: LocalHost is not persistent. You must always set it in code, and never in the property window.
Data Type
String
LocalPort Property (NFS Class)
The TCP port in the local host where the class listens.
Syntax
ANSI (Cross Platform) int GetLocalPort();
int SetLocalPort(int iLocalPort); Unicode (Windows) INT GetLocalPort();
INT SetLocalPort(INT iLocalPort);
int cbfsconnect_nfs_getlocalport(void* lpObj);
int cbfsconnect_nfs_setlocalport(void* lpObj, int iLocalPort);
int GetLocalPort();
int SetLocalPort(int iLocalPort);
Default Value
2049
Remarks
The LocalPort property must be set before the server starts listening. By default, this value is 2049. If its value is 0, then the TCP/IP subsystem picks a port number at random. The port number can be found by checking the value of the LocalPort property after successfully calling StartListening.
The service port is not shared among servers (i.e. there can be only one server 'listening' on a particular port at one time).
Data Type
Integer
Config Method (NFS Class)
Sets or retrieves a configuration setting.
Syntax
ANSI (Cross Platform) char* Config(const char* lpszConfigurationString); Unicode (Windows) LPWSTR Config(LPCWSTR lpszConfigurationString);
char* cbfsconnect_nfs_config(void* lpObj, const char* lpszConfigurationString);
QString Config(const QString& qsConfigurationString);
Remarks
Config is a generic method available in every class. It is used to set and retrieve configuration settings for the class.
These settings are similar in functionality to properties, but they are rarely used. In order to avoid "polluting" the property namespace of the class, access to these internal properties is provided through the Config method.
To set a configuration setting named PROPERTY, you must call Config("PROPERTY=VALUE"), where VALUE is the value of the setting expressed as a string. For boolean values, use the strings "True", "False", "0", "1", "Yes", or "No" (case does not matter).
To read (query) the value of a configuration setting, you must call Config("PROPERTY"). The value will be returned as a string.
Error Handling (C++)
This method returns a String value; after it returns, call the GetLastErrorCode() method to obtain its result code; 0 indicates success, while a non-zero error code indicates that this method encountered an error during its execution. If an error occurs, the GetLastError() method can be called to retrieve the associated error message.
Disconnect Method (NFS Class)
This method disconnects the specified client.
Syntax
ANSI (Cross Platform) int Disconnect(int iConnectionId); Unicode (Windows) INT Disconnect(INT iConnectionId);
int cbfsconnect_nfs_disconnect(void* lpObj, int iConnectionId);
int Disconnect(int iConnectionId);
Remarks
Calling this method will disconnect the client specified by the ConnectionId parameter.
Error Handling (C++)
This method returns a result code; 0 indicates success, while a non-zero error code indicates that this method encountered an error during its execution. If an error occurs, the GetLastError() method can be called to retrieve the associated error message. (Note: This method's result code can also be obtained by calling the GetLastErrorCode() method after it returns.)
DoEvents Method (NFS Class)
This method processes events from the internal message queue.
Syntax
ANSI (Cross Platform) int DoEvents(); Unicode (Windows) INT DoEvents();
int cbfsconnect_nfs_doevents(void* lpObj);
int DoEvents();
Remarks
The method checks for events to process, such as incoming data, and fires corresponding events as necessary. If there are no events to process, the method waits for a time specified by the SelectWaitMillis configuration setting before returning.
Windows: By default, the server socket uses Windows messages, and DoEvents dispatches Windows messages internally. It is not necessary to call DoEvents from Windows GUI applications as these applications have an internal message dispatch loop. When called, this method must be called in the same thread or task in which the StartListening and StopListening methods are called.
To avoid using Windows messages and a dispatch loop, set UseWindowsMessages to false. The application still needs to call this DoEvents method to let the class handle socket updates, but when Windows messages are not used, DoEvents and StopListening may be called from a separate thread or task.
Linux: The method may be called from any worker thread, and events will fire in this thread.
macOS: In GUI applications, it is not necessary to call this method as the class registers itself in the main message loop. In other applications, the method may be called from any worker thread, and events will fire in this thread.
Error Handling (C++)
This method returns a result code; 0 indicates success, while a non-zero error code indicates that this method encountered an error during its execution. If an error occurs, the GetLastError() method can be called to retrieve the associated error message. (Note: This method's result code can also be obtained by calling the GetLastErrorCode() method after it returns.)
FillDir Method (NFS Class)
This method fills the buffer with information about a directory entry.
Syntax
ANSI (Cross Platform) int FillDir(int iConnectionId, const char* lpszName, int64 lFileId, int64 lCookie, int iMode, const char* lpszUser, const char* lpszGroup, int iLinkCount, int64 lSize, int64 lATime, int64 lMTime, int64 lCTime); Unicode (Windows) INT FillDir(INT iConnectionId, LPCWSTR lpszName, LONG64 lFileId, LONG64 lCookie, INT iMode, LPCWSTR lpszUser, LPCWSTR lpszGroup, INT iLinkCount, LONG64 lSize, LONG64 lATime, LONG64 lMTime, LONG64 lCTime);
int cbfsconnect_nfs_filldir(void* lpObj, int iConnectionId, const char* lpszName, int64 lFileId, int64 lCookie, int iMode, const char* lpszUser, const char* lpszGroup, int iLinkCount, int64 lSize, int64 lATime, int64 lMTime, int64 lCTime);
int FillDir(int iConnectionId, const QString& qsName, qint64 lFileId, qint64 lCookie, int iMode, const QString& qsUser, const QString& qsGroup, int iLinkCount, qint64 lSize, QDateTime qdtATime, QDateTime qdtMTime, QDateTime qdtCTime);
Remarks
This method fills the buffer with information about a directory entry. The Path parameter identifies the location and name of this object. The Name parameter identifies only the name of this object.
This method must be called when the class needs to send information regarding a directory entry to a client, specified by ConnectionId.
Information regarding a directory entry is required when the ReadDir event fires. Please see the event description for additional information and sample implementation.
The FileId parameter assigns a unique identifier to the file within the filesystem. If set to 0, the class generates an Id based on the checksum value of the Path. Therefore, if set to 0, the generated Id is guaranteed to be unique for a specific Path, and persist across server restarts assuming equivalent paths.
The Cookie parameter should be set to a value unique to the specific directory entry that can later be used to identify the last returned entry within the listing. As some background, when ReadDir fires, the client is attempting to read all entries within a directory. To start reading from the beginning of a directory, the client will specify a cookie value of 0.
The application is then responsible for calling FillDir for each existing directory entry. In some cases, the directory may contain a large number of entries. This can become problematic as a client will specify a maximum byte limit on the amount of returned data, meaning the application may not be able to return all directory entries in one response.
To ensure the limit is respected, FillDir will return a non-zero value if this limit is reached. After ReadDir returns, the client will follow up with a subsequent request specifying the last cookie value received (the cookie provided in the last successful call to FillDir). This value should be used as a "bookmark", representing a point the application can continue listing directory entries from in subsequent requests.
Note: Cookie values of 0, 1, and 2 should never be specified within this method. These values are considered to be reserved in certain environments.
The Mode parameter is used to specify the mode of the object, indicating its associated file type and permission bits. This parameter should be set to a combination of the following bit flags, as defined in the UNIX standard sys/stat.h header:
File Type
S_IFLNK | 0xA000 | Identifies a symbolic link. |
S_IFREG | 0x8000 | Identifies a regular file. |
S_IFDIR | 0x4000 | Identifies a directory. |
File Mode Bits
S_ISUID | 0x0800 | Set user ID on execution. |
S_ISGID | 0x0400 | Set group ID on execution. |
S_ISVTX | 0x0200 | Save text even after use. |
S_IRUSR | 0x0100 | Read permission, owner. |
S_IWUSR | 0x0080 | Write permission, owner. |
S_IXUSR | 0x0040 | Execute permission, owner. |
S_IRGRP | 0x0020 | Read permission, group. |
S_IWGRP | 0x0010 | Write permission, group. |
S_IXGRP | 0x0008 | Execute permission, group. |
S_IROTH | 0x0004 | Read permission, others. |
S_IWOTH | 0x0002 | Write permission, others. |
S_IXOTH | 0x0001 | Execute permission, others. |
The User parameter is used to provide the NFSv4.0 owner attribute, which is a string name of the owner of this filesystem object. Mode flags S_IRUSR, S_IWUSR, and S_IXUSR apply to the principal identified via the User parameter.
The Group parameter is used to provide the NFSv4.0 owner_group attribute, which is a string name of the group ownership of this filesystem object. Mode flags S_IRGRP, S_IWGRP, and S_IXGRP apply to the principals identified via the Group parameter.
Mode flags S_IROTH, S_IWOTH, and S_IXOTH apply to any principal that does that match the User and does not have a group matching the Group.
The LinkCount parameter is used to provide the NFSv4.0 numlinks attribute, which represents the number of hard links associated with this filesystem object.
The Size parameter is used to provide the NFSv4.0 size attribute, which represents the size of the filesystem object in bytes.
The ATime parameter is used to provide the NFSv4.0 time_access attribute, which represents the time of last access to the object by a Read operation sent to the server.
The MTime parameter is used to provide the NFSv4.0 time_modify attribute, which represents the time of the last modification to the object.
The CTime parameter is used to provide the NFSv4.0 time_create attribute, which represents the time the object was created (unrelated to the UNIX file attribute "ctime").
Error Handling (C++)
This method returns an Integer value; after it returns, call the GetLastErrorCode() method to obtain its result code; 0 indicates success, while a non-zero error code indicates that this method encountered an error during its execution. If an error occurs, the GetLastError() method can be called to retrieve the associated error message.
Shutdown Method (NFS Class)
This method shuts down the server.
Syntax
ANSI (Cross Platform) int Shutdown(); Unicode (Windows) INT Shutdown();
int cbfsconnect_nfs_shutdown(void* lpObj);
int Shutdown();
Remarks
This method shuts down the server. Calling this method is equivalent to calling StopListening and then breaking every client connection by calling Disconnect.
Error Handling (C++)
This method returns a result code; 0 indicates success, while a non-zero error code indicates that this method encountered an error during its execution. If an error occurs, the GetLastError() method can be called to retrieve the associated error message. (Note: This method's result code can also be obtained by calling the GetLastErrorCode() method after it returns.)
StartListening Method (NFS Class)
This method starts listening for incoming connections.
Syntax
ANSI (Cross Platform) int StartListening(); Unicode (Windows) INT StartListening();
int cbfsconnect_nfs_startlistening(void* lpObj);
int StartListening();
Remarks
This method starts listening for incoming connections on the port specified by LocalPort. Once listening, events will fire as new clients connect and data are transferred.
To stop listening for new connections, call StopListening. To stop listening for new connections and to disconnect all existing clients, call Shutdown.
To process incoming client data, call the DoEvents method. It may need to be called from the same thread or task, in which StartListening is called. Please refer to the DoEvents topic for details.
Error Handling (C++)
This method returns a result code; 0 indicates success, while a non-zero error code indicates that this method encountered an error during its execution. If an error occurs, the GetLastError() method can be called to retrieve the associated error message. (Note: This method's result code can also be obtained by calling the GetLastErrorCode() method after it returns.)
StopListening Method (NFS Class)
This method stops listening for new connections.
Syntax
ANSI (Cross Platform) int StopListening(); Unicode (Windows) INT StopListening();
int cbfsconnect_nfs_stoplistening(void* lpObj);
int StopListening();
Remarks
This method stops listening for new connections. After being called, any new connection attempts will be rejected. Calling this method does not disconnect existing connections.
To stop listening and disconnect all existing clients, call Shutdown instead.
Error Handling (C++)
This method returns a result code; 0 indicates success, while a non-zero error code indicates that this method encountered an error during its execution. If an error occurs, the GetLastError() method can be called to retrieve the associated error message. (Note: This method's result code can also be obtained by calling the GetLastErrorCode() method after it returns.)
Access Event (NFS Class)
This event fires when a client verifies their access permissions for an object.
Syntax
ANSI (Cross Platform) virtual int FireAccess(NFSAccessEventParams *e);
typedef struct {
int ConnectionId;
const char *Path;
int Access;
int Supported;
int Result; int reserved; } NFSAccessEventParams;
Unicode (Windows) virtual INT FireAccess(NFSAccessEventParams *e);
typedef struct {
INT ConnectionId;
LPCWSTR Path;
INT Access;
INT Supported;
INT Result; INT reserved; } NFSAccessEventParams;
#define EID_NFS_ACCESS 1 virtual INT CBFSCONNECT_CALL FireAccess(INT &iConnectionId, LPWSTR &lpszPath, INT &iAccess, INT &iSupported, INT &iResult);
class NFSAccessEventParams { public: int ConnectionId(); const QString &Path(); int Access(); void SetAccess(int iAccess); int Supported(); void SetSupported(int iSupported); int Result(); void SetResult(int iResult); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void Access(NFSAccessEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireAccess(NFSAccessEventParams *e) {...}
Remarks
This event fires when a client verifies their access permissions for an object, identified by the Path parameter.
The ConnectionId parameter indicates the client requesting the file access permissions.
The Access parameter contains an encoded bitmask of access rights that the application should check. This parameter can be a combination of the following flags (or access permissions):
ACCESS4_READ | 0x00000001 | Read data from a file or read a directory. |
ACCESS4_LOOKUP | 0x00000002 | Look up a name in a directory (no meaning for non-directory objects). |
ACCESS4_MODIFY | 0x00000004 | Rewrite existing file data or modify existing directory entries. |
ACCESS4_EXTEND | 0x00000008 | Write new data or add directory entries. |
ACCESS4_DELETE | 0x00000010 | Delete an existing directory entry. |
ACCESS4_EXECUTE | 0x00000020 | Execute a file (no meaning for a directory). |
To handle this event appropriately, the application should set the Supported parameter to the access rights which the server can verify reliably. The application should then set the Access parameter to the access rights available to this client for the specified object.
Note that the Supported parameter should only contain as many values as were originally present in the provided Access parameter. For example, if the client is only checking the ACCESS4_READ permission, the application should only set the ACCESS4_READ permission in Supported, assuming it can reliably verify this permission.
Assuming Result is set to NFS4_OK, this operation only serves as an advisement to the client. The return of a certain access permission does not imply such access for this object will be permitted in the future, as the application can revoke or change access rights at any time.
The Result parameter will always be 0 (NFS4_OK) when this event fires. If the event cannot be handled successfully, set it to a nonzero value to report an appropriate error. Possible Result codes and their descriptions are listed in the NFS Result Codes section. Additional information regarding these result codes may be found in RFC 7530 Section 13.
Chmod Event (NFS Class)
This event fires when a client attempts to modify the permission bits of an object.
Syntax
ANSI (Cross Platform) virtual int FireChmod(NFSChmodEventParams *e);
typedef struct {
int ConnectionId;
const char *Path;
void *FileContext;
int Mode;
int Result; int reserved; } NFSChmodEventParams;
Unicode (Windows) virtual INT FireChmod(NFSChmodEventParams *e);
typedef struct {
INT ConnectionId;
LPCWSTR Path;
LPVOID FileContext;
INT Mode;
INT Result; INT reserved; } NFSChmodEventParams;
#define EID_NFS_CHMOD 2 virtual INT CBFSCONNECT_CALL FireChmod(INT &iConnectionId, LPWSTR &lpszPath, LPVOID &lpFileContext, INT &iMode, INT &iResult);
class NFSChmodEventParams { public: int ConnectionId(); const QString &Path(); void *FileContext(); int Mode(); int Result(); void SetResult(int iResult); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void Chmod(NFSChmodEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireChmod(NFSChmodEventParams *e) {...}
Remarks
This event fires when a client attempts to modify the permission bits of an object, identified by the FileContext and/or Path parameters.
The ConnectionId parameter indicates the client attempting to set this attribute.
The Mode parameter specifies the new permission bits the client wishes to set for this object. The client may specify a combination of the following permission bits, as defined in the UNIX standard sys/stat.h header:
S_ISUID | 0x800 | Set user ID on execution. |
S_ISGID | 0x400 | Set group ID on execution. |
S_ISVTX | 0x200 | Save text even after use. |
S_IRUSR | 0x100 | Read permission, owner. |
S_IWUSR | 0x080 | Write permission, owner. |
S_IXUSR | 0x040 | Execute permission, owner. |
S_IRGRP | 0x020 | Read permission, group. |
S_IWGRP | 0x010 | Write permission, group. |
S_IXGRP | 0x008 | Execute permission, group. |
S_IROTH | 0x004 | Read permission, others. |
S_IWOTH | 0x002 | Write permission, others. |
S_IXOTH | 0x001 | Execute permission, others. |
Example: Modifying the permission bits and preserving stored file type
nfs.OnChmod += (o, e) => {
string path = "C:\\NFSRootDir" + e.Path;
int currentFileMode = GetFileMode(path); // Arbitrary function to retrieve stored mode
int currentType = currentFileMode & 0xF000; // 0xF000 == S_IFMT
// Client cannot change type bits, only permission bits
SetFileMode(e.Path, currentType | e.Mode);
};
The Result parameter will always be 0 (NFS4_OK) when this event fires.
If the event cannot be handled successfully, set it to a nonzero value to report an appropriate error.
Possible Result codes and their descriptions are listed in the NFS Result Codes section.
Additional information regarding these result codes may be found in RFC 7530 Section 13.
Chown Event (NFS Class)
This event fires when a client attempts to modify an object's owner attribute, group attribute, or both.
Syntax
ANSI (Cross Platform) virtual int FireChown(NFSChownEventParams *e);
typedef struct {
int ConnectionId;
const char *Path;
void *FileContext;
const char *User;
const char *Group;
int Result; int reserved; } NFSChownEventParams;
Unicode (Windows) virtual INT FireChown(NFSChownEventParams *e);
typedef struct {
INT ConnectionId;
LPCWSTR Path;
LPVOID FileContext;
LPCWSTR User;
LPCWSTR Group;
INT Result; INT reserved; } NFSChownEventParams;
#define EID_NFS_CHOWN 3 virtual INT CBFSCONNECT_CALL FireChown(INT &iConnectionId, LPWSTR &lpszPath, LPVOID &lpFileContext, LPWSTR &lpszUser, LPWSTR &lpszGroup, INT &iResult);
class NFSChownEventParams { public: int ConnectionId(); const QString &Path(); void *FileContext(); const QString &User(); const QString &Group(); int Result(); void SetResult(int iResult); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void Chown(NFSChownEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireChown(NFSChownEventParams *e) {...}
Remarks
This event fires when a client attempts to modify an object's owner attribute, group attribute, or both. The object is identified by the FileContext and/or Path parameters.
The ConnectionId parameter indicates the client attempting to set these attributes.
The User parameter indicates the desired value the client wishes to set the NFSv4.0 owner attribute to. The owner attribute specifies the owner of a file.
The Group parameter indicates the desired value the client wishes to set the NFSv4.0 owner_group attribute to. The owner_group attribute specifies the group ownership of a file.
Note that if the User or Group parameter is equal to an empty string, the client does not wish to modify the associated attribute and the parameter should be ignored.
The Result parameter will always be 0 (NFS4_OK) when this event fires. If the event cannot be handled successfully, set it to a nonzero value to report an appropriate error. Possible Result codes and their descriptions are listed in the NFS Result Codes section. Additional information regarding these result codes may be found in RFC 7530 Section 13.
Close Event (NFS Class)
This event fires when a client requests the closure of a previously opened file.
Syntax
ANSI (Cross Platform) virtual int FireClose(NFSCloseEventParams *e);
typedef struct {
int ConnectionId;
const char *Path;
void *FileContext;
int Result; int reserved; } NFSCloseEventParams;
Unicode (Windows) virtual INT FireClose(NFSCloseEventParams *e);
typedef struct {
INT ConnectionId;
LPCWSTR Path;
LPVOID FileContext;
INT Result; INT reserved; } NFSCloseEventParams;
#define EID_NFS_CLOSE 4 virtual INT CBFSCONNECT_CALL FireClose(INT &iConnectionId, LPWSTR &lpszPath, LPVOID &lpFileContext, INT &iResult);
class NFSCloseEventParams { public: int ConnectionId(); const QString &Path(); void *FileContext(); void SetFileContext(void *lpFileContext); int Result(); void SetResult(int iResult); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void Close(NFSCloseEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireClose(NFSCloseEventParams *e) {...}
Remarks
This event fires when a client requests the closure of a previously opened file, identified by the Path and/or FileContext parameters.
The ConnectionId parameter indicates the client performing this operation.
To handle this event properly, the application should release the share reservations for this specific file created during a previous Open operation. This operation is only applicable to the Open operation performed by a given client for the specified file and does not apply to any Open operations performed by other clients for the same file.
Note that clients should release any byte-range locks currently held for this file before this operation. However, applications should not assume this. In the event any relevant locks exist, the application may release all locks and return NFS4_OK. Alternatively, if the application chooses not to release the locks, it must respond with NFS4ERR_LOCKS_HELD, offloading the task to the client.
Assuming the operation was successful, applications should free the associated FileContext and set this parameter to IntPtr.Zero, if applicable.
The Result parameter will always be 0 (NFS4_OK) when this event fires. If the event cannot be handled successfully, set it to a nonzero value to report an appropriate error. Possible Result codes and their descriptions are listed in the NFS Result Codes section. Additional information regarding these result codes may be found in RFC 7530 Section 13.
Commit Event (NFS Class)
This event fires when a client attempts to flush any uncommitted file data from a previous Write operation to stable storage.
Syntax
ANSI (Cross Platform) virtual int FireCommit(NFSCommitEventParams *e);
typedef struct {
int ConnectionId;
const char *Path;
void *FileContext;
int64 Offset;
int Count;
int Result; int reserved; } NFSCommitEventParams;
Unicode (Windows) virtual INT FireCommit(NFSCommitEventParams *e);
typedef struct {
INT ConnectionId;
LPCWSTR Path;
LPVOID FileContext;
LONG64 Offset;
INT Count;
INT Result; INT reserved; } NFSCommitEventParams;
#define EID_NFS_COMMIT 5 virtual INT CBFSCONNECT_CALL FireCommit(INT &iConnectionId, LPWSTR &lpszPath, LPVOID &lpFileContext, LONG64 &lOffset, INT &iCount, INT &iResult);
class NFSCommitEventParams { public: int ConnectionId(); const QString &Path(); void *FileContext(); qint64 Offset(); int Count(); int Result(); void SetResult(int iResult); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void Commit(NFSCommitEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireCommit(NFSCommitEventParams *e) {...}
Remarks
This event fires when a client attempts to flush any uncommitted file data from a previous Write operation to stable storage. The file is identified by the FileContext and/or Path parameters.
The ConnectionId parameter indicates the client performing this operation.
The data to flush to stable storage is the data that was cached in a previous Write operation. This operation will only occur when the previous Write operation returns a commitment level of UNSTABLE4 or DATA_SYNC4 to the client. If FILE_SYNC4 was returned previously and all data was written to stable storage, this event will not fire.
Note that the application may cache multiple Write operations. If the Offset and Count parameters are equal to zero, this indicates that the application should flush all cached data, buffered with each previous Write operation, for this file to stable storage.
It is also possible that Offset and Count are non-zero. In this case, the application should flush only the specified cached data, buffered with a specific Write operation.
If the data has already been written to stable storage, and no cached data exists for this value (depending on Offset and Count), the operation should succeed.
The Result parameter will always be 0 (NFS4_OK) when this event fires. If the event cannot be handled successfully, set it to a nonzero value to report an appropriate error. Possible Result codes and their descriptions are listed in the NFS Result Codes section. Additional information regarding these result codes may be found in RFC 7530 Section 13.
Connected Event (NFS Class)
This event fires immediately after a connection completes (or fails).
Syntax
ANSI (Cross Platform) virtual int FireConnected(NFSConnectedEventParams *e);
typedef struct {
int ConnectionId;
int StatusCode;
const char *Description; int reserved; } NFSConnectedEventParams;
Unicode (Windows) virtual INT FireConnected(NFSConnectedEventParams *e);
typedef struct {
INT ConnectionId;
INT StatusCode;
LPCWSTR Description; INT reserved; } NFSConnectedEventParams;
#define EID_NFS_CONNECTED 6 virtual INT CBFSCONNECT_CALL FireConnected(INT &iConnectionId, INT &iStatusCode, LPWSTR &lpszDescription);
class NFSConnectedEventParams { public: int ConnectionId(); int StatusCode(); const QString &Description(); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void Connected(NFSConnectedEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireConnected(NFSConnectedEventParams *e) {...}
Remarks
If the connection is made normally, StatusCode is 0, and Description is "OK".
If the connection fails, StatusCode has the error code returned by the system. Description contains a description of this code. The value of StatusCode is equal to the value of the system error.
Please refer to the Error Codes section for more information.
ConnectionRequest Event (NFS Class)
This event fires when a connection request comes from a remote host.
Syntax
ANSI (Cross Platform) virtual int FireConnectionRequest(NFSConnectionRequestEventParams *e);
typedef struct {
const char *Address;
int Port;
int Accept; int reserved; } NFSConnectionRequestEventParams;
Unicode (Windows) virtual INT FireConnectionRequest(NFSConnectionRequestEventParams *e);
typedef struct {
LPCWSTR Address;
INT Port;
BOOL Accept; INT reserved; } NFSConnectionRequestEventParams;
#define EID_NFS_CONNECTIONREQUEST 7 virtual INT CBFSCONNECT_CALL FireConnectionRequest(LPWSTR &lpszAddress, INT &iPort, BOOL &bAccept);
class NFSConnectionRequestEventParams { public: const QString &Address(); int Port(); bool Accept(); void SetAccept(bool bAccept); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void ConnectionRequest(NFSConnectionRequestEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireConnectionRequest(NFSConnectionRequestEventParams *e) {...}
Remarks
This event indicates an incoming connection. The connection is accepted by default. Address and Port will contain information about the remote host requesting the inbound connection. If you want to refuse it, you can set the Accept parameter to False.
CreateLink Event (NFS Class)
This event fires when a client attempts to create a symbolic link or hard link.
Syntax
ANSI (Cross Platform) virtual int FireCreateLink(NFSCreateLinkEventParams *e);
typedef struct {
int ConnectionId;
const char *Path;
const char *Name;
const char *LinkTarget; int lenLinkTarget;
int LinkType;
void *FileContext;
int Result; int reserved; } NFSCreateLinkEventParams;
Unicode (Windows) virtual INT FireCreateLink(NFSCreateLinkEventParams *e);
typedef struct {
INT ConnectionId;
LPCWSTR Path;
LPCWSTR Name;
LPCSTR LinkTarget; INT lenLinkTarget;
INT LinkType;
LPVOID FileContext;
INT Result; INT reserved; } NFSCreateLinkEventParams;
#define EID_NFS_CREATELINK 8 virtual INT CBFSCONNECT_CALL FireCreateLink(INT &iConnectionId, LPWSTR &lpszPath, LPWSTR &lpszName, LPSTR &lpLinkTarget, INT &lenLinkTarget, INT &iLinkType, LPVOID &lpFileContext, INT &iResult);
class NFSCreateLinkEventParams { public: int ConnectionId(); const QString &Path(); const QString &Name(); const QByteArray &LinkTarget(); int LinkType(); void *FileContext(); void SetFileContext(void *lpFileContext); int Result(); void SetResult(int iResult); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void CreateLink(NFSCreateLinkEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireCreateLink(NFSCreateLinkEventParams *e) {...}
Remarks
This event fires when a client attempts to create a symbolic link or hard link.
The Path parameter identifies the location and name of this link. The Name parameter identifies only the name of this link. If an object exists with the same path and name, the operation should fail and Result should be set to NFS4ERR_EXIST.
The ConnectionId parameter indicates the client attempting to create the link.
The LinkType parameter indicates the type of link the client is attempting to create. The following values are applicable:
0 | Indicates the client is attempting to create a symbolic link. |
1 | Indicates the client is attempting to create a hard link. |
Please see below for additional details on how the application should handle this event for each type of link.
Symbolic Links
If LinkType is equal to 0, the client is attempting to create a symbolic link. An object should be created at the specified Path that, in future operations, can be identified as a symbolic link and can be used to return the content of the symbolic link.
The LinkTarget parameter provides the content of the symbolic link, as sent by the client. Note that the content should be treated as opaque by the server, i.e., the server does not need to interpret the data. It is possible that a client will provide a pathname that is not meaningful to the application. Therefore, it is the client's responsibility to interpret the content of the symbolic link. Although UTF-8 encoding is often used, it is not a requirement. In that regard, the content of a symbolic link is like the content of a regular file.
In many cases, the LinkTarget will be a UTF-8 string, though as mentioned, this is not a requirement. Applications should ensure that the exact contents of the LinkTarget are returned to the client in ReadLink.
Hard Links
If LinkType is equal to 1, the client is attempting to create a hard link.
In the case of a hard link, the LinkTarget indicates an existing file that the new object, identified by Path, will point to. Unlike with symbolic links, the LinkTarget parameter is guaranteed to be a UTF-8 string, and will contain the exact file path the hard link should target.
To handle this appropriately, the application should create an object at the specified Path that points to the data associated with the LinkTarget. Changes to any property of the LinkTarget are reflected in all linked files.
Depending on the underlying filesystem, "." and ".." are illegal values for a new object name. In this case, Result should be set to NFS4ERR_BADNAME and the operation should fail.
Additionally, if the new object name has a length of 0, or does not obey the UTF-8 definition, Result should be set to NFS4ERR_INVAL.
Please see below for an example handling both symbolic and hard links.
nfs.OnCreateLink += (o, e) => {
string linkname = GetRealPath(root, e.Path);
if (File.Exists(linkname)) {
e.Result = NFS4ERR_EXIST;
return;
}
// Symbolic link
if (e.LinkType == 0) {
try {
// CreateSymbolicLink function from kernel32.dll
CreateSymbolicLink(linkname, e.LinkTarget, 0);
} catch (Exception ex) {
e.Result = NFS4ERR_IO;
}
return;
}
string target = GetRealPath(root, e.LinkTarget);
// Hard link
if (e.LinkType == 1) {
try {
// CreateHardLink function from kernel32.dll
CreateHardLink(linkname, target, IntPtr.Zero);
} catch (Exception ex) {
e.Result = NFS4ERR_IO;
}
}
};
Disconnected Event (NFS Class)
This event fires when a connection is closed.
Syntax
ANSI (Cross Platform) virtual int FireDisconnected(NFSDisconnectedEventParams *e);
typedef struct {
int ConnectionId;
int StatusCode;
const char *Description; int reserved; } NFSDisconnectedEventParams;
Unicode (Windows) virtual INT FireDisconnected(NFSDisconnectedEventParams *e);
typedef struct {
INT ConnectionId;
INT StatusCode;
LPCWSTR Description; INT reserved; } NFSDisconnectedEventParams;
#define EID_NFS_DISCONNECTED 9 virtual INT CBFSCONNECT_CALL FireDisconnected(INT &iConnectionId, INT &iStatusCode, LPWSTR &lpszDescription);
class NFSDisconnectedEventParams { public: int ConnectionId(); int StatusCode(); const QString &Description(); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void Disconnected(NFSDisconnectedEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireDisconnected(NFSDisconnectedEventParams *e) {...}
Remarks
If the connection is broken normally, StatusCode is 0, and Description is "OK".
If the connection is broken for any other reason, StatusCode has the error code returned by the system. Description contains a description of this code. The value of StatusCode is equal to the value of the system error.
Please refer to the Error Codes section for more information.
Error Event (NFS Class)
This event fires information about errors during data delivery.
Syntax
ANSI (Cross Platform) virtual int FireError(NFSErrorEventParams *e);
typedef struct {
int ConnectionId;
int ErrorCode;
const char *Description; int reserved; } NFSErrorEventParams;
Unicode (Windows) virtual INT FireError(NFSErrorEventParams *e);
typedef struct {
INT ConnectionId;
INT ErrorCode;
LPCWSTR Description; INT reserved; } NFSErrorEventParams;
#define EID_NFS_ERROR 10 virtual INT CBFSCONNECT_CALL FireError(INT &iConnectionId, INT &iErrorCode, LPWSTR &lpszDescription);
class NFSErrorEventParams { public: int ConnectionId(); int ErrorCode(); const QString &Description(); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void Error(NFSErrorEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireError(NFSErrorEventParams *e) {...}
Remarks
The Error event is fired in case of exceptional conditions during message processing. Normally, the class fails with an error.
ErrorCode contains an error code and Description contains a textual description of the error. For a list of valid error codes and their descriptions, please refer to the Error Codes section.
ConnectionId indicates the connection for which the error is applicable.
GetAttr Event (NFS Class)
This event fires when a client requests attributes for an object (such as the owner, group, or mode attributes).
Syntax
ANSI (Cross Platform) virtual int FireGetAttr(NFSGetAttrEventParams *e);
typedef struct {
int ConnectionId;
const char *Path;
void *FileContext;
int64 *pFileId;
int Mode;
char *User;
char *Group;
int LinkCount;
int64 *pSize;
int64 *pATime;
int64 *pMTime;
int64 *pCTime;
char *NFSHandle;
int Result; int reserved; } NFSGetAttrEventParams;
Unicode (Windows) virtual INT FireGetAttr(NFSGetAttrEventParams *e);
typedef struct {
INT ConnectionId;
LPCWSTR Path;
LPVOID FileContext;
LONG64 *pFileId;
INT Mode;
LPWSTR User;
LPWSTR Group;
INT LinkCount;
LONG64 *pSize;
LONG64 *pATime;
LONG64 *pMTime;
LONG64 *pCTime;
LPWSTR NFSHandle;
INT Result; INT reserved; } NFSGetAttrEventParams;
#define EID_NFS_GETATTR 11 virtual INT CBFSCONNECT_CALL FireGetAttr(INT &iConnectionId, LPWSTR &lpszPath, LPVOID &lpFileContext, LONG64 &lFileId, INT &iMode, LPWSTR &lpszUser, LPWSTR &lpszGroup, INT &iLinkCount, LONG64 &lSize, LONG64 &lATime, LONG64 &lMTime, LONG64 &lCTime, LPWSTR &lpszNFSHandle, INT &iResult);
class NFSGetAttrEventParams { public: int ConnectionId(); const QString &Path(); void *FileContext(); qint64 FileId(); void SetFileId(qint64 lFileId); int Mode(); void SetMode(int iMode); const QString &User(); void SetUser(const QString &qsUser); const QString &Group(); void SetGroup(const QString &qsGroup); int LinkCount(); void SetLinkCount(int iLinkCount); qint64 Size(); void SetSize(qint64 lSize); const QDateTime &ATime(); void SetATime(const QDateTime &qdtATime); const QDateTime &MTime(); void SetMTime(const QDateTime &qdtMTime); const QDateTime &CTime(); void SetCTime(const QDateTime &qdtCTime); const QString &NFSHandle(); void SetNFSHandle(const QString &qsNFSHandle); int Result(); void SetResult(int iResult); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void GetAttr(NFSGetAttrEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireGetAttr(NFSGetAttrEventParams *e) {...}
Remarks
This event fires when a client requests attributes for an object (such as the owner, group, or mode attributes), identified by the FileContext, NFSHandle, and/or Path parameters.
The NFSHandle parameter is the hex-encoded value of the internal file handle representation. By default, this parameter is calculated as the PPMD-compressed value of the Path. Assuming this format is used, the class will be able to decompress this handle and obtain the Path, if necessary for future operations.
This functionality is particularly useful in the event the server restarts. Assuming a client maintains their mount, the client may continue to utilize their cached file handles. Because the server was restarted, the class would typically be unable to recognize the received handle, and report the handle as stale. However, assuming the defualt format is used, the class will be able to decompress the file handle, retrieve the Path, and check the object's existence by firing Lookup.
Note that at the protocol-level, file handles must be no more than 128 bytes (NFS4_FHSIZE). It is possible that the PPMD-compressed value of the Path is greater than 128 bytes, though this is unlikely, as the Path would need to be very large. In this case, the NFSHandle will instead be calculated as the SHA256 hash of the Path, which may result in stale file handles in the event of a server restart.
The ConnectionId parameter indicates the client requesting information about the filesystem object.
To handle this event properly, applications should set the below parameters to relevant attributes of the filesystem object.
The FileId parameter assigns a unique identifier to the file within the filesystem. If specified as 0 (default), the class generates an Id based on the checksum value of the Path. Therefore, if this parameter is set to 0 or remains unmodified, the generated Id is guaranteed to be unique for a specific Path, and persist across server restarts assuming equivalent paths.
The Mode parameter is used to specify the mode of the object, indicating its associated file type and permission bits. This parameter should be set to a combination of the following flags, as defined in the UNIX standard sys/stat.h header:
File Type
S_IFLNK | 0xA000 | Identifies a symbolic link. |
S_IFREG | 0x8000 | Identifies a regular file. |
S_IFDIR | 0x4000 | Identifies a directory. |
File Mode Bits
S_ISUID | 0x0800 | Set user ID on execution. |
S_ISGID | 0x0400 | Set group ID on execution. |
S_ISVTX | 0x0200 | Save text even after use. |
S_IRUSR | 0x0100 | Read permission, owner. |
S_IWUSR | 0x0080 | Write permission, owner. |
S_IXUSR | 0x0040 | Execute permission, owner. |
S_IRGRP | 0x0020 | Read permission, group. |
S_IWGRP | 0x0010 | Write permission, group. |
S_IXGRP | 0x0008 | Execute permission, group. |
S_IROTH | 0x0004 | Read permission, others. |
S_IWOTH | 0x0002 | Write permission, others. |
S_IXOTH | 0x0001 | Execute permission, others. |
The User parameter is used to set the NFSv4.0 owner attribute, which is a string name of the owner of this filesystem object. Mode flags S_IRUSR, S_IWUSR, and S_IXUSR apply to the principal identified via the User parameter.
The Group parameter is used to set the NFSv4.0 owner_group attribute, which is a string name of the group ownership of this filesystem object. Mode flags S_IRGRP, S_IWGRP, and S_IXGRP apply to the principals identified via the Group parameter.
Mode flags S_IROTH, S_IWOTH, and S_IXOTH apply to any principal that does not match the User and does not have a group matching the Group.
The LinkCount parameter is used to set the NFSv4.0 numlinks attribute, which represents the number of hard links associated with this filesystem object.
The Size parameter is used to set the NFSv4.0 size attribute, which represents the size of the filesystem object in bytes.
The ATime parameter is used to set the NFSv4.0 time_access attribute, which represents the time of last access to the object by a Read operation sent to the server.
The MTime parameter is used to set the NFSv4.0 time_modify attribute, which represents the time of the last modification to the object.
The CTime parameter is used to set the NFSv4.0 time_create attribute, which represents the time the object was created (unrelated to the UNIX file attribute "ctime").
Example: Retrieving file or directory attributes
nfs.OnGetAttr += (o, e) => {
string path = "C:\\NFSRootDir" + e.Path;
if (!File.Exists(path) && !Directory.Exists(path)) {
e.Result = NFS4ERR_NOENT;
return;
}
e.User = OWNER;
e.Group = OWNER_GROUP;
e.LinkCount = 1;
if (Directory.Exists(path)) {
int fileMode = S_IFDIR | S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; // Indicates file type (S_IFDIR) and permissions (755)
e.Mode = fileMode;
e.Size = 4096;
e.ATime = Directory.GetLastAccessTime(real);
e.CTime = Directory.GetCreationTime(real);
e.MTime = Directory.GetLastWriteTime(real);
} else {
int fileMode = S_IFREG | S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH; // Indicates file type (S_IFREG) and permissions (644)
e.Mode = fileMode;
e.Size = new FileInfo(path).Length;
e.ATime = File.GetLastAccessTime(path);
e.MTime = File.GetLastWriteTime(path);
e.CTime = File.GetCreationTime(path);
}
};
The Result parameter will always be 0 (NFS4_OK) when this event fires.
If the event cannot be handled successfully, set it to a nonzero value to report an appropriate error.
Possible Result codes and their descriptions are listed in the NFS Result Codes section.
Additional information regarding these result codes may be found in RFC 7530 Section 13.
Lock Event (NFS Class)
This event fires when a client attempts to create or test a byte-range lock for a file.
Syntax
ANSI (Cross Platform) virtual int FireLock(NFSLockEventParams *e);
typedef struct {
int ConnectionId;
const char *Path;
void *FileContext;
int LockType;
int64 *pLockOffset;
int64 *pLockLen;
int Test;
int Result; int reserved; } NFSLockEventParams;
Unicode (Windows) virtual INT FireLock(NFSLockEventParams *e);
typedef struct {
INT ConnectionId;
LPCWSTR Path;
LPVOID FileContext;
INT LockType;
LONG64 *pLockOffset;
LONG64 *pLockLen;
BOOL Test;
INT Result; INT reserved; } NFSLockEventParams;
#define EID_NFS_LOCK 12 virtual INT CBFSCONNECT_CALL FireLock(INT &iConnectionId, LPWSTR &lpszPath, LPVOID &lpFileContext, INT &iLockType, LONG64 &lLockOffset, LONG64 &lLockLen, BOOL &bTest, INT &iResult);
class NFSLockEventParams { public: int ConnectionId(); const QString &Path(); void *FileContext(); int LockType(); qint64 LockOffset(); void SetLockOffset(qint64 lLockOffset); qint64 LockLen(); void SetLockLen(qint64 lLockLen); bool Test(); int Result(); void SetResult(int iResult); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void Lock(NFSLockEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireLock(NFSLockEventParams *e) {...}
Remarks
This event fires when a client attempts to create or test a byte-range lock for a file, indicated by the FileContext or Path parameters.
The ConnectionId parameter indicates the client requesting the lock.
The LockOffset parameter specifies the position (or byte) within the file where the lock should begin. The LockLen parameter specifies the number of bytes that should be locked after the specified offset, indicating a range of bytes to lock. If the LockLen parameter is 0, the application should return NFS4ERR_INVAL. If the LockLen parameter is -1, this indicates the client wishes to lock all bytes from the specified LockOffset to the end of the file.
The LockType parameter specifies the type of lock to be created or tested on the file (read or write, blocking or non-blocking). This parameter may be equal to one of the following values:
READ_LT | 1 | Indicates a non-blocking read lock. |
WRITE_LT | 2 | Indicates a non-blocking write lock. |
READW_LT | 3 | Indicates a blocking read lock. |
WRITEW_LT | 4 | Indicates a blocking write lock. |
Note a blocking lock type indicates the client wishes to 'wait' for the mentioned lock if a conflicting lock exists. Please see below for more information regarding blocking locks.
To handle this event properly, applications should determine whether the client wishes to create or test the lock by examining the Test parameter.
Testing a Lock
If the Test parameter is True, the client only intends to test the lock. In this case, no lock should be created. First, the application should determine whether a conflicting lock exists for this file based on the semantics of the server-exported file system. The test for a conflicting lock should exclude any locks held by the client making this request, identified by ConnectionId. If a conflicting lock exists, the application should set the LockOffset and LockLen parameters to that of the conflicting lock and return NFS4ERR_DENIED.
If the application chooses not to exclude these locks, and the client making this request owns the conflicting lock, NFS4ERR_LOCK_RANGE may be returned if any overlap exists between the conflicting lock and the range specified by LockOffset and LockLen.
Additionally, when Test is True, the lock types READ_LT and READW_LT should be interpreted in the same way, without regard to blocking or non-blocking behavior. This is also true for READW_LT and WRITEW_LT.
If no conflicting lock exists, no lock should be created and the operation should succeed.
Creating a Lock
If the Test parameter is False, the client wishes to create the lock. First, the application should determine whether a conflicting lock exists for this file based on the semantics of the server-exported file system. If the client making this request is the owner of the conflicting lock, NFS4ERR_LOCK_RANGE may be returned under the same conditions as described when testing a lock. Otherwise, the application should set the LockOffset and LockLen parameters to that of the conflicting lock and return NFS4ERR_DENIED. If the conflicting lock's offset and length cannot be determined by the application, the corresponding parameters should remain unchanged and NFS4ERR_DENIED should be returned.
If no conflicting lock exists, the application should create the lock and the operation should succeed.
Upgrading and Downgrading Locks
If a client has an existing write lock, they may request an atomic downgrade of the lock to a read lock. This is done by sending a LOCK request with the same LockOffset and LockLen, but specifying the LockType as READ_LT.
If a client has an existing read lock, they may request an atomic upgrade of the lock to a write lock. This is done by sending a LOCK request with the same LockOffset and LockLen, but specifying the LockType as WRITE_LT or WRITEW_LT. If a conflicting lock exists, the application should set the LockOffset and LockLen parameters to that of the conflicting lock and return NFS4ERR_DENIED. Additionally, if the LockType is specified as WRITEW_LT, the application should return NFS4ERR_DEADLOCK if a deadlock condition is detected.
In either case, if the application does not support upgrading or downgrading a lock, NFS4ERR_LOCK_NOTSUPP should be returned.
Blocking Locks
To ensure fairness and to support blocking locks, applications may maintain an ordered list of clients waiting to obtain a conflicting lock. Note this is only applicable to blocking locks. If implemented, it's important to note that clients will poll for the lock, following up with the identical lock request until accepted. Once a conflicting lock is released, the application may wait a fixed time (lease period) to grant the lock to the first waiting client. Since clients will poll for previously denied locks, this period ensures the client still wants the lock. If the application does not receive the re-request within this period, the application should assume the client no longer wants the lock, and the client should be removed from the ordered list. This process repeats with the next waiting client, and so on.
If implementing an ordered list, it may be the case that a waiting client sends the same lock request with a non-blocking lock type specified. If this occurs and the non-blocking request is denied, it can be assumed the client will no longer poll for this lock. The client may then be removed from the ordered list.
If the application determines a file locking deadlock condition would exist after a specific lock request, Result should be set to NFS4ERR_DEADLOCK.
The Result parameter will always be 0 (NFS4_OK) when this event fires. If the event cannot be handled successfully, set it to a nonzero value to report an appropriate error. Possible Result codes and their descriptions are listed in the NFS Result Codes section. Additional information regarding these result codes may be found in RFC 7530 Section 13.
Log Event (NFS Class)
This event fires once for each log message.
Syntax
ANSI (Cross Platform) virtual int FireLog(NFSLogEventParams *e);
typedef struct {
int ConnectionId;
int LogLevel;
const char *Message;
const char *LogType; int reserved; } NFSLogEventParams;
Unicode (Windows) virtual INT FireLog(NFSLogEventParams *e);
typedef struct {
INT ConnectionId;
INT LogLevel;
LPCWSTR Message;
LPCWSTR LogType; INT reserved; } NFSLogEventParams;
#define EID_NFS_LOG 13 virtual INT CBFSCONNECT_CALL FireLog(INT &iConnectionId, INT &iLogLevel, LPWSTR &lpszMessage, LPWSTR &lpszLogType);
class NFSLogEventParams { public: int ConnectionId(); int LogLevel(); const QString &Message(); const QString &LogType(); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void Log(NFSLogEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireLog(NFSLogEventParams *e) {...}
Remarks
This event fires once for each log message generated by the class. The verbosity is controlled by the LogLevel configuration.
LogLevel indicates the detail level of the message. Possible values are:
0 (None) | No messages are logged. |
1 (Info - Default) | Informational events are logged. |
2 (Verbose) | Detailed data is logged. |
3 (Debug) | Debug data including all sent and received NFS operations are logged. |
Message is the log message.
LogType identifies the type of log entry. Possible values are as follows:
- NFS
ConnectionId identifies the connection to which the log message applies.
Lookup Event (NFS Class)
This event fires when the class needs to determine the existence of an object in the current directory.
Syntax
ANSI (Cross Platform) virtual int FireLookup(NFSLookupEventParams *e);
typedef struct {
int ConnectionId;
const char *Name;
const char *Path;
int Result; int reserved; } NFSLookupEventParams;
Unicode (Windows) virtual INT FireLookup(NFSLookupEventParams *e);
typedef struct {
INT ConnectionId;
LPCWSTR Name;
LPCWSTR Path;
INT Result; INT reserved; } NFSLookupEventParams;
#define EID_NFS_LOOKUP 14 virtual INT CBFSCONNECT_CALL FireLookup(INT &iConnectionId, LPWSTR &lpszName, LPWSTR &lpszPath, INT &iResult);
class NFSLookupEventParams { public: int ConnectionId(); const QString &Name(); const QString &Path(); int Result(); void SetResult(int iResult); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void Lookup(NFSLookupEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireLookup(NFSLookupEventParams *e) {...}
Remarks
This event fires when the class needs to determine the existence of an object in the current directory. The Path parameter identifies the location and name of this object. The Name parameter identifies only the name of this object.
The ConnectionId parameter indicates the client this information is required for.
The existence of a filesystem object can be requested in either of the following cases:
- When a client is attempting to open and/or create a regular file. In this case, Open will fire shortly after this event returns.
- When a client is performing a LOOKUP operation on a filesystem object.
- When a client sends an unknown file handle value. In this case, the class will attempt to decompress the handle to obtain the relevant Path, and will check the existence of the object. See GetAttr for additional details.
To handle this event properly, the application should check whether this object exists within the specified directory. If the object does not exist, the Result parameter should be set to NFS4ERR_NOENT. Otherwise, NFS4_OK indicates the object exists.
Example: Check if object exists
nfs.OnLookup += (o, e) => {
string path = e.Path; // Varies depending on underlying filesystem implementation
if (File.Exists(path)) {
return;
}
if (Directory.Exists(path)) {
return;
}
// Object does not exist
e.Result = NFS4ERR_NOENT;
};
The Result parameter will always be 0 (NFS4_OK) when this event fires. If the event cannot be handled successfully, set it to a nonzero value to report an appropriate error. Possible Result codes and their descriptions are listed in the NFS Result Codes section. Additional information regarding these result codes may be found in RFC 7530 Section 13.
MkDir Event (NFS Class)
This event fires when a client attempts to create a new directory.
Syntax
ANSI (Cross Platform) virtual int FireMkDir(NFSMkDirEventParams *e);
typedef struct {
int ConnectionId;
const char *Path;
int Result; int reserved; } NFSMkDirEventParams;
Unicode (Windows) virtual INT FireMkDir(NFSMkDirEventParams *e);
typedef struct {
INT ConnectionId;
LPCWSTR Path;
INT Result; INT reserved; } NFSMkDirEventParams;
#define EID_NFS_MKDIR 15 virtual INT CBFSCONNECT_CALL FireMkDir(INT &iConnectionId, LPWSTR &lpszPath, INT &iResult);
class NFSMkDirEventParams { public: int ConnectionId(); const QString &Path(); int Result(); void SetResult(int iResult); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void MkDir(NFSMkDirEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireMkDir(NFSMkDirEventParams *e) {...}
Remarks
This event fires when a client attempts to create a new directory, identified by the Path parameter.
The ConnectionId parameter indicates the client attempting to create a directory.
The Result parameter will always be 0 (NFS4_OK) when this event fires. If the event cannot be handled successfully, set it to a nonzero value to report an appropriate error. Possible Result codes and their descriptions are listed in the NFS Result Codes section. Additional information regarding these result codes may be found in RFC 7530 Section 13.
Open Event (NFS Class)
This event fires when a client attempts to create or open a file.
Syntax
ANSI (Cross Platform) virtual int FireOpen(NFSOpenEventParams *e);
typedef struct {
int ConnectionId;
const char *Path;
int ShareAccess;
int ShareDeny;
int CreateMode;
int OpenType;
void *FileContext;
int Result; int reserved; } NFSOpenEventParams;
Unicode (Windows) virtual INT FireOpen(NFSOpenEventParams *e);
typedef struct {
INT ConnectionId;
LPCWSTR Path;
INT ShareAccess;
INT ShareDeny;
INT CreateMode;
INT OpenType;
LPVOID FileContext;
INT Result; INT reserved; } NFSOpenEventParams;
#define EID_NFS_OPEN 16 virtual INT CBFSCONNECT_CALL FireOpen(INT &iConnectionId, LPWSTR &lpszPath, INT &iShareAccess, INT &iShareDeny, INT &iCreateMode, INT &iOpenType, LPVOID &lpFileContext, INT &iResult);
class NFSOpenEventParams { public: int ConnectionId(); const QString &Path(); int ShareAccess(); int ShareDeny(); int CreateMode(); int OpenType(); void *FileContext(); void SetFileContext(void *lpFileContext); int Result(); void SetResult(int iResult); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void Open(NFSOpenEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireOpen(NFSOpenEventParams *e) {...}
Remarks
This event fires when a client attempts to create or open a file. This event is not applicable to directories (please see MkDir, ReadDir, and RmDir for further details).
The client where the request originates from is specified via ConnectionId.
The Path parameter contains the path to the file to open, along with the file name. Unless the file is already open, the FileContext parameter will initially be IntPtr.Zero. The application may use the FileContext parameter to store a file handle or other information related to the open file.
To appropriately handle this event, the application should perform any actions needed to create or open the requested file as indicated by the OpenType and CreateMode parameters, with the desired share reservations as specified by the ShareAccess and ShareDeny parameters. Please see the parameter descriptions below for additional information.
The OpenType parameter specifies how the client would like to open the file. This parameter may be equal to one of the following values:
OPEN4_NOCREATE | 0 | Indicates the file should be opened if it exists, but if the file does not exist, the file should not be created. In this case, the operation should fail with the error NFS4ERR_NOENT. |
OPEN4_CREATE | 1 | Indicates the file should be created using the method specified by the CreateMode parameter. |
The CreateMode parameter indicates the file creation method specified by the client. This parameter is only relevant when OpenType is equal to rsOPEN4CREATE;, and may be equal to one of the following values:
UNCHECKED4 | 0 | Indicates the file should be created without checking for the existence of a duplicate file in the associated directory. |
GUARDED4 | 1 | Indicates the file should be created, but the server should check for the presence of a duplicate file before doing so. If the file exists, the open operation should fail with the error NFS4ERR_EXIST. |
EXCLUSIVE4 | 2 | Indicates the file should be exclusively created, or created with the condition that no other client should be concurrently creating or opening a file with the same name. If a file with the same name does exist, the operation should fail with the error NFS4ERR_EXIST. |
Note GUARDED4 only indicates that if the file already exists, the OPEN operation will fail. It does not imply exclusive creation, which would ensure only one client can create or open a file with a specific name at once. If the mentioned exclusive creation semantics cannot be supported by the file system, the OPEN operation should fail and NFS4ERR_NOTSUPP should be returned.
The ShareAccess parameter specifies the client's desired share access utilized when opening a file. This value may be equal to one of the following access flags:
OPEN4_SHARE_ACCESS_READ | 0x00000001 | Indicates the client desires read-only access to the file. |
OPEN4_SHARE_ACCESS_WRITE | 0x00000002 | Indicates the client desires write-only access to the file. |
OPEN4_SHARE_ACCESS_BOTH | 0x00000003 | Indicates the client desires both read and write access to the file. |
In the case that there is an existing share reservation that conflicts with the request, NFS4ERR_SHARE_DENIED should be returned. If the underlying file system is only accessible in a read-only mode, and OPEN4_SHARE_ACCESS_WRITE or OPEN4_SHARE_ACCESS_BOTH are requested, NFS4ERR_ROFS should be returned to indicate a read-only file system.
The ShareDeny parameter defines the client's desired restrictions on share access for other clients when this file is open. This value may be equal to one of the following deny flags:
OPEN4_SHARE_DENY_NONE | 0x00000000 | Indicates no denial of share access to other clients while the file is open. |
OPEN4_SHARE_DENY_READ | 0x00000001 | Indicates denial of read access to other clients while the file is open. |
OPEN4_SHARE_DENY_WRITE | 0x00000002 | Indicates denial of write access to other clients while the file is open. |
OPEN4_SHARE_DENY_BOTH | 0x00000003 | Indicates denial of both read and write access to other clients while the file is open. |
Note that if OPEN4_SHARE_DENY_WRITE or OPEN4_SHARE_DENY_BOTH are specified and Unlink is fired while the object is still open, the application should not delete the file. If OPEN4_SHARE_DENY_NONE or OPEN4_SHARE_DENY_READ are specified and Unlink is fired while the object is still open, the application should delete the file.
Example: Opening or creating a file with share reservations
nfs.OnOpen += (o, e) => {
string path = "C:\\NFSRootDir" + e.Path;
FileStream fs = null;
FileAccess shareAccess = (FileAccess)e.ShareAccess; // ShareAccess correlates directly with FileAccess
FileShare shareDeny = 0; // ShareDeny does not correlate directly with FileShare, so let's translate ShareDeny to FileShare
switch (e.ShareDeny)
{
case OPEN4_SHARE_DENY_BOTH:
{
shareDeny = FileShare.None; // Allow no access by other clients
break;
}
case OPEN4_SHARE_DENY_WRITE:
{
shareDeny = FileShare.Read; // Allow read access by other clients
break;
}
case OPEN4_SHARE_DENY_READ:
{
shareDeny = FileShare.Write | FileShare.Delete; // Allow write access and deletion by other clients
break;
}
default:
{
// Default OPEN4_SHARE_DENY_NONE
shareDeny = FileShare.ReadWrite | FileShare.Delete; // Allow read and write access and deletion by other clients
break;
}
}
FileMode createMode = FileMode.Open;
if (e.OpenType == OPEN4_NOCREATE) {
// The client wishes to open the file without creating it. If it doesn't exist, return NFS4ERR_NOENT, otherwise open with FileMode.Open.
if (!File.Exists(e.Path)) {
e.Result = NFS4ERR_NOENT;
return;
}
} else {
// The client wishes to create a file, with the specified CreateMode
switch (e.CreateMode)
{
case UNCHECKED4:
{
createMode = FileMode.Create; // If a duplicate exists, no error is returned
break;
}
default:
{
// Implies e.CreateMode == GUARDED4 || EXCLUSIVE4. If a duplicate exists, NFS4ERR_EXIST is returned
if (File.Exists(path)) {
e.Result = NFS4ERR_EXIST;
return;
}
// Otherwise, proceed with creating the file.
createMode = FileMode.CreateNew;
break;
}
}
}
fs = File.Open(path, createMode, shareAccess, shareDeny);
e.FileContext = (IntPtr)GCHandle.Alloc(fs);
};
The Result parameter will always be 0 (NFS4_OK) when this event fires. If the event cannot be handled successfully, set it to a nonzero value to report an appropriate error. Possible Result codes and their descriptions are listed in the NFS Result Codes section. Additional information regarding these result codes may be found in RFC 7530 Section 13.
Read Event (NFS Class)
This event fires when a client attempts to read any part of a file.
Syntax
ANSI (Cross Platform) virtual int FireRead(NFSReadEventParams *e);
typedef struct {
int ConnectionId;
const char *Path;
void *FileContext;
const char *Buffer; int lenBuffer;
int Count;
int64 Offset;
int Eof;
int Result; int reserved; } NFSReadEventParams;
Unicode (Windows) virtual INT FireRead(NFSReadEventParams *e);
typedef struct {
INT ConnectionId;
LPCWSTR Path;
LPVOID FileContext;
LPSTR Buffer; INT lenBuffer;
INT Count;
LONG64 Offset;
BOOL Eof;
INT Result; INT reserved; } NFSReadEventParams;
#define EID_NFS_READ 17 virtual INT CBFSCONNECT_CALL FireRead(INT &iConnectionId, LPWSTR &lpszPath, LPVOID &lpFileContext, LPSTR &lpBuffer, INT &lenBuffer, INT &iCount, LONG64 &lOffset, BOOL &bEof, INT &iResult);
class NFSReadEventParams { public: int ConnectionId(); const QString &Path(); void *FileContext(); const QByteArray &Buffer(); int Count(); void SetCount(int iCount); qint64 Offset(); bool Eof(); void SetEof(bool bEof); int Result(); void SetResult(int iResult); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void Read(NFSReadEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireRead(NFSReadEventParams *e) {...}
Remarks
This event fires when a client attempts to read any part of a file, identified by the FileContext and/or Path parameters. Note this operation is subject to access permissions checking performed by the application.
The ConnectionId parameter indicates the client this information is required for.
To handle this event properly, applications should read up to Count bytes of data from the specified file into the byte array provided by Buffer. Reading must begin at the specified Offset in the file, and applications must not copy more than Count bytes into the buffer. Note the server may read less data than requested by the client, though this should only be done under particular circumstances, and will ultimately result in the client sending another read operation (unless EOF was reached) to finish reading the file data.
After the appropriate amount of data is read, the application must set the Count parameter to the number of bytes written to the buffer. The application should also update the last accessed time of the file upon a successful read.
If the EOF is reached (e.g., the offset and count are equal to or greater than the size of the file), the Eof parameter should be set to True.
If Count is specified by the client as 0, this value should remain unchanged and the operation should succeed subject to permissions checking. No data should be returned (Buffer should be empty), and the operation should return success.
If Offset is greater than or equal to the size of the file, Count should be set to 0, Eof should be set to True, and the operation should succeed.
If mandatory byte-range locking is in effect, and the current file has a write lock held by another client that conflicts with the data to be read, the operation should fail and Result should be set to NFS4ERR_LOCKED.
Example: Reading data from a file
nfs.OnRead += (o, e) => {
if (e.Count == 0) {
return;
}
try {
IntPtr p = e.FileContext;
GCHandle h = (GCHandle)p;
FileStream fs = h.Target as FileStream;
if (e.Offset >= fs.Length) {
e.Count = 0;
e.Eof = true;
return;
}
fs.Position = e.Offset;
int count = fs.Read(e.BufferB, 0, e.Count);
// If EOF was reached, notify the client
if (fs.Position == fs.Length) {
e.Eof = true;
} else {
e.Eof = false;
}
// Return number of bytes read
e.Count = c;
} catch (Exception ex) {
e.Result = NFS4ERR_IO;
}
};
The Result parameter will always be 0 (NFS4_OK) when this event fires. If the event cannot be handled successfully, set it to a nonzero value to report an appropriate error. Possible Result codes and their descriptions are listed in the NFS Result Codes section. Additional information regarding these result codes may be found in RFC 7530 Section 13.
ReadDir Event (NFS Class)
This event fires when a client attempts to list the contents of a directory.
Syntax
ANSI (Cross Platform) virtual int FireReadDir(NFSReadDirEventParams *e);
typedef struct {
int ConnectionId;
void *FileContext;
const char *Path;
int64 Cookie;
int Result; int reserved; } NFSReadDirEventParams;
Unicode (Windows) virtual INT FireReadDir(NFSReadDirEventParams *e);
typedef struct {
INT ConnectionId;
LPVOID FileContext;
LPCWSTR Path;
LONG64 Cookie;
INT Result; INT reserved; } NFSReadDirEventParams;
#define EID_NFS_READDIR 18 virtual INT CBFSCONNECT_CALL FireReadDir(INT &iConnectionId, LPVOID &lpFileContext, LPWSTR &lpszPath, LONG64 &lCookie, INT &iResult);
class NFSReadDirEventParams { public: int ConnectionId(); void *FileContext(); void SetFileContext(void *lpFileContext); const QString &Path(); qint64 Cookie(); int Result(); void SetResult(int iResult); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void ReadDir(NFSReadDirEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireReadDir(NFSReadDirEventParams *e) {...}
Remarks
This event fires when a client attempts to list the contents of a directory, identified by the Path parameter. Similar to Open, the application may use the FileContext parameter to store a handle or other information related to the directory.
The FileContext parameter is initially IntPtr.Zero when a directory listing begins, as indicated by a Cookie value of 0. In this case, the application may assign this parameter for future reference, as the directory listing operation could span multiple ReadDir events. See below for more information regarding this case. Note that if all directory entries have been listed, the FileContext should be freed and set to IntPtr.Zero before ReadDir returns.
The ConnectionId parameter indicates the client requesting the directory information.
The Cookie parameter represents where the application should start reading entries from within the directory. A cookie value of 0 is used by the client to start reading at the beginning of the directory. Please see FillDir and below for more details regarding non-zero cookie values.
To handle this event properly, the application must call the FillDir method for each existing entry within the associated directory. Doing so will buffer the relevant directory entry information to be sent to the client upon the return of this event.
Note when listing a directory, the client will specify a limit on the amount of data (or number of entries) to return in a single response. To handle this, the application should analyze the returned value of each call to FillDir within this event to ensure the limit is not exceeded. A non-zero return value indicates that the most recent call to FillDir would have caused the application to send more data than the limit specified by the client. In this case, the event should return immediately with a Result of NFS4_OK.
Afterwards, the client will send subsequent requests to continue retrieving entries. In these requests, the Cookie parameter will be equal to the cookie value the application specified in the last successful entry provided by FillDir. Note that the cookie value provided in FillDir and the Cookie parameter specified by the client are only meaningful to the server. The cookie values should be interpreted and utilized as a "bookmark" of the directory entry, indicating a point for continuing the directory listing.
Note if a single directory entry is unable to be returned by the application within this operation, the event should return immediately with a Result of NFS4ERR_TOOSMALL. Please see FillDir for further details. Additionally, please see below for a simple implementation of ReadDir.
Example: Starting or continuing a directory listing
int baseCookie = 0x12345678;
nfs.OnReadDir += (o, e) => {
int dirOffset = 0; // Initial directory offset
// Arbitrary base cookie to start at for listing directory entries.
// On calls to FillDir, this value will be incremented, so subsequent READDIR operations can resume from a specified cookie.
long cookie = baseCookie;
// If e.Cookie == 0, we start listing from the beginning of the directory.
// Otherwise, we start listing from the offset indicated by this parameter.
if (e.Cookie != 0) {
offset = e.Cookie - baseCookie + 1;
cookie = e.Cookie + 1;
}
string path = "C:\\NFSRootDir" + e.Path;
var entries = Directory.GetFileSystemEntries(path, "*", SearchOption.TopDirectoryOnly);
// Iterate through all directory entries.
// dirOffset indicates the next entry to be listed given the client's provided Cookie.
for (int i = dirOffset; i < entries.Length; i++) {
string name = Path.GetFileName(entries[i]);
bool isDir = Directory.Exists(entries[i]);
int result = 0;
if (isDir) {
int fileMode = S_IFDIR | S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; // Indicates file type (S_IFDIR) and permissions (755)
result = nfs.FillDir(e.ConnectionId, name, cookie++, fileMode, "OWNER", "OWNER_GROUP", 1, 4096,
new DirectoryInfo(path).LastAccessTime, new DirectoryInfo(path).LastWriteTime, new DirectoryInfo(path).CreationTime);
} else {
int fileMode = S_IFREG | S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH; // Indicates file type (S_IFREG) and permissions (644).
result = nfs.FillDir(e.ConnectionId, name, cookie++, fileMode, "OWNER", "OWNER_GROUP", 1, FileInfo(path).Length,
new FileInfo(path).LastAccessTime, new FileInfo(path).LastWriteTime, new FileInfo(path).CreationTime);
}
// Return if FillDir returned non-zero value (client's entry limit has been reached)
if (result != 0) {
// No entries were returned, set Result in this case to alert client
if (i == dirOffset) {
e.Result = NFS4ERR_TOOSMALL;
}
return;
}
}
};
The Result parameter will always be 0 (NFS4_OK) when this event fires. If the event cannot be handled successfully, set it to a nonzero value to report an appropriate error. Possible Result codes and their descriptions are listed in the NFS Result Codes section. Additional information regarding these result codes may be found in RFC 7530 Section 13.
ReadLink Event (NFS Class)
This event fires when a client attempts to read data associated with a symbolic link.
Syntax
ANSI (Cross Platform) virtual int FireReadLink(NFSReadLinkEventParams *e);
typedef struct {
int ConnectionId;
const char *Path;
void *FileContext;
const char *Buffer; int lenBuffer;
int Count;
int64 Offset;
int Eof;
int Result; int reserved; } NFSReadLinkEventParams;
Unicode (Windows) virtual INT FireReadLink(NFSReadLinkEventParams *e);
typedef struct {
INT ConnectionId;
LPCWSTR Path;
LPVOID FileContext;
LPSTR Buffer; INT lenBuffer;
INT Count;
LONG64 Offset;
BOOL Eof;
INT Result; INT reserved; } NFSReadLinkEventParams;
#define EID_NFS_READLINK 19 virtual INT CBFSCONNECT_CALL FireReadLink(INT &iConnectionId, LPWSTR &lpszPath, LPVOID &lpFileContext, LPSTR &lpBuffer, INT &lenBuffer, INT &iCount, LONG64 &lOffset, BOOL &bEof, INT &iResult);
class NFSReadLinkEventParams { public: int ConnectionId(); const QString &Path(); void *FileContext(); const QByteArray &Buffer(); int Count(); void SetCount(int iCount); qint64 Offset(); bool Eof(); void SetEof(bool bEof); int Result(); void SetResult(int iResult); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void ReadLink(NFSReadLinkEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireReadLink(NFSReadLinkEventParams *e) {...}
Remarks
This event fires when a client attempts to read data associated with a symbolic link, identified by the Path or FileContext parameters.
The ConnectionId parameter indicates the client attempting to read the symbolic link.
To appropriately handle this event, the application should attempt to retrieve up to Count bytes of data associated with the symbolic link, i.e., the link's target. This data should be read into the byte array provided by the Buffer parameter starting at the specified Offset. Afterwards, Count should be set to the number of bytes read into the buffer. Additionally, if all bytes were read into the buffer, Eof should be set to True.
If Eof is set to False, this indicates to the class that additional data associated with the symbolic link has not been read. In this case, this event will fire again, allowing the application to continue reading the data associated with the symbolic link from the indicated Offset.
Please see below for an example.
nfs.OnReadLink += (o, e) => {
try {
string real = GetRealPath(root, e.Path);
// NET 6 FileSystemInfo class contains a LinkTarget property
FileSystemInfo fileInfo = new FileInfo(real);
byte[] data = System.Text.Encoding.UTF8.GetBytes(fileInfo.LinkTarget);
int bytesToRead = data.Length - (int)e.Offset;
e.Eof = true;
if (bytesToRead > e.Count) {
bytesToRead = e.Count; // 1024 bytes, size of e.BufferB
e.Eof = false; // ReadLink will fire again to finish copying link content
}
System.Array.Copy(data, e.Offset, e.BufferB, 0, bytesToRead);
e.Count = bytesToRead;
} catch (Exception ex) {
e.Result = NFS4ERR_IO;
}
}
Rename Event (NFS Class)
This event fires when a client attempts to rename or move an object.
Syntax
ANSI (Cross Platform) virtual int FireRename(NFSRenameEventParams *e);
typedef struct {
int ConnectionId;
const char *OldPath;
const char *NewPath;
int Result; int reserved; } NFSRenameEventParams;
Unicode (Windows) virtual INT FireRename(NFSRenameEventParams *e);
typedef struct {
INT ConnectionId;
LPCWSTR OldPath;
LPCWSTR NewPath;
INT Result; INT reserved; } NFSRenameEventParams;
#define EID_NFS_RENAME 20 virtual INT CBFSCONNECT_CALL FireRename(INT &iConnectionId, LPWSTR &lpszOldPath, LPWSTR &lpszNewPath, INT &iResult);
class NFSRenameEventParams { public: int ConnectionId(); const QString &OldPath(); const QString &NewPath(); int Result(); void SetResult(int iResult); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void Rename(NFSRenameEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireRename(NFSRenameEventParams *e) {...}
Remarks
This event fires when a client attempts to rename or move an object from OldPath to NewPath.
If OldPath and NewPath refer to the same object, the application should perform no action and return success immediately.
The ConnectionId parameter indicates the client attempting to rename the file or directory.
If an entry already exists with the name NewPath, the source object must be compatible with the target. To clarify, to be compatible, either both objects must be non-directories, or both objects must be directories. If both objects are directories, the target must be empty.
Assuming the objects are compatible, the existing target is removed before the rename (or move) occurs.
If the objects are incompatible, or if the target is a directory but not empty, the application must set Result to NFS4ERR_EXIST.
Example: Renaming a file or directory
nfs.OnRename += (o, e) => {
string oldPath = "C:\\NFSRootDir" + e.OldPath;
string newPath = "C:\\NFSRootDir" + e.NewPath;
// Check if oldPath and newPath refer to the exact same file. If so, return successfully.
if (oldPath.Equals(newPath)) {
return;
}
// Check whether oldPath is a file or directory
if (Directory.Exists(oldPath)) {
// oldPath is a directory. Check for incompatible rename operation.
if (File.Exists(newPath)) {
// Incompatible, Directory -> File
e.Result = NFS4ERR_EXIST;
return;
}
// Check if target directory exists. If so, check the number of files in this directory.
int fileCount = 0;
if (Directory.Exists(newPath)) {
fileCount = Directory.GetFiles(newPath, "*", SearchOption.TopDirectoryOnly).Length;
}
// If files exist in the target directory, return error.
if (fileCount == 0) {
Directory.Move(oldPath, newPath);
} else {
e.Result = NFS4ERR_EXIST;
}
} else {
// oldPath is a file. Check for incompatible rename operation.
if (Directory.Exists(newPath)) {
// Incompatible, File -> Directory
e.Result = NFS4ERR_EXIST;
return;
}
if (File.Exists(newPath)) {
File.Delete(newPath);
}
File.Move(oldPath, newPath);
}
};
The Result parameter will always be 0 (NFS4_OK) when this event fires. If the event cannot be handled successfully, set it to a nonzero value to report an appropriate error. Possible Result codes and their descriptions are listed in the NFS Result Codes section. Additional information regarding these result codes may be found in RFC 7530 Section 13.
RmDir Event (NFS Class)
This event fires when a client attempts to remove a directory.
Syntax
ANSI (Cross Platform) virtual int FireRmDir(NFSRmDirEventParams *e);
typedef struct {
int ConnectionId;
const char *Path;
int Result; int reserved; } NFSRmDirEventParams;
Unicode (Windows) virtual INT FireRmDir(NFSRmDirEventParams *e);
typedef struct {
INT ConnectionId;
LPCWSTR Path;
INT Result; INT reserved; } NFSRmDirEventParams;
#define EID_NFS_RMDIR 21 virtual INT CBFSCONNECT_CALL FireRmDir(INT &iConnectionId, LPWSTR &lpszPath, INT &iResult);
class NFSRmDirEventParams { public: int ConnectionId(); const QString &Path(); int Result(); void SetResult(int iResult); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void RmDir(NFSRmDirEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireRmDir(NFSRmDirEventParams *e) {...}
Remarks
This event fires when a client attempts to remove a directory, identified by the Path parameter.
The ConnectionId parameter indicates the client attempting to delete the directory.
The Result parameter will always be 0 (NFS4_OK) when this event fires. If the event cannot be handled successfully, set it to a nonzero value to report an appropriate error. Possible Result codes and their descriptions are listed in the NFS Result Codes section. Additional information regarding these result codes may be found in RFC 7530 Section 13.
Truncate Event (NFS Class)
This event fires when a client attempts to modify a file's size attribute.
Syntax
ANSI (Cross Platform) virtual int FireTruncate(NFSTruncateEventParams *e);
typedef struct {
int ConnectionId;
const char *Path;
void *FileContext;
int64 Size;
int Result; int reserved; } NFSTruncateEventParams;
Unicode (Windows) virtual INT FireTruncate(NFSTruncateEventParams *e);
typedef struct {
INT ConnectionId;
LPCWSTR Path;
LPVOID FileContext;
LONG64 Size;
INT Result; INT reserved; } NFSTruncateEventParams;
#define EID_NFS_TRUNCATE 22 virtual INT CBFSCONNECT_CALL FireTruncate(INT &iConnectionId, LPWSTR &lpszPath, LPVOID &lpFileContext, LONG64 &lSize, INT &iResult);
class NFSTruncateEventParams { public: int ConnectionId(); const QString &Path(); void *FileContext(); qint64 Size(); int Result(); void SetResult(int iResult); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void Truncate(NFSTruncateEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireTruncate(NFSTruncateEventParams *e) {...}
Remarks
This event fires when a client attempts to modify a file's size attribute, identified by the FileContext and/or Path parameters.
The ConnectionId parameter indicates the client attempting to truncate the file.
The Size parameter indicates the desired value the client wishes to set the NFSv4.0 size attribute to.
The Result parameter will always be 0 (NFS4_OK) when this event fires. If the event cannot be handled successfully, set it to a nonzero value to report an appropriate error. Possible Result codes and their descriptions are listed in the NFS Result Codes section. Additional information regarding these result codes may be found in RFC 7530 Section 13.
Unlink Event (NFS Class)
This event fires when a client attempts to unlink (or delete) a file.
Syntax
ANSI (Cross Platform) virtual int FireUnlink(NFSUnlinkEventParams *e);
typedef struct {
int ConnectionId;
const char *Path;
int Result; int reserved; } NFSUnlinkEventParams;
Unicode (Windows) virtual INT FireUnlink(NFSUnlinkEventParams *e);
typedef struct {
INT ConnectionId;
LPCWSTR Path;
INT Result; INT reserved; } NFSUnlinkEventParams;
#define EID_NFS_UNLINK 23 virtual INT CBFSCONNECT_CALL FireUnlink(INT &iConnectionId, LPWSTR &lpszPath, INT &iResult);
class NFSUnlinkEventParams { public: int ConnectionId(); const QString &Path(); int Result(); void SetResult(int iResult); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void Unlink(NFSUnlinkEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireUnlink(NFSUnlinkEventParams *e) {...}
Remarks
This event fires when a client attempts to unlink (or delete) a file, identified by the Path parameter.
The ConnectionId parameter indicates the client attempting to delete the file.
Note the file may still be open when this event fires. In this case, the application should not delete the file if the file was opened with OPEN4_SHARE_DENY_WRITE or OPEN4_SHARE_DENY_BOTH (see Open for additional details). If the file was opened with OPEN4_SHARE_DENY_NONE or OPEN4_SHARE_DENY_READ, the application should delete the file.
The Result parameter will always be 0 (NFS4_OK) when this event fires. If the event cannot be handled successfully, set it to a nonzero value to report an appropriate error. Possible Result codes and their descriptions are listed in the NFS Result Codes section. Additional information regarding these result codes may be found in RFC 7530 Section 13.
Unlock Event (NFS Class)
This event fires when a client attempts to release a lock.
Syntax
ANSI (Cross Platform) virtual int FireUnlock(NFSUnlockEventParams *e);
typedef struct {
int ConnectionId;
const char *Path;
void *FileContext;
int LockType;
int64 LockOffset;
int64 LockLen;
int Result; int reserved; } NFSUnlockEventParams;
Unicode (Windows) virtual INT FireUnlock(NFSUnlockEventParams *e);
typedef struct {
INT ConnectionId;
LPCWSTR Path;
LPVOID FileContext;
INT LockType;
LONG64 LockOffset;
LONG64 LockLen;
INT Result; INT reserved; } NFSUnlockEventParams;
#define EID_NFS_UNLOCK 24 virtual INT CBFSCONNECT_CALL FireUnlock(INT &iConnectionId, LPWSTR &lpszPath, LPVOID &lpFileContext, INT &iLockType, LONG64 &lLockOffset, LONG64 &lLockLen, INT &iResult);
class NFSUnlockEventParams { public: int ConnectionId(); const QString &Path(); void *FileContext(); int LockType(); qint64 LockOffset(); qint64 LockLen(); int Result(); void SetResult(int iResult); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void Unlock(NFSUnlockEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireUnlock(NFSUnlockEventParams *e) {...}
Remarks
This event fires when a client attempts to release a lock, indicated by the FileContext and/or Path parameters.
The ConnectionId parameter indicates the client requesting to release the lock.
The LockOffset parameter specifies the position (or byte) within the file where the unlock should begin at. The LockLen parameter specifies the number of bytes that should be unlocked after the specified offset, effectively creating a range of bytes to unlock. If the LockLen parameter is 0, the application should return NFS4ERR_INVAL. If the LockLen parameter is -1, this indicates the client wishes to lock all bytes from the specified LockOffset to the end of the file.
The LockType parameter indicates the type of lock used on the file (read or write, blocking or non-blocking). Please see Lock for possible values. This parameter should not affect the success or failure of this operation.
If the LockOffset and LockLen parameters do not correspond exactly to a lock held by the client, NFS4ERR_LOCK_RANGE may be returned.
The Result parameter will always be 0 (NFS4_OK) when this event fires. If the event cannot be handled successfully, set it to a nonzero value to report an appropriate error. Possible Result codes and their descriptions are listed in the NFS Result Codes section. Additional information regarding these result codes may be found in RFC 7530 Section 13.
UTime Event (NFS Class)
This event fires when a client attempts to change a file's last access time, last modification time, or both.
Syntax
ANSI (Cross Platform) virtual int FireUTime(NFSUTimeEventParams *e);
typedef struct {
int ConnectionId;
const char *Path;
void *FileContext;
int64 ATime;
int64 MTime;
int Result; int reserved; } NFSUTimeEventParams;
Unicode (Windows) virtual INT FireUTime(NFSUTimeEventParams *e);
typedef struct {
INT ConnectionId;
LPCWSTR Path;
LPVOID FileContext;
LONG64 ATime;
LONG64 MTime;
INT Result; INT reserved; } NFSUTimeEventParams;
#define EID_NFS_UTIME 25 virtual INT CBFSCONNECT_CALL FireUTime(INT &iConnectionId, LPWSTR &lpszPath, LPVOID &lpFileContext, LONG64 &lATime, LONG64 &lMTime, INT &iResult);
class NFSUTimeEventParams { public: int ConnectionId(); const QString &Path(); void *FileContext(); const QDateTime &ATime(); const QDateTime &MTime(); int Result(); void SetResult(int iResult); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void UTime(NFSUTimeEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireUTime(NFSUTimeEventParams *e) {...}
Remarks
This event fires when a client attempts to change a file's access time, modification time, or both.
The ConnectionId parameter indicates the client attempting to modify these values.
The ATime parameter indicates the desired value the client wishes to set the NFSv4.0 time_access attribute to.
The MTime parameter indicates the desired value the client wishes to set the NFSv4.0 time_modify attribute to.
Note that if the ATime or MTime parameter is equal to the smallest possible time allowed for the given parameter type, the client does not wish to modify the associated attribute and the parameter should be ignored.
The Result parameter will always be 0 (NFS4_OK) when this event fires. If the event cannot be handled successfully, set it to a nonzero value to report an appropriate error. Possible Result codes and their descriptions are listed in the NFS Result Codes section. Additional information regarding these result codes may be found in RFC 7530 Section 13.
Write Event (NFS Class)
This event fires when a client attempts to write data to a file.
Syntax
ANSI (Cross Platform) virtual int FireWrite(NFSWriteEventParams *e);
typedef struct {
int ConnectionId;
const char *Path;
void *FileContext;
int64 Offset;
const char *Buffer; int lenBuffer;
int Count;
int Stable;
int Result; int reserved; } NFSWriteEventParams;
Unicode (Windows) virtual INT FireWrite(NFSWriteEventParams *e);
typedef struct {
INT ConnectionId;
LPCWSTR Path;
LPVOID FileContext;
LONG64 Offset;
LPCSTR Buffer; INT lenBuffer;
INT Count;
INT Stable;
INT Result; INT reserved; } NFSWriteEventParams;
#define EID_NFS_WRITE 26 virtual INT CBFSCONNECT_CALL FireWrite(INT &iConnectionId, LPWSTR &lpszPath, LPVOID &lpFileContext, LONG64 &lOffset, LPSTR &lpBuffer, INT &lenBuffer, INT &iCount, INT &iStable, INT &iResult);
class NFSWriteEventParams { public: int ConnectionId(); const QString &Path(); void *FileContext(); qint64 Offset(); const QByteArray &Buffer(); int Count(); void SetCount(int iCount); int Stable(); void SetStable(int iStable); int Result(); void SetResult(int iResult); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void Write(NFSWriteEventParams *e);
// Or, subclass NFS and override this emitter function. virtual int FireWrite(NFSWriteEventParams *e) {...}
Remarks
This event fires when a client attempts to write data to a file, identified by the FileContext and/or Path parameters. Note this operation is subject to access permissions checking performed by the application.
The ConnectionId parameter indicates the client writing to a file.
To handle this event properly, applications should write Count bytes of data from the byte array specified by Buffer to the relevant file. Writing must begin at the indicated Offset in the file. Note the server may write less data than requested by the client.
After the appropriate amount of data is written, the application must set the Count parameter to the number of bytes written to the relevant file.
If Count is specified by the client as 0, this value should remain unchanged and the operation should succeed (subject to permissions checking). In this case, the application should also ensure the modified time of the file is not changed.
The Stable parameter is specified by the client to indicate how the write operation should be performed, or how the data should be committed by the application. This parameter may be equal to one of the following values as specified by the connection:
UNSTABLE4 | 0 | Indicates the application is free to commit any part of the data written and filesystem metadata before returning any results. |
DATA_SYNC4 | 1 | Indicates the application must commit all of the data to stable storage and enough filesystem metadata to retrieve the data before returning any results. |
FILE_SYNC4 | 2 | Indicates the application must commit the data written plus all filesystem metadata to stable storage before returning any results. |
The application must also specify the level of commitment fulfilled and can do so by modifying the Stable parameter to one of the above values. Note that the level of commitment must at least be as strong as the value specified in Stable (with FILE_SYNC4 being the strongest and UNSTABLE4 being the weakest). A returned level of commitment less than the provided value of Stable constitutes a protocol violation.
Assuming UNSTABLE4 or DATA_SYNC4 are returned by the application, it can be expected that the client will follow up to ensure the data and metadata are written to stable storage. In this case, Commit will fire.
If mandatory byte-range locking is in effect, and the current file has a read or write lock held by another client that conflicts with the data to be written, the operation should fail and Result should be set to NFS4ERR_LOCKED.
Example: Writing data to a file
nfs.OnWrite += (o, e) => {
if (e.Count == 0) {
return;
}
try {
IntPtr p = e.FileContext;
GCHandle h = (GCHandle)p;
FileStream fs = h.Target as FileStream;
fs.Position = e.Offset;
fs.Write(e.BufferB, 0, e.Count);
fs.Flush();
// All data was written to disk, indicate this via Stable.
e.Stable = FILE_SYNC4;
} catch (Exception ex) {
e.Result = NFS4ERR_IO;
}
};
The Result parameter will always be 0 (NFS4_OK) when this event fires. If the event cannot be handled successfully, set it to a nonzero value to report an appropriate error. Possible Result codes and their descriptions are listed in the NFS Result Codes section. Additional information regarding these result codes may be found in RFC 7530 Section 13.
NFSConnection Type
This type describes a currently connected client.
Syntax
CBFSConnectNFSConnection (declared in cbfsconnect.h)
Remarks
This type describes the connection of a client that is currently connected to the class. You may use the different fields of this type to manage the connection.
Fields
AuxGIDs
char* (read-only)
Default Value: ""
This field contains a comma-separated list of Auxiliary GIDs (or groups the client is a part of) associated with the connection making a request. This field is only meaningful within the classes events.
For example, if a user with a GID of 1000 makes a request, this field may be: 4,24,27,30,46,110,1000
Note that this value may change for a given connection assuming multiple users have access to the mounted folder on the client machine. This field will reflect the Auxiliary GIDs associated with the current user making the request.
Connected
int (read-only)
Default Value: FALSE
This field shows the status of a particular connection (connected/disconnected).
ConnectionId
char* (read-only)
Default Value: ""
An id generated by the class to identify each connection. This id is unique to this connection.
CurrentFile
char* (read-only)
Default Value: ""
This field represents the current file opened by the connection. An empty string indicates the connection has no file opened.
GID
int (read-only)
Default Value: 0
This field represents the current group identifier (GID) of the connection making a request. This field is only meaningful within the classes events.
Note that this value may change for a given connection. Assuming multiple users have access to the mounted folder on the client machine, this field will reflect the GID of the current user making the request.
RemoteHost
char* (read-only)
Default Value: ""
This field indicates the IP address of the remote host through which the connection is coming.
The connection must be valid or an error will be fired.
If the class is configured to use a SOCKS firewall, the value assigned to this property may be preceded with an "*". If this is the case, the host name is passed to the firewall unresolved and the firewall performs the DNS resolution.
RemotePort
int (read-only)
Default Value: 0
This field indicates the TCP port on the remote host through which the connection is coming.
The connection must be valid or an error will be fired.
UID
int (read-only)
Default Value: 0
This field represents the current user identifier (UID) of the connection making a request. This field is only meaningful within the classes events.
Note that this value may change for a given connection. Assuming multiple users have access to the mounted folder on the client machine, this field will reflect the UID of the current user making the request.
Constructors
NFSConnection()
CBFSConnectList Type
Syntax
CBFSConnectList<T> (declared in cbfsconnect.h)
Remarks
CBFSConnectList is a generic class that is used to hold a collection of objects of type T, where T is one of the custom types supported by the NFS class.
Methods | |
GetCount |
This method returns the current size of the collection.
int GetCount() {}
|
SetCount |
This method sets the size of the collection. This method returns 0 if setting the size was successful; or -1 if the collection is ReadOnly. When adding additional objects to a collection call this method to specify the new size. Increasing the size of the collection preserves existing objects in the collection.
int SetCount(int count) {}
|
Get |
This method gets the item at the specified position. The index parameter specifies the index of the item in the collection. This method returns NULL if an invalid index is specified.
T* Get(int index) {}
|
Set |
This method sets the item at the specified position. The index parameter specifies the index of the item in the collection that is being set. This method returns -1 if an invalid index is specified. Note: Objects created using the new operator must be freed using the delete operator; they will not be automatically freed by the class.
T* Set(int index, T* value) {}
|
Config Settings (NFS Class)
The class accepts one or more of the following configuration settings. Configuration settings are similar in functionality to properties, but they are rarely used. In order to avoid "polluting" the property namespace of the class, access to these internal properties is provided through the Config method.NFS Config Settings
When a client connects, the client's address is checked against the list defined here. If there is no match, the ConnectionRequest event fires with an Accept value set to false. If no action is taken within the ConnectionRequest event, the client will be disconnected.
When a client connects, the client's address is checked against the list defined here. If there is a match, the ConnectionRequest event fires with an Accept value set to false. If no action is taken within the ConnectionRequest event, the client will not be connected.
Connection5UID = obj.config("ConnectionUID[5]")
Note: This is applicable only to incoming SSL connections. This should be set only if there is a specific reason to do so.
Some TCP/IP implementations do not support variable buffer sizes. If that is the case, when the class is activated, the InBufferSize reverts to its defined size. The same thing will happen if you attempt to make it too large or too small.
InBufferSize is shared among incoming connections. When the property is set, the corresponding value is set for incoming connections as they are accepted. Existing connections are not modified.
Note: This value is not applicable in macOS.
Note: This configuration setting is available only in the Unix platform, and it is not supported in macOS or FreeBSD.
0 (None) | No messages are logged. |
1 (Info - Default) | Informational events are logged. |
2 (Verbose) | Detailed data is logged. |
3 (Debug) | Debug data including all relevant sent and received NFS operations are logged. |
Note: Unix/Linux operating systems limit the number of simultaneous connections to 1024.
The default value is 50 (milliseconds).
This setting works on Linux and macOS and requires the NFS client to be installed in the system (the "mount" command should be able to mount an NFS server locally). On Windows, this setting is not used due to the lack of the NFS 4 client in Windows.
Some TCP/IP implementations do not support variable buffer sizes. If that is the case, when the class is activated the OutBufferSize reverts to its defined size. The same thing will happen if you attempt to make it too large or too small.
OutBufferSize is shared among incoming connections. When the property is set, the corresponding value is set for incoming connections as they are accepted. Existing connections are not modified.
Nothing else is required to begin accepting IOCP connections. One major benefit to using this model is that there will be no thread blocked waiting for a request to complete. The system notifies the process through an Asynchronous Procedure Call (APC) once the device driver finishes servicing the I/O request. IOCP allows a single I/O worker thread handle multiple clients' input/output "fairly".
Note: When set to true, this setting will automatically set UseWindowsMessages to false.
0 | IPv4 Only |
1 | IPv6 Only |
2 | IPv6 and IPv4 |
Nothing else is required to begin accepting connections using the Windows message queue. In high-traffic environments, messages will be discarded if the queue is full. Additionally, because a single window procedure will service all events on thousands of sockets, the Windows message queue is not scalable from a performance perspective.
If this setting is set to false, the class will instead use the Winsock select model instead. The component supports additional I/O models. Please see UseIOCP for more information.
Base Config Settings
- Product: The product the license is for.
- Product Key: The key the license was generated from.
- License Source: Where the license was found (e.g., RuntimeLicense, License File).
- License Type: The type of license installed (e.g., Royalty Free, Single Server).
Trappable Errors (NFS Class)
Error Handling (C++)
Call the GetLastErrorCode() method to obtain the last called method's result code; 0 indicates success, while a non-zero error code indicates that this method encountered an error during its execution. Known error codes are listed below. If an error occurs, the GetLastError() method can be called to retrieve the associated error message.