]> arthur.barton.de Git - netatalk.git/blob - libatalk/acl/cache.c
Enhanced machine type
[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 *uuidstring = NULL;
52     char timestr[200];
53     struct tm *tmp = NULL;
54
55     for ( i=0 ; i<256; i++) {
56         if ((entry = namecache[i]) != NULL) {
57             do {
58                 uuid_bin2string(entry->uuid, &uuidstring);
59                 tmp = localtime(&entry->creationtime);
60                 if (tmp == NULL)
61                     continue;
62                 if (strftime(timestr, 200, "%c", tmp) == 0)
63                     continue;
64                 LOG(log_debug9, logtype_default, "namecache{%d}: name:%s, uuid:%s, type: %s, cached: %s",
65                     i, entry->name, uuidstring, uuidtype[entry->type], 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: %s, cached: %s",
81                     i, uuidstring, entry->name, uuidtype[entry->type], timestr);
82                 free(uuidstring);
83             } while ((entry = entry->next) != NULL);
84         }
85     }
86
87     return ret;
88 }
89
90 /* hash string it into unsigned char */
91 static unsigned char hashstring(unsigned char *str) {
92     unsigned long hash = 5381;
93     unsigned char index;
94     int c;
95     while ((c = *str++) != 0)
96         hash = ((hash << 5) + hash) ^ c; /* (hash * 33) ^ c */
97
98     index = 85 ^ (hash & 0xff);
99     while ((hash = hash >> 8) != 0)
100         index ^= (hash & 0xff);
101
102     return index;
103 }
104
105 /* hash uuid_t into unsigned char */
106 static unsigned char hashuuid(uuidp_t uuid) {
107     unsigned char index = 83;
108     int i;
109
110     for (i=0; i<16; i++) {
111         index ^= uuid[i];
112         index += uuid[i];
113     }
114     return index;
115 }
116
117 /********************************************************
118  * Interface
119  ********************************************************/
120
121 int add_cachebyname( const char *inname, const uuidp_t inuuid, const uuidtype_t type, const unsigned long uid _U_) {
122     int ret = 0;
123     char *name = NULL;
124     uuidp_t uuid;
125     cacheduser_t *cacheduser = NULL;
126     unsigned char hash;
127
128 #ifdef DEBUG
129     dumpcache();
130 #endif
131
132     /* allocate mem and copy values */
133     name = malloc(strlen(inname)+1);
134     if (!name) {
135         LOG(log_error, logtype_default, "add_cachebyname: mallor error");
136         ret = -1;
137         goto cleanup;
138     }
139
140     uuid = malloc(UUID_BINSIZE);
141     if (!uuid) {
142         LOG(log_error, logtype_default, "add_cachebyname: mallor error");
143         ret = -1;
144         goto cleanup;
145     }
146
147     cacheduser = malloc(sizeof(cacheduser_t));
148     if (!cacheduser) {
149         LOG(log_error, logtype_default, "add_cachebyname: mallor error");
150         ret = -1;
151         goto cleanup;
152     }
153
154     strcpy(name, inname);
155     memcpy(uuid, inuuid, UUID_BINSIZE);
156
157     /* fill in the cacheduser */
158     cacheduser->name = name;
159     cacheduser->uuid = uuid;
160     cacheduser->type = type;
161     cacheduser->creationtime = time(NULL);
162     cacheduser->prev = NULL;
163     cacheduser->next = NULL;
164
165     /* get hash */
166     hash = hashstring((unsigned char *)name);
167
168     /* insert cache entry into cache array at head of queue */
169     if (namecache[hash] == NULL) {
170         /* this queue is empty */
171         namecache[hash] = cacheduser;
172     } else {
173         cacheduser->next = namecache[hash];
174         namecache[hash]->prev = cacheduser;
175         namecache[hash] = cacheduser;
176     }
177
178 cleanup:
179     if (ret != 0) {
180         if (name)
181             free(name);
182         if (uuid)
183             free(uuid);
184         if (cacheduser)
185             free(cacheduser);
186     }
187
188 #ifdef DEBUG
189     dumpcache();
190 #endif
191
192     return ret;
193 }
194
195 /* 
196  * Caller provides buffer uuid for result
197  */
198 int search_cachebyname( const char *name, uuidtype_t type, uuidp_t uuid) {
199     int ret;
200     unsigned char hash;
201     cacheduser_t *entry;
202     time_t tim;
203
204 #ifdef DEBUG
205     dumpcache();
206 #endif
207
208     hash = hashstring((unsigned char *)name);
209
210     if (namecache[hash] == NULL)
211         return -1;
212
213     entry = namecache[hash];
214     while (entry) {
215         ret = strcmp(entry->name, name);
216         if (ret == 0 && type == entry->type) {
217             /* found, now check if expired */
218             tim = time(NULL);
219             if ((tim - entry->creationtime) > CACHESECONDS) {
220                 LOG(log_debug, logtype_default, "search_cachebyname: expired: name:\'%s\' in queue {%d}", entry->name, hash);
221                 /* remove item */
222                 if (entry->prev) {
223                     /* 2nd to last in queue */
224                     entry->prev->next = entry->next;
225                     if (entry->next)
226                         /* not the last element */
227                         entry->next->prev = entry->prev;
228                 } else  {
229                     /* queue head */
230                     if ((namecache[hash] = entry->next) != NULL)
231                         namecache[hash]->prev = NULL;
232                 }
233                 free(entry->name);
234                 free(entry->uuid);
235                 free(entry);
236 #ifdef DEBUG
237                 dumpcache();
238 #endif
239                 return -1;
240             } else {
241                 memcpy(uuid, entry->uuid, UUID_BINSIZE);
242 #ifdef DEBUG
243                 dumpcache();
244 #endif
245                 return 0;
246             }
247         }
248         entry = entry->next;
249     }
250 #ifdef DEBUG
251     dumpcache();
252 #endif
253     return -1;
254 }
255
256 /* 
257  * Caller must free allocated name
258  */
259 int search_cachebyuuid( uuidp_t uuidp, char **name, uuidtype_t *type) {
260     int ret;
261     unsigned char hash;
262     cacheduser_t *entry;
263     time_t tim;
264
265 #ifdef DEBUG
266     dumpcache();
267 #endif
268
269     hash = hashuuid(uuidp);
270
271     if (! uuidcache[hash])
272         return -1;
273
274     entry = uuidcache[hash];
275     while (entry) {
276         ret = memcmp(entry->uuid, uuidp, UUID_BINSIZE);
277         if (ret == 0) {
278             tim = time(NULL);
279             if ((tim - entry->creationtime) > CACHESECONDS) {
280                 LOG(log_debug, logtype_default, "search_cachebyuuid: expired: name:\'%s\' in queue {%d}", entry->name, hash);
281                 if (entry->prev) {
282                     /* 2nd to last in queue */
283                     entry->prev->next = entry->next;
284                     if (entry->next)
285                         /* not the last element */
286                         entry->next->prev = entry->prev;
287                 } else {
288                     /* queue head  */
289                     if ((uuidcache[hash] = entry->next) != NULL)
290                         uuidcache[hash]->prev = NULL;
291                 }
292                 free(entry->name);
293                 free(entry->uuid);
294                 free(entry);
295 #ifdef DEBUG
296                 dumpcache();
297 #endif
298                 return -1;
299             } else {
300                 *name = malloc(strlen(entry->name)+1);
301                 strcpy(*name, entry->name);
302                 *type = entry->type;
303 #ifdef DEBUG
304                 dumpcache();
305 #endif
306                 return 0;
307             }
308         }
309         entry = entry->next;
310     }
311
312 #ifdef DEBUG
313     dumpcache();
314 #endif
315
316     return -1;
317 }
318
319 int add_cachebyuuid( uuidp_t inuuid, const char *inname, uuidtype_t type, const unsigned long uid _U_) {
320     int ret = 0;
321     char *name = NULL;
322     uuidp_t uuid;
323     cacheduser_t *cacheduser = NULL;
324     cacheduser_t *entry;
325     unsigned char hash;
326
327 #ifdef DEBUG
328     dumpcache();
329 #endif
330
331     /* allocate mem and copy values */
332     name = malloc(strlen(inname)+1);
333     if (!name) {
334         LOG(log_error, logtype_default, "add_cachebyuuid: mallor error");
335         ret = -1;
336         goto cleanup;
337     }
338
339     uuid = malloc(UUID_BINSIZE);
340     if (!uuid) {
341         LOG(log_error, logtype_default, "add_cachebyuuid: mallor error");
342         ret = -1;
343         goto cleanup;
344     }
345
346     cacheduser = malloc(sizeof(cacheduser_t));
347     if (!cacheduser) {
348         LOG(log_error, logtype_default, "add_cachebyuuid: mallor error");
349         ret = -1;
350         goto cleanup;
351     }
352
353     strcpy(name, inname);
354     memcpy(uuid, inuuid, UUID_BINSIZE);
355
356     /* fill in the cacheduser */
357     cacheduser->name = name;
358     cacheduser->type = type;
359     cacheduser->uuid = uuid;
360     cacheduser->creationtime = time(NULL);
361     cacheduser->prev = NULL;
362     cacheduser->next = NULL;
363
364     /* get hash */
365     hash = hashuuid(uuid);
366
367     /* insert cache entry into cache array at head of queue */
368     if (uuidcache[hash] == NULL) {
369         /* this queue is empty */
370         uuidcache[hash] = cacheduser;
371     } else {
372         cacheduser->next = uuidcache[hash];
373         uuidcache[hash]->prev = cacheduser;
374         uuidcache[hash] = cacheduser;
375     }
376
377 cleanup:
378     if (ret != 0) {
379         if (name)
380             free(name);
381         if (uuid)
382             free(uuid);
383         if (cacheduser)
384             free(cacheduser);
385     }
386
387 #ifdef DEBUG
388     dumpcache();
389 #endif
390
391     return ret;
392 }