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 28struct name_list { 29 struct name_list *prev, *next; 30 char *name; 31 uint32 stype; 32 char *comment; 33}; 34 35struct 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 43static struct cached_names *cached_names = NULL; 44 45/* Find a list of cached name for a workgroup, server or share list */ 46 47static 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 62static 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 = (struct name_list *)malloc(sizeof(struct name_list)); 69 if (!new_name) return; 70 71 ZERO_STRUCTP(new_name); 72 73 new_name->name = strdup(name); 74 new_name->stype = stype; 75 new_name->comment = strdup(comment); 76 77 DLIST_ADD(*name_list, new_name); 78} 79 80static 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 99BOOL 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 = (struct cached_names *) 121 malloc(sizeof(struct cached_names)); 122 123 ZERO_STRUCTP(new_names); 124 DLIST_ADD(cached_names, new_names); 125 126 } else { 127 128 /* Dispose of out of date name list */ 129 130 free_name_list(names->name_list); 131 names->name_list = NULL; 132 133 new_names = names; 134 } 135 136 result = cli_NetServerEnum(cli, workgroup, stype, 137 add_cached_names, 138 &new_names->name_list); 139 140 new_names->cache_timeout = now; 141 new_names->result = result; 142 new_names->key = strdup(key); 143 144 names = new_names; 145 } 146 147 /* Return names by running callback function. */ 148 149 for (tmp = names->name_list; tmp; tmp = tmp->next) 150 fn(tmp->name, stype, tmp->comment, state); 151 152 return names->result; 153} 154 155/* Wrapper for RNetShareEnum function */ 156 157int smbw_RNetShareEnum(struct cli_state *cli, 158 void (*fn)(const char *, uint32, const char *, void *), 159 void *state) 160{ 161 struct cached_names *names; 162 struct name_list *tmp; 163 time_t now = time(NULL); 164 char key[PATH_MAX]; 165 166 slprintf(key, PATH_MAX - 1, "SHARE/%s", cli->desthost); 167 168 names = find_cached_names(key); 169 170 if (names == NULL || (now - names->cache_timeout) > CACHE_TIMEOUT) { 171 struct cached_names *new_names = NULL; 172 173 /* No names cached for this server */ 174 175 if (names == NULL) { 176 new_names = (struct cached_names *) 177 malloc(sizeof(struct cached_names)); 178 179 ZERO_STRUCTP(new_names); 180 DLIST_ADD(cached_names, new_names); 181 182 } else { 183 184 /* Dispose of out of date name list */ 185 186 free_name_list(names->name_list); 187 names->name_list = NULL; 188 189 new_names = names; 190 } 191 192 new_names->result = cli_RNetShareEnum(cli, add_cached_names, 193 &new_names->name_list); 194 195 new_names->cache_timeout = now; 196 new_names->key = strdup(key); 197 198 names = new_names; 199 } 200 201 /* Return names by running callback function. */ 202 203 for (tmp = names->name_list; tmp; tmp = tmp->next) 204 fn(tmp->name, tmp->stype, tmp->comment, state); 205 206 return names->result; 207} 208