]> arthur.barton.de Git - netatalk.git/blob - libatalk/cnid/cdb/cnid_cdb_lookup.c
7b2f933c5182b4e1c4d4974f5a46c3bd7aa695ac
[netatalk.git] / libatalk / cnid / cdb / cnid_cdb_lookup.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif /* HAVE_CONFIG_H */
4
5 #ifdef CNID_BACKEND_CDB
6 #include "cnid_cdb_private.h"
7
8 #define LOGFILEMAX    100  /* kbytes */
9 #define CHECKTIMEMAX   30  /* minutes */
10
11 /* This returns the CNID corresponding to a particular file.  It will
12  * also fix up the various databases if there's a problem. */
13 cnid_t cnid_cdb_lookup(struct _cnid_db *cdb, const struct stat *st, cnid_t did,
14                        const char *name, size_t len)
15 {
16     unsigned char *buf;
17     CNID_private *db;
18     DBT key, devdata, diddata;
19     char dev[CNID_DEV_LEN];
20     char ino[CNID_INO_LEN];  
21     int devino = 1, didname = 1; 
22     u_int32_t type_devino  = (unsigned)-1;
23     u_int32_t type_didname = (unsigned)-1;
24     u_int32_t type;
25     int update = 0;
26     cnid_t id_devino, id_didname,id = 0;
27     int rc;
28
29     if (!cdb || !(db = cdb->_private) || !st || !name) {
30         return 0;
31     }
32     
33     if ((buf = make_cnid_data(cdb->flags, st, did, name, len)) == NULL) {
34         LOG(log_error, logtype_default, "cnid_lookup: Pathname is too long");
35         return 0;
36     }
37
38     memcpy(&type, buf +CNID_TYPE_OFS, sizeof(type));
39     type = ntohl(type);
40
41     memset(&key, 0, sizeof(key));
42     memset(&diddata, 0, sizeof(diddata));
43     memset(&devdata, 0, sizeof(devdata));
44
45     /* Look for a CNID for our did/name */
46     key.data = buf +CNID_DEVINO_OFS;
47     key.size = CNID_DEVINO_LEN;
48
49     memcpy(dev, buf + CNID_DEV_OFS, CNID_DEV_LEN);
50     memcpy(ino, buf + CNID_INO_OFS, CNID_INO_LEN);
51     
52     if (0 != (rc = db->db_didname->get(db->db_devino, NULL, &key, &devdata, 0 )) ) {
53         if (rc != DB_NOTFOUND) {
54             LOG(log_error, logtype_default, "cnid_lookup: Unable to get CNID did 0x%x, name %s: %s",
55                did, name, db_strerror(rc));
56             return 0;
57         }
58         devino = 0;
59     }
60     else {
61         memcpy(&id_devino, devdata.data, sizeof(cnid_t));
62         memcpy(&type_devino, (char *)devdata.data +CNID_TYPE_OFS, sizeof(type_devino));
63         type_devino = ntohl(type_devino);
64     }
65
66     buf = make_cnid_data(cdb->flags, st, did, name, len);
67     key.data = buf +CNID_DID_OFS;
68     key.size = CNID_DID_LEN + len + 1;
69     
70     if (0 != (rc = db->db_didname->get(db->db_didname, NULL, &key, &diddata, 0 ) ) ) {
71         if (rc != DB_NOTFOUND) {
72             LOG(log_error, logtype_default, "cnid_lookup: Unable to get CNID did 0x%x, name %s: %s",
73                did, name, db_strerror(rc));
74             return 0;
75         }
76         didname = 0;
77     }
78     else {
79         memcpy(&id_didname, diddata.data, sizeof(cnid_t));
80         memcpy(&type_didname, (char *)diddata.data +CNID_TYPE_OFS, sizeof(type_didname));
81         type_didname = ntohl(type_didname);
82     }
83
84     if (!devino && !didname) {  
85         return 0;
86     }
87
88     if (devino && didname && id_devino == id_didname && type_devino == type) {
89         /* the same */
90         return id_didname;
91     }
92  
93     if (didname) {
94         id = id_didname;
95         /* we have a did:name 
96          * if it's the same dev or not the same type
97          * just delete it
98         */
99         if (!memcmp(dev, (char *)diddata.data + CNID_DEV_OFS, CNID_DEV_LEN) ||
100                    type_didname != type) {
101             if (cnid_cdb_delete(cdb, id) < 0) {
102                 return 0;
103             }
104         }
105         else {
106             update = 1;
107         }
108     }
109
110     if (devino) {
111         id = id_devino;
112         if (type_devino != type) {
113             /* same dev:inode but not same type one is a folder the other 
114              * is a file,it's an inode reused, delete the record
115             */
116             if (cnid_cdb_delete(cdb, id) < 0) {
117                 return 0;
118             }
119         }
120         else {
121             update = 1;
122         }
123     }
124     if (!update) {
125         return 0;
126     }
127     /* Fix up the database. assume it was a file move and rename */
128     cnid_cdb_update(cdb, id, st, did, name, len);
129
130 #ifdef DEBUG
131     LOG(log_debug9, logtype_default, "cnid_lookup: Looked up did %u, name %s, as %u (needed update)", ntohl(did), name, ntohl(id));
132 #endif
133     return id;
134 }
135
136 #endif /* CNID_BACKEND_CDB */