mirror of
https://git.proxmox.com/git/libgit2
synced 2025-08-04 16:42:30 +00:00
Add support for atomic file locking
The struct 'git_filelock' represents an atomically-locked file, git-style. Locked files can be modified atomically through the new file lock interface: int git_filelock_init(git_filelock *lock, const char *path); int git_filelock_lock(git_filelock *lock, int append); void git_filelock_unlock(git_filelock *lock); int git_filelock_commit(git_filelock *lock); int git_filelock_write(git_filelock *lock, const char *buffer, size_t length); Signed-off-by: Vicent Marti <tanoku@gmail.com>
This commit is contained in:
parent
3315782cb4
commit
bd0a51c0dd
132
src/filelock.c
Normal file
132
src/filelock.c
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* This file is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License, version 2,
|
||||||
|
* as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* In addition to the permissions in the GNU General Public License,
|
||||||
|
* the authors give you unlimited permission to link the compiled
|
||||||
|
* version of this file into combinations with other programs,
|
||||||
|
* and to distribute those combinations without any restriction
|
||||||
|
* coming from the use of this file. (The General Public License
|
||||||
|
* restrictions do apply in other respects; for example, they cover
|
||||||
|
* modification of the file, and distribution when not linked into
|
||||||
|
* a combined executable.)
|
||||||
|
*
|
||||||
|
* This file is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; see the file COPYING. If not, write to
|
||||||
|
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
||||||
|
* Boston, MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "filelock.h"
|
||||||
|
#include "fileops.h"
|
||||||
|
|
||||||
|
static const char *GIT_FILELOCK_EXTENSION = ".lock\0";
|
||||||
|
static const size_t GIT_FILELOCK_EXTLENGTH = 6;
|
||||||
|
|
||||||
|
#define BUILD_PATH_LOCK(_lock, _path) { \
|
||||||
|
memcpy(_path, _lock->path, _lock->path_length); \
|
||||||
|
memcpy(_path + _lock->path_length, GIT_FILELOCK_EXTENSION,\
|
||||||
|
GIT_FILELOCK_EXTLENGTH);\
|
||||||
|
}
|
||||||
|
|
||||||
|
int git_filelock_init(git_filelock *lock, const char *path)
|
||||||
|
{
|
||||||
|
if (lock == NULL || path == NULL)
|
||||||
|
return GIT_ERROR;
|
||||||
|
|
||||||
|
memset(lock, 0x0, sizeof(git_filelock));
|
||||||
|
|
||||||
|
lock->path_length = strlen(path);
|
||||||
|
|
||||||
|
if (lock->path_length + GIT_FILELOCK_EXTLENGTH >= GIT_PATH_MAX)
|
||||||
|
return GIT_ERROR;
|
||||||
|
|
||||||
|
memcpy(lock->path, path, lock->path_length);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int git_filelock_lock(git_filelock *lock, int append)
|
||||||
|
{
|
||||||
|
char path_lock[GIT_PATH_MAX];
|
||||||
|
BUILD_PATH_LOCK(lock, path_lock);
|
||||||
|
|
||||||
|
/* If file already exists, we cannot create a lock */
|
||||||
|
if (gitfo_exists(path_lock) == 0)
|
||||||
|
return GIT_EOSERR;
|
||||||
|
|
||||||
|
lock->file_lock = gitfo_creat(path_lock, 0666);
|
||||||
|
|
||||||
|
if (lock->file_lock < 0)
|
||||||
|
return GIT_EOSERR;
|
||||||
|
|
||||||
|
lock->is_locked = 1;
|
||||||
|
|
||||||
|
/* TODO: do a flock() in the descriptor file_lock */
|
||||||
|
|
||||||
|
if (append && gitfo_exists(lock->path) == 0) {
|
||||||
|
git_file source;
|
||||||
|
char buffer[2048];
|
||||||
|
size_t read_bytes;
|
||||||
|
|
||||||
|
source = gitfo_open(lock->path, O_RDONLY);
|
||||||
|
if (source < 0)
|
||||||
|
return GIT_EOSERR;
|
||||||
|
|
||||||
|
while ((read_bytes = gitfo_read(source, buffer, 2048)) > 0)
|
||||||
|
gitfo_write(lock->file_lock, buffer, read_bytes);
|
||||||
|
|
||||||
|
gitfo_close(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void git_filelock_unlock(git_filelock *lock)
|
||||||
|
{
|
||||||
|
char path_lock[GIT_PATH_MAX];
|
||||||
|
BUILD_PATH_LOCK(lock, path_lock);
|
||||||
|
|
||||||
|
if (lock->is_locked) {
|
||||||
|
/* The flock() in lock->file_lock is removed
|
||||||
|
* automatically when closing the descriptor */
|
||||||
|
gitfo_close(lock->file_lock);
|
||||||
|
gitfo_unlink(path_lock);
|
||||||
|
lock->is_locked = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int git_filelock_commit(git_filelock *lock)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
char path_lock[GIT_PATH_MAX];
|
||||||
|
BUILD_PATH_LOCK(lock, path_lock);
|
||||||
|
|
||||||
|
if (!lock->is_locked || lock->file_lock < 0)
|
||||||
|
return GIT_ERROR;
|
||||||
|
|
||||||
|
/* FIXME: flush the descriptor? */
|
||||||
|
gitfo_close(lock->file_lock);
|
||||||
|
|
||||||
|
error = gitfo_move_file(path_lock, lock->path);
|
||||||
|
|
||||||
|
if (error < 0)
|
||||||
|
gitfo_unlink(path_lock);
|
||||||
|
|
||||||
|
lock->is_locked = 0;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int git_filelock_write(git_filelock *lock, const void *buffer, size_t length)
|
||||||
|
{
|
||||||
|
if (!lock->is_locked || lock->file_lock < 0)
|
||||||
|
return GIT_ERROR;
|
||||||
|
|
||||||
|
return gitfo_write(lock->file_lock, (void *)buffer, length);
|
||||||
|
}
|
23
src/filelock.h
Normal file
23
src/filelock.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef INCLUDE_filelock_h__
|
||||||
|
#define INCLUDE_filelock_h__
|
||||||
|
|
||||||
|
#include "fileops.h"
|
||||||
|
|
||||||
|
struct git_filelock {
|
||||||
|
|
||||||
|
char path[GIT_PATH_MAX];
|
||||||
|
size_t path_length;
|
||||||
|
|
||||||
|
git_file file_lock;
|
||||||
|
int is_locked;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct git_filelock git_filelock;
|
||||||
|
|
||||||
|
int git_filelock_init(git_filelock *lock, const char *path);
|
||||||
|
int git_filelock_lock(git_filelock *lock, int append);
|
||||||
|
void git_filelock_unlock(git_filelock *lock);
|
||||||
|
int git_filelock_commit(git_filelock *lock);
|
||||||
|
int git_filelock_write(git_filelock *lock, const void *buffer, size_t length);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user