1/* 2 Unix SMB/CIFS implementation. 3 SMB wrapper directory functions 4 Copyright (C) Andrew Tridgell 1998 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#include "realcalls.h" 23 24extern pstring smbw_cwd; 25extern fstring smbw_prefix; 26 27static struct smbw_dir *smbw_dirs; 28 29extern struct bitmap *smbw_file_bmap; 30 31extern int smbw_busy; 32 33/***************************************************** 34map a fd to a smbw_dir structure 35*******************************************************/ 36struct smbw_dir *smbw_dir(int fd) 37{ 38 struct smbw_dir *dir; 39 40 for (dir=smbw_dirs;dir;dir=dir->next) { 41 if (dir->fd == fd) return dir; 42 } 43 return NULL; 44} 45 46/***************************************************** 47check if a DIR* is one of ours 48*******************************************************/ 49int smbw_dirp(DIR *dirp) 50{ 51 struct smbw_dir *d = (struct smbw_dir *)dirp; 52 struct smbw_dir *dir; 53 54 for (dir=smbw_dirs;dir;dir=dir->next) { 55 if (dir == d) return 1; 56 } 57 return 0; 58} 59 60/***************************************************** 61free a smbw_dir structure and all entries 62*******************************************************/ 63static void free_dir(struct smbw_dir *dir) 64{ 65 if(!dir) return; 66 67 SAFE_FREE(dir->list); 68 SAFE_FREE(dir->path); 69 ZERO_STRUCTP(dir); 70 SAFE_FREE(dir); 71} 72 73static struct smbw_dir *cur_dir; 74 75/***************************************************** 76add a entry to a directory listing 77*******************************************************/ 78static void smbw_dir_add(struct file_info *finfo, const char *mask, 79 void *state) 80{ 81 struct file_info *cdl; 82 83 DEBUG(5,("%s\n", finfo->name)); 84 85 if (cur_dir->malloced == cur_dir->count) { 86 cdl = (struct file_info *)Realloc(cur_dir->list, 87 sizeof(cur_dir->list[0])* 88 (cur_dir->count+100)); 89 if (!cdl) { 90 /* oops */ 91 return; 92 } 93 cur_dir->list = cdl; 94 cur_dir->malloced += 100; 95 } 96 97 cur_dir->list[cur_dir->count] = *finfo; 98 cur_dir->count++; 99} 100 101/***************************************************** 102add a entry to a directory listing 103*******************************************************/ 104static void smbw_share_add(const char *share, uint32 type, 105 const char *comment, void *state) 106{ 107 struct file_info finfo; 108 109 if (strcmp(share,"IPC$") == 0) return; 110 111 ZERO_STRUCT(finfo); 112 113 pstrcpy(finfo.name, share); 114 finfo.mode = aRONLY | aDIR; 115 116 smbw_dir_add(&finfo, NULL, NULL); 117} 118 119 120/***************************************************** 121add a server to a directory listing 122*******************************************************/ 123static void smbw_server_add(const char *name, uint32 type, 124 const char *comment, void *state) 125{ 126 struct file_info finfo; 127 128 ZERO_STRUCT(finfo); 129 130 pstrcpy(finfo.name, name); 131 finfo.mode = aRONLY | aDIR; 132 133 smbw_dir_add(&finfo, NULL, NULL); 134} 135 136 137/***************************************************** 138add a entry to a directory listing 139*******************************************************/ 140static void smbw_printjob_add(struct print_job_info *job) 141{ 142 struct file_info finfo; 143 144 ZERO_STRUCT(finfo); 145 146 pstrcpy(finfo.name, job->name); 147 finfo.mode = aRONLY | aDIR; 148 finfo.mtime = job->t; 149 finfo.atime = job->t; 150 finfo.ctime = job->t; 151 finfo.uid = nametouid(job->user); 152 finfo.mode = aRONLY; 153 finfo.size = job->size; 154 155 smbw_dir_add(&finfo, NULL, NULL); 156} 157 158 159/***************************************************** 160open a directory on the server 161*******************************************************/ 162int smbw_dir_open(const char *fname) 163{ 164 fstring server, share; 165 pstring path; 166 struct smbw_server *srv=NULL; 167 struct smbw_dir *dir=NULL; 168 pstring mask; 169 int fd; 170 char *s, *p; 171 172 if (!fname) { 173 errno = EINVAL; 174 return -1; 175 } 176 177 smbw_init(); 178 179 /* work out what server they are after */ 180 s = smbw_parse_path(fname, server, share, path); 181 182 DEBUG(4,("dir_open share=%s\n", share)); 183 184 /* get a connection to the server */ 185 srv = smbw_server(server, share); 186 if (!srv) { 187 /* smbw_server sets errno */ 188 goto failed; 189 } 190 191 dir = (struct smbw_dir *)malloc(sizeof(*dir)); 192 if (!dir) { 193 errno = ENOMEM; 194 goto failed; 195 } 196 197 ZERO_STRUCTP(dir); 198 199 cur_dir = dir; 200 201 slprintf(mask, sizeof(mask)-1, "%s\\*", path); 202 all_string_sub(mask,"\\\\","\\",0); 203 204 if ((p=strstr(srv->server_name,"#01"))) { 205 *p = 0; 206 smbw_server_add(".",0,"", NULL); 207 smbw_server_add("..",0,"", NULL); 208 smbw_NetServerEnum(&srv->cli, srv->server_name, 209 SV_TYPE_DOMAIN_ENUM, smbw_server_add, NULL); 210 *p = '#'; 211 } else if ((p=strstr(srv->server_name,"#1D"))) { 212 DEBUG(4,("doing NetServerEnum\n")); 213 *p = 0; 214 smbw_server_add(".",0,"", NULL); 215 smbw_server_add("..",0,"", NULL); 216 smbw_NetServerEnum(&srv->cli, srv->server_name, SV_TYPE_ALL, 217 smbw_server_add, NULL); 218 *p = '#'; 219 } else if ((strcmp(srv->cli.dev,"IPC") == 0) || (strequal(share,"IPC$"))) { 220 DEBUG(4,("doing NetShareEnum\n")); 221 smbw_share_add(".",0,"", NULL); 222 smbw_share_add("..",0,"", NULL); 223 if (smbw_RNetShareEnum(&srv->cli, smbw_share_add, NULL) < 0) { 224 errno = smbw_errno(&srv->cli); 225 goto failed; 226 } 227 } else if (strncmp(srv->cli.dev,"LPT",3) == 0) { 228 smbw_share_add(".",0,"", NULL); 229 smbw_share_add("..",0,"", NULL); 230 if (cli_print_queue(&srv->cli, smbw_printjob_add) < 0) { 231 errno = smbw_errno(&srv->cli); 232 goto failed; 233 } 234 } else { 235#if 0 236 if (strcmp(path,"\\") == 0) { 237 smbw_share_add(".",0,""); 238 smbw_share_add("..",0,""); 239 } 240#endif 241 if (cli_list(&srv->cli, mask, aHIDDEN|aSYSTEM|aDIR, 242 smbw_dir_add, NULL) < 0) { 243 errno = smbw_errno(&srv->cli); 244 goto failed; 245 } 246 } 247 248 cur_dir = NULL; 249 250 fd = open(SMBW_DUMMY, O_WRONLY); 251 if (fd == -1) { 252 errno = EMFILE; 253 goto failed; 254 } 255 256 if (bitmap_query(smbw_file_bmap, fd)) { 257 DEBUG(0,("ERROR: fd used in smbw_dir_open\n")); 258 errno = EIO; 259 goto failed; 260 } 261 262 DLIST_ADD(smbw_dirs, dir); 263 264 bitmap_set(smbw_file_bmap, fd); 265 266 dir->fd = fd; 267 dir->srv = srv; 268 dir->path = strdup(s); 269 270 DEBUG(4,(" -> %d\n", dir->count)); 271 272 return dir->fd; 273 274 failed: 275 free_dir(dir); 276 277 return -1; 278} 279 280/***************************************************** 281a wrapper for fstat() on a directory 282*******************************************************/ 283int smbw_dir_fstat(int fd, struct stat *st) 284{ 285 struct smbw_dir *dir; 286 287 dir = smbw_dir(fd); 288 if (!dir) { 289 errno = EBADF; 290 return -1; 291 } 292 293 ZERO_STRUCTP(st); 294 295 smbw_setup_stat(st, "", dir->count*DIRP_SIZE, aDIR); 296 297 st->st_dev = dir->srv->dev; 298 299 return 0; 300} 301 302/***************************************************** 303close a directory handle 304*******************************************************/ 305int smbw_dir_close(int fd) 306{ 307 struct smbw_dir *dir; 308 309 dir = smbw_dir(fd); 310 if (!dir) { 311 errno = EBADF; 312 return -1; 313 } 314 315 bitmap_clear(smbw_file_bmap, dir->fd); 316 close(dir->fd); 317 318 DLIST_REMOVE(smbw_dirs, dir); 319 320 free_dir(dir); 321 322 return 0; 323} 324 325/***************************************************** 326a wrapper for getdents() 327*******************************************************/ 328int smbw_getdents(unsigned int fd, struct dirent *dirp, int count) 329{ 330 struct smbw_dir *dir; 331 int n=0; 332 333 smbw_busy++; 334 335 dir = smbw_dir(fd); 336 if (!dir) { 337 errno = EBADF; 338 smbw_busy--; 339 return -1; 340 } 341 342 while (count>=DIRP_SIZE && (dir->offset < dir->count)) { 343#if HAVE_DIRENT_D_OFF 344 dirp->d_off = (dir->offset+1)*DIRP_SIZE; 345#endif 346 dirp->d_reclen = DIRP_SIZE; 347 fstrcpy(&dirp->d_name[0], dir->list[dir->offset].name); 348 dirp->d_ino = smbw_inode(dir->list[dir->offset].name); 349 dir->offset++; 350 count -= dirp->d_reclen; 351#if HAVE_DIRENT_D_OFF 352 if (dir->offset == dir->count) { 353 dirp->d_off = -1; 354 } 355#endif 356 dirp = (struct dirent *)(((char *)dirp) + DIRP_SIZE); 357 n++; 358 } 359 360 smbw_busy--; 361 return n*DIRP_SIZE; 362} 363 364 365/***************************************************** 366a wrapper for chdir() 367*******************************************************/ 368int smbw_chdir(const char *name) 369{ 370 struct smbw_server *srv; 371 fstring server, share; 372 pstring path; 373 uint16 mode = aDIR; 374 char *cwd; 375 int len; 376 377 smbw_init(); 378 379 len = strlen(smbw_prefix); 380 381 if (smbw_busy) return real_chdir(name); 382 383 smbw_busy++; 384 385 if (!name) { 386 errno = EINVAL; 387 goto failed; 388 } 389 390 DEBUG(4,("smbw_chdir(%s)\n", name)); 391 392 /* work out what server they are after */ 393 cwd = smbw_parse_path(name, server, share, path); 394 395 /* a special case - accept cd to /smb */ 396 if (strncmp(cwd, smbw_prefix, len-1) == 0 && 397 cwd[len-1] == 0) { 398 goto success1; 399 } 400 401 if (strncmp(cwd,smbw_prefix,strlen(smbw_prefix))) { 402 if (real_chdir(cwd) == 0) { 403 goto success2; 404 } 405 goto failed; 406 } 407 408 /* get a connection to the server */ 409 srv = smbw_server(server, share); 410 if (!srv) { 411 /* smbw_server sets errno */ 412 goto failed; 413 } 414 415 if (strncmp(srv->cli.dev,"IPC",3) && 416 !strequal(share, "IPC$") && 417 strncmp(srv->cli.dev,"LPT",3) && 418 !smbw_getatr(srv, path, 419 &mode, NULL, NULL, NULL, NULL, NULL)) { 420 errno = smbw_errno(&srv->cli); 421 goto failed; 422 } 423 424 if (!(mode & aDIR)) { 425 errno = ENOTDIR; 426 goto failed; 427 } 428 429 success1: 430 /* we don't want the old directory to be busy */ 431 real_chdir("/"); 432 433 success2: 434 435 DEBUG(4,("set SMBW_CWD to %s\n", cwd)); 436 437 pstrcpy(smbw_cwd, cwd); 438 439 smbw_busy--; 440 return 0; 441 442 failed: 443 smbw_busy--; 444 return -1; 445} 446 447 448/***************************************************** 449a wrapper for lseek() on directories 450*******************************************************/ 451off_t smbw_dir_lseek(int fd, off_t offset, int whence) 452{ 453 struct smbw_dir *dir; 454 off_t ret; 455 456 dir = smbw_dir(fd); 457 if (!dir) { 458 errno = EBADF; 459 return -1; 460 } 461 462 switch (whence) { 463 case SEEK_SET: 464 dir->offset = offset/DIRP_SIZE; 465 break; 466 case SEEK_CUR: 467 dir->offset += offset/DIRP_SIZE; 468 break; 469 case SEEK_END: 470 dir->offset = (dir->count * DIRP_SIZE) + offset; 471 dir->offset /= DIRP_SIZE; 472 break; 473 } 474 475 ret = dir->offset * DIRP_SIZE; 476 477 DEBUG(4,(" -> %d\n", (int)ret)); 478 479 return ret; 480} 481 482 483/***************************************************** 484a wrapper for mkdir() 485*******************************************************/ 486int smbw_mkdir(const char *fname, mode_t mode) 487{ 488 struct smbw_server *srv; 489 fstring server, share; 490 pstring path; 491 492 if (!fname) { 493 errno = EINVAL; 494 return -1; 495 } 496 497 smbw_init(); 498 499 smbw_busy++; 500 501 /* work out what server they are after */ 502 smbw_parse_path(fname, server, share, path); 503 504 /* get a connection to the server */ 505 srv = smbw_server(server, share); 506 if (!srv) { 507 /* smbw_server sets errno */ 508 goto failed; 509 } 510 511 if (!cli_mkdir(&srv->cli, path)) { 512 errno = smbw_errno(&srv->cli); 513 goto failed; 514 } 515 516 smbw_busy--; 517 return 0; 518 519 failed: 520 smbw_busy--; 521 return -1; 522} 523 524/***************************************************** 525a wrapper for rmdir() 526*******************************************************/ 527int smbw_rmdir(const char *fname) 528{ 529 struct smbw_server *srv; 530 fstring server, share; 531 pstring path; 532 533 if (!fname) { 534 errno = EINVAL; 535 return -1; 536 } 537 538 smbw_init(); 539 540 smbw_busy++; 541 542 /* work out what server they are after */ 543 smbw_parse_path(fname, server, share, path); 544 545 /* get a connection to the server */ 546 srv = smbw_server(server, share); 547 if (!srv) { 548 /* smbw_server sets errno */ 549 goto failed; 550 } 551 552 if (!cli_rmdir(&srv->cli, path)) { 553 errno = smbw_errno(&srv->cli); 554 goto failed; 555 } 556 557 smbw_busy--; 558 return 0; 559 560 failed: 561 smbw_busy--; 562 return -1; 563} 564 565 566/***************************************************** 567a wrapper for getcwd() 568*******************************************************/ 569char *smbw_getcwd(char *buf, size_t size) 570{ 571 smbw_init(); 572 573 if (smbw_busy) { 574 return (char *)real_getcwd(buf, size); 575 } 576 577 smbw_busy++; 578 579 if (!buf) { 580 if (size <= 0) size = strlen(smbw_cwd)+1; 581 buf = (char *)malloc(size); 582 if (!buf) { 583 errno = ENOMEM; 584 smbw_busy--; 585 return NULL; 586 } 587 } 588 589 if (strlen(smbw_cwd) > size-1) { 590 errno = ERANGE; 591 smbw_busy--; 592 return NULL; 593 } 594 595 safe_strcpy(buf, smbw_cwd, size); 596 597 smbw_busy--; 598 return buf; 599} 600 601/***************************************************** 602a wrapper for fchdir() 603*******************************************************/ 604int smbw_fchdir(unsigned int fd) 605{ 606 struct smbw_dir *dir; 607 int ret; 608 609 smbw_busy++; 610 611 dir = smbw_dir(fd); 612 if (dir) { 613 smbw_busy--; 614 return chdir(dir->path); 615 } 616 617 ret = real_fchdir(fd); 618 if (ret == 0) { 619 sys_getwd(smbw_cwd); 620 } 621 622 smbw_busy--; 623 return ret; 624} 625 626/***************************************************** 627open a directory on the server 628*******************************************************/ 629DIR *smbw_opendir(const char *fname) 630{ 631 int fd; 632 633 smbw_busy++; 634 635 fd = smbw_dir_open(fname); 636 637 if (fd == -1) { 638 smbw_busy--; 639 return NULL; 640 } 641 642 smbw_busy--; 643 644 return (DIR *)smbw_dir(fd); 645} 646 647/***************************************************** 648read one entry from a directory 649*******************************************************/ 650struct dirent *smbw_readdir(DIR *dirp) 651{ 652 struct smbw_dir *d = (struct smbw_dir *)dirp; 653 static union { 654 char buf[DIRP_SIZE]; 655 struct dirent de; 656 } dbuf; 657 658 if (smbw_getdents(d->fd, &dbuf.de, DIRP_SIZE) > 0) 659 return &dbuf.de; 660 661 return NULL; 662} 663 664/***************************************************** 665close a DIR* 666*******************************************************/ 667int smbw_closedir(DIR *dirp) 668{ 669 struct smbw_dir *d = (struct smbw_dir *)dirp; 670 return smbw_close(d->fd); 671} 672 673/***************************************************** 674seek in a directory 675*******************************************************/ 676void smbw_seekdir(DIR *dirp, off_t offset) 677{ 678 struct smbw_dir *d = (struct smbw_dir *)dirp; 679 smbw_dir_lseek(d->fd,offset, SEEK_SET); 680} 681 682/***************************************************** 683current loc in a directory 684*******************************************************/ 685off_t smbw_telldir(DIR *dirp) 686{ 687 struct smbw_dir *d = (struct smbw_dir *)dirp; 688 return smbw_dir_lseek(d->fd,0,SEEK_CUR); 689} 690