Support access of read only repositories

This commit is contained in:
Jonas Borgström 2013-08-11 22:18:56 +02:00
parent 012e0d4153
commit 16d9e55f84
5 changed files with 37 additions and 14 deletions

View File

@ -9,9 +9,10 @@ Version 0.8
(feature release, released on X)
- Support access of read only repositories.
- New syntax to enable repository encryption:
attic init --encryption="none|passphrase|keyfile"
- Detect and abort if repository is older than the cache
attic init --encryption="none|passphrase|keyfile".
- Detect and abort if repository is older than the cache.
Version 0.7

View File

@ -33,6 +33,7 @@ typedef struct {
int bucket_size;
int lower_limit;
int upper_limit;
int readonly;
} HashIndex;
#define MAGIC "ATTICIDX"
@ -56,7 +57,7 @@ typedef struct {
#define EPRINTF(msg, ...) EPRINTF_PATH(index->path, msg, ##__VA_ARGS__)
#define EPRINTF_PATH(path, msg, ...) fprintf(stderr, "hashindex: %s: " msg "\n", path, ##__VA_ARGS__)
static HashIndex *hashindex_open(const char *path);
static HashIndex *hashindex_open(const char *path, int readonly);
static int hashindex_close(HashIndex *index);
static int hashindex_clear(HashIndex *index);
static int hashindex_flush(HashIndex *index);
@ -138,15 +139,24 @@ hashindex_resize(HashIndex *index, int capacity)
/* Public API */
static HashIndex *
hashindex_open(const char *path)
hashindex_open(const char *path, int readonly)
{
void *addr;
int fd;
int fd, oflags, prot;
off_t length;
HashHeader *header;
HashIndex *index;
if((fd = open(path, O_RDWR)) < 0) {
if(readonly) {
oflags = O_RDONLY;
prot = PROT_READ;
}
else {
oflags = O_RDWR;
prot = PROT_READ | PROT_WRITE;
}
if((fd = open(path, oflags)) < 0) {
EPRINTF_PATH(path, "open failed");
fprintf(stderr, "Failed to open %s\n", path);
return NULL;
@ -158,7 +168,7 @@ hashindex_open(const char *path)
}
return NULL;
}
addr = mmap(0, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
addr = mmap(0, length, prot, MAP_SHARED, fd, 0);
if(close(fd) < 0) {
EPRINTF_PATH(path, "close failed");
return NULL;
@ -180,6 +190,7 @@ hashindex_open(const char *path)
EPRINTF_PATH(path, "malloc failed");
return NULL;
}
index->readonly = readonly;
index->map_addr = addr;
index->map_length = length;
index->num_entries = header->num_entries;
@ -228,7 +239,7 @@ hashindex_create(const char *path, int capacity, int key_size, int value_size)
EPRINTF_PATH(path, "fclose failed");
return NULL;
}
return hashindex_open(path);
return hashindex_open(path, 0);
error:
EPRINTF_PATH(path, "fwrite failed");
if(fclose(fd) < 0) {
@ -251,6 +262,9 @@ hashindex_clear(HashIndex *index)
static int
hashindex_flush(HashIndex *index)
{
if(index->readonly) {
return 1;
}
*((int32_t *)(index->map_addr + 8)) = index->num_entries;
*((int32_t *)(index->map_addr + 12)) = index->num_buckets;
if(msync(index->map_addr, index->map_length, MS_SYNC) < 0) {
@ -264,7 +278,6 @@ static int
hashindex_close(HashIndex *index)
{
int rv = 1;
if(hashindex_flush(index) < 0) {
rv = 0;
}

View File

@ -6,7 +6,7 @@ cdef extern from "_hashindex.c":
ctypedef struct HashIndex:
pass
HashIndex *hashindex_open(char *path)
HashIndex *hashindex_open(char *path, int readonly)
HashIndex *hashindex_create(char *path, int capacity, int key_size, int value_size)
int hashindex_get_size(HashIndex *index)
int hashindex_clear(HashIndex *index)
@ -24,8 +24,8 @@ cdef class IndexBase:
cdef HashIndex *index
key_size = 32
def __cinit__(self, path):
self.index = hashindex_open(<bytes>os.fsencode(path))
def __cinit__(self, path, readonly=False):
self.index = hashindex_open(<bytes>os.fsencode(path), readonly)
if not self.index:
raise Exception('Failed to open %s' % path)

View File

@ -71,7 +71,7 @@ class Repository(object):
self.path = path
if not os.path.isdir(path):
raise self.DoesNotExist(path)
self.lock_fd = open(os.path.join(path, 'README'), 'r+')
self.lock_fd = open(os.path.join(path, 'config'), 'r')
fcntl.flock(self.lock_fd, fcntl.LOCK_EX)
self.config = RawConfigParser()
self.config.read(os.path.join(self.path, 'config'))
@ -108,7 +108,7 @@ class Repository(object):
self.compact = set()
else:
if read_only:
self.index = NSIndex((os.path.join(self.path, 'index.%d') % head).encode('utf-8'))
self.index = NSIndex((os.path.join(self.path, 'index.%d') % head).encode('utf-8'), readonly=True)
else:
shutil.copy(os.path.join(self.path, 'index.%d' % head),
os.path.join(self.path, 'index.tmp'))

View File

@ -210,6 +210,15 @@ class ArchiverTestCase(AtticTestCase):
fd.close()
self.attic('verify', self.repository_location + '::test', exit_code=1)
def test_readonly_repository(self):
self.create_src_archive('test')
os.system('chmod -R ugo-w ' + self.repository_path)
try:
self.attic('verify', self.repository_location + '::test')
finally:
# Restore permissions so shutil.rmtree is able to delete it
os.system('chmod -R u+w ' + self.repository_path)
def test_prune_repository(self):
self.attic('init', self.repository_location)
self.attic('create', self.repository_location + '::test1', src_dir)