]> arthur.barton.de Git - netatalk.git/blob - libatalk/cnid/dbd/cnid_dbd.c
e89af69ac76b1f7a95d7210352b598e8608b0529
[netatalk.git] / libatalk / cnid / dbd / cnid_dbd.c
1 /*
2  * $Id: cnid_dbd.c,v 1.1.4.18.2.1 2005-01-30 20:56:22 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 static int tsock_getfd(char *host, int port)
59 {
60 int sock;
61 struct sockaddr_in server;
62 struct hostent* hp;
63 int attr;
64 int err;
65
66     server.sin_family=AF_INET;
67     server.sin_port=htons((unsigned short)port);
68     if (!host) {
69         LOG(log_error, logtype_cnid, "getfd: -cnidserver not defined");
70         return -1;
71     }
72     
73     hp=gethostbyname(host);
74     if (!hp) {
75         unsigned long int addr=inet_addr(host);
76         LOG(log_warning, logtype_cnid, "getfd: Could not resolve host %s, trying numeric address instead", host);
77         if (addr!= (unsigned)-1)
78             hp=gethostbyaddr((char*)addr,sizeof(addr),AF_INET);
79  
80         if (!hp) {
81             LOG(log_error, logtype_cnid, "getfd: Could not resolve host %s", host);
82             return(-1);
83         }
84     }
85     memcpy((char*)&server.sin_addr,(char*)hp->h_addr,sizeof(server.sin_addr));
86     sock=socket(PF_INET,SOCK_STREAM,0);
87     if (sock==-1) {
88         LOG(log_error, logtype_cnid, "getfd: socket %s: %s", host, strerror(errno));
89         return(-1);
90     }
91     attr = 1;
92     if (setsockopt(sock, SOL_TCP, TCP_NODELAY, &attr, sizeof(attr)) == -1) {
93         LOG(log_error, logtype_cnid, "getfd: set TCP_NODELAY %s: %s", host, strerror(errno));
94         close(sock);
95         return(-1);
96     }
97     if(connect(sock ,(struct sockaddr*)&server,sizeof(server))==-1) {
98         struct timeval tv;
99         err = errno;
100         close(sock);
101         sock=-1;
102         LOG(log_error, logtype_cnid, "getfd: connect %s: %s", host, strerror(err));
103         switch (err) {
104         case ENETUNREACH:
105         case ECONNREFUSED: 
106             
107             tv.tv_usec = 0;
108             tv.tv_sec  = 5;
109             select(0, NULL, NULL, NULL, &tv);
110             break;
111         }
112     }
113     return(sock);
114 }
115
116 /* --------------------- */
117 static int init_tsock(CNID_private *db)
118 {
119     int fd;
120     int len;
121     
122     if ((fd = tsock_getfd(Cnid_srv, Cnid_port)) < 0) 
123         return -1;
124     len = strlen(db->db_dir);
125     if (write(fd, &len, sizeof(int)) != sizeof(int)) {
126         LOG(log_error, logtype_cnid, "init_tsock: Error/short write: %s", strerror(errno));
127         close(fd);
128         return -1;
129     }
130     if (write(fd, db->db_dir, len) != len) {
131         LOG(log_error, logtype_cnid, "init_tsock: Error/short write dir: %s", strerror(errno));
132         close(fd);
133         return -1;
134     }
135     return fd;
136 }
137
138 /* --------------------- */
139 static int send_packet(CNID_private *db, struct cnid_dbd_rqst *rqst, int silent)
140 {
141     struct iovec iov[2];
142     size_t towrite;
143     ssize_t len;
144   
145     iov[0].iov_base = rqst;
146     iov[0].iov_len  = sizeof(struct cnid_dbd_rqst);
147     
148     if (!rqst->namelen) {
149         if (write(db->fd, rqst, sizeof(struct cnid_dbd_rqst)) != sizeof(struct cnid_dbd_rqst)) {
150             if (!silent)
151                 LOG(log_warning, logtype_cnid, "send_packet: Error/short write rqst (db_dir %s): %s", 
152                     db->db_dir, strerror(errno));
153             return -1;
154         }
155         return 0;
156     }
157     iov[1].iov_base = rqst->name;
158     iov[1].iov_len  = rqst->namelen;
159
160     towrite = sizeof(struct cnid_dbd_rqst) +rqst->namelen;
161     while (towrite > 0) {
162         if (((len = writev(db->fd, iov, 2)) == -1 && errno == EINTR) || !len)
163             continue;
164  
165         if (len == towrite) /* wrote everything out */
166             break;
167         else if (len < 0) { /* error */
168             if (!silent)
169                 LOG(log_warning, logtype_cnid, "send_packet: Error writev rqst (db_dir %s): %s", 
170                     db->db_dir, strerror(errno));
171             return -1;
172         }
173  
174         towrite -= len;
175         if (towrite > rqst->namelen) { /* skip part of header */
176             iov[0].iov_base = (char *) iov[0].iov_base + len;
177             iov[0].iov_len -= len;
178         } else { /* skip to data */
179             if (iov[0].iov_len) {
180                 len -= iov[0].iov_len;
181                 iov[0].iov_len = 0;
182             }
183             iov[1].iov_base = (char *) iov[1].iov_base + len;
184             iov[1].iov_len -= len;
185         }
186     }
187     return 0;
188 }
189
190 /* ------------------- */
191 static void dbd_initstamp(struct cnid_dbd_rqst *rqst)
192 {
193     RQST_RESET(rqst);
194     rqst->op = CNID_DBD_OP_GETSTAMP;
195 }
196
197 /* ------------------- */
198 static int dbd_reply_stamp(struct cnid_dbd_rply *rply)
199 {
200     switch (rply->result) {
201     case CNID_DBD_RES_OK:
202         break;
203     case CNID_DBD_RES_NOTFOUND:
204         return -1;
205     case CNID_DBD_RES_ERR_DB:
206     default:
207         errno = CNID_ERR_DB;
208         return -1;
209     }
210     return 0;
211 }
212
213 /* --------------------- 
214  * send a request and get reply
215  * assume send is non blocking
216  * if no answer after sometime (at least MAX_DELAY secondes) return an error
217 */
218 #define MAX_DELAY 40
219 static int dbd_rpc(CNID_private *db, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply, int silent)
220 {
221     int  ret;
222     char *nametmp;
223     struct timeval tv;
224     fd_set readfds;
225     int    maxfd;
226     size_t len;
227
228     if (send_packet(db, rqst, silent) < 0) {
229         return -1;
230     }
231     FD_ZERO(&readfds);
232     FD_SET(db->fd, &readfds);
233     maxfd = db->fd +1;
234         
235     tv.tv_usec = 0;
236     tv.tv_sec  = MAX_DELAY;
237     while ((ret = select(maxfd + 1, &readfds, NULL, NULL, &tv)) < 0 && errno == EINTR);
238
239     if (ret < 0) {
240         if (!silent)
241             LOG(log_error, logtype_cnid, "dbd_rpc: Error in select (db_dir %s): %s",
242                 db->db_dir, strerror(errno));
243         return ret;
244     }
245     /* signal ? */
246     if (!ret) {
247         /* no answer */
248         if (!silent)
249             LOG(log_error, logtype_cnid, "dbd_rpc: select timed out (db_dir %s)",
250                 db->db_dir);
251         return -1;
252     }
253
254     len = rply->namelen;
255     nametmp = rply->name;
256     /* assume that if we have something then everything is there (doesn't sleep) */ 
257     if ((ret = read(db->fd, rply, sizeof(struct cnid_dbd_rply))) != sizeof(struct cnid_dbd_rply)) {
258         if (!silent)
259             LOG(log_error, logtype_cnid, "dbd_rpc: Error reading header from fd (db_dir %s): %s",
260                 db->db_dir, ret == -1?strerror(errno):"closed");
261         rply->name = nametmp;
262         return -1;
263     }
264     rply->name = nametmp;
265     if (rply->namelen && rply->namelen > len) {
266         if (!silent)
267             LOG(log_error, logtype_cnid, 
268                  "dbd_rpc: Error reading name (db_dir %s): %s name too long wanted %d only %d, garbage?",
269                  db->db_dir, rply->namelen, len);
270         return -1;
271     }
272     if (rply->namelen && (ret = read(db->fd, rply->name, rply->namelen)) != rply->namelen) {
273         if (!silent)
274             LOG(log_error, logtype_cnid, "dbd_rpc: Error reading name from fd (db_dir %s): %s",
275                 db->db_dir, ret == -1?strerror(errno):"closed");
276         return -1;
277     }
278     return 0;
279 }
280
281 /* -------------------- */
282 static int transmit(CNID_private *db, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
283 {
284     struct timeval tv;
285     time_t orig, t;
286     int silent = 1;
287     
288     if (db->changed) {
289         /* volume and db don't have the same timestamp
290         */
291         return -1;
292     }
293     time(&orig);
294     while (1) {
295
296         if (db->fd == -1) {
297             if ((db->fd = init_tsock(db)) < 0) {
298                 time(&t);
299                 if (t - orig > MAX_DELAY)
300                     return -1;
301                 continue;
302             }
303             if (db->notfirst) {
304                 struct cnid_dbd_rqst rqst_stamp;
305                 struct cnid_dbd_rply rply_stamp;
306                 char  stamp[ADEDLEN_PRIVSYN];
307                 
308                 dbd_initstamp(&rqst_stamp);
309                 memset(stamp, 0, ADEDLEN_PRIVSYN);
310                 rply_stamp.name = stamp;
311                 rply_stamp.namelen = ADEDLEN_PRIVSYN;
312                 
313                 if (dbd_rpc(db, &rqst_stamp, &rply_stamp, silent) < 0)
314                     goto transmit_fail;
315                 if (dbd_reply_stamp(&rply_stamp ) < 0)
316                     goto transmit_fail;
317                 if (memcmp(stamp, db->stamp, ADEDLEN_PRIVSYN)) {
318                     LOG(log_error, logtype_cnid, "transmit: not the same db!");
319                     db->changed = 1;
320                     return -1;
321                 }
322             }
323
324         }
325         if (!dbd_rpc(db, rqst, rply, silent))
326             return 0;
327
328 transmit_fail:
329         silent = 0; /* From now on dbd_rpc and subroutines called from there
330                        will log messages if something goes wrong again */
331         if (db->fd != -1) {
332             close(db->fd);
333         }
334         time(&t);
335         if (t - orig > MAX_DELAY) {
336             LOG(log_error, logtype_cnid, "transmit: Request to dbd daemon (db_dir %s) timed out.", db->db_dir);
337             return -1;
338         }
339
340         /* sleep a little before retry */
341         db->fd = -1;
342         tv.tv_usec = 0;
343         tv.tv_sec  = 5;
344         select(0, NULL, NULL, NULL, &tv);
345     }
346     return -1;
347 }
348
349 /* ---------------------- */
350 static struct _cnid_db *cnid_dbd_new(const char *volpath)
351 {
352     struct _cnid_db *cdb;
353     
354     if ((cdb = (struct _cnid_db *)calloc(1, sizeof(struct _cnid_db))) == NULL)
355         return NULL;
356         
357     if ((cdb->volpath = strdup(volpath)) == NULL) {
358         free(cdb);
359         return NULL;
360     }
361     
362     cdb->flags = CNID_FLAG_PERSISTENT;
363     
364     cdb->cnid_add = cnid_dbd_add;
365     cdb->cnid_delete = cnid_dbd_delete;
366     cdb->cnid_get = cnid_dbd_get;
367     cdb->cnid_lookup = cnid_dbd_lookup;
368     cdb->cnid_nextid = NULL;
369     cdb->cnid_resolve = cnid_dbd_resolve;
370     cdb->cnid_getstamp = cnid_dbd_getstamp;
371     cdb->cnid_update = cnid_dbd_update;
372     cdb->cnid_close = cnid_dbd_close;
373     
374     return cdb;
375 }
376
377 /* ---------------------- */
378 struct _cnid_db *cnid_dbd_open(const char *dir, mode_t mask)
379 {
380     CNID_private *db = NULL;
381     struct _cnid_db *cdb = NULL;
382
383     if (!dir) {
384          return NULL;
385     }
386     
387     if ((cdb = cnid_dbd_new(dir)) == NULL) {
388         LOG(log_error, logtype_default, "cnid_open: Unable to allocate memory for database");
389         return NULL;
390     }
391         
392     if ((db = (CNID_private *)calloc(1, sizeof(CNID_private))) == NULL) {
393         LOG(log_error, logtype_cnid, "cnid_open: Unable to allocate memory for database");
394         goto cnid_dbd_open_fail;
395     }
396     
397     cdb->_private = db;
398
399     /* We keep a copy of the directory in the db structure so that we can
400        transparently reconnect later. */
401     strcpy(db->db_dir, dir);
402     db->magic = CNID_DB_MAGIC;
403     db->fd = -1;
404 #ifdef DEBUG
405     LOG(log_info, logtype_cnid, "opening database connection to %s", db->db_dir); 
406 #endif
407     return cdb;
408
409 cnid_dbd_open_fail:
410     if (cdb != NULL) {
411         if (cdb->volpath != NULL) {
412             free(cdb->volpath);
413         }
414         free(cdb);
415     }
416     if (db != NULL)
417         free(db);
418         
419     return NULL;
420 }
421
422 /* ---------------------- */
423 void cnid_dbd_close(struct _cnid_db *cdb)
424 {
425     CNID_private *db;
426
427     if (!cdb) {
428         LOG(log_error, logtype_afpd, "cnid_close called with NULL argument !");
429         return;
430     }
431
432     if ((db = cdb->_private) != NULL) {
433 #ifdef DEBUG 
434         LOG(log_info, logtype_cnid, "closing database connection to %s", db->db_dir);
435 #endif  
436         if (db->fd >= 0)
437             close(db->fd);
438         free(db);
439     }
440     
441     free(cdb->volpath);
442     free(cdb);
443     
444     return;
445 }
446
447 /* ---------------------- */
448 cnid_t cnid_dbd_add(struct _cnid_db *cdb, const struct stat *st,
449                 const cnid_t did, char *name, const int len,
450                 cnid_t hint)
451 {
452     CNID_private *db;
453     struct cnid_dbd_rqst rqst;
454     struct cnid_dbd_rply rply;
455     cnid_t id;
456
457     if (!cdb || !(db = cdb->_private) || !st || !name) {
458         LOG(log_error, logtype_cnid, "cnid_add: Parameter error");
459         errno = CNID_ERR_PARAM;
460         return CNID_INVALID;
461     }
462
463     if (len > MAXPATHLEN) {
464         LOG(log_error, logtype_cnid, "cnid_add: Path name is too long");
465         errno = CNID_ERR_PATH;
466         return CNID_INVALID;
467     }
468
469     RQST_RESET(&rqst);
470     rqst.op = CNID_DBD_OP_ADD;
471
472     if (!(cdb->flags & CNID_FLAG_NODEV)) {
473         rqst.dev = st->st_dev;
474     }
475
476     rqst.ino = st->st_ino;
477     rqst.type = S_ISDIR(st->st_mode)?1:0;
478     rqst.did = did;
479     rqst.name = name;
480     rqst.namelen = len;
481
482     if (transmit(db, &rqst, &rply) < 0) {
483         errno = CNID_ERR_DB;
484         return CNID_INVALID;
485     }
486     
487     switch(rply.result) {
488     case CNID_DBD_RES_OK:
489         id = rply.cnid;
490         break;
491     case CNID_DBD_RES_ERR_MAX:
492         errno = CNID_ERR_MAX;
493         id = CNID_INVALID;
494         break;
495     case CNID_DBD_RES_ERR_DB:
496     case CNID_DBD_RES_ERR_DUPLCNID:
497         errno = CNID_ERR_DB;
498         id = CNID_INVALID;
499         break;
500     default:
501         abort();
502     }
503     return id;
504 }
505
506 /* ---------------------- */
507 cnid_t cnid_dbd_get(struct _cnid_db *cdb, const cnid_t did, char *name,
508                 const int len)
509 {
510     CNID_private *db;
511     struct cnid_dbd_rqst rqst;
512     struct cnid_dbd_rply rply;
513     cnid_t id;
514
515
516     if (!cdb || !(db = cdb->_private) || !name) {
517         LOG(log_error, logtype_cnid, "cnid_get: Parameter error");
518         errno = CNID_ERR_PARAM;        
519         return CNID_INVALID;
520     }
521
522     if (len > MAXPATHLEN) {
523         LOG(log_error, logtype_cnid, "cnid_add: Path name is too long");
524         errno = CNID_ERR_PATH;
525         return CNID_INVALID;
526     }
527
528     RQST_RESET(&rqst);
529     rqst.op = CNID_DBD_OP_GET;
530     rqst.did = did;
531     rqst.name = name;
532     rqst.namelen = len;
533
534     if (transmit(db, &rqst, &rply) < 0) {
535         errno = CNID_ERR_DB;
536         return CNID_INVALID;
537     }
538     
539     switch(rply.result) {
540     case CNID_DBD_RES_OK:
541         id = rply.cnid;
542         break;
543     case CNID_DBD_RES_NOTFOUND:
544         id = CNID_INVALID;
545         break;
546     case CNID_DBD_RES_ERR_DB:
547         id = CNID_INVALID;
548         errno = CNID_ERR_DB;
549         break;
550     default: 
551         abort();
552     }
553
554     return id;
555 }
556
557 /* ---------------------- */
558 char *cnid_dbd_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, u_int32_t len)
559 {
560     CNID_private *db;
561     struct cnid_dbd_rqst rqst;
562     struct cnid_dbd_rply rply;
563     char *name;
564
565     if (!cdb || !(db = cdb->_private) || !id || !(*id)) {
566         LOG(log_error, logtype_cnid, "cnid_resolve: Parameter error");
567         errno = CNID_ERR_PARAM;                
568         return NULL;
569     }
570
571     /* TODO: We should maybe also check len. At the moment we rely on the caller
572        to provide a buffer that is large enough for MAXPATHLEN plus
573        CNID_HEADER_LEN plus 1 byte, which is large enough for the maximum that
574        can come from the database. */
575
576     RQST_RESET(&rqst);
577     rqst.op = CNID_DBD_OP_RESOLVE;
578     rqst.cnid = *id;
579
580     /* This mimicks the behaviour of the "regular" cnid_resolve. So far,
581        nobody uses the content of buffer. It only provides space for the
582        name in the caller. */
583     rply.name = (char *)buffer + CNID_HEADER_LEN;
584     rply.namelen = len - CNID_HEADER_LEN;
585
586     if (transmit(db, &rqst, &rply) < 0) {
587         errno = CNID_ERR_DB;
588         *id = CNID_INVALID;
589         return NULL;
590     }
591
592     switch (rply.result) {
593     case CNID_DBD_RES_OK:
594         *id = rply.did;
595         name = rply.name;
596         break;
597     case CNID_DBD_RES_NOTFOUND:
598         *id = CNID_INVALID;
599         name = NULL;
600         break;
601     case CNID_DBD_RES_ERR_DB:
602         errno = CNID_ERR_DB;
603         *id = CNID_INVALID;
604         name = NULL;
605         break;
606     default:
607         abort();
608     }
609
610     return name;
611 }
612
613 /* --------------------- */
614 static int dbd_getstamp(CNID_private *db, void *buffer, const size_t len)
615 {
616     struct cnid_dbd_rqst rqst;
617     struct cnid_dbd_rply rply;
618
619     memset(buffer, 0, len);
620     dbd_initstamp(&rqst);
621
622     rply.name = buffer;
623     rply.namelen = len;
624
625     if (transmit(db, &rqst, &rply) < 0) {
626         errno = CNID_ERR_DB;
627         return -1;
628     }
629     return dbd_reply_stamp(&rply);
630 }
631
632 /* ---------------------- */
633 int cnid_dbd_getstamp(struct _cnid_db *cdb, void *buffer, const int len)
634 {
635     CNID_private *db;
636     int ret;
637
638     if (!cdb || !(db = cdb->_private) || len != ADEDLEN_PRIVSYN) {
639         LOG(log_error, logtype_cnid, "cnid_getstamp: Parameter error");
640         errno = CNID_ERR_PARAM;                
641         return -1;
642     }
643     ret = dbd_getstamp(db, buffer, len);
644     if (!ret) {
645         db->notfirst = 1;
646         memcpy(db->stamp, buffer, len);
647     }
648     return ret;
649 }
650
651 /* ---------------------- */
652 cnid_t cnid_dbd_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
653                    char *name, const int len)
654 {
655     CNID_private *db;
656     struct cnid_dbd_rqst rqst;
657     struct cnid_dbd_rply rply;
658     cnid_t id;
659
660     if (!cdb || !(db = cdb->_private) || !st || !name) {
661         LOG(log_error, logtype_cnid, "cnid_lookup: Parameter error");
662         errno = CNID_ERR_PARAM;        
663         return CNID_INVALID;
664     }
665
666     if (len > MAXPATHLEN) {
667         LOG(log_error, logtype_cnid, "cnid_lookup: Path name is too long");
668         errno = CNID_ERR_PATH;
669         return CNID_INVALID;
670     }
671
672     RQST_RESET(&rqst);
673     rqst.op = CNID_DBD_OP_LOOKUP;
674
675     if (!(cdb->flags & CNID_FLAG_NODEV)) {
676         rqst.dev = st->st_dev;
677     }
678
679     rqst.ino = st->st_ino;
680     rqst.type = S_ISDIR(st->st_mode)?1:0;
681     rqst.did = did;
682     rqst.name = name;
683     rqst.namelen = len;
684
685     if (transmit(db, &rqst, &rply) < 0) {
686         errno = CNID_ERR_DB;
687         return CNID_INVALID;
688     }
689
690     switch (rply.result) {
691     case CNID_DBD_RES_OK:
692         id = rply.cnid;
693         break;
694     case CNID_DBD_RES_NOTFOUND:
695         id = CNID_INVALID;
696         break;
697     case CNID_DBD_RES_ERR_DB:
698         errno = CNID_ERR_DB;
699         id = CNID_INVALID;
700         break;
701     default:
702         abort();
703     }
704
705     return id;
706 }
707
708 /* ---------------------- */
709 int cnid_dbd_update(struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
710                 const cnid_t did, char *name, const int len)
711 {
712     CNID_private *db;
713     struct cnid_dbd_rqst rqst;
714     struct cnid_dbd_rply rply;
715
716     
717     if (!cdb || !(db = cdb->_private) || !id || !st || !name) {
718         LOG(log_error, logtype_cnid, "cnid_update: Parameter error");
719         errno = CNID_ERR_PARAM;        
720         return -1;
721     }
722
723     if (len > MAXPATHLEN) {
724         LOG(log_error, logtype_cnid, "cnid_update: Path name is too long");
725         errno = CNID_ERR_PATH;
726         return -1;
727     }
728
729     RQST_RESET(&rqst);
730     rqst.op = CNID_DBD_OP_UPDATE;
731     rqst.cnid = id;
732     if (!(cdb->flags & CNID_FLAG_NODEV)) {
733         rqst.dev = st->st_dev;
734     }
735     rqst.ino = st->st_ino;
736     rqst.type = S_ISDIR(st->st_mode)?1:0;
737     rqst.did = did;
738     rqst.name = name;
739     rqst.namelen = len;
740
741     if (transmit(db, &rqst, &rply) < 0) {
742         errno = CNID_ERR_DB;
743         return -1;
744     }
745
746     switch (rply.result) {
747     case CNID_DBD_RES_OK:
748     case CNID_DBD_RES_NOTFOUND:
749         return 0;
750     case CNID_DBD_RES_ERR_DB:
751         errno = CNID_ERR_DB;
752         return -1;
753     default:
754         abort();
755     }
756 }
757
758 /* ---------------------- */
759 int cnid_dbd_delete(struct _cnid_db *cdb, const cnid_t id) 
760 {
761     CNID_private *db;
762     struct cnid_dbd_rqst rqst;
763     struct cnid_dbd_rply rply;
764
765
766     if (!cdb || !(db = cdb->_private) || !id) {
767         LOG(log_error, logtype_cnid, "cnid_delete: Parameter error");
768         errno = CNID_ERR_PARAM;        
769         return -1;
770     }
771
772     RQST_RESET(&rqst);
773     rqst.op = CNID_DBD_OP_DELETE;
774     rqst.cnid = id;
775
776     if (transmit(db, &rqst, &rply) < 0) {
777         errno = CNID_ERR_DB;
778         return -1;
779     }
780
781     switch (rply.result) {
782     case CNID_DBD_RES_OK:
783     case CNID_DBD_RES_NOTFOUND:
784         return 0;
785     case CNID_DBD_RES_ERR_DB:
786         errno = CNID_ERR_DB;
787         return -1;
788     default:
789         abort();
790     }
791 }
792
793 struct _cnid_module cnid_dbd_module = {
794     "dbd",
795     {NULL, NULL},
796     cnid_dbd_open,
797 };
798
799 #endif /* CNID_DBD */
800