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