libndr: Avoid assigning duplicate versions to symbols
[amitay/samba.git] / source3 / smbd / files.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Files[] structure handling
4    Copyright (C) Andrew Tridgell 1998
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "smbd/smbd.h"
22 #include "smbd/globals.h"
23 #include "libcli/security/security.h"
24 #include "util_tdb.h"
25 #include "lib/util/bitmap.h"
26
27 #define FILE_HANDLE_OFFSET 0x1000
28
29 /**
30  * create new fsp to be used for file_new or a durable handle reconnect
31  */
32 NTSTATUS fsp_new(struct connection_struct *conn, TALLOC_CTX *mem_ctx,
33                  files_struct **result)
34 {
35         NTSTATUS status = NT_STATUS_NO_MEMORY;
36         files_struct *fsp = NULL;
37         struct smbd_server_connection *sconn = conn->sconn;
38
39         fsp = talloc_zero(mem_ctx, struct files_struct);
40         if (fsp == NULL) {
41                 goto fail;
42         }
43
44         /*
45          * This can't be a child of fsp because the file_handle can be ref'd
46          * when doing a dos/fcb open, which will then share the file_handle
47          * across multiple fsps.
48          */
49         fsp->fh = talloc_zero(mem_ctx, struct fd_handle);
50         if (fsp->fh == NULL) {
51                 goto fail;
52         }
53
54 #if defined(HAVE_OFD_LOCKS)
55         fsp->fsp_flags.use_ofd_locks = true;
56         if (lp_parm_bool(SNUM(conn),
57                          "smbd",
58                          "force process locks",
59                          false)) {
60                 fsp->fsp_flags.use_ofd_locks = false;
61         }
62 #endif
63         fsp->fh->ref_count = 1;
64         fsp->fh->fd = -1;
65
66         fsp->fnum = FNUM_FIELD_INVALID;
67         fsp->conn = conn;
68         fsp->close_write_time = make_omit_timespec();
69
70         DLIST_ADD(sconn->files, fsp);
71         sconn->num_files += 1;
72
73         conn->num_files_open++;
74
75         *result = fsp;
76         return NT_STATUS_OK;
77
78 fail:
79         if (fsp != NULL) {
80                 TALLOC_FREE(fsp->fh);
81         }
82         TALLOC_FREE(fsp);
83
84         return status;
85 }
86
87 void fsp_set_gen_id(files_struct *fsp)
88 {
89         static uint64_t gen_id = 1;
90
91         /*
92          * A billion of 64-bit increments per second gives us
93          * more than 500 years of runtime without wrap.
94          */
95         fsp->fh->gen_id = gen_id++;
96 }
97
98 /****************************************************************************
99  Find first available file slot.
100 ****************************************************************************/
101
102 NTSTATUS fsp_bind_smb(struct files_struct *fsp, struct smb_request *req)
103 {
104         struct smbXsrv_open *op = NULL;
105         NTTIME now;
106         NTSTATUS status;
107
108         if (req == NULL) {
109                 DBG_DEBUG("INTERNAL_OPEN_ONLY, skipping smbXsrv_open\n");
110                 return NT_STATUS_OK;
111         }
112
113         now = timeval_to_nttime(&fsp->open_time);
114
115         status = smbXsrv_open_create(req->xconn,
116                                      fsp->conn->session_info,
117                                      now,
118                                      &op);
119         if (!NT_STATUS_IS_OK(status)) {
120                 return status;
121         }
122         fsp->op = op;
123         op->compat = fsp;
124         fsp->fnum = op->local_id;
125
126         fsp->mid = req->mid;
127         req->chain_fsp = fsp;
128
129         DBG_DEBUG("fsp [%s] mid [%" PRIu64"]\n",
130                 fsp_str_dbg(fsp), fsp->mid);
131
132         return NT_STATUS_OK;
133 }
134
135 NTSTATUS file_new(struct smb_request *req, connection_struct *conn,
136                   files_struct **result)
137 {
138         struct smbd_server_connection *sconn = conn->sconn;
139         files_struct *fsp;
140         NTSTATUS status;
141
142         status = fsp_new(conn, conn, &fsp);
143         if (!NT_STATUS_IS_OK(status)) {
144                 return status;
145         }
146
147         GetTimeOfDay(&fsp->open_time);
148
149         status = fsp_bind_smb(fsp, req);
150         if (!NT_STATUS_IS_OK(status)) {
151                 file_free(NULL, fsp);
152                 return status;
153         }
154
155         fsp_set_gen_id(fsp);
156
157         /*
158          * Create an smb_filename with "" for the base_name.  There are very
159          * few NULL checks, so make sure it's initialized with something. to
160          * be safe until an audit can be done.
161          */
162         fsp->fsp_name = synthetic_smb_fname(fsp,
163                                             "",
164                                             NULL,
165                                             NULL,
166                                             0,
167                                             0);
168         if (fsp->fsp_name == NULL) {
169                 file_free(NULL, fsp);
170                 return NT_STATUS_NO_MEMORY;
171         }
172
173         DEBUG(5,("allocated file structure %s (%u used)\n",
174                  fsp_fnum_dbg(fsp), (unsigned int)sconn->num_files));
175
176         /* A new fsp invalidates the positive and
177           negative fsp_fi_cache as the new fsp is pushed
178           at the start of the list and we search from
179           a cache hit to the *end* of the list. */
180
181         ZERO_STRUCT(sconn->fsp_fi_cache);
182
183         *result = fsp;
184         return NT_STATUS_OK;
185 }
186
187 /*
188  * Create an internal fsp for an *existing* directory.
189  *
190  * This should only be used by callers in the VFS that need to control the
191  * opening of the directory. Otherwise use open_internal_dirfsp_at().
192  */
193 NTSTATUS create_internal_dirfsp(connection_struct *conn,
194                                 const struct smb_filename *smb_dname,
195                                 struct files_struct **_fsp)
196 {
197         struct files_struct *fsp = NULL;
198         NTSTATUS status;
199
200         status = file_new(NULL, conn, &fsp);
201         if (!NT_STATUS_IS_OK(status)) {
202                 return status;
203         }
204
205         status = fsp_set_smb_fname(fsp, smb_dname);
206         if (!NT_STATUS_IS_OK(status)) {
207                 file_free(NULL, fsp);
208                 return status;
209         }
210
211         fsp->access_mask = FILE_LIST_DIRECTORY;
212         fsp->fsp_flags.is_directory = true;
213         fsp->fsp_flags.is_dirfsp = true;
214
215         *_fsp = fsp;
216         return NT_STATUS_OK;
217 }
218
219 /*
220  * Open an internal fsp for an *existing* directory.
221  */
222 NTSTATUS open_internal_dirfsp(connection_struct *conn,
223                               const struct smb_filename *smb_dname,
224                               int open_flags,
225                               struct files_struct **_fsp)
226 {
227         struct files_struct *fsp = NULL;
228         NTSTATUS status;
229         int ret;
230
231         status = create_internal_dirfsp(conn, smb_dname, &fsp);
232         if (!NT_STATUS_IS_OK(status)) {
233                 return status;
234         }
235
236 #ifdef O_DIRECTORY
237         open_flags |= O_DIRECTORY;
238 #endif
239         status = fd_open(fsp, open_flags, 0);
240         if (!NT_STATUS_IS_OK(status)) {
241                 DBG_INFO("Could not open fd for %s (%s)\n",
242                          smb_fname_str_dbg(smb_dname),
243                          nt_errstr(status));
244                 file_free(NULL, fsp);
245                 return status;
246         }
247
248         ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
249         if (ret != 0) {
250                 return map_nt_error_from_unix(errno);
251         }
252
253         if (!S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
254                 DBG_ERR("%s is not a directory!\n",
255                         smb_fname_str_dbg(smb_dname));
256                 file_free(NULL, fsp);
257                 return NT_STATUS_NOT_A_DIRECTORY;
258         }
259
260         fsp->file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
261
262         *_fsp = fsp;
263         return NT_STATUS_OK;
264 }
265
266 /****************************************************************************
267  Close all open files for a connection.
268 ****************************************************************************/
269
270 void file_close_conn(connection_struct *conn)
271 {
272         files_struct *fsp, *next;
273
274         for (fsp=conn->sconn->files; fsp; fsp=next) {
275                 next = fsp->next;
276                 if (fsp->conn != conn) {
277                         continue;
278                 }
279                 if (fsp->op != NULL && fsp->op->global->durable) {
280                         /*
281                          * A tree disconnect closes a durable handle
282                          */
283                         fsp->op->global->durable = false;
284                 }
285                 close_file(NULL, fsp, SHUTDOWN_CLOSE);
286         }
287 }
288
289 /****************************************************************************
290  Initialise file structures.
291 ****************************************************************************/
292
293 static int files_max_open_fds;
294
295 bool file_init_global(void)
296 {
297         int request_max = lp_max_open_files();
298         int real_lim;
299         int real_max;
300
301         if (files_max_open_fds != 0) {
302                 return true;
303         }
304
305         /*
306          * Set the max_open files to be the requested
307          * max plus a fudgefactor to allow for the extra
308          * fd's we need such as log files etc...
309          */
310         real_lim = set_maxfiles(request_max + MAX_OPEN_FUDGEFACTOR);
311
312         real_max = real_lim - MAX_OPEN_FUDGEFACTOR;
313
314         if (real_max + FILE_HANDLE_OFFSET + MAX_OPEN_PIPES > 65536) {
315                 real_max = 65536 - FILE_HANDLE_OFFSET - MAX_OPEN_PIPES;
316         }
317
318         if (real_max != request_max) {
319                 DEBUG(1, ("file_init_global: Information only: requested %d "
320                           "open files, %d are available.\n",
321                           request_max, real_max));
322         }
323
324         SMB_ASSERT(real_max > 100);
325
326         files_max_open_fds = real_max;
327         return true;
328 }
329
330 bool file_init(struct smbd_server_connection *sconn)
331 {
332         bool ok;
333
334         ok = file_init_global();
335         if (!ok) {
336                 return false;
337         }
338
339         sconn->real_max_open_files = files_max_open_fds;
340
341         return true;
342 }
343
344 /****************************************************************************
345  Close files open by a specified vuid.
346 ****************************************************************************/
347
348 void file_close_user(struct smbd_server_connection *sconn, uint64_t vuid)
349 {
350         files_struct *fsp, *next;
351
352         for (fsp=sconn->files; fsp; fsp=next) {
353                 next=fsp->next;
354                 if (fsp->vuid == vuid) {
355                         close_file(NULL, fsp, SHUTDOWN_CLOSE);
356                 }
357         }
358 }
359
360 /*
361  * Walk the files table until "fn" returns non-NULL
362  */
363
364 struct files_struct *files_forall(
365         struct smbd_server_connection *sconn,
366         struct files_struct *(*fn)(struct files_struct *fsp,
367                                    void *private_data),
368         void *private_data)
369 {
370         struct files_struct *fsp, *next;
371
372         for (fsp = sconn->files; fsp; fsp = next) {
373                 struct files_struct *ret;
374                 next = fsp->next;
375                 ret = fn(fsp, private_data);
376                 if (ret != NULL) {
377                         return ret;
378                 }
379         }
380         return NULL;
381 }
382
383 /****************************************************************************
384  Find a fsp given a file descriptor.
385 ****************************************************************************/
386
387 files_struct *file_find_fd(struct smbd_server_connection *sconn, int fd)
388 {
389         int count=0;
390         files_struct *fsp;
391
392         for (fsp=sconn->files; fsp; fsp=fsp->next,count++) {
393                 if (fsp->fh->fd == fd) {
394                         if (count > 10) {
395                                 DLIST_PROMOTE(sconn->files, fsp);
396                         }
397                         return fsp;
398                 }
399         }
400
401         return NULL;
402 }
403
404 /****************************************************************************
405  Find a fsp given a device, inode and file_id.
406 ****************************************************************************/
407
408 files_struct *file_find_dif(struct smbd_server_connection *sconn,
409                             struct file_id id, unsigned long gen_id)
410 {
411         int count=0;
412         files_struct *fsp;
413
414         if (gen_id == 0) {
415                 return NULL;
416         }
417
418         for (fsp=sconn->files; fsp; fsp=fsp->next,count++) {
419                 /* We can have a fsp->fh->fd == -1 here as it could be a stat open. */
420                 if (file_id_equal(&fsp->file_id, &id) &&
421                     fsp->fh->gen_id == gen_id ) {
422                         if (count > 10) {
423                                 DLIST_PROMOTE(sconn->files, fsp);
424                         }
425                         /* Paranoia check. */
426                         if ((fsp->fh->fd == -1) &&
427                             (fsp->oplock_type != NO_OPLOCK &&
428                              fsp->oplock_type != LEASE_OPLOCK)) {
429                                 struct file_id_buf idbuf;
430                                 DEBUG(0,("file_find_dif: file %s file_id = "
431                                          "%s, gen = %u oplock_type = %u is a "
432                                          "stat open with oplock type !\n",
433                                          fsp_str_dbg(fsp),
434                                          file_id_str_buf(fsp->file_id, &idbuf),
435                                          (unsigned int)fsp->fh->gen_id,
436                                          (unsigned int)fsp->oplock_type ));
437                                 smb_panic("file_find_dif");
438                         }
439                         return fsp;
440                 }
441         }
442
443         return NULL;
444 }
445
446 /****************************************************************************
447  Find the first fsp given a device and inode.
448  We use a singleton cache here to speed up searching from getfilepathinfo
449  calls.
450 ****************************************************************************/
451
452 files_struct *file_find_di_first(struct smbd_server_connection *sconn,
453                                  struct file_id id)
454 {
455         files_struct *fsp;
456
457         if (file_id_equal(&sconn->fsp_fi_cache.id, &id)) {
458                 /* Positive or negative cache hit. */
459                 return sconn->fsp_fi_cache.fsp;
460         }
461
462         sconn->fsp_fi_cache.id = id;
463
464         for (fsp=sconn->files;fsp;fsp=fsp->next) {
465                 if (file_id_equal(&fsp->file_id, &id)) {
466                         /* Setup positive cache. */
467                         sconn->fsp_fi_cache.fsp = fsp;
468                         return fsp;
469                 }
470         }
471
472         /* Setup negative cache. */
473         sconn->fsp_fi_cache.fsp = NULL;
474         return NULL;
475 }
476
477 /****************************************************************************
478  Find the next fsp having the same device and inode.
479 ****************************************************************************/
480
481 files_struct *file_find_di_next(files_struct *start_fsp)
482 {
483         files_struct *fsp;
484
485         for (fsp = start_fsp->next;fsp;fsp=fsp->next) {
486                 if (file_id_equal(&fsp->file_id, &start_fsp->file_id)) {
487                         return fsp;
488                 }
489         }
490
491         return NULL;
492 }
493
494 struct files_struct *file_find_one_fsp_from_lease_key(
495         struct smbd_server_connection *sconn,
496         const struct smb2_lease_key *lease_key)
497 {
498         struct files_struct *fsp;
499
500         for (fsp = sconn->files; fsp; fsp=fsp->next) {
501                 if ((fsp->lease != NULL) &&
502                     (fsp->lease->lease.lease_key.data[0] ==
503                      lease_key->data[0]) &&
504                     (fsp->lease->lease.lease_key.data[1] ==
505                      lease_key->data[1])) {
506                         return fsp;
507                 }
508         }
509         return NULL;
510 }
511
512 /****************************************************************************
513  Find any fsp open with a pathname below that of an already open path.
514 ****************************************************************************/
515
516 bool file_find_subpath(files_struct *dir_fsp)
517 {
518         files_struct *fsp;
519         size_t dlen;
520         char *d_fullname = NULL;
521
522         d_fullname = talloc_asprintf(talloc_tos(), "%s/%s",
523                                      dir_fsp->conn->connectpath,
524                                      dir_fsp->fsp_name->base_name);
525
526         if (!d_fullname) {
527                 return false;
528         }
529
530         dlen = strlen(d_fullname);
531
532         for (fsp=dir_fsp->conn->sconn->files; fsp; fsp=fsp->next) {
533                 char *d1_fullname;
534
535                 if (fsp == dir_fsp) {
536                         continue;
537                 }
538
539                 d1_fullname = talloc_asprintf(talloc_tos(),
540                                         "%s/%s",
541                                         fsp->conn->connectpath,
542                                         fsp->fsp_name->base_name);
543
544                 /*
545                  * If the open file has a path that is a longer
546                  * component, then it's a subpath.
547                  */
548                 if (strnequal(d_fullname, d1_fullname, dlen) &&
549                                 (d1_fullname[dlen] == '/')) {
550                         TALLOC_FREE(d1_fullname);
551                         TALLOC_FREE(d_fullname);
552                         return true;
553                 }
554                 TALLOC_FREE(d1_fullname);
555         }
556
557         TALLOC_FREE(d_fullname);
558         return false;
559 }
560
561 /****************************************************************************
562  Free up a fsp.
563 ****************************************************************************/
564
565 void fsp_free(files_struct *fsp)
566 {
567         struct smbd_server_connection *sconn = fsp->conn->sconn;
568
569         if (fsp == sconn->fsp_fi_cache.fsp) {
570                 ZERO_STRUCT(sconn->fsp_fi_cache);
571         }
572
573         DLIST_REMOVE(sconn->files, fsp);
574         SMB_ASSERT(sconn->num_files > 0);
575         sconn->num_files--;
576
577         TALLOC_FREE(fsp->fake_file_handle);
578
579         if (fsp->fh->ref_count == 1) {
580                 TALLOC_FREE(fsp->fh);
581         } else {
582                 fsp->fh->ref_count--;
583         }
584
585         if (fsp->lease != NULL) {
586                 if (fsp->lease->ref_count == 1) {
587                         TALLOC_FREE(fsp->lease);
588                 } else {
589                         fsp->lease->ref_count--;
590                 }
591         }
592
593         fsp->conn->num_files_open--;
594
595         /* this is paranoia, just in case someone tries to reuse the
596            information */
597         ZERO_STRUCTP(fsp);
598
599         /* fsp->fsp_name is a talloc child and is free'd automatically. */
600         TALLOC_FREE(fsp);
601 }
602
603 void file_free(struct smb_request *req, files_struct *fsp)
604 {
605         struct smbd_server_connection *sconn = fsp->conn->sconn;
606         uint64_t fnum = fsp->fnum;
607
608         if (fsp == fsp->conn->cwd_fsp) {
609                 return;
610         }
611
612         if (fsp->notify) {
613                 size_t len = fsp_fullbasepath(fsp, NULL, 0);
614                 char fullpath[len+1];
615
616                 fsp_fullbasepath(fsp, fullpath, sizeof(fullpath));
617
618                 /*
619                  * Avoid /. at the end of the path name. notify can't
620                  * deal with it.
621                  */
622                 if (len > 1 && fullpath[len-1] == '.' &&
623                     fullpath[len-2] == '/') {
624                         fullpath[len-2] = '\0';
625                 }
626
627                 notify_remove(fsp->conn->sconn->notify_ctx, fsp, fullpath);
628                 TALLOC_FREE(fsp->notify);
629         }
630
631         /* Ensure this event will never fire. */
632         TALLOC_FREE(fsp->update_write_time_event);
633
634         if (fsp->op != NULL) {
635                 fsp->op->compat = NULL;
636         }
637         TALLOC_FREE(fsp->op);
638
639         if ((req != NULL) && (fsp == req->chain_fsp)) {
640                 req->chain_fsp = NULL;
641         }
642
643         /*
644          * Clear all possible chained fsp
645          * pointers in the SMB2 request queue.
646          */
647         remove_smb2_chained_fsp(fsp);
648
649         /* Drop all remaining extensions. */
650         vfs_remove_all_fsp_extensions(fsp);
651
652         fsp_free(fsp);
653
654         DEBUG(5,("freed files structure %llu (%u used)\n",
655                  (unsigned long long)fnum, (unsigned int)sconn->num_files));
656 }
657
658 /****************************************************************************
659  Get an fsp from a packet given a 16 bit fnum.
660 ****************************************************************************/
661
662 files_struct *file_fsp(struct smb_request *req, uint16_t fid)
663 {
664         struct smbXsrv_open *op;
665         NTSTATUS status;
666         NTTIME now = 0;
667         files_struct *fsp;
668
669         if (req == NULL) {
670                 /*
671                  * We should never get here. req==NULL could in theory
672                  * only happen from internal opens with a non-zero
673                  * root_dir_fid. Internal opens just don't do that, at
674                  * least they are not supposed to do so. And if they
675                  * start to do so, they better fake up a smb_request
676                  * from which we get the right smbd_server_conn. While
677                  * this should never happen, let's return NULL here.
678                  */
679                 return NULL;
680         }
681
682         if (req->chain_fsp != NULL) {
683                 if (req->chain_fsp->fsp_flags.closing) {
684                         return NULL;
685                 }
686                 return req->chain_fsp;
687         }
688
689         if (req->xconn == NULL) {
690                 return NULL;
691         }
692
693         now = timeval_to_nttime(&req->request_time);
694
695         status = smb1srv_open_lookup(req->xconn,
696                                      fid, now, &op);
697         if (!NT_STATUS_IS_OK(status)) {
698                 return NULL;
699         }
700
701         fsp = op->compat;
702         if (fsp == NULL) {
703                 return NULL;
704         }
705
706         if (fsp->fsp_flags.closing) {
707                 return NULL;
708         }
709
710         req->chain_fsp = fsp;
711         return fsp;
712 }
713
714 struct files_struct *file_fsp_get(struct smbd_smb2_request *smb2req,
715                                   uint64_t persistent_id,
716                                   uint64_t volatile_id)
717 {
718         struct smbXsrv_open *op;
719         NTSTATUS status;
720         NTTIME now = 0;
721         struct files_struct *fsp;
722
723         now = timeval_to_nttime(&smb2req->request_time);
724
725         status = smb2srv_open_lookup(smb2req->xconn,
726                                      persistent_id, volatile_id,
727                                      now, &op);
728         if (!NT_STATUS_IS_OK(status)) {
729                 return NULL;
730         }
731
732         fsp = op->compat;
733         if (fsp == NULL) {
734                 return NULL;
735         }
736
737         if (smb2req->tcon == NULL) {
738                 return NULL;
739         }
740
741         if (smb2req->tcon->compat != fsp->conn) {
742                 return NULL;
743         }
744
745         if (smb2req->session == NULL) {
746                 return NULL;
747         }
748
749         if (smb2req->session->global->session_wire_id != fsp->vuid) {
750                 return NULL;
751         }
752
753         if (fsp->fsp_flags.closing) {
754                 return NULL;
755         }
756
757         return fsp;
758 }
759
760 struct files_struct *file_fsp_smb2(struct smbd_smb2_request *smb2req,
761                                    uint64_t persistent_id,
762                                    uint64_t volatile_id)
763 {
764         struct files_struct *fsp;
765
766         if (smb2req->compat_chain_fsp != NULL) {
767                 if (smb2req->compat_chain_fsp->fsp_flags.closing) {
768                         return NULL;
769                 }
770                 return smb2req->compat_chain_fsp;
771         }
772
773         fsp = file_fsp_get(smb2req, persistent_id, volatile_id);
774         if (fsp == NULL) {
775                 return NULL;
776         }
777
778         smb2req->compat_chain_fsp = fsp;
779         return fsp;
780 }
781
782 /****************************************************************************
783  Duplicate the file handle part for a DOS or FCB open.
784 ****************************************************************************/
785
786 NTSTATUS dup_file_fsp(
787         struct smb_request *req,
788         files_struct *from,
789         uint32_t access_mask,
790         uint32_t create_options,
791         files_struct *to)
792 {
793         /* this can never happen for print files */
794         SMB_ASSERT(from->print_file == NULL);
795
796         TALLOC_FREE(to->fh);
797
798         to->fh = from->fh;
799         to->fh->ref_count++;
800
801         to->file_id = from->file_id;
802         to->initial_allocation_size = from->initial_allocation_size;
803         to->file_pid = from->file_pid;
804         to->vuid = from->vuid;
805         to->open_time = from->open_time;
806         to->access_mask = access_mask;
807         to->oplock_type = from->oplock_type;
808         to->fsp_flags.can_lock = from->fsp_flags.can_lock;
809         to->fsp_flags.can_read = ((access_mask & FILE_READ_DATA) != 0);
810         to->fsp_flags.can_write =
811                 CAN_WRITE(from->conn) &&
812                 ((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0);
813         to->fsp_flags.modified = from->fsp_flags.modified;
814         to->fsp_flags.is_directory = from->fsp_flags.is_directory;
815         to->fsp_flags.aio_write_behind = from->fsp_flags.aio_write_behind;
816
817         return fsp_set_smb_fname(to, from->fsp_name);
818 }
819
820 /**
821  * Return a jenkins hash of a pathname on a connection.
822  */
823
824 NTSTATUS file_name_hash(connection_struct *conn,
825                         const char *name, uint32_t *p_name_hash)
826 {
827         char tmpbuf[PATH_MAX];
828         char *fullpath, *to_free;
829         ssize_t len;
830         TDB_DATA key;
831
832         /* Set the hash of the full pathname. */
833
834         len = full_path_tos(conn->connectpath, name, tmpbuf, sizeof(tmpbuf),
835                             &fullpath, &to_free);
836         if (len == -1) {
837                 return NT_STATUS_NO_MEMORY;
838         }
839         key = (TDB_DATA) { .dptr = (uint8_t *)fullpath, .dsize = len+1 };
840         *p_name_hash = tdb_jenkins_hash(&key);
841
842         DEBUG(10,("file_name_hash: %s hash 0x%x\n",
843                   fullpath,
844                 (unsigned int)*p_name_hash ));
845
846         TALLOC_FREE(to_free);
847         return NT_STATUS_OK;
848 }
849
850 /**
851  * The only way that the fsp->fsp_name field should ever be set.
852  */
853 NTSTATUS fsp_set_smb_fname(struct files_struct *fsp,
854                            const struct smb_filename *smb_fname_in)
855 {
856         struct smb_filename *smb_fname_new;
857
858         smb_fname_new = cp_smb_filename(fsp, smb_fname_in);
859         if (smb_fname_new == NULL) {
860                 return NT_STATUS_NO_MEMORY;
861         }
862
863         TALLOC_FREE(fsp->fsp_name);
864         fsp->fsp_name = smb_fname_new;
865
866         return file_name_hash(fsp->conn,
867                         smb_fname_str_dbg(fsp->fsp_name),
868                         &fsp->name_hash);
869 }
870
871 size_t fsp_fullbasepath(struct files_struct *fsp, char *buf, size_t buflen)
872 {
873         int len = 0;
874         char tmp_buf[1] = {'\0'};
875
876         /*
877          * Don't pass NULL buffer to snprintf (to satisfy static checker)
878          * Some callers will call this function with NULL for buf and
879          * 0 for buflen in order to get length of fullbasepatch (without
880          * needing to allocate or write to buf)
881          */
882         if (buf == NULL) {
883                 buf = tmp_buf;
884         }
885
886         len = snprintf(buf, buflen, "%s/%s", fsp->conn->connectpath,
887                        fsp->fsp_name->base_name);
888         SMB_ASSERT(len>0);
889
890         return len;
891 }