~ubuntu-branches/ubuntu/precise/netatalk/precise

« back to all changes in this revision

Viewing changes to libatalk/cnid/cnid_lookup.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Rittau
  • Date: 2004-01-19 12:43:49 UTC
  • Revision ID: james.westby@ubuntu.com-20040119124349-es563jbp0hk0ae51
Tags: upstream-1.6.4
ImportĀ upstreamĀ versionĀ 1.6.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * $Id: cnid_lookup.c,v 1.14.2.1 2003/02/08 03:16:53 jmarcus Exp $
 
3
 */
 
4
 
 
5
#ifdef HAVE_CONFIG_H
 
6
#include "config.h"
 
7
#endif /* HAVE_CONFIG_H */
 
8
 
 
9
#ifdef CNID_DB
 
10
#include <stdio.h>
 
11
#include <string.h>
 
12
#include <sys/param.h>
 
13
#include <sys/stat.h>
 
14
#include <atalk/logger.h>
 
15
#include <errno.h>
 
16
 
 
17
#include <db.h>
 
18
#include <netatalk/endian.h>
 
19
#include <atalk/adouble.h>
 
20
#include <atalk/cnid.h>
 
21
 
 
22
#include "cnid_private.h"
 
23
 
 
24
#define LOGFILEMAX    100  /* kbytes */
 
25
#define CHECKTIMEMAX   30  /* minutes */
 
26
 
 
27
/* This returns the CNID corresponding to a particular file.  It will
 
28
 * also fix up the various databases if there's a problem. */
 
29
cnid_t cnid_lookup(void *CNID, const struct stat *st, const cnid_t did,
 
30
                   const char *name, const int len)
 
31
{
 
32
    char *buf;
 
33
    CNID_private *db;
 
34
    DBT key, devdata, diddata;
 
35
    int devino = 1, didname = 1;
 
36
    cnid_t id = 0;
 
37
    int rc;
 
38
 
 
39
    if (!(db = CNID) || !st || !name) {
 
40
        return 0;
 
41
    }
 
42
 
 
43
#ifndef CNID_DB_CDB
 
44
    /* Do a little checkpointing if necessary.  I stuck it here as cnid_lookup
 
45
     * gets called when we do directory lookups.  Only do this if we're using
 
46
     * a read-write database. */
 
47
    if ((db->flags & CNIDFLAG_DB_RO) == 0) {
 
48
#ifdef DEBUG
 
49
        LOG(log_info, logtype_default, "cnid_lookup: Running database checkpoint");
 
50
#endif
 
51
#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
 
52
        db->dbenv->txn_checkpoint(db->dbenv, LOGFILEMAX, CHECKTIMEMAX, 0)
 
53
#else
 
54
#if DB_VERSION_MAJOR >= 4
 
55
        switch (rc = db->dbenv->txn_checkpoint(db->dbenv, LOGFILEMAX, CHECKTIMEMAX, 0)) {
 
56
#else
 
57
        switch (rc = txn_checkpoint(db->dbenv, LOGFILEMAX, CHECKTIMEMAX, 0)) {
 
58
#endif /* DB_VERSION_MAJOR >= 4 */
 
59
        case 0:
 
60
        case DB_INCOMPLETE:
 
61
            break;
 
62
        default:
 
63
            LOG(log_error, logtype_default, "cnid_lookup: txn_checkpoint: %s",
 
64
                db_strerror(rc));
 
65
            return 0;
 
66
        }
 
67
    }
 
68
#endif /* DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1) */
 
69
#endif /* CNID_DB_CDB */
 
70
 
 
71
        if ((buf = make_cnid_data(st, did, name, len)) == NULL) {
 
72
            LOG(log_error, logtype_default, "cnid_lookup: Pathname is too long");
 
73
            return 0;
 
74
        }
 
75
 
 
76
        memset(&key, 0, sizeof(key));
 
77
        memset(&devdata, 0, sizeof(devdata));
 
78
        memset(&diddata, 0, sizeof(diddata));
 
79
 
 
80
        /* Look for a CNID.  We have two options: dev/ino or did/name.  If we
 
81
         * only get a match in one of them, that means a file has moved. */
 
82
        key.data = buf;
 
83
        key.size = CNID_DEVINO_LEN;
 
84
        while ((rc = db->db_devino->get(db->db_devino, NULL, &key, &devdata, 0))) {
 
85
#ifndef CNID_DB_CDB
 
86
            if (rc == DB_LOCK_DEADLOCK) {
 
87
                continue;
 
88
            }
 
89
#endif /* CNID_DB_CDB */
 
90
 
 
91
            if (rc == DB_NOTFOUND) {
 
92
                devino = 0;
 
93
                break;
 
94
            }
 
95
 
 
96
            LOG(log_error, logtype_default, "cnid_lookup: Unable to get CNID dev %u, ino %u: %s",
 
97
                st->st_dev, st->st_ino, db_strerror(rc));
 
98
            return 0;
 
99
        }
 
100
 
 
101
        /* did/name now */
 
102
        key.data = buf + CNID_DEVINO_LEN;
 
103
        key.size = CNID_DID_LEN + len + 1;
 
104
        while ((rc = db->db_didname->get(db->db_didname, NULL, &key, &diddata, 0))) {
 
105
#ifndef CNID_DB_CDB
 
106
            if (rc == DB_LOCK_DEADLOCK) {
 
107
                continue;
 
108
            }
 
109
#endif /* CNID_DB_CDB */
 
110
 
 
111
            if (rc == DB_NOTFOUND) {
 
112
                didname = 0;
 
113
                break;
 
114
            }
 
115
 
 
116
            LOG(log_error, logtype_default, "cnid_lookup: Unable to get CNID %u, name %s: %s",
 
117
                ntohl(did), name, db_strerror(rc));
 
118
            return 0;
 
119
        }
 
120
 
 
121
        /* Set id.  Honor did/name over dev/ino as dev/ino isn't necessarily
 
122
         * 1-1. */
 
123
        if (didname) {
 
124
            memcpy(&id, diddata.data, sizeof(id));
 
125
        }
 
126
        else if (devino) {
 
127
            memcpy(&id, devdata.data, sizeof(id));
 
128
        }
 
129
 
 
130
        /* Either entries are in both databases or neither of them. */
 
131
        if ((devino && didname) || !(devino || didname)) {
 
132
#ifdef DEBUG
 
133
            LOG(log_info, logtype_default, "cnid_lookup: Looked up did %u, name %s, as %u",
 
134
                ntohl(did), name, ntohl(id));
 
135
#endif
 
136
            return id;
 
137
        }
 
138
 
 
139
        /* Fix up the database. */
 
140
        cnid_update(db, id, st, did, name, len);
 
141
#ifdef DEBUG
 
142
        LOG(log_info, logtype_default, "cnid_lookup: Looked up did %u, name %s, as %u (needed update)", ntohl(did), name, ntohl(id));
 
143
#endif
 
144
        return id;
 
145
    }
 
146
#endif /* CNID_DB */
 
147
 
 
148