15
# ifndef DIR_SEPARATOR
16
# define DIR_SEPARATOR "\\"
19
# define S_IRUSR _S_IREAD
22
# define S_IWUSR _S_IWRITE
25
# define DIR_SEPARATOR "/"
33
extern Store *store_new();
34
extern void store_destroy(Store *store);
35
extern OutStream *os_new();
36
extern InStream *is_new();
37
extern int file_is_lock(char *filename);
40
* Create a filepath for a file in the store using the operating systems
41
* default file seperator.
43
static char *join_path(char *buf, const char *base, const char *filename)
45
snprintf(buf, MAX_FILE_PATH, "%s"DIR_SEPARATOR"%s", base, filename);
49
static void fs_touch(Store *store, char *filename)
52
char path[MAX_FILE_PATH];
53
join_path(path, store->dir.path, filename);
54
if ((f = creat(path, store->file_mode)) == 0) {
55
RAISE(IO_ERROR, "couldn't create file %s: <%s>", path,
61
static int fs_exists(Store *store, char *filename)
64
char path[MAX_FILE_PATH];
65
join_path(path, store->dir.path, filename);
68
if (errno != ENOENT) {
69
RAISE(IO_ERROR, "checking existance of %s: <%s>", path,
78
static int fs_remove(Store *store, char *filename)
80
char path[MAX_FILE_PATH];
81
return remove(join_path(path, store->dir.path, filename));
84
static void fs_rename(Store *store, char *from, char *to)
86
char path1[MAX_FILE_PATH], path2[MAX_FILE_PATH];
89
remove(join_path(path1, store->dir.path, to));
92
if (rename(join_path(path1, store->dir.path, from),
93
join_path(path2, store->dir.path, to)) < 0) {
94
RAISE(IO_ERROR, "couldn't rename file \"%s\" to \"%s\": <%s>",
95
path1, path2, strerror(errno));
99
static int fs_count(Store *store)
103
DIR *d = opendir(store->dir.path);
106
RAISE(IO_ERROR, "counting files in %s: <%s>",
107
store->dir.path, strerror(errno));
110
while ((de = readdir(d)) != NULL) {
111
if (de->d_name[0] > '/') { /* skip ., .., / and '\0'*/
120
static void fs_each(Store *store, void (*func)(char *fname, void *arg), void *arg)
123
DIR *d = opendir(store->dir.path);
126
RAISE(IO_ERROR, "doing 'each' in %s: <%s>",
127
store->dir.path, strerror(errno));
130
while ((de = readdir(d)) != NULL) {
131
if (de->d_name[0] > '/' /* skip ., .., / and '\0'*/
132
&& !file_is_lock(de->d_name)) {
133
func(de->d_name, arg);
139
static void fs_clear_locks(Store *store)
142
DIR *d = opendir(store->dir.path);
145
RAISE(IO_ERROR, "clearing locks in %s: <%s>",
146
store->dir.path, strerror(errno));
149
while ((de = readdir(d)) != NULL) {
150
if (file_is_lock(de->d_name)) {
151
char path[MAX_FILE_PATH];
152
remove(join_path(path, store->dir.path, de->d_name));
158
static void fs_clear(Store *store)
161
DIR *d = opendir(store->dir.path);
164
RAISE(IO_ERROR, "clearing files in %s: <%s>",
165
store->dir.path, strerror(errno));
168
while ((de = readdir(d)) != NULL) {
169
if (de->d_name[0] > '/' /* skip ., .., / and '\0'*/
170
&& !file_is_lock(de->d_name)) {
171
char path[MAX_FILE_PATH];
172
remove(join_path(path, store->dir.path, de->d_name));
178
static void fs_clear_all(Store *store)
181
DIR *d = opendir(store->dir.path);
184
RAISE(IO_ERROR, "clearing all files in %s: <%s>",
185
store->dir.path, strerror(errno));
188
while ((de = readdir(d)) != NULL) {
189
if (de->d_name[0] > '/') { /* skip ., .., / and '\0'*/
190
char path[MAX_FILE_PATH];
191
remove(join_path(path, store->dir.path, de->d_name));
200
* @param p the store to destroy
201
* @raise IO_ERROR if there is an error deleting the locks
203
static void fs_destroy(Store *store)
206
fs_clear_locks(store);
210
free(store->dir.path);
211
store_destroy(store);
214
static off_t fs_length(Store *store, char *filename)
216
char path[MAX_FILE_PATH];
219
if (stat(join_path(path, store->dir.path, filename), &stt)) {
220
RAISE(IO_ERROR, "getting lenth of %s: <%s>", path,
227
static void fso_flush_i(OutStream *os, uchar *src, int len)
229
if (len != write(os->file.fd, src, len)) {
230
RAISE(IO_ERROR, "flushing src of length %d, <%s>", len,
235
static void fso_seek_i(OutStream *os, off_t pos)
237
if (lseek(os->file.fd, pos, SEEK_SET) < 0) {
238
RAISE(IO_ERROR, "seeking position %"F_OFF_T_PFX"d: <%s>",
239
pos, strerror(errno));
243
static void fso_close_i(OutStream *os)
245
if (close(os->file.fd)) {
246
RAISE(IO_ERROR, "closing file: <%s>", strerror(errno));
250
const struct OutStreamMethods FS_OUT_STREAM_METHODS = {
256
static OutStream *fs_new_output(Store *store, const char *filename)
258
char path[MAX_FILE_PATH];
259
int fd = open(join_path(path, store->dir.path, filename),
260
O_WRONLY | O_CREAT | O_BINARY, store->file_mode);
263
RAISE(IO_ERROR, "couldn't create OutStream %s: <%s>",
264
path, strerror(errno));
269
os->m = &FS_OUT_STREAM_METHODS;
273
static void fsi_read_i(InStream *is, uchar *path, int len)
275
int fd = is->file.fd;
276
off_t pos = is_pos(is);
277
if (pos != lseek(fd, 0, SEEK_CUR)) {
278
lseek(fd, pos, SEEK_SET);
280
if (read(fd, path, len) != len) {
281
/* win: the wrong value can be returned for some reason so double check */
282
if (lseek(fd, 0, SEEK_CUR) != (pos + len)) {
283
RAISE(IO_ERROR, "couldn't read %d chars from %s: <%s>",
284
len, path, strerror(errno));
289
static void fsi_seek_i(InStream *is, off_t pos)
291
if (lseek(is->file.fd, pos, SEEK_SET) < 0) {
292
RAISE(IO_ERROR, "seeking pos %"F_OFF_T_PFX"d: <%s>",
293
pos, strerror(errno));
297
static void fsi_close_i(InStream *is)
299
if (close(is->file.fd)) {
300
RAISE(IO_ERROR, strerror(errno));
305
static off_t fsi_length_i(InStream *is)
308
if (fstat(is->file.fd, &stt)) {
309
RAISE(IO_ERROR, "fstat failed: <%s>", strerror(errno));
314
static const struct InStreamMethods FS_IN_STREAM_METHODS = {
321
static InStream *fs_open_input(Store *store, const char *filename)
324
char path[MAX_FILE_PATH];
325
int fd = open(join_path(path, store->dir.path, filename), O_RDONLY | O_BINARY);
327
RAISE(FILE_NOT_FOUND_ERROR,
328
"tried to open \"%s\" but it doesn't exist: <%s>",
329
path, strerror(errno));
333
is->d.path = estrdup(path);
334
is->m = &FS_IN_STREAM_METHODS;
338
#define LOCK_OBTAIN_TIMEOUT 10
341
struct timeval rb_time_interval _((VALUE));
344
static int fs_lock_obtain(Lock *lock)
347
int trys = LOCK_OBTAIN_TIMEOUT;
349
open(lock->name, O_CREAT | O_EXCL | O_RDWR,
350
S_IRUSR | S_IWUSR)) < 0) && (trys > 0)) {
352
/* sleep for 10 milliseconds */
365
static int fs_lock_is_locked(Lock *lock)
367
int f = open(lock->name, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR);
369
if (close(f) || remove(lock->name)) {
370
RAISE(IO_ERROR, "couldn't close lock \"%s\": <%s>", lock->name,
380
void fs_lock_release(Lock *lock)
385
static Lock *fs_open_lock_i(Store *store, char *lockname)
387
Lock *lock = ALLOC(Lock);
389
char path[MAX_FILE_PATH];
390
snprintf(lname, 100, "%s%s.lck", LOCK_PREFIX, lockname);
391
lock->name = estrdup(join_path(path, store->dir.path, lname));
393
lock->obtain = &fs_lock_obtain;
394
lock->release = &fs_lock_release;
395
lock->is_locked = &fs_lock_is_locked;
399
static void fs_close_lock_i(Lock *lock)
406
static HashTable stores = {
409
/* mask */ HASH_MINSIZE - 1,
411
/* table */ stores.smalltable,
412
/* smalltable */ {{0, NULL, NULL}},
413
/* lookup */ (h_lookup_ft)&h_lookup_str,
416
/* free_key */ (free_ft)&dummy_free,
417
/* free_value */ (free_ft)&fs_destroy
421
static mutex_t stores_mutex = MUTEX_INITIALIZER;
424
static void fs_close_i(Store *store)
426
mutex_lock(&stores_mutex);
427
h_del(&stores, store->dir.path);
428
mutex_unlock(&stores_mutex);
431
static Store *fs_store_new(const char *pathname)
434
Store *new_store = store_new();
436
new_store->file_mode = S_IRUSR | S_IWUSR;
437
#ifndef POSH_OS_WIN32
438
if (!stat(pathname, &stt) && stt.st_gid == getgid()) {
439
if (stt.st_mode & S_IWGRP) {
442
new_store->file_mode |= stt.st_mode & (S_IRGRP | S_IWGRP);
446
new_store->dir.path = estrdup(pathname);
447
new_store->touch = &fs_touch;
448
new_store->exists = &fs_exists;
449
new_store->remove = &fs_remove;
450
new_store->rename = &fs_rename;
451
new_store->count = &fs_count;
452
new_store->close_i = &fs_close_i;
453
new_store->clear = &fs_clear;
454
new_store->clear_all = &fs_clear_all;
455
new_store->clear_locks = &fs_clear_locks;
456
new_store->length = &fs_length;
457
new_store->each = &fs_each;
458
new_store->new_output = &fs_new_output;
459
new_store->open_input = &fs_open_input;
460
new_store->open_lock_i = &fs_open_lock_i;
461
new_store->close_lock_i = &fs_close_lock_i;
465
Store *open_fs_store(const char *pathname)
469
mutex_lock(&stores_mutex);
470
store = h_get(&stores, pathname);
472
mutex_lock(&store->mutex);
474
mutex_unlock(&store->mutex);
477
store = fs_store_new(pathname);
478
h_set(&stores, store->dir.path, store);
480
mutex_unlock(&stores_mutex);