]> arthur.barton.de Git - netatalk.git/blob - libatalk/cnid/tdb/cnid_tdb_open.c
d1072afefa6ebea66436f9cc21d13ad2bb4dbaaf
[netatalk.git] / libatalk / cnid / tdb / cnid_tdb_open.c
1 /*
2  * $Id: cnid_tdb_open.c,v 1.4 2009-11-20 17:37:14 didg Exp $
3  *
4  * Copyright (c) 1999. Adrian Sun (asun@zoology.washington.edu)
5  * All Rights Reserved. See COPYRIGHT.
6  *
7  */
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif
11
12 #ifdef CNID_BACKEND_TDB
13 #include <sys/param.h>   
14
15 #include "cnid_tdb.h"
16 #include <atalk/logger.h>
17 #include <stdlib.h>
18 #define DBHOME       ".AppleDB"
19 #define DBNAME       "private_tdb.%sX"
20 #define DBHOMELEN    9                  /* strlen(DBHOME) +1 for / */
21 #define DBLEN        12
22 #define DBCNID       "cnid.tdb"
23 #define DBDEVINO     "devino.tdb"
24 #define DBDIDNAME    "didname.tdb"      /* did/full name mapping */
25
26 #define DBVERSION_KEY    "\0\0\0\0Version"
27 #define DBVERSION_KEYLEN (sizeof(DBVERSION_KEY))
28 #define DBVERSION1       0x00000001U
29 #define DBVERSION        DBVERSION1
30
31 static struct _cnid_db *cnid_tdb_new(const char *volpath)
32 {
33     struct _cnid_db *cdb;
34     struct _cnid_tdb_private *priv;
35
36     if ((cdb = (struct _cnid_db *) calloc(1, sizeof(struct _cnid_db))) == NULL)
37         return NULL;
38
39     if ((cdb->volpath = strdup(volpath)) == NULL) {
40         free(cdb);
41         return NULL;
42     }
43
44     if ((cdb->_private = calloc(1, sizeof(struct _cnid_tdb_private))) == NULL) {
45         free(cdb->volpath);
46         free(cdb);
47         return NULL;
48     }
49
50     /* Set up private state */
51     priv = (struct _cnid_tdb_private *) (cdb->_private);
52
53     /* Set up standard fields */
54     cdb->flags = CNID_FLAG_PERSISTENT;
55
56     cdb->cnid_add = cnid_tdb_add;
57     cdb->cnid_delete = cnid_tdb_delete;
58     cdb->cnid_get = cnid_tdb_get;
59     cdb->cnid_lookup = cnid_tdb_lookup;
60     cdb->cnid_nextid = NULL;    /*cnid_tdb_nextid;*/
61     cdb->cnid_resolve = cnid_tdb_resolve;
62     cdb->cnid_update = cnid_tdb_update;
63     cdb->cnid_close = cnid_tdb_close;
64     
65     return cdb;
66 }
67
68 /* ---------------------------- */
69 struct _cnid_db *cnid_tdb_open(const char *dir, mode_t mask)
70 {
71     struct stat               st;
72     struct _cnid_db           *cdb;
73     struct _cnid_tdb_private *db;
74     size_t                    len;
75     char                      path[MAXPATHLEN + 1];
76     TDB_DATA                  key, data;
77     
78     if (!dir) {
79         return NULL;
80     }
81
82     if ((len = strlen(dir)) > (MAXPATHLEN - DBLEN - 1)) {
83         LOG(log_error, logtype_default, "tdb_open: Pathname too large: %s", dir);
84         return NULL;
85     }
86     
87     if ((cdb = cnid_tdb_new(dir)) == NULL) {
88         LOG(log_error, logtype_default, "tdb_open: Unable to allocate memory for tdb");
89         return NULL;
90     }
91     strcpy(path, dir);
92     if (path[len - 1] != '/') {
93         strcat(path, "/");
94         len++;
95     }
96  
97     strcpy(path + len, DBHOME);
98     if ((stat(path, &st) < 0) && (ad_mkdir(path, 0777 & ~mask) < 0)) {
99         LOG(log_error, logtype_default, "tdb_open: DBHOME mkdir failed for %s", path);
100         goto fail;
101     }
102     strcat(path, "/");
103  
104     db = (struct _cnid_tdb_private *)cdb->_private;
105
106     path[len + DBHOMELEN] = '\0';
107     strcat(path, DBCNID);
108     db->tdb_cnid = tdb_open(path, 0, 0 , O_RDWR | O_CREAT, 0666 & ~mask);
109     if (!db->tdb_cnid) {
110         LOG(log_error, logtype_default, "tdb_open: unable to open tdb", path);
111         goto fail;
112     }
113     /* ------------- */
114
115     path[len + DBHOMELEN] = '\0';
116     strcat(path, DBDIDNAME);
117     db->tdb_didname = tdb_open(path, 0, 0 , O_RDWR | O_CREAT, 0666 & ~mask);
118     if (!db->tdb_cnid) {
119         LOG(log_error, logtype_default, "tdb_open: unable to open tdb", path);
120         goto fail;
121     }
122     /* Check for version.  This way we can update the database if we need
123      * to change the format in any way. */
124     memset(&key, 0, sizeof(key));
125     memset(&data, 0, sizeof(data));
126     key.dptr = DBVERSION_KEY;
127     key.dsize = DBVERSION_KEYLEN;
128
129     data = tdb_fetch(db->tdb_didname, key);
130     if (!data.dptr) {
131         u_int32_t version = htonl(DBVERSION);
132
133         data.dptr = (char *)&version;
134         data.dsize = sizeof(version);
135         if (tdb_store(db->tdb_didname, key, data, TDB_REPLACE)) {
136             LOG(log_error, logtype_default, "tdb_open: Error putting new version");
137             goto fail;
138         }
139     }
140     else {
141         free(data.dptr);
142     }
143         
144     /* ------------- */
145     path[len + DBHOMELEN] = '\0';
146     strcat(path, DBDEVINO);
147     db->tdb_devino = tdb_open(path, 0, 0 , O_RDWR | O_CREAT, 0666 & ~mask);
148     if (!db->tdb_devino) {
149         LOG(log_error, logtype_default, "tdb_open: unable to open tdb", path);
150         goto fail;
151     }
152
153     return cdb;
154
155 fail:
156     free(cdb->_private);
157     free(cdb->volpath);
158     free(cdb);
159     
160     return NULL;
161 }
162
163 struct _cnid_module cnid_tdb_module = {
164     "tdb",
165     {NULL, NULL},
166     cnid_tdb_open,
167     CNID_FLAG_SETUID | CNID_FLAG_BLOCK
168 };
169
170
171 #endif