mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-03-03 14:52:21 +02:00
Abstract Posix storage driver code into a separate module.
This commit is contained in:
parent
348278bb68
commit
bd25248df0
@ -36,7 +36,7 @@
|
||||
</release-item>
|
||||
|
||||
<release-item>
|
||||
<p>Storage object improvements. Convert all functions to variadic functions. Enforce read-only storage. Add <code>storageLocalWrite()</code> helper function. Add <code>storageExists()</code>, <code>storagePathCreate()</code>, <code>storageRemove()</code>, and <code>storageStat()</code>. Add <code>StorageFile</code> object and <code>storageOpenRead()</code>/<code>storageOpenWrite()</code>.</p>
|
||||
<p>Storage object improvements. Convert all functions to variadic functions. Enforce read-only storage. Add <code>storageLocalWrite()</code> helper function. Add <code>storageExists()</code>, <code>storagePathCreate()</code>, and <code>storageRemove()</code>. Add <code>StorageFile</code> object and <code>storageOpenRead()</code>/<code>storageOpenWrite()</code>. Abstract Posix driver code into a separate module.</p>
|
||||
</release-item>
|
||||
|
||||
<release-item>
|
||||
|
@ -100,6 +100,7 @@ my @stryCFile =
|
||||
'config/parse.c',
|
||||
'perl/config.c',
|
||||
'postgres/pageChecksum.c',
|
||||
'storage/driver/posix.c',
|
||||
'storage/file.c',
|
||||
'storage/helper.c',
|
||||
'storage/storage.c',
|
||||
|
@ -79,6 +79,7 @@ SRCS = \
|
||||
config/parse.c \
|
||||
perl/config.c \
|
||||
perl/exec.c \
|
||||
storage/driver/posix.c \
|
||||
storage/file.c \
|
||||
storage/helper.c \
|
||||
storage/storage.c \
|
||||
|
287
src/storage/driver/posix.c
Normal file
287
src/storage/driver/posix.c
Normal file
@ -0,0 +1,287 @@
|
||||
/***********************************************************************************************************************************
|
||||
Storage Posix Driver
|
||||
***********************************************************************************************************************************/
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common/memContext.h"
|
||||
#include "common/regExp.h"
|
||||
#include "storage/driver/posix.h"
|
||||
#include "storage/storage.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Storage file data - holds the file handle.
|
||||
***********************************************************************************************************************************/
|
||||
typedef struct StorageFileDataPosix
|
||||
{
|
||||
MemContext *memContext;
|
||||
int handle;
|
||||
} StorageFileDataPosix;
|
||||
|
||||
#define STORAGE_DATA(file) \
|
||||
((StorageFileDataPosix *)storageFileData(file))
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Does a file/path exist?
|
||||
***********************************************************************************************************************************/
|
||||
bool
|
||||
storageDriverPosixExists(const String *path)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
// Attempt to stat the file to determine if it exists
|
||||
struct stat statFile;
|
||||
|
||||
// Any error other than entry not found should be reported
|
||||
if (stat(strPtr(path), &statFile) == -1)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
THROW_SYS_ERROR(FileOpenError, "unable to stat '%s'", strPtr(path));
|
||||
}
|
||||
// Else found
|
||||
else
|
||||
result = !S_ISDIR(statFile.st_mode);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Read from storage into a buffer
|
||||
***********************************************************************************************************************************/
|
||||
Buffer *
|
||||
storageDriverPosixGet(const StorageFile *file)
|
||||
{
|
||||
Buffer volatile *result = NULL;
|
||||
|
||||
TRY_BEGIN()
|
||||
{
|
||||
// Create result buffer with buffer size
|
||||
ssize_t actualBytes = 0;
|
||||
size_t totalBytes = 0;
|
||||
|
||||
do
|
||||
{
|
||||
size_t bufferSize = storageBufferSize(storageFileStorage(file));
|
||||
|
||||
// Allocate the buffer before first read
|
||||
if (result == NULL)
|
||||
result = bufNew(bufferSize);
|
||||
// Grow the buffer on subsequent reads
|
||||
else
|
||||
bufResize((Buffer *)result, bufSize((Buffer *)result) + bufferSize);
|
||||
|
||||
// Read and handle errors
|
||||
actualBytes = read(
|
||||
STORAGE_DATA(file)->handle, bufPtr((Buffer *)result) + totalBytes, bufferSize);
|
||||
|
||||
// Error occurred during write
|
||||
if (actualBytes == -1)
|
||||
THROW_SYS_ERROR(FileReadError, "unable to read '%s'", strPtr(storageFileName(file)));
|
||||
|
||||
// Track total bytes read
|
||||
totalBytes += (size_t)actualBytes;
|
||||
}
|
||||
while (actualBytes != 0);
|
||||
|
||||
// Resize buffer to total bytes read
|
||||
bufResize((Buffer *)result, totalBytes);
|
||||
}
|
||||
CATCH_ANY()
|
||||
{
|
||||
// Free buffer on error if it was allocated
|
||||
bufFree((Buffer *)result);
|
||||
|
||||
RETHROW();
|
||||
}
|
||||
FINALLY()
|
||||
{
|
||||
close(STORAGE_DATA(file)->handle);
|
||||
storageFileFree(file);
|
||||
}
|
||||
TRY_END();
|
||||
|
||||
return (Buffer *)result;
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Get a list of files from a directory
|
||||
***********************************************************************************************************************************/
|
||||
StringList *
|
||||
storageDriverPosixList(const String *path, bool errorOnMissing, const String *expression)
|
||||
{
|
||||
StringList *result = NULL;
|
||||
|
||||
DIR *dir = NULL;
|
||||
RegExp *regExp = NULL;
|
||||
|
||||
TRY_BEGIN()
|
||||
{
|
||||
// Open the directory for read
|
||||
dir = opendir(strPtr(path));
|
||||
|
||||
// If the directory could not be opened process errors but ignore missing directories when specified
|
||||
if (!dir)
|
||||
{
|
||||
if (errorOnMissing || errno != ENOENT)
|
||||
THROW_SYS_ERROR(PathOpenError, "unable to open directory '%s' for read", strPtr(path));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Prepare regexp if an expression was passed
|
||||
if (expression != NULL)
|
||||
regExp = regExpNew(expression);
|
||||
|
||||
// Create the string list now that we know the directory is valid
|
||||
result = strLstNew();
|
||||
|
||||
// Read the directory entries
|
||||
struct dirent *dirEntry = readdir(dir);
|
||||
|
||||
while (dirEntry != NULL)
|
||||
{
|
||||
String *entry = strNew(dirEntry->d_name);
|
||||
|
||||
// Exclude current/parent directory and apply the expression if specified
|
||||
if (!strEqZ(entry, ".") && !strEqZ(entry, "..") && (regExp == NULL || regExpMatch(regExp, entry)))
|
||||
strLstAdd(result, entry);
|
||||
else
|
||||
strFree(entry);
|
||||
|
||||
dirEntry = readdir(dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
CATCH_ANY()
|
||||
{
|
||||
// Free list on error
|
||||
strLstFree(result);
|
||||
|
||||
RETHROW();
|
||||
}
|
||||
FINALLY()
|
||||
{
|
||||
if (dir != NULL)
|
||||
closedir(dir);
|
||||
|
||||
if (regExp != NULL)
|
||||
regExpFree(regExp);
|
||||
}
|
||||
TRY_END();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Open a file for reading
|
||||
***********************************************************************************************************************************/
|
||||
void *
|
||||
storageDriverPosixOpenRead(const String *file, bool ignoreMissing)
|
||||
{
|
||||
StorageFileDataPosix *result = NULL;
|
||||
|
||||
// Open the file and handle errors
|
||||
int fileHandle = open(strPtr(file), O_RDONLY, 0);
|
||||
|
||||
if (fileHandle == -1)
|
||||
{
|
||||
// Error unless ignore missing is specified
|
||||
if (!ignoreMissing || errno != ENOENT)
|
||||
THROW_SYS_ERROR(FileOpenError, "unable to open '%s' for read", strPtr(file));
|
||||
}
|
||||
// Else create the storage file and data
|
||||
else
|
||||
{
|
||||
MEM_CONTEXT_NEW_BEGIN("StorageFileDataPosix")
|
||||
{
|
||||
result = memNew(sizeof(StorageFileDataPosix));
|
||||
result->memContext = MEM_CONTEXT_NEW();
|
||||
result->handle = fileHandle;
|
||||
}
|
||||
MEM_CONTEXT_NEW_END();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Open a file for writing
|
||||
***********************************************************************************************************************************/
|
||||
void *
|
||||
storageDriverPosixOpenWrite(const String *file, mode_t mode)
|
||||
{
|
||||
// Open the file and handle errors
|
||||
int fileHandle = open(strPtr(file), O_CREAT | O_TRUNC | O_WRONLY, mode);
|
||||
|
||||
if (fileHandle == -1)
|
||||
THROW_SYS_ERROR(FileOpenError, "unable to open '%s' for write", strPtr(file));
|
||||
|
||||
// Create the storage file and data
|
||||
StorageFileDataPosix *result = NULL;
|
||||
|
||||
MEM_CONTEXT_NEW_BEGIN("StorageFileDataPosix")
|
||||
{
|
||||
result = memNew(sizeof(StorageFileDataPosix));
|
||||
result->memContext = MEM_CONTEXT_NEW();
|
||||
result->handle = fileHandle;
|
||||
}
|
||||
MEM_CONTEXT_NEW_END();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Create a path
|
||||
***********************************************************************************************************************************/
|
||||
void
|
||||
storageDriverPosixPathCreate(const String *path, bool errorOnExists, bool noParentCreate, mode_t mode)
|
||||
{
|
||||
// Attempt to create the directory
|
||||
if (mkdir(strPtr(path), mode) == -1)
|
||||
{
|
||||
// If the parent path does not exist then create it if allowed
|
||||
if (errno == ENOENT && !noParentCreate)
|
||||
{
|
||||
storageDriverPosixPathCreate(strPath(path), errorOnExists, noParentCreate, mode);
|
||||
storageDriverPosixPathCreate(path, errorOnExists, noParentCreate, mode);
|
||||
}
|
||||
// Ignore path exists if allowed
|
||||
else if (errno != EEXIST || errorOnExists)
|
||||
THROW_SYS_ERROR(PathCreateError, "unable to create path '%s'", strPtr(path));
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Write a buffer to storage
|
||||
***********************************************************************************************************************************/
|
||||
void
|
||||
storageDriverPosixPut(const StorageFile *file, const Buffer *buffer)
|
||||
{
|
||||
TRY_BEGIN()
|
||||
{
|
||||
if (write(STORAGE_DATA(file)->handle, bufPtr(buffer), bufSize(buffer)) != (ssize_t)bufSize(buffer))
|
||||
THROW_SYS_ERROR(FileWriteError, "unable to write '%s'", strPtr(storageFileName(file)));
|
||||
}
|
||||
FINALLY()
|
||||
{
|
||||
close(STORAGE_DATA(file)->handle);
|
||||
storageFileFree(file);
|
||||
}
|
||||
TRY_END();
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Remove a file
|
||||
***********************************************************************************************************************************/
|
||||
void
|
||||
storageDriverPosixRemove(const String *file, bool errorOnMissing)
|
||||
{
|
||||
// Attempt to unlink the file
|
||||
if (unlink(strPtr(file)) == -1)
|
||||
{
|
||||
if (errorOnMissing || errno != ENOENT)
|
||||
THROW_SYS_ERROR(FileRemoveError, "unable to remove '%s'", strPtr(file));
|
||||
}
|
||||
}
|
26
src/storage/driver/posix.h
Normal file
26
src/storage/driver/posix.h
Normal file
@ -0,0 +1,26 @@
|
||||
/***********************************************************************************************************************************
|
||||
Storage Posix Driver
|
||||
***********************************************************************************************************************************/
|
||||
#ifndef STORAGE_DRIVER_POSIX_H
|
||||
#define STORAGE_DRIVER_POSIX_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "common/type/buffer.h"
|
||||
#include "common/type/string.h"
|
||||
#include "storage/file.h"
|
||||
#include "storage/storage.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Function
|
||||
***********************************************************************************************************************************/
|
||||
bool storageDriverPosixExists(const String *path);
|
||||
Buffer *storageDriverPosixGet(const StorageFile *file);
|
||||
StringList *storageDriverPosixList(const String *path, bool errorOnMissing, const String *expression);
|
||||
void *storageDriverPosixOpenRead(const String *file, bool ignoreMissing);
|
||||
void *storageDriverPosixOpenWrite(const String *file, mode_t mode);
|
||||
void storageDriverPosixPathCreate(const String *path, bool errorOnExists, bool noParentCreate, mode_t mode);
|
||||
void storageDriverPosixPut(const StorageFile *file, const Buffer *buffer);
|
||||
void storageDriverPosixRemove(const String *file, bool errorOnMissing);
|
||||
|
||||
#endif
|
@ -1,17 +1,12 @@
|
||||
/***********************************************************************************************************************************
|
||||
Storage Manager
|
||||
***********************************************************************************************************************************/
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/memContext.h"
|
||||
#include "common/regExp.h"
|
||||
#include "common/wait.h"
|
||||
#include "storage/driver/posix.h"
|
||||
#include "storage/storage.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
@ -28,18 +23,6 @@ struct Storage
|
||||
StoragePathExpressionCallback pathExpressionFunction;
|
||||
};
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Storage file data - holds the file handle. This should eventually be moved to the Posix/CIFS driver.
|
||||
***********************************************************************************************************************************/
|
||||
typedef struct StorageFileDataPosix
|
||||
{
|
||||
MemContext *memContext;
|
||||
int handle;
|
||||
} StorageFileDataPosix;
|
||||
|
||||
#define STORAGE_DATA(file) \
|
||||
((StorageFileDataPosix *)storageFileData(file))
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Debug Asserts
|
||||
***********************************************************************************************************************************/
|
||||
@ -76,6 +59,15 @@ storageNew(const String *path, StorageNewParam param)
|
||||
return this;
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Get storage buffer size
|
||||
***********************************************************************************************************************************/
|
||||
size_t
|
||||
storageBufferSize(const Storage *this)
|
||||
{
|
||||
return this->bufferSize;
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Does a file/path exist?
|
||||
***********************************************************************************************************************************/
|
||||
@ -95,20 +87,11 @@ storageExists(const Storage *this, const String *pathExp, StorageExistsParam par
|
||||
// Create Wait object of timeout > 0
|
||||
Wait *wait = param.timeout != 0 ? waitNew(param.timeout) : NULL;
|
||||
|
||||
// Attempt to stat the file to determine if it exists
|
||||
struct stat statFile;
|
||||
|
||||
// Loop until file exists or timeout
|
||||
do
|
||||
{
|
||||
// Any error other than entry not found should be reported
|
||||
if (stat(strPtr(path), &statFile) == -1)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
THROW_SYS_ERROR(FileOpenError, "unable to stat '%s'", strPtr(path));
|
||||
}
|
||||
// Else found
|
||||
else
|
||||
result = true;
|
||||
// Call driver function
|
||||
result = storageDriverPosixExists(path);
|
||||
}
|
||||
while (!result && wait != NULL && waitMore(wait));
|
||||
}
|
||||
@ -123,58 +106,13 @@ Read from storage into a buffer
|
||||
Buffer *
|
||||
storageGet(const StorageFile *file)
|
||||
{
|
||||
Buffer volatile *result = NULL;
|
||||
Buffer *result = NULL;
|
||||
|
||||
// Nothing to do unless a file was passed
|
||||
// Call driver function if a file was passed
|
||||
if (file != NULL)
|
||||
{
|
||||
TRY_BEGIN()
|
||||
{
|
||||
// Create result buffer with buffer size
|
||||
ssize_t actualBytes = 0;
|
||||
size_t totalBytes = 0;
|
||||
result = storageDriverPosixGet(file);
|
||||
|
||||
do
|
||||
{
|
||||
// Allocate the buffer before first read
|
||||
if (result == NULL)
|
||||
result = bufNew(storageFileStorage(file)->bufferSize);
|
||||
// Grow the buffer on subsequent reads
|
||||
else
|
||||
bufResize((Buffer *)result, bufSize((Buffer *)result) + (size_t)storageFileStorage(file)->bufferSize);
|
||||
|
||||
// Read and handle errors
|
||||
actualBytes = read(
|
||||
STORAGE_DATA(file)->handle, bufPtr((Buffer *)result) + totalBytes, storageFileStorage(file)->bufferSize);
|
||||
|
||||
// Error occurred during write
|
||||
if (actualBytes == -1)
|
||||
THROW_SYS_ERROR(FileReadError, "unable to read '%s'", strPtr(storageFileName(file)));
|
||||
|
||||
// Track total bytes read
|
||||
totalBytes += (size_t)actualBytes;
|
||||
}
|
||||
while (actualBytes != 0);
|
||||
|
||||
// Resize buffer to total bytes read
|
||||
bufResize((Buffer *)result, totalBytes);
|
||||
}
|
||||
CATCH_ANY()
|
||||
{
|
||||
// Free buffer on error if it was allocated
|
||||
bufFree((Buffer *)result);
|
||||
|
||||
RETHROW();
|
||||
}
|
||||
FINALLY()
|
||||
{
|
||||
close(STORAGE_DATA(file)->handle);
|
||||
storageFileFree(file);
|
||||
}
|
||||
TRY_END();
|
||||
}
|
||||
|
||||
return (Buffer *)result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
@ -186,65 +124,18 @@ storageList(const Storage *this, const String *pathExp, StorageListParam param)
|
||||
StringList *result = NULL;
|
||||
|
||||
String *path = NULL;
|
||||
DIR *dir = NULL;
|
||||
RegExp *regExp = NULL;
|
||||
|
||||
TRY_BEGIN()
|
||||
{
|
||||
// Build the path
|
||||
path = storagePathNP(this, pathExp);
|
||||
|
||||
// Open the directory for read
|
||||
dir = opendir(strPtr(path));
|
||||
|
||||
// If the directory could not be opened process errors but ignore missing directories when specified
|
||||
if (!dir)
|
||||
{
|
||||
if (param.errorOnMissing || errno != ENOENT)
|
||||
THROW_SYS_ERROR(PathOpenError, "unable to open directory '%s' for read", strPtr(path));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Prepare regexp if an expression was passed
|
||||
if (param.expression != NULL)
|
||||
regExp = regExpNew(param.expression);
|
||||
|
||||
// Create the string list now that we know the directory is valid
|
||||
result = strLstNew();
|
||||
|
||||
// Read the directory entries
|
||||
struct dirent *dirEntry = readdir(dir);
|
||||
|
||||
while (dirEntry != NULL)
|
||||
{
|
||||
String *entry = strNew(dirEntry->d_name);
|
||||
|
||||
// Exclude current/parent directory and apply the expression if specified
|
||||
if (!strEqZ(entry, ".") && !strEqZ(entry, "..") && (regExp == NULL || regExpMatch(regExp, entry)))
|
||||
strLstAdd(result, entry);
|
||||
else
|
||||
strFree(entry);
|
||||
|
||||
dirEntry = readdir(dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
CATCH_ANY()
|
||||
{
|
||||
// Free list on error
|
||||
strLstFree(result);
|
||||
|
||||
RETHROW();
|
||||
// Call driver function
|
||||
result = storageDriverPosixList(path, param.errorOnMissing, param.expression);
|
||||
}
|
||||
FINALLY()
|
||||
{
|
||||
strFree(path);
|
||||
|
||||
if (dir != NULL)
|
||||
closedir(dir);
|
||||
|
||||
if (regExp != NULL)
|
||||
regExpFree(regExp);
|
||||
}
|
||||
TRY_END();
|
||||
|
||||
@ -263,36 +154,19 @@ storageOpenRead(const Storage *this, const String *fileExp, StorageOpenReadParam
|
||||
MEM_CONTEXT_NEW_BEGIN("StorageFileRead")
|
||||
{
|
||||
String *fileName = storagePathNP(this, fileExp);
|
||||
int fileHandle;
|
||||
|
||||
// Open the file and handle errors
|
||||
fileHandle = open(strPtr(fileName), O_RDONLY, 0);
|
||||
// Call driver function
|
||||
void *data = storageDriverPosixOpenRead(fileName, param.ignoreMissing);
|
||||
|
||||
if (fileHandle == -1)
|
||||
// Free mem contexts if missing files are ignored
|
||||
if (data == NULL)
|
||||
{
|
||||
// Error unless ignore missing is specified
|
||||
if (!param.ignoreMissing || errno != ENOENT)
|
||||
THROW_SYS_ERROR(FileOpenError, "unable to open '%s' for read", strPtr(fileName));
|
||||
|
||||
// Free mem contexts if missing files are ignored
|
||||
memContextSwitch(MEM_CONTEXT_OLD());
|
||||
memContextFree(MEM_CONTEXT_NEW());
|
||||
}
|
||||
// Else create the storage file
|
||||
else
|
||||
{
|
||||
// Create the storage file and data
|
||||
StorageFileDataPosix *data = NULL;
|
||||
|
||||
MEM_CONTEXT_NEW_BEGIN("StorageFileReadDataPosix")
|
||||
{
|
||||
data = memNew(sizeof(StorageFileDataPosix));
|
||||
data->memContext = MEM_CONTEXT_NEW();
|
||||
data->handle = fileHandle;
|
||||
}
|
||||
MEM_CONTEXT_NEW_END();
|
||||
|
||||
result = storageFileNew(this, fileName, storageFileTypeRead, data);
|
||||
}
|
||||
}
|
||||
MEM_CONTEXT_NEW_END();
|
||||
|
||||
@ -312,27 +186,11 @@ storageOpenWrite(const Storage *this, const String *fileExp, StorageOpenWritePar
|
||||
MEM_CONTEXT_NEW_BEGIN("StorageFileWrite")
|
||||
{
|
||||
String *fileName = storagePathNP(this, fileExp);
|
||||
int fileHandle;
|
||||
|
||||
// Open the file and handle errors
|
||||
fileHandle = open(
|
||||
strPtr(fileName), O_CREAT | O_TRUNC | O_WRONLY, param.mode == 0 ? this->modeFile : param.mode);
|
||||
|
||||
if (fileHandle == -1)
|
||||
THROW_SYS_ERROR(FileOpenError, "unable to open '%s' for write", strPtr(fileName));
|
||||
|
||||
// Create the storage file and data
|
||||
StorageFileDataPosix *data = NULL;
|
||||
|
||||
MEM_CONTEXT_NEW_BEGIN("StorageFileReadDataPosix")
|
||||
{
|
||||
data = memNew(sizeof(StorageFileDataPosix));
|
||||
data->memContext = MEM_CONTEXT_NEW();
|
||||
data->handle = fileHandle;
|
||||
}
|
||||
MEM_CONTEXT_NEW_END();
|
||||
|
||||
result = storageFileNew(this, fileName, storageFileTypeWrite, data);
|
||||
// Call driver function
|
||||
result = storageFileNew(
|
||||
this, fileName, storageFileTypeWrite,
|
||||
storageDriverPosixOpenWrite(fileName, param.mode != 0 ? param.mode : this->modeFile));
|
||||
}
|
||||
MEM_CONTEXT_NEW_END();
|
||||
|
||||
@ -451,19 +309,9 @@ storagePathCreate(const Storage *this, const String *pathExp, StoragePathCreateP
|
||||
// Build the path
|
||||
String *path = storagePathNP(this, pathExp);
|
||||
|
||||
// Attempt to create the directory
|
||||
if (mkdir(strPtr(path), param.mode != 0 ? param.mode : STORAGE_PATH_MODE_DEFAULT) == -1)
|
||||
{
|
||||
// If the parent path does not exist then create it if allowed
|
||||
if (errno == ENOENT && !param.noParentCreate)
|
||||
{
|
||||
storagePathCreate(this, strPath(path), param);
|
||||
storagePathCreate(this, path, param);
|
||||
}
|
||||
// Ignore path exists if allowed
|
||||
else if (errno != EEXIST || param.errorOnExists)
|
||||
THROW_SYS_ERROR(PathCreateError, "unable to create path '%s'", strPtr(path));
|
||||
}
|
||||
// Call driver function
|
||||
storageDriverPosixPathCreate(
|
||||
path, param.errorOnExists, param.noParentCreate, param.mode != 0 ? param.mode : this->modePath);
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
}
|
||||
@ -476,81 +324,28 @@ storagePut(const StorageFile *file, const Buffer *buffer)
|
||||
{
|
||||
// Write data if buffer is not null. Otherwise, an empty file is expected.
|
||||
if (buffer != NULL)
|
||||
{
|
||||
TRY_BEGIN()
|
||||
{
|
||||
if (write(STORAGE_DATA(file)->handle, bufPtr(buffer), bufSize(buffer)) != (ssize_t)bufSize(buffer))
|
||||
THROW_SYS_ERROR(FileWriteError, "unable to write '%s'", strPtr(storageFileName(file)));
|
||||
}
|
||||
FINALLY()
|
||||
{
|
||||
close(STORAGE_DATA(file)->handle);
|
||||
storageFileFree(file);
|
||||
}
|
||||
TRY_END();
|
||||
}
|
||||
storageDriverPosixPut(file, buffer);
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Remove a file
|
||||
***********************************************************************************************************************************/
|
||||
void
|
||||
storageRemove(const Storage *this, const String *pathExp, StorageRemoveParam param)
|
||||
storageRemove(const Storage *this, const String *fileExp, StorageRemoveParam param)
|
||||
{
|
||||
ASSERT_STORAGE_ALLOWS_WRITE();
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
// Build the path
|
||||
String *file = storagePathNP(this, pathExp);
|
||||
String *file = storagePathNP(this, fileExp);
|
||||
|
||||
// Attempt to unlink the file
|
||||
if (unlink(strPtr(file)) == -1)
|
||||
{
|
||||
if (param.errorOnMissing || errno != ENOENT)
|
||||
THROW_SYS_ERROR(FileRemoveError, "unable to remove '%s'", strPtr(file));
|
||||
}
|
||||
// Call driver function
|
||||
storageDriverPosixRemove(file, param.errorOnMissing);
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Stat a file
|
||||
***********************************************************************************************************************************/
|
||||
StorageStat *
|
||||
storageStat(const Storage *this, const String *pathExp, StorageStatParam param)
|
||||
{
|
||||
StorageStat *result = NULL;
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
// Build the path
|
||||
String *path = storagePathNP(this, pathExp);
|
||||
|
||||
// Attempt to stat the file
|
||||
struct stat statFile;
|
||||
|
||||
if (stat(strPtr(path), &statFile) == -1)
|
||||
{
|
||||
if (errno != ENOENT || !param.ignoreMissing)
|
||||
THROW_SYS_ERROR(FileOpenError, "unable to stat '%s'", strPtr(path));
|
||||
}
|
||||
// Else set stats
|
||||
else
|
||||
{
|
||||
memContextSwitch(MEM_CONTEXT_OLD());
|
||||
result = memNew(sizeof(StorageStat));
|
||||
|
||||
result->mode = statFile.st_mode & 0777;
|
||||
|
||||
memContextSwitch(MEM_CONTEXT_TEMP());
|
||||
}
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Free storage
|
||||
***********************************************************************************************************************************/
|
||||
|
@ -164,33 +164,13 @@ typedef struct StorageRemoveParam
|
||||
bool errorOnMissing;
|
||||
} StorageRemoveParam;
|
||||
|
||||
#define storageRemoveP(this, pathExp, ...) \
|
||||
storageRemove(this, pathExp, (StorageRemoveParam){__VA_ARGS__})
|
||||
#define storageRemoveNP(this, pathExp) \
|
||||
storageRemove(this, pathExp, (StorageRemoveParam){0})
|
||||
#define storageRemoveP(this, fileExp, ...) \
|
||||
storageRemove(this, fileExp, (StorageRemoveParam){__VA_ARGS__})
|
||||
#define storageRemoveNP(this, fileExp) \
|
||||
storageRemove(this, fileExp, (StorageRemoveParam){0})
|
||||
|
||||
void storageRemove(const Storage *this, const String *fileExp, StorageRemoveParam param);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
storageStat
|
||||
***********************************************************************************************************************************/
|
||||
typedef struct StorageStat
|
||||
{
|
||||
mode_t mode;
|
||||
} StorageStat;
|
||||
|
||||
typedef struct StorageStatParam
|
||||
{
|
||||
bool ignoreMissing;
|
||||
} StorageStatParam;
|
||||
|
||||
#define storageStatP(this, pathExp, ...) \
|
||||
storageStat(this, pathExp, (StorageStatParam){__VA_ARGS__})
|
||||
#define storageStatNP(this, pathExp) \
|
||||
storageStat(this, pathExp, (StorageStatParam){0})
|
||||
|
||||
StorageStat *storageStat(const Storage *this, const String *pathExp, StorageStatParam param);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
storageFree
|
||||
***********************************************************************************************************************************/
|
||||
@ -199,4 +179,9 @@ storageFree
|
||||
|
||||
void storageFree(const Storage *this);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Functions
|
||||
***********************************************************************************************************************************/
|
||||
size_t storageBufferSize(const Storage *this);
|
||||
|
||||
#endif
|
||||
|
@ -626,11 +626,12 @@ my $oTestDef =
|
||||
},
|
||||
{
|
||||
&TESTDEF_NAME => 'storage',
|
||||
&TESTDEF_TOTAL => 10,
|
||||
&TESTDEF_TOTAL => 9,
|
||||
&TESTDEF_C => true,
|
||||
|
||||
&TESTDEF_COVERAGE =>
|
||||
{
|
||||
'storage/driver/posix' => TESTDEF_COVERAGE_FULL,
|
||||
'storage/storage' => TESTDEF_COVERAGE_FULL,
|
||||
},
|
||||
},
|
||||
|
@ -4,6 +4,21 @@ Test Storage Manager
|
||||
#include "common/time.h"
|
||||
#include "storage/file.h"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Get the mode of a file on local storage
|
||||
***********************************************************************************************************************************/
|
||||
mode_t
|
||||
storageStatMode(const String *path)
|
||||
{
|
||||
// Attempt to stat the file
|
||||
struct stat statFile;
|
||||
|
||||
if (stat(strPtr(path), &statFile) == -1) // {uncovered - error should not happen}
|
||||
THROW_SYS_ERROR(FileOpenError, "unable to stat '%s'", strPtr(path)); // {uncovered+}
|
||||
|
||||
return statFile.st_mode & 0777;
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Test function for path expression
|
||||
***********************************************************************************************************************************/
|
||||
@ -183,14 +198,14 @@ testRun()
|
||||
if (testBegin("storagePathCreate()"))
|
||||
{
|
||||
TEST_RESULT_VOID(storagePathCreateNP(storageTest, strNew("sub1")), "create sub1");
|
||||
TEST_RESULT_INT(storageStatNP(storageTest, strNew("sub1"))->mode, 0750, "check sub1 dir mode");
|
||||
TEST_RESULT_INT(storageStatMode(storagePath(storageTest, strNew("sub1"))), 0750, "check sub1 dir mode");
|
||||
TEST_RESULT_VOID(storagePathCreateNP(storageTest, strNew("sub1")), "create sub1 again");
|
||||
TEST_ERROR(
|
||||
storagePathCreateP(storageTest, strNew("sub1"), .errorOnExists = true), PathCreateError,
|
||||
strPtr(strNewFmt("unable to create path '%s/sub1': [17] File exists", testPath())));
|
||||
|
||||
TEST_RESULT_VOID(storagePathCreateP(storageTest, strNew("sub2"), .mode = 0777), "create sub2 with custom mode");
|
||||
TEST_RESULT_INT(storageStatNP(storageTest, strNew("sub2"))->mode, 0777, "check sub2 dir mode");
|
||||
TEST_RESULT_INT(storageStatMode(storagePath(storageTest, strNew("sub2"))), 0777, "check sub2 dir mode");
|
||||
|
||||
TEST_ERROR(
|
||||
storagePathCreateP(storageTest, strNew("sub3/sub4"), .noParentCreate = true), PathCreateError,
|
||||
@ -230,14 +245,14 @@ testRun()
|
||||
String *fileName = strNewFmt("%s/testfile", testPath());
|
||||
|
||||
TEST_ASSIGN(file, storageOpenWriteNP(storageTest, fileName), "open file for write (defaults)");
|
||||
TEST_RESULT_INT(storageStatNP(storageTest, fileName)->mode, 0640, "check dir mode");
|
||||
TEST_RESULT_INT(storageStatMode(storagePath(storageTest, fileName)), 0640, "check file mode");
|
||||
close(STORAGE_DATA(file)->handle);
|
||||
|
||||
storageRemoveP(storageTest, fileName, .errorOnMissing = true);
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_ASSIGN(file, storageOpenWriteP(storageTest, fileName, .mode = 0777), "open file for write (custom)");
|
||||
TEST_RESULT_INT(storageStatNP(storageTest, fileName)->mode, 0777, "check file mode");
|
||||
TEST_RESULT_INT(storageStatMode(storagePath(storageTest, fileName)), 0777, "check file mode");
|
||||
close(STORAGE_DATA(file)->handle);
|
||||
|
||||
storageRemoveP(storageTest, fileName, .errorOnMissing = true);
|
||||
@ -316,25 +331,4 @@ testRun()
|
||||
storageRemoveNP(storageTest, fileNoPerm), FileRemoveError,
|
||||
strPtr(strNewFmt("unable to remove '%s': [13] Permission denied", strPtr(fileNoPerm))));
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
if (testBegin("storageStat()"))
|
||||
{
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_RESULT_VOID(storagePathCreateP(storageTest, strNew("dir"), .mode = 0777), "create dir with custom mode");
|
||||
TEST_RESULT_INT(storageStatNP(storageTest, strNew("dir"))->mode, 0777, "check dir mode");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_ERROR(
|
||||
storageStatNP(storageTest, strNew("missing")), FileOpenError,
|
||||
strPtr(strNewFmt("unable to stat '%s/missing': [2] No such file or directory", testPath())));
|
||||
TEST_RESULT_PTR(storageStatP(storageTest, strNew("missing"), .ignoreMissing = true), NULL, "ignore missing file");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_ERROR(
|
||||
storageStatNP(storageTest, fileNoPerm), FileOpenError,
|
||||
strPtr(strNewFmt("unable to stat '%s': [13] Permission denied", strPtr(fileNoPerm))));
|
||||
|
||||
TEST_RESULT_INT(system(strPtr(strNewFmt("sudo rm -rf %s", strPtr(strPath(fileNoPerm))))), 0, "remove no perm dir");
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user