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