• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/netatalk-3.0.5/libatalk/cnid/tdb/
1/*
2 * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
3 * All Rights Reserved. See COPYRIGHT.
4 *
5 */
6
7#ifdef HAVE_CONFIG_H
8#include "config.h"
9#endif
10
11#ifdef CNID_BACKEND_TDB
12#include "cnid_tdb.h"
13#include <atalk/util.h>
14#include <sys/param.h>
15#include <sys/types.h>
16#include <sys/stat.h>
17#include <unistd.h>
18#include <atalk/logger.h>
19
20static void make_devino_data(unsigned char *buf, dev_t dev, ino_t ino)
21{
22    buf[CNID_DEV_LEN - 1] = dev; dev >>= 8;
23    buf[CNID_DEV_LEN - 2] = dev; dev >>= 8;
24    buf[CNID_DEV_LEN - 3] = dev; dev >>= 8;
25    buf[CNID_DEV_LEN - 4] = dev; dev >>= 8;
26    buf[CNID_DEV_LEN - 5] = dev; dev >>= 8;
27    buf[CNID_DEV_LEN - 6] = dev; dev >>= 8;
28    buf[CNID_DEV_LEN - 7] = dev; dev >>= 8;
29    buf[CNID_DEV_LEN - 8] = dev;
30
31    buf[CNID_DEV_LEN + CNID_INO_LEN - 1] = ino; ino >>= 8;
32    buf[CNID_DEV_LEN + CNID_INO_LEN - 2] = ino; ino >>= 8;
33    buf[CNID_DEV_LEN + CNID_INO_LEN - 3] = ino; ino >>= 8;
34    buf[CNID_DEV_LEN + CNID_INO_LEN - 4] = ino; ino >>= 8;
35    buf[CNID_DEV_LEN + CNID_INO_LEN - 5] = ino; ino >>= 8;
36    buf[CNID_DEV_LEN + CNID_INO_LEN - 6] = ino; ino >>= 8;
37    buf[CNID_DEV_LEN + CNID_INO_LEN - 7] = ino; ino >>= 8;
38    buf[CNID_DEV_LEN + CNID_INO_LEN - 8] = ino;
39}
40
41unsigned char *make_tdb_data(uint32_t flags, const struct stat *st,const cnid_t did,
42                     const char *name, const size_t len)
43{
44    static unsigned char start[CNID_HEADER_LEN + MAXPATHLEN + 1];
45    unsigned char *buf = start  +CNID_LEN;
46    uint32_t i;
47
48    if (len > MAXPATHLEN)
49        return NULL;
50
51    make_devino_data(buf, !(flags & CNID_FLAG_NODEV)?st->st_dev:0, st->st_ino);
52    buf += CNID_DEVINO_LEN;
53
54    i = S_ISDIR(st->st_mode)?1:0;
55    i = htonl(i);
56    memcpy(buf, &i, sizeof(i));
57    buf += sizeof(i);
58
59    /* did is already in network byte order */
60    memcpy(buf, &did, sizeof(did));
61    buf += sizeof(did);
62
63    memcpy(buf, name, len);
64    *(buf + len) = '\0';
65
66    return start;
67}
68
69/* add an entry to the CNID databases. we do this as a transaction
70 * to prevent messiness.
71 * key:   cnid
72 * data:
73 */
74static int add_cnid (struct _cnid_tdb_private *db, TDB_DATA *key, TDB_DATA *data) {
75    TDB_DATA altkey, altdata;
76
77    memset(&altkey, 0, sizeof(altkey));
78    memset(&altdata, 0, sizeof(altdata));
79
80
81    /* main database */
82    if (tdb_store(db->tdb_cnid, *key, *data, TDB_REPLACE)) {
83        goto abort;
84    }
85
86    /* dev/ino database */
87    altkey.dptr = data->dptr +CNID_DEVINO_OFS;
88    altkey.dsize = CNID_DEVINO_LEN;
89    altdata.dptr = key->dptr;
90    altdata.dsize = key->dsize;
91    if (tdb_store(db->tdb_devino, altkey, altdata, TDB_REPLACE)) {
92        goto abort;
93    }
94
95    /* did/name database */
96    altkey.dptr = data->dptr +CNID_DID_OFS;
97    altkey.dsize = data->dsize -CNID_DID_OFS;
98    if (tdb_store(db->tdb_didname, altkey, altdata, TDB_REPLACE)) {
99        goto abort;
100    }
101    return 0;
102
103abort:
104    return -1;
105}
106
107/* ----------------------- */
108static cnid_t get_cnid(struct _cnid_tdb_private *db)
109{
110    TDB_DATA rootinfo_key, data;
111    cnid_t hint,id;
112
113    memset(&rootinfo_key, 0, sizeof(rootinfo_key));
114    memset(&data, 0, sizeof(data));
115    rootinfo_key.dptr = (unsigned char *)ROOTINFO_KEY;
116    rootinfo_key.dsize = ROOTINFO_KEYLEN;
117
118    tdb_chainlock(db->tdb_didname, rootinfo_key);
119    data = tdb_fetch(db->tdb_didname, rootinfo_key);
120    if (data.dptr)
121    {
122        memcpy(&hint, data.dptr, sizeof(cnid_t));
123        free(data.dptr);
124        id = ntohl(hint);
125        /* If we've hit the max CNID allowed, we return a fatal error.  CNID
126         * needs to be recycled before proceding. */
127        if (++id == CNID_INVALID) {
128            LOG(log_error, logtype_default, "cnid_add: FATAL: CNID database has reached its limit.");
129            errno = CNID_ERR_MAX;
130            goto cleanup;
131        }
132        hint = htonl(id);
133    }
134    else {
135        hint = htonl(CNID_START);
136    }
137
138    memset(&data, 0, sizeof(data));
139    data.dptr = (unsigned char *)&hint;
140    data.dsize = sizeof(hint);
141    if (tdb_store(db->tdb_didname, rootinfo_key, data, TDB_REPLACE)) {
142        goto cleanup;
143    }
144
145    tdb_chainunlock(db->tdb_didname, rootinfo_key );
146    return hint;
147cleanup:
148    tdb_chainunlock(db->tdb_didname, rootinfo_key);
149    return CNID_INVALID;
150}
151
152
153/* ------------------------ */
154cnid_t cnid_tdb_add(struct _cnid_db *cdb, const struct stat *st,
155                    cnid_t did, const char *name, size_t len, cnid_t hint)
156{
157    const struct stat *lstp;
158    cnid_t id;
159    struct _cnid_tdb_private *priv;
160    TDB_DATA key, data;
161    int rc;
162
163    if (!cdb || !(priv = cdb->_private) || !st || !name) {
164        errno = CNID_ERR_PARAM;
165        return CNID_INVALID;
166    }
167    /* Do a lookup. */
168    id = cnid_tdb_lookup(cdb, st, did, name, len);
169    /* ... Return id if it is valid, or if Rootinfo is read-only. */
170    if (id || (priv->flags & CNIDFLAG_DB_RO)) {
171        return id;
172    }
173
174#if 0
175    struct stat lst;
176    lstp = lstat(name, &lst) < 0 ? st : &lst;
177#endif
178    lstp = st;
179
180    /* Initialize our DBT data structures. */
181    memset(&key, 0, sizeof(key));
182    memset(&data, 0, sizeof(data));
183
184    key.dptr = (unsigned char *)&hint;
185    key.dsize = sizeof(cnid_t);
186    if ((data.dptr = make_tdb_data(cdb->flags, lstp, did, name, len)) == NULL) {
187        LOG(log_error, logtype_default, "tdb_add: Path name is too long");
188        errno = CNID_ERR_PATH;
189        return CNID_INVALID;
190    }
191    data.dsize = CNID_HEADER_LEN + len + 1;
192    hint = get_cnid(priv);
193    if (hint == 0) {
194        errno = CNID_ERR_DB;
195        return CNID_INVALID;
196    }
197    memcpy(data.dptr, &hint, sizeof(hint));
198
199    /* Now we need to add the CNID data to the databases. */
200    rc = add_cnid(priv, &key, &data);
201    if (rc) {
202        LOG(log_error, logtype_default, "tdb_add: Failed to add CNID for %s to database using hint %u", name, ntohl(hint));
203        errno = CNID_ERR_DB;
204        return CNID_INVALID;
205    }
206
207    return hint;
208}
209
210#endif
211