Serving Files and Directories
Build with UA_BUILD_EXAMPLES, Method calls and a reduced or full
Namespace Zero.
This example serves a local directory and a separate read-only file through
the OPC UA Part 20 Methods.
Create a backend, construct its driver, then register it with the server.
Registration starts the driver if the server is already running; otherwise
it starts with the server. Shutdown stops drivers; deleting the server
frees them. For parameters and backend callbacks, see
File Transfer Driver. A custom in-memory backend is shown in
examples/filetransfer/server_filetransfer_custom_backend.c.
Serving a local directory
The default root Object is named “FileSystem”. Its entries are mirrored on start and refreshed periodically. Client Methods operate on storage directly.
static UA_StatusCode
mountLocalDirectory(UA_Server *server, const char *rootPath) {
UA_FileTransferBackend backend;
UA_StatusCode res =
UA_FileTransferBackend_localDirectory(UA_STRING((char*)(uintptr_t)rootPath),
&backend);
if(res != UA_STATUSCODE_GOOD)
return res;
UA_Driver *ftd = NULL;
res = UA_FileTransferDriver_newDirectory(server, &backend, NULL, NULL, &ftd);
if(res != UA_STATUSCODE_GOOD) {
backend.file.clear(&backend.file);
return res;
}
res = UA_Server_addDriver(server, ftd);
if(res != UA_STATUSCODE_GOOD)
ftd->free(ftd);
return res;
}
Exposing a single file
Individual files (a configuration file, a manual, a log) can be exposed as standalone FileType Objects without mirroring a whole directory. Here the file is served read-only: the Writable/UserWritable Properties are false and opening the file for writing fails.
static UA_StatusCode
addReadOnlyFile(UA_Server *server, const char *rootPath) {
char filePath[512];
int length = snprintf(filePath, sizeof(filePath), "%s/readme.txt", rootPath);
if(length < 0 || (size_t)length >= sizeof(filePath))
return UA_STATUSCODE_BADINVALIDARGUMENT;
UA_FileTransferFileBackend backend;
UA_StatusCode res =
UA_FileTransferFileBackend_localFile(UA_STRING(filePath), &backend);
if(res != UA_STATUSCODE_GOOD)
return res;
UA_Driver *ftd = NULL;
UA_FileTransferNodeDescription description;
memset(&description, 0, sizeof(description));
description.browseName = UA_QUALIFIEDNAME(1, "ReadMe");
res = UA_FileTransferDriver_newFile(server, &backend, UA_STRING_NULL,
&description, NULL, &ftd);
if(res != UA_STATUSCODE_GOOD) {
backend.clear(&backend);
return res;
}
/* Configure the driver before adding it: registration starts it immediately
* when the server is already running. */
UA_Boolean readOnly = true;
res = UA_KeyValueMap_setScalar(&ftd->params, UA_QUALIFIEDNAME(0, "read-only"),
&readOnly, &UA_TYPES[UA_TYPES_BOOLEAN]);
if(res == UA_STATUSCODE_GOOD)
res = UA_Server_addDriver(server, ftd);
if(res != UA_STATUSCODE_GOOD)
ftd->free(ftd);
return res;
}
/* Prepare the served directory with demo content */
static void
prepareDemoDirectory(const char *rootPath) {