]> arthur.barton.de Git - netatalk.git/blob - libatalk/cnid/tdb/cnid_tdb_add.c
407424dfb535fae3fa71ce2ab589d8b0050ff336
[netatalk.git] / libatalk / cnid / tdb / cnid_tdb_add.c
1 /*
2  * $Id: cnid_tdb_add.c,v 1.1.2.1 2003-09-09 16:42:21 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 /* add an entry to the CNID databases. we do this as a transaction
23  * to prevent messiness. */
24
25 static int add_cnid (struct _cnid_tdb_private *db, TDB_DATA *key, TDB_DATA *data) {
26     TDB_DATA altkey, altdata;
27     int rc;
28
29     memset(&altkey, 0, sizeof(altkey));
30     memset(&altdata, 0, sizeof(altdata));
31
32
33     /* main database */
34     if (tdb_store(db->tdb_cnid, *key, *data, TDB_REPLACE)) {
35         goto abort;
36     }
37
38     /* dev/ino database */
39     altkey.dptr = data->dptr;
40     altkey.dsize = TDB_DEVINO_LEN;
41     altdata.dptr = key->dptr;
42     altdata.dsize = key->dsize;
43     if (tdb_store(db->tdb_devino, altkey, altdata, TDB_REPLACE)) {
44         goto abort;
45     }
46
47     /* did/name database */
48     altkey.dptr = (char *) data->dptr + TDB_DEVINO_LEN;
49     altkey.dsize = data->dsize - TDB_DEVINO_LEN;
50     if (tdb_store(db->tdb_didname, altkey, altdata, TDB_REPLACE)) {
51         goto abort;
52     }
53     return 0;
54
55 abort:
56     return rc;
57 }
58
59 /* ----------------------- */
60 static cnid_t get_cnid(struct _cnid_tdb_private *db)
61 {
62     TDB_DATA rootinfo_key, data;
63     cnid_t hint,id;
64     
65     memset(&rootinfo_key, 0, sizeof(rootinfo_key));
66     memset(&data, 0, sizeof(data));
67     rootinfo_key.dptr = ROOTINFO_KEY;
68     rootinfo_key.dsize = ROOTINFO_KEYLEN;
69     
70     tdb_chainlock(db->tdb_didname, rootinfo_key);  
71     data = tdb_fetch(db->tdb_didname, rootinfo_key);
72     if (data.dptr)
73     {
74         memcpy(&hint, data.dptr, sizeof(cnid_t));
75         free(data.dptr);
76         id = ntohl(hint);
77         /* If we've hit the max CNID allowed, we return a fatal error.  CNID
78          * needs to be recycled before proceding. */
79         if (++id == CNID_INVALID) {
80             LOG(log_error, logtype_default, "cnid_add: FATAL: CNID database has reached its limit.");
81             errno = CNID_ERR_MAX;
82             goto cleanup;
83         }
84         hint = htonl(id);
85     }
86     else {
87         hint = htonl(TDB_START);
88     }
89     
90     memset(&data, 0, sizeof(data));
91     data.dptr = (char *)&hint;
92     data.dsize = sizeof(hint);
93     if (tdb_store(db->tdb_didname, rootinfo_key, data, TDB_REPLACE)) {
94         goto cleanup;
95     }
96
97     tdb_chainunlock(db->tdb_didname, rootinfo_key );  
98     return hint;
99 cleanup:
100     tdb_chainunlock(db->tdb_didname, rootinfo_key);  
101     return CNID_INVALID;
102 }
103
104
105 /* ------------------------ */
106 cnid_t cnid_tdb_add(struct _cnid_db *cdb, const struct stat *st,
107                      const cnid_t did, const char *name, const int len, cnid_t hint)
108 {
109     const struct stat *lstp;
110     cnid_t id;
111     struct _cnid_tdb_private *priv;
112     TDB_DATA key, data; 
113     int rc;      
114     
115     if (!cdb || !(priv = cdb->_private) || !st || !name) {
116         errno = CNID_ERR_PARAM;
117         return CNID_INVALID;
118     }
119     /* Do a lookup. */
120     id = cnid_tdb_lookup(cdb, st, did, name, len);
121     /* ... Return id if it is valid, or if Rootinfo is read-only. */
122     if (id || (priv->flags & TDBFLAG_DB_RO)) {
123         return id;
124     }
125
126 #if 0
127     struct stat lst;
128     lstp = lstat(name, &lst) < 0 ? st : &lst;
129 #endif
130     lstp = st;
131
132     /* Initialize our DBT data structures. */
133     memset(&key, 0, sizeof(key));
134     memset(&data, 0, sizeof(data));
135
136     key.dptr = (char *)&hint;
137     key.dsize = sizeof(cnid_t);
138     if ((data.dptr = make_tdb_data(lstp, did, name, len)) == NULL) {
139         LOG(log_error, logtype_default, "tdb_add: Path name is too long");
140         errno = CNID_ERR_PATH;
141         return CNID_INVALID;
142     }
143     data.dsize = TDB_HEADER_LEN + len + 1;
144     hint = get_cnid(priv);
145     if (hint == 0) {
146         errno = CNID_ERR_DB;
147         return CNID_INVALID;
148     }
149     
150     /* Now we need to add the CNID data to the databases. */
151     rc = add_cnid(priv, &key, &data);
152     if (rc) {
153         LOG(log_error, logtype_default, "tdb_add: Failed to add CNID for %s to database using hint %u", name, ntohl(hint));
154         errno = CNID_ERR_DB;
155         return CNID_INVALID;
156     }
157
158     return hint;
159 }
160
161 #endif