2 * $Id: cnid_cdb_add.c,v 1.1.4.1 2003-09-09 16:42:21 didg Exp $
4 * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
5 * All Rights Reserved. See COPYRIGHT.
7 * cnid_add (db, dev, ino, did, name, hint):
8 * add a name to the CNID database. we use both dev/ino and did/name
9 * to keep track of things.
14 #endif /* HAVE_CONFIG_H */
16 #ifdef CNID_BACKEND_CDB
19 #include <sys/param.h>
24 #endif /* HAVE_UNISTD_H */
27 #endif /* HAVE_FCNTL_H */
29 #include <atalk/logger.h>
30 #ifdef HAVE_SYS_TIME_H
32 #endif /* HAVE_SYS_TIME_H */
35 #include <netatalk/endian.h>
37 #include <atalk/adouble.h>
39 #include <atalk/util.h>
41 #include "cnid_cdb_private.h"
46 char *make_cnid_data(const struct stat *st,const cnid_t did,
47 const char *name, const int len)
49 static char start[CNID_HEADER_LEN + MAXPATHLEN + 1];
50 char *buf = start +CNID_LEN;
56 memcpy(buf, &st->st_dev, sizeof(st->st_dev));
57 buf += sizeof(st->st_dev);
59 i = htonl(st->st_ino);
60 memcpy(buf , &st->st_ino, sizeof(st->st_ino));
61 buf += sizeof(st->st_ino);
63 i = S_ISDIR(st->st_mode)?1:0;
65 memcpy(buf, &i, sizeof(i));
68 /* did is already in network byte order */
69 memcpy(buf, &did, sizeof(did));
72 memcpy(buf, name, len);
79 extern int cnid_cdb_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
80 const cnid_t did, const char *name, const int len);
82 /* ----------------------------- */
83 static cnid_t get_cnid(CNID_private *db)
85 DBT rootinfo_key, rootinfo_data;
90 char buf[ROOTINFO_DATALEN];
92 if ((rc = db->db_cnid->cursor(db->db_cnid, NULL, &cursor, DB_WRITECURSOR) ) != 0) {
93 LOG(log_error, logtype_default, "get_cnid: Unable to get a cursor: %s", db_strerror(rc));
97 memset(&rootinfo_key, 0, sizeof(rootinfo_key));
98 memset(&rootinfo_data, 0, sizeof(rootinfo_data));
99 rootinfo_key.data = ROOTINFO_KEY;
100 rootinfo_key.size = ROOTINFO_KEYLEN;
102 switch (rc = cursor->c_get(cursor, &rootinfo_key, &rootinfo_data, DB_SET)) {
104 memcpy(&hint, (char *)rootinfo_data.data +CNID_TYPE_OFS, sizeof(hint));
106 /* If we've hit the max CNID allowed, we return a fatal error. CNID
107 * needs to be recycled before proceding. */
108 if (++id == CNID_INVALID) {
109 LOG(log_error, logtype_default, "cnid_add: FATAL: CNID database has reached its limit.");
110 errno = CNID_ERR_MAX;
117 hint = htonl(CNID_START);
121 LOG(log_error, logtype_default, "cnid_add: Unable to lookup rootinfo: %s", db_strerror(rc));
126 memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN);
127 rootinfo_data.data = buf;
128 rootinfo_data.size = ROOTINFO_DATALEN;
129 memcpy((char *)rootinfo_data.data +CNID_TYPE_OFS, &hint, sizeof(hint));
131 switch (rc = cursor->c_put(cursor, &rootinfo_key, &rootinfo_data, flag)) {
135 LOG(log_error, logtype_default, "cnid_add: Unable to update rootinfo: %s", db_strerror(rc));
139 if ((rc = cursor->c_close(cursor)) != 0) {
140 LOG(log_error, logtype_default, "get_cnid: Unable to close cursor: %s", db_strerror(rc));
146 if ((rc = cursor->c_close(cursor)) != 0) {
147 LOG(log_error, logtype_default, "get_cnid: Unable to close cursor: %s", db_strerror(rc));
153 /* ------------------------ */
154 cnid_t cnid_cdb_add(struct _cnid_db *cdb, const struct stat *st,
155 const cnid_t did, const char *name, const int len,
163 if (!cdb || !(db = cdb->_private) || !st || !name) {
164 errno = CNID_ERR_PARAM;
169 id = cnid_cdb_lookup(cdb, st, did, name, len);
170 /* ... Return id if it is valid, or if Rootinfo is read-only. */
171 if (id || (db->flags & CNIDFLAG_DB_RO)) {
173 LOG(log_info, logtype_default, "cnid_add: Looked up did %u, name %s as %u", ntohl(did), name, ntohl(id));
178 /* Initialize our DBT data structures. */
179 memset(&key, 0, sizeof(key));
180 memset(&data, 0, sizeof(data));
182 if ((data.data = make_cnid_data(st, did, name, len)) == NULL) {
183 LOG(log_error, logtype_default, "cnid_add: Path name is too long");
184 errno = CNID_ERR_PATH;
187 data.size = CNID_HEADER_LEN + len + 1;
189 if ((hint = get_cnid(db)) == 0) {
193 memcpy(data.data, &hint, sizeof(hint));
196 key.size = sizeof(hint);
198 /* Now we need to add the CNID data to the databases. */
199 if ((rc = db->db_cnid->put(db->db_cnid, tid, &key, &data, DB_NOOVERWRITE))) {
201 /* if we have a duplicate
202 * on cnid it's a fatal error.
204 * - leftover should have been delete before.
205 * - a second process already updated the db
206 * - it's a new file eg our file is already deleted and replaced
207 * on did:name leftover
209 if (cnid_cdb_update(cdb, hint, st, did, name, len)) {
215 LOG(log_error, logtype_default
216 , "cnid_add: Failed to add CNID for %s to database using hint %u: %s",
217 name, ntohl(hint), db_strerror(rc));
224 LOG(log_info, logtype_default, "cnid_add: Returned CNID for did %u, name %s as %u", ntohl(did), name, ntohl(hint));
230 #endif /* CNID_BACKEND_CDB */