Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : POSIX NTVFS backend - rename
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 "librpc/gen_ndr/security.h"
25 : #include "param/param.h"
26 :
27 :
28 : /*
29 : do a file rename, and send any notify triggers
30 : */
31 116 : NTSTATUS pvfs_do_rename(struct pvfs_state *pvfs,
32 : struct odb_lock *lck,
33 : const struct pvfs_filename *name1,
34 : const char *name2)
35 : {
36 0 : const char *r1, *r2;
37 0 : uint32_t mask;
38 0 : NTSTATUS status;
39 :
40 116 : if (pvfs_sys_rename(pvfs, name1->full_name, name2,
41 116 : name1->allow_override) == -1) {
42 4 : return pvfs_map_errno(pvfs, errno);
43 : }
44 :
45 112 : status = odb_rename(lck, name2);
46 112 : NT_STATUS_NOT_OK_RETURN(status);
47 :
48 112 : if (name1->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) {
49 40 : mask = FILE_NOTIFY_CHANGE_DIR_NAME;
50 : } else {
51 72 : mask = FILE_NOTIFY_CHANGE_FILE_NAME;
52 : }
53 : /*
54 : renames to the same directory cause a OLD_NAME->NEW_NAME notify.
55 : renames to a different directory are considered a remove/add
56 : */
57 112 : r1 = strrchr_m(name1->full_name, '/');
58 112 : r2 = strrchr_m(name2, '/');
59 :
60 112 : if ((r1-name1->full_name) != (r2-name2) ||
61 110 : strncmp(name1->full_name, name2, r1-name1->full_name) != 0) {
62 2 : notify_trigger(pvfs->notify_context,
63 : NOTIFY_ACTION_REMOVED,
64 : mask,
65 2 : name1->full_name);
66 2 : notify_trigger(pvfs->notify_context,
67 : NOTIFY_ACTION_ADDED,
68 : mask,
69 : name2);
70 : } else {
71 110 : notify_trigger(pvfs->notify_context,
72 : NOTIFY_ACTION_OLD_NAME,
73 : mask,
74 110 : name1->full_name);
75 110 : notify_trigger(pvfs->notify_context,
76 : NOTIFY_ACTION_NEW_NAME,
77 : mask,
78 : name2);
79 : }
80 :
81 : /* this is a strange one. w2k3 gives an additional event for CHANGE_ATTRIBUTES
82 : and CHANGE_CREATION on the new file when renaming files, but not
83 : directories */
84 112 : if ((name1->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) == 0) {
85 72 : notify_trigger(pvfs->notify_context,
86 : NOTIFY_ACTION_MODIFIED,
87 : FILE_NOTIFY_CHANGE_ATTRIBUTES|FILE_NOTIFY_CHANGE_CREATION,
88 : name2);
89 : }
90 :
91 112 : return NT_STATUS_OK;
92 : }
93 :
94 :
95 : /*
96 : resolve a wildcard rename pattern. This works on one component of the name
97 : */
98 12 : static const char *pvfs_resolve_wildcard_component(TALLOC_CTX *mem_ctx,
99 : const char *fname,
100 : const char *pattern)
101 : {
102 0 : const char *p1, *p2;
103 0 : char *dest, *d;
104 :
105 : /* the length is bounded by the length of the two strings combined */
106 12 : dest = talloc_array(mem_ctx, char, strlen(fname) + strlen(pattern) + 1);
107 12 : if (dest == NULL) {
108 0 : return NULL;
109 : }
110 :
111 12 : p1 = fname;
112 12 : p2 = pattern;
113 12 : d = dest;
114 :
115 30 : while (*p2) {
116 0 : codepoint_t c1, c2;
117 0 : size_t c_size1, c_size2;
118 24 : c1 = next_codepoint(p1, &c_size1);
119 24 : c2 = next_codepoint(p2, &c_size2);
120 24 : if (c2 == '?') {
121 0 : d += push_codepoint(d, c1);
122 24 : } else if (c2 == '*') {
123 6 : memcpy(d, p1, strlen(p1));
124 6 : d += strlen(p1);
125 6 : break;
126 : } else {
127 18 : d += push_codepoint(d, c2);
128 : }
129 :
130 18 : p1 += c_size1;
131 18 : p2 += c_size2;
132 : }
133 :
134 12 : *d = 0;
135 :
136 12 : talloc_set_name_const(dest, dest);
137 :
138 12 : return dest;
139 : }
140 :
141 : /*
142 : resolve a wildcard rename pattern.
143 : */
144 6 : static const char *pvfs_resolve_wildcard(TALLOC_CTX *mem_ctx,
145 : const char *fname,
146 : const char *pattern)
147 : {
148 0 : const char *base1, *base2;
149 0 : const char *ext1, *ext2;
150 0 : char *p;
151 :
152 : /* break into base part plus extension */
153 6 : p = strrchr_m(fname, '.');
154 6 : if (p == NULL) {
155 0 : ext1 = "";
156 0 : base1 = fname;
157 : } else {
158 6 : ext1 = talloc_strdup(mem_ctx, p+1);
159 6 : base1 = talloc_strndup(mem_ctx, fname, p-fname);
160 : }
161 6 : if (ext1 == NULL || base1 == NULL) {
162 0 : return NULL;
163 : }
164 :
165 6 : p = strrchr_m(pattern, '.');
166 6 : if (p == NULL) {
167 0 : ext2 = "";
168 0 : base2 = fname;
169 : } else {
170 6 : ext2 = talloc_strdup(mem_ctx, p+1);
171 6 : base2 = talloc_strndup(mem_ctx, pattern, p-pattern);
172 : }
173 6 : if (ext2 == NULL || base2 == NULL) {
174 0 : return NULL;
175 : }
176 :
177 6 : base1 = pvfs_resolve_wildcard_component(mem_ctx, base1, base2);
178 6 : ext1 = pvfs_resolve_wildcard_component(mem_ctx, ext1, ext2);
179 6 : if (base1 == NULL || ext1 == NULL) {
180 0 : return NULL;
181 : }
182 :
183 6 : if (*ext1 == 0) {
184 0 : return base1;
185 : }
186 :
187 6 : return talloc_asprintf(mem_ctx, "%s.%s", base1, ext1);
188 : }
189 :
190 : /*
191 : retry an rename after a sharing violation
192 : */
193 15 : static void pvfs_retry_rename(struct pvfs_odb_retry *r,
194 : struct ntvfs_module_context *ntvfs,
195 : struct ntvfs_request *req,
196 : void *_io,
197 : void *private_data,
198 : enum pvfs_wait_notice reason)
199 : {
200 15 : union smb_rename *io = talloc_get_type(_io, union smb_rename);
201 15 : NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
202 :
203 15 : talloc_free(r);
204 :
205 15 : switch (reason) {
206 0 : case PVFS_WAIT_CANCEL:
207 : /*TODO*/
208 0 : status = NT_STATUS_CANCELLED;
209 11 : break;
210 11 : case PVFS_WAIT_TIMEOUT:
211 : /* if it timed out, then give the failure
212 : immediately */
213 : /*TODO*/
214 11 : status = NT_STATUS_SHARING_VIOLATION;
215 11 : break;
216 4 : case PVFS_WAIT_EVENT:
217 :
218 : /* try the open again, which could trigger another retry setup
219 : if it wants to, so we have to unmark the async flag so we
220 : will know if it does a second async reply */
221 4 : req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
222 :
223 4 : status = pvfs_rename(ntvfs, req, io);
224 4 : if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
225 : /* the 2nd try also replied async, so we don't send
226 : the reply yet */
227 4 : return;
228 : }
229 :
230 : /* re-mark it async, just in case someone up the chain does
231 : paranoid checking */
232 0 : req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
233 0 : break;
234 : }
235 :
236 : /* send the reply up the chain */
237 11 : req->async_states->status = status;
238 11 : req->async_states->send_fn(req);
239 : }
240 :
241 : /*
242 : setup for a rename retry after a sharing violation
243 : or a non granted oplock
244 : */
245 15 : static NTSTATUS pvfs_rename_setup_retry(struct ntvfs_module_context *ntvfs,
246 : struct ntvfs_request *req,
247 : union smb_rename *io,
248 : struct odb_lock *lck,
249 : NTSTATUS status)
250 : {
251 15 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
252 : struct pvfs_state);
253 0 : struct timeval end_time;
254 :
255 15 : if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
256 11 : end_time = timeval_add(&req->statistics.request_time,
257 : 0, pvfs->sharing_violation_delay);
258 4 : } else if (NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
259 4 : end_time = timeval_add(&req->statistics.request_time,
260 : pvfs->oplock_break_timeout, 0);
261 : } else {
262 0 : return NT_STATUS_INTERNAL_ERROR;
263 : }
264 :
265 15 : return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io, NULL,
266 : pvfs_retry_rename);
267 : }
268 :
269 : /*
270 : rename one file from a wildcard set
271 : */
272 6 : static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs,
273 : struct ntvfs_request *req,
274 : const char *dir_path,
275 : const char *fname1,
276 : const char *fname2,
277 : uint16_t attrib)
278 : {
279 0 : struct pvfs_filename *name1, *name2;
280 6 : TALLOC_CTX *mem_ctx = talloc_new(req);
281 6 : struct odb_lock *lck = NULL;
282 0 : NTSTATUS status;
283 :
284 : /* resolve the wildcard pattern for this name */
285 6 : fname2 = pvfs_resolve_wildcard(mem_ctx, fname1, fname2);
286 6 : if (fname2 == NULL) {
287 0 : return NT_STATUS_NO_MEMORY;
288 : }
289 :
290 : /* get a pvfs_filename source object */
291 6 : status = pvfs_resolve_partial(pvfs, mem_ctx,
292 : dir_path, fname1,
293 : PVFS_RESOLVE_NO_OPENDB,
294 : &name1);
295 6 : if (!NT_STATUS_IS_OK(status)) {
296 0 : goto failed;
297 : }
298 :
299 : /* make sure its matches the given attributes */
300 6 : status = pvfs_match_attrib(pvfs, name1, attrib, 0);
301 6 : if (!NT_STATUS_IS_OK(status)) {
302 0 : goto failed;
303 : }
304 :
305 6 : status = pvfs_can_rename(pvfs, req, name1, &lck);
306 6 : if (!NT_STATUS_IS_OK(status)) {
307 0 : talloc_free(lck);
308 0 : goto failed;
309 : }
310 :
311 : /* get a pvfs_filename dest object */
312 6 : status = pvfs_resolve_partial(pvfs, mem_ctx,
313 : dir_path, fname2,
314 : PVFS_RESOLVE_NO_OPENDB,
315 : &name2);
316 6 : if (NT_STATUS_IS_OK(status)) {
317 0 : status = pvfs_can_delete(pvfs, req, name2, NULL);
318 0 : if (!NT_STATUS_IS_OK(status)) {
319 0 : goto failed;
320 : }
321 : }
322 :
323 6 : status = NT_STATUS_OK;
324 :
325 6 : fname2 = talloc_asprintf(mem_ctx, "%s/%s", dir_path, fname2);
326 6 : if (fname2 == NULL) {
327 0 : return NT_STATUS_NO_MEMORY;
328 : }
329 :
330 6 : status = pvfs_do_rename(pvfs, lck, name1, fname2);
331 :
332 6 : failed:
333 6 : talloc_free(mem_ctx);
334 6 : return status;
335 : }
336 :
337 :
338 : /*
339 : rename a set of files with wildcards
340 : */
341 2 : static NTSTATUS pvfs_rename_wildcard(struct pvfs_state *pvfs,
342 : struct ntvfs_request *req,
343 : union smb_rename *ren,
344 : struct pvfs_filename *name1,
345 : struct pvfs_filename *name2)
346 : {
347 0 : struct pvfs_dir *dir;
348 0 : NTSTATUS status;
349 2 : off_t ofs = 0;
350 0 : const char *fname, *fname2, *dir_path;
351 2 : uint16_t attrib = ren->rename.in.attrib;
352 2 : int total_renamed = 0;
353 :
354 : /* get list of matching files */
355 2 : status = pvfs_list_start(pvfs, name1, req, &dir);
356 2 : if (!NT_STATUS_IS_OK(status)) {
357 0 : return status;
358 : }
359 :
360 2 : status = NT_STATUS_NO_SUCH_FILE;
361 :
362 2 : dir_path = pvfs_list_unix_path(dir);
363 :
364 : /* only allow wildcard renames within a directory */
365 2 : if (strncmp(dir_path, name2->full_name, strlen(dir_path)) != 0 ||
366 2 : name2->full_name[strlen(dir_path)] != '/' ||
367 2 : strchr(name2->full_name + strlen(dir_path) + 1, '/')) {
368 0 : DEBUG(3,(__location__ ": Invalid rename for %s -> %s\n",
369 : name1->original_name, name2->original_name));
370 0 : return NT_STATUS_INVALID_PARAMETER;
371 : }
372 :
373 2 : fname2 = talloc_strdup(name2, name2->full_name + strlen(dir_path) + 1);
374 2 : if (fname2 == NULL) {
375 0 : return NT_STATUS_NO_MEMORY;
376 : }
377 :
378 8 : while ((fname = pvfs_list_next(dir, &ofs))) {
379 6 : status = pvfs_rename_one(pvfs, req,
380 : dir_path,
381 : fname, fname2, attrib);
382 6 : if (NT_STATUS_IS_OK(status)) {
383 2 : total_renamed++;
384 : }
385 : }
386 :
387 2 : if (total_renamed == 0) {
388 0 : return status;
389 : }
390 :
391 2 : return NT_STATUS_OK;
392 : }
393 :
394 : /*
395 : rename a set of files - SMBmv interface
396 : */
397 110 : static NTSTATUS pvfs_rename_mv(struct ntvfs_module_context *ntvfs,
398 : struct ntvfs_request *req, union smb_rename *ren)
399 : {
400 110 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
401 : struct pvfs_state);
402 0 : NTSTATUS status;
403 0 : struct pvfs_filename *name1, *name2;
404 110 : struct odb_lock *lck = NULL;
405 :
406 : /* resolve the cifs name to a posix name */
407 110 : status = pvfs_resolve_name(pvfs, req, ren->rename.in.pattern1,
408 : PVFS_RESOLVE_WILDCARD, &name1);
409 110 : if (!NT_STATUS_IS_OK(status)) {
410 7 : return status;
411 : }
412 :
413 103 : status = pvfs_resolve_name(pvfs, req, ren->rename.in.pattern2,
414 : PVFS_RESOLVE_WILDCARD, &name2);
415 103 : if (!NT_STATUS_IS_OK(status)) {
416 2 : return status;
417 : }
418 :
419 101 : if (name1->has_wildcard || name2->has_wildcard) {
420 2 : return pvfs_rename_wildcard(pvfs, req, ren, name1, name2);
421 : }
422 :
423 99 : if (!name1->exists) {
424 2 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
425 : }
426 :
427 97 : if (strcmp(name1->full_name, name2->full_name) == 0) {
428 2 : return NT_STATUS_OK;
429 : }
430 :
431 95 : if (name2->exists) {
432 0 : return NT_STATUS_OBJECT_NAME_COLLISION;
433 : }
434 :
435 95 : status = pvfs_match_attrib(pvfs, name1, ren->rename.in.attrib, 0);
436 95 : if (!NT_STATUS_IS_OK(status)) {
437 1 : return status;
438 : }
439 :
440 94 : status = pvfs_access_check_parent(pvfs, req, name2, SEC_DIR_ADD_FILE);
441 94 : if (!NT_STATUS_IS_OK(status)) {
442 0 : return status;
443 : }
444 :
445 94 : status = pvfs_can_rename(pvfs, req, name1, &lck);
446 : /*
447 : * on a sharing violation we need to retry when the file is closed by
448 : * the other user, or after 1 second
449 : * on a non granted oplock we need to retry when the file is closed by
450 : * the other user, or after 30 seconds
451 : */
452 94 : if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
453 86 : NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
454 10 : (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
455 10 : return pvfs_rename_setup_retry(pvfs->ntvfs, req, ren, lck, status);
456 : }
457 :
458 84 : if (!NT_STATUS_IS_OK(status)) {
459 0 : return status;
460 : }
461 :
462 84 : status = pvfs_do_rename(pvfs, lck, name1, name2->full_name);
463 84 : if (!NT_STATUS_IS_OK(status)) {
464 0 : return status;
465 : }
466 :
467 84 : return NT_STATUS_OK;
468 : }
469 :
470 :
471 : /*
472 : rename a stream
473 : */
474 4 : static NTSTATUS pvfs_rename_stream(struct ntvfs_module_context *ntvfs,
475 : struct ntvfs_request *req, union smb_rename *ren,
476 : struct pvfs_filename *name1)
477 : {
478 4 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
479 : struct pvfs_state);
480 0 : NTSTATUS status;
481 4 : struct odb_lock *lck = NULL;
482 :
483 4 : if (name1->has_wildcard) {
484 0 : DEBUG(3,(__location__ ": Invalid wildcard rename for %s\n",
485 : name1->original_name));
486 0 : return NT_STATUS_INVALID_PARAMETER;
487 : }
488 :
489 4 : if (ren->ntrename.in.new_name[0] != ':') {
490 2 : DEBUG(3,(__location__ ": Invalid rename for %s\n",
491 : ren->ntrename.in.new_name));
492 2 : return NT_STATUS_INVALID_PARAMETER;
493 : }
494 :
495 2 : if (!name1->exists) {
496 0 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
497 : }
498 :
499 2 : if (ren->ntrename.in.flags != RENAME_FLAG_RENAME) {
500 0 : DEBUG(3,(__location__ ": Invalid rename flags 0x%x for %s\n",
501 : ren->ntrename.in.flags, ren->ntrename.in.new_name));
502 0 : return NT_STATUS_INVALID_PARAMETER;
503 : }
504 :
505 2 : status = pvfs_can_rename(pvfs, req, name1, &lck);
506 : /*
507 : * on a sharing violation we need to retry when the file is closed by
508 : * the other user, or after 1 second
509 : * on a non granted oplock we need to retry when the file is closed by
510 : * the other user, or after 30 seconds
511 : */
512 2 : if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
513 2 : NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
514 0 : (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
515 0 : return pvfs_rename_setup_retry(pvfs->ntvfs, req, ren, lck, status);
516 : }
517 2 : if (!NT_STATUS_IS_OK(status)) {
518 0 : return status;
519 : }
520 :
521 2 : status = pvfs_access_check_simple(pvfs, req, name1, SEC_FILE_WRITE_ATTRIBUTE);
522 2 : NT_STATUS_NOT_OK_RETURN(status);
523 :
524 2 : status = pvfs_stream_rename(pvfs, name1, -1,
525 2 : ren->ntrename.in.new_name+1,
526 : true);
527 2 : NT_STATUS_NOT_OK_RETURN(status);
528 :
529 1 : return NT_STATUS_OK;
530 : }
531 :
532 : /*
533 : rename a set of files - ntrename interface
534 : */
535 4125 : static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs,
536 : struct ntvfs_request *req, union smb_rename *ren)
537 : {
538 4125 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
539 : struct pvfs_state);
540 0 : NTSTATUS status;
541 0 : struct pvfs_filename *name1, *name2;
542 4125 : struct odb_lock *lck = NULL;
543 :
544 4125 : switch (ren->ntrename.in.flags) {
545 25 : case RENAME_FLAG_RENAME:
546 : case RENAME_FLAG_HARD_LINK:
547 : case RENAME_FLAG_COPY:
548 : case RENAME_FLAG_MOVE_CLUSTER_INFORMATION:
549 25 : break;
550 4100 : default:
551 4100 : return NT_STATUS_ACCESS_DENIED;
552 : }
553 :
554 : /* resolve the cifs name to a posix name */
555 25 : status = pvfs_resolve_name(pvfs, req, ren->ntrename.in.old_name,
556 : PVFS_RESOLVE_WILDCARD | PVFS_RESOLVE_STREAMS, &name1);
557 25 : if (!NT_STATUS_IS_OK(status)) {
558 0 : return status;
559 : }
560 :
561 25 : if (name1->stream_name) {
562 : /* stream renames need to be handled separately */
563 4 : return pvfs_rename_stream(ntvfs, req, ren, name1);
564 : }
565 :
566 21 : status = pvfs_resolve_name(pvfs, req, ren->ntrename.in.new_name,
567 : PVFS_RESOLVE_WILDCARD, &name2);
568 21 : if (!NT_STATUS_IS_OK(status)) {
569 3 : return status;
570 : }
571 :
572 18 : if (name1->has_wildcard || name2->has_wildcard) {
573 1 : return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
574 : }
575 :
576 17 : if (!name1->exists) {
577 1 : return NT_STATUS_OBJECT_NAME_NOT_FOUND;
578 : }
579 :
580 16 : if (strcmp(name1->full_name, name2->full_name) == 0) {
581 1 : return NT_STATUS_OK;
582 : }
583 :
584 15 : if (name2->exists) {
585 1 : return NT_STATUS_OBJECT_NAME_COLLISION;
586 : }
587 :
588 14 : status = pvfs_match_attrib(pvfs, name1, ren->ntrename.in.attrib, 0);
589 14 : if (!NT_STATUS_IS_OK(status)) {
590 1 : return status;
591 : }
592 :
593 13 : status = pvfs_can_rename(pvfs, req, name1, &lck);
594 : /*
595 : * on a sharing violation we need to retry when the file is closed by
596 : * the other user, or after 1 second
597 : * on a non granted oplock we need to retry when the file is closed by
598 : * the other user, or after 30 seconds
599 : */
600 13 : if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
601 10 : NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
602 5 : (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
603 5 : return pvfs_rename_setup_retry(pvfs->ntvfs, req, ren, lck, status);
604 : }
605 8 : if (!NT_STATUS_IS_OK(status)) {
606 0 : return status;
607 : }
608 :
609 8 : switch (ren->ntrename.in.flags) {
610 3 : case RENAME_FLAG_RENAME:
611 3 : status = pvfs_access_check_parent(pvfs, req, name2, SEC_DIR_ADD_FILE);
612 6 : NT_STATUS_NOT_OK_RETURN(status);
613 3 : status = pvfs_do_rename(pvfs, lck, name1, name2->full_name);
614 3 : NT_STATUS_NOT_OK_RETURN(status);
615 3 : break;
616 :
617 2 : case RENAME_FLAG_HARD_LINK:
618 2 : status = pvfs_access_check_parent(pvfs, req, name2, SEC_DIR_ADD_FILE);
619 2 : NT_STATUS_NOT_OK_RETURN(status);
620 2 : if (link(name1->full_name, name2->full_name) == -1) {
621 0 : return pvfs_map_errno(pvfs, errno);
622 : }
623 2 : break;
624 :
625 2 : case RENAME_FLAG_COPY:
626 2 : status = pvfs_access_check_parent(pvfs, req, name2, SEC_DIR_ADD_FILE);
627 2 : NT_STATUS_NOT_OK_RETURN(status);
628 2 : return pvfs_copy_file(pvfs, name1, name2, name1->allow_override && name2->allow_override);
629 :
630 1 : case RENAME_FLAG_MOVE_CLUSTER_INFORMATION:
631 1 : DEBUG(3,(__location__ ": Invalid rename cluster for %s\n",
632 : name1->original_name));
633 1 : return NT_STATUS_INVALID_PARAMETER;
634 :
635 0 : default:
636 0 : return NT_STATUS_ACCESS_DENIED;
637 : }
638 :
639 :
640 5 : return NT_STATUS_OK;
641 : }
642 :
643 : /*
644 : rename a set of files - ntrename interface
645 : */
646 4236 : NTSTATUS pvfs_rename(struct ntvfs_module_context *ntvfs,
647 : struct ntvfs_request *req, union smb_rename *ren)
648 : {
649 4236 : struct pvfs_state *pvfs = talloc_get_type(ntvfs->private_data,
650 : struct pvfs_state);
651 0 : struct pvfs_file *f;
652 :
653 4236 : switch (ren->generic.level) {
654 110 : case RAW_RENAME_RENAME:
655 4236 : return pvfs_rename_mv(ntvfs, req, ren);
656 :
657 4125 : case RAW_RENAME_NTRENAME:
658 4125 : return pvfs_rename_nt(ntvfs, req, ren);
659 :
660 1 : case RAW_RENAME_NTTRANS:
661 1 : f = pvfs_find_fd(pvfs, req, ren->nttrans.in.file.ntvfs);
662 1 : if (!f) {
663 0 : return NT_STATUS_INVALID_HANDLE;
664 : }
665 :
666 : /* wk23 ignores the request */
667 1 : return NT_STATUS_OK;
668 :
669 0 : default:
670 0 : break;
671 : }
672 :
673 0 : return NT_STATUS_INVALID_LEVEL;
674 : }
675 :
|