1
0
Fork 0
arangodb/lib/BasicsC/files.c

1121 lines
26 KiB
C

////////////////////////////////////////////////////////////////////////////////
/// @brief file functions
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-2012 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "files.h"
#ifdef TRI_HAVE_DIRENT_H
#include <dirent.h>
#endif
#ifdef TRI_HAVE_DIRECT_H
#include <direct.h>
#endif
#ifdef TRI_HAVE_SYS_FILE_H
#include <sys/file.h>
#endif
#include "BasicsC/conversions.h"
#include "BasicsC/locks.h"
#include "BasicsC/logging.h"
#include "BasicsC/string-buffer.h"
#include "BasicsC/strings.h"
#include "BasicsC/threads.h"
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup Files
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief already initialised
////////////////////////////////////////////////////////////////////////////////
static bool Initialised = false;
////////////////////////////////////////////////////////////////////////////////
/// @brief names of blocking files
////////////////////////////////////////////////////////////////////////////////
static TRI_vector_string_t FileNames;
////////////////////////////////////////////////////////////////////////////////
/// @brief descriptors of blocking files
////////////////////////////////////////////////////////////////////////////////
static TRI_vector_t FileDescriptors;
////////////////////////////////////////////////////////////////////////////////
/// @brief lock for protected access to vector FileNames
////////////////////////////////////////////////////////////////////////////////
static TRI_read_write_lock_t FileNamesLock;
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup Files
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief linear search of the giving element
///
/// @return index of the element in the vector
/// -1 when the element was not found
////////////////////////////////////////////////////////////////////////////////
static ssize_t LookupElementVectorString (TRI_vector_string_t * vector, char const * element) {
int idx = -1;
size_t i;
TRI_ReadLockReadWriteLock(&FileNamesLock);
for (i = 0; i < vector->_length; i++) {
if (TRI_EqualString(element, vector->_buffer[i])) {
idx = i;
break;
}
}
TRI_ReadUnlockReadWriteLock(&FileNamesLock);
return idx;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief callback function for removing all locked files by a process
////////////////////////////////////////////////////////////////////////////////
static void RemoveAllLockedFiles (void) {
size_t i;
int fd;
TRI_WriteLockReadWriteLock(&FileNamesLock);
for (i = 0; i < FileNames._length; i++) {
TRI_UnlinkFile(FileNames._buffer[i]);
TRI_RemoveVectorString(&FileNames, i);
fd = * (int*) TRI_AtVector(&FileDescriptors, i);
TRI_CLOSE(fd);
TRI_RemoveVector(&FileDescriptors, i);
}
TRI_WriteUnlockReadWriteLock(&FileNamesLock);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief initializes some structures which are needed by the file functions
////////////////////////////////////////////////////////////////////////////////
static void InitialiseLockFiles (void) {
if (Initialised) {
return;
}
TRI_InitVectorString(&FileNames, TRI_CORE_MEM_ZONE);
TRI_InitVector(&FileDescriptors, TRI_CORE_MEM_ZONE, sizeof(int));
TRI_InitReadWriteLock(&FileNamesLock);
atexit(&RemoveAllLockedFiles);
Initialised = true;
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup Files
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief sets close-on-exit for a socket
////////////////////////////////////////////////////////////////////////////////
#ifdef TRI_HAVE_WIN32_CLOSE_ON_EXEC
bool TRI_SetCloseOnExecFile (socket_t fd) {
return true;
}
#else
bool TRI_SetCloseOnExecFile (socket_t fd) {
long flags = fcntl(fd, F_GETFD, 0);
if (flags < 0) {
return false;
}
flags = fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
if (flags < 0) {
return false;
}
return true;
}
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief checks if path is a directory
////////////////////////////////////////////////////////////////////////////////
bool TRI_IsDirectory (char const* path) {
struct stat stbuf;
int res;
res = stat(path, &stbuf);
return (res == 0) && ((stbuf.st_mode & S_IFMT) == S_IFDIR);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief checks if file exists
////////////////////////////////////////////////////////////////////////////////
bool TRI_ExistsFile (char const* path) {
struct stat stbuf;
int res;
res = stat(path, &stbuf);
return res == 0;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a directory
////////////////////////////////////////////////////////////////////////////////
bool TRI_CreateDirectory (char const* path) {
int res;
res = TRI_MKDIR(path, 0777);
if (res != 0) {
TRI_set_errno(TRI_ERROR_SYS_ERROR);
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief removes an empty directory
////////////////////////////////////////////////////////////////////////////////
int TRI_RemoveEmptyDirectory (char const* filename) {
int res;
res = TRI_RMDIR(filename);
if (res != 0) {
LOG_TRACE("cannot remove directory '%s': %s", filename, TRI_LAST_ERROR_STR);
return TRI_set_errno(TRI_ERROR_SYS_ERROR);
}
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief removes a directory recursively
////////////////////////////////////////////////////////////////////////////////
int TRI_RemoveDirectory (char const* filename) {
if (TRI_IsDirectory(filename)) {
TRI_vector_string_t files;
size_t i;
int res;
int subres;
LOG_TRACE("removing directory '%s'", filename);
res = TRI_ERROR_NO_ERROR;
files = TRI_FilesDirectory(filename);
for (i = 0; i < files._length; ++i) {
char* full;
full = TRI_Concatenate2File(filename, files._buffer[i]);
subres = TRI_RemoveDirectory(full);
TRI_FreeString(TRI_CORE_MEM_ZONE, full);
if (subres != TRI_ERROR_NO_ERROR) {
res = subres;
}
}
TRI_DestroyVectorString(&files);
if (res == TRI_ERROR_NO_ERROR) {
res = TRI_RemoveEmptyDirectory(filename);
}
return res;
}
else if (TRI_ExistsFile(filename)) {
LOG_TRACE("removing file '%s'", filename);
return TRI_UnlinkFile(filename);
}
else {
LOG_TRACE("removing non-existing file '%s'", filename);
return TRI_ERROR_NO_ERROR;
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief extracts the dirname
////////////////////////////////////////////////////////////////////////////////
char* TRI_Dirname (char const* path) {
size_t n;
size_t m;
char const* p;
n = strlen(path);
m = 0;
if (1 < n) {
if (path[n - 1] == TRI_DIR_SEPARATOR_CHAR) {
m = 1;
}
}
if (n == 0) {
return TRI_DuplicateString(".");
}
else if (n == 1 && *path == TRI_DIR_SEPARATOR_CHAR) {
return TRI_DuplicateString(TRI_DIR_SEPARATOR_STR);
}
else if (n - m == 1 && *path == '.') {
return TRI_DuplicateString(".");
}
else if (n - m == 2 && path[0] == '.' && path[1] == '.') {
return TRI_DuplicateString("..");
}
for (p = path + (n - m - 1); path < p; --p) {
if (*p == TRI_DIR_SEPARATOR_CHAR) {
break;
}
}
if (path == p) {
if (*p == TRI_DIR_SEPARATOR_CHAR) {
return TRI_DuplicateString(TRI_DIR_SEPARATOR_STR);
}
else {
return TRI_DuplicateString(".");
}
}
n = p - path;
return TRI_DuplicateString2(path, n);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief extracts the basename
////////////////////////////////////////////////////////////////////////////////
char* TRI_Basename (char const* path) {
size_t n;
size_t m;
char const* p;
n = strlen(path);
m = 0;
if (1 < n) {
if (path[n - 1] == TRI_DIR_SEPARATOR_CHAR) {
m = 1;
}
}
if (n == 0) {
return TRI_DuplicateString("");
}
else if (n == 1 && *path == TRI_DIR_SEPARATOR_CHAR) {
return TRI_DuplicateString("");
}
else if (n - m == 1 && *path == '.') {
return TRI_DuplicateString("");
}
else if (n - m == 2 && path[0] == '.' && path[1] == '.') {
return TRI_DuplicateString("");
}
for (p = path + (n - m - 1); path < p; --p) {
if (*p == TRI_DIR_SEPARATOR_CHAR) {
break;
}
}
if (path == p) {
if (*p == TRI_DIR_SEPARATOR_CHAR) {
return TRI_DuplicateString2(path + 1, n - m);
}
}
n -= p - path;
return TRI_DuplicateString2(p + 1, n - 1);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a filename
////////////////////////////////////////////////////////////////////////////////
char* TRI_Concatenate2File (char const* path, char const* name) {
return TRI_Concatenate3String(path, TRI_DIR_SEPARATOR_STR, name);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a filename
////////////////////////////////////////////////////////////////////////////////
char* TRI_Concatenate3File (char const* path1, char const* path2, char const* name) {
return TRI_Concatenate5String(path1, TRI_DIR_SEPARATOR_STR, path2, TRI_DIR_SEPARATOR_STR, name);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns a list of files in path
////////////////////////////////////////////////////////////////////////////////
#ifdef TRI_HAVE_WIN32_LIST_FILES
TRI_vector_string_t TRI_FilesDirectory (char const* path) {
TRI_vector_string_t result;
struct _finddata_t fd;
intptr_t handle;
char* filter;
TRI_InitVectorString(&result, TRI_CORE_MEM_ZONE);
filter = TRI_Concatenate2String(path, "\\*");
if (!filter) {
return result;
}
handle = _findfirst(filter, &fd);
TRI_FreeString(TRI_CORE_MEM_ZONE, filter);
if (handle == -1) {
return result;
}
do {
if (strcmp(fd.name, ".") != 0 && strcmp(fd.name, "..") != 0) {
TRI_PushBackVectorString(&result, TRI_DuplicateString(fd.name));
}
}
while(_findnext(handle, &fd) != -1);
_findclose(handle);
return result;
}
#else
TRI_vector_string_t TRI_FilesDirectory (char const* path) {
TRI_vector_string_t result;
DIR * d;
struct dirent * de;
TRI_InitVectorString(&result, TRI_CORE_MEM_ZONE);
d = opendir(path);
if (d == 0) {
return result;
}
de = readdir(d);
while (de != 0) {
if (strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0) {
TRI_PushBackVectorString(&result, TRI_DuplicateString(de->d_name));
}
de = readdir(d);
}
closedir(d);
return result;
}
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief renames a file
////////////////////////////////////////////////////////////////////////////////
int TRI_RenameFile (char const* old, char const* filename) {
int res;
res = rename(old, filename);
if (res != 0) {
LOG_TRACE("cannot rename file from '%s' to '%s': %s", old, filename, TRI_LAST_ERROR_STR);
return TRI_set_errno(TRI_ERROR_SYS_ERROR);
}
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief unlinks a file
////////////////////////////////////////////////////////////////////////////////
int TRI_UnlinkFile (char const* filename) {
int res;
res = TRI_UNLINK(filename);
if (res != 0) {
LOG_TRACE("cannot unlink file '%s': %s", filename, TRI_LAST_ERROR_STR);
return TRI_set_errno(TRI_ERROR_SYS_ERROR);
}
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief reads into a buffer from a file
////////////////////////////////////////////////////////////////////////////////
bool TRI_ReadPointer (int fd, void* buffer, size_t length) {
char* ptr;
ptr = buffer;
while (0 < length) {
ssize_t n = TRI_READ(fd, ptr, length);
if (n < 0) {
TRI_set_errno(TRI_ERROR_SYS_ERROR);
LOG_ERROR("cannot read: %s", TRI_LAST_ERROR_STR);
return false;
}
else if (n == 0) {
TRI_set_errno(TRI_ERROR_SYS_ERROR);
LOG_ERROR("cannot read, end-of-file");
return false;
}
ptr += n;
length -= n;
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief writes buffer to a file
////////////////////////////////////////////////////////////////////////////////
bool TRI_WritePointer (int fd, void const* buffer, size_t length) {
char const* ptr;
ptr = buffer;
while (0 < length) {
ssize_t n = TRI_WRITE(fd, ptr, length);
if (n < 0) {
TRI_set_errno(TRI_ERROR_SYS_ERROR);
LOG_ERROR("cannot write: %s", TRI_LAST_ERROR_STR);
return false;
}
ptr += n;
length -= n;
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief fsyncs a file
////////////////////////////////////////////////////////////////////////////////
bool TRI_fsync (int fd) {
int res = fsync(fd);
#ifdef __APPLE__
if (res == 0) {
res = fcntl(fd, F_FULLFSYNC, 0);
}
#endif
if (res == 0) {
return true;
}
else {
TRI_set_errno(TRI_ERROR_SYS_ERROR);
return false;
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief slurps in a file
////////////////////////////////////////////////////////////////////////////////
char* TRI_SlurpFile (TRI_memory_zone_t* zone, char const* filename) {
TRI_string_buffer_t result;
char buffer[10240];
int fd;
int res;
fd = TRI_OPEN(filename, O_RDONLY);
if (fd == -1) {
TRI_set_errno(TRI_ERROR_SYS_ERROR);
return NULL;
}
TRI_InitStringBuffer(&result, zone);
while (true) {
ssize_t n;
n = TRI_READ(fd, buffer, sizeof(buffer));
if (n == 0) {
break;
}
if (n < 0) {
TRI_CLOSE(fd);
TRI_AnnihilateStringBuffer(&result);
TRI_set_errno(TRI_ERROR_SYS_ERROR);
return NULL;
}
res = TRI_AppendString2StringBuffer(&result, buffer, n);
if (res != TRI_ERROR_NO_ERROR) {
TRI_CLOSE(fd);
TRI_AnnihilateStringBuffer(&result);
return NULL;
}
}
TRI_CLOSE(fd);
return result._buffer;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a lock file based on the PID
////////////////////////////////////////////////////////////////////////////////
#ifdef TRI_HAVE_WIN32_FILE_LOCKING
int TRI_CreateLockFile (char const* filename) {
TRI_pid_t pid;
char* buf;
char* fn;
int fd;
int rv;
int res;
InitialiseLockFiles();
if (0 <= LookupElementVectorString(&FileNames, filename)) {
return TRI_ERROR_NO_ERROR;
}
fd = TRI_CREATE(filename, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1) {
return TRI_set_errno(TRI_ERROR_SYS_ERROR);
}
pid = TRI_CurrentProcessId();
buf = TRI_StringUInt32(pid);
rv = TRI_WRITE(fd, buf, strlen(buf));
if (rv == -1) {
res = TRI_set_errno(TRI_ERROR_SYS_ERROR);
TRI_FreeString(TRI_CORE_MEM_ZONE, buf);
TRI_CLOSE(fd);
TRI_UNLINK(filename);
return res;
}
TRI_FreeString(TRI_CORE_MEM_ZONE, buf);
TRI_CLOSE(fd);
// try to open pid file
fd = TRI_OPEN(filename, O_RDONLY);
if (fd < 0) {
return TRI_set_errno(TRI_ERROR_SYS_ERROR);
}
// ..........................................................................
// TODO: use windows LockFile to lock the file
// ..........................................................................
//rv = LockFileEx(fd, LOCKFILE_EXCLUSIVE_LOCK, 0, 0, 0, 0);
// rv = flock(fd, LOCK_EX);
rv = true;
if (!rv) {
res = TRI_set_errno(TRI_ERROR_SYS_ERROR);
TRI_CLOSE(fd);
TRI_UNLINK(filename);
return res;
}
fn = TRI_DuplicateString(filename);
TRI_WriteLockReadWriteLock(&FileNamesLock);
TRI_PushBackVectorString(&FileNames, fn);
TRI_PushBackVector(&FileDescriptors, &fd);
TRI_WriteUnlockReadWriteLock(&FileNamesLock);
return TRI_ERROR_NO_ERROR;
}
#else
int TRI_CreateLockFile (char const* filename) {
TRI_pid_t pid;
char* buf;
char* fn;
int fd;
int rv;
int res;
InitialiseLockFiles();
if (0 <= LookupElementVectorString(&FileNames, filename)) {
return TRI_ERROR_NO_ERROR;
}
fd = TRI_CREATE(filename, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1) {
return TRI_set_errno(TRI_ERROR_SYS_ERROR);
}
pid = TRI_CurrentProcessId();
buf = TRI_StringUInt32(pid);
rv = TRI_WRITE(fd, buf, strlen(buf));
if (rv == -1) {
res = TRI_set_errno(TRI_ERROR_SYS_ERROR);
TRI_FreeString(TRI_CORE_MEM_ZONE, buf);
TRI_CLOSE(fd);
TRI_UNLINK(filename);
return res;
}
TRI_FreeString(TRI_CORE_MEM_ZONE, buf);
TRI_CLOSE(fd);
// try to open pid file
fd = TRI_OPEN(filename, O_RDONLY);
if (fd < 0) {
return TRI_set_errno(TRI_ERROR_SYS_ERROR);
}
// try to lock pid file
rv = flock(fd, LOCK_EX);
if (rv == -1) {
res = TRI_set_errno(TRI_ERROR_SYS_ERROR);
TRI_CLOSE(fd);
TRI_UNLINK(filename);
return res;
}
fn = TRI_DuplicateString(filename);
TRI_WriteLockReadWriteLock(&FileNamesLock);
TRI_PushBackVectorString(&FileNames, fn);
TRI_PushBackVector(&FileDescriptors, &fd);
TRI_WriteUnlockReadWriteLock(&FileNamesLock);
return TRI_ERROR_NO_ERROR;
}
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief verifies a lock file based on the PID
////////////////////////////////////////////////////////////////////////////////
#ifdef TRI_HAVE_WIN32_FILE_LOCKING
int TRI_VerifyLockFile (char const* filename) {
TRI_pid_t pid;
char buffer[128];
int can_lock;
int fd;
int res;
ssize_t n;
uint32_t fc;
if (! TRI_ExistsFile(filename)) {
return TRI_set_errno(TRI_ERROR_SYS_ERROR);
}
fd = TRI_OPEN(filename, O_RDONLY);
n = TRI_READ(fd, buffer, sizeof(buffer));
TRI_CLOSE(fd);
// file empty
if (n == 0) {
return TRI_set_errno(TRI_ERROR_ILLEGAL_NUMBER);
}
// not really necessary, but this shuts up valgrind
memset(buffer, 0, sizeof(buffer));
fc = TRI_UInt32String(buffer);
res = TRI_errno();
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
pid = fc;
// ..........................................................................
// determine if a process with pid exists
// ..........................................................................
// use OpenProcess / TerminateProcess as a replacement for kill
//if (kill(pid, 0) == -1) {
// return TRI_set_errno(TRI_ERROR_DEAD_PID);
//}
fd = TRI_OPEN(filename, O_RDONLY);
if (fd < 0) {
return TRI_set_errno(TRI_ERROR_SYS_ERROR);
}
// ..........................................................................
// TODO: Use windows LockFileEx to determine if file can be locked
// ..........................................................................
// = LockFileEx(fd, LOCKFILE_EXCLUSIVE_LOCK, 0, 0, 0, 0);
//can_lock = flock(fd, LOCK_EX | LOCK_NB);
can_lock = true;
// file was not yet be locked
if (can_lock == 0) {
res = TRI_set_errno(TRI_ERROR_SYS_ERROR);
// ........................................................................
// TODO: Use windows LockFileEx to determine if file can be locked
// ........................................................................
//flock(fd, LOCK_UN);
TRI_CLOSE(fd);
return res;
}
TRI_CLOSE(fd);
return TRI_ERROR_NO_ERROR;
}
#else
int TRI_VerifyLockFile (char const* filename) {
TRI_pid_t pid;
char buffer[128];
int can_lock;
int fd;
int res;
ssize_t n;
uint32_t fc;
if (! TRI_ExistsFile(filename)) {
return TRI_set_errno(TRI_ERROR_SYS_ERROR);
}
fd = TRI_OPEN(filename, O_RDONLY);
n = TRI_READ(fd, buffer, sizeof(buffer));
TRI_CLOSE(fd);
// file empty
if (n == 0) {
return TRI_set_errno(TRI_ERROR_ILLEGAL_NUMBER);
}
// not really necessary, but this shuts up valgrind
memset(buffer, 0, sizeof(buffer));
fc = TRI_UInt32String(buffer);
res = TRI_errno();
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
pid = fc;
if (kill(pid, 0) == -1) {
return TRI_set_errno(TRI_ERROR_DEAD_PID);
}
fd = TRI_OPEN(filename, O_RDONLY);
if (fd < 0) {
return TRI_set_errno(TRI_ERROR_SYS_ERROR);
}
can_lock = flock(fd, LOCK_EX | LOCK_NB);
// file was not yet be locked
if (can_lock == 0) {
res = TRI_set_errno(TRI_ERROR_SYS_ERROR);
flock(fd, LOCK_UN);
TRI_CLOSE(fd);
return res;
}
TRI_CLOSE(fd);
return TRI_ERROR_NO_ERROR;
}
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief releases a lock file based on the PID
////////////////////////////////////////////////////////////////////////////////
#ifdef TRI_HAVE_WIN32_FILE_LOCKING
int TRI_DestroyLockFile (char const* filename) {
int fd;
int n;
int res;
InitialiseLockFiles();
n = LookupElementVectorString(&FileNames, filename);
if (n < 0) {
return false;
}
fd = TRI_OPEN(filename, O_RDWR);
// ..........................................................................
// TODO: Use windows LockFileEx to determine if file can be locked
// ..........................................................................
//flock(fd, LOCK_UN);
//res = flock(fd, LOCK_UN);
res = 0;
TRI_CLOSE(fd);
if (res == 0) {
TRI_UnlinkFile(filename);
TRI_WriteLockReadWriteLock(&FileNamesLock);
TRI_RemoveVectorString(&FileNames, n);
fd = * (int*) TRI_AtVector(&FileDescriptors, n);
TRI_CLOSE(fd);
TRI_WriteUnlockReadWriteLock(&FileNamesLock);
}
return res;
}
#else
int TRI_DestroyLockFile (char const* filename) {
int fd;
int n;
int res;
InitialiseLockFiles();
n = LookupElementVectorString(&FileNames, filename);
if (n < 0) {
return false;
}
fd = TRI_OPEN(filename, O_RDWR);
res = flock(fd, LOCK_UN);
TRI_CLOSE(fd);
if (res == 0) {
TRI_UnlinkFile(filename);
TRI_WriteLockReadWriteLock(&FileNamesLock);
TRI_RemoveVectorString(&FileNames, n);
fd = * (int*) TRI_AtVector(&FileDescriptors, n);
TRI_CLOSE(fd);
TRI_WriteUnlockReadWriteLock(&FileNamesLock);
}
return res;
}
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief locates the directory containing the program
////////////////////////////////////////////////////////////////////////////////
char* TRI_LocateBinaryPath (char const* argv0) {
char const* p;
char* dir;
char* binaryPath = NULL;
size_t i;
// check if name contains a '/' ( or '\' for windows)
p = argv0;
for (; *p && *p != TRI_DIR_SEPARATOR_CHAR; ++p) {
}
// contains a path
if (*p) {
dir = TRI_Dirname(argv0);
if (dir == 0) {
binaryPath = TRI_DuplicateString("");
}
else {
binaryPath = TRI_DuplicateString(dir);
TRI_FreeString(TRI_CORE_MEM_ZONE, dir);
}
}
// check PATH variable
else {
p = getenv("PATH");
if (p == 0) {
binaryPath = TRI_DuplicateString("");
}
else {
TRI_vector_string_t files;
files = TRI_SplitString(p, ':');
for (i = 0; i < files._length; ++i) {
char* full;
char* prefix;
prefix = files._buffer[i];
if (*prefix) {
full = TRI_Concatenate2File(prefix, argv0);
}
else {
full = TRI_Concatenate2File(".", argv0);
}
if (TRI_ExistsFile(full)) {
TRI_FreeString(TRI_CORE_MEM_ZONE, full);
binaryPath = TRI_DuplicateString(files._buffer[i]);
break;
}
TRI_FreeString(TRI_CORE_MEM_ZONE, full);
}
if (binaryPath == NULL) {
binaryPath = TRI_DuplicateString(".");
}
TRI_DestroyVectorString(&files);
}
}
return binaryPath;
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
// End: