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