]> arthur.barton.de Git - netatalk.git/blob - libatalk/acl/cache.c
Merge from branch-2-1
[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     uuidp_t 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     uuidp_t uuid;
121     cacheduser_t *cacheduser = NULL;
122     cacheduser_t *entry;
123     unsigned char hash;
124
125 #ifdef DEBUG
126     dumpcache();
127 #endif
128
129     /* allocate mem and copy values */
130     name = malloc(strlen(inname)+1);
131     if (!name) {
132         LOG(log_error, logtype_default, "add_cachebyname: mallor error");
133         ret = -1;
134         goto cleanup;
135     }
136
137     uuid = malloc(UUID_BINSIZE);
138     if (!uuid) {
139         LOG(log_error, logtype_default, "add_cachebyname: mallor error");
140         ret = -1;
141         goto cleanup;
142     }
143
144     cacheduser = malloc(sizeof(cacheduser_t));
145     if (!cacheduser) {
146         LOG(log_error, logtype_default, "add_cachebyname: mallor error");
147         ret = -1;
148         goto cleanup;
149     }
150
151     strcpy(name, inname);
152     memcpy(uuid, inuuid, UUID_BINSIZE);
153
154     /* fill in the cacheduser */
155     cacheduser->name = name;
156     cacheduser->uuid = uuid;
157     cacheduser->type = type;
158     cacheduser->creationtime = time(NULL);
159     cacheduser->prev = NULL;
160     cacheduser->next = NULL;
161
162     /* get hash */
163     hash = hashstring((unsigned char *)name);
164
165     /* insert cache entry into cache array */
166     if (namecache[hash] == NULL) { /* this queue is empty */
167         namecache[hash] = cacheduser;
168     } else {            /* queue is not empty, search end of queue*/
169         entry = namecache[hash];
170         while( entry->next != NULL)
171             entry = entry->next;
172         cacheduser->prev = entry;
173         entry->next = cacheduser;
174     }
175
176 cleanup:
177     if (ret != 0) {
178         if (name)
179             free(name);
180         if (uuid)
181             free(uuid);
182         if (cacheduser)
183             free(cacheduser);
184     }
185
186 #ifdef DEBUG
187     dumpcache();
188 #endif
189
190     return ret;
191 }
192
193 /* 
194  * Caller provides buffer uuid for result
195  */
196 int search_cachebyname( const char *name, uuidtype_t type, uuidp_t uuid) {
197     int ret;
198     unsigned char hash;
199     cacheduser_t *entry;
200     time_t tim;
201
202 #ifdef DEBUG
203     dumpcache();
204 #endif
205
206     hash = hashstring((unsigned char *)name);
207
208     if (! namecache[hash])
209         return -1;
210
211     entry = namecache[hash];
212     while (entry) {
213         ret = strcmp(entry->name, name);
214         if (ret == 0 && type == entry->type) {
215             /* found, now check if expired */
216             tim = time(NULL);
217             if ((tim - entry->creationtime) > CACHESECONDS) {
218                 LOG(log_debug, logtype_default, "search_cachebyname: expired: name:\'%s\' in queue {%d}", entry->name, hash);
219                 /* remove item */
220                 if (entry->prev) /* 2nd to last in queue */
221                     entry->prev->next = entry->next;
222                 else  { /* queue head */
223                     if ((namecache[hash] = entry->next) != NULL)
224                         namecache[hash]->prev = NULL;
225                 }
226                 free(entry->name);
227                 free(entry->uuid);
228                 free(entry);
229 #ifdef DEBUG
230                 dumpcache();
231 #endif
232                 return -1;
233             } else {
234                 memcpy(uuid, entry->uuid, UUID_BINSIZE);
235 #ifdef DEBUG
236                 dumpcache();
237 #endif
238                 return 0;
239             }
240         }
241         entry = entry->next;
242     }
243 #ifdef DEBUG
244     dumpcache();
245 #endif
246     return -1;
247 }
248
249 /* 
250  * Caller must free allocated name
251  */
252 int search_cachebyuuid( uuidp_t uuidp, char **name, uuidtype_t *type) {
253     int ret;
254     unsigned char hash;
255     cacheduser_t *entry;
256     time_t tim;
257
258 #ifdef DEBUG
259     dumpcache();
260 #endif
261
262     hash = hashuuid(uuidp);
263
264     if (! uuidcache[hash])
265         return -1;
266
267     entry = uuidcache[hash];
268     while (entry) {
269         ret = memcmp(entry->uuid, uuidp, UUID_BINSIZE);
270         if (ret == 0) {
271             tim = time(NULL);
272             if ((tim - entry->creationtime) > CACHESECONDS) {
273                 LOG(log_debug, logtype_default, "search_cachebyuuid: expired: name:\'%s\' in queue {%d}", entry->name, hash);
274                 if (entry->prev) /* 2nd to last in queue */
275                     entry->prev->next = entry->next;
276                 else { /* queue head  */
277                     if ((uuidcache[hash] = entry->next) != NULL)
278                         uuidcache[hash]->prev = NULL;
279                 }
280                 free(entry->name);
281                 free(entry->uuid);
282                 free(entry);
283 #ifdef DEBUG
284                 dumpcache();
285 #endif
286                 return -1;
287             } else {
288                 *name = malloc(strlen(entry->name)+1);
289                 strcpy(*name, entry->name);
290                 *type = entry->type;
291 #ifdef DEBUG
292                 dumpcache();
293 #endif
294                 return 0;
295             }
296         }
297         entry = entry->next;
298     }
299
300 #ifdef DEBUG
301     dumpcache();
302 #endif
303
304     return -1;
305 }
306
307 int add_cachebyuuid( uuidp_t inuuid, const char *inname, uuidtype_t type, const unsigned long uid _U_) {
308     int ret = 0;
309     char *name = NULL;
310     uuidp_t uuid;
311     cacheduser_t *cacheduser = NULL;
312     cacheduser_t *entry;
313     unsigned char hash;
314
315 #ifdef DEBUG
316     dumpcache();
317 #endif
318
319     /* allocate mem and copy values */
320     name = malloc(strlen(inname)+1);
321     if (!name) {
322         LOG(log_error, logtype_default, "add_cachebyuuid: mallor error");
323         ret = -1;
324         goto cleanup;
325     }
326
327     uuid = malloc(UUID_BINSIZE);
328     if (!uuid) {
329         LOG(log_error, logtype_default, "add_cachebyuuid: mallor error");
330         ret = -1;
331         goto cleanup;
332     }
333
334     cacheduser = malloc(sizeof(cacheduser_t));
335     if (!cacheduser) {
336         LOG(log_error, logtype_default, "add_cachebyuuid: mallor error");
337         ret = -1;
338         goto cleanup;
339     }
340
341     strcpy(name, inname);
342     memcpy(uuid, inuuid, UUID_BINSIZE);
343
344     /* fill in the cacheduser */
345     cacheduser->name = name;
346     cacheduser->type = type;
347     cacheduser->uuid = uuid;
348     cacheduser->creationtime = time(NULL);
349     cacheduser->prev = NULL;
350     cacheduser->next = NULL;
351
352     /* get hash */
353     hash = hashuuid(uuid);
354
355     /* insert cache entry into cache array */
356     if (uuidcache[hash] == NULL) { /* this queue is empty */
357         uuidcache[hash] = cacheduser;
358     } else {            /* queue is not empty, search end of queue*/
359         entry = uuidcache[hash];
360         while( entry->next != NULL)
361             entry = entry->next;
362         cacheduser->prev = entry;
363         entry->next = cacheduser;
364     }
365
366 cleanup:
367     if (ret != 0) {
368         if (name)
369             free(name);
370         if (uuid)
371             free(uuid);
372         if (cacheduser)
373             free(cacheduser);
374     }
375
376 #ifdef DEBUG
377     dumpcache();
378 #endif
379
380     return ret;
381 }