]> arthur.barton.de Git - netatalk.git/blob - libatalk/cnid/cnid_lookup.c
massive commenting/autoconf changes
[netatalk.git] / libatalk / cnid / cnid_lookup.c
1 /*
2  * $Id: cnid_lookup.c,v 1.2 2001-06-29 14:14:46 rufustfirefly Exp $
3  */
4
5 #ifdef HAVE_CONFIG_H
6 #include "config.h"
7 #endif /* HAVE_CONFIG_H */
8
9 #include <stdio.h>
10 #include <string.h>
11 #include <sys/param.h>
12 #include <sys/stat.h>
13 #include <syslog.h>
14 #include <errno.h>
15
16 #include <db.h>
17 #include <netatalk/endian.h>
18 #include <atalk/adouble.h>
19 #include <atalk/cnid.h>
20
21 #include "cnid_private.h"
22
23 #define LOGFILEMAX    100  /* kbytes */
24 #define CHECKTIMEMAX   30  /* minutes */
25
26 /* this returns the cnid corresponding to a particular file. it will
27    also fix up the various databases if there's a problem. */
28 cnid_t cnid_lookup(void *CNID,
29                    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   DB_TXNMGR *txnp;
36   int devino = 1, didname = 1;
37   cnid_t id = 0;
38   
39   if (!(db = CNID) || !st || !name)
40     return 0;
41
42   /* do a little checkpointing if necessary. i stuck it here as 
43    * cnid_lookup gets called when we do directory lookups. only do 
44    * this if we're using a read-write database. */
45   if ((db->flags & CNIDFLAG_DB_RO) == 0) {
46     txnp = db->dbenv.tx_info;
47     errno = txn_checkpoint(txnp, LOGFILEMAX, CHECKTIMEMAX);
48     while (errno == DB_INCOMPLETE)
49       errno = txn_checkpoint(txnp, 0, 0);
50   }
51
52  if ((buf = make_cnid_data(st, did, name, len)) == NULL) {
53     syslog(LOG_ERR, "cnid_lookup: path name too long");
54     return 0;
55   }
56
57   memset(&key, 0, sizeof(key));
58   memset(&devdata, 0, sizeof(devdata));
59
60   /* look for a CNID. we have two options: dev/ino or did/name. if we
61      only get a match on one of them, that means a file has moved. */
62   key.data = buf; /* dev/ino is the first part of the buffer */
63   key.size = CNID_DEVINO_LEN;
64   while (errno = db->db_devino->get(db->db_devino, NULL,
65                                     &key, &devdata, 0)) {
66     if (errno == EAGAIN)
67       continue;
68     
69     if (errno == DB_NOTFOUND) {
70       devino = 0;
71       break;
72     }
73     
74     syslog(LOG_ERR, "cnid_lookup: can't get CNID(%u/%u)",
75            st->st_dev, st->st_ino);
76     return 0;
77   }
78
79   /* did/name is right afterwards. */
80   key.data = buf + CNID_DEVINO_LEN; 
81   key.size = CNID_DID_LEN + len + 1;
82   memset(&diddata, 0, sizeof(diddata));
83   while (errno = db->db_didname->get(db->db_didname, NULL,
84                                        &key, &diddata, 0)) {
85     if (errno == EAGAIN)
86       continue;
87
88     if (errno == DB_NOTFOUND) {
89       didname = 0;
90       break;
91     }
92
93     syslog(LOG_ERR, "cnid_lookup: can't get CNID(%u:%s)",
94            did, name);
95     return 0;
96   }
97
98   /* set id. honor did/name over dev/ino as dev/ino isn't necessarily 
99    * 1-1. */
100   if (didname) {
101     memcpy(&id, diddata.data, sizeof(id));
102   } else if (devino) {
103     memcpy(&id, devdata.data, sizeof(id));
104   } 
105
106   /* either entries in both databases exist or neither of them do. */
107   if ((devino && didname) || !(devino || didname)) 
108     return id;
109
110   /* fix up the databases */
111   cnid_update(db, id, st, did, name, len);
112   return id;
113 }