tdb_fetch_compat: use instead of tdb_fetch.
[kai/samba.git] / source3 / libsmb / libsmb_dir.c
index 9cb3351433c945301a0e4dfeb6358ef71d0a842c..ea75dbf26494d6a1fe9c81020dffd66cfabb93cd 100644 (file)
@@ -1,31 +1,35 @@
-/* 
+/*
    Unix SMB/Netbios implementation.
    SMB client library implementation
    Copyright (C) Andrew Tridgell 1998
    Copyright (C) Richard Sharpe 2000, 2002
    Copyright (C) John Terpstra 2000
-   Copyright (C) Tom Jansen (Ninja ISD) 2002 
+   Copyright (C) Tom Jansen (Ninja ISD) 2002
    Copyright (C) Derrell Lipman 2003-2008
    Copyright (C) Jeremy Allison 2007, 2008
-   
+
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
-   
+
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
-   
+
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
+#include "libsmb/libsmb.h"
+#include "popt_common.h"
 #include "libsmbclient.h"
 #include "libsmb_internal.h"
-
+#include "rpc_client/cli_pipe.h"
+#include "../librpc/gen_ndr/ndr_srvsvc_c.h"
+#include "libsmb/nmblib.h"
 
 /*
  * Routine to open a directory
@@ -63,12 +67,12 @@ add_dirent(SMBCFILE *dir,
         int comment_len = (comment == NULL ? 0 : strlen(comment));
 
        /*
-        * Allocate space for the dirent, which must be increased by the 
+        * Allocate space for the dirent, which must be increased by the
         * size of the name and the comment and 1 each for the null terminator.
         */
 
        size = sizeof(struct smbc_dirent) + name_length + comment_len + 2;
