Initial import
[samba] / source / smbwrapper / smbw_cache.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB wrapper directory functions
4    Copyright (C) Tim Potter 2000
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 /* We cache lists of workgroups, lists of servers in workgroups, and lists
24    of shares exported by servers. */
25
26 #define CACHE_TIMEOUT 30
27
28 struct name_list {
29         struct name_list *prev, *next;
30         char *name;
31         uint32 stype;
32         char *comment;
33 };
34
35 struct cached_names {
36         struct cached_names *prev, *next;
37         char *key;
38         struct name_list *name_list;
39         time_t cache_timeout;
40         int result;
41 };
42
43 static struct cached_names *cached_names = NULL;
44
45 /* Find a list of cached name for a workgroup, server or share list */
46
47 static struct cached_names *find_cached_names(char *key)
48 {
49         struct cached_names *tmp;
50
51         for (tmp = cached_names; tmp; tmp = tmp->next) {
52                 if (strequal(tmp->key, key)) {
53                         return tmp;
54                 }
55         }
56
57         return NULL;
58 }
59
60 /* Add a name to a list stored in the state variable */
61
62 static void add_cached_names(const char *name, uint32 stype, 
63                              const char *comment, void *state)
64 {
65         struct name_list **name_list = (struct name_list **)state;
66         struct name_list *new_name;
67
68         new_name = SMB_MALLOC_P(struct name_list);
69         if (!new_name) return;
70
71         ZERO_STRUCTP(new_name);
72
73         new_name->name = SMB_STRDUP(name);
74         new_name->stype = stype;
75         new_name->comment = SMB_STRDUP(comment);
76
77         DLIST_ADD(*name_list, new_name);
78 }
79
80 static void free_name_list(struct name_list *name_list)
81 {
82         struct name_list *tmp = name_list;
83
84         while(tmp) {
85                 struct name_list *next;
86
87                 next = tmp->next;
88
89                 SAFE_FREE(tmp->name);
90                 SAFE_FREE(tmp->comment);
91                 SAFE_FREE(tmp);
92                 
93                 tmp = next;
94         }
95 }
96
97 /* Wrapper for NetServerEnum function */
98
99 BOOL smbw_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
100                         void (*fn)(const char *, uint32, const char *, void *),
101                         void *state)
102 {
103         struct cached_names *names;
104         struct name_list *tmp;
105         time_t now = time(NULL);
106         char key[PATH_MAX];
107         BOOL result = True;
108
109         slprintf(key, PATH_MAX - 1, "%s/%s#%s", cli->desthost, 
110                  workgroup, (stype == SV_TYPE_DOMAIN_ENUM ? "DOM" : "SRV"));
111
112         names = find_cached_names(key);
113
114         if (names == NULL || (now - names->cache_timeout) > CACHE_TIMEOUT) {
115                 struct cached_names *new_names = NULL;
116
117                 /* No names cached for this workgroup */
118
119                 if (names == NULL) {
120                         new_names = SMB_MALLOC_P(struct cached_names);
121
122                         ZERO_STRUCTP(new_names);
123                         DLIST_ADD(cached_names, new_names);
124
125                 } else {
126
127                         /* Dispose of out of date name list */
128
129                         free_name_list(names->name_list);
130                         names->name_list = NULL;
131
132                         new_names = names;
133                 }               
134
135                 result = cli_NetServerEnum(cli, workgroup, stype, 
136                                            add_cached_names, 
137                                            &new_names->name_list);
138                                            
139                 new_names->cache_timeout = now;
140                 new_names->result = result;
141                 new_names->key = SMB_STRDUP(key);
142
143                 names = new_names;
144         }
145
146         /* Return names by running callback function. */
147
148         for (tmp = names->name_list; tmp; tmp = tmp->next)
149                 fn(tmp->name, stype, tmp->comment, state);
150         
151         return names->result;
152 }
153
154 /* Wrapper for RNetShareEnum function */
155
156 int smbw_RNetShareEnum(struct cli_state *cli, 
157                        void (*fn)(const char *, uint32, const char *, void *), 
158                        void *state)
159 {
160         struct cached_names *names;
161         struct name_list *tmp;
162         time_t now = time(NULL);
163         char key[PATH_MAX];
164
165         slprintf(key, PATH_MAX - 1, "SHARE/%s", cli->desthost);
166
167         names = find_cached_names(key);
168
169         if (names == NULL || (now - names->cache_timeout) > CACHE_TIMEOUT) {
170                 struct cached_names *new_names = NULL;
171
172                 /* No names cached for this server */
173
174                 if (names == NULL) {
175                         new_names = SMB_MALLOC_P(struct cached_names);
176
177                         ZERO_STRUCTP(new_names);
178                         DLIST_ADD(cached_names, new_names);
179
180                 } else {
181
182                         /* Dispose of out of date name list */
183
184                         free_name_list(names->name_list);
185                         names->name_list = NULL;
186
187                         new_names = names;
188                 }
189
190                 new_names->result = cli_RNetShareEnum(cli, add_cached_names, 
191                                                       &new_names->name_list);
192                 
193                 new_names->cache_timeout = now;
194                 new_names->key = SMB_STRDUP(key);
195
196                 names = new_names;
197         }
198
199         /* Return names by running callback function. */
200
201         for (tmp = names->name_list; tmp; tmp = tmp->next)
202                 fn(tmp->name, tmp->stype, tmp->comment, state);
203         
204         return names->result;
205 }