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