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