dsdb-acl: introduce a 'msg' helper variable to acl_modify()
[Samba.git] / source4 / ntvfs / posix / pvfs_unlink.c
bloba4b51d1d7d3e446ce593e0cb4d249fa1f5a14507
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 = talloc_get_type(ntvfs->private_data,
88 struct pvfs_state);
89 struct timeval end_time;
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;
101 return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io, NULL,
102 pvfs_retry_unlink);
107 unlink a file
109 static NTSTATUS pvfs_unlink_file(struct pvfs_state *pvfs,
110 struct pvfs_filename *name)
112 NTSTATUS status = NT_STATUS_OK;
114 if (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) {
115 return NT_STATUS_FILE_IS_A_DIRECTORY;
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;
125 /* finally try the actual unlink */
126 if (pvfs_sys_unlink(pvfs, name->full_name, name->allow_override) == -1) {
127 status = pvfs_map_errno(pvfs, errno);
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);
137 return status;
141 unlink one file
143 static NTSTATUS pvfs_unlink_one(struct pvfs_state *pvfs,
144 struct ntvfs_request *req,
145 union smb_unlink *unl,
146 struct pvfs_filename *name)
148 NTSTATUS status;
149 struct odb_lock *lck = NULL;
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;
158 status = pvfs_can_delete(pvfs, req, name, &lck);
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
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);
172 if (!NT_STATUS_IS_OK(status)) {
173 return status;
176 if (name->stream_name) {
177 if (!name->stream_exists) {
178 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
181 return pvfs_stream_delete(pvfs, name, -1);
184 return pvfs_unlink_file(pvfs, name);
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)
191 NTSTATUS pvfs_unlink(struct ntvfs_module_context *ntvfs,
192 struct ntvfs_request *req,
193 union smb_unlink *unl)
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;
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;
214 if (!name->exists && !name->has_wildcard) {
215 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
218 if (name->exists &&
219 (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
220 return NT_STATUS_FILE_IS_A_DIRECTORY;
223 if (!name->has_wildcard) {
224 return pvfs_unlink_one(pvfs, req, unl, name);
228 * disable async requests in the wildcard case
229 * untill we have proper tests for this
231 req->async_states->state &= ~NTVFS_ASYNC_STATE_MAY_ASYNC;
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;
239 status = NT_STATUS_NO_SUCH_FILE;
240 talloc_free(name);
242 ofs = 0;
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;
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;
261 status = pvfs_unlink_one(pvfs, req, unl, name);
262 if (NT_STATUS_IS_OK(status)) {
263 total_deleted++;
266 talloc_free(name);
269 if (total_deleted > 0) {
270 status = NT_STATUS_OK;
273 return status;