• 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/cdb/
1/*
2 * $Id: cnid_cdb_add.c,v 1.8 2009-11-20 17:22:11 didg Exp $
3 *
4 * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
5 * All Rights Reserved. See COPYRIGHT.
6 *
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.
10 */
11
12#ifdef HAVE_CONFIG_H
13#include "config.h"
14#endif /* HAVE_CONFIG_H */
15
16#ifdef CNID_BACKEND_CDB
17#include "cnid_cdb_private.h"
18
19extern int cnid_cdb_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
20                const cnid_t did, char *name, const size_t len);
21
22
23#define tid    NULL
24
25static void make_devino_data(unsigned char *buf, dev_t dev, ino_t ino)
26{
27    buf[CNID_DEV_LEN - 1] = dev; dev >>= 8;
28    buf[CNID_DEV_LEN - 2] = dev; dev >>= 8;
29    buf[CNID_DEV_LEN - 3] = dev; dev >>= 8;
30    buf[CNID_DEV_LEN - 4] = dev; dev >>= 8;
31    buf[CNID_DEV_LEN - 5] = dev; dev >>= 8;
32    buf[CNID_DEV_LEN - 6] = dev; dev >>= 8;
33    buf[CNID_DEV_LEN - 7] = dev; dev >>= 8;
34    buf[CNID_DEV_LEN - 8] = dev;
35
36    buf[CNID_DEV_LEN + CNID_INO_LEN - 1] = ino; ino >>= 8;
37    buf[CNID_DEV_LEN + CNID_INO_LEN - 2] = ino; ino >>= 8;
38    buf[CNID_DEV_LEN + CNID_INO_LEN - 3] = ino; ino >>= 8;
39    buf[CNID_DEV_LEN + CNID_INO_LEN - 4] = ino; ino >>= 8;
40    buf[CNID_DEV_LEN + CNID_INO_LEN - 5] = ino; ino >>= 8;
41    buf[CNID_DEV_LEN + CNID_INO_LEN - 6] = ino; ino >>= 8;
42    buf[CNID_DEV_LEN + CNID_INO_LEN - 7] = ino; ino >>= 8;
43    buf[CNID_DEV_LEN + CNID_INO_LEN - 8] = ino;
44}
45
46unsigned char *make_cnid_data(u_int32_t flags, const struct stat *st, const cnid_t did,
47                     const char *name, const size_t len)
48{
49    static unsigned char start[CNID_HEADER_LEN + MAXPATHLEN + 1];
50    unsigned char *buf = start  +CNID_LEN;
51    u_int32_t i;
52
53    if (len > MAXPATHLEN)
54        return NULL;
55
56    make_devino_data(buf, !(flags & CNID_FLAG_NODEV)?st->st_dev:0, st->st_ino);
57    buf += CNID_DEVINO_LEN;
58
59    i = S_ISDIR(st->st_mode)?1:0;
60    i = htonl(i);
61    memcpy(buf, &i, sizeof(i));
62    buf += sizeof(i);
63
64    /* did is already in network byte order */
65    memcpy(buf, &did, sizeof(did));
66    buf += sizeof(did);
67
68    memcpy(buf, name, len);
69    *(buf + len) = '\0';
70
71    return start;
72}
73
74/* --------------- */
75static int db_stamp(void *buffer, size_t size)
76{
77time_t t;
78    memset(buffer, 0, size);
79    /* return the current time. */
80    if (size < sizeof(time_t))
81        return -1;
82    t = time(NULL);
83    memcpy(buffer,&t, sizeof(time_t));
84    return 0;
85
86}
87
88
89/* ----------------------------- */
90static cnid_t get_cnid(CNID_private *db)
91{
92    DBT rootinfo_key, rootinfo_data;
93    DBC  *cursor;
94    int rc;
95    int flag, setstamp=0;
96    cnid_t hint,id;
97    char buf[ROOTINFO_DATALEN];
98    char stamp[CNID_DEV_LEN];
99
100    if ((rc = db->db_cnid->cursor(db->db_cnid, NULL, &cursor, DB_WRITECURSOR) ) != 0) {
101        LOG(log_error, logtype_default, "get_cnid: Unable to get a cursor: %s", db_strerror(rc));
102        return CNID_INVALID;
103    }
104
105    memset(&rootinfo_key, 0, sizeof(rootinfo_key));
106    memset(&rootinfo_data, 0, sizeof(rootinfo_data));
107    rootinfo_key.data = ROOTINFO_KEY;
108    rootinfo_key.size = ROOTINFO_KEYLEN;
109
110    switch (rc = cursor->c_get(cursor, &rootinfo_key, &rootinfo_data, DB_SET)) {
111    case 0:
112        memcpy(&hint, (char *)rootinfo_data.data +CNID_TYPE_OFS, sizeof(hint));
113        id = ntohl(hint);
114        /* If we've hit the max CNID allowed, we return a fatal error.  CNID
115         * needs to be recycled before proceding. */
116        if (++id == CNID_INVALID) {
117            LOG(log_error, logtype_default, "cnid_add: FATAL: CNID database has reached its limit.");
118            errno = CNID_ERR_MAX;
119            goto cleanup;
120        }
121        hint = htonl(id);
122        flag = DB_CURRENT;
123        break;
124    case DB_NOTFOUND:
125        hint = htonl(CNID_START);
126        flag = DB_KEYFIRST;
127	setstamp = 1;
128        break;
129    default:
130        LOG(log_error, logtype_default, "cnid_add: Unable to lookup rootinfo: %s", db_strerror(rc));
131	errno = CNID_ERR_DB;
132        goto cleanup;
133    }
134
135    memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN);
136    rootinfo_data.data = buf;
137    rootinfo_data.size = ROOTINFO_DATALEN;
138    memcpy((char *)rootinfo_data.data +CNID_TYPE_OFS, &hint, sizeof(hint));
139    if (setstamp) {
140        if (db_stamp(stamp, CNID_DEV_LEN) < 0) {
141            goto cleanup;
142        }
143        memcpy((char *)rootinfo_data.data +CNID_DEV_OFS, stamp, sizeof(stamp));
144    }
145
146
147    switch (rc = cursor->c_put(cursor, &rootinfo_key, &rootinfo_data, flag)) {
148    case 0:
149        break;
150    default:
151        LOG(log_error, logtype_default, "cnid_add: Unable to update rootinfo: %s", db_strerror(rc));
152	errno = CNID_ERR_DB;
153        goto cleanup;
154    }
155    if ((rc = cursor->c_close(cursor)) != 0) {
156        LOG(log_error, logtype_default, "get_cnid: Unable to close cursor: %s", db_strerror(rc));
157	errno = CNID_ERR_DB;
158        return CNID_INVALID;
159    }
160    return hint;
161cleanup:
162    if ((rc = cursor->c_close(cursor)) != 0) {
163        LOG(log_error, logtype_default, "get_cnid: Unable to close cursor: %s", db_strerror(rc));
164        return CNID_INVALID;
165    }
166    return CNID_INVALID;
167}
168
169/* ------------------------ */
170cnid_t cnid_cdb_add(struct _cnid_db *cdb, const struct stat *st,
171                const cnid_t did, char *name, const size_t len,
172                cnid_t hint)
173{
174    CNID_private *db;
175    DBT key, data;
176    cnid_t id;
177    int rc;
178
179    if (!cdb || !(db = cdb->_private) || !st || !name) {
180        errno = CNID_ERR_PARAM;
181        return CNID_INVALID;
182    }
183
184    /* Do a lookup. */
185    id = cnid_cdb_lookup(cdb, st, did, name, len);
186    /* ... Return id if it is valid, or if Rootinfo is read-only. */
187    if (id || (db->flags & CNIDFLAG_DB_RO)) {
188#ifdef DEBUG
189        LOG(log_debug9, logtype_default, "cnid_add: Looked up did %u, name %s as %u", ntohl(did), name, ntohl(id));
190#endif
191        return id;
192    }
193
194    /* Initialize our DBT data structures. */
195    memset(&key, 0, sizeof(key));
196    memset(&data, 0, sizeof(data));
197
198    if ((data.data = make_cnid_data(cdb->flags, st, did, name, len)) == NULL) {
199        LOG(log_error, logtype_default, "cnid_add: Path name is too long");
200        errno = CNID_ERR_PATH;
201        return CNID_INVALID;
202    }
203    data.size = CNID_HEADER_LEN + len + 1;
204
205    if ((hint = get_cnid(db)) == 0) {
206         errno = CNID_ERR_DB;
207         return CNID_INVALID;
208    }
209    memcpy(data.data, &hint, sizeof(hint));
210
211    key.data = &hint;
212    key.size = sizeof(hint);
213
214    /* Now we need to add the CNID data to the databases. */
215    if ((rc = db->db_cnid->put(db->db_cnid, tid, &key, &data, DB_NOOVERWRITE))) {
216        if (rc == EINVAL) {
217            /* if we have a duplicate
218             * on cnid it's a fatal error.
219             * on dev:inode
220             *   - leftover should have been delete before.
221             *   - a second process already updated the db
222             *   - it's a new file eg our file is already deleted and replaced
223             * on did:name leftover
224            */
225            if (cnid_cdb_update(cdb, hint, st, did, name, len)) {
226                errno = CNID_ERR_DB;
227                return CNID_INVALID;
228            }
229        }
230        else {
231            LOG(log_error, logtype_default
232                   , "cnid_add: Failed to add CNID for %s to database using hint %u: %s",
233                   name, ntohl(hint), db_strerror(rc));
234            errno = CNID_ERR_DB;
235            return CNID_INVALID;
236        }
237    }
238
239#ifdef DEBUG
240    LOG(log_debug9, logtype_default, "cnid_add: Returned CNID for did %u, name %s as %u", ntohl(did), name, ntohl(hint));
241#endif
242
243    return hint;
244}
245
246/* cnid_cbd_getstamp */
247/*-----------------------*/
248int cnid_cdb_getstamp(struct _cnid_db *cdb, void *buffer, const size_t len)
249{
250    DBT key, data;
251    int rc;
252    CNID_private *db;
253
254    if (!cdb || !(db = cdb->_private) || !buffer || !len) {
255        errno = CNID_ERR_PARAM;
256        return -1;
257    }
258
259    memset(buffer, 0, len);
260    memset(&key, 0, sizeof(key));
261    memset(&data, 0, sizeof(data));
262
263    key.data = ROOTINFO_KEY;
264    key.size = ROOTINFO_KEYLEN;
265
266    if (0 != (rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0 )) ) {
267        if (rc != DB_NOTFOUND) {
268            LOG(log_error, logtype_default, "cnid_lookup: Unable to get database stamp: %s",
269               db_strerror(rc));
270            errno = CNID_ERR_DB;
271            return -1;
272        }
273	/* we waste a single ID here... */
274        get_cnid(db);
275        memset(&key, 0, sizeof(key));
276        memset(&data, 0, sizeof(data));
277        key.data = ROOTINFO_KEY;
278        key.size = ROOTINFO_KEYLEN;
279	if (0 != (rc = db->db_cnid->get(db->db_cnid, NULL, &key, &data, 0 )) ) {
280	    LOG(log_error, logtype_default, "cnid_getstamp: failed to get rootinfo: %s",
281               db_strerror(rc));
282            errno = CNID_ERR_DB;
283	    return -1;
284        }
285    }
286
287    memcpy(buffer, (char*)data.data + CNID_DEV_OFS, len);
288#ifdef DEBUG
289    LOG(log_debug9, logtype_cnid, "cnid_getstamp: Returning stamp");
290#endif
291   return 0;
292}
293
294
295#endif /* CNID_BACKEND_CDB */
296