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