source: trunk/server/source4/ntvfs/posix/pvfs_unlink.c

Last change on this file was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 7.2 KB
Line 
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*/
29static 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 union smb_unlink *io = talloc_get_type(_io, union smb_unlink);
37 NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
38
39 talloc_free(r);
40
41 switch (reason) {
42 case PVFS_WAIT_CANCEL:
43/*TODO*/
44 status = NT_STATUS_CANCELLED;
45 break;
46 case PVFS_WAIT_TIMEOUT:
47 /* if it timed out, then give the failure
48 immediately */
49/*TODO*/
50 status = NT_STATUS_SHARING_VIOLATION;
51 break;
52 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 req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
58
59 status = pvfs_unlink(ntvfs, req, io);
60 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 return;
64 }
65
66 /* re-mark it async, just in case someone up the chain does
67 paranoid checking */
68 req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
69 break;
70 }
71
72 /* send the reply up the chain */
73 req->async_states->status = status;
74 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*/
81static 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 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
88 struct pvfs_state);
89 struct timeval end_time;
90
91 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
92 end_time = timeval_add(&req->statistics.request_time,
93 0, pvfs->sharing_violation_delay);
94 } else if (NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
95 end_time = timeval_add(&req->statistics.request_time,
96 pvfs->oplock_break_timeout, 0);
97 } else {
98 return NT_STATUS_INTERNAL_ERROR;
99 }
100
101 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*/
109static NTSTATUS pvfs_unlink_file(struct pvfs_state *pvfs,
110 struct pvfs_filename *name)
111{
112 NTSTATUS status = NT_STATUS_OK;
113
114 if (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) {
115 return NT_STATUS_FILE_IS_A_DIRECTORY;
116 }
117
118 if (name->st.st_nlink == 1) {
119 status = pvfs_xattr_unlink_hook(pvfs, name->full_name);
120 if (!NT_STATUS_IS_OK(status)) {
121 return status;
122 }
123 }
124
125 /* finally try the actual unlink */
126 if (pvfs_sys_unlink(pvfs, name->full_name) == -1) {
127 status = pvfs_map_errno(pvfs, errno);
128 }
129
130 if (NT_STATUS_IS_OK(status)) {
131 notify_trigger(pvfs->notify_context,
132 NOTIFY_ACTION_REMOVED,
133 FILE_NOTIFY_CHANGE_FILE_NAME,
134 name->full_name);
135 }
136
137 return status;
138}
139
140/*
141 unlink one file
142*/
143static 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 NTSTATUS status;
149 struct odb_lock *lck = NULL;
150
151 /* make sure its matches the given attributes */
152 status = pvfs_match_attrib(pvfs, name,
153 unl->unlink.in.attrib, 0);
154 if (!NT_STATUS_IS_OK(status)) {
155 return status;
156 }
157
158 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 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
167 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
168 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
169 return pvfs_unlink_setup_retry(pvfs->ntvfs, req, unl, lck, status);
170 }
171
172 if (!NT_STATUS_IS_OK(status)) {
173 return status;
174 }
175
176 if (name->stream_name) {
177 if (!name->stream_exists) {
178 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
179 }
180
181 return pvfs_stream_delete(pvfs, name, -1);
182 }
183
184 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*/
191NTSTATUS pvfs_unlink(struct ntvfs_module_context *ntvfs,
192 struct ntvfs_request *req,
193 union smb_unlink *unl)
194{
195 struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
196 struct pvfs_state);
197 struct pvfs_dir *dir;
198 NTSTATUS status;
199 uint32_t total_deleted=0;
200 struct pvfs_filename *name;
201 const char *fname;
202 off_t ofs;
203
204 /* resolve the cifs name to a posix name */
205 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 if (!NT_STATUS_IS_OK(status)) {
211 return status;
212 }
213
214 if (!name->exists && !name->has_wildcard) {
215 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
216 }
217
218 if (name->exists &&
219 (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
220 return NT_STATUS_FILE_IS_A_DIRECTORY;
221 }
222
223 if (!name->has_wildcard) {
224 return pvfs_unlink_one(pvfs, req, unl, name);
225 }
226
227 /*
228 * disable async requests in the wildcard case
229 * untill we have proper tests for this
230 */
231 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
232
233 /* get list of matching files */
234 status = pvfs_list_start(pvfs, name, req, &dir);
235 if (!NT_STATUS_IS_OK(status)) {
236 return status;
237 }
238
239 status = NT_STATUS_NO_SUCH_FILE;
240 talloc_free(name);
241
242 ofs = 0;
243
244 while ((fname = pvfs_list_next(dir, &ofs))) {
245 /* this seems to be a special case */
246 if ((unl->unlink.in.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
247 (ISDOT(fname) || ISDOTDOT(fname))) {
248 return NT_STATUS_OBJECT_NAME_INVALID;
249 }
250
251 /* get a pvfs_filename object */
252 status = pvfs_resolve_partial(pvfs, req,
253 pvfs_list_unix_path(dir),
254 fname,
255 PVFS_RESOLVE_NO_OPENDB,
256 &name);
257 if (!NT_STATUS_IS_OK(status)) {
258 return status;
259 }
260
261 status = pvfs_unlink_one(pvfs, req, unl, name);
262 if (NT_STATUS_IS_OK(status)) {
263 total_deleted++;
264 }
265
266 talloc_free(name);
267 }
268
269 if (total_deleted > 0) {
270 status = NT_STATUS_OK;
271 }
272
273 return status;
274}
275
276
Note: See TracBrowser for help on using the repository browser.