Ensure we don't prematurely clean out the bytes read.
[samba.git] / source3 / smbd / vfs.c
1 /*
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    VFS initialisation and support functions
5    Copyright (C) Tim Potter 1999
6    Copyright (C) Alexander Bokovoy 2002
7    Copyright (C) James Peach 2006
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
22    This work was sponsored by Optifacio Software Services, Inc.
23 */
24
25 #include "includes.h"
26
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_VFS
29
30 static_decl_vfs;
31
32 struct vfs_init_function_entry {
33         char *name;
34         vfs_op_tuple *vfs_op_tuples;
35         struct vfs_init_function_entry *prev, *next;
36 };
37
38 static struct vfs_init_function_entry *backends = NULL;
39
40 /****************************************************************************
41     maintain the list of available backends
42 ****************************************************************************/
43
44 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
45 {
46         struct vfs_init_function_entry *entry = backends;
47
48         DEBUG(10, ("vfs_find_backend_entry called for %s\n", name));
49  
50         while(entry) {
51                 if (strcmp(entry->name, name)==0) return entry;
52                 entry = entry->next;
53         }
54
55         return NULL;
56 }
57
58 NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples)
59 {
60         struct vfs_init_function_entry *entry = backends;
61
62         if ((version != SMB_VFS_INTERFACE_VERSION)) {
63                 DEBUG(0, ("Failed to register vfs module.\n"
64                           "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
65                           "current SMB_VFS_INTERFACE_VERSION is %d.\n"
66                           "Please recompile against the current Samba Version!\n",  
67                           version, SMB_VFS_INTERFACE_VERSION));
68                 return NT_STATUS_OBJECT_TYPE_MISMATCH;
69         }
70
71         if (!name || !name[0] || !vfs_op_tuples) {
72                 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
73                 return NT_STATUS_INVALID_PARAMETER;
74         }
75
76         if (vfs_find_backend_entry(name)) {
77                 DEBUG(0,("VFS module %s already loaded!\n", name));
78                 return NT_STATUS_OBJECT_NAME_COLLISION;
79         }
80
81         entry = SMB_XMALLOC_P(struct vfs_init_function_entry);
82         entry->name = smb_xstrdup(name);
83         entry->vfs_op_tuples = vfs_op_tuples;
84
85         DLIST_ADD(backends, entry);
86         DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
87         return NT_STATUS_OK;
88 }
89
90 /****************************************************************************
91   initialise default vfs hooks
92 ****************************************************************************/
93
94 static void vfs_init_default(connection_struct *conn)
95 {
96         DEBUG(3, ("Initialising default vfs hooks\n"));
97         vfs_init_custom(conn, DEFAULT_VFS_MODULE_NAME);
98 }
99
100 /****************************************************************************
101   initialise custom vfs hooks
102  ****************************************************************************/
103
104 static inline void vfs_set_operation(struct vfs_ops * vfs, vfs_op_type which,
105                                 struct vfs_handle_struct * handle, void * op)
106 {
107         ((struct vfs_handle_struct **)&vfs->handles)[which] = handle;
108         ((void **)(void *)&vfs->ops)[which] = op;
109 }
110
111 bool vfs_init_custom(connection_struct *conn, const char *vfs_object)
112 {
113         vfs_op_tuple *ops;
114         char *module_path = NULL;
115         char *module_name = NULL;
116         char *module_param = NULL, *p;
117         int i;
118         vfs_handle_struct *handle;
119         struct vfs_init_function_entry *entry;
120         
121         if (!conn||!vfs_object||!vfs_object[0]) {
122                 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
123                 return False;
124         }
125
126         if(!backends) {
127                 static_init_vfs;
128         }
129
130         DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
131
132         module_path = smb_xstrdup(vfs_object);
133
134         p = strchr_m(module_path, ':');
135
136         if (p) {
137                 *p = 0;
138                 module_param = p+1;
139                 trim_char(module_param, ' ', ' ');
140         }
141
142         trim_char(module_path, ' ', ' ');
143
144         module_name = smb_xstrdup(module_path);
145
146         if ((module_name[0] == '/') &&
147             (strcmp(module_path, DEFAULT_VFS_MODULE_NAME) != 0)) {
148
149                 /*
150                  * Extract the module name from the path. Just use the base
151                  * name of the last path component.
152                  */
153
154                 SAFE_FREE(module_name);
155                 module_name = smb_xstrdup(strrchr_m(module_path, '/')+1);
156
157                 p = strchr_m(module_name, '.');
158
159                 if (p != NULL) {
160                         *p = '\0';
161                 }
162         }
163
164         /* First, try to load the module with the new module system */
165         if((entry = vfs_find_backend_entry(module_name)) || 
166            (NT_STATUS_IS_OK(smb_probe_module("vfs", module_path)) &&
167                 (entry = vfs_find_backend_entry(module_name)))) {
168
169                 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
170                 
171                 if ((ops = entry->vfs_op_tuples) == NULL) {
172                         DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
173                         goto fail;
174                 }
175         } else {
176                 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
177                 goto fail;
178         }
179
180         handle = TALLOC_ZERO_P(conn->mem_ctx,vfs_handle_struct);
181         if (!handle) {
182                 DEBUG(0,("TALLOC_ZERO() failed!\n"));
183                 goto fail;
184         }
185         memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
186         handle->conn = conn;
187         if (module_param) {
188                 handle->param = talloc_strdup(conn->mem_ctx, module_param);
189         }
190         DLIST_ADD(conn->vfs_handles, handle);
191
192         for(i=0; ops[i].op != NULL; i++) {
193                 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
194                 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
195                         /* If this operation was already made opaque by different module, it
196                          * will be overridden here.
197                          */
198                         DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
199                         vfs_set_operation(&conn->vfs_opaque, ops[i].type, handle, ops[i].op);
200                 }
201                 /* Change current VFS disposition*/
202                 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
203                 vfs_set_operation(&conn->vfs, ops[i].type, handle, ops[i].op);
204         }
205
206         SAFE_FREE(module_path);
207         SAFE_FREE(module_name);
208         return True;
209
210  fail:
211         SAFE_FREE(module_path);
212         SAFE_FREE(module_name);
213         return False;
214 }
215
216 /*****************************************************************
217  Allow VFS modules to extend files_struct with VFS-specific state.
218  This will be ok for small numbers of extensions, but might need to
219  be refactored if it becomes more widely used.
220 ******************************************************************/
221
222 #define EXT_DATA_AREA(e) ((uint8 *)(e) + sizeof(struct vfs_fsp_data))
223
224 void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle, files_struct *fsp, size_t ext_size)
225 {
226         struct vfs_fsp_data *ext;
227         void * ext_data;
228
229         /* Prevent VFS modules adding multiple extensions. */
230         if ((ext_data = vfs_fetch_fsp_extension(handle, fsp))) {
231                 return ext_data;
232         }
233
234         ext = (struct vfs_fsp_data *)TALLOC_ZERO(
235                 handle->conn->mem_ctx, sizeof(struct vfs_fsp_data) + ext_size);
236         if (ext == NULL) {
237                 return NULL;
238         }
239
240         ext->owner = handle;
241         ext->next = fsp->vfs_extension;
242         fsp->vfs_extension = ext;
243         return EXT_DATA_AREA(ext);
244 }
245
246 void vfs_remove_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
247 {
248         struct vfs_fsp_data *curr;
249         struct vfs_fsp_data *prev;
250
251         for (curr = fsp->vfs_extension, prev = NULL;
252              curr;
253              prev = curr, curr = curr->next) {
254                 if (curr->owner == handle) {
255                     if (prev) {
256                             prev->next = curr->next;
257                     } else {
258                             fsp->vfs_extension = curr->next;
259                     }
260                     TALLOC_FREE(curr);
261                     return;
262                 }
263         }
264 }
265
266 void *vfs_fetch_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
267 {
268         struct vfs_fsp_data *head;
269
270         for (head = fsp->vfs_extension; head; head = head->next) {
271                 if (head->owner == handle) {
272                         return EXT_DATA_AREA(head);
273                 }
274         }
275
276         return NULL;
277 }
278
279 #undef EXT_DATA_AREA
280
281 /*****************************************************************
282  Generic VFS init.
283 ******************************************************************/
284
285 bool smbd_vfs_init(connection_struct *conn)
286 {
287         const char **vfs_objects;
288         unsigned int i = 0;
289         int j = 0;
290         
291         /* Normal share - initialise with disk access functions */
292         vfs_init_default(conn);
293         vfs_objects = lp_vfs_objects(SNUM(conn));
294
295         /* Override VFS functions if 'vfs object' was not specified*/
296         if (!vfs_objects || !vfs_objects[0])
297                 return True;
298         
299         for (i=0; vfs_objects[i] ;) {
300                 i++;
301         }
302
303         for (j=i-1; j >= 0; j--) {
304                 if (!vfs_init_custom(conn, vfs_objects[j])) {
305                         DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
306                         return False;
307                 }
308         }
309         return True;
310 }
311
312 /*******************************************************************
313  Check if directory exists.
314 ********************************************************************/
315
316 bool vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
317 {
318         SMB_STRUCT_STAT st2;
319         bool ret;
320
321         if (!st)
322                 st = &st2;
323
324         if (SMB_VFS_STAT(conn,dname,st) != 0)
325                 return(False);
326
327         ret = S_ISDIR(st->st_mode);
328         if(!ret)
329                 errno = ENOTDIR;
330
331         return ret;
332 }
333
334 /*******************************************************************
335  Check if an object exists in the vfs.
336 ********************************************************************/
337
338 bool vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
339 {
340         SMB_STRUCT_STAT st;
341
342         if (!sbuf)
343                 sbuf = &st;
344
345         ZERO_STRUCTP(sbuf);
346
347         if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
348                 return(False);
349         return True;
350 }
351
352 /*******************************************************************
353  Check if a file exists in the vfs.
354 ********************************************************************/
355
356 bool vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
357 {
358         SMB_STRUCT_STAT st;
359
360         if (!sbuf)
361                 sbuf = &st;
362
363         ZERO_STRUCTP(sbuf);
364
365         if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
366                 return False;
367         return(S_ISREG(sbuf->st_mode));
368 }
369
370 /****************************************************************************
371  Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
372 ****************************************************************************/
373
374 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
375 {
376         size_t total=0;
377
378         while (total < byte_count)
379         {
380                 ssize_t ret = SMB_VFS_READ(fsp, fsp->fh->fd, buf + total,
381                                         byte_count - total);
382
383                 if (ret == 0) return total;
384                 if (ret == -1) {
385                         if (errno == EINTR)
386                                 continue;
387                         else
388                                 return -1;
389                 }
390                 total += ret;
391         }
392         return (ssize_t)total;
393 }
394
395 ssize_t vfs_pread_data(files_struct *fsp, char *buf,
396                 size_t byte_count, SMB_OFF_T offset)
397 {
398         size_t total=0;
399
400         while (total < byte_count)
401         {
402                 ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fh->fd, buf + total,
403                                         byte_count - total, offset + total);
404
405                 if (ret == 0) return total;
406                 if (ret == -1) {
407                         if (errno == EINTR)
408                                 continue;
409                         else
410                                 return -1;
411                 }
412                 total += ret;
413         }
414         return (ssize_t)total;
415 }
416
417 /****************************************************************************
418  Write data to a fd on the vfs.
419 ****************************************************************************/
420
421 ssize_t vfs_write_data(struct smb_request *req,
422                         files_struct *fsp,
423                         const char *buffer,
424                         size_t N)
425 {
426         size_t total=0;
427         ssize_t ret;
428
429         if (req && req->unread_bytes) {
430                 SMB_ASSERT(req->unread_bytes == N);
431                 ret = SMB_VFS_RECVFILE(smbd_server_fd(),
432                                         fsp,
433                                         fsp->fh->fd,
434                                         (SMB_OFF_T)-1,
435                                         N);
436                 if (ret != -1) {
437                         req->unread_bytes = 0;
438                 }
439                 return ret;
440         }
441
442         while (total < N) {
443                 ret = SMB_VFS_WRITE(fsp,fsp->fh->fd,buffer + total,N - total);
444
445                 if (ret == -1)
446                         return -1;
447                 if (ret == 0)
448                         return total;
449
450                 total += ret;
451         }
452         return (ssize_t)total;
453 }
454
455 ssize_t vfs_pwrite_data(struct smb_request *req,
456                         files_struct *fsp,
457                         const char *buffer,
458                         size_t N,
459                         SMB_OFF_T offset)
460 {
461         size_t total=0;
462         ssize_t ret;
463
464         if (req && req->unread_bytes) {
465                 SMB_ASSERT(req->unread_bytes == N);
466                 ret = SMB_VFS_RECVFILE(smbd_server_fd(),
467                                         fsp,
468                                         fsp->fh->fd,
469                                         offset,
470                                         N);
471                 if (ret != -1) {
472                         req->unread_bytes = 0;
473                 }
474                 return ret;
475         }
476
477         while (total < N) {
478                 ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, buffer + total,
479                                 N - total, offset + total);
480
481                 if (ret == -1)
482                         return -1;
483                 if (ret == 0)
484                         return total;
485
486                 total += ret;
487         }
488         return (ssize_t)total;
489 }
490 /****************************************************************************
491  An allocate file space call using the vfs interface.
492  Allocates space for a file from a filedescriptor.
493  Returns 0 on success, -1 on failure.
494 ****************************************************************************/
495
496 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
497 {
498         int ret;
499         SMB_STRUCT_STAT st;
500         connection_struct *conn = fsp->conn;
501         SMB_BIG_UINT space_avail;
502         SMB_BIG_UINT bsize,dfree,dsize;
503
504         release_level_2_oplocks_on_change(fsp);
505
506         /*
507          * Actually try and commit the space on disk....
508          */
509
510         DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
511
512         if (((SMB_OFF_T)len) < 0) {
513                 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
514                 errno = EINVAL;
515                 return -1;
516         }
517
518         ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
519         if (ret == -1)
520                 return ret;
521
522         if (len == (SMB_BIG_UINT)st.st_size)
523                 return 0;
524
525         if (len < (SMB_BIG_UINT)st.st_size) {
526                 /* Shrink - use ftruncate. */
527
528                 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
529                                 fsp->fsp_name, (double)st.st_size ));
530
531                 flush_write_cache(fsp, SIZECHANGE_FLUSH);
532                 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, (SMB_OFF_T)len)) != -1) {
533                         set_filelen_write_cache(fsp, len);
534                 }
535                 return ret;
536         }
537
538         /* Grow - we need to test if we have enough space. */
539
540         if (!lp_strict_allocate(SNUM(fsp->conn)))
541                 return 0;
542
543         len -= st.st_size;
544         len /= 1024; /* Len is now number of 1k blocks needed. */
545         space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
546         if (space_avail == (SMB_BIG_UINT)-1) {
547                 return -1;
548         }
549
550         DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
551                         fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
552
553         if (len > space_avail) {
554                 errno = ENOSPC;
555                 return -1;
556         }
557
558         return 0;
559 }
560
561 /****************************************************************************
562  A vfs set_filelen call.
563  set the length of a file from a filedescriptor.
564  Returns 0 on success, -1 on failure.
565 ****************************************************************************/
566
567 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
568 {
569         int ret;
570
571         release_level_2_oplocks_on_change(fsp);
572         DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
573         flush_write_cache(fsp, SIZECHANGE_FLUSH);
574         if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1) {
575                 set_filelen_write_cache(fsp, len);
576                 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
577                              FILE_NOTIFY_CHANGE_SIZE
578                              | FILE_NOTIFY_CHANGE_ATTRIBUTES,
579                              fsp->fsp_name);
580         }
581
582         return ret;
583 }
584
585 /****************************************************************************
586  A vfs fill sparse call.
587  Writes zeros from the end of file to len, if len is greater than EOF.
588  Used only by strict_sync.
589  Returns 0 on success, -1 on failure.
590 ****************************************************************************/
591
592 static char *sparse_buf;
593 #define SPARSE_BUF_WRITE_SIZE (32*1024)
594
595 int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
596 {
597         int ret;
598         SMB_STRUCT_STAT st;
599         SMB_OFF_T offset;
600         size_t total;
601         size_t num_to_write;
602         ssize_t pwrite_ret;
603
604         release_level_2_oplocks_on_change(fsp);
605         ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
606         if (ret == -1) {
607                 return ret;
608         }
609
610         if (len <= st.st_size) {
611                 return 0;
612         }
613
614         DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
615                 fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
616
617         flush_write_cache(fsp, SIZECHANGE_FLUSH);
618
619         if (!sparse_buf) {
620                 sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
621                 if (!sparse_buf) {
622                         errno = ENOMEM;
623                         return -1;
624                 }
625         }
626
627         offset = st.st_size;
628         num_to_write = len - st.st_size;
629         total = 0;
630
631         while (total < num_to_write) {
632                 size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
633
634                 pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, sparse_buf, curr_write_size, offset + total);
635                 if (pwrite_ret == -1) {
636                         DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
637                                 fsp->fsp_name, strerror(errno) ));
638                         return -1;
639                 }
640                 if (pwrite_ret == 0) {
641                         return 0;
642                 }
643
644                 total += pwrite_ret;
645         }
646
647         set_filelen_write_cache(fsp, len);
648         return 0;
649 }
650
651 /****************************************************************************
652  Transfer some data (n bytes) between two file_struct's.
653 ****************************************************************************/
654
655 static files_struct *in_fsp;
656 static files_struct *out_fsp;
657
658 static ssize_t read_fn(int fd, void *buf, size_t len)
659 {
660         return SMB_VFS_READ(in_fsp, fd, buf, len);
661 }
662
663 static ssize_t write_fn(int fd, const void *buf, size_t len)
664 {
665         return SMB_VFS_WRITE(out_fsp, fd, buf, len);
666 }
667
668 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
669 {
670         in_fsp = in;
671         out_fsp = out;
672
673         return transfer_file_internal(in_fsp->fh->fd, out_fsp->fh->fd, n, read_fn, write_fn);
674 }
675
676 /*******************************************************************
677  A vfs_readdir wrapper which just returns the file name.
678 ********************************************************************/
679
680 char *vfs_readdirname(connection_struct *conn, void *p)
681 {
682         SMB_STRUCT_DIRENT *ptr= NULL;
683         char *dname;
684
685         if (!p)
686                 return(NULL);
687
688         ptr = SMB_VFS_READDIR(conn, (DIR *)p);
689         if (!ptr)
690                 return(NULL);
691
692         dname = ptr->d_name;
693
694 #ifdef NEXT2
695         if (telldir(p) < 0)
696                 return(NULL);
697 #endif
698
699 #ifdef HAVE_BROKEN_READDIR_NAME
700         /* using /usr/ucb/cc is BAD */
701         dname = dname - 2;
702 #endif
703
704         return(dname);
705 }
706
707 /*******************************************************************
708  A wrapper for vfs_chdir().
709 ********************************************************************/
710
711 int vfs_ChDir(connection_struct *conn, const char *path)
712 {
713         int res;
714         static char *LastDir = NULL;
715
716         if (!LastDir) {
717                 LastDir = SMB_STRDUP("");
718         }
719
720         if (strcsequal(path,"."))
721                 return(0);
722
723         if (*path == '/' && strcsequal(LastDir,path))
724                 return(0);
725
726         DEBUG(4,("vfs_ChDir to %s\n",path));
727
728         res = SMB_VFS_CHDIR(conn,path);
729         if (!res) {
730                 SAFE_FREE(LastDir);
731                 LastDir = SMB_STRDUP(path);
732         }
733         return(res);
734 }
735
736 /* number of list structures for a caching GetWd function. */
737 #define MAX_GETWDCACHE (50)
738
739 static struct {
740         SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
741         SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
742         char *path; /* The pathname. */
743         bool valid;
744 } ino_list[MAX_GETWDCACHE];
745
746 extern bool use_getwd_cache;
747
748 /****************************************************************************
749  Prompte a ptr (to make it recently used)
750 ****************************************************************************/
751
752 static void array_promote(char *array,int elsize,int element)
753 {
754         char *p;
755         if (element == 0)
756                 return;
757
758         p = (char *)SMB_MALLOC(elsize);
759
760         if (!p) {
761                 DEBUG(5,("array_promote: malloc fail\n"));
762                 return;
763         }
764
765         memcpy(p,array + element * elsize, elsize);
766         memmove(array + elsize,array,elsize*element);
767         memcpy(array,p,elsize);
768         SAFE_FREE(p);
769 }
770
771 /*******************************************************************
772  Return the absolute current directory path - given a UNIX pathname.
773  Note that this path is returned in DOS format, not UNIX
774  format. Note this can be called with conn == NULL.
775 ********************************************************************/
776
777 char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn)
778 {
779 #ifdef PATH_MAX
780         char s[PATH_MAX+1];
781 #else
782         pstring s;
783 #endif
784         static bool getwd_cache_init = False;
785         SMB_STRUCT_STAT st, st2;
786         int i;
787         char *ret = NULL;
788
789         *s = 0;
790
791         if (!use_getwd_cache) {
792  nocache:
793                 ret = SMB_VFS_GETWD(conn,s);
794                 if (!ret) {
795                         DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, "
796                                 "errno %s\n",strerror(errno)));
797                         return NULL;
798                 }
799                 return talloc_strdup(ctx, ret);
800         }
801
802         /* init the cache */
803         if (!getwd_cache_init) {
804                 getwd_cache_init = True;
805                 for (i=0;i<MAX_GETWDCACHE;i++) {
806                         string_set(&ino_list[i].path,"");
807                         ino_list[i].valid = False;
808                 }
809         }
810
811         /*  Get the inode of the current directory, if this doesn't work we're
812                 in trouble :-) */
813
814         if (SMB_VFS_STAT(conn, ".",&st) == -1) {
815                 /* Known to fail for root: the directory may be
816                  * NFS-mounted and exported with root_squash (so has no root access). */
817                 DEBUG(1,("vfs_GetWd: couldn't stat \".\" error %s "
818                         "(NFS problem ?)\n",
819                         strerror(errno) ));
820                 goto nocache;
821         }
822
823
824         for (i=0; i<MAX_GETWDCACHE; i++) {
825                 if (ino_list[i].valid) {
826
827                         /*  If we have found an entry with a matching inode and dev number
828                                 then find the inode number for the directory in the cached string.
829                                 If this agrees with that returned by the stat for the current
830                                 directory then all is o.k. (but make sure it is a directory all
831                                 the same...) */
832
833                         if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
834                                 if (SMB_VFS_STAT(conn,ino_list[i].path,&st2) == 0) {
835                                         if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
836                                                         (st2.st_mode & S_IFMT) == S_IFDIR) {
837
838                                                 ret = talloc_strdup(ctx,
839                                                         ino_list[i].path);
840
841                                                 /* promote it for future use */
842                                                 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
843                                                 if (ret == NULL) {
844                                                         errno = ENOMEM;
845                                                 }
846                                                 return ret;
847                                         } else {
848                                                 /*  If the inode is different then something's changed,
849                                                         scrub the entry and start from scratch. */
850                                                 ino_list[i].valid = False;
851                                         }
852                                 }
853                         }
854                 }
855         }
856
857         /*  We don't have the information to hand so rely on traditional
858          *  methods. The very slow getcwd, which spawns a process on some
859          *  systems, or the not quite so bad getwd. */
860
861         if (!SMB_VFS_GETWD(conn,s)) {
862                 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",
863                                 strerror(errno)));
864                 return (NULL);
865         }
866
867         ret = talloc_strdup(ctx,s);
868
869         DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",
870                                 s,(double)st.st_ino,(double)st.st_dev));
871
872         /* add it to the cache */
873         i = MAX_GETWDCACHE - 1;
874         string_set(&ino_list[i].path,s);
875         ino_list[i].dev = st.st_dev;
876         ino_list[i].inode = st.st_ino;
877         ino_list[i].valid = True;
878
879         /* put it at the top of the list */
880         array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
881
882         if (ret == NULL) {
883                 errno = ENOMEM;
884         }
885         return ret;
886 }
887
888 /*******************************************************************
889  Reduce a file name, removing .. elements and checking that
890  it is below dir in the heirachy. This uses realpath.
891 ********************************************************************/
892
893 NTSTATUS check_reduced_name(connection_struct *conn, const char *fname)
894 {
895 #ifdef REALPATH_TAKES_NULL
896         bool free_resolved_name = True;
897 #else
898 #ifdef PATH_MAX
899         char resolved_name_buf[PATH_MAX+1];
900 #else
901         pstring resolved_name_buf;
902 #endif
903         bool free_resolved_name = False;
904 #endif
905         char *resolved_name = NULL;
906         size_t con_path_len = strlen(conn->connectpath);
907         char *p = NULL;
908
909         DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
910
911 #ifdef REALPATH_TAKES_NULL
912         resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
913 #else
914         resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
915 #endif
916
917         if (!resolved_name) {
918                 switch (errno) {
919                         case ENOTDIR:
920                                 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
921                                 return map_nt_error_from_unix(errno);
922                         case ENOENT:
923                         {
924                                 TALLOC_CTX *tmp_ctx = talloc_stackframe();
925                                 char *tmp_fname = NULL;
926                                 char *last_component = NULL;
927                                 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
928
929                                 tmp_fname = talloc_strdup(tmp_ctx, fname);
930                                 if (!tmp_fname) {
931                                         TALLOC_FREE(tmp_ctx);
932                                         return NT_STATUS_NO_MEMORY;
933                                 }
934                                 p = strrchr_m(tmp_fname, '/');
935                                 if (p) {
936                                         *p++ = '\0';
937                                         last_component = p;
938                                 } else {
939                                         last_component = tmp_fname;
940                                         tmp_fname = talloc_strdup(tmp_ctx,
941                                                         ".");
942                                         if (!tmp_fname) {
943                                                 TALLOC_FREE(tmp_ctx);
944                                                 return NT_STATUS_NO_MEMORY;
945                                         }
946                                 }
947
948 #ifdef REALPATH_TAKES_NULL
949                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
950 #else
951                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
952 #endif
953                                 if (!resolved_name) {
954                                         DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
955                                         TALLOC_FREE(tmp_ctx);
956                                         return map_nt_error_from_unix(errno);
957                                 }
958                                 tmp_fname = talloc_asprintf(tmp_ctx,
959                                                 "%s/%s",
960                                                 resolved_name,
961                                                 last_component);
962                                 if (!tmp_fname) {
963                                         TALLOC_FREE(tmp_ctx);
964                                         return NT_STATUS_NO_MEMORY;
965                                 }
966 #ifdef REALPATH_TAKES_NULL
967                                 SAFE_FREE(resolved_name);
968                                 resolved_name = SMB_STRDUP(tmp_fname);
969                                 if (!resolved_name) {
970                                         DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
971                                         return NT_STATUS_NO_MEMORY;
972                                 }
973 #else
974 #ifdef PATH_MAX
975                                 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
976 #else
977                                 pstrcpy(resolved_name_buf, tmp_fname);
978 #endif
979                                 resolved_name = resolved_name_buf;
980 #endif
981                                 TALLOC_FREE(tmp_ctx);
982                                 break;
983                         }
984                         default:
985                                 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
986                                 return map_nt_error_from_unix(errno);
987                 }
988         }
989
990         DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
991
992         if (*resolved_name != '/') {
993                 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
994                 if (free_resolved_name) {
995                         SAFE_FREE(resolved_name);
996                 }
997                 return NT_STATUS_OBJECT_NAME_INVALID;
998         }
999
1000         /* Check for widelinks allowed. */
1001         if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
1002                 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
1003                 if (free_resolved_name) {
1004                         SAFE_FREE(resolved_name);
1005                 }
1006                 return NT_STATUS_ACCESS_DENIED;
1007         }
1008
1009         /* Check if we are allowing users to follow symlinks */
1010         /* Patch from David Clerc <David.Clerc@cui.unige.ch>
1011                 University of Geneva */
1012
1013 #ifdef S_ISLNK
1014         if (!lp_symlinks(SNUM(conn))) {
1015                 SMB_STRUCT_STAT statbuf;
1016                 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
1017                                 (S_ISLNK(statbuf.st_mode)) ) {
1018                         if (free_resolved_name) {
1019                                 SAFE_FREE(resolved_name);
1020                         }
1021                         DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
1022                         return NT_STATUS_ACCESS_DENIED;
1023                 }
1024         }
1025 #endif
1026
1027         DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
1028         if (free_resolved_name) {
1029                 SAFE_FREE(resolved_name);
1030         }
1031         return NT_STATUS_OK;
1032 }