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#include <string.h> 12#ifdef HAVE_UNISTD_H 13#include <unistd.h> 14#endif /* HAVE_UNISTD_H */ 15#ifdef HAVE_FCNTL_H 16#include <fcntl.h> 17#endif /* HAVE_FCNTL_H */ 18#include <errno.h> 19#ifdef HAVE_SYS_TIME_H 20#include <sys/time.h> 21#endif /* HAVE_SYS_TIME_H */ 22 23#include <atalk/logger.h> 24#include <atalk/cnid_dbd_private.h> 25#include <atalk/cnid.h> 26#ifdef HAVE_DB4_DB_H 27#include <db4/db.h> 28#else 29#include <db.h> 30#endif 31 32#include "dbif.h" 33#include "pack.h" 34#include "dbd.h" 35 36int add_cnid(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply) 37{ 38 DBT key, data; 39 int rc; 40 41 memset(&key, 0, sizeof(key)); 42 memset(&data, 0, sizeof(data)); 43 44 key.data = &rply->cnid; 45 key.size = sizeof(rply->cnid); 46 47 data.data = pack_cnid_data(rqst); 48 data.size = CNID_HEADER_LEN + rqst->namelen + 1; 49 memcpy(data.data, &rply->cnid, sizeof(rply->cnid)); 50 51 /* main database */ 52 if ((rc = dbif_put(dbd, DBIF_CNID, &key, &data, DB_NOOVERWRITE))) { 53 /* This could indicate a database error or that the key already exists 54 (because of DB_NOOVERWRITE). In that case we still look at some sort of 55 database corruption since that is not supposed to happen. */ 56 57 switch (rc) { 58 case 1: 59 rply->result = CNID_DBD_RES_ERR_DUPLCNID; 60 break; 61 case -1: 62 /* FIXME: Should that not be logged for case 1:? */ 63 LOG(log_error, logtype_cnid, "add_cnid: duplicate %x %s", rply->cnid 64 , (char *)data.data + CNID_NAME_OFS); 65 66 rqst->cnid = rply->cnid; 67 rc = dbd_update(dbd, rqst, rply); 68 if (rc < 0) { 69 rply->result = CNID_DBD_RES_ERR_DB; 70 return -1; 71 } 72 else 73 return 0; 74 break; 75 } 76 return -1; 77 } 78 79 return 0; 80} 81 82/* ---------------------- */ 83int get_cnid(DBD *dbd, struct cnid_dbd_rply *rply) 84{ 85 static cnid_t id; 86 static char buf[ROOTINFO_DATALEN]; 87 DBT rootinfo_key, rootinfo_data; 88 int rc; 89 cnid_t hint; 90 91 memset(&rootinfo_key, 0, sizeof(rootinfo_key)); 92 memset(&rootinfo_data, 0, sizeof(rootinfo_data)); 93 rootinfo_key.data = ROOTINFO_KEY; 94 rootinfo_key.size = ROOTINFO_KEYLEN; 95 96 if (id == 0) { 97 if ((rc = dbif_get(dbd, DBIF_CNID, &rootinfo_key, &rootinfo_data, 0)) < 0) { 98 rply->result = CNID_DBD_RES_ERR_DB; 99 return -1; 100 } 101 if (rc == 0) { 102 /* no rootinfo key yet */ 103 memcpy(buf, ROOTINFO_DATA, ROOTINFO_DATALEN); 104 id = CNID_START - 1; 105 } else { 106 memcpy(buf, (char *)rootinfo_data.data, ROOTINFO_DATALEN); 107 memcpy(&hint, buf + CNID_TYPE_OFS, sizeof(hint)); 108 id = ntohl(hint); 109 if (id < CNID_START - 1) 110 id = CNID_START - 1; 111 } 112 } 113 114 /* If we've hit the max CNID allowed, we return an error. CNID 115 * needs to be recycled before proceding. */ 116 if (++id == CNID_INVALID) { 117 rply->result = CNID_DBD_RES_ERR_MAX; 118 return -1; 119 } 120 121 rootinfo_data.data = buf; 122 rootinfo_data.size = ROOTINFO_DATALEN; 123 hint = htonl(id); 124 memcpy(buf + CNID_TYPE_OFS, &hint, sizeof(hint)); 125 126 if (dbif_put(dbd, DBIF_CNID, &rootinfo_key, &rootinfo_data, 0) < 0) { 127 rply->result = CNID_DBD_RES_ERR_DB; 128 return -1; 129 } 130 rply->cnid = hint; 131 return 0; 132} 133 134/* ------------------------ */ 135/* We need a nolookup version for `dbd` */ 136int dbd_add(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply, int nolookup) 137{ 138 rply->namelen = 0; 139 140 LOG(log_debug, logtype_cnid, "dbd_add(did:%u, '%s', dev/ino:0x%llx/0x%llx) {start}", 141 ntohl(rqst->did), rqst->name, (unsigned long long)rqst->dev, (unsigned long long)rqst->ino); 142 143 /* See if we have an entry already and return it if yes */ 144 if (! nolookup) { 145 if (dbd_lookup(dbd, rqst, rply, 0) < 0) { 146 LOG(log_debug, logtype_cnid, "dbd_add(did:%u, '%s', dev/ino:0x%llx/0x%llx): error in dbd_lookup", 147 ntohl(rqst->did), rqst->name, (unsigned long long)rqst->dev, (unsigned long long)rqst->ino); 148 return -1; 149 } 150 151 if (rply->result == CNID_DBD_RES_OK) { 152 /* Found it. rply->cnid is the correct CNID now. */ 153 LOG(log_debug, logtype_cnid, "dbd_add: dbd_lookup success --> CNID: %u", ntohl(rply->cnid)); 154 return 1; 155 } 156 } 157 158 LOG(log_debug, logtype_cnid, "dbd_add(did:%u, '%s', dev/ino:0x%llx/0x%llx): {adding to database ...}", 159 ntohl(rqst->did), rqst->name, (unsigned long long)rqst->dev, (unsigned long long)rqst->ino); 160 161 162 if (get_cnid(dbd, rply) < 0) { 163 if (rply->result == CNID_DBD_RES_ERR_MAX) { 164 LOG(log_error, logtype_cnid, "dbd_add: FATAL: CNID database has reached its limit."); 165 /* This will cause an abort/rollback if transactions are used */ 166 return 0; 167 } else { 168 LOG(log_error, logtype_cnid, "dbd_add: Failed to compute CNID for %s, error reading/updating Rootkey", rqst->name); 169 return -1; 170 } 171 } 172 173 if (add_cnid(dbd, rqst, rply) < 0) { 174 if (rply->result == CNID_DBD_RES_ERR_DUPLCNID) { 175 LOG(log_error, logtype_cnid, "dbd_add(DID: %u/\"%s\", dev/ino 0x%llx/0x%llx): Cannot add CNID: %u", 176 ntohl(rqst->did), rqst->name, (unsigned long long)rqst->dev, (unsigned long long)rqst->ino, ntohl(rply->cnid)); 177 /* abort/rollback, see above */ 178 return 0; 179 } else { 180 LOG(log_error, logtype_cnid, "dbd_add: Failed to add CNID for %s to database", rqst->name); 181 return -1; 182 } 183 } 184 LOG(log_debug, logtype_cnid, "dbd_add(did:%u, '%s', dev/ino:0x%llx/0x%llx): Added with CNID: %u", 185 ntohl(rqst->did), rqst->name, (unsigned long long)rqst->dev, (unsigned long long)rqst->ino, ntohl(rply->cnid)); 186 187 rply->result = CNID_DBD_RES_OK; 188 return 1; 189} 190