]> arthur.barton.de Git - netatalk.git/blob - libatalk/cnid/cnid_update.c
1c7a021733e32e2d8a25be6c87c76fb0c365034b
[netatalk.git] / libatalk / cnid / cnid_update.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <sys/param.h>
4 #include <sys/stat.h>
5 #include <errno.h>
6 #include <syslog.h>
7
8 #include <db.h>
9 #include <netatalk/endian.h>
10 #include <atalk/adouble.h>
11 #include <atalk/cnid.h>
12
13 #include "cnid_private.h"
14
15
16 /* cnid_update: takes the given cnid and updates the metadata. to
17    handle the did/name data, there are a bunch of functions to get
18    and set the various fields. */
19 int cnid_update(void *CNID, cnid_t id, const struct stat *st, 
20                 const cnid_t did, const char *name, const int len,
21                 const char *info, const int infolen)
22 {
23   CNID_private *db;
24   DBT key, data, altdata;
25   DB_TXN *tid;
26   DB_TXNMGR *txnp;
27   
28   if (!(db = CNID) || !id || !st || !name || (db->flags & CNIDFLAG_DB_RO))
29     return -1;
30
31   memset(&key, 0, sizeof(key));
32   memset(&data, 0, sizeof(data));
33   memset(&altdata, 0, sizeof(altdata));
34   txnp = db->dbenv.tx_info;
35
36   /* begin a transaction */
37 retry:
38   if (errno = txn_begin(txnp, NULL, &tid)) {
39     return errno;
40   }
41
42   /* get the old info */
43   key.data = &id;
44   key.size = sizeof(id);
45   if (errno = db->db_cnid->get(db->db_cnid, tid, &key, &data, 0)) {
46     txn_abort(tid);
47     if (errno == EAGAIN)
48       goto retry;
49     goto update_err;
50   }
51
52   /* delete the old dev/ino mapping */
53   key.data = data.data;
54   key.size = CNID_DEVINO_LEN;
55   if (errno = db->db_devino->del(db->db_devino, tid, &key, 0)) {
56     if (errno == EAGAIN) {
57       txn_abort(tid);
58       goto retry;
59     }
60       
61     /* silently fail on a non-existent entry */
62     if (errno != DB_NOTFOUND) {
63       txn_abort(tid);
64       goto update_err;
65     }
66   }
67
68   /* delete the old did/name mapping */
69   key.data = data.data + CNID_DEVINO_LEN;
70   key.size = data.size - CNID_DEVINO_LEN;
71   if (errno = db->db_didname->del(db->db_didname, tid, &key, 0)) {
72     if (errno == EAGAIN) {
73       txn_abort(tid);
74       goto retry;
75     }
76
77     /* silently fail on a non-existent entry */
78     if (errno != DB_NOTFOUND) {
79       txn_abort(tid);
80       goto update_err;
81     }
82   }
83   
84   /* delete the old aliases if necessary */
85
86
87   /* make a new entry */
88   data.data = make_cnid_data(st, did, name, len);
89   data.size = CNID_HEADER_LEN + len + 1;
90   
91   /* put a new dev/ino mapping in */
92   key.data = data.data;
93   key.size = CNID_DEVINO_LEN;
94   altdata.data = &id;
95   altdata.size = sizeof(id);
96   if (errno = db->db_devino->put(db->db_devino, tid, &key, &altdata, 0)) {
97     txn_abort(tid);
98     if (errno == EAGAIN) {
99       goto retry;
100     }
101     goto update_err;
102   }
103   
104   /* put a new did/name mapping in */
105   key.data = data.data + CNID_DEVINO_LEN;
106   key.size = data.size - CNID_DEVINO_LEN;
107   if (errno = db->db_didname->put(db->db_didname, tid, &key, &altdata, 0)) {
108     txn_abort(tid);
109     if (errno == EAGAIN) {
110       goto retry;
111     }
112     goto update_err;
113   }
114   
115   /* update the old CNID with the new info */
116   key.data = &id;
117   key.size = sizeof(id);
118   if (errno = db->db_cnid->put(db->db_cnid, tid, &key, &data, 0)) {
119     txn_abort(tid);
120     if (errno == EAGAIN) {
121       goto retry;
122     }
123     goto update_err;
124   }
125   
126   /* end transaction */
127   return txn_commit(tid);
128
129 update_err:
130   syslog(LOG_ERR, "cnid_update: can't update CNID(%x)", id);
131   return -1;
132 }