2 * $Id: cnid_tdb_add.c,v 1.4 2009-11-20 17:37:14 didg Exp $
4 * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
5 * All Rights Reserved. See COPYRIGHT.
13 #ifdef CNID_BACKEND_TDB
15 #include <atalk/util.h>
16 #include <sys/param.h>
17 #include <sys/types.h>
20 #include <atalk/logger.h>
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_tdb_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);
71 /* add an entry to the CNID databases. we do this as a transaction
72 * to prevent messiness.
76 static int add_cnid (struct _cnid_tdb_private *db, TDB_DATA *key, TDB_DATA *data) {
77 TDB_DATA altkey, altdata;
79 memset(&altkey, 0, sizeof(altkey));
80 memset(&altdata, 0, sizeof(altdata));
84 if (tdb_store(db->tdb_cnid, *key, *data, TDB_REPLACE)) {
88 /* dev/ino database */
89 altkey.dptr = data->dptr +CNID_DEVINO_OFS;
90 altkey.dsize = CNID_DEVINO_LEN;
91 altdata.dptr = key->dptr;
92 altdata.dsize = key->dsize;
93 if (tdb_store(db->tdb_devino, altkey, altdata, TDB_REPLACE)) {
97 /* did/name database */
98 altkey.dptr = (char *) data->dptr +CNID_DID_OFS;
99 altkey.dsize = data->dsize -CNID_DID_OFS;
100 if (tdb_store(db->tdb_didname, altkey, altdata, TDB_REPLACE)) {
109 /* ----------------------- */
110 static cnid_t get_cnid(struct _cnid_tdb_private *db)
112 TDB_DATA rootinfo_key, data;
115 memset(&rootinfo_key, 0, sizeof(rootinfo_key));
116 memset(&data, 0, sizeof(data));
117 rootinfo_key.dptr = ROOTINFO_KEY;
118 rootinfo_key.dsize = ROOTINFO_KEYLEN;
120 tdb_chainlock(db->tdb_didname, rootinfo_key);
121 data = tdb_fetch(db->tdb_didname, rootinfo_key);
124 memcpy(&hint, data.dptr, sizeof(cnid_t));
127 /* If we've hit the max CNID allowed, we return a fatal error. CNID
128 * needs to be recycled before proceding. */
129 if (++id == CNID_INVALID) {
130 LOG(log_error, logtype_default, "cnid_add: FATAL: CNID database has reached its limit.");
131 errno = CNID_ERR_MAX;
137 hint = htonl(CNID_START);
140 memset(&data, 0, sizeof(data));
141 data.dptr = (char *)&hint;
142 data.dsize = sizeof(hint);
143 if (tdb_store(db->tdb_didname, rootinfo_key, data, TDB_REPLACE)) {
147 tdb_chainunlock(db->tdb_didname, rootinfo_key );
150 tdb_chainunlock(db->tdb_didname, rootinfo_key);
155 /* ------------------------ */
156 cnid_t cnid_tdb_add(struct _cnid_db *cdb, const struct stat *st,
157 const cnid_t did, char *name, const size_t len, cnid_t hint)
159 const struct stat *lstp;
161 struct _cnid_tdb_private *priv;
165 if (!cdb || !(priv = cdb->_private) || !st || !name) {
166 errno = CNID_ERR_PARAM;
170 id = cnid_tdb_lookup(cdb, st, did, name, len);
171 /* ... Return id if it is valid, or if Rootinfo is read-only. */
172 if (id || (priv->flags & CNIDFLAG_DB_RO)) {
178 lstp = lstat(name, &lst) < 0 ? st : &lst;
182 /* Initialize our DBT data structures. */
183 memset(&key, 0, sizeof(key));
184 memset(&data, 0, sizeof(data));
186 key.dptr = (char *)&hint;
187 key.dsize = sizeof(cnid_t);
188 if ((data.dptr = make_tdb_data(cdb->flags, lstp, did, name, len)) == NULL) {
189 LOG(log_error, logtype_default, "tdb_add: Path name is too long");
190 errno = CNID_ERR_PATH;
193 data.dsize = CNID_HEADER_LEN + len + 1;
194 hint = get_cnid(priv);
199 memcpy(data.dptr, &hint, sizeof(hint));
201 /* Now we need to add the CNID data to the databases. */
202 rc = add_cnid(priv, &key, &data);
204 LOG(log_error, logtype_default, "tdb_add: Failed to add CNID for %s to database using hint %u", name, ntohl(hint));