]> arthur.barton.de Git - netatalk.git/blob - libatalk/cnid/cnid_lookup.c
Add a static variable to track the exclusive lock. Seems Macs like to open
[netatalk.git] / libatalk / cnid / cnid_lookup.c
1 /*
2  * $Id: cnid_lookup.c,v 1.9 2001-10-21 08:33:33 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 <syslog.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         /* Do a little checkpointing if necessary.  I stuck it here as cnid_lookup
44          * gets called when we do directory lookups.  Only do this if we're using
45          * a read-write database. */
46         if ((db->flags & CNIDFLAG_DB_RO) == 0) {
47 #ifdef DEBUG
48                 syslog(LOG_INFO, "cnid_lookup: Running database checkpoint");
49 #endif
50                 switch (rc = txn_checkpoint(db->dbenv, LOGFILEMAX, CHECKTIMEMAX, 0)) {
51                         case 0:
52                         case DB_INCOMPLETE:
53                                 break;
54                         default:
55                                 syslog(LOG_ERR, "cnid_lookup: txn_checkpoint: %s", 
56                                        db_strerror(rc));
57                                 return 0;
58                 }
59         }
60
61         if ((buf = make_cnid_data(st, did, name, len)) == NULL) {
62                 syslog(LOG_ERR, "cnid_lookup: Pathname is too long");
63                 return 0;
64         }
65
66         memset(&key, 0, sizeof(key));
67         memset(&devdata, 0, sizeof(devdata));
68         memset(&diddata, 0, sizeof(diddata));
69
70         /* Look for a CNID.  We have two options: dev/ino or did/name.  If we
71          * only get a match in one of them, that means a file has moved. */
72         key.data = buf;
73         key.size = CNID_DEVINO_LEN;
74         while ((rc = db->db_devino->get(db->db_devino, NULL, &key, &devdata, 0))) {
75                 if (rc == DB_LOCK_DEADLOCK) {
76                         continue;
77                 }
78
79                 if (rc == DB_NOTFOUND) {
80                         devino = 0;
81                         break;
82                 }
83
84                 syslog(LOG_ERR, "cnid_lookup: Unable to get CNID dev %u, ino %u: %s",
85                        st->st_dev, st->st_ino, db_strerror(rc));
86                 return 0;
87         }
88
89         /* did/name now */
90         key.data = buf + CNID_DEVINO_LEN;
91         key.size = CNID_DID_LEN + len + 1;
92         while ((rc = db->db_didname->get(db->db_didname, NULL, &key, &diddata, 0))) {
93                 if (rc == DB_LOCK_DEADLOCK) {
94                         continue;
95                 }
96
97                 if (rc == DB_NOTFOUND) {
98                         didname = 0;
99                         break;
100                 }
101
102                 syslog(LOG_ERR, "cnid_lookup: Unable to get CNID %u, name %s: %s",
103                        ntohl(did), name, db_strerror(rc));
104                 return 0;
105         }
106
107         /* Set id.  Honor did/name over dev/ino as dev/ino isn't necessarily
108          * 1-1. */
109         if (didname) {
110                 memcpy(&id, diddata.data, sizeof(id));
111         }
112         else if (devino) {
113                 memcpy(&id, devdata.data, sizeof(id));
114         }
115
116         /* Either entries are in both databases or neither of them. */
117         if ((devino && didname) || !(devino || didname)) {
118 #ifdef DEBUG
119                 syslog(LOG_INFO, "cnid_lookup: Looked up did %u, name %s, as %u",
120                        ntohl(did), name, ntohl(id));
121 #endif
122                 return id;
123         }
124
125         /* Fix up the database. */
126         cnid_update(db, id, st, did, name, len);
127 #ifdef DEBUG
128         syslog(LOG_INFO, "cnid_lookup: Looked up did %u, name %s, as %u (needed update)", ntohl(did), name, ntohl(id));
129 #endif
130         return id;
131 }
132 #endif /* CNID_DB */
133
134