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 "cnid_cdb_private.h"
17 extern int cnid_cdb_update(struct _cnid_db *cdb, cnid_t id, const struct stat *st,
18 cnid_t did, const char *name, size_t len);
22 static void make_devino_data(unsigned char *buf, dev_t dev, ino_t ino)
24 buf[CNID_DEV_LEN - 1] = dev; dev >>= 8;
25 buf[CNID_DEV_LEN - 2] = dev; dev >>= 8;
26 buf[CNID_DEV_LEN - 3] = dev; dev >>= 8;
27 buf[CNID_DEV_LEN - 4] = dev; dev >>= 8;
28 buf[CNID_DEV_LEN - 5] = dev; dev >>= 8;
29 buf[CNID_DEV_LEN - 6] = dev; dev >>= 8;
30 buf[CNID_DEV_LEN - 7] = dev; dev >>= 8;
31 buf[CNID_DEV_LEN - 8] = dev;
33 buf[CNID_DEV_LEN + CNID_INO_LEN - 1] = ino; ino >>= 8;
34 buf[CNID_DEV_LEN + CNID_INO_LEN - 2] = ino; ino >>= 8;
35 buf[CNID_DEV_LEN + CNID_INO_LEN - 3] = ino; ino >>= 8;
36 buf[CNID_DEV_LEN + CNID_INO_LEN - 4] = ino; ino >>= 8;
37 buf[CNID_DEV_LEN + CNID_INO_LEN - 5] = ino; ino >>= 8;
38 buf[CNID_DEV_LEN + CNID_INO_LEN - 6] = ino; ino >>= 8;
39 buf[CNID_DEV_LEN + CNID_INO_LEN - 7] = ino; ino >>= 8;
40 buf[CNID_DEV_LEN + CNID_INO_LEN - 8] = ino;
43 unsigned char *make_cnid_data(u_int32_t flags, const struct stat *st, const cnid_t did,
44 const char *name, const size_t len)
46 static unsigned char start[CNID_HEADER_LEN + MAXPATHLEN + 1];
47 unsigned char *buf = start +CNID_LEN;
53 make_devino_data(buf, !(flags & CNID_FLAG_NODEV)?st->st_dev:0, st->st_ino);
54 buf += CNID_DEVINO_LEN;
56 i = S_ISDIR(st->st_mode)?1:0;
58 memcpy(buf, &i, sizeof(i));
61 /* did is already in network byte order */
62 memcpy(buf, &did, sizeof(did));
65 memcpy(buf, name, len);
72 static int db_stamp(void *buffer, size_t size)
75 memset(buffer, 0, size);
76 /* return the current time. */
77 if (size < sizeof(time_t))
80 memcpy(buffer,&t, sizeof(time_t));
86 /* ----------------------------- */
87 static cnid_t get_cnid(CNID_private *db)
89 DBT rootinfo_key, rootinfo_data;
94 char buf[ROOTINFO_DATALEN];
95 char stamp[CNID_DEV_LEN];
97 if ((rc = db->db_cnid->cursor(db->db_cnid, NULL, &cursor, DB_WRITECURSOR) ) != 0) {
98 LOG(log_error, logtype_default, "get_cnid: Unable to get a cursor: %s", db_strerror(rc));
102 memset(&rootinfo_key, 0, sizeof(rootinfo_key));
103 memset(&rootinfo_data, 0, sizeof(rootinfo_data));
104 rootinfo_key.data = ROOTINFO_KEY;
105 rootinfo_key.size = ROOTINFO_KEYLEN;
107 switch (rc = cursor->c_get(cursor, &rootinfo_key, &rootinfo_data, DB_SET)) {
109 memcpy(&hint, (char *)rootinfo_data.data +CNID_TYPE_OFS, sizeof(hint));
111 /* If we've hit the max CNID allowed, we return a fatal error. CNID
112 * needs to be recycled before proceding. */
113 if (++id == CNID_INVALID) {
114 LOG(log_error, logtype_default, "cnid_add: FATAL: CNID database has reached its limit.");
115 errno = CNID_ERR_MAX;
122 hint = htonl(CNID_START);
127 LOG(log_error, logtype_default, "cnid_add: Unable to lookup rootinfo: %s", db_strerror(rc));
132 memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN);
133 rootinfo_data.data = buf;
134 rootinfo_data.size = ROOTINFO_DATALEN;
135 memcpy((char *)rootinfo_data.data +CNID_TYPE_OFS, &hint, sizeof(hint));
137 if (db_stamp(stamp, CNID_DEV_LEN) < 0) {
140 memcpy((char *)rootinfo_data.data +CNID_DEV_OFS, stamp, sizeof(stamp));
144 switch (rc = cursor->c_put(cursor, &rootinfo_key, &rootinfo_data, flag)) {
148 LOG(log_error, logtype_default, "cnid_add: Unable to update rootinfo: %s", db_strerror(rc));
152 if ((rc = cursor->c_close(cursor)) != 0) {
153 LOG(log_error, logtype_default, "get_cnid: Unable to close cursor: %s", db_strerror(rc));
159 if ((rc = cursor->c_close(cursor)) != 0) {
160 LOG(log_error, logtype_default, "get_cnid: Unable to close cursor: %s", db_strerror(rc));
166 /* ------------------------ */
167 cnid_t cnid_cdb_add(struct _cnid_db *cdb, const struct stat *st,
168 cnid_t did, const char *name, size_t len, cnid_t hint)
175 if (!cdb || !(db = cdb->_private) || !st || !name) {
176 errno = CNID_ERR_PARAM;
181 id = cnid_cdb_lookup(cdb, st, did, name, len);
182 /* ... Return id if it is valid, or if Rootinfo is read-only. */
183 if (id || (db->flags & CNIDFLAG_DB_RO)) {
185 LOG(log_debug9, logtype_default, "cnid_add: Looked up did %u, name %s as %u", ntohl(did), name, ntohl(id));
190 /* Initialize our DBT data structures. */
191 memset(&key, 0, sizeof(key));
192 memset(&data, 0, sizeof(data));
194 if ((data.data = make_cnid_data(cdb->flags, st, did, name, len)) == NULL) {
195 LOG(log_error, logtype_default, "cnid_add: Path name is too long");
196 errno = CNID_ERR_PATH;
199 data.size = CNID_HEADER_LEN + len + 1;
201 if ((hint = get_cnid(db)) == 0) {
205 memcpy(data.data, &hint, sizeof(hint));
208 key.size = sizeof(hint);
210 /* Now we need to add the CNID data to the databases. */
211 if ((rc = db->db_cnid->put(db->db_cnid, tid, &key, &data, DB_NOOVERWRITE))) {
213 /* if we have a duplicate
214 * on cnid it's a fatal error.
216 * - leftover should have been delete before.
217 * - a second process already updated the db
218 * - it's a new file eg our file is already deleted and replaced
219 * on did:name leftover
221 if (cnid_cdb_update(cdb, hint, st, did, name, len)) {
227 LOG(log_error, logtype_default
228 , "cnid_add: Failed to add CNID for %s to database using hint %u: %s",
229 name, ntohl(hint), db_strerror(rc));
236 LOG(log_debug9, logtype_default, "cnid_add: Returned CNID for did %u, name %s as %u", ntohl(did), name, ntohl(hint));
242 /* cnid_cbd_getstamp */
243 /*-----------------------*/
244 int cnid_cdb_getstamp(struct _cnid_db *cdb, void *buffer, const size_t len)
250 if (!cdb || !(db = cdb->_private) || !buffer || !len) {
251 errno = CNID_ERR_PARAM;
255 memset(buffer, 0, len);
256 memset(&key, 0, sizeof(key));
257 memset(&data, 0, sizeof(data));
259 key.data = ROOTINFO_KEY;
260 key.size = ROOTINFO_KEYLEN;
262 if (0 != (rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0 )) ) {
263 if (rc != DB_NOTFOUND) {
264 LOG(log_error, logtype_default, "cnid_lookup: Unable to get database stamp: %s",
269 /* we waste a single ID here... */
271 memset(&key, 0, sizeof(key));
272 memset(&data, 0, sizeof(data));
273 key.data = ROOTINFO_KEY;
274 key.size = ROOTINFO_KEYLEN;
275 if (0 != (rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0 )) ) {
276 LOG(log_error, logtype_default, "cnid_getstamp: failed to get rootinfo: %s",
283 memcpy(buffer, (char*)data.data + CNID_DEV_OFS, len);
285 LOG(log_debug9, logtype_cnid, "cnid_getstamp: Returning stamp");
291 #endif /* CNID_BACKEND_CDB */