Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : POSIX NTVFS backend - unlink
5 :
6 : Copyright (C) Andrew Tridgell 2004
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "includes.h"
23 : #include "vfs_posix.h"
24 : #include "system/dir.h"
25 :
26 : /*
27 : retry an open after a sharing violation
28 : */
29 37 : static void pvfs_retry_unlink(struct pvfs_odb_retry *r,
30 : struct ntvfs_module_context *ntvfs,
31 : struct ntvfs_request *req,
32 : void *_io,
33 : void *private_data,
34 : enum pvfs_wait_notice reason)
35 : {
36 37 : union smb_unlink *io = talloc_get_type(_io, union smb_unlink);
37 37 : NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
38 :
39 37 : talloc_free(r);
40 :
41 37 : switch (reason) {
42 0 : case PVFS_WAIT_CANCEL:
43 : /*TODO*/
44 0 : status = NT_STATUS_CANCELLED;
45 33 : break;
46 31 : case PVFS_WAIT_TIMEOUT:
47 : /* if it timed out, then give the failure
48 : immediately */
49 : /*TODO*/
50 31 : status = NT_STATUS_SHARING_VIOLATION;
51 31 : break;
52 6 : case PVFS_WAIT_EVENT:
53 :
54 : /* try the open again, which could trigger another retry setup
55 : if it wants to, so we have to unmark the async flag so we
56 : will know if it does a second async reply */
57 6 : req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
58 :
59 6 : status = pvfs_unlink(ntvfs, req, io);
60 6 : if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
61 : /* the 2nd try also replied async, so we don't send
62 : the reply yet */
63 4 : return;
64 : }
65 :
66 : /* re-mark it async, just in case someone up the chain does
67 : paranoid checking */
68 2 : req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
69 2 : break;
70 : }
71 :
72 : /* send the reply up the chain */
73 33 : req->async_states->status = status;
74 33 : req->async_states->send_fn(req);
75 : }
76 :
77 : /*
78 : setup for a unlink retry after a sharing violation
79 : or a non granted oplock
80 : */
81 37 : static NTSTATUS pvfs_unlink_setup_retry(struct ntvfs_module_context *ntvfs,
82 : struct ntvfs_request *req,
83 : union smb_unlink *io,
84 : struct odb_lock *lck,
85 : NTSTATUS status)
86 : {
87 37 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
88 : struct pvfs_state);
89 0 : struct timeval end_time;
90 :
91 37 : if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
92 31 : end_time = timeval_add(&req->statistics.request_time,
93 : 0, pvfs->sharing_violation_delay);
94 6 : } else if (NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
95 6 : end_time = timeval_add(&req->statistics.request_time,
96 : pvfs->oplock_break_timeout, 0);
97 : } else {
98 0 : return NT_STATUS_INTERNAL_ERROR;
99 : }
100 :
101 37 : return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io, NULL,
102 : pvfs_retry_unlink);
103 : }
104 :
105 :
106 : /*
107 : unlink a file
108 : */
109 31016 : static NTSTATUS pvfs_unlink_file(struct pvfs_state *pvfs,
110 : struct pvfs_filename *name)
111 : {
112 31016 : NTSTATUS status = NT_STATUS_OK;
113 :
114 31016 : if (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) {
115 0 : return NT_STATUS_FILE_IS_A_DIRECTORY;
116 : }
117 :
118 31016 : if (name->st.st_nlink == 1) {
119 31014 : status = pvfs_xattr_unlink_hook(pvfs, name->full_name);
120 31014 : if (!NT_STATUS_IS_OK(status)) {
121 0 : return status;
122 : }
123 : }
124 :
125 : /* finally try the actual unlink */
126 31016 : if (pvfs_sys_unlink(pvfs, name->full_name, name->allow_override) == -1) {
127 0 : status = pvfs_map_errno(pvfs, errno);
128 : }
129 :
130 31016 : if (NT_STATUS_IS_OK(status)) {
131 31016 : notify_trigger(pvfs->notify_context,
132 : NOTIFY_ACTION_REMOVED,
133 : FILE_NOTIFY_CHANGE_FILE_NAME,
134 31016 : name->full_name);
135 : }
136 :
137 31016 : return status;
138 : }
139 :
140 : /*
141 : unlink one file
142 : */
143 31057 : static NTSTATUS pvfs_unlink_one(struct pvfs_state *pvfs,
144 : struct ntvfs_request *req,
145 : union smb_unlink *unl,
146 : struct pvfs_filename *name)
147 : {
148 0 : NTSTATUS status;
149 31057 : struct odb_lock *lck = NULL;
150 :
151 : /* make sure its matches the given attributes */
152 31057 : status = pvfs_match_attrib(pvfs, name,
153 31057 : unl->unlink.in.attrib, 0);
154 31057 : if (!NT_STATUS_IS_OK(status)) {
155 1 : return status;
156 : }
157 :
158 31056 : status = pvfs_can_delete(pvfs, req, name, &lck);
159 :
160 : /*
161 : * on a sharing violation we need to retry when the file is closed by
162 : * the other user, or after 1 second
163 : * on a non granted oplock we need to retry when the file is closed by
164 : * the other user, or after 30 seconds
165 : */
166 31056 : if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
167 31025 : NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
168 37 : (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
169 37 : return pvfs_unlink_setup_retry(pvfs->ntvfs, req, unl, lck, status);
170 : }
171 :
172 31019 : if (!NT_STATUS_IS_OK(status)) {
173 0 : return status;
174 : }
175 :
176 31019 : if (name->stream_name) {
177 3 : if (!name->stream_exists) {
178 1 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
179 : }
180 :
181 2 : return pvfs_stream_delete(pvfs, name, -1);
182 : }
183 :
184 31016 : return pvfs_unlink_file(pvfs, name);
185 : }
186 :
187 : /*
188 : delete a file - the dirtype specifies the file types to include in the search.
189 : The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
190 : */
191 34441 : NTSTATUS pvfs_unlink(struct ntvfs_module_context *ntvfs,
192 : struct ntvfs_request *req,
193 : union smb_unlink *unl)
194 : {
195 34441 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
196 : struct pvfs_state);
197 0 : struct pvfs_dir *dir;
198 0 : NTSTATUS status;
199 34441 : uint32_t total_deleted=0;
200 0 : struct pvfs_filename *name;
201 0 : const char *fname;
202 0 : off_t ofs;
203 :
204 : /* resolve the cifs name to a posix name */
205 34441 : status = pvfs_resolve_name(pvfs, req, unl->unlink.in.pattern,
206 : PVFS_RESOLVE_WILDCARD |
207 : PVFS_RESOLVE_STREAMS |
208 : PVFS_RESOLVE_NO_OPENDB,
209 : &name);
210 34441 : if (!NT_STATUS_IS_OK(status)) {
211 65 : return status;
212 : }
213 :
214 34376 : if (!name->exists && !name->has_wildcard) {
215 1074 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
216 : }
217 :
218 33302 : if (name->exists &&
219 31262 : (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
220 205 : return NT_STATUS_FILE_IS_A_DIRECTORY;
221 : }
222 :
223 33097 : if (!name->has_wildcard) {
224 31057 : return pvfs_unlink_one(pvfs, req, unl, name);
225 : }
226 :
227 : /*
228 : * disable async requests in the wildcard case
229 : * until we have proper tests for this
230 : */
231 2040 : req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
232 :
233 : /* get list of matching files */
234 2040 : status = pvfs_list_start(pvfs, name, req, &dir);
235 2040 : if (!NT_STATUS_IS_OK(status)) {
236 2 : return status;
237 : }
238 :
239 2038 : status = NT_STATUS_NO_SUCH_FILE;
240 2038 : talloc_free(name);
241 :
242 2038 : ofs = 0;
243 :
244 2038 : while ((fname = pvfs_list_next(dir, &ofs))) {
245 : /* this seems to be a special case */
246 2038 : if ((unl->unlink.in.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
247 2038 : (ISDOT(fname) || ISDOTDOT(fname))) {
248 2038 : return NT_STATUS_OBJECT_NAME_INVALID;
249 : }
250 :
251 : /* get a pvfs_filename object */
252 0 : status = pvfs_resolve_partial(pvfs, req,
253 : pvfs_list_unix_path(dir),
254 : fname,
255 : PVFS_RESOLVE_NO_OPENDB,
256 : &name);
257 0 : if (!NT_STATUS_IS_OK(status)) {
258 0 : return status;
259 : }
260 :
261 0 : status = pvfs_unlink_one(pvfs, req, unl, name);
262 0 : if (NT_STATUS_IS_OK(status)) {
263 0 : total_deleted++;
264 : }
265 :
266 0 : talloc_free(name);
267 : }
268 :
269 0 : if (total_deleted > 0) {
270 0 : status = NT_STATUS_OK;
271 : }
272 :
273 0 : return status;
274 : }
275 :
276 :
|