]> arthur.barton.de Git - netatalk.git/blobdiff - libatalk/cnid/cdb/cnid_cdb_rebuild_add.c
- merge branch-netatalk-afp-3x-dev, HEAD was tagged before
[netatalk.git] / libatalk / cnid / cdb / cnid_cdb_rebuild_add.c
diff --git a/libatalk/cnid/cdb/cnid_cdb_rebuild_add.c b/libatalk/cnid/cdb/cnid_cdb_rebuild_add.c
new file mode 100644 (file)
index 0000000..7ea872e
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * $Id: cnid_cdb_rebuild_add.c,v 1.2 2005-04-28 20:49:59 bfernhomberg Exp $
+ *
+ * All Rights Reserved. See COPYRIGHT.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef CNID_BACKEND_CDB
+#include "cnid_cdb_private.h"
+
+#define tid    NULL
+#define DEBUG 1
+
+#include "cnid_cdb.h"
+
+#ifdef ATACC
+/* FIXME: Enhance for 8 byte dev/inode */
+char *make_cnid_data(const struct stat *st,const cnid_t did,
+                     const char *name, const int len)
+{
+    static char start[CNID_HEADER_LEN + MAXPATHLEN + 1];
+    char *buf = start  +CNID_LEN;
+    u_int32_t i;
+
+    if (len > MAXPATHLEN)
+        return NULL;
+
+    memcpy(buf, &st->st_dev, sizeof(st->st_dev));
+    buf += sizeof(st->st_dev);
+
+    i = htonl(st->st_ino);
+    memcpy(buf , &st->st_ino, sizeof(st->st_ino));
+    buf += sizeof(st->st_ino);
+
+    i = S_ISDIR(st->st_mode)?1:0;
+    i = htonl(i);
+    memcpy(buf, &i, sizeof(i));
+    buf += sizeof(i);
+    
+    /* did is already in network byte order */
+    memcpy(buf, &did, sizeof(did));
+    buf += sizeof(did);
+
+    memcpy(buf, name, len);
+    *(buf + len) = '\0';
+
+    return start;
+}    
+#endif
+
+
+/* ----------------------------- */
+static cnid_t set_max_cnid(CNID_private *db, cnid_t hint)
+{
+    DBT rootinfo_key, rootinfo_data;
+    int rc;
+    char buf[ROOTINFO_DATALEN];
+    cnid_t id, id1;
+    time_t t;
+    
+    memset(&rootinfo_key, 0, sizeof(rootinfo_key));
+    memset(&rootinfo_data, 0, sizeof(rootinfo_data));
+    
+    rootinfo_key.data = ROOTINFO_KEY;
+    rootinfo_key.size = ROOTINFO_KEYLEN;
+
+    switch ((rc = db->db_cnid->get(db->db_cnid, tid, &rootinfo_key, &rootinfo_data, 0))) {
+    case 0:
+       memcpy(buf, (char *)rootinfo_data.data, ROOTINFO_DATALEN);
+        break;
+    case DB_NOTFOUND:
+       /* FIXME: This duplicates stuff from cnid_cdb_add.c. 
+          We also implicitely assume that sizeof(time_t) <= CNID_DEV_LEN */
+       memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN);
+       t = time(NULL);
+       memset(buf + CNID_DEV_OFS, 0, CNID_DEV_LEN);
+       memcpy(buf + CNID_DEV_OFS, &t, sizeof(time_t));
+        id = htonl(CNID_START);
+       memcpy(buf + CNID_TYPE_OFS, &id, sizeof(id));
+       break;
+    default:
+        LOG(log_error, logtype_default, "set_max_cnid: Unable to read rootinfo: %s", db_strerror(rc));
+       errno = CNID_ERR_DB; 
+        goto cleanup;
+    }
+
+    memcpy(&id, buf + CNID_TYPE_OFS, sizeof(id));
+    id = ntohl(id);
+    id1 = ntohl(hint);
+
+    if (id1 > id) {
+       memcpy(buf + CNID_TYPE_OFS, &hint, sizeof(hint));
+       rootinfo_data.data = buf;
+       rootinfo_data.size = ROOTINFO_DATALEN;
+       if ((rc = db->db_cnid->put(db->db_cnid, tid, &rootinfo_key, &rootinfo_data, 0))) {
+           LOG(log_error, logtype_default, "set_max_cnid: Unable to write rootinfo: %s", db_strerror(rc));
+           errno = CNID_ERR_DB; 
+           goto cleanup;
+       }
+    }
+
+    return hint;
+
+cleanup:
+    return CNID_INVALID;
+}
+
+/* ------------------------ */
+cnid_t cnid_cdb_rebuild_add(struct _cnid_db *cdb, const struct stat *st,
+                const cnid_t did, const char *name, const int len, 
+               cnid_t hint)
+{
+    CNID_private *db;
+    DBT key, data;
+    int rc;
+
+    if (!cdb || !(db = cdb->_private) || !st || !name || hint == CNID_INVALID || hint < CNID_START) {
+        errno = CNID_ERR_PARAM;
+        return CNID_INVALID;
+    }
+
+#if 0
+    /* FIXME: Bjoern does a lookup. Should we not overwrite unconditionally? */
+    /* Do a lookup. */
+    id = cnid_cdb_lookup(cdb, st, did, name, len);
+    /* ... Return id if it is valid, or if Rootinfo is read-only. */
+    if (id || (db->flags & CNIDFLAG_DB_RO)) {
+#ifdef DEBUG
+        LOG(log_info, logtype_default, "cnid_add: Looked up did %u, name %s as %u", ntohl(did), name, ntohl(id));
+#endif
+        return id;
+    }
+#endif
+
+    /* Initialize our DBT data structures. */
+    memset(&key, 0, sizeof(key));
+    memset(&data, 0, sizeof(data));
+
+    if ((data.data = make_cnid_data(st, did, name, len)) == NULL) {
+        LOG(log_error, logtype_default, "cnid_add: Path name is too long");
+        errno = CNID_ERR_PATH;
+        return CNID_INVALID;
+    }
+    data.size = CNID_HEADER_LEN + len + 1;
+    
+    memcpy(data.data, &hint, sizeof(hint));
+    
+    key.data = &hint;
+    key.size = sizeof(hint);
+
+    /* Now we need to add the CNID data to the databases. */
+    if ((rc = db->db_cnid->put(db->db_cnid, tid, &key, &data, 0))) {
+            LOG(log_error, logtype_default
+                   , "cnid_add: Failed to add CNID for %s to database using hint %u: %s", 
+                   name, ntohl(hint), db_strerror(rc));  
+            errno = CNID_ERR_DB;
+           goto cleanup;
+    }
+
+    if (set_max_cnid(db, hint) == CNID_INVALID) {
+           errno = CNID_ERR_DB;
+           goto cleanup;
+    }
+
+#ifdef DEBUG
+    LOG(log_info, logtype_default, "cnid_add: Returned CNID for did %u, name %s as %u", ntohl(did), name, ntohl(hint));
+#endif
+
+    return hint;
+
+cleanup:
+    return CNID_INVALID;
+}
+
+#endif /* CNID_BACKEND_CDB */