Coverage Report

Created: 2026-06-07 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source4/libcli/clideltree.c
Line
Count
Source
1
/* 
2
   Unix SMB/CIFS implementation.
3
   useful function for deleting a whole directory tree
4
   Copyright (C) Andrew Tridgell 2003
5
   
6
   This program is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 3 of the License, or
9
   (at your option) any later version.
10
   
11
   This program is distributed in the hope that it will be useful,
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
   GNU General Public License for more details.
15
   
16
   You should have received a copy of the GNU General Public License
17
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
*/
19
20
#include "includes.h"
21
#include "libcli/raw/libcliraw.h"
22
#include "libcli/libcli.h"
23
#include "system/dir.h"
24
25
struct delete_state {
26
  struct smbcli_tree *tree;
27
  int total_deleted;
28
  bool failed;
29
};
30
31
/* 
32
   callback function for torture_deltree() 
33
*/
34
static void delete_fn(struct clilist_file_info *finfo, const char *name, void *state)
35
0
{
36
0
  struct delete_state *dstate = (struct delete_state *)state;
37
0
  char *s, *n;
38
0
  if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
39
0
    return;
40
0
  }
41
42
0
  n = strdup(name);
43
0
  n[strlen(n)-1] = 0;
44
0
  if (asprintf(&s, "%s%s", n, finfo->name) < 0) {
45
0
    free(n);
46
0
    return;
47
0
  }
48
49
0
  if (finfo->attrib & FILE_ATTRIBUTE_READONLY) {
50
0
    if (NT_STATUS_IS_ERR(smbcli_setatr(dstate->tree, s, 0, 0))) {
51
0
      DEBUG(2,("Failed to remove READONLY on %s - %s\n",
52
0
         s, smbcli_errstr(dstate->tree)));      
53
0
    }
54
0
  }
55
56
0
  if (finfo->attrib & FILE_ATTRIBUTE_DIRECTORY) {
57
0
    char *s2;
58
0
    if (asprintf(&s2, "%s\\*", s) < 0) {
59
0
      free(s);
60
0
      free(n);
61
0
      return;
62
0
    }
63
0
    smbcli_unlink(dstate->tree, s2);
64
0
    smbcli_list(dstate->tree, s2, 
65
0
       FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM, 
66
0
       delete_fn, state);
67
0
    free(s2);
68
0
    if (NT_STATUS_IS_ERR(smbcli_rmdir(dstate->tree, s))) {
69
0
      DEBUG(2,("Failed to delete %s - %s\n", 
70
0
         s, smbcli_errstr(dstate->tree)));
71
0
      dstate->failed = true;
72
0
    }
73
0
    dstate->total_deleted++;
74
0
  } else {
75
0
    if (NT_STATUS_IS_ERR(smbcli_unlink(dstate->tree, s))) {
76
0
      DEBUG(2,("Failed to delete %s - %s\n", 
77
0
         s, smbcli_errstr(dstate->tree)));
78
0
      dstate->failed = true;
79
0
    }
80
0
    dstate->total_deleted++;
81
0
  }
82
0
  free(s);
83
0
  free(n);
84
0
}
85
86
/* 
87
   recursively descend a tree deleting all files
88
   returns the number of files deleted, or -1 on error
89
*/
90
int smbcli_deltree(struct smbcli_tree *tree, const char *dname)
91
0
{
92
0
  char *mask;
93
0
  struct delete_state dstate;
94
0
  NTSTATUS status;
95
96
0
  dstate.tree = tree;
97
0
  dstate.total_deleted = 0;
98
0
  dstate.failed = false;
99
100
  /* it might be a file */
101
0
  status = smbcli_unlink(tree, dname);
102
0
  if (NT_STATUS_IS_OK(status)) {
103
0
    return 1;
104
0
  }
105
0
  if (NT_STATUS_EQUAL(smbcli_nt_error(tree), NT_STATUS_OBJECT_NAME_NOT_FOUND) ||
106
0
      NT_STATUS_EQUAL(smbcli_nt_error(tree), NT_STATUS_OBJECT_PATH_NOT_FOUND) ||
107
0
      NT_STATUS_EQUAL(smbcli_nt_error(tree), NT_STATUS_NO_SUCH_FILE) ||
108
0
      NT_STATUS_EQUAL(smbcli_nt_error(tree), NT_STATUS_DOS(ERRDOS, ERRbadfile))) {
109
0
    return 0;
110
0
  }
111
0
  if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) {
112
    /* it could be read-only */
113
0
    smbcli_setatr(tree, dname, FILE_ATTRIBUTE_NORMAL, 0);
114
0
    if (NT_STATUS_IS_OK(smbcli_unlink(tree, dname))) {
115
0
      return 1;
116
0
    }
117
0
  }
118
119
0
  if (asprintf(&mask, "%s\\*", dname) < 0) {
120
0
    return -1;
121
0
  }
122
0
  smbcli_unlink_wcard(dstate.tree, mask);
123
0
  smbcli_list(dstate.tree, mask, 
124
0
     FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM, 
125
0
     delete_fn, &dstate);
126
0
  free(mask);
127
128
0
  status = smbcli_rmdir(dstate.tree, dname);
129
0
  if (NT_STATUS_EQUAL(status, NT_STATUS_CANNOT_DELETE)) {
130
    /* it could be read-only */
131
0
    smbcli_setatr(dstate.tree, dname, FILE_ATTRIBUTE_NORMAL, 0);
132
0
    status = smbcli_rmdir(dstate.tree, dname);
133
0
  }
134
0
  if (NT_STATUS_IS_ERR(status)) {
135
0
    DEBUG(2,("Failed to delete %s - %s\n", 
136
0
       dname, smbcli_errstr(dstate.tree)));
137
0
    return -1;
138
0
  }
139
0
  dstate.total_deleted++;
140
141
0
  if (dstate.failed) {
142
0
    return -1;
143
0
  }
144
145
0
  return dstate.total_deleted;
146
0
}