root/source3/libsmb/libsmb_dir.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. remove_dir
  2. add_dirent
  3. list_unique_wg_fn
  4. list_fn
  5. dir_list_fn
  6. net_share_enum_rpc
  7. SMBC_check_options
  8. SMBC_opendir_ctx
  9. SMBC_closedir_ctx
  10. smbc_readdir_internal
  11. SMBC_readdir_ctx
  12. SMBC_getdents_ctx
  13. SMBC_mkdir_ctx
  14. rmdir_list_fn
  15. SMBC_rmdir_ctx
  16. SMBC_telldir_ctx
  17. check_dir_ent
  18. SMBC_lseekdir_ctx
  19. SMBC_fstatdir_ctx
  20. SMBC_chmod_ctx
  21. SMBC_utimes_ctx
  22. SMBC_unlink_ctx
  23. SMBC_rename_ctx

   1 /*
   2    Unix SMB/Netbios implementation.
   3    SMB client library implementation
   4    Copyright (C) Andrew Tridgell 1998
   5    Copyright (C) Richard Sharpe 2000, 2002
   6    Copyright (C) John Terpstra 2000
   7    Copyright (C) Tom Jansen (Ninja ISD) 2002
   8    Copyright (C) Derrell Lipman 2003-2008
   9    Copyright (C) Jeremy Allison 2007, 2008
  10 
  11    This program is free software; you can redistribute it and/or modify
  12    it under the terms of the GNU General Public License as published by
  13    the Free Software Foundation; either version 3 of the License, or
  14    (at your option) any later version.
  15 
  16    This program is distributed in the hope that it will be useful,
  17    but WITHOUT ANY WARRANTY; without even the implied warranty of
  18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19    GNU General Public License for more details.
  20 
  21    You should have received a copy of the GNU General Public License
  22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  23 */
  24 
  25 #include "includes.h"
  26 #include "libsmbclient.h"
  27 #include "libsmb_internal.h"
  28 
  29 
  30 /*
  31  * Routine to open a directory
  32  * We accept the URL syntax explained in SMBC_parse_path(), above.
  33  */
  34 
  35 static void
  36 remove_dir(SMBCFILE *dir)
     /* [<][>][^][v][top][bottom][index][help] */
  37 {
  38         struct smbc_dir_list *d,*f;
  39 
  40         d = dir->dir_list;
  41         while (d) {
  42 
  43                 f = d; d = d->next;
  44 
  45                 SAFE_FREE(f->dirent);
  46                 SAFE_FREE(f);
  47 
  48         }
  49 
  50         dir->dir_list = dir->dir_end = dir->dir_next = NULL;
  51 
  52 }
  53 
  54 static int
  55 add_dirent(SMBCFILE *dir,
     /* [<][>][^][v][top][bottom][index][help] */
  56            const char *name,
  57            const char *comment,
  58            uint32 type)
  59 {
  60         struct smbc_dirent *dirent;
  61         int size;
  62         int name_length = (name == NULL ? 0 : strlen(name));
  63         int comment_len = (comment == NULL ? 0 : strlen(comment));
  64 
  65         /*
  66          * Allocate space for the dirent, which must be increased by the
  67          * size of the name and the comment and 1 each for the null terminator.
  68          */
  69 
  70         size = sizeof(struct smbc_dirent) + name_length + comment_len + 2;
  71 
  72         dirent = (struct smbc_dirent *)SMB_MALLOC(size);
  73 
  74         if (!dirent) {
  75 
  76                 dir->dir_error = ENOMEM;
  77                 return -1;
  78 
  79         }
  80 
  81         ZERO_STRUCTP(dirent);
  82 
  83         if (dir->dir_list == NULL) {
  84 
  85                 dir->dir_list = SMB_MALLOC_P(struct smbc_dir_list);
  86                 if (!dir->dir_list) {
  87 
  88                         SAFE_FREE(dirent);
  89                         dir->dir_error = ENOMEM;
  90                         return -1;
  91 
  92                 }
  93                 ZERO_STRUCTP(dir->dir_list);
  94 
  95                 dir->dir_end = dir->dir_next = dir->dir_list;
  96         }
  97         else {
  98 
  99                 dir->dir_end->next = SMB_MALLOC_P(struct smbc_dir_list);
 100 
 101                 if (!dir->dir_end->next) {
 102 
 103                         SAFE_FREE(dirent);
 104                         dir->dir_error = ENOMEM;
 105                         return -1;
 106 
 107                 }
 108                 ZERO_STRUCTP(dir->dir_end->next);
 109 
 110                 dir->dir_end = dir->dir_end->next;
 111         }
 112 
 113         dir->dir_end->next = NULL;
 114         dir->dir_end->dirent = dirent;
 115 
 116         dirent->smbc_type = type;
 117         dirent->namelen = name_length;
 118         dirent->commentlen = comment_len;
 119         dirent->dirlen = size;
 120 
 121         /*
 122          * dirent->namelen + 1 includes the null (no null termination needed)
 123          * Ditto for dirent->commentlen.
 124          * The space for the two null bytes was allocated.
 125          */
 126         strncpy(dirent->name, (name?name:""), dirent->namelen + 1);
 127         dirent->comment = (char *)(&dirent->name + dirent->namelen + 1);
 128         strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1);
 129 
 130         return 0;
 131 
 132 }
 133 
 134 static void
 135 list_unique_wg_fn(const char *name,
     /* [<][>][^][v][top][bottom][index][help] */
 136                   uint32 type,
 137                   const char *comment,
 138                   void *state)
 139 {
 140         SMBCFILE *dir = (SMBCFILE *)state;
 141         struct smbc_dir_list *dir_list;
 142         struct smbc_dirent *dirent;
 143         int dirent_type;
 144         int do_remove = 0;
 145 
 146         dirent_type = dir->dir_type;
 147 
 148         if (add_dirent(dir, name, comment, dirent_type) < 0) {
 149 
 150                 /* An error occurred, what do we do? */
 151                 /* FIXME: Add some code here */
 152         }
 153 
 154         /* Point to the one just added */
 155         dirent = dir->dir_end->dirent;
 156 
 157         /* See if this was a duplicate */
 158         for (dir_list = dir->dir_list;
 159              dir_list != dir->dir_end;
 160              dir_list = dir_list->next) {
 161                 if (! do_remove &&
 162                     strcmp(dir_list->dirent->name, dirent->name) == 0) {
 163                         /* Duplicate.  End end of list need to be removed. */
 164                         do_remove = 1;
 165                 }
 166 
 167                 if (do_remove && dir_list->next == dir->dir_end) {
 168                         /* Found the end of the list.  Remove it. */
 169                         dir->dir_end = dir_list;
 170                         free(dir_list->next);
 171                         free(dirent);
 172                         dir_list->next = NULL;
 173                         break;
 174                 }
 175         }
 176 }
 177 
 178 static void
 179 list_fn(const char *name,
     /* [<][>][^][v][top][bottom][index][help] */
 180         uint32 type,
 181         const char *comment,
 182         void *state)
 183 {
 184         SMBCFILE *dir = (SMBCFILE *)state;
 185         int dirent_type;
 186 
 187         /*
 188          * We need to process the type a little ...
 189          *
 190          * Disk share     = 0x00000000
 191          * Print share    = 0x00000001
 192          * Comms share    = 0x00000002 (obsolete?)
 193          * IPC$ share     = 0x00000003
 194          *
 195          * administrative shares:
 196          * ADMIN$, IPC$, C$, D$, E$ ...  are type |= 0x80000000
 197          */
 198 
 199         if (dir->dir_type == SMBC_FILE_SHARE) {
 200                 switch (type) {
 201                 case 0 | 0x80000000:
 202                 case 0:
 203                         dirent_type = SMBC_FILE_SHARE;
 204                         break;
 205 
 206                 case 1:
 207                         dirent_type = SMBC_PRINTER_SHARE;
 208                         break;
 209 
 210                 case 2:
 211                         dirent_type = SMBC_COMMS_SHARE;
 212                         break;
 213 
 214                 case 3 | 0x80000000:
 215                 case 3:
 216                         dirent_type = SMBC_IPC_SHARE;
 217                         break;
 218 
 219                 default:
 220                         dirent_type = SMBC_FILE_SHARE; /* FIXME, error? */
 221                         break;
 222                 }
 223         }
 224         else {
 225                 dirent_type = dir->dir_type;
 226         }
 227 
 228         if (add_dirent(dir, name, comment, dirent_type) < 0) {
 229 
 230                 /* An error occurred, what do we do? */
 231                 /* FIXME: Add some code here */
 232 
 233         }
 234 }
 235 
 236 static void
 237 dir_list_fn(const char *mnt,
     /* [<][>][^][v][top][bottom][index][help] */
 238             file_info *finfo,
 239             const char *mask,
 240             void *state)
 241 {
 242 
 243         if (add_dirent((SMBCFILE *)state, finfo->name, "",
 244                        (finfo->mode&aDIR?SMBC_DIR:SMBC_FILE)) < 0) {
 245 
 246                 /* Handle an error ... */
 247 
 248                 /* FIXME: Add some code ... */
 249 
 250         }
 251 
 252 }
 253 
 254 static int
 255 net_share_enum_rpc(struct cli_state *cli,
     /* [<][>][^][v][top][bottom][index][help] */
 256                    void (*fn)(const char *name,
 257                               uint32 type,
 258                               const char *comment,
 259                               void *state),
 260                    void *state)
 261 {
 262         int i;
 263         WERROR result;
 264         uint32 preferred_len = 0xffffffff;
 265         uint32 type;
 266         struct srvsvc_NetShareInfoCtr info_ctr;
 267         struct srvsvc_NetShareCtr1 ctr1;
 268         fstring name = "";
 269         fstring comment = "";
 270         struct rpc_pipe_client *pipe_hnd;
 271         NTSTATUS nt_status;
 272         uint32_t resume_handle = 0;
 273         uint32_t total_entries = 0;
 274 
 275         /* Open the server service pipe */
 276         nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_srvsvc.syntax_id,
 277                                              &pipe_hnd);
 278         if (!NT_STATUS_IS_OK(nt_status)) {
 279                 DEBUG(1, ("net_share_enum_rpc pipe open fail!\n"));
 280                 return -1;
 281         }
 282 
 283         ZERO_STRUCT(info_ctr);
 284         ZERO_STRUCT(ctr1);
 285 
 286         info_ctr.level = 1;
 287         info_ctr.ctr.ctr1 = &ctr1;
 288 
 289         /* Issue the NetShareEnum RPC call and retrieve the response */
 290         nt_status = rpccli_srvsvc_NetShareEnumAll(pipe_hnd, talloc_tos(),
 291                                                   pipe_hnd->desthost,
 292                                                   &info_ctr,
 293                                                   preferred_len,
 294                                                   &total_entries,
 295                                                   &resume_handle,
 296                                                   &result);
 297 
 298         /* Was it successful? */
 299         if (!NT_STATUS_IS_OK(nt_status) || !W_ERROR_IS_OK(result) ||
 300             total_entries == 0) {
 301                 /*  Nope.  Go clean up. */
 302                 goto done;
 303         }
 304 
 305         /* For each returned entry... */
 306         for (i = 0; i < total_entries; i++) {
 307 
 308                 /* pull out the share name */
 309                 fstrcpy(name, info_ctr.ctr.ctr1->array[i].name);
 310 
 311                 /* pull out the share's comment */
 312                 fstrcpy(comment, info_ctr.ctr.ctr1->array[i].comment);
 313 
 314                 /* Get the type value */
 315                 type = info_ctr.ctr.ctr1->array[i].type;
 316 
 317                 /* Add this share to the list */
 318                 (*fn)(name, type, comment, state);
 319         }
 320 
 321 done:
 322         /* Close the server service pipe */
 323         TALLOC_FREE(pipe_hnd);
 324 
 325         /* Tell 'em if it worked */
 326         return W_ERROR_IS_OK(result) ? 0 : -1;
 327 }
 328 
 329 
 330 /*
 331  * Verify that the options specified in a URL are valid
 332  */
 333 int
 334 SMBC_check_options(char *server,
     /* [<][>][^][v][top][bottom][index][help] */
 335                    char *share,
 336                    char *path,
 337                    char *options)
 338 {
 339         DEBUG(4, ("SMBC_check_options(): server='%s' share='%s' "
 340                   "path='%s' options='%s'\n",
 341                   server, share, path, options));
 342 
 343         /* No options at all is always ok */
 344         if (! *options) return 0;
 345 
 346         /* Currently, we don't support any options. */
 347         return -1;
 348 }
 349 
 350 
 351 SMBCFILE *
 352 SMBC_opendir_ctx(SMBCCTX *context,
     /* [<][>][^][v][top][bottom][index][help] */
 353                  const char *fname)
 354 {
 355         int saved_errno;
 356         char *server = NULL;
 357         char *share = NULL;
 358         char *user = NULL;
 359         char *password = NULL;
 360         char *options = NULL;
 361         char *workgroup = NULL;
 362         char *path = NULL;
 363         uint16 mode;
 364         char *p = NULL;
 365         SMBCSRV *srv  = NULL;
 366         SMBCFILE *dir = NULL;
 367         struct sockaddr_storage rem_ss;
 368         TALLOC_CTX *frame = talloc_stackframe();
 369 
 370         if (!context || !context->internal->initialized) {
 371                 DEBUG(4, ("no valid context\n"));
 372                 errno = EINVAL + 8192;
 373                 TALLOC_FREE(frame);
 374                 return NULL;
 375 
 376         }
 377 
 378         if (!fname) {
 379                 DEBUG(4, ("no valid fname\n"));
 380                 errno = EINVAL + 8193;
 381                 TALLOC_FREE(frame);
 382                 return NULL;
 383         }
 384 
 385         if (SMBC_parse_path(frame,
 386                             context,
 387                             fname,
 388                             &workgroup,
 389                             &server,
 390                             &share,
 391                             &path,
 392                             &user,
 393                             &password,
 394                             &options)) {
 395                 DEBUG(4, ("no valid path\n"));
 396                 errno = EINVAL + 8194;
 397                 TALLOC_FREE(frame);
 398                 return NULL;
 399         }
 400 
 401         DEBUG(4, ("parsed path: fname='%s' server='%s' share='%s' "
 402                   "path='%s' options='%s'\n",
 403                   fname, server, share, path, options));
 404 
 405         /* Ensure the options are valid */
 406         if (SMBC_check_options(server, share, path, options)) {
 407                 DEBUG(4, ("unacceptable options (%s)\n", options));
 408                 errno = EINVAL + 8195;
 409                 TALLOC_FREE(frame);
 410                 return NULL;
 411         }
 412 
 413         if (!user || user[0] == (char)0) {
 414                 user = talloc_strdup(frame, smbc_getUser(context));
 415                 if (!user) {
 416                         errno = ENOMEM;
 417                         TALLOC_FREE(frame);
 418                         return NULL;
 419                 }
 420         }
 421 
 422         dir = SMB_MALLOC_P(SMBCFILE);
 423 
 424         if (!dir) {
 425                 errno = ENOMEM;
 426                 TALLOC_FREE(frame);
 427                 return NULL;
 428         }
 429 
 430         ZERO_STRUCTP(dir);
 431 
 432         dir->cli_fd   = 0;
 433         dir->fname    = SMB_STRDUP(fname);
 434         dir->srv      = NULL;
 435         dir->offset   = 0;
 436         dir->file     = False;
 437         dir->dir_list = dir->dir_next = dir->dir_end = NULL;
 438 
 439         if (server[0] == (char)0) {
 440 
 441                 int i;
 442                 int count;
 443                 int max_lmb_count;
 444                 struct ip_service *ip_list;
 445                 struct ip_service server_addr;
 446                 struct user_auth_info u_info;
 447 
 448                 if (share[0] != (char)0 || path[0] != (char)0) {
 449 
 450                         errno = EINVAL + 8196;
 451                         if (dir) {
 452                                 SAFE_FREE(dir->fname);
 453                                 SAFE_FREE(dir);
 454                         }
 455                         TALLOC_FREE(frame);
 456                         return NULL;
 457                 }
 458 
 459                 /* Determine how many local master browsers to query */
 460                 max_lmb_count = (smbc_getOptionBrowseMaxLmbCount(context) == 0
 461                                  ? INT_MAX
 462                                  : smbc_getOptionBrowseMaxLmbCount(context));
 463 
 464                 memset(&u_info, '\0', sizeof(u_info));
 465                 u_info.username = talloc_strdup(frame,user);
 466                 u_info.password = talloc_strdup(frame,password);
 467                 if (!u_info.username || !u_info.password) {
 468                         if (dir) {
 469                                 SAFE_FREE(dir->fname);
 470                                 SAFE_FREE(dir);
 471                         }
 472                         TALLOC_FREE(frame);
 473                         return NULL;
 474                 }
 475 
 476                 /*
 477                  * We have server and share and path empty but options
 478                  * requesting that we scan all master browsers for their list
 479                  * of workgroups/domains.  This implies that we must first try
 480                  * broadcast queries to find all master browsers, and if that
 481                  * doesn't work, then try our other methods which return only
 482                  * a single master browser.
 483                  */
 484 
 485                 ip_list = NULL;
 486                 if (!NT_STATUS_IS_OK(name_resolve_bcast(MSBROWSE, 1, &ip_list,
 487                                                         &count)))
 488                 {
 489 
 490                         SAFE_FREE(ip_list);
 491 
 492                         if (!find_master_ip(workgroup, &server_addr.ss)) {
 493 
 494                                 if (dir) {
 495                                         SAFE_FREE(dir->fname);
 496                                         SAFE_FREE(dir);
 497                                 }
 498                                 errno = ENOENT;
 499                                 TALLOC_FREE(frame);
 500                                 return NULL;
 501                         }
 502 
 503                         ip_list = (struct ip_service *)memdup(
 504                                 &server_addr, sizeof(server_addr));
 505                         if (ip_list == NULL) {
 506                                 errno = ENOMEM;
 507                                 TALLOC_FREE(frame);
 508                                 return NULL;
 509                         }
 510                         count = 1;
 511                 }
 512 
 513                 for (i = 0; i < count && i < max_lmb_count; i++) {
 514                         char addr[INET6_ADDRSTRLEN];
 515                         char *wg_ptr = NULL;
 516                         struct cli_state *cli = NULL;
 517 
 518                         print_sockaddr(addr, sizeof(addr), &ip_list[i].ss);
 519                         DEBUG(99, ("Found master browser %d of %d: %s\n",
 520                                    i+1, MAX(count, max_lmb_count),
 521                                    addr));
 522 
 523                         cli = get_ipc_connect_master_ip(talloc_tos(),
 524                                                         &ip_list[i],
 525                                                         &u_info,
 526                                                         &wg_ptr);
 527                         /* cli == NULL is the master browser refused to talk or
 528                            could not be found */
 529                         if (!cli) {
 530                                 continue;
 531                         }
 532 
 533                         workgroup = talloc_strdup(frame, wg_ptr);
 534                         server = talloc_strdup(frame, cli->desthost);
 535 
 536                         cli_shutdown(cli);
 537 
 538                         if (!workgroup || !server) {
 539                                 errno = ENOMEM;
 540                                 TALLOC_FREE(frame);
 541                                 return NULL;
 542                         }
 543 
 544                         DEBUG(4, ("using workgroup %s %s\n",
 545                                   workgroup, server));
 546 
 547                         /*
 548                          * For each returned master browser IP address, get a
 549                          * connection to IPC$ on the server if we do not
 550                          * already have one, and determine the
 551                          * workgroups/domains that it knows about.
 552                          */
 553 
 554                         srv = SMBC_server(frame, context, True, server, "IPC$",
 555                                           &workgroup, &user, &password);
 556                         if (!srv) {
 557                                 continue;
 558                         }
 559 
 560                         dir->srv = srv;
 561                         dir->dir_type = SMBC_WORKGROUP;
 562 
 563                         /* Now, list the stuff ... */
 564 
 565                         if (!cli_NetServerEnum(srv->cli,
 566                                                workgroup,
 567                                                SV_TYPE_DOMAIN_ENUM,
 568                                                list_unique_wg_fn,
 569                                                (void *)dir)) {
 570                                 continue;
 571                         }
 572                 }
 573 
 574                 SAFE_FREE(ip_list);
 575         } else {
 576                 /*
 577                  * Server not an empty string ... Check the rest and see what
 578                  * gives
 579                  */
 580                 if (*share == '\0') {
 581                         if (*path != '\0') {
 582 
 583                                 /* Should not have empty share with path */
 584                                 errno = EINVAL + 8197;
 585                                 if (dir) {
 586                                         SAFE_FREE(dir->fname);
 587                                         SAFE_FREE(dir);
 588                                 }
 589                                 TALLOC_FREE(frame);
 590                                 return NULL;
 591 
 592                         }
 593 
 594                         /*
 595                          * We don't know if <server> is really a server name
 596                          * or is a workgroup/domain name.  If we already have
 597                          * a server structure for it, we'll use it.
 598                          * Otherwise, check to see if <server><1D>,
 599                          * <server><1B>, or <server><20> translates.  We check
 600                          * to see if <server> is an IP address first.
 601                          */
 602 
 603                         /*
 604                          * See if we have an existing server.  Do not
 605                          * establish a connection if one does not already
 606                          * exist.
 607                          */
 608                         srv = SMBC_server(frame, context, False,
 609                                           server, "IPC$",
 610                                           &workgroup, &user, &password);
 611 
 612                         /*
 613                          * If no existing server and not an IP addr, look for
 614                          * LMB or DMB
 615                          */
 616                         if (!srv &&
 617                             !is_ipaddress(server) &&
 618                             (resolve_name(server, &rem_ss, 0x1d) ||   /* LMB */
 619                              resolve_name(server, &rem_ss, 0x1b) )) { /* DMB */
 620                                 /*
 621                                  * "server" is actually a workgroup name,
 622                                  * not a server. Make this clear.
 623                                  */
 624                                 char *wgroup = server;
 625                                 fstring buserver;
 626 
 627                                 dir->dir_type = SMBC_SERVER;
 628 
 629                                 /*
 630                                  * Get the backup list ...
 631                                  */
 632                                 if (!name_status_find(wgroup, 0, 0,
 633                                                       &rem_ss, buserver)) {
 634                                         char addr[INET6_ADDRSTRLEN];
 635 
 636                                         print_sockaddr(addr, sizeof(addr), &rem_ss);
 637                                         DEBUG(0,("Could not get name of "
 638                                                 "local/domain master browser "
 639                                                 "for workgroup %s fro m"
 640                                                 "address %s\n",
 641                                                 wgroup,
 642                                                 addr));
 643                                         if (dir) {
 644                                                 SAFE_FREE(dir->fname);
 645                                                 SAFE_FREE(dir);
 646                                         }
 647                                         errno = EPERM;
 648                                         TALLOC_FREE(frame);
 649                                         return NULL;
 650 
 651                                 }
 652 
 653                                 /*
 654                                  * Get a connection to IPC$ on the server if
 655                                  * we do not already have one
 656                                  */
 657                                 srv = SMBC_server(frame, context, True,
 658                                                   buserver, "IPC$",
 659                                                   &workgroup,
 660                                                   &user, &password);
 661                                 if (!srv) {
 662                                         DEBUG(0, ("got no contact to IPC$\n"));
 663                                         if (dir) {
 664                                                 SAFE_FREE(dir->fname);
 665                                                 SAFE_FREE(dir);
 666                                         }
 667                                         TALLOC_FREE(frame);
 668                                         return NULL;
 669 
 670                                 }
 671 
 672                                 dir->srv = srv;
 673 
 674                                 /* Now, list the servers ... */
 675                                 if (!cli_NetServerEnum(srv->cli, wgroup,
 676                                                        0x0000FFFE, list_fn,
 677                                                        (void *)dir)) {
 678 
 679                                         if (dir) {
 680                                                 SAFE_FREE(dir->fname);
 681                                                 SAFE_FREE(dir);
 682                                         }
 683                                         TALLOC_FREE(frame);
 684                                         return NULL;
 685                                 }
 686                         } else if (srv ||
 687                                    (resolve_name(server, &rem_ss, 0x20))) {
 688 
 689                                 /*
 690                                  * If we hadn't found the server, get one now
 691                                  */
 692                                 if (!srv) {
 693                                         srv = SMBC_server(frame, context, True,
 694                                                           server, "IPC$",
 695                                                           &workgroup,
 696                                                           &user, &password);
 697                                 }
 698 
 699                                 if (!srv) {
 700                                         if (dir) {
 701                                                 SAFE_FREE(dir->fname);
 702                                                 SAFE_FREE(dir);
 703                                         }
 704                                         TALLOC_FREE(frame);
 705                                         return NULL;
 706 
 707                                 }
 708 
 709                                 dir->dir_type = SMBC_FILE_SHARE;
 710                                 dir->srv = srv;
 711 
 712                                 /* List the shares ... */
 713 
 714                                 if (net_share_enum_rpc(
 715                                             srv->cli,
 716                                             list_fn,
 717                                             (void *) dir) < 0 &&
 718                                     cli_RNetShareEnum(
 719                                             srv->cli,
 720                                             list_fn,
 721                                             (void *)dir) < 0) {
 722 
 723                                         errno = cli_errno(srv->cli);
 724                                         if (dir) {
 725                                                 SAFE_FREE(dir->fname);
 726                                                 SAFE_FREE(dir);
 727                                         }
 728                                         TALLOC_FREE(frame);
 729                                         return NULL;
 730 
 731                                 }
 732                         } else {
 733                                 /* Neither the workgroup nor server exists */
 734                                 errno = ECONNREFUSED;
 735                                 if (dir) {
 736                                         SAFE_FREE(dir->fname);
 737                                         SAFE_FREE(dir);
 738                                 }
 739                                 TALLOC_FREE(frame);
 740                                 return NULL;
 741                         }
 742 
 743                 }
 744                 else {
 745                         /*
 746                          * The server and share are specified ... work from
 747                          * there ...
 748                          */
 749                         char *targetpath;
 750                         struct cli_state *targetcli;
 751 
 752                         /* We connect to the server and list the directory */
 753                         dir->dir_type = SMBC_FILE_SHARE;
 754 
 755                         srv = SMBC_server(frame, context, True, server, share,
 756                                           &workgroup, &user, &password);
 757 
 758                         if (!srv) {
 759                                 if (dir) {
 760                                         SAFE_FREE(dir->fname);
 761                                         SAFE_FREE(dir);
 762                                 }
 763                                 TALLOC_FREE(frame);
 764                                 return NULL;
 765                         }
 766 
 767                         dir->srv = srv;
 768 
 769                         /* Now, list the files ... */
 770 
 771                         p = path + strlen(path);
 772                         path = talloc_asprintf_append(path, "\\*");
 773                         if (!path) {
 774                                 if (dir) {
 775                                         SAFE_FREE(dir->fname);
 776                                         SAFE_FREE(dir);
 777                                 }
 778                                 TALLOC_FREE(frame);
 779                                 return NULL;
 780                         }
 781 
 782                         if (!cli_resolve_path(frame, "", context->internal->auth_info,
 783                                                 srv->cli, path,
 784                                                 &targetcli, &targetpath)) {
 785                                 d_printf("Could not resolve %s\n", path);
 786                                 if (dir) {
 787                                         SAFE_FREE(dir->fname);
 788                                         SAFE_FREE(dir);
 789                                 }
 790                                 TALLOC_FREE(frame);
 791                                 return NULL;
 792                         }
 793 
 794                         if (cli_list(targetcli, targetpath,
 795                                      aDIR | aSYSTEM | aHIDDEN,
 796                                      dir_list_fn, (void *)dir) < 0) {
 797 
 798                                 if (dir) {
 799                                         SAFE_FREE(dir->fname);
 800                                         SAFE_FREE(dir);
 801                                 }
 802                                 saved_errno = SMBC_errno(context, targetcli);
 803 
 804                                 if (saved_errno == EINVAL) {
 805                                         /*
 806                                          * See if they asked to opendir
 807                                          * something other than a directory.
 808                                          * If so, the converted error value we
 809                                          * got would have been EINVAL rather
 810                                          * than ENOTDIR.
 811                                          */
 812                                         *p = '\0'; /* restore original path */
 813 
 814                                         if (SMBC_getatr(context, srv, path,
 815                                                         &mode, NULL,
 816                                                         NULL, NULL, NULL, NULL,
 817                                                         NULL) &&
 818                                             ! IS_DOS_DIR(mode)) {
 819 
 820                                                 /* It is.  Correct the error value */
 821                                                 saved_errno = ENOTDIR;
 822                                         }
 823                                 }
 824 
 825                                 /*
 826                                  * If there was an error and the server is no
 827                                  * good any more...
 828                                  */
 829                                 if (cli_is_error(targetcli) &&
 830                                     smbc_getFunctionCheckServer(context)(context, srv)) {
 831 
 832                                         /* ... then remove it. */
 833                                         if (smbc_getFunctionRemoveUnusedServer(context)(context,
 834                                                                                         srv)) {
 835                                                 /*
 836                                                  * We could not remove the
 837                                                  * server completely, remove
 838                                                  * it from the cache so we
 839                                                  * will not get it again. It
 840                                                  * will be removed when the
 841                                                  * last file/dir is closed.
 842                                                  */
 843                                                 smbc_getFunctionRemoveCachedServer(context)(context, srv);
 844                                         }
 845                                 }
 846 
 847                                 errno = saved_errno;
 848                                 TALLOC_FREE(frame);
 849                                 return NULL;
 850                         }
 851                 }
 852 
 853         }
 854 
 855         DLIST_ADD(context->internal->files, dir);
 856         TALLOC_FREE(frame);
 857         return dir;
 858 
 859 }
 860 
 861 /*
 862  * Routine to close a directory
 863  */
 864 
 865 int
 866 SMBC_closedir_ctx(SMBCCTX *context,
     /* [<][>][^][v][top][bottom][index][help] */
 867                   SMBCFILE *dir)
 868 {
 869         TALLOC_CTX *frame = talloc_stackframe();
 870 
 871         if (!context || !context->internal->initialized) {
 872                 errno = EINVAL;
 873                 TALLOC_FREE(frame);
 874                 return -1;
 875         }
 876 
 877         if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
 878                 errno = EBADF;
 879                 TALLOC_FREE(frame);
 880                 return -1;
 881         }
 882 
 883         remove_dir(dir); /* Clean it up */
 884 
 885         DLIST_REMOVE(context->internal->files, dir);
 886 
 887         if (dir) {
 888 
 889                 SAFE_FREE(dir->fname);
 890                 SAFE_FREE(dir);    /* Free the space too */
 891         }
 892 
 893         TALLOC_FREE(frame);
 894         return 0;
 895 
 896 }
 897 
 898 static void
 899 smbc_readdir_internal(SMBCCTX * context,
     /* [<][>][^][v][top][bottom][index][help] */
 900                       struct smbc_dirent *dest,
 901                       struct smbc_dirent *src,
 902                       int max_namebuf_len)
 903 {
 904         if (smbc_getOptionUrlEncodeReaddirEntries(context)) {
 905 
 906                 /* url-encode the name.  get back remaining buffer space */
 907                 max_namebuf_len =
 908                         smbc_urlencode(dest->name, src->name, max_namebuf_len);
 909 
 910                 /* We now know the name length */
 911                 dest->namelen = strlen(dest->name);
 912 
 913                 /* Save the pointer to the beginning of the comment */
 914                 dest->comment = dest->name + dest->namelen + 1;
 915 
 916                 /* Copy the comment */
 917                 strncpy(dest->comment, src->comment, max_namebuf_len - 1);
 918                 dest->comment[max_namebuf_len - 1] = '\0';
 919 
 920                 /* Save other fields */
 921                 dest->smbc_type = src->smbc_type;
 922                 dest->commentlen = strlen(dest->comment);
 923                 dest->dirlen = ((dest->comment + dest->commentlen + 1) -
 924                                 (char *) dest);
 925         } else {
 926 
 927                 /* No encoding.  Just copy the entry as is. */
 928                 memcpy(dest, src, src->dirlen);
 929                 dest->comment = (char *)(&dest->name + src->namelen + 1);
 930         }
 931 
 932 }
 933 
 934 /*
 935  * Routine to get a directory entry
 936  */
 937 
 938 struct smbc_dirent *
 939 SMBC_readdir_ctx(SMBCCTX *context,
     /* [<][>][^][v][top][bottom][index][help] */
 940                  SMBCFILE *dir)
 941 {
 942         int maxlen;
 943         struct smbc_dirent *dirp, *dirent;
 944         TALLOC_CTX *frame = talloc_stackframe();
 945 
 946         /* Check that all is ok first ... */
 947 
 948         if (!context || !context->internal->initialized) {
 949 
 950                 errno = EINVAL;
 951                 DEBUG(0, ("Invalid context in SMBC_readdir_ctx()\n"));
 952                 TALLOC_FREE(frame);
 953                 return NULL;
 954 
 955         }
 956 
 957         if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
 958 
 959                 errno = EBADF;
 960                 DEBUG(0, ("Invalid dir in SMBC_readdir_ctx()\n"));
 961                 TALLOC_FREE(frame);
 962                 return NULL;
 963 
 964         }
 965 
 966         if (dir->file != False) { /* FIXME, should be dir, perhaps */
 967 
 968                 errno = ENOTDIR;
 969                 DEBUG(0, ("Found file vs directory in SMBC_readdir_ctx()\n"));
 970                 TALLOC_FREE(frame);
 971                 return NULL;
 972 
 973         }
 974 
 975         if (!dir->dir_next) {
 976                 TALLOC_FREE(frame);
 977                 return NULL;
 978         }
 979 
 980         dirent = dir->dir_next->dirent;
 981         if (!dirent) {
 982 
 983                 errno = ENOENT;
 984                 TALLOC_FREE(frame);
 985                 return NULL;
 986 
 987         }
 988 
 989         dirp = &context->internal->dirent;
 990         maxlen = sizeof(context->internal->_dirent_name);
 991 
 992         smbc_readdir_internal(context, dirp, dirent, maxlen);
 993 
 994         dir->dir_next = dir->dir_next->next;
 995 
 996         TALLOC_FREE(frame);
 997         return dirp;
 998 }
 999 
