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/>.
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
,
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
;
42 case PVFS_WAIT_CANCEL
:
44 status
= NT_STATUS_CANCELLED
;
46 case PVFS_WAIT_TIMEOUT
:
47 /* if it timed out, then give the failure
50 status
= NT_STATUS_SHARING_VIOLATION
;
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
66 /* re-mark it async, just in case someone up the chain does
68 req
->async_states
->state
|= NTVFS_ASYNC_STATE_ASYNC
;
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
,
87 struct pvfs_state
*pvfs
= talloc_get_type(ntvfs
->private_data
,
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);
98 return NT_STATUS_INTERNAL_ERROR
;
101 return pvfs_odb_retry_setup(ntvfs
, req
, lck
, end_time
, io
, NULL
,
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
)) {
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
,
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
)
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
)) {
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
)) {
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
,
197 struct pvfs_dir
*dir
;
199 uint32_t total_deleted
=0;
200 struct pvfs_filename
*name
;
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
,
210 if (!NT_STATUS_IS_OK(status
)) {
214 if (!name
->exists
&& !name
->has_wildcard
) {
215 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
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
)) {
239 status
= NT_STATUS_NO_SUCH_FILE
;
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
),
255 PVFS_RESOLVE_NO_OPENDB
,
257 if (!NT_STATUS_IS_OK(status
)) {
261 status
= pvfs_unlink_one(pvfs
, req
, unl
, name
);
262 if (NT_STATUS_IS_OK(status
)) {
269 if (total_deleted
> 0) {
270 status
= NT_STATUS_OK
;