return (ret < 0 ? ret : found);
}
+/*!
+ * Upgrade CNID database versions
+ *
+ * For now this does nothing, as upgrading from ver. 0 to 1 is done in dbif_open
+ */
+static int dbif_upgrade(DBD *dbd)
+{
+ int version;
+
+ if ((version = dbif_getversion(dbd)) == -1)
+ return -1;
+
+ /*
+ * Do upgrade stuff ...
+ */
+
+ /* Write current version to database */
+ if (version != CNID_VERSION) {
+ if (dbif_setversion(dbd, CNID_VERSION) != 0)
+ return -1;
+ }
+
+ LOG(log_debug, logtype_cnid, "Finished CNID database version upgrade check");
+
+ return 0;
+}
+
/* --------------- */
static int dbif_openlog(DBD *dbd)
{
LOG(log_error, logtype_cnid, "error forcing checkpoint: %s", db_strerror(ret));
return -1;
}
- LOG(log_debug, logtype_cnid, "Finished CNID database upgrade check");
+ LOG(log_debug, logtype_cnid, "Finished BerkeleyBD upgrade check");
}
if ((fchdir(cwd)) != 0) {
dbd->db_txn,
dbd->db_table[DBIF_IDX_NAME].db,
idxname,
- DB_CREATE))
- != 0) {
- LOG(log_error, logtype_cnid, "Failed to associate name index: %s",db_strerror(ret));
+ (reindex
+ ||
+ ((CNID_VERSION == CNID_VERSION_1) && (dbif_getversion(dbd) == CNID_VERSION_0)))
+ ? DB_CREATE : 0)) != 0) {
+ LOG(log_error, logtype_cnid, "Failed to associate name index: %s", db_strerror(ret));
return -1;
}
if (reindex)
LOG(log_info, logtype_cnid, "... done.");
+
+ if ((ret = dbif_upgrade(dbd)) != 0) {
+ LOG(log_error, logtype_cnid, "Error upgrading CNID database to version %d", CNID_VERSION);
+ return -1;
+ }
return 0;
}
In order to support silent database upgrades:
destroy env at cnid_dbd shutdown.
*/
-int dbif_prep_upgrade(const char *path)
+int dbif_env_remove(const char *path)
{
int ret;
DBD *dbd;
return 1;
}
+/*!
+ * Return CNID database version number
+ * @returns -1 on error, version number otherwise
+ */
+int dbif_getversion(DBD *dbd)
+{
+ DBT key, data;
+ uint32_t version;
+ int ret;
+
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+ key.data = ROOTINFO_KEY;
+ key.size = ROOTINFO_KEYLEN;
+
+ switch (dbif_get(dbd, DBIF_CNID, &key, &data, 0)) {
+ case 1:
+ memcpy(&version, (char *)data.data + CNID_DID_OFS, sizeof(version));
+ version = ntohl(version);
+ LOG(log_debug, logtype_cnid, "CNID database version %u", version);
+ ret = version;
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+ return ret;
+}
+
+/*!
+ * Return CNID database version number
+ * @returns -1 on error, version number otherwise
+ */
+int dbif_setversion(DBD *dbd, int version)
+{
+ DBT key, data;
+ uint32_t v;
+
+ v = version;
+ v = htonl(v);
+
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+ key.data = ROOTINFO_KEY;
+ key.size = ROOTINFO_KEYLEN;
+
+ switch (dbif_get(dbd, DBIF_CNID, &key, &data, 0)) {
+ case 1:
+ break;
+ default:
+ return -1;
+ }
+
+ memcpy((char *)data.data + CNID_DID_OFS, &v, sizeof(v));
+ data.size = ROOTINFO_DATALEN;
+ if (dbif_put(dbd, DBIF_CNID, &key, &data, 0) < 0)
+ return -1;
+
+ return 0;
+}
+
/*!
* Search the database by name
*
extern int dbif_env_open(DBD *dbd, struct db_param *dbp, uint32_t dbenv_oflags);
extern int dbif_open(DBD *dbd, struct db_param *dbp, int reindex);
extern int dbif_close(DBD *dbd);
-extern int dbif_prep_upgrade(const char *path);
+extern int dbif_env_remove(const char *path);
+extern int dbif_getversion(DBD *dbd);
+extern int dbif_setversion(DBD *dbd, int);
extern int dbif_get(DBD *, const int, DBT *, DBT *, u_int32_t);
extern int dbif_pget(DBD *, const int, DBT *, DBT *, DBT *, u_int32_t);
#define ROOTINFO_KEYLEN 4
/*
- Rootinfo data:
- 4 unused bytes (cnid)
- 8 bytes, in first 4 bytes db stamp: struct stat.st_ctime of database file (dev)
- 8 unused bytes (inode)
+ Rootinfo data, fields as they are used by normal entries for CNIDs (for reference):
+ 4 bytes: CNID
+ 8 bytes: dev
+ 8 bytes: inode
4 bytes: is a file/directory (type)
- 4 unused bytes (did)
- 9 bytes name "RootInfo"
+ 4 bytes: DID
+ x bytes: name
+
+ Contents in Rootinfo entry:
+ 4 bytes: 0
+ 8 bytes: db stamp: struct stat.st_ctime of database file
+ 8 bytes: unused
+ 4 bytes: last used CNID
+ 4 bytes: version as htonl(uint32_t)
+ 9 bytes: name "RootInfo"
*/
#define ROOTINFO_DATA "\0\0\0\0" \
"\0\0\0\0\0\0\0\0" \
"RootInfo"
#define ROOTINFO_DATALEN (3*4 + 2*8 + 9)
+/*
+ * CNID version history:
+ * 0: up to Netatalk 2.1.x
+ * 1: starting with 2.2, additional name index, used in cnid_find
+ */
+#define CNID_VERSION_0 0
+#define CNID_VERSION_1 1
+
+/* Current CNID version */
+#define CNID_VERSION CNID_VERSION_1
+
#endif