summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYorhel <git@yorhel.nl>2013-06-16 16:11:12 +0200
committerYorhel <git@yorhel.nl>2013-06-16 16:19:41 +0200
commit8f091f36abb7773f677b681418236bfba9338f73 (patch)
tree67015606c1606c25255f90b7d3592f25c4e7d269
parent997de91a2db054aa53b648d98bc821e0069f91c8 (diff)
share/fl: Use separate 'is directory' flag instead of special size value
This allows directories themselves to have a size, too. I initially preferred using bit fields, but bit fields are not specified to work on 64 bit integers. The current solution is more portable. Note that the size field isn't updated for directories yet. I'll get to that once files are actually being hashed. Unhashed files should be treated as if they don't exist in the list yet, atfer all.
-rw-r--r--src/share/conf.c9
-rw-r--r--src/share/db.c3
-rw-r--r--src/share/fl.c15
-rw-r--r--src/share/fl.h28
-rw-r--r--src/share/scan.c20
-rw-r--r--src/share/share.c2
6 files changed, 50 insertions, 27 deletions
diff --git a/src/share/conf.c b/src/share/conf.c
index 3ceb2a0..f104937 100644
--- a/src/share/conf.c
+++ b/src/share/conf.c
@@ -291,16 +291,17 @@ static void share_List(share_t *s, DBusMessage *msg, const char *_vpath) {
share_fl_t *fl = dir->sub.a[i];
buf.l = 0;
casestr_orig(share_fl_name(fl), &buf);
- if(fl->size == UINT64_MAX)
+ if(share_fl_isdir(fl))
kputc('/', &buf);
- const char *arr = fl->size == UINT64_MAX ? "" : fl->tth;
+ const char *arr = share_fl_isdir(fl) ? "" : fl->tth;
+ uint64_t size = share_fl_size(fl);
dbus_message_iter_open_container(iter+1, DBUS_TYPE_DICT_ENTRY, NULL, iter+2);
dbus_message_iter_append_basic(iter+2, DBUS_TYPE_STRING, &buf.s);
dbus_message_iter_open_container(iter+2, DBUS_TYPE_STRUCT, NULL, iter+3);
- dbus_message_iter_append_basic(iter+3, DBUS_TYPE_UINT64, &fl->size);
+ dbus_message_iter_append_basic(iter+3, DBUS_TYPE_UINT64, &size);
dbus_message_iter_open_container(iter+3, DBUS_TYPE_ARRAY, "y", iter+4);
- dbus_message_iter_append_fixed_array(iter+4, DBUS_TYPE_BYTE, &arr, fl->size == UINT64_MAX ? 0 : sizeof(fl->tth));
+ dbus_message_iter_append_fixed_array(iter+4, DBUS_TYPE_BYTE, &arr, share_fl_isdir(fl) ? 0 : sizeof(fl->tth));
dbus_message_iter_close_container(iter+3, iter+4);
dbus_message_iter_close_container(iter+2, iter+3);
dbus_message_iter_close_container(iter+1, iter+2);
diff --git a/src/share/db.c b/src/share/db.c
index 80e015d..e90d286 100644
--- a/src/share/db.c
+++ b/src/share/db.c
@@ -94,7 +94,8 @@ static void share_db_load_filepath(share_path_t *p, char *path, const char *name
path = path + fslen;
/* path is now relative to the configured share path, but does have a '/' prefix */
- share_fl_t *fl = share_fl_create(size, name, buf);
+ share_fl_t *fl = share_fl_create(false, name, buf);
+ share_fl_setsize(fl, size);
fl->lastmod = lastmod;
fl->pathid = p->id;
memcpy(fl->tth, tth, 24);
diff --git a/src/share/fl.c b/src/share/fl.c
index 439832d..ceb6ff3 100644
--- a/src/share/fl.c
+++ b/src/share/fl.c
@@ -24,11 +24,12 @@
#include <share/local.h>
-share_fl_t *share_fl_create(uint64_t size, const char *name, kstring_t *buf) {
+share_fl_t *share_fl_create(bool isdir, const char *name, kstring_t *buf) {
buf->l = 0;
casestr_create(name, buf);
- share_fl_t *f = calloc(1, buf->l + (size == UINT64_MAX ? offsetof(share_fl_t, dname) : offsetof(share_fl_t, fname)));
- f->size = size;
+ share_fl_t *f = calloc(1, buf->l + (isdir ? offsetof(share_fl_t, dname) : offsetof(share_fl_t, fname)));
+ if(isdir)
+ f->flags = SHARE_FL_DIRFLAG;
memcpy(share_fl_name(f), buf->s, buf->l);
return f;
}
@@ -36,7 +37,7 @@ share_fl_t *share_fl_create(uint64_t size, const char *name, kstring_t *buf) {
void share_fl_free(share_fl_t *fl) {
size_t i;
- if(fl->size == UINT64_MAX) {
+ if(share_fl_isdir(fl)) {
for(i=0; i<fl->sub.n; i++)
share_fl_free(fl->sub.a[i]);
free(fl->sub.a);
@@ -77,7 +78,7 @@ share_fl_t *share_fl_getdir(share_fl_t *root, char *path, char *pathf, kstring_t
size_t r;
vec_search_insert(root->sub, r, strcmp(share_fl_name(root->sub.a[i]), pathf));
if(r == root->sub.n || strcmp(share_fl_name(root->sub.a[r]), pathf) != 0) {
- share_fl_t *fl = share_fl_create(UINT64_MAX, path, buf);
+ share_fl_t *fl = share_fl_create(true, path, buf);
vec_insert_order(root->sub, r, fl);
}
@@ -94,7 +95,7 @@ share_fl_t *share_fl_resolve(share_fl_t *root, char *path) {
path++;
if(!*path)
return root;
- assert(root->size == UINT64_MAX);
+ assert(share_fl_isdir(root));
char *end = strchr(path, '/');
if(end)
*end = 0;
@@ -110,7 +111,7 @@ share_fl_t *share_fl_resolve(share_fl_t *root, char *path) {
if(fl && casestr_cmp(share_fl_name(fl), buf.s) == 0) {
if(!end)
ret = fl;
- else if(fl->size == UINT64_MAX)
+ else if(share_fl_isdir(fl))
ret = share_fl_resolve(fl, end+1);
}
free(buf.s);
diff --git a/src/share/fl.h b/src/share/fl.h
index ae4ec57..4c578cf 100644
--- a/src/share/fl.h
+++ b/src/share/fl.h
@@ -23,9 +23,14 @@
#ifndef SHARE_FL_H
#define SHARE_FL_H
+#define SHARE_FL_DIRFLAG (((uint64_t)1)<<63)
+
struct share_fl_t {
share_fl_t *parent;
- uint64_t size; /* UINT64_MAX for directories */
+ /* Holds the size of this item in the lower bits and any flags in the high
+ * bits. The only flag currently used is the SHARE_FL_DIRFLAG. Use
+ * share_fl_size() and share_fl_isdir() functions to access this field. */
+ uint64_t flags;
union {
struct {
char tth[24]; /* All zeros if not hashed yet */
@@ -45,13 +50,28 @@ struct share_fl_t {
};
+static inline uint64_t share_fl_size(share_fl_t *f) {
+ return f->flags & ~SHARE_FL_DIRFLAG;
+}
+
+
+static inline void share_fl_setsize(share_fl_t *f, uint64_t size) {
+ f->flags = size | (f->flags & SHARE_FL_DIRFLAG);
+}
+
+
+static inline bool share_fl_isdir(share_fl_t *f) {
+ return f->flags & SHARE_FL_DIRFLAG;
+}
+
+
static inline char *share_fl_name(share_fl_t *f) {
- return f->size == UINT64_MAX ? f->dname : f->fname;
+ return share_fl_isdir(f) ? f->dname : f->fname;
}
static inline bool share_fl_hastth(share_fl_t *f) {
- assert(f->size != UINT64_MAX);
+ assert(!share_fl_isdir(f));
return memcmp(f->tth, (uint64_t[]){0,0,0}, 24) == 0;
}
@@ -68,7 +88,7 @@ static inline int share_fl_sort_cmp(const void *a, const void *b) {
/* Create a new fl struct. The given *buf will be used as temporary workspace
* for case folding the name. Re-using the same buffer across calls
* significantly improves performance. */
-share_fl_t *share_fl_create(uint64_t size, const char *name, kstring_t *buf);
+share_fl_t *share_fl_create(bool isdir, const char *name, kstring_t *buf);
/* Recursively frees an fl item. To free a single item (either a file, or a
diff --git a/src/share/scan.c b/src/share/scan.c
index 39fe7b7..ca987fa 100644
--- a/src/share/scan.c
+++ b/src/share/scan.c
@@ -80,8 +80,7 @@
* create 2^20 (more than a million) files of 16 TiB.
* (Still, even with this check you can get an overflow if you tried hard
* enough...)
- * - This gives us 20 unused bits in share_fl.size, which can be used for
- * various flags if we need any.
+ * - This gives us 20 bits in share_fl.flags, usable for various flags
* - Regardless of how fast your machine is, hashing a single 16 TiB file take
* a while. Globster doesn't remember hashing progress of a single file
* across restarts.
@@ -147,8 +146,9 @@ static share_fl_t *share_scan_thread_item(share_scan_work_t *w, const char *fnam
return NULL;
}
- fl = share_fl_create(S_ISDIR(st.st_mode) ? UINT64_MAX : (uint64_t)st.st_size, fname, buf);
- if(fl->size != UINT64_MAX) {
+ fl = share_fl_create(S_ISDIR(st.st_mode), fname, buf);
+ if(!share_fl_isdir(fl)) {
+ share_fl_setsize(fl, st.st_size);
fl->lastmod = st.st_mtime;
fl->pathid = w->pathid;
}
@@ -258,7 +258,7 @@ static void share_scan_merge_del(share_fl_t *fl) {
/* TODO: Remove from hash index or queue */
/* TODO: Remove from sharefiles table */
- if(fl->size == UINT64_MAX) {
+ if(share_fl_isdir(fl)) {
size_t i;
for(i=0; i<fl->sub.n; i++)
share_scan_merge_del(fl->sub.a[i]);
@@ -293,8 +293,8 @@ static void share_scan_merge(share_fl_t *dst, share_flv_t *lst) {
}
/* lf == df, the item is in both dst and lst. Check for differences. */
- if(lf->size != df->size /* Also catches lf->isdir != df->isdir */
- || (lf->size != UINT64_MAX && (lf->lastmod != df->lastmod || lf->pathid != lf->pathid))
+ if(share_fl_isdir(lf) != share_fl_isdir(df)
+ || (!share_fl_isdir(lf) && (share_fl_size(lf) != share_fl_size(df) || lf->lastmod != df->lastmod || lf->pathid != lf->pathid))
|| casestr_cmp(share_fl_name(lf), share_fl_name(df)) != 0) {
share_scan_merge_del(df);
share_scan_merge_new(dst, lf);
@@ -378,7 +378,7 @@ static void share_scan_dir_addvpath(share_flv_t *dest, const char *vpath, share_
end++;
char endc = *end;
*end = 0;
- share_fl_t *fl = share_fl_create(UINT64_MAX, ps, buf);
+ share_fl_t *fl = share_fl_create(true, ps, buf);
*end = endc;
vec_insert_sorted(*dest, strcmp(share_fl_name(dest->a[i]), share_fl_name(fl)), fl);
@@ -424,7 +424,7 @@ static void share_scan_next(share_scan_t *sc) {
/* Look for the first child dir */
for(j=0; j<fl->sub.n; j++)
- if(fl->sub.a[j]->size == UINT64_MAX) {
+ if(share_fl_isdir(fl->sub.a[j])) {
sc->dir = fl->sub.a[j];
share_scan_dir(sc);
return;
@@ -436,7 +436,7 @@ static void share_scan_next(share_scan_t *sc) {
par = fl->parent;
vec_search(par->sub, strcmp(share_fl_name(par->sub.a[i]), share_fl_name(fl)), j=i);
for(j++; j<par->sub.n; j++)
- if(par->sub.a[j]->size == UINT64_MAX) {
+ if(share_fl_isdir(par->sub.a[j])) {
sc->dir = par->sub.a[j];
share_scan_dir(sc);
return;
diff --git a/src/share/share.c b/src/share/share.c
index cb17b0e..94572e3 100644
--- a/src/share/share.c
+++ b/src/share/share.c
@@ -29,7 +29,7 @@ share_share_t *share_share_create(share_t *s) {
ss->s = s;
kstring_t buf = {};
- ss->root = share_fl_create(UINT64_MAX, "", &buf);
+ ss->root = share_fl_create(true, "", &buf);
free(buf.s);
return ss;