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_size(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_new(req);
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)) {
147 /* make sure its matches the given attributes */
148 status = pvfs_match_attrib(pvfs, name1, attrib, 0);
149 if (!NT_STATUS_IS_OK(status)) {
153 status = pvfs_can_rename(pvfs, name1);
154 if (!NT_STATUS_IS_OK(status)) {
158 /* get a pvfs_filename dest object */
159 status = pvfs_resolve_partial(pvfs, mem_ctx,
160 dir_path, fname2, &name2);
161 if (NT_STATUS_IS_OK(status)) {
162 status = pvfs_can_delete(pvfs, req, name2);
163 if (!NT_STATUS_IS_OK(status)) {
168 status = NT_STATUS_OK;
170 fname2 = talloc_asprintf(mem_ctx, "%s/%s", dir_path, fname2);
171 if (fname2 == NULL) {
172 return NT_STATUS_NO_MEMORY;
175 if (rename(name1->full_name, fname2) == -1) {
176 talloc_free(mem_ctx);
177 return pvfs_map_errno(pvfs, errno);
181 talloc_free(mem_ctx);
187 rename a set of files with wildcards
189 static NTSTATUS pvfs_rename_wildcard(struct pvfs_state *pvfs,
190 struct smbsrv_request *req,
191 union smb_rename *ren,
192 struct pvfs_filename *name1,
193 struct pvfs_filename *name2)
195 struct pvfs_dir *dir;
198 const char *fname, *fname2, *dir_path;
199 uint16_t attrib = ren->rename.in.attrib;
200 int total_renamed = 0;
202 /* get list of matching files */
203 status = pvfs_list_start(pvfs, name1, req, &dir);
204 if (!NT_STATUS_IS_OK(status)) {
208 status = NT_STATUS_NO_SUCH_FILE;
210 dir_path = pvfs_list_unix_path(dir);
212 /* only allow wildcard renames within a directory */
213 if (strncmp(dir_path, name2->full_name, strlen(dir_path)) != 0 ||
214 name2->full_name[strlen(dir_path)] != '/' ||
215 strchr(name2->full_name + strlen(dir_path) + 1, '/')) {
216 return NT_STATUS_INVALID_PARAMETER;
219 fname2 = talloc_strdup(name2, name2->full_name + strlen(dir_path) + 1);
220 if (fname2 == NULL) {
221 return NT_STATUS_NO_MEMORY;
224 while ((fname = pvfs_list_next(dir, &ofs))) {
225 status = pvfs_rename_one(pvfs, req,
227 fname, fname2, attrib);
228 if (NT_STATUS_IS_OK(status)) {
233 if (total_renamed == 0) {
241 rename a set of files - SMBmv interface
243 static NTSTATUS pvfs_rename_mv(struct ntvfs_module_context *ntvfs,
244 struct smbsrv_request *req, union smb_rename *ren)
246 struct pvfs_state *pvfs = ntvfs->private_data;
248 struct pvfs_filename *name1, *name2;
250 /* resolve the cifs name to a posix name */
251 status = pvfs_resolve_name(pvfs, req, ren->rename.in.pattern1,
252 PVFS_RESOLVE_WILDCARD, &name1);
253 if (!NT_STATUS_IS_OK(status)) {
257 status = pvfs_resolve_name(pvfs, req, ren->rename.in.pattern2,
258 PVFS_RESOLVE_WILDCARD, &name2);
259 if (!NT_STATUS_IS_OK(status)) {
263 if (name1->has_wildcard || name2->has_wildcard) {
264 return pvfs_rename_wildcard(pvfs, req, ren, name1, name2);
267 if (!name1->exists) {
268 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
271 if (strcmp(name1->full_name, name2->full_name) == 0) {
276 return NT_STATUS_OBJECT_NAME_COLLISION;
279 status = pvfs_match_attrib(pvfs, name1, ren->rename.in.attrib, 0);
280 if (!NT_STATUS_IS_OK(status)) {
284 status = pvfs_access_check_create(pvfs, req, name2);
285 if (!NT_STATUS_IS_OK(status)) {
289 status = pvfs_can_rename(pvfs, name1);
290 if (!NT_STATUS_IS_OK(status)) {
294 if (rename(name1->full_name, name2->full_name) == -1) {
295 return pvfs_map_errno(pvfs, errno);
303 rename a set of files - ntrename interface
305 static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs,
306 struct smbsrv_request *req, union smb_rename *ren)
308 struct pvfs_state *pvfs = ntvfs->private_data;
310 struct pvfs_filename *name1, *name2;
312 switch (ren->ntrename.in.flags) {
313 case RENAME_FLAG_RENAME:
314 case RENAME_FLAG_HARD_LINK:
315 case RENAME_FLAG_COPY:
316 case RENAME_FLAG_MOVE_CLUSTER_INFORMATION:
319 return NT_STATUS_ACCESS_DENIED;
322 /* resolve the cifs name to a posix name */
323 status = pvfs_resolve_name(pvfs, req, ren->ntrename.in.old_name,
324 PVFS_RESOLVE_WILDCARD, &name1);
325 if (!NT_STATUS_IS_OK(status)) {
329 status = pvfs_resolve_name(pvfs, req, ren->ntrename.in.new_name,
330 PVFS_RESOLVE_WILDCARD, &name2);
331 if (!NT_STATUS_IS_OK(status)) {
335 if (name1->has_wildcard || name2->has_wildcard) {
336 return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
339 if (!name1->exists) {
340 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
343 if (strcmp(name1->full_name, name2->full_name) == 0) {
348 return NT_STATUS_OBJECT_NAME_COLLISION;
351 status = pvfs_match_attrib(pvfs, name1, ren->ntrename.in.attrib, 0);
352 if (!NT_STATUS_IS_OK(status)) {
356 status = pvfs_can_rename(pvfs, name1);
357 if (!NT_STATUS_IS_OK(status)) {
361 switch (ren->ntrename.in.flags) {
362 case RENAME_FLAG_RENAME:
363 status = pvfs_access_check_create(pvfs, req, name2);
364 if (!NT_STATUS_IS_OK(status)) {
367 if (rename(name1->full_name, name2->full_name) == -1) {
368 return pvfs_map_errno(pvfs, errno);
372 case RENAME_FLAG_HARD_LINK:
373 status = pvfs_access_check_create(pvfs, req, name2);
374 if (!NT_STATUS_IS_OK(status)) {
377 if (link(name1->full_name, name2->full_name) == -1) {
378 return pvfs_map_errno(pvfs, errno);
382 case RENAME_FLAG_COPY:
383 status = pvfs_access_check_create(pvfs, req, name2);
384 if (!NT_STATUS_IS_OK(status)) {
387 return pvfs_copy_file(pvfs, name1, name2);
389 case RENAME_FLAG_MOVE_CLUSTER_INFORMATION:
390 return NT_STATUS_INVALID_PARAMETER;
393 return NT_STATUS_ACCESS_DENIED;
401 rename a set of files - ntrename interface
403 NTSTATUS pvfs_rename(struct ntvfs_module_context *ntvfs,
404 struct smbsrv_request *req, union smb_rename *ren)
406 switch (ren->generic.level) {
407 case RAW_RENAME_RENAME:
408 return pvfs_rename_mv(ntvfs, req, ren);
410 case RAW_RENAME_NTRENAME:
411 return pvfs_rename_nt(ntvfs, req, ren);
417 return NT_STATUS_INVALID_LEVEL;