diff options
-rw-r--r-- | source3/Makefile.in | 1 | ||||
-rw-r--r-- | source3/smbwrapper/smbw_cache.c | 208 | ||||
-rw-r--r-- | source3/smbwrapper/smbw_dir.c | 13 |
3 files changed, 215 insertions, 7 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index b3723223ee..d6a2cfed1f 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -275,6 +275,7 @@ PAM_WINBIND_OBJ = nsswitch/pam_winbind.po nsswitch/wb_common.po SMBW_OBJ = smbwrapper/smbw.o \ smbwrapper/smbw_dir.o smbwrapper/smbw_stat.o \ smbwrapper/realcalls.o smbwrapper/shared.o \ + smbwrapper/smbw_cache.o \ $(LIBSMB_OBJ) $(PARAM_OBJ) \ $(UBIQX_OBJ) $(LIB_OBJ) diff --git a/source3/smbwrapper/smbw_cache.c b/source3/smbwrapper/smbw_cache.c new file mode 100644 index 0000000000..3213d99941 --- /dev/null +++ b/source3/smbwrapper/smbw_cache.c @@ -0,0 +1,208 @@ +/* + Unix SMB/Netbios implementation. + Version 2.0 + SMB wrapper directory functions + Copyright (C) Tim Potter 2000 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" + +/* We cache lists of workgroups, lists of servers in workgroups, and lists + of shares exported by servers. */ + +#define CACHE_TIMEOUT 30 + +struct name_list { + struct name_list *prev, *next; + char *name; + uint32 stype; + char *comment; +}; + +struct cached_names { + struct cached_names *prev, *next; + char *key; + struct name_list *name_list; + time_t cache_timeout; + int result; +}; + +static struct cached_names *cached_names = NULL; + +/* Find a list of cached name for a workgroup, server or share list */ + +static struct cached_names *find_cached_names(char *key) +{ + struct cached_names *tmp; + + for (tmp = cached_names; tmp; tmp = tmp->next) { + if (strequal(tmp->key, key)) { + return tmp; + } + } + + return NULL; +} + +/* Add a name to a list stored in the state variable */ + +static void add_cached_names(const char *name, uint32 stype, + const char *comment, void *state) +{ + struct name_list **name_list = (struct name_list **)state; + struct name_list *new_name; + + new_name = (struct name_list *)malloc(sizeof(struct name_list)); + if (!new_name) return; + + ZERO_STRUCTP(new_name); + + new_name->name = strdup(name); + new_name->stype = stype; + new_name->comment = strdup(comment); + + DLIST_ADD(*name_list, new_name); +} + +static void free_name_list(struct name_list *name_list) +{ + struct name_list *tmp = name_list; + + while(tmp) { + struct name_list *next; + + next = tmp->next; + + free(tmp->name); + free(tmp->comment); + free(tmp); + + tmp = next; + } +} + +/* Wrapper for NetServerEnum function */ + +BOOL smbw_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype, + void (*fn)(const char *, uint32, const char *, void *), + void *state) +{ + struct cached_names *names; + struct name_list *tmp; + time_t now = time(NULL); + char key[PATH_MAX]; + BOOL result = True; + + slprintf(key, PATH_MAX - 1, "%s/%s#%s", cli->desthost, + workgroup, (stype == SV_TYPE_DOMAIN_ENUM ? "DOM" : "SRV")); + + names = find_cached_names(key); + + if (names == NULL || (now - names->cache_timeout) > CACHE_TIMEOUT) { + struct cached_names *new_names = NULL; + + /* No names cached for this workgroup */ + + if (names == NULL) { + new_names = (struct cached_names *) + malloc(sizeof(struct cached_names)); + + ZERO_STRUCTP(new_names); + DLIST_ADD(cached_names, new_names); + + } else { + + /* Dispose of out of date name list */ + + free_name_list(names->name_list); + names->name_list = NULL; + + new_names = names; + } + + result = cli_NetServerEnum(cli, workgroup, stype, + add_cached_names, + &new_names->name_list); + + new_names->cache_timeout = now; + new_names->result = result; + new_names->key = strdup(key); + + names = new_names; + } + + /* Return names by running callback function. */ + + for (tmp = names->name_list; tmp; tmp = tmp->next) + fn(tmp->name, stype, tmp->comment, state); + + return names->result; +} + +/* Wrapper for RNetShareEnum function */ + +int smbw_RNetShareEnum(struct cli_state *cli, + void (*fn)(const char *, uint32, const char *, void *), + void *state) +{ + struct cached_names *names; + struct name_list *tmp; + time_t now = time(NULL); + char key[PATH_MAX]; + + slprintf(key, PATH_MAX - 1, "SHARE/%s", cli->desthost); + + names = find_cached_names(key); + + if (names == NULL || (now - names->cache_timeout) > CACHE_TIMEOUT) { + struct cached_names *new_names = NULL; + + /* No names cached for this server */ + + if (names == NULL) { + new_names = (struct cached_names *) + malloc(sizeof(struct cached_names)); + + ZERO_STRUCTP(new_names); + DLIST_ADD(cached_names, new_names); + + } else { + + /* Dispose of out of date name list */ + + free_name_list(names->name_list); + names->name_list = NULL; + + new_names = names; + } + + new_names->result = cli_RNetShareEnum(cli, add_cached_names, + &new_names->name_list); + + new_names->cache_timeout = now; + new_names->key = strdup(key); + + names = new_names; + } + + /* Return names by running callback function. */ + + for (tmp = names->name_list; tmp; tmp = tmp->next) + fn(tmp->name, tmp->stype, tmp->comment, state); + + return names->result; +} diff --git a/source3/smbwrapper/smbw_dir.c b/source3/smbwrapper/smbw_dir.c index d94ea6ec87..4f6c18eb7f 100644 --- a/source3/smbwrapper/smbw_dir.c +++ b/source3/smbwrapper/smbw_dir.c @@ -72,7 +72,6 @@ static void free_dir(struct smbw_dir *dir) free(dir); } - static struct smbw_dir *cur_dir; /***************************************************** @@ -102,7 +101,7 @@ static void smbw_dir_add(struct file_info *finfo, const char *mask, add a entry to a directory listing *******************************************************/ static void smbw_share_add(const char *share, uint32 type, - const char *comment, void *state) + const char *comment, void *state) { struct file_info finfo; @@ -205,22 +204,22 @@ int smbw_dir_open(const char *fname) *p = 0; smbw_server_add(".",0,"", NULL); smbw_server_add("..",0,"", NULL); - cli_NetServerEnum(&srv->cli, srv->server_name, SV_TYPE_DOMAIN_ENUM, - smbw_server_add, NULL); + smbw_NetServerEnum(&srv->cli, srv->server_name, + SV_TYPE_DOMAIN_ENUM, smbw_server_add, NULL); *p = '#'; } else if ((p=strstr(srv->server_name,"#1D"))) { DEBUG(4,("doing NetServerEnum\n")); *p = 0; smbw_server_add(".",0,"", NULL); smbw_server_add("..",0,"", NULL); - cli_NetServerEnum(&srv->cli, srv->server_name, SV_TYPE_ALL, - smbw_server_add, NULL); + smbw_NetServerEnum(&srv->cli, srv->server_name, SV_TYPE_ALL, + smbw_server_add, NULL); *p = '#'; } else if (strcmp(srv->cli.dev,"IPC") == 0) { DEBUG(4,("doing NetShareEnum\n")); smbw_share_add(".",0,"", NULL); smbw_share_add("..",0,"", NULL); - if (cli_RNetShareEnum(&srv->cli, smbw_share_add, NULL) < 0) { + if (smbw_RNetShareEnum(&srv->cli, smbw_share_add, NULL) < 0) { errno = smbw_errno(&srv->cli); goto failed; } |