]> arthur.barton.de Git - netatalk.git/blob - libatalk/cnid/cnid_lookup.c
153dcca735da404828b86cd3df8114c6229399ee
[netatalk.git] / libatalk / cnid / cnid_lookup.c
1 /*
2  * $Id: cnid_lookup.c,v 1.17 2003-06-06 21:22:44 srittau 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 #define use_make_cnid_data
23 #include "cnid_private.h"
24
25 #define LOGFILEMAX    100  /* kbytes */
26 #define CHECKTIMEMAX   30  /* minutes */
27
28 /* This returns the CNID corresponding to a particular file.  It will
29  * also fix up the various databases if there's a problem. */
30 cnid_t cnid_lookup(void *CNID, const struct stat *st, const cnid_t did,
31                    const char *name, const int len)
32 {
33     char *buf;
34     CNID_private *db;
35     DBT key, devdata, diddata;
36     int devino = 1, didname = 1;
37     cnid_t id = 0;
38     int rc;
39
40     if (!(db = CNID) || !st || !name) {
41         return 0;
42     }
43
44 #ifndef CNID_DB_CDB
45     /* Do a little checkpointing if necessary.  I stuck it here as cnid_lookup
46      * gets called when we do directory lookups.  Only do this if we're using
47      * a read-write database. */
48     if ((db->flags & CNIDFLAG_DB_RO) == 0) {
49 #ifdef DEBUG
50         LOG(log_info, logtype_default, "cnid_lookup: Running database checkpoint");
51 #endif
52 #if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
53         db->dbenv->txn_checkpoint(db->dbenv, LOGFILEMAX, CHECKTIMEMAX, 0)
54 #else
55 #if DB_VERSION_MAJOR >= 4
56         switch (rc = db->dbenv->txn_checkpoint(db->dbenv, LOGFILEMAX, CHECKTIMEMAX, 0)) {
57 #else
58         switch (rc = txn_checkpoint(db->dbenv, LOGFILEMAX, CHECKTIMEMAX, 0)) {
59 #endif /* DB_VERSION_MAJOR >= 4 */
60         case 0:
61         case DB_INCOMPLETE:
62             break;
63         default:
64             LOG(log_error, logtype_default, "cnid_lookup: txn_checkpoint: %s",
65                 db_strerror(rc));
66             return 0;
67         }
68     }
69 #endif /* DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1) */
70 #endif /* CNID_DB_CDB */
71
72         if ((buf = make_cnid_data(st, did, name, len)) == NULL) {
73             LOG(log_error, logtype_default, "cnid_lookup: Pathname is too long");
74             return 0;
75         }
76
77         memset(&key, 0, sizeof(key));
78         memset(&devdata, 0, sizeof(devdata));
79         memset(&diddata, 0, sizeof(diddata));
80
81         /* Look for a CNID.  We have two options: dev/ino or did/name.  If we
82          * only get a match in one of them, that means a file has moved. */
83         key.data = buf;
84         key.size = CNID_DEVINO_LEN;
85         while ((rc = db->db_devino->get(db->db_devino, NULL, &key, &devdata, 0))) {
86 #ifndef CNID_DB_CDB
87             if (rc == DB_LOCK_DEADLOCK) {
88                 continue;
89             }
90 #endif /* CNID_DB_CDB */
91
92             if (rc == DB_NOTFOUND) {
93                 devino = 0;
94                 break;
95             }
96
97             LOG(log_error, logtype_default, "cnid_lookup: Unable to get CNID dev %u, ino %u: %s",
98                 st->st_dev, st->st_ino, db_strerror(rc));
99             return 0;
100         }
101
102         /* did/name now */
103         key.data = buf + CNID_DEVINO_LEN;
104         key.size = CNID_DID_LEN + len + 1;
105         while ((rc = db->db_didname->get(db->db_didname, NULL, &key, &diddata, 0))) {
106 #ifndef CNID_DB_CDB
107             if (rc == DB_LOCK_DEADLOCK) {
108                 continue;
109             }
110 #endif /* CNID_DB_CDB */
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         }
127         else if (devino) {
128             memcpy(&id, devdata.data, sizeof(id));
129         }
130
131         /* Either entries are in both databases or neither of them. */
132         if ((devino && didname) || !(devino || didname)) {
133 #ifdef DEBUG
134             LOG(log_info, logtype_default, "cnid_lookup: Looked up did %u, name %s, as %u",
135                 ntohl(did), name, ntohl(id));
136 #endif
137             return id;
138         }
139
140         /* Fix up the database. */
141         cnid_update(db, id, st, did, name, len);
142 #ifdef DEBUG
143         LOG(log_info, logtype_default, "cnid_lookup: Looked up did %u, name %s, as %u (needed update)", ntohl(did), name, ntohl(id));
144 #endif
145         return id;
146     }
147 #endif /* CNID_DB */
148
149