1/* 2 Unix SMB/Netbios implementation. 3 Version 2.0 4 SMB wrapper directory functions 5 Copyright (C) Andrew Tridgell 1998 6 Copyright (C) Derrell Lipman 2003-2005 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program. If not, see <http://www.gnu.org/licenses/>. 20*/ 21 22#include "smbw.h" 23#include "bsd-strlfunc.h" 24 25/***************************************************** 26determine if a directory handle is a smb one 27*******************************************************/ 28int smbw_dirp(DIR * dirp) 29{ 30 return ((char *) dirp >= (char *) smbw_fd_map && 31 (char *) dirp < (char *) &smbw_fd_map[__FD_SETSIZE] && 32 *(int *) dirp != -1); 33} 34 35 36/***************************************************** 37a wrapper for getdents() 38*******************************************************/ 39int smbw_getdents(unsigned int fd_smbw, 40 struct SMBW_dirent *dirent_external, 41 int count) 42{ 43 int remaining; 44 int fd_client = smbw_fd_map[fd_smbw]; 45 struct smbc_dirent *dirent_internal; 46 47 48 for (remaining = count; 49 remaining > sizeof(struct SMBW_dirent); 50 dirent_external++) { 51 52 /* 53 * We do these one at a time because there's otherwise no way 54 * to limit how many smbc_getdents() will return for us, and 55 * if it returns too many, it also doesn't give us offsets to 56 * be able to seek back to where we need to be. In practice, 57 * this one-at-a-time retrieval isn't a problem because the 58 * time-consuming network transaction is all done at 59 * smbc_opendir() time. 60 */ 61 dirent_internal = smbc_readdir(fd_client); 62 if (dirent_internal == NULL) { 63 break; 64 } 65 66 remaining -= sizeof(struct SMBW_dirent); 67 68 dirent_external->d_ino = -1; /* not supported */ 69 dirent_external->d_off = smbc_telldir(fd_client); 70 dirent_external->d_reclen = sizeof(struct SMBW_dirent); 71 dirent_external->d_type = dirent_internal->smbc_type; 72 73 smbw_strlcpy(dirent_external->d_name, 74 dirent_internal->name, 75 sizeof(dirent_external->d_name) - 1); 76 smbw_strlcpy(dirent_external->d_comment, 77 dirent_internal->comment, 78 sizeof(dirent_external->d_comment) - 1); 79 } 80 81 return(count - remaining); 82} 83 84 85/***************************************************** 86a wrapper for chdir() 87*******************************************************/ 88int smbw_chdir(const char *name) 89{ 90 int simulate; 91 struct stat statbuf; 92 char path[PATH_MAX]; 93 char *p; 94 95 SMBW_INIT(); 96 97 if (!name) { 98 errno = EINVAL; 99 return -1; 100 } 101 102 if (! smbw_path((char *) name)) { 103 if ((* smbw_libc.chdir)(name) == 0) { 104 *smbw_cwd = '\0'; 105 return 0; 106 } 107 108 return -1; 109 } 110 111 smbw_fix_path(name, path); 112 113 /* ensure it exists */ 114 p = path + 6; /* look just past smb:// */ 115 simulate = (strchr(p, '/') == NULL); 116 117 /* special case for full-network scan, workgroups, and servers */ 118 if (! simulate) { 119 120 if (smbc_stat(path, &statbuf) < 0) { 121 return -1; 122 } 123 124 /* ensure it's a directory */ 125 if (! S_ISDIR(statbuf.st_mode)) { 126 errno = ENOTDIR; 127 return -1; 128 } 129 } 130 131 smbw_strlcpy(smbw_cwd, path, PATH_MAX); 132 133 /* we don't want the old directory to be busy */ 134 (* smbw_libc.chdir)("/"); 135 136 return 0; 137} 138 139 140/***************************************************** 141a wrapper for mkdir() 142*******************************************************/ 143int smbw_mkdir(const char *fname, mode_t mode) 144{ 145 char path[PATH_MAX]; 146 147 if (!fname) { 148 errno = EINVAL; 149 return -1; 150 } 151 152 SMBW_INIT(); 153 154 smbw_fix_path(fname, path); 155 return smbc_mkdir(path, mode); 156} 157 158/***************************************************** 159a wrapper for rmdir() 160*******************************************************/ 161int smbw_rmdir(const char *fname) 162{ 163 char path[PATH_MAX]; 164 165 if (!fname) { 166 errno = EINVAL; 167 return -1; 168 } 169 170 SMBW_INIT(); 171 172 smbw_fix_path(fname, path); 173 return smbc_rmdir(path); 174} 175 176 177/***************************************************** 178a wrapper for getcwd() 179*******************************************************/ 180char *smbw_getcwd(char *buf, size_t size) 181{ 182 SMBW_INIT(); 183 184 if (*smbw_cwd == '\0') { 185 return (* smbw_libc.getcwd)(buf, size); 186 } 187 188 if (buf == NULL) { 189 if (size == 0) { 190 size = strlen(smbw_cwd) + 1; 191 } 192 buf = malloc(size); 193 if (buf == NULL) { 194 errno = ENOMEM; 195 return NULL; 196 } 197 } 198 199 smbw_strlcpy(buf, smbw_cwd, size); 200 buf[size-1] = '\0'; 201 return buf; 202} 203 204/***************************************************** 205a wrapper for fchdir() 206*******************************************************/ 207int smbw_fchdir(int fd_smbw) 208{ 209 int ret; 210 211 SMBW_INIT(); 212 213 if (! smbw_fd(fd_smbw)) { 214 ret = (* smbw_libc.fchdir)(fd_smbw); 215 (void) (* smbw_libc.getcwd)(smbw_cwd, PATH_MAX); 216 return ret; 217 } 218 219 errno = EACCES; 220 return -1; 221} 222 223/***************************************************** 224open a directory on the server 225*******************************************************/ 226DIR *smbw_opendir(const char *fname) 227{ 228 int fd_client; 229 int fd_smbw; 230 char path[PATH_MAX]; 231 DIR * dirp; 232 233 SMBW_INIT(); 234 235 if (!fname) { 236 errno = EINVAL; 237 return NULL; 238 } 239 240 fd_smbw = (smbw_libc.open)(SMBW_DUMMY, O_WRONLY, 0200); 241 if (fd_smbw == -1) { 242 errno = EMFILE; 243 return NULL; 244 } 245 246 smbw_fix_path(fname, path); 247 fd_client = smbc_opendir(path); 248 249 if (fd_client < 0) { 250 (* smbw_libc.close)(fd_smbw); 251 return NULL; 252 } 253 254 smbw_fd_map[fd_smbw] = fd_client; 255 smbw_ref(fd_client, SMBW_RCT_Increment); 256 dirp = (DIR *) &smbw_fd_map[fd_smbw]; 257 return dirp; 258} 259 260/***************************************************** 261read one entry from a directory 262*******************************************************/ 263struct SMBW_dirent *smbw_readdir(DIR *dirp) 264{ 265 int fd_smbw; 266 int fd_client; 267 struct smbc_dirent *dirent_internal; 268 static struct SMBW_dirent dirent_external; 269 270 fd_smbw = (int *) dirp - smbw_fd_map; 271 fd_client = smbw_fd_map[fd_smbw]; 272 273 if ((dirent_internal = smbc_readdir(fd_client)) == NULL) { 274 return NULL; 275 } 276 277 dirent_external.d_ino = -1; /* not supported */ 278 dirent_external.d_off = smbc_telldir(fd_client); 279 dirent_external.d_reclen = sizeof(struct SMBW_dirent); 280 dirent_external.d_type = dirent_internal->smbc_type; 281 smbw_strlcpy(dirent_external.d_name, 282 dirent_internal->name, 283 sizeof(dirent_external.d_name) - 1); 284 smbw_strlcpy(dirent_external.d_comment, 285 dirent_internal->comment, 286 sizeof(dirent_external.d_comment) - 1); 287 288 return &dirent_external; 289} 290 291/***************************************************** 292read one entry from a directory in a reentrant fashion 293ha! samba is not re-entrant, and neither is the 294libsmbclient library 295*******************************************************/ 296int smbw_readdir_r(DIR *dirp, 297 struct SMBW_dirent *__restrict entry, 298 struct SMBW_dirent **__restrict result) 299{ 300 SMBW_dirent *dirent; 301 302 dirent = smbw_readdir(dirp); 303 304 if (dirent != NULL) { 305 *entry = *dirent; 306 if (result != NULL) { 307 *result = entry; 308 } 309 return 0; 310 } 311 312 if (result != NULL) { 313 *result = NULL; 314 } 315 return EBADF; 316} 317 318 319/***************************************************** 320close a DIR* 321*******************************************************/ 322int smbw_closedir(DIR *dirp) 323{ 324 int fd_smbw = (int *) dirp - smbw_fd_map; 325 int fd_client = smbw_fd_map[fd_smbw]; 326 327 (* smbw_libc.close)(fd_smbw); 328 if (smbw_ref(fd_client, SMBW_RCT_Decrement) > 0) { 329 return 0; 330 } 331 smbw_fd_map[fd_smbw] = -1; 332 return smbc_closedir(fd_client); 333} 334 335/***************************************************** 336seek in a directory 337*******************************************************/ 338void smbw_seekdir(DIR *dirp, long long offset) 339{ 340 int fd_smbw = (int *) dirp - smbw_fd_map; 341 int fd_client = smbw_fd_map[fd_smbw]; 342 343 smbc_lseekdir(fd_client, offset); 344} 345 346/***************************************************** 347current loc in a directory 348*******************************************************/ 349long long smbw_telldir(DIR *dirp) 350{ 351 int fd_smbw = (int *) dirp - smbw_fd_map; 352 int fd_client = smbw_fd_map[fd_smbw]; 353 354 return (long long) smbc_telldir(fd_client); 355} 356