]> arthur.barton.de Git - netatalk.git/blob - libatalk/cnid/tdb/cnid_tdb_lookup.c
c95631afee52574c292cb0534b85b6a407cc6e0f
[netatalk.git] / libatalk / cnid / tdb / cnid_tdb_lookup.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #ifdef CNID_BACKEND_TDB
6
7 #include "cnid_tdb.h"
8 #include <atalk/logger.h>
9
10 cnid_t cnid_tdb_lookup(struct _cnid_db *cdb, const struct stat *st, cnid_t did, const char *name, size_t len)
11 {
12     char *buf;
13     struct _cnid_tdb_private *db;
14     TDB_DATA key, devdata, diddata, cniddata;
15     int devino = 1, didname = 1;
16     char dev[CNID_DEV_LEN];
17     char ino[CNID_INO_LEN];  
18     uint32_t type_devino  = (unsigned)-1;
19     uint32_t type_didname = (unsigned)-1;
20     uint32_t type;
21     int update = 0;
22     cnid_t id_devino = 0, id_didname = 0,id = 0;
23
24     if (!cdb || !(db = cdb->_private) || !st || !name) {
25         return 0;
26     }
27
28     if ((buf = (char *)make_tdb_data(cdb->flags, st, did, name, len)) == NULL) {
29         LOG(log_error, logtype_default, "tdb_lookup: Pathname is too long");
30         return 0;
31     }
32     memcpy(&type, buf +CNID_TYPE_OFS, sizeof(type));
33     type = ntohl(type);
34
35     memset(&key, 0, sizeof(key));
36     memset(&devdata, 0, sizeof(devdata));
37     memset(&diddata, 0, sizeof(diddata));
38     memset(&cniddata, 0, sizeof(cniddata));
39
40     /* Look for a CNID.  We have two options: dev/ino or did/name.  If we
41     * only get a match in one of them, that means a file has moved. */
42     memcpy(dev, buf + CNID_DEV_OFS, CNID_DEV_LEN);
43     memcpy(ino, buf + CNID_INO_OFS, CNID_INO_LEN);
44
45     key.dptr = (unsigned char *)buf + CNID_DEVINO_OFS;
46     key.dsize  = CNID_DEVINO_LEN;
47     cniddata = tdb_fetch(db->tdb_devino, key);
48     if (!cniddata.dptr) {
49          devino = 0;
50     }
51     else {
52         
53         key.dptr = cniddata.dptr;
54         key.dsize = sizeof(id);
55
56         devdata = tdb_fetch(db->tdb_cnid, key);
57         free(cniddata.dptr);
58         if (devdata.dptr) {
59             memcpy(&id_devino, devdata.dptr, sizeof(cnid_t));
60             memcpy(&type_devino, (char *)devdata.dptr +CNID_TYPE_OFS, sizeof(type_devino));
61             type_devino = ntohl(type_devino);
62         }
63         else {
64              devino = 0;
65         }
66     }
67
68     /* did/name now */
69     key.dptr = (unsigned char *)buf + CNID_DID_OFS;
70     key.dsize = CNID_DID_LEN + len + 1;
71     cniddata = tdb_fetch(db->tdb_didname, key);
72     if (!cniddata.dptr) {
73         didname = 0;
74     }
75     else {
76         
77         key.dptr = cniddata.dptr;
78         key.dsize = sizeof(id);
79
80         diddata = tdb_fetch(db->tdb_cnid, key);
81         free(cniddata.dptr);
82         if (diddata.dptr) {
83             memcpy(&id_didname, diddata.dptr, sizeof(cnid_t));
84             memcpy(&type_didname, (char *)diddata.dptr +CNID_TYPE_OFS, sizeof(type_didname));
85             type_didname = ntohl(type_didname);
86         }
87         else {
88              didname = 0;
89         }
90     }
91     /* Set id.  Honor did/name over dev/ino as dev/ino isn't necessarily
92      * 1-1. */
93     if (!devino && !didname) {  
94         free(devdata.dptr);
95         free(diddata.dptr);
96         return 0;
97     }
98
99     if (devino && didname && id_devino == id_didname && type_devino == type) {
100         /* the same */
101         free(devdata.dptr);
102         free(diddata.dptr);
103         return id_didname;
104     }
105  
106     if (didname) {
107         id = id_didname;
108         /* we have a did:name 
109          * if it's the same dev or not the same type
110          * just delete it
111         */
112         if (!memcmp(dev, (char *)diddata.dptr + CNID_DEV_OFS, CNID_DEV_LEN) ||
113                    type_didname != type) {
114             if (cnid_tdb_delete(cdb, id) < 0) {
115                 free(devdata.dptr);
116                 free(diddata.dptr);
117                 return 0;
118             }
119         }
120         else {
121             update = 1;
122         }
123     }
124
125     if (devino) {
126         id = id_devino;
127         if (type_devino != type) {
128             /* same dev:inode but not same type one is a folder the other 
129              * is a file,it's an inode reused, delete the record
130             */
131             if (cnid_tdb_delete(cdb, id) < 0) {
132                 free(devdata.dptr);
133                 free(diddata.dptr);
134                 return 0;
135             }
136         }
137         else {
138             update = 1;
139         }
140     }
141     free(devdata.dptr);
142     free(diddata.dptr);
143     if (!update) {
144         return 0;
145     }
146
147     /* Fix up the database. */
148     cnid_tdb_update(cdb, id, st, did, name, len);
149     return id;
150 }
151
152 #endif