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