2 * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
3 * All Rights Reserved. See COPYRIGHT.
5 * cnid_add (db, dev, ino, did, name, hint):
6 * add a name to the CNID database. we use both dev/ino and did/name
7 * to keep track of things.
12 #endif /* HAVE_CONFIG_H */
14 #ifdef CNID_BACKEND_CDB
15 #include <arpa/inet.h>
16 #include "cnid_cdb_private.h"
18 extern int cnid_cdb_update(struct _cnid_db *cdb, cnid_t id, const struct stat *st,
19 cnid_t did, const char *name, size_t len);
23 static void make_devino_data(unsigned char *buf, dev_t dev, ino_t ino)
25 buf[CNID_DEV_LEN - 1] = dev; dev >>= 8;
26 buf[CNID_DEV_LEN - 2] = dev; dev >>= 8;
27 buf[CNID_DEV_LEN - 3] = dev; dev >>= 8;
28 buf[CNID_DEV_LEN - 4] = dev; dev >>= 8;
29 buf[CNID_DEV_LEN - 5] = dev; dev >>= 8;
30 buf[CNID_DEV_LEN - 6] = dev; dev >>= 8;
31 buf[CNID_DEV_LEN - 7] = dev; dev >>= 8;
32 buf[CNID_DEV_LEN - 8] = dev;
34 buf[CNID_DEV_LEN + CNID_INO_LEN - 1] = ino; ino >>= 8;
35 buf[CNID_DEV_LEN + CNID_INO_LEN - 2] = ino; ino >>= 8;
36 buf[CNID_DEV_LEN + CNID_INO_LEN - 3] = ino; ino >>= 8;
37 buf[CNID_DEV_LEN + CNID_INO_LEN - 4] = ino; ino >>= 8;
38 buf[CNID_DEV_LEN + CNID_INO_LEN - 5] = ino; ino >>= 8;
39 buf[CNID_DEV_LEN + CNID_INO_LEN - 6] = ino; ino >>= 8;
40 buf[CNID_DEV_LEN + CNID_INO_LEN - 7] = ino; ino >>= 8;
41 buf[CNID_DEV_LEN + CNID_INO_LEN - 8] = ino;
44 unsigned char *make_cnid_data(u_int32_t flags, const struct stat *st, const cnid_t did,
45 const char *name, const size_t len)
47 static unsigned char start[CNID_HEADER_LEN + MAXPATHLEN + 1];
48 unsigned char *buf = start +CNID_LEN;
54 make_devino_data(buf, !(flags & CNID_FLAG_NODEV)?st->st_dev:0, st->st_ino);
55 buf += CNID_DEVINO_LEN;
57 i = S_ISDIR(st->st_mode)?1:0;
59 memcpy(buf, &i, sizeof(i));
62 /* did is already in network byte order */
63 memcpy(buf, &did, sizeof(did));
66 memcpy(buf, name, len);
73 static int db_stamp(void *buffer, size_t size)
76 memset(buffer, 0, size);
77 /* return the current time. */
78 if (size < sizeof(time_t))
81 memcpy(buffer,&t, sizeof(time_t));
87 /* ----------------------------- */
88 static cnid_t get_cnid(CNID_private *db)
90 DBT rootinfo_key, rootinfo_data;
95 char buf[ROOTINFO_DATALEN];
96 char stamp[CNID_DEV_LEN];
98 if ((rc = db->db_cnid->cursor(db->db_cnid, NULL, &cursor, DB_WRITECURSOR) ) != 0) {
99 LOG(log_error, logtype_default, "get_cnid: Unable to get a cursor: %s", db_strerror(rc));
103 memset(&rootinfo_key, 0, sizeof(rootinfo_key));
104 memset(&rootinfo_data, 0, sizeof(rootinfo_data));
105 rootinfo_key.data = ROOTINFO_KEY;
106 rootinfo_key.size = ROOTINFO_KEYLEN;
108 switch (rc = cursor->c_get(cursor, &rootinfo_key, &rootinfo_data, DB_SET)) {
110 memcpy(&hint, (char *)rootinfo_data.data +CNID_TYPE_OFS, sizeof(hint));
112 /* If we've hit the max CNID allowed, we return a fatal error. CNID
113 * needs to be recycled before proceding. */
114 if (++id == CNID_INVALID) {
115 LOG(log_error, logtype_default, "cnid_add: FATAL: CNID database has reached its limit.");
116 errno = CNID_ERR_MAX;
123 hint = htonl(CNID_START);
128 LOG(log_error, logtype_default, "cnid_add: Unable to lookup rootinfo: %s", db_strerror(rc));
133 memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN);
134 rootinfo_data.data = buf;
135 rootinfo_data.size = ROOTINFO_DATALEN;
136 memcpy((char *)rootinfo_data.data +CNID_TYPE_OFS, &hint, sizeof(hint));
138 if (db_stamp(stamp, CNID_DEV_LEN) < 0) {
141 memcpy((char *)rootinfo_data.data +CNID_DEV_OFS, stamp, sizeof(stamp));
145 switch (rc = cursor->c_put(cursor, &rootinfo_key, &rootinfo_data, flag)) {
149 LOG(log_error, logtype_default, "cnid_add: Unable to update rootinfo: %s", db_strerror(rc));
153 if ((rc = cursor->c_close(cursor)) != 0) {
154 LOG(log_error, logtype_default, "get_cnid: Unable to close cursor: %s", db_strerror(rc));
160 if ((rc = cursor->c_close(cursor)) != 0) {
161 LOG(log_error, logtype_default, "get_cnid: Unable to close cursor: %s", db_strerror(rc));
167 /* ------------------------ */
168 cnid_t cnid_cdb_add(struct _cnid_db *cdb, const struct stat *st,
169 cnid_t did, const char *name, size_t len, cnid_t hint)
176 if (!cdb || !(db = cdb->_private) || !st || !name) {
177 errno = CNID_ERR_PARAM;
182 id = cnid_cdb_lookup(cdb, st, did, name, len);
183 /* ... Return id if it is valid, or if Rootinfo is read-only. */
184 if (id || (db->flags & CNIDFLAG_DB_RO)) {
186 LOG(log_debug9, logtype_default, "cnid_add: Looked up did %u, name %s as %u", ntohl(did), name, ntohl(id));
191 /* Initialize our DBT data structures. */
192 memset(&key, 0, sizeof(key));
193 memset(&data, 0, sizeof(data));
195 if ((data.data = make_cnid_data(cdb->flags, st, did, name, len)) == NULL) {
196 LOG(log_error, logtype_default, "cnid_add: Path name is too long");
197 errno = CNID_ERR_PATH;
200 data.size = CNID_HEADER_LEN + len + 1;
202 if ((hint = get_cnid(db)) == 0) {
206 memcpy(data.data, &hint, sizeof(hint));
209 key.size = sizeof(hint);
211 /* Now we need to add the CNID data to the databases. */
212 if ((rc = db->db_cnid->put(db->db_cnid, tid, &key, &data, DB_NOOVERWRITE))) {
214 /* if we have a duplicate
215 * on cnid it's a fatal error.
217 * - leftover should have been delete before.
218 * - a second process already updated the db
219 * - it's a new file eg our file is already deleted and replaced
220 * on did:name leftover
222 if (cnid_cdb_update(cdb, hint, st, did, name, len)) {
228 LOG(log_error, logtype_default
229 , "cnid_add: Failed to add CNID for %s to database using hint %u: %s",
230 name, ntohl(hint), db_strerror(rc));
237 LOG(log_debug9, logtype_default, "cnid_add: Returned CNID for did %u, name %s as %u", ntohl(did), name, ntohl(hint));
243 /* cnid_cbd_getstamp */
244 /*-----------------------*/
245 int cnid_cdb_getstamp(struct _cnid_db *cdb, void *buffer, const size_t len)
251 if (!cdb || !(db = cdb->_private) || !buffer || !len) {
252 errno = CNID_ERR_PARAM;
256 memset(buffer, 0, len);
257 memset(&key, 0, sizeof(key));
258 memset(&data, 0, sizeof(data));
260 key.data = ROOTINFO_KEY;
261 key.size = ROOTINFO_KEYLEN;
263 if (0 != (rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0 )) ) {
264 if (rc != DB_NOTFOUND) {
265 LOG(log_error, logtype_default, "cnid_lookup: Unable to get database stamp: %s",
270 /* we waste a single ID here... */
272 memset(&key, 0, sizeof(key));
273 memset(&data, 0, sizeof(data));
274 key.data = ROOTINFO_KEY;
275 key.size = ROOTINFO_KEYLEN;
276 if (0 != (rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0 )) ) {
277 LOG(log_error, logtype_default, "cnid_getstamp: failed to get rootinfo: %s",
284 memcpy(buffer, (char*)data.data + CNID_DEV_OFS, len);
286 LOG(log_debug9, logtype_cnid, "cnid_getstamp: Returning stamp");
292 #endif /* CNID_BACKEND_CDB */