]> arthur.barton.de Git - netatalk.git/blob - libatalk/cnid/cnid_update.c
c635d2471b347335e6e652148c261852d5f922c1
[netatalk.git] / libatalk / cnid / cnid_update.c
1 /*
2  * $Id: cnid_update.c,v 1.19 2002-01-24 16:46:53 jmarcus Exp $
3  */
4
5 #ifdef HAVE_CONFIG_H
6 #include "config.h"
7 #endif /* HAVE_CONFIG_H */
8
9 #ifdef CNID_DB
10 #include <stdio.h>
11 #include <string.h>
12 #include <sys/param.h>
13 #include <sys/stat.h>
14 #include <errno.h>
15 #include <atalk/logger.h>
16
17 #include <db.h>
18 #include <netatalk/endian.h>
19 #include <atalk/adouble.h>
20 #include <atalk/cnid.h>
21
22 #include "cnid_private.h"
23
24 /* cnid_update: takes the given cnid and updates the metadata.  To
25  * handle the did/name data, there are a bunch of functions to get
26  * and set the various fields. */
27 int cnid_update(void *CNID, const cnid_t id, const struct stat *st,
28                 const cnid_t did, const char *name, const int len
29                 /*, const char *info, const int infolen*/)
30 {
31     CNID_private *db;
32     DBT key, data, altdata;
33     DB_TXN *tid;
34     int rc;
35
36     if (!(db = CNID) || !id || !st || !name || (db->flags & CNIDFLAG_DB_RO)) {
37         return -1;
38     }
39
40     memset(&key, 0, sizeof(key));
41     memset(&altdata, 0, sizeof(altdata));
42
43 retry:
44     if ((rc = txn_begin(db->dbenv, NULL, &tid, 0))) {
45         LOG(log_error, logtype_default, "cnid_update: Failed to begin transaction: %s", db_strerror(rc));
46         return rc;
47     }
48
49     /* Get the old info. */
50     key.data = (cnid_t *)&id;
51     key.size = sizeof(id);
52     memset(&data, 0, sizeof(data));
53     if ((rc = db->db_cnid->get(db->db_cnid, tid, &key, &data, DB_RMW))) {
54         txn_abort(tid);
55         switch (rc) {
56         case DB_LOCK_DEADLOCK:
57             goto retry;
58         case DB_NOTFOUND:
59             /* Silently fail here.  We're allowed to do this since this CNID
60              * might have been deleted out from under us, or someone has
61              * called cnid_lookup then cnid_update (which is redundant). */
62             return 0;
63         default:
64             goto update_err;
65         }
66     }
67
68     /* Delete the old dev/ino mapping. */
69     key.data = data.data;
70     key.size = CNID_DEVINO_LEN;
71     if ((rc = db->db_devino->del(db->db_devino, tid, &key, 0))) {
72         switch (rc) {
73         case DB_LOCK_DEADLOCK:
74             txn_abort(tid);
75             goto retry;
76         case DB_NOTFOUND:
77             break;
78         default:
79             txn_abort(tid);
80             goto update_err;
81         }
82     }
83
84     /* Delete the old did/name mapping. */
85     key.data = (char *) data.data + CNID_DEVINO_LEN;
86     key.size = data.size - CNID_DEVINO_LEN;
87     if ((rc = db->db_didname->del(db->db_didname, tid, &key, 0))) {
88         switch (rc) {
89         case DB_LOCK_DEADLOCK:
90             txn_abort(tid);
91             goto retry;
92         case DB_NOTFOUND:
93             break;
94         default:
95             txn_abort(tid);
96             goto update_err;
97         }
98     }
99
100     /* Make a new entry. */
101     data.data = make_cnid_data(st, did, name, len);
102     data.size = CNID_HEADER_LEN + len + 1;
103
104     /* Update the old CNID with the new info. */
105     key.data = (cnid_t *) &id;
106     key.size = sizeof(id);
107     if ((rc = db->db_cnid->put(db->db_cnid, tid, &key, &data, 0))) {
108         txn_abort(tid);
109         switch (rc) {
110         case DB_LOCK_DEADLOCK:
111             goto retry;
112         default:
113             goto update_err;
114         }
115     }
116
117     /* Put in a new dev/ino mapping. */
118     key.data = data.data;
119     key.size = CNID_DEVINO_LEN;
120     altdata.data = (cnid_t *) &id;
121     altdata.size = sizeof(id);
122     if ((rc = db->db_devino->put(db->db_devino, tid, &key, &altdata, 0))) {
123         txn_abort(tid);
124         switch (rc) {
125         case DB_LOCK_DEADLOCK:
126             goto retry;
127         default:
128             goto update_err;
129         }
130     }
131
132     /* put in a new did/name mapping. */
133     key.data = (char *) data.data + CNID_DEVINO_LEN;
134     key.size = data.size - CNID_DEVINO_LEN;
135     if ((rc = db->db_didname->put(db->db_didname, tid, &key, &altdata, 0))) {
136         txn_abort(tid);
137         switch (rc) {
138         case DB_LOCK_DEADLOCK:
139             goto retry;
140         default:
141             goto update_err;
142         }
143     }
144
145
146     return txn_commit(tid, 0);
147
148 update_err:
149     LOG(log_error, logtype_default, "cnid_update: Unable to update CNID %u: %s",
150         ntohl(id), db_strerror(rc));
151     return -1;
152 }
153 #endif /* CNID_DB */