r23792: convert Samba4 to GPLv3
[kai/samba-autobuild/.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 /*
28   unlink a stream
29  */
30 static NTSTATUS pvfs_unlink_stream(struct pvfs_state *pvfs, 
31                                    struct ntvfs_request *req,
32                                    struct pvfs_filename *name, 
33                                    uint16_t attrib)
34 {
35         NTSTATUS status;
36         struct odb_lock *lck;
37
38         if (!name->stream_exists) {
39                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
40         }
41
42         /* make sure its matches the given attributes */
43         status = pvfs_match_attrib(pvfs, name, attrib, 0);
44         if (!NT_STATUS_IS_OK(status)) {
45                 return status;
46         }
47
48         status = pvfs_can_delete(pvfs, req, name, &lck);
49         if (!NT_STATUS_IS_OK(status)) {
50                 return status;
51         }
52
53         return pvfs_stream_delete(pvfs, name, -1);
54 }
55
56
57 /*
58   unlink one file
59 */
60 static NTSTATUS pvfs_unlink_one(struct pvfs_state *pvfs, 
61                                 struct ntvfs_request *req,
62                                 const char *unix_path, 
63                                 const char *fname, uint32_t attrib)
64 {
65         struct pvfs_filename *name;
66         NTSTATUS status;
67         struct odb_lock *lck;
68
69         /* get a pvfs_filename object */
70         status = pvfs_resolve_partial(pvfs, req, 
71                                       unix_path, fname, &name);
72         if (!NT_STATUS_IS_OK(status)) {
73                 return status;
74         }
75
76         /* make sure its matches the given attributes */
77         status = pvfs_match_attrib(pvfs, name, attrib, 0);
78         if (!NT_STATUS_IS_OK(status)) {
79                 talloc_free(name);
80                 return status;
81         }
82
83         status = pvfs_can_delete(pvfs, req, name, &lck);
84         if (!NT_STATUS_IS_OK(status)) {
85                 talloc_free(name);
86                 return status;
87         }
88
89         if (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) {
90                 talloc_free(name);
91                 return NT_STATUS_FILE_IS_A_DIRECTORY;
92         }
93
94         if (name->st.st_nlink == 1) {
95                 status = pvfs_xattr_unlink_hook(pvfs, name->full_name);
96                 if (!NT_STATUS_IS_OK(status)) {
97                         return status;
98                 }
99         }
100
101         /* finally try the actual unlink */
102         if (unlink(name->full_name) == -1) {
103                 status = pvfs_map_errno(pvfs, errno);
104         }
105
106         if (NT_STATUS_IS_OK(status)) {
107                 notify_trigger(pvfs->notify_context, 
108                                NOTIFY_ACTION_REMOVED, 
109                                FILE_NOTIFY_CHANGE_FILE_NAME,
110                                name->full_name);
111         }
112
113         talloc_free(name);
114
115         return status;
116 }
117
118 /*
119   delete a file - the dirtype specifies the file types to include in the search. 
120   The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
121 */
122 NTSTATUS pvfs_unlink(struct ntvfs_module_context *ntvfs,
123                      struct ntvfs_request *req,
124                      union smb_unlink *unl)
125 {
126         struct pvfs_state *pvfs = ntvfs->private_data;
127         struct pvfs_dir *dir;
128         NTSTATUS status;
129         uint32_t total_deleted=0;
130         struct pvfs_filename *name;
131         const char *fname;
132         off_t ofs;
133
134         /* resolve the cifs name to a posix name */
135         status = pvfs_resolve_name(pvfs, req, unl->unlink.in.pattern, 
136                                    PVFS_RESOLVE_WILDCARD | PVFS_RESOLVE_STREAMS, &name);
137         if (!NT_STATUS_IS_OK(status)) {
138                 return status;
139         }
140
141         if (!name->exists && !name->has_wildcard) {
142                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
143         }
144
145         if (name->exists && 
146             (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY)) {
147                 return NT_STATUS_FILE_IS_A_DIRECTORY;
148         }
149
150         if (name->stream_name) {
151                 return pvfs_unlink_stream(pvfs, req, name, unl->unlink.in.attrib);
152         }
153
154         /* get list of matching files */
155         status = pvfs_list_start(pvfs, name, req, &dir);
156         if (!NT_STATUS_IS_OK(status)) {
157                 return status;
158         }
159
160         status = NT_STATUS_NO_SUCH_FILE;
161
162         ofs = 0;
163
164         while ((fname = pvfs_list_next(dir, &ofs))) {
165                 /* this seems to be a special case */
166                 if ((unl->unlink.in.attrib & FILE_ATTRIBUTE_DIRECTORY) &&
167                     (ISDOT(fname) || ISDOTDOT(fname))) {
168                         return NT_STATUS_OBJECT_NAME_INVALID;
169                 }
170
171                 status = pvfs_unlink_one(pvfs, req, pvfs_list_unix_path(dir), fname, unl->unlink.in.attrib);
172                 if (NT_STATUS_IS_OK(status)) {
173                         total_deleted++;
174                 }
175         }
176
177         if (total_deleted > 0) {
178                 status = NT_STATUS_OK;
179         }
180
181         return status;
182 }
183
184