Fix the mess with ldb includes.
[Samba/ekacnet.git] / source4 / ntvfs / posix / pvfs_unlink.c
blob6a5704177041ea9b1b808fa7bda36d9f3bd29ef6
1 /*
2 Unix SMB/CIFS implementation.
4 POSIX NTVFS backend - unlink
6 Copyright (C) Andrew Tridgell 2004
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.
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.
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/>.
22 #include "includes.h"
23 #include "vfs_posix.h"
24 #include "system/dir.h"
27 retry an open after a sharing violation
29 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)
36 union smb_unlink *io = talloc_get_type(_io, union smb_unlink);
37 NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
39 talloc_free(r);
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:
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;
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;
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;
72 /* send the reply up the chain */
73 req->async_states->status = status;
74 req->async_states->send_fn(req);
78 setup for a unlink retry after a sharing violation
79 or a non granted oplock
81 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)
87 struct pvfs_state *pvfs = ntvfs->private_data;
88 struct timeval end_time;
90 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
91 end_time = timeval_add(&req->statistics.request_time,
92 0, pvfs->sharing_violation_delay);
93 } else if (NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
94 end_time = timeval_add(&req->statistics.request_time,
95 pvfs->oplock_break_timeout, 0);
96 } else {
97 return NT_STATUS_INTERNAL_ERROR;
100 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io, NULL,
101 pvfs_retry_unlink);
106 unlink a file
108 static NTSTATUS pvfs_unlink_file(struct pvfs_state *pvfs,
109 struct pvfs_filename *name)
111 NTSTATUS status;
113 if (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) {
114 return NT_STATUS_FILE_IS_A_DIRECTORY;
117 if (name->st.st_nlink == 1) {
118 status = pvfs_xattr_unlink_hook(pvfs, name->full_name);
119 if (!NT_STATUS_IS_OK(status)) {
120 return status;
124 /* finally try the actual unlink */
125 if (unlink(name->full_name) == -1) {
126 status = pvfs_map_errno(pvfs, errno);
129 if (NT_STATUS_IS_OK(status)) {
130 notify_trigger(pvfs->notify_context,
131 NOTIFY_ACTION_REMOVED,
132 FILE_NOTIFY_CHANGE_FILE_NAME,
133 name->full_name);
136 return status;
140 unlink one file
142 static NTSTATUS pvfs_unlink_one(struct pvfs_state *pvfs,
143 struct ntvfs_request *req,
144 union smb_unlink *unl,
145 struct pvfs_filename *name)
147 NTSTATUS status;
148 struct odb_lock *lck = NULL;
150 /* make sure its matches the given attributes */
151 status = pvfs_match_attrib(pvfs, name,
152 unl->unlink.in.attrib, 0);
153 if (!NT_STATUS_IS_OK(status)) {
154 return status;
157 status = pvfs_can_delete(pvfs, req, name, &lck);
160 * on a sharing violation we need to retry when the file is closed by
161 * the other user, or after 1 second
162 * on a non granted oplock we need to retry when the file is closed by
163 * the other user, or after 30 seconds
165 if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
166 NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
167 (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
168 return pvfs_unlink_setup_retry(pvfs->ntvfs, req, unl, lck, status);
171 if (!NT_STATUS_IS_OK(status)) {
172 return status;
175 if (name->stream_name) {
176 if (!name->stream_exists) {
177 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
180 return pvfs_stream_delete(pvfs, name, -1);
183 return pvfs_unlink_file(pvfs, name);
187 delete a file - the dirtype specifies the file types to include in the search.
188 The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
190 NTSTATUS pvfs_unlink(struct ntvfs_module_context *ntvfs,
191 struct ntvfs_request *req,
192 union smb_unlink *unl)
194 struct pvfs_state *pvfs = ntvfs->private_data;
195 struct pvfs_dir *dir;
196 NTSTATUS status;
197 uint32_t total_deleted=0;
198 struct pvfs_filename *name;
199 const char *fname;
200 off_t ofs;
202 /* resolve the cifs name to a posix name */
203 status = pvfs_resolve_name(pvfs, req, unl->unlink.in.pattern,
204 PVFS_RESOLVE_WILDCARD |
205 PVFS_RESOLVE_STREAMS |
206 PVFS_RESOLVE_NO_OPENDB,
207 &name);
208 if (!NT_STATUS_IS_OK(status)) {
209 return status;
212 if (!name->exists && !name->has_wildcard) {
213 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
216 if (name->exists &&
217 (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
218 return NT_STATUS_FILE_IS_A_DIRECTORY;
221 if (!name->has_wildcard) {
222 return pvfs_unlink_one(pvfs, req, unl, name);
226 * disable async requests in the wildcard case
227 * untill we have proper tests for this
229 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
231 /* get list of matching files */
232 status = pvfs_list_start(pvfs, name, req, &dir);
233 if (!NT_STATUS_IS_OK(status)) {
234 return status;
237 status = NT_STATUS_NO_SUCH_FILE;
238 talloc_free(name);
240 ofs = 0;
242 while ((fname = pvfs_list_next(dir, &ofs))) {
243 /* this seems to be a special case */
244 if ((unl->unlink.in.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
245 (ISDOT(fname) || ISDOTDOT(fname))) {
246 return NT_STATUS_OBJECT_NAME_INVALID;
249 /* get a pvfs_filename object */
250 status = pvfs_resolve_partial(pvfs, req,
251 pvfs_list_unix_path(dir),
252 fname,
253 PVFS_RESOLVE_NO_OPENDB,
254 &name);
255 if (!NT_STATUS_IS_OK(status)) {
256 return status;
259 status = pvfs_unlink_one(pvfs, req, unl, name);
260 if (NT_STATUS_IS_OK(status)) {
261 total_deleted++;
264 talloc_free(name);
267 if (total_deleted > 0) {
268 status = NT_STATUS_OK;
271 return status;