2 * $Id: cnid.c,v 1.6 2009-11-19 06:40:51 didg Exp $
4 * Copyright (c) 2003 the Netatalk Team
5 * Copyright (c) 2003 Rafal Lewczuk <rlewczuk@pronet.pl>
7 * This program is free software; you can redistribute and/or modify
8 * it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation version 2 of the License or later
10 * version if explicitly stated by any of above copyright holders.
17 #endif /* HAVE_CONFIG_H */
19 #include <sys/types.h>
22 #include <sys/param.h>
30 #include <atalk/cnid.h>
31 #include <atalk/list.h>
32 #include <atalk/logger.h>
33 #include <atalk/util.h>
35 /* List of all registered modules. */
36 static struct list_head modules = ATALK_LIST_HEAD_INIT(modules);
38 static sigset_t sigblockset;
39 static const struct itimerval none = {{0, 0}, {0, 0}};
40 static struct itimerval savetimer;
42 /* Registers new CNID backend module. */
44 /* Once module has been registered, it cannot be unregistered. */
45 void cnid_register(struct _cnid_module *module)
47 struct list_head *ptr;
49 /* Check if our module is already registered. */
50 list_for_each(ptr, &modules)
51 if (0 == strcmp(list_entry(ptr, cnid_module, db_list)->name, module->name)) {
52 LOG(log_error, logtype_afpd, "Module with name [%s] is already registered !", module->name);
56 LOG(log_info, logtype_afpd, "Registering CNID module [%s]", module->name);
57 ptr = &(module->db_list);
58 list_add_tail(ptr, &modules);
62 static int cnid_dir(const char *dir, mode_t mask)
67 if (stat(dir, &st) < 0) {
70 if (ad_stat( dir, &st) < 0)
73 LOG(log_info, logtype_cnid, "Setting uid/gid to %d/%d", st.st_uid, st.st_gid);
74 if (setegid(st.st_gid) < 0 || seteuid(st.st_uid) < 0) {
75 LOG(log_error, logtype_cnid, "uid/gid: %s", strerror(errno));
79 if (mkdir(dir, 0777 & ~mask) < 0)
82 strlcpy(tmp, dir, sizeof(tmp));
83 strlcat(tmp, "/.AppleDB", sizeof(tmp));
84 if (stat(tmp, &st1) < 0) /* use .AppleDB owner, if folder already exists */
86 LOG(log_info, logtype_cnid, "Setting uid/gid to %d/%d", st1.st_uid, st1.st_gid);
87 if (setegid(st1.st_gid) < 0 || seteuid(st1.st_uid) < 0) {
88 LOG(log_error, logtype_cnid, "uid/gid: %s", strerror(errno));
95 /* Opens CNID database using particular back-end */
96 struct _cnid_db *cnid_open(const char *volpath, mode_t mask, char *type, int flags)
99 cnid_module *mod = NULL;
100 struct list_head *ptr;
104 list_for_each(ptr, &modules) {
105 if (0 == strcmp(list_entry(ptr, cnid_module, db_list)->name, type)) {
106 mod = list_entry(ptr, cnid_module, db_list);
112 LOG(log_error, logtype_afpd, "Cannot find module named [%s] in registered module list!", type);
116 if ((mod->flags & CNID_FLAG_SETUID)) {
120 LOG(log_error, logtype_afpd, "seteuid failed %s", strerror(errno));
123 if (cnid_dir(volpath, mask) < 0) {
124 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
125 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
132 db = mod->cnid_open(volpath, mask);
134 if ((mod->flags & CNID_FLAG_SETUID)) {
136 if ( setegid(gid) < 0 || seteuid(uid) < 0) {
137 LOG(log_error, logtype_afpd, "can't seteuid back %s", strerror(errno));
143 LOG(log_error, logtype_afpd, "Cannot open CNID db at [%s].", volpath);
146 /* FIXME should module know about it ? */
148 db->flags |= CNID_FLAG_NODEV;
150 db->flags |= mod->flags;
152 if ((db->flags & CNID_FLAG_BLOCK)) {
153 sigemptyset(&sigblockset);
154 sigaddset(&sigblockset, SIGTERM);
155 sigaddset(&sigblockset, SIGHUP);
156 sigaddset(&sigblockset, SIGUSR1);
157 sigaddset(&sigblockset, SIGUSR2);
158 sigaddset(&sigblockset, SIGALRM);
164 /* ------------------- */
165 static void block_signal( u_int32_t flags)
167 if ((flags & CNID_FLAG_BLOCK)) {
168 sigprocmask(SIG_BLOCK, &sigblockset, NULL);
169 setitimer(ITIMER_REAL, &none, &savetimer);
173 /* ------------------- */
174 static void unblock_signal(u_int32_t flags)
176 if ((flags & CNID_FLAG_BLOCK)) {
177 setitimer(ITIMER_REAL, &savetimer, NULL);
178 sigprocmask(SIG_UNBLOCK, &sigblockset, NULL);
182 /* Closes CNID database. Currently it's just a wrapper around db->cnid_close(). */
183 void cnid_close(struct _cnid_db *db)
188 LOG(log_error, logtype_afpd, "Error: cnid_close called with NULL argument !");
191 /* cnid_close free db */
195 unblock_signal(flags);
198 /* --------------- */
199 cnid_t cnid_add(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
200 char *name, const size_t len, cnid_t hint)
204 block_signal(cdb->flags);
205 ret = cdb->cnid_add(cdb, st, did, name, len, hint);
206 unblock_signal(cdb->flags);
210 /* --------------- */
211 int cnid_delete(struct _cnid_db *cdb, cnid_t id)
215 block_signal(cdb->flags);
216 ret = cdb->cnid_delete(cdb, id);
217 unblock_signal(cdb->flags);
222 /* --------------- */
223 cnid_t cnid_get(struct _cnid_db *cdb, const cnid_t did, char *name,const size_t len)
227 block_signal(cdb->flags);
228 ret = cdb->cnid_get(cdb, did, name, len);
229 unblock_signal(cdb->flags);
233 /* --------------- */
234 int cnid_getstamp(struct _cnid_db *cdb, void *buffer, const size_t len)
239 if (!cdb->cnid_getstamp) {
240 memset(buffer, 0, len);
241 /* return the current time. it will invalide cache */
242 if (len < sizeof(time_t))
245 memcpy(buffer, &t, sizeof(time_t));
248 block_signal(cdb->flags);
249 ret = cdb->cnid_getstamp(cdb, buffer, len);
250 unblock_signal(cdb->flags);
254 /* --------------- */
255 cnid_t cnid_lookup(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
256 char *name, const size_t len)
260 block_signal(cdb->flags);
261 ret = cdb->cnid_lookup(cdb, st, did, name, len);
262 unblock_signal(cdb->flags);
266 /* --------------- */
267 char *cnid_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, size_t len)
271 block_signal(cdb->flags);
272 ret = cdb->cnid_resolve(cdb, id, buffer, len);
273 unblock_signal(cdb->flags);
274 if (ret && !strcmp(ret, "..")) {
275 LOG(log_error, logtype_afpd, "cnid_resolve: name is '..', corrupted db? ");
281 /* --------------- */
282 int cnid_update (struct _cnid_db *cdb, const cnid_t id, const struct stat *st,
283 const cnid_t did, char *name, const size_t len)
287 block_signal(cdb->flags);
288 ret = cdb->cnid_update(cdb, id, st, did, name, len);
289 unblock_signal(cdb->flags);
293 /* --------------- */
294 cnid_t cnid_rebuild_add(struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
295 char *name, const size_t len, cnid_t hint)
299 block_signal(cdb->flags);
300 ret = cdb->cnid_rebuild_add(cdb, st, did, name, len, hint);
301 unblock_signal(cdb->flags);