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