2 Unix SMB/CIFS implementation.
4 POSIX NTVFS backend - rename
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 2 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, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "vfs_posix.h"
28 resolve a wildcard rename pattern. This works on one component of the name
30 static const char *pvfs_resolve_wildcard_component(TALLOC_CTX *mem_ctx,
37 /* the length is bounded by the length of the two strings combined */
38 dest = talloc(mem_ctx, strlen(fname) + strlen(pattern) + 1);
49 size_t c_size1, c_size2;
50 c1 = next_codepoint(p1, &c_size1);
51 c2 = next_codepoint(p2, &c_size2);
53 d += push_codepoint(d, c1);
54 } else if (c2 == '*') {
55 memcpy(d, p1, strlen(p1));
59 d += push_codepoint(d, c2);
72 resolve a wildcard rename pattern.
74 static const char *pvfs_resolve_wildcard(TALLOC_CTX *mem_ctx,
78 const char *base1, *base2;
79 const char *ext1, *ext2;
82 /* break into base part plus extension */
83 p = strrchr_m(fname, '.');
88 ext1 = talloc_strdup(mem_ctx, p+1);
89 base1 = talloc_strndup(mem_ctx, fname, p-fname);
91 if (ext1 == NULL || base1 == NULL) {
95 p = strrchr_m(pattern, '.');
100 ext2 = talloc_strdup(mem_ctx, p+1);
101 base2 = talloc_strndup(mem_ctx, pattern, p-pattern);
103 if (ext2 == NULL || base2 == NULL) {
107 base1 = pvfs_resolve_wildcard_component(mem_ctx, base1, base2);
108 ext1 = pvfs_resolve_wildcard_component(mem_ctx, ext1, ext2);
109 if (base1 == NULL || ext1 == NULL) {
117 return talloc_asprintf(mem_ctx, "%s.%s", base1, ext1);
121 rename one file from a wildcard set
123 static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs,
124 struct smbsrv_request *req,
125 const char *dir_path,
130 struct pvfs_filename *name1, *name2;
131 TALLOC_CTX *mem_ctx = talloc(req, 0);
134 /* resolve the wildcard pattern for this name */
135 fname2 = pvfs_resolve_wildcard(mem_ctx, fname1, fname2);
136 if (fname2 == NULL) {
137 return NT_STATUS_NO_MEMORY;
140 /* get a pvfs_filename source object */
141 status = pvfs_resolve_partial(pvfs, mem_ctx,
142 dir_path, fname1, &name1);
143 if (!NT_STATUS_IS_OK(status)) {
144 talloc_free(mem_ctx);
148 /* make sure its matches the given attributes */
149 status = pvfs_match_attrib(pvfs, name1, attrib, 0);
150 if (!NT_STATUS_IS_OK(status)) {
151 talloc_free(mem_ctx);
155 status = pvfs_can_rename(pvfs, name1);
156 if (!NT_STATUS_IS_OK(status)) {
157 talloc_free(mem_ctx);
161 /* get a pvfs_filename dest object */
162 status = pvfs_resolve_partial(pvfs, mem_ctx,
163 dir_path, fname2, &name2);
164 if (NT_STATUS_IS_OK(status)) {
165 status = pvfs_can_delete(pvfs, name2);
166 if (!NT_STATUS_IS_OK(status)) {
167 talloc_free(mem_ctx);
172 fname2 = talloc_asprintf(mem_ctx, "%s/%s", dir_path, fname2);
173 if (fname2 == NULL) {
174 return NT_STATUS_NO_MEMORY;
177 if (rename(name1->full_name, fname2) == -1) {
178 talloc_free(mem_ctx);
179 return pvfs_map_errno(pvfs, errno);
182 talloc_free(mem_ctx);
189 rename a set of files with wildcards
191 static NTSTATUS pvfs_rename_wildcard(struct pvfs_state *pvfs,
192 struct smbsrv_request *req,
193 union smb_rename *ren,
194 struct pvfs_filename *name1,
195 struct pvfs_filename *name2)
197 struct pvfs_dir *dir;
200 const char *fname, *fname2, *dir_path;
201 uint16_t attrib = ren->rename.in.attrib;
202 int total_renamed = 0;
204 /* get list of matching files */
205 status = pvfs_list_start(pvfs, name1, req, &dir);
206 if (!NT_STATUS_IS_OK(status)) {
210 status = NT_STATUS_NO_SUCH_FILE;
212 dir_path = pvfs_list_unix_path(dir);
214 /* only allow wildcard renames within a directory */
215 if (strncmp(dir_path, name2->full_name, strlen(dir_path)) != 0 ||
216 name2->full_name[strlen(dir_path)] != '/' ||
217 strchr(name2->full_name + strlen(dir_path) + 1, '/')) {
218 return NT_STATUS_INVALID_PARAMETER;
221 fname2 = talloc_strdup(name2, name2->full_name + strlen(dir_path) + 1);
222 if (fname2 == NULL) {
223 return NT_STATUS_NO_MEMORY;
226 while ((fname = pvfs_list_next(dir, &ofs))) {
227 status = pvfs_rename_one(pvfs, req,
229 fname, fname2, attrib);
230 if (NT_STATUS_IS_OK(status)) {
235 if (total_renamed == 0) {
243 rename a set of files - SMBmv interface
245 static NTSTATUS pvfs_rename_mv(struct ntvfs_module_context *ntvfs,
246 struct smbsrv_request *req, union smb_rename *ren)
248 struct pvfs_state *pvfs = ntvfs->private_data;
250 struct pvfs_filename *name1, *name2;
252 /* resolve the cifs name to a posix name */
253 status = pvfs_resolve_name(pvfs, req, ren->rename.in.pattern1,
254 PVFS_RESOLVE_WILDCARD, &name1);
255 if (!NT_STATUS_IS_OK(status)) {
259 status = pvfs_resolve_name(pvfs, req, ren->rename.in.pattern2,
260 PVFS_RESOLVE_WILDCARD, &name2);
261 if (!NT_STATUS_IS_OK(status)) {
265 if (name1->has_wildcard || name2->has_wildcard) {
266 return pvfs_rename_wildcard(pvfs, req, ren, name1, name2);
269 if (!name1->exists) {
270 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
273 if (strcmp(name1->full_name, name2->full_name) == 0) {
278 return NT_STATUS_OBJECT_NAME_COLLISION;
281 status = pvfs_match_attrib(pvfs, name1, ren->rename.in.attrib, 0);
282 if (!NT_STATUS_IS_OK(status)) {
286 status = pvfs_can_rename(pvfs, name1);
287 if (!NT_STATUS_IS_OK(status)) {
291 if (rename(name1->full_name, name2->full_name) == -1) {
292 return pvfs_map_errno(pvfs, errno);
300 rename a set of files - ntrename interface
302 static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs,
303 struct smbsrv_request *req, union smb_rename *ren)
305 struct pvfs_state *pvfs = ntvfs->private_data;
307 struct pvfs_filename *name1, *name2;
309 switch (ren->ntrename.in.flags) {
310 case RENAME_FLAG_RENAME:
311 case RENAME_FLAG_HARD_LINK:
312 case RENAME_FLAG_COPY:
313 case RENAME_FLAG_MOVE_CLUSTER_INFORMATION:
316 return NT_STATUS_ACCESS_DENIED;
319 /* resolve the cifs name to a posix name */
320 status = pvfs_resolve_name(pvfs, req, ren->ntrename.in.old_name, 0, &name1);
321 if (!NT_STATUS_IS_OK(status)) {
325 status = pvfs_resolve_name(pvfs, req, ren->ntrename.in.new_name, 0, &name2);
326 if (!NT_STATUS_IS_OK(status)) {
330 if (!name1->exists) {
331 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
334 if (strcmp(name1->full_name, name2->full_name) == 0) {
339 return NT_STATUS_OBJECT_NAME_COLLISION;
342 status = pvfs_match_attrib(pvfs, name1, ren->ntrename.in.attrib, 0);
343 if (!NT_STATUS_IS_OK(status)) {
347 status = pvfs_can_rename(pvfs, name1);
348 if (!NT_STATUS_IS_OK(status)) {
352 switch (ren->ntrename.in.flags) {
353 case RENAME_FLAG_RENAME:
354 if (rename(name1->full_name, name2->full_name) == -1) {
355 return pvfs_map_errno(pvfs, errno);
359 case RENAME_FLAG_HARD_LINK:
360 if (link(name1->full_name, name2->full_name) == -1) {
361 return pvfs_map_errno(pvfs, errno);
365 case RENAME_FLAG_COPY:
366 return pvfs_copy_file(pvfs, name1, name2);
368 case RENAME_FLAG_MOVE_CLUSTER_INFORMATION:
369 return NT_STATUS_INVALID_PARAMETER;
372 return NT_STATUS_ACCESS_DENIED;
380 rename a set of files - ntrename interface
382 NTSTATUS pvfs_rename(struct ntvfs_module_context *ntvfs,
383 struct smbsrv_request *req, union smb_rename *ren)
385 switch (ren->generic.level) {
386 case RAW_RENAME_RENAME:
387 return pvfs_rename_mv(ntvfs, req, ren);
389 case RAW_RENAME_NTRENAME:
390 return pvfs_rename_nt(ntvfs, req, ren);
396 return NT_STATUS_INVALID_LEVEL;