Rework PublishProduct to use MSI_IterateRecords.
[wine] / dlls / netapi32 / nbnamecache.c
1 /* Copyright (c) 2003 Juan Lang
2  *
3  * This library is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Lesser General Public
5  * License as published by the Free Software Foundation; either
6  * version 2.1 of the License, or (at your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with this library; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  *
17  * This implementation uses a linked list, because I don't have a decent
18  * hash table implementation handy.  This is somewhat inefficient, but it's
19  * rather more efficient than not having a name cache at all.
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24 #include "wine/debug.h"
25
26 #include "nbnamecache.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(netbios);
29
30 typedef struct _NBNameCacheNode
31 {
32     DWORD expireTime;
33     NBNameCacheEntry *entry;
34     struct _NBNameCacheNode *next;
35 } NBNameCacheNode;
36
37 struct NBNameCache
38 {
39     HANDLE heap;
40     CRITICAL_SECTION cs;
41     DWORD entryExpireTimeMS;
42     NBNameCacheNode *head;
43 };
44
45 /* Unlinks the node pointed to by *prev, and frees any associated memory.
46  * If that node's next pointed to another node, *prev now points to it.
47  * Assumes the caller owns cache's lock.
48  */
49 static void NBNameCacheUnlinkNode(struct NBNameCache *cache,
50  NBNameCacheNode **prev)
51 {
52     if (cache && prev && *prev)
53     {
54         NBNameCacheNode *next = (*prev)->next;
55
56         HeapFree(cache->heap, 0, (*prev)->entry);
57         HeapFree(cache->heap, 0, *prev);
58         *prev = next;
59     }
60 }
61
62 /* Walks the list beginning with cache->head looking for the node with name
63  * name.  If the node is found, returns a pointer to the next pointer of the
64  * node _prior_ to the found node (or head if head points to it).  Thus, if the
65  * node's all you want, dereference the return value twice.  If you want to
66  * modify the list, modify the referent of the return value.
67  * While it's at it, deletes nodes whose time has expired (except the node
68  * you're looking for, of course).
69  * Returns NULL if the node isn't found.
70  * Assumes the caller owns cache's lock.
71  */
72 static NBNameCacheNode **NBNameCacheWalk(struct NBNameCache *cache,
73  const char name[NCBNAMSZ])
74 {
75     NBNameCacheNode **ret = NULL;
76
77     if (cache && cache->head)
78     {
79         NBNameCacheNode **ptr;
80
81         ptr = &cache->head;
82         while (ptr && *ptr && (*ptr)->entry)
83         {
84             if (!memcmp((*ptr)->entry->name, name, NCBNAMSZ - 1))
85                 ret = ptr;
86             else
87             {
88                 if (GetTickCount() > (*ptr)->expireTime)
89                     NBNameCacheUnlinkNode(cache, ptr);
90             }
91             if (*ptr)
92                 ptr = &(*ptr)->next;
93         }
94     }
95     return ret;
96 }
97
98 struct NBNameCache *NBNameCacheCreate(HANDLE heap, DWORD entryExpireTimeMS)
99 {
100     struct NBNameCache *cache;
101     
102     
103     if (!heap)
104         heap = GetProcessHeap();
105     cache = HeapAlloc(heap, 0, sizeof(struct NBNameCache));
106     if (cache)
107     {
108         cache->heap = heap;
109         InitializeCriticalSection(&cache->cs);
110         cache->entryExpireTimeMS = entryExpireTimeMS;
111         cache->head = NULL;
112     }
113     return cache;
114 }
115
116 BOOL NBNameCacheAddEntry(struct NBNameCache *cache, NBNameCacheEntry *entry)
117 {
118     BOOL ret;
119
120     if (cache && entry)
121     {
122         NBNameCacheNode **node;
123
124         EnterCriticalSection(&cache->cs);
125         node = NBNameCacheWalk(cache, entry->name);
126         if (node)
127         {
128             (*node)->expireTime = GetTickCount() +
129              cache->entryExpireTimeMS;
130             HeapFree(cache->heap, 0, (*node)->entry);
131             (*node)->entry = entry;
132             ret = TRUE;
133         }
134         else
135         {
136             NBNameCacheNode *newNode = HeapAlloc(cache->heap, 0, sizeof(NBNameCacheNode));
137             if (newNode)
138             {
139                 newNode->expireTime = GetTickCount() +
140                  cache->entryExpireTimeMS;
141                 newNode->entry = entry;
142                 newNode->next = cache->head;
143                 cache->head = newNode;
144                 ret = TRUE;
145             }
146             else
147                 ret = FALSE;
148         }
149         LeaveCriticalSection(&cache->cs);
150     }
151     else
152         ret = FALSE;
153     return ret;
154 }
155
156 const NBNameCacheEntry *NBNameCacheFindEntry(struct NBNameCache *cache,
157  const UCHAR name[NCBNAMSZ])
158 {
159     const NBNameCacheEntry *ret;
160     UCHAR printName[NCBNAMSZ];
161
162     memcpy(printName, name, NCBNAMSZ - 1);
163     printName[NCBNAMSZ - 1] = '\0';
164     if (cache)
165     {
166         NBNameCacheNode **node;
167
168         EnterCriticalSection(&cache->cs);
169         node = NBNameCacheWalk(cache, name);
170         if (node)
171             ret = (*node)->entry;
172         else
173             ret = NULL;
174         LeaveCriticalSection(&cache->cs);
175     }
176     else
177         ret = NULL;
178     return ret;
179 }
180
181 BOOL NBNameCacheUpdateNBName(struct NBNameCache *cache,
182  const UCHAR name[NCBNAMSZ], const UCHAR nbname[NCBNAMSZ])
183 {
184     BOOL ret;
185
186     if (cache)
187     {
188         NBNameCacheNode **node;
189
190         EnterCriticalSection(&cache->cs);
191         node = NBNameCacheWalk(cache, name);
192         if (node && *node && (*node)->entry)
193         {
194             memcpy((*node)->entry->nbname, nbname, NCBNAMSZ);
195             ret = TRUE;
196         }
197         else
198             ret = FALSE;
199         LeaveCriticalSection(&cache->cs);
200     }
201     else
202         ret = FALSE;
203     return ret;
204 }
205
206 void NBNameCacheDestroy(struct NBNameCache *cache)
207 {
208     if (cache)
209     {
210         DeleteCriticalSection(&cache->cs);
211         while (cache->head)
212             NBNameCacheUnlinkNode(cache, &cache->head);
213         HeapFree(cache->heap, 0, cache);
214     }
215 }