• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/netatalk-2.2.0/libatalk/cnid/tdb/
1/*
2 * $Id: cnid_tdb_add.c,v 1.4 2009-11-20 17:37:14 didg Exp $
3 *
4 * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
5 * All Rights Reserved. See COPYRIGHT.
6 *
7 */
8
9#ifdef HAVE_CONFIG_H
10#include "config.h"
11#endif
12
13#ifdef CNID_BACKEND_TDB
14#include "cnid_tdb.h"
15#include <atalk/util.h>
16#include <sys/param.h>
17#include <sys/types.h>
18#include <sys/stat.h>
19#include <unistd.h>
20#include <atalk/logger.h>
21
22static void make_devino_data(unsigned char *buf, dev_t dev, ino_t ino)
23{
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;
32
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;
41}
42
43unsigned char *make_tdb_data(u_int32_t flags, const struct stat *st,const cnid_t did,
44                     const char *name, const size_t len)
45{
46    static unsigned char start[CNID_HEADER_LEN + MAXPATHLEN + 1];
47    unsigned char *buf = start  +CNID_LEN;
48    u_int32_t i;
49
50    if (len > MAXPATHLEN)
51        return NULL;
52
53    make_devino_data(buf, !(flags & CNID_FLAG_NODEV)?st->st_dev:0, st->st_ino);
54    buf += CNID_DEVINO_LEN;
55
56    i = S_ISDIR(st->st_mode)?1:0;
57    i = htonl(i);
58    memcpy(buf, &i, sizeof(i));
59    buf += sizeof(i);
60
61    /* did is already in network byte order */
62    memcpy(buf, &did, sizeof(did));
63    buf += sizeof(did);
64
65    memcpy(buf, name, len);
66    *(buf + len) = '\0';
67
68    return start;
69}
70
71/* add an entry to the CNID databases. we do this as a transaction
72 * to prevent messiness.
73 * key:   cnid
74 * data:
75 */
76static int add_cnid (struct _cnid_tdb_private *db, TDB_DATA *key, TDB_DATA *data) {
77    TDB_DATA altkey, altdata;
78
79    memset(&altkey, 0, sizeof(altkey));
80    memset(&altdata, 0, sizeof(altdata));
81
82
83    /* main database */
84    if (tdb_store(db->tdb_cnid, *key, *data, TDB_REPLACE)) {
85        goto abort;
86    }
87
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)) {
94        goto abort;
95    }
96
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)) {
101        goto abort;
102    }
103    return 0;
104
105abort:
106    return -1;
107}
108
109/* ----------------------- */
110static cnid_t get_cnid(struct _cnid_tdb_private *db)
111{
112    TDB_DATA rootinfo_key, data;
113    cnid_t hint,id;
114
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;
119
120    tdb_chainlock(db->tdb_didname, rootinfo_key);
121    data = tdb_fetch(db->tdb_didname, rootinfo_key);
122    if (data.dptr)
123    {
124        memcpy(&hint, data.dptr, sizeof(cnid_t));
125        free(data.dptr);
126        id = ntohl(hint);
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;
132            goto cleanup;
133        }
134        hint = htonl(id);
135    }
136    else {
137        hint = htonl(CNID_START);
138    }
139
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)) {
144        goto cleanup;
145    }
146
147    tdb_chainunlock(db->tdb_didname, rootinfo_key );
148    return hint;
149cleanup:
150    tdb_chainunlock(db->tdb_didname, rootinfo_key);
151    return CNID_INVALID;
152}
153
154
155/* ------------------------ */
156cnid_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)
158{
159    const struct stat *lstp;
160    cnid_t id;
161    struct _cnid_tdb_private *priv;
162    TDB_DATA key, data;
163    int rc;
164
165    if (!cdb || !(priv = cdb->_private) || !st || !name) {
166        errno = CNID_ERR_PARAM;
167        return CNID_INVALID;
168    }
169    /* Do a lookup. */
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)) {
173        return id;
174    }
175
176#if 0
177    struct stat lst;
178    lstp = lstat(name, &lst) < 0 ? st : &lst;
179#endif
180    lstp = st;
181
182    /* Initialize our DBT data structures. */
183    memset(&key, 0, sizeof(key));
184    memset(&data, 0, sizeof(data));
185
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;
191        return CNID_INVALID;
192    }
193    data.dsize = CNID_HEADER_LEN + len + 1;
194    hint = get_cnid(priv);
195    if (hint == 0) {
196        errno = CNID_ERR_DB;
197        return CNID_INVALID;
198    }
199    memcpy(data.dptr, &hint, sizeof(hint));
200
201    /* Now we need to add the CNID data to the databases. */
202    rc = add_cnid(priv, &key, &data);
203    if (rc) {
204        LOG(log_error, logtype_default, "tdb_add: Failed to add CNID for %s to database using hint %u", name, ntohl(hint));
205        errno = CNID_ERR_DB;
206        return CNID_INVALID;
207    }
208
209    return hint;
210}
211
212#endif
213