]> arthur.barton.de Git - netatalk.git/blob - libatalk/cnid/tdb/cnid_tdb_add.c
update tdb to use the same format as dbd/cdb, still broken (exchangefile)
[netatalk.git] / libatalk / cnid / tdb / cnid_tdb_add.c
1 /*
2  * $Id: cnid_tdb_add.c,v 1.4 2009-11-20 17:37:14 didg Exp $
3  *
4  * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
5  * All Rights Reserved. See COPYRIGHT.
6  *
7  */
8
9 #ifdef HAVE_CONFIG_H
10 #include "config.h"
11 #endif
12
13 #ifdef CNID_BACKEND_TDB
14 #include "cnid_tdb.h"
15 #include <atalk/util.h>
16 #include <sys/param.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <unistd.h>
20 #include <atalk/logger.h>
21
22 static void make_devino_data(unsigned char *buf, dev_t dev, ino_t ino)
23 {
24     buf[CNID_DEV_LEN - 1] = dev; dev >>= 8;
25     buf[CNID_DEV_LEN - 2] = dev; dev >>= 8;
26     buf[CNID_DEV_LEN - 3] = dev; dev >>= 8;
27     buf[CNID_DEV_LEN - 4] = dev; dev >>= 8;
28     buf[CNID_DEV_LEN - 5] = dev; dev >>= 8;
29     buf[CNID_DEV_LEN - 6] = dev; dev >>= 8;
30     buf[CNID_DEV_LEN - 7] = dev; dev >>= 8;
31     buf[CNID_DEV_LEN - 8] = dev;
32
33     buf[CNID_DEV_LEN + CNID_INO_LEN - 1] = ino; ino >>= 8;
34     buf[CNID_DEV_LEN + CNID_INO_LEN - 2] = ino; ino >>= 8;
35     buf[CNID_DEV_LEN + CNID_INO_LEN - 3] = ino; ino >>= 8;
36     buf[CNID_DEV_LEN + CNID_INO_LEN - 4] = ino; ino >>= 8;
37     buf[CNID_DEV_LEN + CNID_INO_LEN - 5] = ino; ino >>= 8;
38     buf[CNID_DEV_LEN + CNID_INO_LEN - 6] = ino; ino >>= 8;
39     buf[CNID_DEV_LEN + CNID_INO_LEN - 7] = ino; ino >>= 8;
40     buf[CNID_DEV_LEN + CNID_INO_LEN - 8] = ino;    
41 }
42
43 unsigned char *make_tdb_data(u_int32_t flags, const struct stat *st,const cnid_t did,
44                      const char *name, const size_t len)
45 {
46     static unsigned char start[CNID_HEADER_LEN + MAXPATHLEN + 1];
47     unsigned char *buf = start  +CNID_LEN;
48     u_int32_t i;
49
50     if (len > MAXPATHLEN)
51         return NULL;
52
53     make_devino_data(buf, !(flags & CNID_FLAG_NODEV)?st->st_dev:0, st->st_ino);
54     buf += CNID_DEVINO_LEN;
55
56     i = S_ISDIR(st->st_mode)?1:0;
57     i = htonl(i);
58     memcpy(buf, &i, sizeof(i));
59     buf += sizeof(i);
60     
61     /* did is already in network byte order */
62     memcpy(buf, &did, sizeof(did));
63     buf += sizeof(did);
64
65     memcpy(buf, name, len);
66     *(buf + len) = '\0';
67
68     return start;
69 }    
70
71 /* add an entry to the CNID databases. we do this as a transaction
72  * to prevent messiness. 
73  * key:   cnid
74  * data:
75  */
76 static int add_cnid (struct _cnid_tdb_private *db, TDB_DATA *key, TDB_DATA *data) {
77     TDB_DATA altkey, altdata;
78
79     memset(&altkey, 0, sizeof(altkey));
80     memset(&altdata, 0, sizeof(altdata));
81
82
83     /* main database */
84     if (tdb_store(db->tdb_cnid, *key, *data, TDB_REPLACE)) {
85         goto abort;
86     }
87
88     /* dev/ino database */
89     altkey.dptr = data->dptr +CNID_DEVINO_OFS;
90     altkey.dsize = CNID_DEVINO_LEN;
91     altdata.dptr = key->dptr;
92     altdata.dsize = key->dsize;
93     if (tdb_store(db->tdb_devino, altkey, altdata, TDB_REPLACE)) {
94         goto abort;
95     }
96
97     /* did/name database */
98     altkey.dptr = (char *) data->dptr +CNID_DID_OFS;
99     altkey.dsize = data->dsize -CNID_DID_OFS;
100     if (tdb_store(db->tdb_didname, altkey, altdata, TDB_REPLACE)) {
101         goto abort;
102     }
103     return 0;
104
105 abort:
106     return -1;
107 }
108
109 /* ----------------------- */
110 static cnid_t get_cnid(struct _cnid_tdb_private *db)
111 {
112     TDB_DATA rootinfo_key, data;
113     cnid_t hint,id;
114     
115     memset(&rootinfo_key, 0, sizeof(rootinfo_key));
116     memset(&data, 0, sizeof(data));
117     rootinfo_key.dptr = ROOTINFO_KEY;
118     rootinfo_key.dsize = ROOTINFO_KEYLEN;
119     
120     tdb_chainlock(db->tdb_didname, rootinfo_key);  
121     data = tdb_fetch(db->tdb_didname, rootinfo_key);
122     if (data.dptr)
123     {
124         memcpy(&hint, data.dptr, sizeof(cnid_t));
125         free(data.dptr);
126         id = ntohl(hint);
127         /* If we've hit the max CNID allowed, we return a fatal error.  CNID
128          * needs to be recycled before proceding. */
129         if (++id == CNID_INVALID) {
130             LOG(log_error, logtype_default, "cnid_add: FATAL: CNID database has reached its limit.");
131             errno = CNID_ERR_MAX;
132             goto cleanup;
133         }
134         hint = htonl(id);
135     }
136     else {
137         hint = htonl(CNID_START);
138     }
139     
140     memset(&data, 0, sizeof(data));
141     data.dptr = (char *)&hint;
142     data.dsize = sizeof(hint);
143     if (tdb_store(db->tdb_didname, rootinfo_key, data, TDB_REPLACE)) {
144         goto cleanup;
145     }
146
147     tdb_chainunlock(db->tdb_didname, rootinfo_key );  
148     return hint;
149 cleanup:
150     tdb_chainunlock(db->tdb_didname, rootinfo_key);  
151     return CNID_INVALID;
152 }
153
154
155 /* ------------------------ */
156 cnid_t cnid_tdb_add(struct _cnid_db *cdb, const struct stat *st,
157                      const cnid_t did, char *name, const size_t len, cnid_t hint)
158 {
159     const struct stat *lstp;
160     cnid_t id;
161     struct _cnid_tdb_private *priv;
162     TDB_DATA key, data; 
163     int rc;      
164     
165     if (!cdb || !(priv = cdb->_private) || !st || !name) {
166         errno = CNID_ERR_PARAM;
167         return CNID_INVALID;
168     }
169     /* Do a lookup. */
170     id = cnid_tdb_lookup(cdb, st, did, name, len);
171     /* ... Return id if it is valid, or if Rootinfo is read-only. */
172     if (id || (priv->flags & CNIDFLAG_DB_RO)) {
173         return id;
174     }
175
176 #if 0
177     struct stat lst;
178     lstp = lstat(name, &lst) < 0 ? st : &lst;
179 #endif
180     lstp = st;
181
182     /* Initialize our DBT data structures. */
183     memset(&key, 0, sizeof(key));
184     memset(&data, 0, sizeof(data));
185
186     key.dptr = (char *)&hint;
187     key.dsize = sizeof(cnid_t);
188     if ((data.dptr = make_tdb_data(cdb->flags, lstp, did, name, len)) == NULL) {
189         LOG(log_error, logtype_default, "tdb_add: Path name is too long");
190         errno = CNID_ERR_PATH;
191         return CNID_INVALID;
192     }
193     data.dsize = CNID_HEADER_LEN + len + 1;
194     hint = get_cnid(priv);
195     if (hint == 0) {
196         errno = CNID_ERR_DB;
197         return CNID_INVALID;
198     }
199     memcpy(data.dptr, &hint, sizeof(hint));
200     
201     /* Now we need to add the CNID data to the databases. */
202     rc = add_cnid(priv, &key, &data);
203     if (rc) {
204         LOG(log_error, logtype_default, "tdb_add: Failed to add CNID for %s to database using hint %u", name, ntohl(hint));
205         errno = CNID_ERR_DB;
206         return CNID_INVALID;
207     }
208
209     return hint;
210 }
211
212 #endif