]> arthur.barton.de Git - netatalk.git/blob - libatalk/cnid/db3/cnid_db3_lookup.c
use log_debug rather than log_info for LOG inside ifdef DEBUG
[netatalk.git] / libatalk / cnid / db3 / cnid_db3_lookup.c
1
2 /*
3  * $Id: cnid_db3_lookup.c,v 1.4 2009-10-29 13:17:29 didg Exp $
4  */
5
6 #ifdef HAVE_CONFIG_H
7 #include "config.h"
8 #endif /* HAVE_CONFIG_H */
9
10 #ifdef CNID_BACKEND_DB3
11
12 #include <stdio.h>
13 #include <string.h>
14 #include <sys/param.h>
15 #include <sys/stat.h>
16 #include <atalk/logger.h>
17 #include <errno.h>
18
19 #ifdef HAVE_DB4_DB_H
20 #include <db4/db.h>
21 #else
22 #include <db.h>
23 #endif
24 #include <netatalk/endian.h>
25 #include <atalk/adouble.h>
26 #include "cnid_db3.h"
27
28 #include "cnid_db3_private.h"
29
30 #define LOGFILEMAX    100       /* kbytes */
31 #define CHECKTIMEMAX   30       /* minutes */
32
33 /* This returns the CNID corresponding to a particular file.  It will
34  * also fix up the various databases if there's a problem. */
35 cnid_t cnid_db3_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did, char *name, const size_t len)
36 {
37     unsigned char *buf;
38     CNID_private *db;
39     DBT key, devdata, diddata;
40     int devino = 1, didname = 1;
41     cnid_t id = 0;
42     int rc;
43
44     if (!cdb || !(db = cdb->_private) || !st || !name) {
45         return 0;
46     }
47
48     /* Do a little checkpointing if necessary.  I stuck it here as cnid_lookup
49      * gets called when we do directory lookups.  Only do this if we're using
50      * a read-write database. */
51     if ((db->flags & CNIDFLAG_DB_RO) == 0) {
52 #ifdef DEBUG
53         LOG(log_debug, logtype_default, "cnid_lookup: Running database checkpoint");
54 #endif
55 #if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
56         if ((rc = db->dbenv->txn_checkpoint(db->dbenv, LOGFILEMAX, CHECKTIMEMAX, 0))) {
57             LOG(log_error, logtype_default, "cnid_lookup: txn_checkpoint: %s", db_strerror(rc));
58             return 0;
59         }
60 #else
61 #if DB_VERSION_MAJOR >= 4
62         switch (rc = db->dbenv->txn_checkpoint(db->dbenv, LOGFILEMAX, CHECKTIMEMAX, 0)) {
63 #else
64         switch (rc = txn_checkpoint(db->dbenv, LOGFILEMAX, CHECKTIMEMAX, 0)) {
65 #endif /* DB_VERSION_MAJOR >= 4 */
66         case 0:
67         case DB_INCOMPLETE:
68             break;
69         default:
70             LOG(log_error, logtype_default, "cnid_lookup: txn_checkpoint: %s", db_strerror(rc));
71             return 0;
72         }
73 #endif /* DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1) */
74     }
75
76     if ((buf = make_cnid_data(st, did, name, len)) == NULL) {
77         LOG(log_error, logtype_default, "cnid_lookup: Pathname is too long");
78         return 0;
79     }
80
81     memset(&key, 0, sizeof(key));
82     memset(&devdata, 0, sizeof(devdata));
83     memset(&diddata, 0, sizeof(diddata));
84
85     /* Look for a CNID.  We have two options: dev/ino or did/name.  If we
86      * only get a match in one of them, that means a file has moved. */
87     key.data = buf;
88     key.size = CNID_DEVINO_LEN;
89     while ((rc = db->db_devino->get(db->db_devino, NULL, &key, &devdata, 0))) {
90         if (rc == DB_LOCK_DEADLOCK) {
91             continue;
92         }
93
94         if (rc == DB_NOTFOUND) {
95             devino = 0;
96             break;
97         }
98
99         LOG(log_error, logtype_default, "cnid_lookup: Unable to get CNID dev %u, ino %u: %s",
100             st->st_dev, st->st_ino, db_strerror(rc));
101         return 0;
102     }
103
104     /* did/name now */
105     key.data = buf + CNID_DEVINO_LEN;
106     key.size = CNID_DID_LEN + len + 1;
107     while ((rc = db->db_didname->get(db->db_didname, NULL, &key, &diddata, 0))) {
108         if (rc == DB_LOCK_DEADLOCK) {
109             continue;
110         }
111
112         if (rc == DB_NOTFOUND) {
113             didname = 0;
114             break;
115         }
116
117         LOG(log_error, logtype_default, "cnid_lookup: Unable to get CNID %u, name %s: %s",
118             ntohl(did), name, db_strerror(rc));
119         return 0;
120     }
121
122     /* Set id.  Honor did/name over dev/ino as dev/ino isn't necessarily
123      * 1-1. */
124     if (didname) {
125         memcpy(&id, diddata.data, sizeof(id));
126     } else if (devino) {
127         memcpy(&id, devdata.data, sizeof(id));
128     }
129
130     /* Either entries are in both databases or neither of them. */
131     if ((devino && didname) || !(devino || didname)) {
132 #ifdef DEBUG
133         LOG(log_debug, logtype_default, "cnid_lookup: Looked up did %u, name %s, as %u", ntohl(did), name, ntohl(id));
134 #endif
135         return id;
136     }
137
138     /* Fix up the database. */
139     cnid_db3_update(cdb, id, st, did, name, len);
140 #ifdef DEBUG
141     LOG(log_debug, logtype_default, "cnid_lookup: Looked up did %u, name %s, as %u (needed update)", ntohl(did), name,
142         ntohl(id));
143 #endif
144     return id;
145 }
146
147
148 #endif /* CNID_BACKEND_DB3 */