]> arthur.barton.de Git - netatalk.git/blob - libatalk/cnid/dbd/cnid_dbd.c
Whitespace and exclamation mark fixes
[netatalk.git] / libatalk / cnid / dbd / cnid_dbd.c
1 /*
2  * Copyright (C) Joerg Lenneis 2003
3  * Copyright (C) Frank Lahm 2010
4  * All Rights Reserved.  See COPYING.
5  */
6
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif /* HAVE_CONFIG_H */
10
11 #ifdef CNID_BACKEND_DBD
12
13 #include <stdlib.h>
14 #include <sys/stat.h>
15 #include <sys/uio.h>
16 #include <sys/time.h>
17 #include <sys/un.h>
18 #include <sys/socket.h>
19 #include <sys/param.h>
20 #include <errno.h>
21 #include <netinet/in.h>
22 #include <net/if.h>
23 #include <netinet/tcp.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <errno.h>
27 #include <netdb.h>
28 #include <time.h>
29 #include <arpa/inet.h>
30
31 #include <atalk/logger.h>
32 #include <atalk/adouble.h>
33 #include <atalk/cnid.h>
34 #include <atalk/cnid_bdb_private.h>
35 #include <atalk/util.h>
36 #include <atalk/volume.h>
37
38 #include "cnid_dbd.h"
39
40 #ifndef SOL_TCP
41 #define SOL_TCP IPPROTO_TCP
42 #endif /* ! SOL_TCP */
43
44 /* Wait MAX_DELAY seconds before a request to the CNID server times out */
45 #define MAX_DELAY 20
46 #define ONE_DELAY 5
47
48 static void RQST_RESET(struct cnid_dbd_rqst  *r)
49 {
50     memset(r, 0, sizeof(struct cnid_dbd_rqst ));
51 }
52
53 static void delay(int sec)
54 {
55     struct timeval tv;
56
57     tv.tv_usec = 0;
58     tv.tv_sec  = sec;
59     select(0, NULL, NULL, NULL, &tv);
60 }
61
62 static int tsock_getfd(const char *host, const char *port)
63 {
64     int sock = -1;
65     int attr;
66     int err;
67     struct addrinfo hints, *servinfo, *p;
68     int optval;
69     socklen_t optlen = sizeof(optval);
70
71     /* Prepare hint for getaddrinfo */
72     memset(&hints, 0, sizeof hints);
73     hints.ai_family = AF_UNSPEC;
74     hints.ai_socktype = SOCK_STREAM;
75 #ifdef AI_NUMERICSERV
76     hints.ai_flags = AI_NUMERICSERV;
77 #endif
78
79     if ((err = getaddrinfo(host, port, &hints, &servinfo)) != 0) {
80         LOG(log_error, logtype_default, "tsock_getfd: getaddrinfo: CNID server %s:%s : %s\n",
81             host, port, gai_strerror(err));
82         return -1;
83     }
84
85     /* loop through all the results and bind to the first we can */
86     for (p = servinfo; p != NULL; p = p->ai_next) {
87         if ((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
88             LOG(log_info, logtype_default, "tsock_getfd: socket CNID server %s:: %s",
89                 host, strerror(errno));
90             continue;
91         }
92
93         attr = 1;
94         if (setsockopt(sock, SOL_TCP, TCP_NODELAY, &attr, sizeof(attr)) == -1) {
95             LOG(log_error, logtype_cnid, "getfd: set TCP_NODELAY CNID server %s: %s",
96                 host, strerror(errno));
97             close(sock);
98             sock = -1;
99             return -1;
100         }
101
102         if (setnonblock(sock, 1) != 0) {
103             LOG(log_error, logtype_cnid, "getfd: setnonblock: %s", strerror(errno));
104             close(sock);
105             sock = -1;
106             return -1;
107         }
108
109         if (connect(sock, p->ai_addr, p->ai_addrlen) == -1) {
110             if (errno == EINPROGRESS) {
111                 struct timeval tv;
112                 tv.tv_usec = 0;
113                 tv.tv_sec  = 5; /* give it five seconds ... */
114                 fd_set wfds;
115                 FD_ZERO(&wfds);
116                 FD_SET(sock, &wfds);
117
118                 if ((err = select(sock + 1, NULL, &wfds, NULL, &tv)) == 0) {
119                     /* timeout */
120                     LOG(log_error, logtype_cnid, "getfd: select timed out for CNID server %s",
121                         host);
122                     close(sock);
123                     sock = -1;
124                     continue;
125                 }
126                 if (err == -1) {
127                     /* select failed */
128                     LOG(log_error, logtype_cnid, "getfd: select failed for CNID server %s",
129                         host);
130                     close(sock);
131                     sock = -1;
132                     continue;
133                 }
134
135                 if ( ! FD_ISSET(sock, &wfds)) {
136                     /* give up */
137                     LOG(log_error, logtype_cnid, "getfd: socket not ready connecting to %s",
138                         host);
139                     close(sock);
140                     sock = -1;
141                     continue;
142                 }
143
144                 if ((err = getsockopt(sock, SOL_SOCKET, SO_ERROR, &optval, &optlen)) != 0 || optval != 0) {
145                     if (err != 0) {
146                         /* somethings very wrong */
147                         LOG(log_error, logtype_cnid, "getfd: getsockopt error with CNID server %s: %s",
148                             host, strerror(errno));
149                     } else {
150                         errno = optval;
151                         LOG(log_error, logtype_cnid, "getfd: getsockopt says: %s",
152                             strerror(errno));
153                     }
154                     close(sock);
155                     sock = -1;
156                     continue;
157                 }
158             } else {
159                 LOG(log_error, logtype_cnid, "getfd: connect CNID server %s: %s",
160                     host, strerror(errno));
161                 close(sock);
162                 sock = -1;
163                 continue;
164             }
165         }
166
167         /* We've got a socket */
168         break;
169     }
170
171     freeaddrinfo(servinfo);
172
173     if (p == NULL) {
174         errno = optval;
175         LOG(log_error, logtype_cnid, "tsock_getfd: no suitable network config from CNID server (%s:%s): %s",
176             host, port, strerror(errno));
177         return -1;
178     }
179
180     return(sock);
181 }
182
183 /*!
184  * Write "towrite" bytes using writev on non-blocking fd
185  *
186  * Every short write is considered an error, transmit can handle that.
187  *
188  * @param fd      (r) socket fd which must be non-blocking
189  * @param iov     (r) iovec for writev
190  * @param towrite (r) number of bytes in all iovec elements
191  * @param vecs    (r) number of iovecs in array
192  *
193  * @returns "towrite" bytes written or -1 on error
194  */
195 static int write_vec(int fd, struct iovec *iov, ssize_t towrite, int vecs)
196 {
197     ssize_t len;
198     int slept = 0;
199     int sleepsecs;
200
201     while (1) {
202         if (((len = writev(fd, iov, vecs)) == -1 && errno == EINTR))
203             continue;
204
205         if ((! slept) && len == -1 && errno == EAGAIN) {
206             sleepsecs = 2;
207             while ((sleepsecs = sleep(sleepsecs)));
208             slept = 1;
209             continue;
210         }
211
212         if (len == towrite) /* wrote everything out */
213             break;
214
215         if (len == -1)
216             LOG(log_error, logtype_cnid, "write_vec: %s", strerror(errno));
217         else
218             LOG(log_error, logtype_cnid, "write_vec: short write: %d", len);
219         return len;
220     }
221
222     LOG(log_maxdebug, logtype_cnid, "write_vec: wrote %d bytes", len);
223
224     return len;
225 }
226
227 /* --------------------- */
228 static int init_tsock(CNID_bdb_private *db)
229 {
230     int fd;
231     int len[DBD_NUM_OPEN_ARGS];
232     int iovecs;
233     struct iovec iov[DBD_NUM_OPEN_ARGS + 1] = {{0}};
234     struct vol *vol = db->vol;
235     ssize_t iovlen;
236
237     LOG(log_debug, logtype_cnid, "connecting to CNID server: %s:%s",
238         vol->v_cnidserver, vol->v_cnidport);
239
240     if ((fd = tsock_getfd(vol->v_cnidserver, vol->v_cnidport)) < 0)
241         return -1;
242
243     LOG(log_debug, logtype_cnid, "connecting volume '%s', path: %s, user: %s",
244         vol->v_configname, vol->v_path, vol->v_obj->username[0] ? vol->v_obj->username : "-");
245
246     iovecs = 1 + DBD_NUM_OPEN_ARGS - 1;
247
248     len[0] = strlen(vol->v_configname) + 1;
249     len[1] = strlen(vol->v_path) + 1;
250     len[2] = strlen(vol->v_obj->username);
251
252     iov[0].iov_base = &len[0];
253     iov[0].iov_len  = DBD_NUM_OPEN_ARGS * sizeof(int);
254
255     iov[1].iov_base = vol->v_configname;
256     iov[1].iov_len  = len[0];
257
258     iov[2].iov_base = vol->v_path;
259     iov[2].iov_len  = len[1];
260
261     if (len[2] > 0) {
262         len[2] += 1;
263         iovecs++;
264         iov[3].iov_base = vol->v_obj->username;
265         iov[3].iov_len  = len[2];
266     }
267
268     iovlen = iov[0].iov_len + iov[1].iov_len + iov[2].iov_len + iov[3].iov_len;
269
270     if (write_vec(fd, iov, iovlen, iovecs) != iovlen) {
271         LOG(log_error, logtype_cnid, "init_tsock: Error/short write: %s", strerror(errno));
272         close(fd);
273         return -1;
274     }
275
276     LOG(log_debug, logtype_cnid, "init_tsock: ok");
277
278     return fd;
279 }
280
281 /* --------------------- */
282 static int send_packet(CNID_bdb_private *db, struct cnid_dbd_rqst *rqst)
283 {
284     struct iovec iov[2];
285     size_t towrite;
286     int vecs;
287
288     iov[0].iov_base = rqst;
289     iov[0].iov_len  = sizeof(struct cnid_dbd_rqst);
290     towrite = sizeof(struct cnid_dbd_rqst);
291     vecs = 1;
292
293     if (rqst->namelen) {
294         iov[1].iov_base = (char *)rqst->name;
295         iov[1].iov_len  = rqst->namelen;
296         towrite += rqst->namelen;
297         vecs++;
298     }
299
300     if (write_vec(db->fd, iov, towrite, vecs) != towrite) {
301         LOG(log_warning, logtype_cnid, "send_packet: Error writev rqst (volume %s): %s",
302             db->vol->v_localname, strerror(errno));
303         return -1;
304     }
305
306     LOG(log_maxdebug, logtype_cnid, "send_packet: {done}");
307     return 0;
308 }
309
310 /* ------------------- */
311 static void dbd_initstamp(struct cnid_dbd_rqst *rqst)
312 {
313     RQST_RESET(rqst);
314     rqst->op = CNID_DBD_OP_GETSTAMP;
315 }
316
317 /* ------------------- */
318 static int dbd_reply_stamp(struct cnid_dbd_rply *rply)
319 {
320     switch (rply->result) {
321     case CNID_DBD_RES_OK:
322         break;
323     case CNID_DBD_RES_NOTFOUND:
324         return -1;
325     case CNID_DBD_RES_ERR_DB:
326     default:
327         errno = CNID_ERR_DB;
328         return -1;
329     }
330     return 0;
331 }
332
333 /* ---------------------
334  * send a request and get reply
335  * assume send is non blocking
336  * if no answer after sometime (at least MAX_DELAY secondes) return an error
337  */
338 static int dbd_rpc(CNID_bdb_private *db, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
339 {
340     ssize_t ret;
341     char *nametmp;
342     size_t len;
343
344     if (send_packet(db, rqst) < 0) {
345         return -1;
346     }
347     len = rply->namelen;
348     nametmp = rply->name;
349
350     ret = readt(db->fd, rply, sizeof(struct cnid_dbd_rply), 0, ONE_DELAY);
351
352     if (ret != sizeof(struct cnid_dbd_rply)) {
353         LOG(log_debug, logtype_cnid, "dbd_rpc: Error reading header from fd (volume %s): %s",
354             db->vol->v_localname, ret == -1 ? strerror(errno) : "closed");
355         rply->name = nametmp;
356         return -1;
357     }
358     rply->name = nametmp;
359     if (rply->namelen && rply->namelen > len) {
360         LOG(log_error, logtype_cnid,
361             "dbd_rpc: Error reading name (volume %s): %s name too long: %d. only wanted %d, garbage?",
362             db->vol->v_localname, rply->name, rply->namelen, len);
363         return -1;
364     }
365     if (rply->namelen && (ret = readt(db->fd, rply->name, rply->namelen, 0, ONE_DELAY)) != (ssize_t)rply->namelen) {
366         LOG(log_error, logtype_cnid, "dbd_rpc: Error reading name from fd (volume %s): %s",
367             db->vol->v_localname, ret == -1?strerror(errno):"closed");
368         return -1;
369     }
370
371     LOG(log_maxdebug, logtype_cnid, "dbd_rpc: {done}");
372
373     return 0;
374 }
375
376 /* -------------------- */
377 static int transmit(CNID_bdb_private *db, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
378 {
379     time_t orig, t;
380     int clean = 1; /* no errors so far - to prevent sleep on first try */
381
382     while (1) {
383         if (db->fd == -1) {
384             LOG(log_maxdebug, logtype_cnid, "transmit: connecting to cnid_dbd ...");
385             if ((db->fd = init_tsock(db)) < 0) {
386                 goto transmit_fail;
387             }
388             if (db->notfirst) {
389                 LOG(log_debug7, logtype_cnid, "transmit: reconnected to cnid_dbd");
390             } else { /* db->notfirst == 0 */
391                 db->notfirst = 1;
392             }
393             LOG(log_debug, logtype_cnid, "transmit: attached to '%s'", db->vol->v_localname);
394         }
395         if (!dbd_rpc(db, rqst, rply)) {
396             LOG(log_maxdebug, logtype_cnid, "transmit: {done}");
397             return 0;
398         }
399     transmit_fail:
400         if (db->fd != -1) {
401             close(db->fd);
402             db->fd = -1; /* FD not valid... will need to reconnect */
403         }
404
405         if (errno == ECONNREFUSED) { /* errno carefully injected in tsock_getfd */
406             /* give up */
407             LOG(log_error, logtype_cnid, "transmit: connection refused (volume %s)", db->vol->v_localname);
408             return -1;
409         }
410
411         if (!clean) { /* don't sleep if just got disconnected by cnid server */
412             time(&t);
413             if (t - orig > MAX_DELAY) {
414                 LOG(log_error, logtype_cnid, "transmit: Request to dbd daemon (volume %s) timed out.", db->vol->v_localname);
415                 return -1;
416             }
417             /* sleep a little before retry */
418             delay(1);
419         } else {
420             clean = 0; /* false... next time sleep */
421             time(&orig);
422         }
423     }
424     return -1;
425 }
426
427 /* ---------------------- */
428 static struct _cnid_db *cnid_dbd_new(struct vol *vol)
429 {
430     struct _cnid_db *cdb;
431
432     if ((cdb = (struct _cnid_db *)calloc(1, sizeof(struct _cnid_db))) == NULL)
433         return NULL;
434
435     cdb->cnid_db_vol = vol;
436     cdb->cnid_db_flags = CNID_FLAG_PERSISTENT | CNID_FLAG_LAZY_INIT;
437     cdb->cnid_add = cnid_dbd_add;
438     cdb->cnid_delete = cnid_dbd_delete;
439     cdb->cnid_get = cnid_dbd_get;
440     cdb->cnid_lookup = cnid_dbd_lookup;
441     cdb->cnid_find = cnid_dbd_find;
442     cdb->cnid_nextid = NULL;
443     cdb->cnid_resolve = cnid_dbd_resolve;
444     cdb->cnid_getstamp = cnid_dbd_getstamp;
445     cdb->cnid_update = cnid_dbd_update;
446     cdb->cnid_rebuild_add = cnid_dbd_rebuild_add;
447     cdb->cnid_close = cnid_dbd_close;
448     cdb->cnid_wipe = cnid_dbd_wipe;
449     return cdb;
450 }
451
452 /* ---------------------- */
453 struct _cnid_db *cnid_dbd_open(struct cnid_open_args *args)
454 {
455     CNID_bdb_private *db = NULL;
456     struct _cnid_db *cdb = NULL;
457
458     if ((cdb = cnid_dbd_new(args->cnid_args_vol)) == NULL) {
459         LOG(log_error, logtype_cnid, "cnid_open: Unable to allocate memory for database");
460         return NULL;
461     }
462
463     if ((db = (CNID_bdb_private *)calloc(1, sizeof(CNID_bdb_private))) == NULL) {
464         LOG(log_error, logtype_cnid, "cnid_open: Unable to allocate memory for database");
465         goto cnid_dbd_open_fail;
466     }
467
468     cdb->cnid_db_private = db;
469
470     db->fd = -1;
471     db->vol = args->cnid_args_vol;
472
473     LOG(log_debug, logtype_cnid, "Finished initializing CNID dbd module for volume '%s'",
474         args->cnid_args_vol->v_localname);
475
476     return cdb;
477
478 cnid_dbd_open_fail:
479     if (cdb != NULL)
480         free(cdb);
481     if (db != NULL)
482         free(db);
483
484     return NULL;
485 }
486
487 /* ---------------------- */
488 void cnid_dbd_close(struct _cnid_db *cdb)
489 {
490     CNID_bdb_private *db;
491
492     if (!cdb) {
493         LOG(log_error, logtype_cnid, "cnid_close called with NULL argument!");
494         return;
495     }
496
497     if ((db = cdb->cnid_db_private) != NULL) {
498         LOG(log_debug, logtype_cnid, "closing database connection for volume '%s'", db->vol->v_localname);
499
500         if (db->fd >= 0)
501             close(db->fd);
502         free(db);
503     }
504
505     free(cdb);
506
507     return;
508 }
509
510 /**
511  * Get the db stamp
512  **/
513 static int cnid_dbd_stamp(CNID_bdb_private *db)
514 {
515     struct cnid_dbd_rqst rqst_stamp;
516     struct cnid_dbd_rply rply_stamp;
517     char  stamp[ADEDLEN_PRIVSYN];
518
519     dbd_initstamp(&rqst_stamp);
520     memset(stamp, 0, ADEDLEN_PRIVSYN);
521     rply_stamp.name = stamp;
522     rply_stamp.namelen = ADEDLEN_PRIVSYN;
523
524     if (transmit(db, &rqst_stamp, &rply_stamp) < 0)
525         return -1;
526     if (dbd_reply_stamp(&rply_stamp ) < 0)
527         return -1;
528
529     if (db->client_stamp)
530         memcpy(db->client_stamp, stamp, ADEDLEN_PRIVSYN);
531     memcpy(db->stamp, stamp, ADEDLEN_PRIVSYN);
532
533     return 0;
534 }
535
536 /* ---------------------- */
537 cnid_t cnid_dbd_add(struct _cnid_db *cdb, const struct stat *st,
538                     cnid_t did, const char *name, size_t len, cnid_t hint)
539 {
540     CNID_bdb_private *db;
541     struct cnid_dbd_rqst rqst;
542     struct cnid_dbd_rply rply;
543     cnid_t id;
544
545     if (!cdb || !(db = cdb->cnid_db_private) || !st || !name) {
546         LOG(log_error, logtype_cnid, "cnid_add: Parameter error");
547         errno = CNID_ERR_PARAM;
548         return CNID_INVALID;
549     }
550
551     if (len > MAXPATHLEN) {
552         LOG(log_error, logtype_cnid, "cnid_add: Path name is too long");
553         errno = CNID_ERR_PATH;
554         return CNID_INVALID;
555     }
556
557     RQST_RESET(&rqst);
558     rqst.op = CNID_DBD_OP_ADD;
559
560     if (!(cdb->cnid_db_flags & CNID_FLAG_NODEV)) {
561         rqst.dev = st->st_dev;
562     }
563
564     rqst.ino = st->st_ino;
565     rqst.type = S_ISDIR(st->st_mode)?1:0;
566     rqst.cnid = hint;
567     rqst.did = did;
568     rqst.name = name;
569     rqst.namelen = len;
570
571     LOG(log_debug, logtype_cnid, "cnid_dbd_add: CNID: %u, name: '%s', dev: 0x%llx, inode: 0x%llx, type: %s",
572         ntohl(did), name, (long long)rqst.dev, (long long)st->st_ino, rqst.type ? "dir" : "file");
573
574     rply.namelen = 0;
575     if (transmit(db, &rqst, &rply) < 0) {
576         errno = CNID_ERR_DB;
577         return CNID_INVALID;
578     }
579
580     switch(rply.result) {
581     case CNID_DBD_RES_OK:
582         id = rply.cnid;
583         LOG(log_debug, logtype_cnid, "cnid_dbd_add: got CNID: %u", ntohl(id));
584         break;
585     case CNID_DBD_RES_ERR_MAX:
586         errno = CNID_ERR_MAX;
587         id = CNID_INVALID;
588         break;
589     case CNID_DBD_RES_ERR_DB:
590     case CNID_DBD_RES_ERR_DUPLCNID:
591         errno = CNID_ERR_DB;
592         id = CNID_INVALID;
593         break;
594     default:
595         abort();
596     }
597
598     return id;
599 }
600
601 /* ---------------------- */
602 cnid_t cnid_dbd_get(struct _cnid_db *cdb, cnid_t did, const char *name, size_t len)
603 {
604     CNID_bdb_private *db;
605     struct cnid_dbd_rqst rqst;
606     struct cnid_dbd_rply rply;
607     cnid_t id;
608
609     if (!cdb || !(db = cdb->cnid_db_private) || !name) {
610         LOG(log_error, logtype_cnid, "cnid_dbd_get: Parameter error");
611         errno = CNID_ERR_PARAM;
612         return CNID_INVALID;
613     }
614
615     if (len > MAXPATHLEN) {
616         LOG(log_error, logtype_cnid, "cnid_dbd_get: Path name is too long");
617         errno = CNID_ERR_PATH;
618         return CNID_INVALID;
619     }
620
621     LOG(log_debug, logtype_cnid, "cnid_dbd_get: DID: %u, name: '%s'", ntohl(did), name);
622
623     RQST_RESET(&rqst);
624     rqst.op = CNID_DBD_OP_GET;
625     rqst.did = did;
626     rqst.name = name;
627     rqst.namelen = len;
628
629     rply.namelen = 0;
630     if (transmit(db, &rqst, &rply) < 0) {
631         errno = CNID_ERR_DB;
632         return CNID_INVALID;
633     }
634
635     switch(rply.result) {
636     case CNID_DBD_RES_OK:
637         id = rply.cnid;
638         LOG(log_debug, logtype_cnid, "cnid_dbd_get: got CNID: %u", ntohl(id));
639         break;
640     case CNID_DBD_RES_NOTFOUND:
641         id = CNID_INVALID;
642         break;
643     case CNID_DBD_RES_ERR_DB:
644         id = CNID_INVALID;
645         errno = CNID_ERR_DB;
646         break;
647     default:
648         abort();
649     }
650
651     return id;
652 }
653
654 /* ---------------------- */
655 char *cnid_dbd_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, size_t len)
656 {
657     CNID_bdb_private *db;
658     struct cnid_dbd_rqst rqst;
659     struct cnid_dbd_rply rply;
660     char *name;
661
662     if (!cdb || !(db = cdb->cnid_db_private) || !id || !(*id)) {
663         LOG(log_error, logtype_cnid, "cnid_resolve: Parameter error");
664         errno = CNID_ERR_PARAM;
665         return NULL;
666     }
667
668     LOG(log_debug, logtype_cnid, "cnid_dbd_resolve: resolving CNID: %u", ntohl(*id));
669
670     /* TODO: We should maybe also check len. At the moment we rely on the caller
671        to provide a buffer that is large enough for MAXPATHLEN plus
672        CNID_HEADER_LEN plus 1 byte, which is large enough for the maximum that
673        can come from the database. */
674
675     RQST_RESET(&rqst);
676     rqst.op = CNID_DBD_OP_RESOLVE;
677     rqst.cnid = *id;
678
679     /* Pass buffer to transmit so it can stuff the reply data there */
680     rply.name = (char *)buffer;
681     rply.namelen = len;
682
683     if (transmit(db, &rqst, &rply) < 0) {
684         errno = CNID_ERR_DB;
685         *id = CNID_INVALID;
686         return NULL;
687     }
688
689     switch (rply.result) {
690     case CNID_DBD_RES_OK:
691         *id = rply.did;
692         name = rply.name + CNID_NAME_OFS;
693         LOG(log_debug, logtype_cnid, "cnid_dbd_resolve: resolved did: %u, name: '%s'", ntohl(*id), name);
694         break;
695     case CNID_DBD_RES_NOTFOUND:
696         *id = CNID_INVALID;
697         name = NULL;
698         break;
699     case CNID_DBD_RES_ERR_DB:
700         errno = CNID_ERR_DB;
701         *id = CNID_INVALID;
702         name = NULL;
703         break;
704     default:
705         abort();
706     }
707
708     return name;
709 }
710
711 /**
712  * Caller passes buffer where we will store the db stamp
713  **/
714 int cnid_dbd_getstamp(struct _cnid_db *cdb, void *buffer, const size_t len)
715 {
716     CNID_bdb_private *db;
717
718     if (!cdb || !(db = cdb->cnid_db_private) || len != ADEDLEN_PRIVSYN) {
719         LOG(log_error, logtype_cnid, "cnid_getstamp: Parameter error");
720         errno = CNID_ERR_PARAM;
721         return -1;
722     }
723     db->client_stamp = buffer;
724     db->stamp_size = len;
725
726     return cnid_dbd_stamp(db);
727 }
728
729 /* ---------------------- */
730 cnid_t cnid_dbd_lookup(struct _cnid_db *cdb, const struct stat *st, cnid_t did,
731                        const char *name, size_t len)
732 {
733     CNID_bdb_private *db;
734     struct cnid_dbd_rqst rqst;
735     struct cnid_dbd_rply rply;
736     cnid_t id;
737
738     if (!cdb || !(db = cdb->cnid_db_private) || !st || !name) {
739         LOG(log_error, logtype_cnid, "cnid_lookup: Parameter error");
740         errno = CNID_ERR_PARAM;
741         return CNID_INVALID;
742     }
743
744     if (len > MAXPATHLEN) {
745         LOG(log_error, logtype_cnid, "cnid_lookup: Path name is too long");
746         errno = CNID_ERR_PATH;
747         return CNID_INVALID;
748     }
749
750     RQST_RESET(&rqst);
751     rqst.op = CNID_DBD_OP_LOOKUP;
752
753     if (!(cdb->cnid_db_flags & CNID_FLAG_NODEV)) {
754         rqst.dev = st->st_dev;
755     }
756
757     rqst.ino = st->st_ino;
758     rqst.type = S_ISDIR(st->st_mode)?1:0;
759     rqst.did = did;
760     rqst.name = name;
761     rqst.namelen = len;
762
763     LOG(log_debug, logtype_cnid, "cnid_dbd_lookup: CNID: %u, name: '%s', inode: 0x%llx, type: %d (0=file, 1=dir)",
764         ntohl(did), name, (long long)st->st_ino, rqst.type);
765
766     rply.namelen = 0;
767     if (transmit(db, &rqst, &rply) < 0) {
768         errno = CNID_ERR_DB;
769         return CNID_INVALID;
770     }
771
772     switch (rply.result) {
773     case CNID_DBD_RES_OK:
774         id = rply.cnid;
775         LOG(log_debug, logtype_cnid, "cnid_dbd_lookup: got CNID: %u", ntohl(id));
776         break;
777     case CNID_DBD_RES_NOTFOUND:
778         id = CNID_INVALID;
779         break;
780     case CNID_DBD_RES_ERR_DB:
781         errno = CNID_ERR_DB;
782         id = CNID_INVALID;
783         break;
784     default:
785         abort();
786     }
787
788     return id;
789 }
790
791 /* ---------------------- */
792 int cnid_dbd_find(struct _cnid_db *cdb, const char *name, size_t namelen, void *buffer, size_t buflen)
793 {
794     CNID_bdb_private *db;
795     struct cnid_dbd_rqst rqst;
796     struct cnid_dbd_rply rply;
797     int count;
798
799     if (!cdb || !(db = cdb->cnid_db_private) || !name) {
800         LOG(log_error, logtype_cnid, "cnid_find: Parameter error");
801         errno = CNID_ERR_PARAM;
802         return CNID_INVALID;
803     }
804
805     if (namelen > MAXPATHLEN) {
806         LOG(log_error, logtype_cnid, "cnid_find: Path name is too long");
807         errno = CNID_ERR_PATH;
808         return CNID_INVALID;
809     }
810
811     LOG(log_debug, logtype_cnid, "cnid_find(\"%s\")", name);
812
813     RQST_RESET(&rqst);
814     rqst.op = CNID_DBD_OP_SEARCH;
815
816     rqst.name = name;
817     rqst.namelen = namelen;
818
819     rply.name = buffer;
820     rply.namelen = buflen;
821
822     if (transmit(db, &rqst, &rply) < 0) {
823         errno = CNID_ERR_DB;
824         return CNID_INVALID;
825     }
826
827     switch (rply.result) {
828     case CNID_DBD_RES_OK:
829         count = rply.namelen / sizeof(cnid_t);
830         LOG(log_debug, logtype_cnid, "cnid_find: got %d matches", count);
831         break;
832     case CNID_DBD_RES_NOTFOUND:
833         count = 0;
834         break;
835     case CNID_DBD_RES_ERR_DB:
836         errno = CNID_ERR_DB;
837         count = -1;
838         break;
839     default:
840         abort();
841     }
842
843     return count;
844 }
845
846 /* ---------------------- */
847 int cnid_dbd_update(struct _cnid_db *cdb, cnid_t id, const struct stat *st,
848                     cnid_t did, const char *name, size_t len)
849 {
850     CNID_bdb_private *db;
851     struct cnid_dbd_rqst rqst;
852     struct cnid_dbd_rply rply;
853
854     if (!cdb || !(db = cdb->cnid_db_private) || !id || !st || !name) {
855         LOG(log_error, logtype_cnid, "cnid_update: Parameter error");
856         errno = CNID_ERR_PARAM;
857         return -1;
858     }
859
860     if (len > MAXPATHLEN) {
861         LOG(log_error, logtype_cnid, "cnid_update: Path name is too long");
862         errno = CNID_ERR_PATH;
863         return -1;
864     }
865
866     RQST_RESET(&rqst);
867     rqst.op = CNID_DBD_OP_UPDATE;
868     rqst.cnid = id;
869     if (!(cdb->cnid_db_flags & CNID_FLAG_NODEV)) {
870         rqst.dev = st->st_dev;
871     }
872     rqst.ino = st->st_ino;
873     rqst.type = S_ISDIR(st->st_mode)?1:0;
874     rqst.did = did;
875     rqst.name = name;
876     rqst.namelen = len;
877
878     LOG(log_debug, logtype_cnid, "cnid_dbd_update: CNID: %u, name: '%s', inode: 0x%llx, type: %d (0=file, 1=dir)",
879         ntohl(id), name, (long long)st->st_ino, rqst.type);
880
881     rply.namelen = 0;
882     if (transmit(db, &rqst, &rply) < 0) {
883         errno = CNID_ERR_DB;
884         return -1;
885     }
886
887     switch (rply.result) {
888     case CNID_DBD_RES_OK:
889         LOG(log_debug, logtype_cnid, "cnid_dbd_update: updated");
890     case CNID_DBD_RES_NOTFOUND:
891         return 0;
892     case CNID_DBD_RES_ERR_DB:
893         errno = CNID_ERR_DB;
894         return -1;
895     default:
896         abort();
897     }
898 }
899
900 /* ---------------------- */
901 cnid_t cnid_dbd_rebuild_add(struct _cnid_db *cdb, const struct stat *st,
902                             cnid_t did, const char *name, size_t len, cnid_t hint)
903 {
904     CNID_bdb_private *db;
905     struct cnid_dbd_rqst rqst;
906     struct cnid_dbd_rply rply;
907     cnid_t id;
908
909     if (!cdb || !(db = cdb->cnid_db_private) || !st || !name || hint == CNID_INVALID) {
910         LOG(log_error, logtype_cnid, "cnid_rebuild_add: Parameter error");
911         errno = CNID_ERR_PARAM;
912         return CNID_INVALID;
913     }
914
915     if (len > MAXPATHLEN) {
916         LOG(log_error, logtype_cnid, "cnid_rebuild_add: Path name is too long");
917         errno = CNID_ERR_PATH;
918         return CNID_INVALID;
919     }
920
921     RQST_RESET(&rqst);
922     rqst.op = CNID_DBD_OP_REBUILD_ADD;
923
924     if (!(cdb->cnid_db_flags & CNID_FLAG_NODEV)) {
925         rqst.dev = st->st_dev;
926     }
927
928     rqst.ino = st->st_ino;
929     rqst.type = S_ISDIR(st->st_mode)?1:0;
930     rqst.did = did;
931     rqst.name = name;
932     rqst.namelen = len;
933     rqst.cnid = hint;
934
935     LOG(log_debug, logtype_cnid, "cnid_dbd_rebuild_add: CNID: %u, name: '%s', inode: 0x%llx, type: %d (0=file, 1=dir), hint: %u",
936         ntohl(did), name, (long long)st->st_ino, rqst.type, hint);
937
938     if (transmit(db, &rqst, &rply) < 0) {
939         errno = CNID_ERR_DB;
940         return CNID_INVALID;
941     }
942
943     switch(rply.result) {
944     case CNID_DBD_RES_OK:
945         id = rply.cnid;
946         LOG(log_debug, logtype_cnid, "cnid_dbd_rebuild_add: got CNID: %u", ntohl(id));
947         break;
948     case CNID_DBD_RES_ERR_MAX:
949         errno = CNID_ERR_MAX;
950         id = CNID_INVALID;
951         break;
952     case CNID_DBD_RES_ERR_DB:
953     case CNID_DBD_RES_ERR_DUPLCNID:
954         errno = CNID_ERR_DB;
955         id = CNID_INVALID;
956         break;
957     default:
958         abort();
959     }
960     return id;
961 }
962
963 /* ---------------------- */
964 int cnid_dbd_delete(struct _cnid_db *cdb, const cnid_t id)
965 {
966     CNID_bdb_private *db;
967     struct cnid_dbd_rqst rqst;
968     struct cnid_dbd_rply rply;
969
970     if (!cdb || !(db = cdb->cnid_db_private) || !id) {
971         LOG(log_error, logtype_cnid, "cnid_delete: Parameter error");
972         errno = CNID_ERR_PARAM;
973         return -1;
974     }
975
976     LOG(log_debug, logtype_cnid, "cnid_dbd_delete: delete CNID: %u", ntohl(id));
977
978     RQST_RESET(&rqst);
979     rqst.op = CNID_DBD_OP_DELETE;
980     rqst.cnid = id;
981
982     rply.namelen = 0;
983     if (transmit(db, &rqst, &rply) < 0) {
984         errno = CNID_ERR_DB;
985         return -1;
986     }
987
988     switch (rply.result) {
989     case CNID_DBD_RES_OK:
990         LOG(log_debug, logtype_cnid, "cnid_dbd_delete: deleted CNID: %u", ntohl(id));
991     case CNID_DBD_RES_NOTFOUND:
992         return 0;
993     case CNID_DBD_RES_ERR_DB:
994         errno = CNID_ERR_DB;
995         return -1;
996     default:
997         abort();
998     }
999 }
1000
1001 int cnid_dbd_wipe(struct _cnid_db *cdb)
1002 {
1003     CNID_bdb_private *db;
1004     struct cnid_dbd_rqst rqst;
1005     struct cnid_dbd_rply rply;
1006
1007     if (!cdb || !(db = cdb->cnid_db_private)) {
1008         LOG(log_error, logtype_cnid, "cnid_wipe: Parameter error");
1009         errno = CNID_ERR_PARAM;
1010         return -1;
1011     }
1012
1013     LOG(log_debug, logtype_cnid, "cnid_dbd_wipe");
1014
1015     RQST_RESET(&rqst);
1016     rqst.op = CNID_DBD_OP_WIPE;
1017     rqst.cnid = 0;
1018
1019     rply.namelen = 0;
1020     if (transmit(db, &rqst, &rply) < 0) {
1021         errno = CNID_ERR_DB;
1022         return -1;
1023     }
1024
1025     if (rply.result != CNID_DBD_RES_OK) {
1026         errno = CNID_ERR_DB;
1027         return -1;
1028     }
1029     LOG(log_debug, logtype_cnid, "cnid_dbd_wipe: ok");
1030
1031     return cnid_dbd_stamp(db);
1032 }
1033
1034
1035 struct _cnid_module cnid_dbd_module = {
1036     "dbd",
1037     {NULL, NULL},
1038     cnid_dbd_open,
1039     0
1040 };
1041
1042 #endif /* CNID_DBD */
1043