s4-pvfs: another uninitialised variable
[ira/wip.git] / source4 / ntvfs / posix / pvfs_unlink.c
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 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         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 */
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)
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 */
109 static 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 (unlink(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 */
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)
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 */
191 NTSTATUS 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