]> arthur.barton.de Git - netatalk.git/blob - libatalk/cnid/cnid_update.c
Fix a bunch of problems with database contention and corruption. Note:
[netatalk.git] / libatalk / cnid / cnid_update.c
1 /*
2  * $Id: cnid_update.c,v 1.8 2001-09-21 15:08:37 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 <syslog.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
25 /* cnid_update: takes the given cnid and updates the metadata. to
26    handle the did/name data, there are a bunch of functions to get
27    and set the various fields. */
28 int cnid_update(void *CNID, const cnid_t id, const struct stat *st,
29                 const cnid_t did, const char *name, const int len/*,
30                 const char *info, const int infolen*/)
31 {
32   CNID_private *db;
33   DBT key, data, altdata;
34   DB_TXN *tid;
35   int rc = 0;
36   
37   if (!(db = CNID) || !id || !st || !name || (db->flags & CNIDFLAG_DB_RO))
38     return -1;
39
40   memset(&key, 0, sizeof(key));
41   memset(&data, 0, sizeof(data));
42   memset(&altdata, 0, sizeof(altdata));
43
44   /* begin a transaction */
45 retry:
46   if ((rc = txn_begin(db->dbenv, NULL, &tid, 0))) {
47         syslog(LOG_ERR, "cnid_update: txn_begin failed with: %d", rc);
48     return rc;
49   }
50
51   /* get the old info */
52   key.data = (cnid_t *) &id;
53   key.size = sizeof(id);
54   if ((rc = db->db_cnid->get(db->db_cnid, tid, &key, &data, 0))) {
55     txn_abort(tid);
56     if (rc == DB_LOCK_DEADLOCK)
57       goto retry;
58     goto update_err;
59   }
60
61   /* delete the old dev/ino mapping */
62   key.data = data.data;
63   key.size = CNID_DEVINO_LEN;
64   if ((rc = db->db_devino->del(db->db_devino, tid, &key, 0))) {
65     if (rc == DB_LOCK_DEADLOCK) {
66       txn_abort(tid);
67       goto retry;
68     }
69
70     /* silently fail on a non-existent entry */
71     if (rc != DB_NOTFOUND) {
72       txn_abort(tid);
73       goto update_err;
74     }
75   }
76
77   /* delete the old did/name mapping */
78   key.data = (char *) data.data + CNID_DEVINO_LEN;
79   key.size = data.size - CNID_DEVINO_LEN;
80   if ((rc = db->db_didname->del(db->db_didname, tid, &key, 0))) {
81     if (rc == DB_LOCK_DEADLOCK) {
82       txn_abort(tid);
83       goto retry;
84     }
85
86     /* silently fail on a non-existent entry */
87     if (rc != DB_NOTFOUND) {
88       txn_abort(tid);
89       goto update_err;
90     }
91   }
92
93   /* delete the old aliases if necessary */
94
95
96   /* make a new entry */
97   data.data = make_cnid_data(st, did, name, len);
98   data.size = CNID_HEADER_LEN + len + 1;
99
100   /* put a new dev/ino mapping in */
101   key.data = data.data;
102   key.size = CNID_DEVINO_LEN;
103   altdata.data = (cnid_t *) &id;
104   altdata.size = sizeof(id);
105   if ((rc = db->db_devino->put(db->db_devino, tid, &key, &altdata, 0))) {
106     txn_abort(tid);
107     if (rc == DB_LOCK_DEADLOCK) {
108       goto retry;
109     }
110     goto update_err;
111   }
112
113   /* put a new did/name mapping in */
114   key.data = (char *) data.data + CNID_DEVINO_LEN;
115   key.size = data.size - CNID_DEVINO_LEN;
116   if ((rc = db->db_didname->put(db->db_didname, tid, &key, &altdata, 0))) {
117     txn_abort(tid);
118     if (rc == DB_LOCK_DEADLOCK) {
119       goto retry;
120     }
121     goto update_err;
122   }
123
124   /* update the old CNID with the new info */
125   key.data = (cnid_t *) &id;
126   key.size = sizeof(id);
127   if ((rc = db->db_cnid->put(db->db_cnid, tid, &key, &data, 0))) {
128     txn_abort(tid);
129     if (rc == DB_LOCK_DEADLOCK) {
130       goto retry;
131     }
132     goto update_err;
133   }
134
135   /* end transaction */
136   return txn_commit(tid, 0);
137
138 update_err:
139   syslog(LOG_ERR, "cnid_update: can't update CNID(%x)", id);
140   return -1;
141 }
142 #endif /* CNID_DB */