]> arthur.barton.de Git - netatalk.git/blob - libatalk/acl/cache.c
Merge master
[netatalk.git] / libatalk / acl / cache.c
1 /*
2   Copyright (c) 2008,2009 Frank Lahm <franklahm@gmail.com>
3
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License as published by
6   the Free Software Foundation; either version 2 of the License, or
7   (at your option) any later version.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13 */
14
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif /* HAVE_CONFIG_H */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <time.h>
23 #include <errno.h>
24
25 #include <atalk/logger.h>
26 #include <atalk/afp.h>
27 #include <atalk/uuid.h>
28 #include "cache.h"
29
30 typedef struct cacheduser {
31     unsigned long uid;      /* for future use */
32     uuidtype_t type;
33     unsigned char *uuid;
34     char *name;
35     time_t creationtime;
36     struct cacheduser *prev;
37     struct cacheduser *next;
38 } cacheduser_t;
39
40 cacheduser_t *namecache[256];   /* indexed by hash of name */
41 cacheduser_t *uuidcache[256];   /* indexed by hash of uuid */
42
43 /********************************************************
44  * helper function
45  ********************************************************/
46
47 static int dumpcache() {
48     int i;
49     int ret = 0;
50     cacheduser_t *entry;
51     char timestr[200];
52     struct tm *tmp = NULL;
53
54     for ( i=0 ; i<256; i++) {
55         if ((entry = namecache[i]) != NULL) {
56             do {
57                 tmp = localtime(&entry->creationtime);
58                 if (tmp == NULL)
59                     continue;
60                 if (strftime(timestr, 200, "%c", tmp) == 0)
61                     continue;
62                 LOG(log_debug9, logtype_default, "namecache{%d}: name:%s, uuid:%s, type: %s, cached: %s",
63                     i, entry->name, uuid_bin2string(entry->uuid), uuidtype[entry->type], timestr);
64             } while ((entry = entry->next) != NULL);
65         }
66     }
67
68     for ( i=0; i<256; i++) {
69         if ((entry = uuidcache[i]) != NULL) {
70             do {
71
72                 tmp = localtime(&entry->creationtime);
73                 if (tmp == NULL)
74                     continue;
75                 if (strftime(timestr, 200, "%c", tmp) == 0)
76                     continue;
77                 LOG(log_debug9, logtype_default, "uuidcache{%d}: uuid:%s, name:%s, type: %s, cached: %s",
78                     i, uuid_bin2string(entry->uuid), entry->name, uuidtype[entry->type], timestr);
79             } while ((entry = entry->next) != NULL);
80         }
81     }
82
83     return ret;
84 }
85
86 /* hash string it into unsigned char */
87 static unsigned char hashstring(unsigned char *str) {
88     unsigned long hash = 5381;
89     unsigned char index;
90     int c;
91     while ((c = *str++) != 0)
92         hash = ((hash << 5) + hash) ^ c; /* (hash * 33) ^ c */
93
94     index = 85 ^ (hash & 0xff);
95     while ((hash = hash >> 8) != 0)
96         index ^= (hash & 0xff);
97
98     return index;
99 }
100
101 /* hash atalk_uuid_t into unsigned char */
102 static unsigned char hashuuid(uuidp_t uuid) {
103     unsigned char index = 83;
104     int i;
105
106     for (i=0; i<16; i++) {
107         index ^= uuid[i];
108         index += uuid[i];
109     }
110     return index;
111 }
112
113 /********************************************************
114  * Interface
115  ********************************************************/
116
117 int add_cachebyname( const char *inname, const uuidp_t inuuid, const uuidtype_t type, const unsigned long uid _U_) {
118     int ret = 0;
119     char *name = NULL;
120     unsigned char *uuid = NULL;
121     cacheduser_t *cacheduser = NULL;
122     unsigned char hash;
123
124 #ifdef DEBUG
125     dumpcache();
126 #endif
127
128     /* allocate mem and copy values */
129     name = malloc(strlen(inname)+1);
130     if (!name) {
131         LOG(log_error, logtype_default, "add_cachebyname: mallor error");
132         ret = -1;
133         goto cleanup;
134     }
135
136     uuid = malloc(UUID_BINSIZE);
137     if (!uuid) {
138         LOG(log_error, logtype_default, "add_cachebyname: mallor error");
139         ret = -1;
140         goto cleanup;
141     }
142
143     cacheduser = malloc(sizeof(cacheduser_t));
144     if (!cacheduser) {
145         LOG(log_error, logtype_default, "add_cachebyname: mallor error");
146         ret = -1;
147         goto cleanup;
148     }
149
150     strcpy(name, inname);
151     memcpy(uuid, inuuid, UUID_BINSIZE);
152
153     /* fill in the cacheduser */
154     cacheduser->name = name;
155     cacheduser->uuid = uuid;
156     cacheduser->type = type;
157     cacheduser->creationtime = time(NULL);
158     cacheduser->prev = NULL;
159     cacheduser->next = NULL;
160
161     /* get hash */
162     hash = hashstring((unsigned char *)name);
163
164     /* insert cache entry into cache array at head of queue */
165     if (namecache[hash] == NULL) {
166         /* this queue is empty */
167         namecache[hash] = cacheduser;
168     } else {
169         cacheduser->next = namecache[hash];
170         namecache[hash]->prev = cacheduser;
171         namecache[hash] = cacheduser;
172     }
173
174 cleanup:
175     if (ret != 0) {
176         if (name)
177             free(name);
178         if (uuid)
179             free(uuid);
180         if (cacheduser)
181             free(cacheduser);
182     }
183
184 #ifdef DEBUG
185     dumpcache();
186 #endif
187
188     return ret;
189 }
190
191 /* 
192  * Caller provides buffer uuid for result
193  */
194 int search_cachebyname( const char *name, uuidtype_t type, unsigned char *uuid) {
195     int ret;
196     unsigned char hash;
197     cacheduser_t *entry;
198     time_t tim;
199
200 #ifdef DEBUG
201     dumpcache();
202 #endif
203
204     hash = hashstring((unsigned char *)name);
205
206     if (namecache[hash] == NULL)
207         return -1;
208
209     entry = namecache[hash];
210     while (entry) {
211         ret = strcmp(entry->name, name);
212         if (ret == 0 && type == entry->type) {
213             /* found, now check if expired */
214             tim = time(NULL);
215             if ((tim - entry->creationtime) > CACHESECONDS) {
216                 LOG(log_debug, logtype_default, "search_cachebyname: expired: name:\'%s\' in queue {%d}", entry->name, hash);
217                 /* remove item */
218                 if (entry->prev) {
219                     /* 2nd to last in queue */
220                     entry->prev->next = entry->next;
221                     if (entry->next)
222                         /* not the last element */
223                         entry->next->prev = entry->prev;
224                 } else  {
225                     /* queue head */
226                     if ((namecache[hash] = entry->next) != NULL)
227                         namecache[hash]->prev = NULL;
228                 }
229                 free(entry->name);
230                 free(entry->uuid);
231                 free(entry);
232 #ifdef DEBUG
233                 dumpcache();
234 #endif
235                 return -1;
236             } else {
237                 memcpy(uuid, entry->uuid, UUID_BINSIZE);
238 #ifdef DEBUG
239                 dumpcache();
240 #endif
241                 return 0;
242             }
243         }
244         entry = entry->next;
245     }
246 #ifdef DEBUG
247     dumpcache();
248 #endif
249     return -1;
250 }
251
252 /* 
253  * Caller must free allocated name
254  */
255 int search_cachebyuuid( uuidp_t uuidp, char **name, uuidtype_t *type) {
256     int ret;
257     unsigned char hash;
258     cacheduser_t *entry;
259     time_t tim;
260
261 #ifdef DEBUG
262     dumpcache();
263 #endif
264
265     hash = hashuuid(uuidp);
266
267     if (! uuidcache[hash])
268         return -1;
269
270     entry = uuidcache[hash];
271     while (entry) {
272         ret = memcmp(entry->uuid, uuidp, UUID_BINSIZE);
273         if (ret == 0) {
274             tim = time(NULL);
275             if ((tim - entry->creationtime) > CACHESECONDS) {
276                 LOG(log_debug, logtype_default, "search_cachebyuuid: expired: name:\'%s\' in queue {%d}", entry->name, hash);
277                 if (entry->prev) {
278                     /* 2nd to last in queue */
279                     entry->prev->next = entry->next;
280                     if (entry->next)
281                         /* not the last element */
282                         entry->next->prev = entry->prev;
283                 } else {
284                     /* queue head  */
285                     if ((uuidcache[hash] = entry->next) != NULL)
286                         uuidcache[hash]->prev = NULL;
287                 }
288                 free(entry->name);
289                 free(entry->uuid);
290                 free(entry);
291 #ifdef DEBUG
292                 dumpcache();
293 #endif
294                 return -1;
295             } else {
296                 *name = malloc(strlen(entry->name)+1);
297                 strcpy(*name, entry->name);
298                 *type = entry->type;
299 #ifdef DEBUG
300                 dumpcache();
301 #endif
302                 return 0;
303             }
304         }
305         entry = entry->next;
306     }
307
308 #ifdef DEBUG
309     dumpcache();
310 #endif
311
312     return -1;
313 }
314
315 int add_cachebyuuid( uuidp_t inuuid, const char *inname, uuidtype_t type, const unsigned long uid _U_) {
316     int ret = 0;
317     char *name = NULL;
318     unsigned char *uuid = NULL;
319     cacheduser_t *cacheduser = NULL;
320     cacheduser_t *entry;
321     unsigned char hash;
322
323 #ifdef DEBUG
324     dumpcache();
325 #endif
326
327     /* allocate mem and copy values */
328     name = malloc(strlen(inname)+1);
329     if (!name) {
330         LOG(log_error, logtype_default, "add_cachebyuuid: mallor error");
331         ret = -1;
332         goto cleanup;
333     }
334
335     uuid = malloc(UUID_BINSIZE);
336     if (!uuid) {
337         LOG(log_error, logtype_default, "add_cachebyuuid: mallor error");
338         ret = -1;
339         goto cleanup;
340     }
341
342     cacheduser = malloc(sizeof(cacheduser_t));
343     if (!cacheduser) {
344         LOG(log_error, logtype_default, "add_cachebyuuid: mallor error");
345         ret = -1;
346         goto cleanup;
347     }
348
349     strcpy(name, inname);
350     memcpy(uuid, inuuid, UUID_BINSIZE);
351
352     /* fill in the cacheduser */
353     cacheduser->name = name;
354     cacheduser->type = type;
355     cacheduser->uuid = uuid;
356     cacheduser->creationtime = time(NULL);
357     cacheduser->prev = NULL;
358     cacheduser->next = NULL;
359
360     /* get hash */
361     hash = hashuuid(uuid);
362
363     /* insert cache entry into cache array at head of queue */
364     if (uuidcache[hash] == NULL) {
365         /* this queue is empty */
366         uuidcache[hash] = cacheduser;
367     } else {
368         cacheduser->next = uuidcache[hash];
369         uuidcache[hash]->prev = cacheduser;
370         uuidcache[hash] = cacheduser;
371     }
372
373 cleanup:
374     if (ret != 0) {
375         if (name)
376             free(name);
377         if (uuid)
378             free(uuid);
379         if (cacheduser)
380             free(cacheduser);
381     }
382
383 #ifdef DEBUG
384     dumpcache();
385 #endif
386
387     return ret;
388 }