~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/ntvfs/posix/pvfs_rename.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

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