• 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/etc/cnid_dbd/
1/*
2 * Copyright (C) Joerg Lenneis 2003
3 * Copyright (C) Frank Lahm 2010
4 * All Rights Reserved.  See COPYING.
5 */
6
7#ifdef HAVE_CONFIG_H
8#include "config.h"
9#endif /* HAVE_CONFIG_H */
10
11#include <string.h>
12#ifdef HAVE_UNISTD_H
13#include <unistd.h>
14#endif /* HAVE_UNISTD_H */
15#ifdef HAVE_FCNTL_H
16#include <fcntl.h>
17#endif /* HAVE_FCNTL_H */
18#include <errno.h>
19#ifdef HAVE_SYS_TIME_H
20#include <sys/time.h>
21#endif /* HAVE_SYS_TIME_H */
22
23#include <atalk/logger.h>
24#include <atalk/cnid_dbd_private.h>
25#include <atalk/cnid.h>
26#ifdef HAVE_DB4_DB_H
27#include <db4/db.h>
28#else
29#include <db.h>
30#endif
31
32#include "dbif.h"
33#include "pack.h"
34#include "dbd.h"
35
36int add_cnid(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
37{
38    DBT key, data;
39    int rc;
40
41    memset(&key, 0, sizeof(key));
42    memset(&data, 0, sizeof(data));
43
44    key.data = &rply->cnid;
45    key.size = sizeof(rply->cnid);
46
47    data.data = pack_cnid_data(rqst);
48    data.size = CNID_HEADER_LEN + rqst->namelen + 1;
49    memcpy(data.data, &rply->cnid, sizeof(rply->cnid));
50
51    /* main database */
52    if ((rc = dbif_put(dbd, DBIF_CNID, &key, &data, DB_NOOVERWRITE))) {
53        /* This could indicate a database error or that the key already exists
54         (because of DB_NOOVERWRITE). In that case we still look at some sort of
55         database corruption since that is not supposed to happen. */
56
57        switch (rc) {
58        case 1:
59            rply->result = CNID_DBD_RES_ERR_DUPLCNID;
60            break;
61        case -1:
62	    /* FIXME: Should that not be logged for case 1:? */
63            LOG(log_error, logtype_cnid, "add_cnid: duplicate %x %s", rply->cnid
64             , (char *)data.data + CNID_NAME_OFS);
65
66            rqst->cnid = rply->cnid;
67            rc = dbd_update(dbd, rqst, rply);
68            if (rc < 0) {
69                rply->result = CNID_DBD_RES_ERR_DB;
70                return -1;
71            }
72            else
73               return 0;
74            break;
75        }
76        return -1;
77    }
78
79    return 0;
80}
81
82/* ---------------------- */
83int get_cnid(DBD *dbd, struct cnid_dbd_rply *rply)
84{
85    static cnid_t id;
86    static char buf[ROOTINFO_DATALEN];
87    DBT rootinfo_key, rootinfo_data;
88    int rc;
89    cnid_t hint;
90
91    memset(&rootinfo_key, 0, sizeof(rootinfo_key));
92    memset(&rootinfo_data, 0, sizeof(rootinfo_data));
93    rootinfo_key.data = ROOTINFO_KEY;
94    rootinfo_key.size = ROOTINFO_KEYLEN;
95
96    if (id == 0) {
97        if ((rc = dbif_get(dbd, DBIF_CNID, &rootinfo_key, &rootinfo_data, 0)) < 0) {
98            rply->result = CNID_DBD_RES_ERR_DB;
99            return -1;
100        }
101        if (rc == 0) {
102            /* no rootinfo key yet */
103            memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN);
104            id = CNID_START - 1;
105        } else {
106            memcpy(buf, (char *)rootinfo_data.data, ROOTINFO_DATALEN);
107            memcpy(&hint, buf + CNID_TYPE_OFS, sizeof(hint));
108            id = ntohl(hint);
109            if (id < CNID_START - 1)
110                id = CNID_START - 1;
111        }
112    }
113
114    /* If we've hit the max CNID allowed, we return an error. CNID
115     * needs to be recycled before proceding. */
116    if (++id == CNID_INVALID) {
117        rply->result = CNID_DBD_RES_ERR_MAX;
118        return -1;
119    }
120
121    rootinfo_data.data = buf;
122    rootinfo_data.size = ROOTINFO_DATALEN;
123    hint = htonl(id);
124    memcpy(buf + CNID_TYPE_OFS, &hint, sizeof(hint));
125
126    if (dbif_put(dbd, DBIF_CNID, &rootinfo_key, &rootinfo_data, 0) < 0) {
127        rply->result = CNID_DBD_RES_ERR_DB;
128        return -1;
129    }
130    rply->cnid = hint;
131    return 0;
132}
133
134/* ------------------------ */
135/* We need a nolookup version for `dbd` */
136int dbd_add(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply, int nolookup)
137{
138    rply->namelen = 0;
139
140    LOG(log_debug, logtype_cnid, "dbd_add(did:%u, '%s', dev/ino:0x%llx/0x%llx) {start}",
141        ntohl(rqst->did), rqst->name, (unsigned long long)rqst->dev, (unsigned long long)rqst->ino);
142
143    /* See if we have an entry already and return it if yes */
144    if (! nolookup) {
145        if (dbd_lookup(dbd, rqst, rply, 0) < 0) {
146            LOG(log_debug, logtype_cnid, "dbd_add(did:%u, '%s', dev/ino:0x%llx/0x%llx): error in dbd_lookup",
147                ntohl(rqst->did), rqst->name, (unsigned long long)rqst->dev, (unsigned long long)rqst->ino);
148            return -1;
149        }
150
151        if (rply->result == CNID_DBD_RES_OK) {
152            /* Found it. rply->cnid is the correct CNID now. */
153            LOG(log_debug, logtype_cnid, "dbd_add: dbd_lookup success --> CNID: %u", ntohl(rply->cnid));
154            return 1;
155        }
156    }
157
158    LOG(log_debug, logtype_cnid, "dbd_add(did:%u, '%s', dev/ino:0x%llx/0x%llx): {adding to database ...}",
159        ntohl(rqst->did), rqst->name, (unsigned long long)rqst->dev, (unsigned long long)rqst->ino);
160
161
162    if (get_cnid(dbd, rply) < 0) {
163        if (rply->result == CNID_DBD_RES_ERR_MAX) {
164            LOG(log_error, logtype_cnid, "dbd_add: FATAL: CNID database has reached its limit.");
165            /* This will cause an abort/rollback if transactions are used */
166            return 0;
167        } else {
168            LOG(log_error, logtype_cnid, "dbd_add: Failed to compute CNID for %s, error reading/updating Rootkey", rqst->name);
169            return -1;
170        }
171    }
172
173    if (add_cnid(dbd, rqst, rply) < 0) {
174        if (rply->result == CNID_DBD_RES_ERR_DUPLCNID) {
175            LOG(log_error, logtype_cnid, "dbd_add(DID: %u/\"%s\", dev/ino 0x%llx/0x%llx): Cannot add CNID: %u",
176                ntohl(rqst->did), rqst->name, (unsigned long long)rqst->dev, (unsigned long long)rqst->ino, ntohl(rply->cnid));
177            /* abort/rollback, see above */
178            return 0;
179        } else {
180            LOG(log_error, logtype_cnid, "dbd_add: Failed to add CNID for %s to database", rqst->name);
181            return -1;
182        }
183    }
184    LOG(log_debug, logtype_cnid, "dbd_add(did:%u, '%s', dev/ino:0x%llx/0x%llx): Added with CNID: %u",
185        ntohl(rqst->did), rqst->name, (unsigned long long)rqst->dev, (unsigned long long)rqst->ino, ntohl(rply->cnid));
186
187    rply->result = CNID_DBD_RES_OK;
188    return 1;
189}
190