-    
+
        dirent = (struct smbc_dirent *)SMB_MALLOC(size);
 
        if (!dirent) {
@@ -97,9 +101,9 @@ add_dirent(SMBCFILE *dir,
        else {
 
                dir->dir_end->next = SMB_MALLOC_P(struct smbc_dir_list);
-               
+
                if (!dir->dir_end->next) {
-                       
+
                        SAFE_FREE(dirent);
                        dir->dir_error = ENOMEM;
                        return -1;
@@ -112,12 +116,12 @@ add_dirent(SMBCFILE *dir,
 
        dir->dir_end->next = NULL;
        dir->dir_end->dirent = dirent;
-       
+
        dirent->smbc_type = type;
        dirent->namelen = name_length;
        dirent->commentlen = comment_len;
        dirent->dirlen = size;
-  
+
         /*
          * dirent->namelen + 1 includes the null (no null termination needed)
          * Ditto for dirent->commentlen.
@@ -126,7 +130,7 @@ add_dirent(SMBCFILE *dir,
        strncpy(dirent->name, (name?name:""), dirent->namelen + 1);
        dirent->comment = (char *)(&dirent->name + dirent->namelen + 1);
        strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1);
-       
+
        return 0;
 
 }
@@ -146,9 +150,10 @@ list_unique_wg_fn(const char *name,
        dirent_type = dir->dir_type;
 
        if (add_dirent(dir, name, comment, dirent_type) < 0) {
-
                /* An error occurred, what do we do? */
                /* FIXME: Add some code here */
+               /* Change cli_NetServerEnum to take a fn
+                  returning NTSTATUS... JRA. */
        }
 
         /* Point to the one just added */
@@ -226,29 +231,26 @@ list_fn(const char *name,
         }
 
        if (add_dirent(dir, name, comment, dirent_type) < 0) {
-
                /* An error occurred, what do we do? */
                /* FIXME: Add some code here */
-
+               /* Change cli_NetServerEnum to take a fn
+                  returning NTSTATUS... JRA. */
        }
 }
 
-static void
+static NTSTATUS
 dir_list_fn(const char *mnt,
-            file_info *finfo,
+            struct file_info *finfo,
             const char *mask,
             void *state)
 {
 
-       if (add_dirent((SMBCFILE *)state, finfo->name, "", 
-                      (finfo->mode&aDIR?SMBC_DIR:SMBC_FILE)) < 0) {
-
-               /* Handle an error ... */
-
-               /* FIXME: Add some code ... */
-
-       } 
-
+       if (add_dirent((SMBCFILE *)state, finfo->name, "",
+                      (finfo->mode&FILE_ATTRIBUTE_DIRECTORY?SMBC_DIR:SMBC_FILE)) < 0) {
+               SMBCFILE *dir = (SMBCFILE *)state;
+               return map_nt_error_from_unix(dir->dir_error);
+       }
+       return NT_STATUS_OK;
 }
 
 static int
@@ -261,51 +263,72 @@ net_share_enum_rpc(struct cli_state *cli,
 {
         int i;
        WERROR result;
-       ENUM_HND enum_hnd;
-        uint32 info_level = 1;
        uint32 preferred_len = 0xffffffff;
         uint32 type;
-       SRV_SHARE_INFO_CTR ctr;
+       struct srvsvc_NetShareInfoCtr info_ctr;
+       struct srvsvc_NetShareCtr1 ctr1;
        fstring name = "";
         fstring comment = "";
-       struct rpc_pipe_client *pipe_hnd;
+       struct rpc_pipe_client *pipe_hnd = NULL;
         NTSTATUS nt_status;
+       uint32_t resume_handle = 0;
+       uint32_t total_entries = 0;
+       struct dcerpc_binding_handle *b;
 
         /* Open the server service pipe */
-        pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SRVSVC, &nt_status);
-        if (!pipe_hnd) {
+        nt_status = cli_rpc_pipe_open_noauth(cli, &ndr_table_srvsvc.syntax_id,
+                                            &pipe_hnd);
+        if (!NT_STATUS_IS_OK(nt_status)) {
                 DEBUG(1, ("net_share_enum_rpc pipe open fail!\n"));
                 return -1;
         }
 
+       ZERO_STRUCT(info_ctr);
+       ZERO_STRUCT(ctr1);
+
+       info_ctr.level = 1;
+       info_ctr.ctr.ctr1 = &ctr1;
+
+       b = pipe_hnd->binding_handle;
+
         /* Issue the NetShareEnum RPC call and retrieve the response */
-       init_enum_hnd(&enum_hnd, 0);
-       result = rpccli_srvsvc_net_share_enum(pipe_hnd,
-                                              talloc_tos(),
-                                              info_level,
-                                              &ctr,
-                                              preferred_len,
-                                              &enum_hnd);
+       nt_status = dcerpc_srvsvc_NetShareEnumAll(b, talloc_tos(),
+                                                 pipe_hnd->desthost,
+                                                 &info_ctr,
+                                                 preferred_len,
+                                                 &total_entries,
+                                                 &resume_handle,
+                                                 &result);
 
         /* Was it successful? */
-       if (!W_ERROR_IS_OK(result) || ctr.num_entries == 0) {
+       if (!NT_STATUS_IS_OK(nt_status)) {
+                /*  Nope.  Go clean up. */
+               result = ntstatus_to_werror(nt_status);
+               goto done;
+       }
+
+       if (!W_ERROR_IS_OK(result)) {
                 /*  Nope.  Go clean up. */
                goto done;
         }
 
+       if (total_entries == 0) {
+                /*  Nope.  Go clean up. */
+               result = WERR_GENERAL_FAILURE;
+               goto done;
+       }
+
         /* For each returned entry... */
-        for (i = 0; i < ctr.num_entries; i++) {
+        for (i = 0; i < info_ctr.ctr.ctr1->count; i++) {
 
                 /* pull out the share name */
-                rpcstr_pull_unistr2_fstring(
-                        name, &ctr.share.info1[i].info_1_str.uni_netname);
+               fstrcpy(name, info_ctr.ctr.ctr1->array[i].name);
 
                 /* pull out the share's comment */
-                rpcstr_pull_unistr2_fstring(
-                        comment, &ctr.share.info1[i].info_1_str.uni_remark);
+               fstrcpy(comment, info_ctr.ctr.ctr1->array[i].comment);
 
                 /* Get the type value */
-                type = ctr.share.info1[i].info_1.type;
+                type = info_ctr.ctr.ctr1->array[i].type;
 
                 /* Add this share to the list */
                 (*fn)(name, type, comment, state);
@@ -313,7 +336,7 @@ net_share_enum_rpc(struct cli_state *cli,
 
 done:
         /* Close the server service pipe */
-        cli_rpc_pipe_close(pipe_hnd);
+        TALLOC_FREE(pipe_hnd);
 
         /* Tell 'em if it worked */
         return W_ERROR_IS_OK(result) ? 0 : -1;
@@ -346,7 +369,11 @@ SMBC_opendir_ctx(SMBCCTX *context,
                  const char *fname)
 {
         int saved_errno;
-       char *server = NULL, *share = NULL, *user = NULL, *password = NULL, *options = NULL;
+       char *server = NULL;
+        char *share = NULL;
+        char *user = NULL;
+        char *password = NULL;
+        char *options = NULL;
        char *workgroup = NULL;
        char *path = NULL;
         uint16 mode;
@@ -356,34 +383,34 @@ SMBC_opendir_ctx(SMBCCTX *context,
        struct sockaddr_storage rem_ss;
        TALLOC_CTX *frame = talloc_stackframe();
 
-       if (!context || !context->initialized) {
+       if (!context || !context->internal->initialized) {
                DEBUG(4, ("no valid context\n"));
-               errno = EINVAL + 8192;
                TALLOC_FREE(frame);
+               errno = EINVAL + 8192;
                return NULL;
 
        }
 
        if (!fname) {
                DEBUG(4, ("no valid fname\n"));
-               errno = EINVAL + 8193;
                TALLOC_FREE(frame);
+               errno = EINVAL + 8193;
                return NULL;
        }
 
        if (SMBC_parse_path(frame,
-                               context,
-                               fname,
-                               &workgroup,
-                               &server,
-                               &share,
-                               &path,
-                               &user,
-                               &password,
-                               &options)) {
+                            context,
+                            fname,
+                            &workgroup,
+                            &server,
+                            &share,
+                            &path,
+                            &user,
+                            &password,
+                            &options)) {
                DEBUG(4, ("no valid path\n"));
-               errno = EINVAL + 8194;
                TALLOC_FREE(frame);
+               errno = EINVAL + 8194;
                return NULL;
        }
 
@@ -394,16 +421,16 @@ SMBC_opendir_ctx(SMBCCTX *context,
         /* Ensure the options are valid */
         if (SMBC_check_options(server, share, path, options)) {
                 DEBUG(4, ("unacceptable options (%s)\n", options));
-                errno = EINVAL + 8195;
                TALLOC_FREE(frame);
+                errno = EINVAL + 8195;
                 return NULL;
         }
 
        if (!user || user[0] == (char)0) {
-               user = talloc_strdup(frame, context->user);
+               user = talloc_strdup(frame, smbc_getUser(context));
                if (!user) {
-                       errno = ENOMEM;
                        TALLOC_FREE(frame);
+                       errno = ENOMEM;
                        return NULL;
                }
        }
@@ -411,8 +438,8 @@ SMBC_opendir_ctx(SMBCCTX *context,
        dir = SMB_MALLOC_P(SMBCFILE);
 
        if (!dir) {
-               errno = ENOMEM;
                TALLOC_FREE(frame);
+               errno = ENOMEM;
                return NULL;
        }
 
@@ -430,25 +457,26 @@ SMBC_opendir_ctx(SMBCCTX *context,
                 int i;
                 int count;
                 int max_lmb_count;
-                struct ip_service *ip_list;
-                struct ip_service server_addr;
+                struct sockaddr_storage *ip_list;
+                struct sockaddr_storage server_addr;
                 struct user_auth_info u_info;
+               NTSTATUS status;
 
                if (share[0] != (char)0 || path[0] != (char)0) {
 
-                       errno = EINVAL + 8196;
                        if (dir) {
                                SAFE_FREE(dir->fname);
                                SAFE_FREE(dir);
                        }
                        TALLOC_FREE(frame);
+                       errno = EINVAL + 8196;
                        return NULL;
                }
 
                 /* Determine how many local master browsers to query */
-                max_lmb_count = (context->browse_max_lmb_count == 0
+                max_lmb_count = (smbc_getOptionBrowseMaxLmbCount(context) == 0
                                  ? INT_MAX
-                                 : context->browse_max_lmb_count);
+                                 : smbc_getOptionBrowseMaxLmbCount(context));
 
                memset(&u_info, '\0', sizeof(u_info));
                u_info.username = talloc_strdup(frame,user);
@@ -472,28 +500,34 @@ SMBC_opendir_ctx(SMBCCTX *context,
                  */
 
                 ip_list = NULL;
-                if (!NT_STATUS_IS_OK(name_resolve_bcast(MSBROWSE, 1, &ip_list,
-                                    &count)))
+               status = name_resolve_bcast(MSBROWSE, 1, talloc_tos(),
+                                           &ip_list, &count);
+                if (!NT_STATUS_IS_OK(status))
                {
 
-                        SAFE_FREE(ip_list);
+                        TALLOC_FREE(ip_list);
 
-                        if (!find_master_ip(workgroup, &server_addr.ss)) {
+                        if (!find_master_ip(workgroup, &server_addr)) {
 
                                if (dir) {
                                        SAFE_FREE(dir->fname);
                                        SAFE_FREE(dir);
                                }
-                                errno = ENOENT;
                                TALLOC_FREE(frame);
+                                errno = ENOENT;
                                 return NULL;
                         }
 
-                       ip_list = (struct ip_service *)memdup(
-                               &server_addr, sizeof(server_addr));
+                       ip_list = (struct sockaddr_storage *)talloc_memdup(
+                               talloc_tos(), &server_addr,
+                               sizeof(server_addr));
                        if (ip_list == NULL) {
-                               errno = ENOMEM;
+                               if (dir) {
+                                       SAFE_FREE(dir->fname);
+                                       SAFE_FREE(dir);
+                               }
                                TALLOC_FREE(frame);
+                               errno = ENOMEM;
                                return NULL;
                        }
                         count = 1;
@@ -504,7 +538,7 @@ SMBC_opendir_ctx(SMBCCTX *context,
                        char *wg_ptr = NULL;
                        struct cli_state *cli = NULL;
 
-                       print_sockaddr(addr, sizeof(addr), &ip_list[i].ss);
+                       print_sockaddr(addr, sizeof(addr), &ip_list[i]);
                         DEBUG(99, ("Found master browser %d of %d: %s\n",
                                    i+1, MAX(count, max_lmb_count),
                                    addr));
@@ -525,8 +559,12 @@ SMBC_opendir_ctx(SMBCCTX *context,
                         cli_shutdown(cli);
 
                        if (!workgroup || !server) {
-                               errno = ENOMEM;
+                               if (dir) {
+                                       SAFE_FREE(dir->fname);
+                                       SAFE_FREE(dir);
+                               }
                                TALLOC_FREE(frame);
+                               errno = ENOMEM;
                                return NULL;
                        }
 
@@ -560,7 +598,7 @@ SMBC_opendir_ctx(SMBCCTX *context,
                         }
                 }
 
-                SAFE_FREE(ip_list);
+                TALLOC_FREE(ip_list);
         } else {
                 /*
                  * Server not an empty string ... Check the rest and see what
@@ -570,12 +608,12 @@ SMBC_opendir_ctx(SMBCCTX *context,
                        if (*path != '\0') {
 
                                 /* Should not have empty share with path */
-                               errno = EINVAL + 8197;
                                if (dir) {
                                        SAFE_FREE(dir->fname);
                                        SAFE_FREE(dir);
                                }
                                TALLOC_FREE(frame);
+                               errno = EINVAL + 8197;
                                return NULL;
 
                        }
@@ -594,7 +632,8 @@ SMBC_opendir_ctx(SMBCCTX *context,
                          * establish a connection if one does not already
                          * exist.
                          */
-                        srv = SMBC_server(frame, context, False, server, "IPC$",
+                        srv = SMBC_server(frame, context, False,
+                                          server, "IPC$",
                                           &workgroup, &user, &password);
 
                         /*
@@ -603,9 +642,13 @@ SMBC_opendir_ctx(SMBCCTX *context,
                          */
                        if (!srv &&
                             !is_ipaddress(server) &&
-                           (resolve_name(server, &rem_ss, 0x1d) ||   /* LMB */
-                             resolve_name(server, &rem_ss, 0x1b) )) { /* DMB */
-
+                           (resolve_name(server, &rem_ss, 0x1d, false) ||   /* LMB */
+                             resolve_name(server, &rem_ss, 0x1b, false) )) { /* DMB */
+                               /*
+                                * "server" is actually a workgroup name,
+                                * not a server. Make this clear.
+                                */
+                               char *wgroup = server;
                                fstring buserver;
 
                                dir->dir_type = SMBC_SERVER;
@@ -613,18 +656,23 @@ SMBC_opendir_ctx(SMBCCTX *context,
                                /*
                                 * Get the backup list ...
                                 */
-                               if (!name_status_find(server, 0, 0,
+                               if (!name_status_find(wgroup, 0, 0,
                                                       &rem_ss, buserver)) {
-
-                                        DEBUG(0, ("Could not get name of "
-                                                  "local/domain master browser "
-                                                  "for server %s\n", server));
+                                       char addr[INET6_ADDRSTRLEN];
+
+                                       print_sockaddr(addr, sizeof(addr), &rem_ss);
+                                        DEBUG(0,("Could not get name of "
+                                                "local/domain master browser "
+                                                "for workgroup %s from "
+                                               "address %s\n",
+                                               wgroup,
+                                               addr));
                                        if (dir) {
                                                SAFE_FREE(dir->fname);
                                                SAFE_FREE(dir);
                                        }
-                                       errno = EPERM;
                                        TALLOC_FREE(frame);
+                                       errno = EPERM;
                                        return NULL;
 
                                }
@@ -635,7 +683,8 @@ SMBC_opendir_ctx(SMBCCTX *context,
                                  */
                                srv = SMBC_server(frame, context, True,
                                                   buserver, "IPC$",
-                                                  &workgroup, &user, &password);
+                                                  &workgroup,
+                                                  &user, &password);
                                if (!srv) {
                                        DEBUG(0, ("got no contact to IPC$\n"));
                                        if (dir) {
@@ -650,7 +699,7 @@ SMBC_opendir_ctx(SMBCCTX *context,
                                dir->srv = srv;
 
                                /* Now, list the servers ... */
-                               if (!cli_NetServerEnum(srv->cli, server,
+                               if (!cli_NetServerEnum(srv->cli, wgroup,
                                                        0x0000FFFE, list_fn,
                                                       (void *)dir)) {
 
@@ -662,9 +711,11 @@ SMBC_opendir_ctx(SMBCCTX *context,
                                        return NULL;
                                }
                        } else if (srv ||
-                                   (resolve_name(server, &rem_ss, 0x20))) {
+                                   (resolve_name(server, &rem_ss, 0x20, false))) {
 
-                                /* If we hadn't found the server, get one now */
+                                /*
+                                 * If we hadn't found the server, get one now
+                                 */
                                 if (!srv) {
                                         srv = SMBC_server(frame, context, True,
                                                           server, "IPC$",
@@ -724,6 +775,7 @@ SMBC_opendir_ctx(SMBCCTX *context,
                          */
                        char *targetpath;
                        struct cli_state *targetcli;
+                       NTSTATUS status;
 
                        /* We connect to the server and list the directory */
                        dir->dir_type = SMBC_FILE_SHARE;
@@ -755,8 +807,9 @@ SMBC_opendir_ctx(SMBCCTX *context,
                                return NULL;
                        }
 
-                       if (!cli_resolve_path(frame, "", srv->cli, path,
-                                              &targetcli, &targetpath)) {
+                       if (!cli_resolve_path(frame, "", context->internal->auth_info,
+                                               srv->cli, path,
+                                               &targetcli, &targetpath)) {
                                d_printf("Could not resolve %s\n", path);
                                if (dir) {
                                        SAFE_FREE(dir->fname);
@@ -766,10 +819,10 @@ SMBC_opendir_ctx(SMBCCTX *context,
                                return NULL;
                        }
 
-                       if (cli_list(targetcli, targetpath,
-                                     aDIR | aSYSTEM | aHIDDEN,
-                                     dir_list_fn, (void *)dir) < 0) {
-
+                       status = cli_list(targetcli, targetpath,
+                                         FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
+                                         dir_list_fn, (void *)dir);
+                       if (!NT_STATUS_IS_OK(status)) {
                                if (dir) {
                                        SAFE_FREE(dir->fname);
                                        SAFE_FREE(dir);
@@ -777,23 +830,24 @@ SMBC_opendir_ctx(SMBCCTX *context,
                                saved_errno = SMBC_errno(context, targetcli);
 
                                 if (saved_errno == EINVAL) {
-                                    /*
-                                     * See if they asked to opendir something
-                                     * other than a directory.  If so, the
-                                     * converted error value we got would have
-                                     * been EINVAL rather than ENOTDIR.
-                                     */
-                                    *p = '\0'; /* restore original path */
-
-                                    if (SMBC_getatr(context, srv, path,
-                                                    &mode, NULL,
-                                                    NULL, NULL, NULL, NULL,
-                                                    NULL) &&
-                                        ! IS_DOS_DIR(mode)) {
-
-                                        /* It is.  Correct the error value */
-                                        saved_errno = ENOTDIR;
-                                    }
+                                        /*
+                                         * See if they asked to opendir
+                                         * something other than a directory.
+                                         * If so, the converted error value we
+                                         * got would have been EINVAL rather
+                                         * than ENOTDIR.
+                                         */
+                                        *p = '\0'; /* restore original path */
+
+                                        if (SMBC_getatr(context, srv, path,
+                                                        &mode, NULL,
+                                                        NULL, NULL, NULL, NULL,
+                                                        NULL) &&
+                                            ! IS_DOS_DIR(mode)) {
+
+                                                /* It is.  Correct the error value */
+                                                saved_errno = ENOTDIR;
+                                        }
                                 }
 
                                 /*
@@ -801,11 +855,11 @@ SMBC_opendir_ctx(SMBCCTX *context,
                                  * good any more...
                                  */
                                 if (cli_is_error(targetcli) &&
-                                    (context->server.check_server_fn)(context, srv)) {
+                                    smbc_getFunctionCheckServer(context)(context, srv)) {
 
                                         /* ... then remove it. */
-                                        if ((context->server.remove_unused_server_fn)(context,
-                                                                          srv)) { 
+                                        if (smbc_getFunctionRemoveUnusedServer(context)(context,
+                                                                                        srv)) {
                                                 /*
                                                  * We could not remove the
                                                  * server completely, remove
@@ -814,19 +868,19 @@ SMBC_opendir_ctx(SMBCCTX *context,
                                                  * will be removed when the
                                                  * last file/dir is closed.
                                                  */
-                                                (context->cache.remove_cached_server_fn)(context, srv);
+                                                smbc_getFunctionRemoveCachedServer(context)(context, srv);
                                         }
                                 }
 
-                                errno = saved_errno;
                                TALLOC_FREE(frame);
+                                errno = saved_errno;
                                return NULL;
                        }
                }
 
        }
 
-       DLIST_ADD(context->files, dir);
+       DLIST_ADD(context->internal->files, dir);
        TALLOC_FREE(frame);
        return dir;
 
@@ -842,13 +896,13 @@ SMBC_closedir_ctx(SMBCCTX *context,
 {
        TALLOC_CTX *frame = talloc_stackframe();
 
-       if (!context || !context->initialized) {
+       if (!context || !context->internal->initialized) {
                errno = EINVAL;
                TALLOC_FREE(frame);
                return -1;
        }
 
-       if (!dir || !SMBC_dlist_contains(context->files, dir)) {
+       if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
                errno = EBADF;
                TALLOC_FREE(frame);
                return -1;
@@ -856,7 +910,7 @@ SMBC_closedir_ctx(SMBCCTX *context,
 
        remove_dir(dir); /* Clean it up */
 
-       DLIST_REMOVE(context->files, dir);
+       DLIST_REMOVE(context->internal->files, dir);
 
        if (dir) {
 
@@ -875,11 +929,11 @@ smbc_readdir_internal(SMBCCTX * context,
                       struct smbc_dirent *src,
                       int max_namebuf_len)
 {
-        if (context->urlencode_readdir_entries) {
+        if (smbc_getOptionUrlEncodeReaddirEntries(context)) {
 
                 /* url-encode the name.  get back remaining buffer space */
                 max_namebuf_len =
-                        SMBC_urlencode(dest->name, src->name, max_namebuf_len);
+                        smbc_urlencode(dest->name, src->name, max_namebuf_len);
 
                 /* We now know the name length */
                 dest->namelen = strlen(dest->name);
@@ -902,7 +956,7 @@ smbc_readdir_internal(SMBCCTX * context,
                 memcpy(dest, src, src->dirlen);
                 dest->comment = (char *)(&dest->name + src->namelen + 1);
         }
-        
+
 }
 
 /*
@@ -919,7 +973,7 @@ SMBC_readdir_ctx(SMBCCTX *context,
 
        /* Check that all is ok first ... */
 
-       if (!context || !context->initialized) {
+       if (!context || !context->internal->initialized) {
 
                errno = EINVAL;
                 DEBUG(0, ("Invalid context in SMBC_readdir_ctx()\n"));
@@ -928,7 +982,7 @@ SMBC_readdir_ctx(SMBCCTX *context,
 
        }
 
-       if (!dir || !SMBC_dlist_contains(context->files, dir)) {
+       if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
 
                errno = EBADF;
                 DEBUG(0, ("Invalid dir in SMBC_readdir_ctx()\n"));
@@ -960,9 +1014,8 @@ SMBC_readdir_ctx(SMBCCTX *context,
 
         }
 
-        dirp = (struct smbc_dirent *)context->dirent;
-        maxlen = (sizeof(context->dirent) -
-                  sizeof(struct smbc_dirent));
+        dirp = &context->internal->dirent;
+        maxlen = sizeof(context->internal->_dirent_name);
 
         smbc_readdir_internal(context, dirp, dirent, maxlen);
 
@@ -991,7 +1044,7 @@ SMBC_getdents_ctx(SMBCCTX *context,
 
        /* Check that all is ok first ... */
 
-       if (!context || !context->initialized) {
+       if (!context || !context->internal->initialized) {
 
                errno = EINVAL;
                TALLOC_FREE(frame);
@@ -999,12 +1052,12 @@ SMBC_getdents_ctx(SMBCCTX *context,
 
        }
 
-       if (!dir || !SMBC_dlist_contains(context->files, dir)) {
+       if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
 
                errno = EBADF;
                TALLOC_FREE(frame);
                return -1;
-    
+
        }
 
        if (dir->file != False) { /* FIXME, should be dir, perhaps */
@@ -1015,14 +1068,15 @@ SMBC_getdents_ctx(SMBCCTX *context,
 
        }
 
-       /* 
+       /*
         * Now, retrieve the number of entries that will fit in what was passed
-        * We have to figure out if the info is in the list, or we need to 
+        * We have to figure out if the info is in the list, or we need to
         * send a request to the server to get the info.
         */
 
        while ((dirlist = dir->dir_next)) {
                struct smbc_dirent *dirent;
+               struct smbc_dirent *currentEntry = (struct smbc_dirent *)ndir;
 
                if (!dirlist->dirent) {
 
@@ -1033,10 +1087,10 @@ SMBC_getdents_ctx(SMBCCTX *context,
                }
 
                 /* Do urlencoding of next entry, if so selected */
-                dirent = (struct smbc_dirent *)context->dirent;
-                maxlen = (sizeof(context->dirent) -
-                          sizeof(struct smbc_dirent));
-                smbc_readdir_internal(context, dirent, dirlist->dirent, maxlen);
+                dirent = &context->internal->dirent;
+                maxlen = sizeof(context->internal->_dirent_name);
+                smbc_readdir_internal(context, dirent,
+                                      dirlist->dirent, maxlen);
 
                 reqd = dirent->dirlen;
 
@@ -1059,17 +1113,23 @@ SMBC_getdents_ctx(SMBCCTX *context,
 
                }
 
-               memcpy(ndir, dirent, reqd); /* Copy the data in ... */
-    
-               ((struct smbc_dirent *)ndir)->comment = 
-                       (char *)(&((struct smbc_dirent *)ndir)->name +
-                                 dirent->namelen +
-                                 1);
+               memcpy(currentEntry, dirent, reqd); /* Copy the data in ... */
 
-               ndir += reqd;
+               currentEntry->comment = &currentEntry->name[0] +
+                                               dirent->namelen + 1;
 
+               ndir += reqd;
                rem -= reqd;
 
+               /* Try and align the struct for the next entry
+                  on a valid pointer boundary by appending zeros */
+               while((rem > 0) && ((unsigned long long)ndir & (sizeof(void*) - 1))) {
+                       *ndir = '\0';
+                       rem--;
+                       ndir++;
+                       currentEntry->dirlen++;
+               }
+
                dir->dir_next = dirlist = dirlist -> next;
        }
 
@@ -1102,7 +1162,7 @@ SMBC_mkdir_ctx(SMBCCTX *context,
        struct cli_state *targetcli = NULL;
        TALLOC_CTX *frame = talloc_stackframe();
 
-       if (!context || !context->initialized) {
+       if (!context || !context->internal->initialized) {
                errno = EINVAL;
                TALLOC_FREE(frame);
                return -1;
@@ -1117,22 +1177,22 @@ SMBC_mkdir_ctx(SMBCCTX *context,
        DEBUG(4, ("smbc_mkdir(%s)\n", fname));
 
        if (SMBC_parse_path(frame,
-                               context,
-                               fname,
-                               &workgroup,
-                               &server,
-                               &share,
-                               &path,
-                               &user,
-                               &password,
-                               NULL)) {
+                            context,
+                            fname,
+                            &workgroup,
+                            &server,
+                            &share,
+                            &path,
+                            &user,
+                            &password,
+                            NULL)) {
                 errno = EINVAL;
                TALLOC_FREE(frame);
                return -1;
         }
 
        if (!user || user[0] == (char)0) {
-               user = talloc_strdup(frame, context->user);
+               user = talloc_strdup(frame, smbc_getUser(context));
                if (!user) {
                        errno = ENOMEM;
                        TALLOC_FREE(frame);
@@ -1151,21 +1211,22 @@ SMBC_mkdir_ctx(SMBCCTX *context,
        }
 
        /*d_printf(">>>mkdir: resolving %s\n", path);*/
-       if (!cli_resolve_path(frame, "", srv->cli, path,
+       if (!cli_resolve_path(frame, "", context->internal->auth_info,
+                               srv->cli, path,
                                &targetcli, &targetpath)) {
                d_printf("Could not resolve %s\n", path);
-               TALLOC_FREE(frame);
+                errno = ENOENT;
+                TALLOC_FREE(frame);
                return -1;
        }
        /*d_printf(">>>mkdir: resolved path as %s\n", targetpath);*/
 
-       if (!cli_mkdir(targetcli, targetpath)) {
-
+       if (!NT_STATUS_IS_OK(cli_mkdir(targetcli, targetpath))) {
                errno = SMBC_errno(context, targetcli);
                TALLOC_FREE(frame);
                return -1;
 
-       } 
+       }
 
        TALLOC_FREE(frame);
        return 0;
@@ -1176,18 +1237,18 @@ SMBC_mkdir_ctx(SMBCCTX *context,
  * Our list function simply checks to see if a directory is not empty
  */
 
-static int smbc_rmdir_dirempty = True;
-
-static void
+static NTSTATUS
 rmdir_list_fn(const char *mnt,
-              file_info *finfo,
+              struct file_info *finfo,
               const char *mask,
               void *state)
 {
        if (strncmp(finfo->name, ".", 1) != 0 &&
             strncmp(finfo->name, "..", 2) != 0) {
-               smbc_rmdir_dirempty = False;
+               bool *smbc_rmdir_dirempty = (bool *)state;
+               *smbc_rmdir_dirempty = false;
         }
+       return NT_STATUS_OK;
 }
 
 /*
@@ -1209,7 +1270,7 @@ SMBC_rmdir_ctx(SMBCCTX *context,
        struct cli_state *targetcli = NULL;
        TALLOC_CTX *frame = talloc_stackframe();
 
-       if (!context || !context->initialized) {
+       if (!context || !context->internal->initialized) {
                errno = EINVAL;
                TALLOC_FREE(frame);
                return -1;
@@ -1224,22 +1285,22 @@ SMBC_rmdir_ctx(SMBCCTX *context,
        DEBUG(4, ("smbc_rmdir(%s)\n", fname));
 
        if (SMBC_parse_path(frame,
-                               context,
-                               fname,
-                               &workgroup,
-                               &server,
-                               &share,
-                               &path,
-                               &user,
-                               &password,
-                               NULL)) {
+                            context,
+                            fname,
+                            &workgroup,
+                            &server,
+                            &share,
+                            &path,
+                            &user,
+                            &password,
+                            NULL)) {
                 errno = EINVAL;
                TALLOC_FREE(frame);
                return -1;
         }
 
        if (!user || user[0] == (char)0) {
-               user = talloc_strdup(frame, context->user);
+               user = talloc_strdup(frame, smbc_getUser(context));
                if (!user) {
                        errno = ENOMEM;
                        TALLOC_FREE(frame);
@@ -1258,16 +1319,17 @@ SMBC_rmdir_ctx(SMBCCTX *context,
        }
 
        /*d_printf(">>>rmdir: resolving %s\n", path);*/
-       if (!cli_resolve_path(frame, "", srv->cli, path,
+       if (!cli_resolve_path(frame, "", context->internal->auth_info,
+                               srv->cli, path,
                                &targetcli, &targetpath)) {
                d_printf("Could not resolve %s\n", path);
+                errno = ENOENT;
                TALLOC_FREE(frame);
                return -1;
        }
        /*d_printf(">>>rmdir: resolved path as %s\n", targetpath);*/
 
-
-       if (!cli_rmdir(targetcli, targetpath)) {
+       if (!NT_STATUS_IS_OK(cli_rmdir(targetcli, targetpath))) {
 
                errno = SMBC_errno(context, targetcli);
 
@@ -1275,8 +1337,8 @@ SMBC_rmdir_ctx(SMBCCTX *context,
 
                         /* Local storage to avoid buffer overflows */
                        char *lpath;
-
-                       smbc_rmdir_dirempty = True;  /* Make this so ... */
+                       bool smbc_rmdir_dirempty = true;
+                       NTSTATUS status;
 
                        lpath = talloc_asprintf(frame, "%s\\*",
                                                targetpath);
@@ -1286,10 +1348,12 @@ SMBC_rmdir_ctx(SMBCCTX *context,
                                return -1;
                        }
 
-                       if (cli_list(targetcli, lpath,
-                                     aDIR | aSYSTEM | aHIDDEN,
-                                     rmdir_list_fn, NULL) < 0) {
+                       status = cli_list(targetcli, lpath,
+                                         FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
+                                         rmdir_list_fn,
+                                         &smbc_rmdir_dirempty);
 
+                       if (!NT_STATUS_IS_OK(status)) {
                                /* Fix errno to ignore latest error ... */
                                DEBUG(5, ("smbc_rmdir: "
                                           "cli_list returned an error: %d\n",
@@ -1308,7 +1372,7 @@ SMBC_rmdir_ctx(SMBCCTX *context,
                TALLOC_FREE(frame);
                return -1;
 
-       } 
+       }
 
        TALLOC_FREE(frame);
        return 0;
@@ -1325,7 +1389,7 @@ SMBC_telldir_ctx(SMBCCTX *context,
 {
        TALLOC_CTX *frame = talloc_stackframe();
 
-       if (!context || !context->initialized) {
+       if (!context || !context->internal->initialized) {
 
                errno = EINVAL;
                TALLOC_FREE(frame);
@@ -1333,7 +1397,7 @@ SMBC_telldir_ctx(SMBCCTX *context,
 
        }
 
-       if (!dir || !SMBC_dlist_contains(context->files, dir)) {
+       if (!dir || !SMBC_dlist_contains(context->internal->files, dir)) {
 
                errno = EBADF;
                TALLOC_FREE(frame);
@@ -1368,8 +1432,8 @@ SMBC_telldir_ctx(SMBCCTX *context,
  */
 
 static struct smbc_dir_list *
-check_dir_ent(struct smbc_dir_list *list, 
-                   struct smbc_dirent *dirent)
+check_dir_ent(struct smbc_dir_list *list,
+              struct smbc_dirent *dirent)
 {
 
        /* Run down the list looking for what we want */
@@ -1408,7 +1472,7 @@ SMBC_lseekdir_ctx(SMBCCTX *context,
        struct smbc_dir_list *list_ent = (struct smbc_dir_list *)NULL;
        TALLOC_CTX *frame = talloc_stackframe();
 
-       if (!context || !context->initialized) {
+       if (!context || !context->internal->initialized) {
 
                errno = EINVAL;
                TALLOC_FREE(frame);
@@ -1465,7 +1529,7 @@ SMBC_fstatdir_ctx(SMBCCTX *context,
                   struct stat *st)
 {
 
-       if (!context || !context->initialized) {
+       if (!context || !context->internal->initialized) {
 
                errno = EINVAL;
                return -1;
@@ -1486,11 +1550,13 @@ SMBC_chmod_ctx(SMBCCTX *context,
         char *user = NULL;
         char *password = NULL;
         char *workgroup = NULL;
+       char *targetpath = NULL;
+       struct cli_state *targetcli = NULL;
        char *path = NULL;
        uint16 mode;
        TALLOC_CTX *frame = talloc_stackframe();
 
-       if (!context || !context->initialized) {
+       if (!context || !context->internal->initialized) {
 
                errno = EINVAL;  /* Best I can think of ... */
                TALLOC_FREE(frame);
@@ -1503,25 +1569,25 @@ SMBC_chmod_ctx(SMBCCTX *context,
                return -1;
        }
 
-       DEBUG(4, ("smbc_chmod(%s, 0%3o)\n", fname, newmode));
+       DEBUG(4, ("smbc_chmod(%s, 0%3o)\n", fname, (unsigned int)newmode));
 
        if (SMBC_parse_path(frame,
-                               context,
-                               fname,
-                               &workgroup,
-                               &server,
-                               &share,
-                               &path,
-                               &user,
-                               &password,
-                               NULL)) {
+                            context,
+                            fname,
+                            &workgroup,
+                            &server,
+                            &share,
+                            &path,
+                            &user,
+                            &password,
+                            NULL)) {
                 errno = EINVAL;
                TALLOC_FREE(frame);
                return -1;
         }
 
        if (!user || user[0] == (char)0) {
-               user = talloc_strdup(frame, context->user);
+               user = talloc_strdup(frame, smbc_getUser(context));
                if (!user) {
                        errno = ENOMEM;
                        TALLOC_FREE(frame);
@@ -1536,16 +1602,26 @@ SMBC_chmod_ctx(SMBCCTX *context,
                TALLOC_FREE(frame);
                return -1;  /* errno set by SMBC_server */
        }
+       
+       /*d_printf(">>>unlink: resolving %s\n", path);*/
+       if (!cli_resolve_path(frame, "", context->internal->auth_info,
+                               srv->cli, path,
+                               &targetcli, &targetpath)) {
+               d_printf("Could not resolve %s\n", path);
+                errno = ENOENT;
+               TALLOC_FREE(frame);
+               return -1;
+       }
 
        mode = 0;
 
-       if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= aRONLY;
-       if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= aARCH;
-       if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM;
-       if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN;
+       if (!(newmode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode |= FILE_ATTRIBUTE_READONLY;
+       if ((newmode & S_IXUSR) && lp_map_archive(-1)) mode |= FILE_ATTRIBUTE_ARCHIVE;
+       if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= FILE_ATTRIBUTE_SYSTEM;
+       if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= FILE_ATTRIBUTE_HIDDEN;
 
-       if (!cli_setatr(srv->cli, path, mode, 0)) {
-               errno = SMBC_errno(context, srv->cli);
+       if (!NT_STATUS_IS_OK(cli_setatr(targetcli, targetpath, mode, 0))) {
+               errno = SMBC_errno(context, targetcli);
                TALLOC_FREE(frame);
                return -1;
        }
@@ -1570,7 +1646,7 @@ SMBC_utimes_ctx(SMBCCTX *context,
         time_t write_time;
        TALLOC_CTX *frame = talloc_stackframe();
 
-       if (!context || !context->initialized) {
+       if (!context || !context->internal->initialized) {
 
                errno = EINVAL;  /* Best I can think of ... */
                TALLOC_FREE(frame);
@@ -1612,22 +1688,22 @@ SMBC_utimes_ctx(SMBCCTX *context,
         }
 
        if (SMBC_parse_path(frame,
-                               context,
-                               fname,
-                               &workgroup,
-                               &server,
-                               &share,
-                               &path,
-                               &user,
-                               &password,
-                               NULL)) {
+                            context,
+                            fname,
+                            &workgroup,
+                            &server,
+                            &share,
+                            &path,
+                            &user,
+                            &password,
+                            NULL)) {
                errno = EINVAL;
                TALLOC_FREE(frame);
                return -1;
         }
 
        if (!user || user[0] == (char)0) {
-               user = talloc_strdup(frame, context->user);
+               user = talloc_strdup(frame, smbc_getUser(context));
                if (!user) {
                        errno = ENOMEM;
                        TALLOC_FREE(frame);
@@ -1661,14 +1737,18 @@ int
 SMBC_unlink_ctx(SMBCCTX *context,
                 const char *fname)
 {
-       char *server = NULL, *share = NULL, *user = NULL, *password = NULL, *workgroup = NULL;
+       char *server = NULL;
+        char *share = NULL;
+        char *user = NULL;
+        char *password = NULL;
+        char *workgroup = NULL;
        char *path = NULL;
        char *targetpath = NULL;
        struct cli_state *targetcli = NULL;
        SMBCSRV *srv = NULL;
        TALLOC_CTX *frame = talloc_stackframe();
 
-       if (!context || !context->initialized) {
+       if (!context || !context->internal->initialized) {
 
                errno = EINVAL;  /* Best I can think of ... */
                TALLOC_FREE(frame);
@@ -1684,22 +1764,22 @@ SMBC_unlink_ctx(SMBCCTX *context,
        }
 
        if (SMBC_parse_path(frame,
-                               context,
-                               fname,
-                               &workgroup,
-                               &server,
-                               &share,
-                               &path,
-                               &user,
-                               &password,
-                               NULL)) {
+                            context,
+                            fname,
+                            &workgroup,
+                            &server,
+                            &share,
+                            &path,
+                            &user,
+                            &password,
+                            NULL)) {
                 errno = EINVAL;
                TALLOC_FREE(frame);
                 return -1;
         }
 
        if (!user || user[0] == (char)0) {
-               user = talloc_strdup(frame, context->user);
+               user = talloc_strdup(frame, smbc_getUser(context));
                if (!user) {
                        errno = ENOMEM;
                        TALLOC_FREE(frame);
@@ -1717,15 +1797,17 @@ SMBC_unlink_ctx(SMBCCTX *context,
        }
 
        /*d_printf(">>>unlink: resolving %s\n", path);*/
-       if (!cli_resolve_path(frame, "", srv->cli, path,
+       if (!cli_resolve_path(frame, "", context->internal->auth_info,
+                               srv->cli, path,
                                &targetcli, &targetpath)) {
                d_printf("Could not resolve %s\n", path);
+                errno = ENOENT;
                TALLOC_FREE(frame);
                return -1;
        }
        /*d_printf(">>>unlink: resolved path as %s\n", targetpath);*/
 
-       if (!cli_unlink(targetcli, targetpath)) {
+       if (!NT_STATUS_IS_OK(cli_unlink(targetcli, targetpath, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN))) {
 
                errno = SMBC_errno(context, targetcli);
 
@@ -1779,7 +1861,7 @@ SMBC_unlink_ctx(SMBCCTX *context,
 
 int
 SMBC_rename_ctx(SMBCCTX *ocontext,
-                const char *oname, 
+                const char *oname,
                 SMBCCTX *ncontext,
                 const char *nname)
 {
@@ -1802,9 +1884,9 @@ SMBC_rename_ctx(SMBCCTX *ocontext,
        TALLOC_CTX *frame = talloc_stackframe();
 
        if (!ocontext || !ncontext ||
-           !ocontext->initialized ||
-           !ncontext->initialized) {
-            
+           !ocontext->internal->initialized ||
+           !ncontext->internal->initialized) {
+
                errno = EINVAL;  /* Best I can think of ... */
                TALLOC_FREE(frame);
                return -1;
@@ -1819,22 +1901,22 @@ SMBC_rename_ctx(SMBCCTX *ocontext,
        DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname));
 
        if (SMBC_parse_path(frame,
-                       ocontext,
-                       oname,
-                       &workgroup,
-                       &server1,
-                       &share1,
-                       &path1,
-                       &user1,
-                       &password1,
-                        NULL)) {
+                            ocontext,
+                            oname,
+                            &workgroup,
+                            &server1,
+                            &share1,
+                            &path1,
+                            &user1,
+                            &password1,
+                            NULL)) {
                 errno = EINVAL;
                TALLOC_FREE(frame);
                return -1;
        }
 
        if (!user1 || user1[0] == (char)0) {
-               user1 = talloc_strdup(frame, ocontext->user);
+               user1 = talloc_strdup(frame, smbc_getUser(ocontext));
                if (!user1) {
                        errno = ENOMEM;
                        TALLOC_FREE(frame);
@@ -1843,22 +1925,22 @@ SMBC_rename_ctx(SMBCCTX *ocontext,
        }
 
        if (SMBC_parse_path(frame,
-                               ncontext,
-                               nname,
-                               NULL,
-                               &server2,
-                               &share2,
-                               &path2,
-                               &user2,
-                               &password2,
-                               NULL)) {
+                            ncontext,
+                            nname,
+                            NULL,
+                            &server2,
+                            &share2,
+                            &path2,
+                            &user2,
+                            &password2,
+                            NULL)) {
                 errno = EINVAL;
                TALLOC_FREE(frame);
                 return -1;
        }
 
        if (!user2 || user2[0] == (char)0) {
-               user2 = talloc_strdup(frame, ncontext->user);
+               user2 = talloc_strdup(frame, smbc_getUser(ncontext));
                if (!user2) {
                        errno = ENOMEM;
                        TALLOC_FREE(frame);
@@ -1882,18 +1964,37 @@ SMBC_rename_ctx(SMBCCTX *ocontext,
 
        }
 
+       /* set the credentials to make DFS work */
+       smbc_set_credentials_with_fallback(ocontext,
+                                          workgroup,
+                                          user1,
+                                          password1);
+
        /*d_printf(">>>rename: resolving %s\n", path1);*/
-       if (!cli_resolve_path(frame, "", srv->cli, path1,
+       if (!cli_resolve_path(frame, "", ocontext->internal->auth_info,
+                               srv->cli,
+                               path1,
                                &targetcli1, &targetpath1)) {
                d_printf("Could not resolve %s\n", path1);
+                errno = ENOENT;
                TALLOC_FREE(frame);
                return -1;
        }
+       
+       /* set the credentials to make DFS work */
+       smbc_set_credentials_with_fallback(ncontext,
+                                          workgroup,
+                                          user2,
+                                          password2);
+       
        /*d_printf(">>>rename: resolved path as %s\n", targetpath1);*/
        /*d_printf(">>>rename: resolving %s\n", path2);*/
-       if (!cli_resolve_path(frame, "", srv->cli, path2,
+       if (!cli_resolve_path(frame, "", ncontext->internal->auth_info,
+                               srv->cli, 
+                               path2,
                                &targetcli2, &targetpath2)) {
                d_printf("Could not resolve %s\n", path2);
+                errno = ENOENT;
                TALLOC_FREE(frame);
                return -1;
        }
@@ -1908,12 +2009,12 @@ SMBC_rename_ctx(SMBCCTX *ocontext,
                return -1;
        }
 
-       if (!cli_rename(targetcli1, targetpath1, targetpath2)) {
+       if (!NT_STATUS_IS_OK(cli_rename(targetcli1, targetpath1, targetpath2))) {
                int eno = SMBC_errno(ocontext, targetcli1);
 
                if (eno != EEXIST ||
-                   !cli_unlink(targetcli1, targetpath2) ||
-                   !cli_rename(targetcli1, targetpath1, targetpath2)) {
+                   !NT_STATUS_IS_OK(cli_unlink(targetcli1, targetpath2, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN)) ||
+                   !NT_STATUS_IS_OK(cli_rename(targetcli1, targetpath1, targetpath2))) {
 
                        errno = eno;
                        TALLOC_FREE(frame);