]> arthur.barton.de Git - netatalk.git/blob - libatalk/acl/cache.c
Add LOG debug message on cache expiration
[netatalk.git] / libatalk / acl / cache.c
1 /*
2   $Id: cache.c,v 1.3 2009-11-28 12:37:30 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, cached: %s", i, entry->name, uuidstring, timestr);
66                 free(uuidstring);
67             } while ((entry = entry->next) != NULL);
68         }
69     }
70
71     for ( i=0; i<256; i++) {
72         if ((entry = uuidcache[i]) != NULL) {
73             do {
74                 uuid_bin2string(entry->uuid, &uuidstring);
75                 tmp = localtime(&entry->creationtime);
76                 if (tmp == NULL)
77                     continue;
78                 if (strftime(timestr, 200, "%c", tmp) == 0)
79                     continue;
80                 LOG(log_debug9, logtype_default, "uuidcache{%d}: uuid:%s, name:%s, type:%d, cached: %s", i, uuidstring, entry->name, entry->type,timestr);
81                 free(uuidstring);
82             } while ((entry = entry->next) != NULL);
83         }
84     }
85
86     return ret;
87 }
88
89 /* hash string it into unsigned char */
90 static unsigned char hashstring(unsigned char *str) {
91     unsigned long hash = 5381;
92     unsigned char index;
93     int c;
94     while ((c = *str++) != 0)
95         hash = ((hash << 5) + hash) ^ c; /* (hash * 33) ^ c */
96
97     index = 85 ^ (hash & 0xff);
98     while ((hash = hash >> 8) != 0)
99         index ^= (hash & 0xff);
100
101     return index;
102 }
103
104 /* hash uuid_t into unsigned char */
105 static unsigned char hashuuid(uuidp_t uuid) {
106     unsigned char index = 83;
107     int i;
108
109     for (i=0; i<16; i++) {
110         index ^= uuid[i];
111         index += uuid[i];
112     }
113     return index;
114 }
115
116 /********************************************************
117  * Interface
118  ********************************************************/
119
120 int add_cachebyname( const char *inname, const uuidp_t inuuid, const uuidtype_t type, const unsigned long uid _U_) {
121     int ret = 0;
122     char *name = NULL;
123     uuidp_t uuid;
124     cacheduser_t *cacheduser = NULL;
125     cacheduser_t *entry;
126     unsigned char hash;
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 */
165     if (namecache[hash] == NULL) { /* this queue is empty */
166         namecache[hash] = cacheduser;
167     } else {            /* queue is not empty, search end of queue*/
168         entry = namecache[hash];
169         while( entry->next != NULL)
170             entry = entry->next;
171         cacheduser->prev = entry;
172         entry->next = cacheduser;
173     }
174
175 cleanup:
176     if (ret != 0) {
177         if (name)
178             free(name);
179         if (uuid)
180             free(uuid);
181         if (cacheduser)
182             free(cacheduser);
183     }
184     return ret;
185 }
186
187 int search_cachebyname( const char *name, uuidtype_t type, uuidp_t uuid) {
188     int ret;
189     unsigned char hash;
190     cacheduser_t *entry;
191     time_t tim;
192
193     hash = hashstring((unsigned char *)name);
194
195     if (! namecache[hash])
196         return -1;
197
198     entry = namecache[hash];
199     while (entry) {
200         ret = strcmp(entry->name, name);
201         if (ret == 0 && type == entry->type) {
202             /* found, now check if expired */
203             tim = time(NULL);
204             if ((tim - entry->creationtime) > CACHESECONDS) {
205                 LOG(log_debug, logtype_default, "search_cachebyname: expired: name:\'%s\' in queue {%d}", entry->name, hash);
206                 /* remove item */
207                 if (entry->prev) /* 2nd to last in queue */
208                     entry->prev->next = entry->next;
209                 else        /* queue head */
210                     namecache[hash] = entry->next;
211                 free(entry->name);
212                 free(entry->uuid);
213                 free(entry);
214                 return -1;
215             } else {
216                 memcpy(uuid, entry->uuid, UUID_BINSIZE);
217                 return 0;
218             }
219         }
220         entry = entry->next;
221     }
222     return -1;
223 }
224
225 int search_cachebyuuid( uuidp_t uuidp, char **name, uuidtype_t *type) {
226     int ret;
227     unsigned char hash;
228     cacheduser_t *entry;
229     time_t tim;
230
231     hash = hashuuid(uuidp);
232
233     if (! uuidcache[hash])
234         return -1;
235
236     entry = uuidcache[hash];
237     while (entry) {
238         ret = memcmp(entry->uuid, uuidp, UUID_BINSIZE);
239         if (ret == 0) {
240             tim = time(NULL);
241             if ((tim - entry->creationtime) > CACHESECONDS) {
242                 LOG(log_info, logtype_default, "search_cachebyuuid: expired: name:\'%s\' in queue {%d}", entry->name, hash);
243                 if (entry->prev)
244                     entry->prev->next = entry->next;
245                 else
246                     uuidcache[hash] = entry->next;
247                 free(entry->name);
248                 free(entry->uuid);
249                 free(entry);
250                 return -1;
251             } else {
252                 *name = malloc(strlen(entry->name)+1);
253                 strcpy(*name, entry->name);
254                 *type = entry->type;
255                 return 0;
256             }
257         }
258         entry = entry->next;
259     }
260
261     return -1;
262 }
263
264 int add_cachebyuuid( uuidp_t inuuid, const char *inname, uuidtype_t type, const unsigned long uid _U_) {
265     int ret = 0;
266     char *name = NULL;
267     uuidp_t uuid;
268     cacheduser_t *cacheduser = NULL;
269     cacheduser_t *entry;
270     unsigned char hash;
271
272     /* allocate mem and copy values */
273     name = malloc(strlen(inname)+1);
274     if (!name) {
275         LOG(log_error, logtype_default, "add_cachebyuuid: mallor error");
276         ret = -1;
277         goto cleanup;
278     }
279
280     uuid = malloc(UUID_BINSIZE);
281     if (!uuid) {
282         LOG(log_error, logtype_default, "add_cachebyuuid: mallor error");
283         ret = -1;
284         goto cleanup;
285     }
286
287     cacheduser = malloc(sizeof(cacheduser_t));
288     if (!cacheduser) {
289         LOG(log_error, logtype_default, "add_cachebyuuid: mallor error");
290         ret = -1;
291         goto cleanup;
292     }
293
294     strcpy(name, inname);
295     memcpy(uuid, inuuid, UUID_BINSIZE);
296
297     /* fill in the cacheduser */
298     cacheduser->name = name;
299     cacheduser->type = type;
300     cacheduser->uuid = uuid;
301     cacheduser->creationtime = time(NULL);
302     cacheduser->prev = NULL;
303     cacheduser->next = NULL;
304
305     /* get hash */
306     hash = hashuuid(uuid);
307
308     /* insert cache entry into cache array */
309     if (uuidcache[hash] == NULL) { /* this queue is empty */
310         uuidcache[hash] = cacheduser;
311     } else {            /* queue is not empty, search end of queue*/
312         entry = uuidcache[hash];
313         while( entry->next != NULL)
314             entry = entry->next;
315         cacheduser->prev = entry;
316         entry->next = cacheduser;
317     }
318
319 cleanup:
320     if (ret != 0) {
321         if (name)
322             free(name);
323         if (uuid)
324             free(uuid);
325         if (cacheduser)
326             free(cacheduser);
327     }
328     return ret;
329 }