1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-23 17:34:34 +03:00
samba-mirror/source4/libcli/clideltree.c
Tim Beale 31d4f692ad s4:libcli: Fix error in smbcli_deltree()
Commit 094afe614b fixed an uninitialized variable, which meant we
tried to delete the file twice. The 2nd time fails, so the function
returns an error, instead of success (even though the file is now gone).

Note we want to be using the source3 SMB library code going forward.
However, fixing this bug makes it easier to write tests against the
(currently s4) SMB python bindings.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13676

Signed-off-by: Tim Beale <timbeale@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
2018-12-12 04:38:13 +01:00

147 lines
3.9 KiB
C

/*
Unix SMB/CIFS implementation.
useful function for deleting a whole directory tree
Copyright (C) Andrew Tridgell 2003
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 "libcli/raw/libcliraw.h"
#include "libcli/libcli.h"
#include "system/dir.h"
struct delete_state {
struct smbcli_tree *tree;
int total_deleted;
bool failed;
};
/*
callback function for torture_deltree()
*/
static void delete_fn(struct clilist_file_info *finfo, const char *name, void *state)
{
struct delete_state *dstate = (struct delete_state *)state;
char *s, *n;
if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
return;
}
n = strdup(name);
n[strlen(n)-1] = 0;
if (asprintf(&s, "%s%s", n, finfo->name) < 0) {
free(n);
return;
}
if (finfo->attrib & FILE_ATTRIBUTE_READONLY) {
if (NT_STATUS_IS_ERR(smbcli_setatr(dstate->tree, s, 0, 0))) {
DEBUG(2,("Failed to remove READONLY on %s - %s\n",
s, smbcli_errstr(dstate->tree)));
}
}
if (finfo->attrib & FILE_ATTRIBUTE_DIRECTORY) {
char *s2;
if (asprintf(&s2, "%s\\*", s) < 0) {
free(s);
free(n);
return;
}
smbcli_unlink(dstate->tree, s2);
smbcli_list(dstate->tree, s2,
FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM,
delete_fn, state);
free(s2);
if (NT_STATUS_IS_ERR(smbcli_rmdir(dstate->tree, s))) {
DEBUG(2,("Failed to delete %s - %s\n",
s, smbcli_errstr(dstate->tree)));
dstate->failed = true;
}
dstate->total_deleted++;
} else {
if (NT_STATUS_IS_ERR(smbcli_unlink(dstate->tree, s))) {
DEBUG(2,("Failed to delete %s - %s\n",
s, smbcli_errstr(dstate->tree)));
dstate->failed = true;
}
dstate->total_deleted++;
}
free(s);
free(n);
}
/*
recursively descend a tree deleting all files
returns the number of files deleted, or -1 on error
*/
int smbcli_deltree(struct smbcli_tree *tree, const char *dname)
{
char *mask;
struct delete_state dstate;
NTSTATUS status;
dstate.tree = tree;
dstate.total_deleted = 0;
dstate.failed = false;
/* it might be a file */
status = smbcli_unlink(tree, dname);
if (NT_STATUS_IS_OK(status)) {
return 1;
}
if (NT_STATUS_EQUAL(smbcli_nt_error(tree), NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
NT_STATUS_EQUAL(smbcli_nt_error(tree), NT_STATUS_OBJECT_PATH_NOT_FOUND) ||
NT_STATUS_EQUAL(smbcli_nt_error(tree), NT_STATUS_NO_SUCH_FILE) ||
NT_STATUS_EQUAL(smbcli_nt_error(tree), NT_STATUS_DOS(ERRDOS, ERRbadfile))) {
return 0;
}
if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) {
/* it could be read-only */
status = smbcli_setatr(tree, dname, FILE_ATTRIBUTE_NORMAL, 0);
if (NT_STATUS_IS_OK(smbcli_unlink(tree, dname))) {
return 1;
}
}
if (asprintf(&mask, "%s\\*", dname) < 0) {
return -1;
}
smbcli_unlink(dstate.tree, mask);
smbcli_list(dstate.tree, mask,
FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM,
delete_fn, &dstate);
free(mask);
status = smbcli_rmdir(dstate.tree, dname);
if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) {
/* it could be read-only */
status = smbcli_setatr(dstate.tree, dname, FILE_ATTRIBUTE_NORMAL, 0);
status = smbcli_rmdir(dstate.tree, dname);
}
if (NT_STATUS_IS_ERR(status)) {
DEBUG(2,("Failed to delete %s - %s\n",
dname, smbcli_errstr(dstate.tree)));
return -1;
}
dstate.total_deleted++;
if (dstate.failed) {
return -1;
}
return dstate.total_deleted;
}