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