1000 /*
1001  * Routine to get directory entries
1002  */
1003 
1004 int
1005 SMBC_getdents_ctx(SMBCCTX *context,
     /* [<][>][^][v][top][bottom][index][help] */
1006                   SMBCFILE *dir,
1007                   struct smbc_dirent *dirp,
1008                   int count)
1009 {
1010         int rem = count;
1011         int reqd;
1012         int maxlen;
1013         char *ndir = (char *)dirp;
1014         struct smbc_dir_list *dirlist;
1015         TALLOC_CTX *frame = talloc_stackframe();
1016 
1017         /* Check that all is ok first ... */
1018 
1019         if (!context || !context->internal->initialized) {
1020 
1021                 errno = EINVAL;
1022                 TALLOC_FREE(frame);
1023                 return -1;
1024 
1025         }
1026 
1027         if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
1028 
1029                 errno = EBADF;
1030                 TALLOC_FREE(frame);
1031                 return -1;
1032 
1033         }
1034 
1035         if (dir->file != False) { /* FIXME, should be dir, perhaps */
1036 
1037                 errno = ENOTDIR;
1038                 TALLOC_FREE(frame);
1039                 return -1;
1040 
1041         }
1042 
1043         /*
1044          * Now, retrieve the number of entries that will fit in what was passed
1045          * We have to figure out if the info is in the list, or we need to
1046          * send a request to the server to get the info.
1047          */
1048 
1049         while ((dirlist = dir->dir_next)) {
1050                 struct smbc_dirent *dirent;
1051 
1052                 if (!dirlist->dirent) {
1053 
1054                         errno = ENOENT;  /* Bad error */
1055                         TALLOC_FREE(frame);
1056                         return -1;
1057 
1058                 }
1059 
1060                 /* Do urlencoding of next entry, if so selected */
1061                 dirent = &context->internal->dirent;
1062                 maxlen = sizeof(context->internal->_dirent_name);
1063                 smbc_readdir_internal(context, dirent,
1064                                       dirlist->dirent, maxlen);
1065 
1066                 reqd = dirent->dirlen;
1067 
1068                 if (rem < reqd) {
1069 
1070                         if (rem < count) { /* We managed to copy something */
1071 
1072                                 errno = 0;
1073                                 TALLOC_FREE(frame);
1074                                 return count - rem;
1075 
1076                         }
1077                         else { /* Nothing copied ... */
1078 
1079                                 errno = EINVAL;  /* Not enough space ... */
1080                                 TALLOC_FREE(frame);
1081                                 return -1;
1082 
1083                         }
1084 
1085                 }
1086 
1087                 memcpy(ndir, dirent, reqd); /* Copy the data in ... */
1088 
1089                 ((struct smbc_dirent *)ndir)->comment =
1090                         (char *)(&((struct smbc_dirent *)ndir)->name +
1091                                  dirent->namelen +
1092                                  1);
1093 
1094                 ndir += reqd;
1095 
1096                 rem -= reqd;
1097 
1098                 dir->dir_next = dirlist = dirlist -> next;
1099         }
1100 
1101         TALLOC_FREE(frame);
1102 
1103         if (rem == count)
1104                 return 0;
1105         else
1106                 return count - rem;
1107 
1108 }
1109 
1110 /*
1111  * Routine to create a directory ...
1112  */
1113 
1114 int
1115 SMBC_mkdir_ctx(SMBCCTX *context,
     /* [<][>][^][v][top][bottom][index][help] */
1116                const char *fname,
1117                mode_t mode)
1118 {
1119         SMBCSRV *srv = NULL;
1120         char *server = NULL;
1121         char *share = NULL;
1122         char *user = NULL;
1123         char *password = NULL;
1124         char *workgroup = NULL;
1125         char *path = NULL;
1126         char *targetpath = NULL;
1127         struct cli_state *targetcli = NULL;
1128         TALLOC_CTX *frame = talloc_stackframe();
1129 
1130         if (!context || !context->internal->initialized) {
1131                 errno = EINVAL;
1132                 TALLOC_FREE(frame);
1133                 return -1;
1134         }
1135 
1136         if (!fname) {
1137                 errno = EINVAL;
1138                 TALLOC_FREE(frame);
1139                 return -1;
1140         }
1141 
1142         DEBUG(4, ("smbc_mkdir(%s)\n", fname));
1143 
1144         if (SMBC_parse_path(frame,
1145                             context,
1146                             fname,
1147                             &workgroup,
1148                             &server,
1149                             &share,
1150                             &path,
1151                             &user,
1152                             &password,
1153                             NULL)) {
1154                 errno = EINVAL;
1155                 TALLOC_FREE(frame);
1156                 return -1;
1157         }
1158 
1159         if (!user || user[0] == (char)0) {
1160                 user = talloc_strdup(frame, smbc_getUser(context));
1161                 if (!user) {
1162                         errno = ENOMEM;
1163                         TALLOC_FREE(frame);
1164                         return -1;
1165                 }
1166         }
1167 
1168         srv = SMBC_server(frame, context, True,
1169                           server, share, &workgroup, &user, &password);
1170 
1171         if (!srv) {
1172 
1173                 TALLOC_FREE(frame);
1174                 return -1;  /* errno set by SMBC_server */
1175 
1176         }
1177 
1178         /*d_printf(">>>mkdir: resolving %s\n", path);*/
1179         if (!cli_resolve_path(frame, "", context->internal->auth_info,
1180                                 srv->cli, path,
1181                                 &targetcli, &targetpath)) {
1182                 d_printf("Could not resolve %s\n", path);
1183                 errno = ENOENT;
1184                 TALLOC_FREE(frame);
1185                 return -1;
1186         }
1187         /*d_printf(">>>mkdir: resolved path as %s\n", targetpath);*/
1188 
1189         if (!cli_mkdir(targetcli, targetpath)) {
1190 
1191                 errno = SMBC_errno(context, targetcli);
1192                 TALLOC_FREE(frame);
1193                 return -1;
1194 
1195         }
1196 
1197         TALLOC_FREE(frame);
1198         return 0;
1199 
1200 }
1201 
1202 /*
1203  * Our list function simply checks to see if a directory is not empty
1204  */
1205 
1206 static void
1207 rmdir_list_fn(const char *mnt,
     /* [<][>][^][v][top][bottom][index][help] */
1208               file_info *finfo,
1209               const char *mask,
1210               void *state)
1211 {
1212         if (strncmp(finfo->name, ".", 1) != 0 &&
1213             strncmp(finfo->name, "..", 2) != 0) {
1214                 bool *smbc_rmdir_dirempty = (bool *)state;
1215                 *smbc_rmdir_dirempty = false;
1216         }
1217 }
1218 
1219 /*
1220  * Routine to remove a directory
1221  */
1222 
1223 int
1224 SMBC_rmdir_ctx(SMBCCTX *context,
     /* [<][>][^][v][top][bottom][index][help] */
1225                const char *fname)
1226 {
1227         SMBCSRV *srv = NULL;
1228         char *server = NULL;
1229         char *share = NULL;
1230         char *user = NULL;
1231         char *password = NULL;
1232         char *workgroup = NULL;
1233         char *path = NULL;
1234         char *targetpath = NULL;
1235         struct cli_state *targetcli = NULL;
1236         TALLOC_CTX *frame = talloc_stackframe();
1237 
1238         if (!context || !context->internal->initialized) {
1239                 errno = EINVAL;
1240                 TALLOC_FREE(frame);
1241                 return -1;
1242         }
1243 
1244         if (!fname) {
1245                 errno = EINVAL;
1246                 TALLOC_FREE(frame);
1247                 return -1;
1248         }
1249 
1250         DEBUG(4, ("smbc_rmdir(%s)\n", fname));
1251 
1252         if (SMBC_parse_path(frame,
1253                             context,
1254                             fname,
1255                             &workgroup,
1256                             &server,
1257                             &share,
1258                             &path,
1259                             &user,
1260                             &password,
1261                             NULL)) {
1262                 errno = EINVAL;
1263                 TALLOC_FREE(frame);
1264                 return -1;
1265         }
1266 
1267         if (!user || user[0] == (char)0) {
1268                 user = talloc_strdup(frame, smbc_getUser(context));
1269                 if (!user) {
1270                         errno = ENOMEM;
1271                         TALLOC_FREE(frame);
1272                         return -1;
1273                 }
1274         }
1275 
1276         srv = SMBC_server(frame, context, True,
1277                           server, share, &workgroup, &user, &password);
1278 
1279         if (!srv) {
1280 
1281                 TALLOC_FREE(frame);
1282                 return -1;  /* errno set by SMBC_server */
1283 
1284         }
1285 
1286         /*d_printf(">>>rmdir: resolving %s\n", path);*/
1287         if (!cli_resolve_path(frame, "", context->internal->auth_info,
1288                                 srv->cli, path,
1289                                 &targetcli, &targetpath)) {
1290                 d_printf("Could not resolve %s\n", path);
1291                 errno = ENOENT;
1292                 TALLOC_FREE(frame);
1293                 return -1;
1294         }
1295         /*d_printf(">>>rmdir: resolved path as %s\n", targetpath);*/
1296 
1297 
1298         if (!cli_rmdir(targetcli, targetpath)) {
1299 
1300                 errno = SMBC_errno(context, targetcli);
1301 
1302                 if (errno == EACCES) {  /* Check if the dir empty or not */
1303 
1304                         /* Local storage to avoid buffer overflows */
1305                         char *lpath;
1306                         bool smbc_rmdir_dirempty = true;
1307 
1308                         lpath = talloc_asprintf(frame, "%s\\*",
1309                                                 targetpath);
1310                         if (!lpath) {
1311                                 errno = ENOMEM;
1312                                 TALLOC_FREE(frame);
1313                                 return -1;
1314                         }
1315 
1316                         if (cli_list(targetcli, lpath,
1317                                      aDIR | aSYSTEM | aHIDDEN,
1318                                      rmdir_list_fn,
1319                                      &smbc_rmdir_dirempty) < 0) {
1320 
1321                                 /* Fix errno to ignore latest error ... */
1322                                 DEBUG(5, ("smbc_rmdir: "
1323                                           "cli_list returned an error: %d\n",
1324                                           SMBC_errno(context, targetcli)));
1325                                 errno = EACCES;
1326 
1327                         }
1328 
1329                         if (smbc_rmdir_dirempty)
1330                                 errno = EACCES;
1331                         else
1332                                 errno = ENOTEMPTY;
1333 
1334                 }
1335 
1336                 TALLOC_FREE(frame);
1337                 return -1;
1338 
1339         }
1340 
1341         TALLOC_FREE(frame);
1342         return 0;
1343 
1344 }
1345 
1346 /*
1347  * Routine to return the current directory position
1348  */
1349 
1350 off_t
1351 SMBC_telldir_ctx(SMBCCTX *context,
     /* [<][>][^][v][top][bottom][index][help] */
1352                  SMBCFILE *dir)
1353 {
1354         TALLOC_CTX *frame = talloc_stackframe();
1355 
1356         if (!context || !context->internal->initialized) {
1357 
1358                 errno = EINVAL;
1359                 TALLOC_FREE(frame);
1360                 return -1;
1361 
1362         }
1363 
1364         if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
1365 
1366                 errno = EBADF;
1367                 TALLOC_FREE(frame);
1368                 return -1;
1369 
1370         }
1371 
1372         if (dir->file != False) { /* FIXME, should be dir, perhaps */
1373 
1374                 errno = ENOTDIR;
1375                 TALLOC_FREE(frame);
1376                 return -1;
1377 
1378         }
1379 
1380         /* See if we're already at the end. */
1381         if (dir->dir_next == NULL) {
1382                 /* We are. */
1383                 TALLOC_FREE(frame);
1384                 return -1;
1385         }
1386 
1387         /*
1388          * We return the pointer here as the offset
1389          */
1390         TALLOC_FREE(frame);
1391         return (off_t)(long)dir->dir_next->dirent;
1392 }
1393 
1394 /*
1395  * A routine to run down the list and see if the entry is OK
1396  */
1397 
1398 static struct smbc_dir_list *
1399 check_dir_ent(struct smbc_dir_list *list,
     /* [<][>][^][v][top][bottom][index][help] */
1400               struct smbc_dirent *dirent)
1401 {
1402 
1403         /* Run down the list looking for what we want */
1404 
1405         if (dirent) {
1406 
1407                 struct smbc_dir_list *tmp = list;
1408 
1409                 while (tmp) {
1410 
1411                         if (tmp->dirent == dirent)
1412                                 return tmp;
1413 
1414                         tmp = tmp->next;
1415 
1416                 }
1417 
1418         }
1419 
1420         return NULL;  /* Not found, or an error */
1421 
1422 }
1423 
1424 
1425 /*
1426  * Routine to seek on a directory
1427  */
1428 
1429 int
1430 SMBC_lseekdir_ctx(SMBCCTX *context,
     /* [<][>][^][v][top][bottom][index][help] */
1431                   SMBCFILE *dir,
1432                   off_t offset)
1433 {
1434         long int l_offset = offset;  /* Handle problems of size */
1435         struct smbc_dirent *dirent = (struct smbc_dirent *)l_offset;
1436         struct smbc_dir_list *list_ent = (struct smbc_dir_list *)NULL;
1437         TALLOC_CTX *frame = talloc_stackframe();
1438 
1439         if (!context || !context->internal->initialized) {
1440 
1441                 errno = EINVAL;
1442                 TALLOC_FREE(frame);
1443                 return -1;
1444 
1445         }
1446 
1447         if (dir->file != False) { /* FIXME, should be dir, perhaps */
1448 
1449                 errno = ENOTDIR;
1450                 TALLOC_FREE(frame);
1451                 return -1;
1452 
1453         }
1454 
1455         /* Now, check what we were passed and see if it is OK ... */
1456 
1457         if (dirent == NULL) {  /* Seek to the begining of the list */
1458 
1459                 dir->dir_next = dir->dir_list;
1460                 TALLOC_FREE(frame);
1461                 return 0;
1462 
1463         }
1464 
1465         if (offset == -1) {     /* Seek to the end of the list */
1466                 dir->dir_next = NULL;
1467                 TALLOC_FREE(frame);
1468                 return 0;
1469         }
1470 
1471         /* Now, run down the list and make sure that the entry is OK       */
1472         /* This may need to be changed if we change the format of the list */
1473 
1474         if ((list_ent = check_dir_ent(dir->dir_list, dirent)) == NULL) {
1475                 errno = EINVAL;   /* Bad entry */
1476                 TALLOC_FREE(frame);
1477                 return -1;
1478         }
1479 
1480         dir->dir_next = list_ent;
1481 
1482         TALLOC_FREE(frame);
1483         return 0;
1484 }
1485 
1486 /*
1487  * Routine to fstat a dir
1488  */
1489 
1490 int
1491 SMBC_fstatdir_ctx(SMBCCTX *context,
     /* [<][>][^][v][top][bottom][index][help] */
1492                   SMBCFILE *dir,
1493                   struct stat *st)
1494 {
1495 
1496         if (!context || !context->internal->initialized) {
1497 
1498                 errno = EINVAL;
1499                 return -1;
1500         }
1501 
1502         /* No code yet ... */
1503         return 0;
1504 }
1505 
1506 int
1507 SMBC_chmod_ctx(SMBCCTX *context,
     /* [<][>][^][v][top][bottom][index][help] */
1508                const char *fname,
1509                mode_t newmode)
1510 {
1511         SMBCSRV *srv = NULL;
1512         char *server = NULL;
1513         char *share = NULL;
1514         char *user = NULL;
1515         char *password = NULL;
1516         char *workgroup = NULL;
1517         char *targetpath = NULL;
1518         struct cli_state *targetcli = NULL;
1519         char *path = NULL;
1520         uint16 mode;
1521         TALLOC_CTX *frame = talloc_stackframe();
1522 
1523         if (!context || !context->internal->initialized) {
1524 
1525                 errno = EINVAL;  /* Best I can think of ... */
1526                 TALLOC_FREE(frame);
1527                 return -1;
1528         }
1529 
1530         if (!fname) {
1531                 errno = EINVAL;
1532                 TALLOC_FREE(frame);
1533                 return -1;
1534         }
1535 
1536         DEBUG(4, ("smbc_chmod(%s, 0%3o)\n", fname, (unsigned int)newmode));
1537 
1538         if (SMBC_parse_path(frame,
1539                             context,
1540                             fname,
1541                             &workgroup,
1542                             &server,
1543                             &share,
1544                             &path,
1545                             &user,
1546                             &password,
1547                             NULL)) {
1548                 errno = EINVAL;
1549                 TALLOC_FREE(frame);
1550                 return -1;
1551         }
1552 
1553         if (!user || user[0] == (char)0) {
1554                 user = talloc_strdup(frame, smbc_getUser(context));
1555                 if (!user) {
1556                         errno = ENOMEM;
1557                         TALLOC_FREE(frame);
1558                         return -1;
1559                 }
1560         }
1561 
1562         srv = SMBC_server(frame, context, True,
1563                           server, share, &workgroup, &user, &password);
1564 
1565         if (!srv) {
1566                 TALLOC_FREE(frame);
1567                 return -1;  /* errno set by SMBC_server */
1568         }
1569         
1570         /*d_printf(">>>unlink: resolving %s\n", path);*/
1571         if (!cli_resolve_path(frame, "", context->internal->auth_info,
1572                                 srv->cli, path,
1573                                 &targetcli, &targetpath)) {
1574                 d_printf("Could not resolve %s\n", path);
1575                 errno = ENOENT;
1576                 TALLOC_FREE(frame);
1577                 return -1;
1578         }
1579 
1580         mode = 0;
1581 
1582         if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY;
1583         if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH;
1584         if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM;
1585         if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN;
1586 
1587         if (!cli_setatr(targetcli, targetpath, mode, 0)) {
1588                 errno = SMBC_errno(context, targetcli);
1589                 TALLOC_FREE(frame);
1590                 return -1;
1591         }
1592 
1593         TALLOC_FREE(frame);
1594         return 0;
1595 }
1596 
1597 int
1598 SMBC_utimes_ctx(SMBCCTX *context,
     /* [<][>][^][v][top][bottom][index][help] */
1599                 const char *fname,
1600                 struct timeval *tbuf)
1601 {
1602         SMBCSRV *srv = NULL;
1603         char *server = NULL;
1604         char *share = NULL;
1605         char *user = NULL;
1606         char *password = NULL;
1607         char *workgroup = NULL;
1608         char *path = NULL;
1609         time_t access_time;
1610         time_t write_time;
1611         TALLOC_CTX *frame = talloc_stackframe();
1612 
1613         if (!context || !context->internal->initialized) {
1614 
1615                 errno = EINVAL;  /* Best I can think of ... */
1616                 TALLOC_FREE(frame);
1617                 return -1;
1618         }
1619 
1620         if (!fname) {
1621                 errno = EINVAL;
1622                 TALLOC_FREE(frame);
1623                 return -1;
1624         }
1625 
1626         if (tbuf == NULL) {
1627                 access_time = write_time = time(NULL);
1628         } else {
1629                 access_time = tbuf[0].tv_sec;
1630                 write_time = tbuf[1].tv_sec;
1631         }
1632 
1633         if (DEBUGLVL(4)) {
1634                 char *p;
1635                 char atimebuf[32];
1636                 char mtimebuf[32];
1637 
1638                 strncpy(atimebuf, ctime(&access_time), sizeof(atimebuf) - 1);
1639                 atimebuf[sizeof(atimebuf) - 1] = '\0';
1640                 if ((p = strchr(atimebuf, '\n')) != NULL) {
1641                         *p = '\0';
1642                 }
1643 
1644                 strncpy(mtimebuf, ctime(&write_time), sizeof(mtimebuf) - 1);
1645                 mtimebuf[sizeof(mtimebuf) - 1] = '\0';
1646                 if ((p = strchr(mtimebuf, '\n')) != NULL) {
1647                         *p = '\0';
1648                 }
1649 
1650                 dbgtext("smbc_utimes(%s, atime = %s mtime = %s)\n",
1651                         fname, atimebuf, mtimebuf);
1652         }
1653 
1654         if (SMBC_parse_path(frame,
1655                             context,
1656                             fname,
1657                             &workgroup,
1658                             &server,
1659                             &share,
1660                             &path,
1661                             &user,
1662                             &password,
1663                             NULL)) {
1664                 errno = EINVAL;
1665                 TALLOC_FREE(frame);
1666                 return -1;
1667         }
1668 
1669         if (!user || user[0] == (char)0) {
1670                 user = talloc_strdup(frame, smbc_getUser(context));
1671                 if (!user) {
1672                         errno = ENOMEM;
1673                         TALLOC_FREE(frame);
1674                         return -1;
1675                 }
1676         }
1677 
1678         srv = SMBC_server(frame, context, True,
1679                           server, share, &workgroup, &user, &password);
1680 
1681         if (!srv) {
1682                 TALLOC_FREE(frame);
1683                 return -1;      /* errno set by SMBC_server */
1684         }
1685 
1686         if (!SMBC_setatr(context, srv, path,
1687                          0, access_time, write_time, 0, 0)) {
1688                 TALLOC_FREE(frame);
1689                 return -1;      /* errno set by SMBC_setatr */
1690         }
1691 
1692         TALLOC_FREE(frame);
1693         return 0;
1694 }
1695 
1696 /*
1697  * Routine to unlink() a file
1698  */
1699 
1700 int
1701 SMBC_unlink_ctx(SMBCCTX *context,
     /* [<][>][^][v][top][bottom][index][help] */
1702                 const char *fname)
1703 {
1704         char *server = NULL;
1705         char *share = NULL;
1706         char *user = NULL;
1707         char *password = NULL;
1708         char *workgroup = NULL;
1709         char *path = NULL;
1710         char *targetpath = NULL;
1711         struct cli_state *targetcli = NULL;
1712         SMBCSRV *srv = NULL;
1713         TALLOC_CTX *frame = talloc_stackframe();
1714 
1715         if (!context || !context->internal->initialized) {
1716 
1717                 errno = EINVAL;  /* Best I can think of ... */
1718                 TALLOC_FREE(frame);
1719                 return -1;
1720 
1721         }
1722 
1723         if (!fname) {
1724                 errno = EINVAL;
1725                 TALLOC_FREE(frame);
1726                 return -1;
1727 
1728         }
1729 
1730         if (SMBC_parse_path(frame,
1731                             context,
1732                             fname,
1733                             &workgroup,
1734                             &server,
1735                             &share,
1736                             &path,
1737                             &user,
1738                             &password,
1739                             NULL)) {
1740                 errno = EINVAL;
1741                 TALLOC_FREE(frame);
1742                 return -1;
1743         }
1744 
1745         if (!user || user[0] == (char)0) {
1746                 user = talloc_strdup(frame, smbc_getUser(context));
1747                 if (!user) {
1748                         errno = ENOMEM;
1749                         TALLOC_FREE(frame);
1750                         return -1;
1751                 }
1752         }
1753 
1754         srv = SMBC_server(frame, context, True,
1755                           server, share, &workgroup, &user, &password);
1756 
1757         if (!srv) {
1758                 TALLOC_FREE(frame);
1759                 return -1;  /* SMBC_server sets errno */
1760 
1761         }
1762 
1763         /*d_printf(">>>unlink: resolving %s\n", path);*/
1764         if (!cli_resolve_path(frame, "", context->internal->auth_info,
1765                                 srv->cli, path,
1766                                 &targetcli, &targetpath)) {
1767                 d_printf("Could not resolve %s\n", path);
1768                 errno = ENOENT;
1769                 TALLOC_FREE(frame);
1770                 return -1;
1771         }
1772         /*d_printf(">>>unlink: resolved path as %s\n", targetpath);*/
1773 
1774         if (!cli_unlink(targetcli, targetpath)) {
1775 
1776                 errno = SMBC_errno(context, targetcli);
1777 
1778                 if (errno == EACCES) { /* Check if the file is a directory */
1779 
1780                         int saverr = errno;
1781                         SMB_OFF_T size = 0;
1782                         uint16 mode = 0;
1783                         struct timespec write_time_ts;
1784                         struct timespec access_time_ts;
1785                         struct timespec change_time_ts;
1786                         SMB_INO_T ino = 0;
1787 
1788                         if (!SMBC_getatr(context, srv, path, &mode, &size,
1789                                          NULL,
1790                                          &access_time_ts,
1791                                          &write_time_ts,
1792                                          &change_time_ts,
1793                                          &ino)) {
1794 
1795                                 /* Hmmm, bad error ... What? */
1796 
1797                                 errno = SMBC_errno(context, targetcli);
1798                                 TALLOC_FREE(frame);
1799                                 return -1;
1800 
1801                         }
1802                         else {
1803 
1804                                 if (IS_DOS_DIR(mode))
1805                                         errno = EISDIR;
1806                                 else
1807                                         errno = saverr;  /* Restore this */
1808 
1809                         }
1810                 }
1811 
1812                 TALLOC_FREE(frame);
1813                 return -1;
1814 
1815         }
1816 
1817         TALLOC_FREE(frame);
1818         return 0;  /* Success ... */
1819 
1820 }
1821 
1822 /*
1823  * Routine to rename() a file
1824  */
1825 
1826 int
1827 SMBC_rename_ctx(SMBCCTX *ocontext,
     /* [<][>][^][v][top][bottom][index][help] */
1828                 const char *oname,
1829                 SMBCCTX *ncontext,
1830                 const char *nname)
1831 {
1832         char *server1 = NULL;
1833         char *share1 = NULL;
1834         char *server2 = NULL;
1835         char *share2 = NULL;
1836         char *user1 = NULL;
1837         char *user2 = NULL;
1838         char *password1 = NULL;
1839         char *password2 = NULL;
1840         char *workgroup = NULL;
1841         char *path1 = NULL;
1842         char *path2 = NULL;
1843         char *targetpath1 = NULL;
1844         char *targetpath2 = NULL;
1845         struct cli_state *targetcli1 = NULL;
1846         struct cli_state *targetcli2 = NULL;
1847         SMBCSRV *srv = NULL;
1848         TALLOC_CTX *frame = talloc_stackframe();
1849 
1850         if (!ocontext || !ncontext ||
1851             !ocontext->internal->initialized ||
1852             !ncontext->internal->initialized) {
1853 
1854                 errno = EINVAL;  /* Best I can think of ... */
1855                 TALLOC_FREE(frame);
1856                 return -1;
1857         }
1858 
1859         if (!oname || !nname) {
1860                 errno = EINVAL;
1861                 TALLOC_FREE(frame);
1862                 return -1;
1863         }
1864 
1865         DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname));
1866 
1867         if (SMBC_parse_path(frame,
1868                             ocontext,
1869                             oname,
1870                             &workgroup,
1871                             &server1,
1872                             &share1,
1873                             &path1,
1874                             &user1,
1875                             &password1,
1876                             NULL)) {
1877                 errno = EINVAL;
1878                 TALLOC_FREE(frame);
1879                 return -1;
1880         }
1881 
1882         if (!user1 || user1[0] == (char)0) {
1883                 user1 = talloc_strdup(frame, smbc_getUser(ocontext));
1884                 if (!user1) {
1885                         errno = ENOMEM;
1886                         TALLOC_FREE(frame);
1887                         return -1;
1888                 }
1889         }
1890 
1891         if (SMBC_parse_path(frame,
1892                             ncontext,
1893                             nname,
1894                             NULL,
1895                             &server2,
1896                             &share2,
1897                             &path2,
1898                             &user2,
1899                             &password2,
1900                             NULL)) {
1901                 errno = EINVAL;
1902                 TALLOC_FREE(frame);
1903                 return -1;
1904         }
1905 
1906         if (!user2 || user2[0] == (char)0) {
1907                 user2 = talloc_strdup(frame, smbc_getUser(ncontext));
1908                 if (!user2) {
1909                         errno = ENOMEM;
1910                         TALLOC_FREE(frame);
1911                         return -1;
1912                 }
1913         }
1914 
1915         if (strcmp(server1, server2) || strcmp(share1, share2) ||
1916             strcmp(user1, user2)) {
1917                 /* Can't rename across file systems, or users?? */
1918                 errno = EXDEV;
1919                 TALLOC_FREE(frame);
1920                 return -1;
1921         }
1922 
1923         srv = SMBC_server(frame, ocontext, True,
1924                           server1, share1, &workgroup, &user1, &password1);
1925         if (!srv) {
1926                 TALLOC_FREE(frame);
1927                 return -1;
1928 
1929         }
1930 
1931         /* set the credentials to make DFS work */
1932         smbc_set_credentials_with_fallback(ocontext,
1933                                            workgroup,
1934                                            user1,
1935                                            password1);
1936 
1937         /*d_printf(">>>rename: resolving %s\n", path1);*/
1938         if (!cli_resolve_path(frame, "", ocontext->internal->auth_info,
1939                                 srv->cli,
1940                                 path1,
1941                                 &targetcli1, &targetpath1)) {
1942                 d_printf("Could not resolve %s\n", path1);
1943                 errno = ENOENT;
1944                 TALLOC_FREE(frame);
1945                 return -1;
1946         }
1947         
1948         /* set the credentials to make DFS work */
1949         smbc_set_credentials_with_fallback(ncontext,
1950                                            workgroup,
1951                                            user2,
1952                                            password2);
1953         
1954         /*d_printf(">>>rename: resolved path as %s\n", targetpath1);*/
1955         /*d_printf(">>>rename: resolving %s\n", path2);*/
1956         if (!cli_resolve_path(frame, "", ncontext->internal->auth_info,
1957                                 srv->cli, 
1958                                 path2,
1959                                 &targetcli2, &targetpath2)) {
1960                 d_printf("Could not resolve %s\n", path2);
1961                 errno = ENOENT;
1962                 TALLOC_FREE(frame);
1963                 return -1;
1964         }
1965         /*d_printf(">>>rename: resolved path as %s\n", targetpath2);*/
1966 
1967         if (strcmp(targetcli1->desthost, targetcli2->desthost) ||
1968             strcmp(targetcli1->share, targetcli2->share))
1969         {
1970                 /* can't rename across file systems */
1971                 errno = EXDEV;
1972                 TALLOC_FREE(frame);
1973                 return -1;
1974         }
1975 
1976         if (!cli_rename(targetcli1, targetpath1, targetpath2)) {
1977                 int eno = SMBC_errno(ocontext, targetcli1);
1978 
1979                 if (eno != EEXIST ||
1980                     !cli_unlink(targetcli1, targetpath2) ||
1981                     !cli_rename(targetcli1, targetpath1, targetpath2)) {
1982 
1983                         errno = eno;
1984                         TALLOC_FREE(frame);
1985                         return -1;
1986 
1987                 }
1988         }
1989 
1990         TALLOC_FREE(frame);
1991         return 0; /* Success */
1992 }
1993 

/* [<][>][^][v][top][bottom][index][help] */