r6841: Attempt to fix buf #2681. With "strict allocate = yes" we now zero
[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
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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 struct vfs_init_function_entry {
31         char *name;
32         vfs_op_tuple *vfs_op_tuples;
33         struct vfs_init_function_entry *prev, *next;
34 };
35
36 static struct vfs_init_function_entry *backends = NULL;
37
38 /* Some structures to help us initialise the vfs operations table */
39
40 struct vfs_syminfo {
41         char *name;
42         void *fptr;
43 };
44
45 /* Default vfs hooks.  WARNING: The order of these initialisers is
46    very important.  They must be in the same order as defined in
47    vfs.h.  Change at your own peril. */
48
49 static struct vfs_ops default_vfs = {
50
51         {
52                 /* Disk operations */
53         
54                 vfswrap_dummy_connect,
55                 vfswrap_dummy_disconnect,
56                 vfswrap_disk_free,
57                 vfswrap_get_quota,
58                 vfswrap_set_quota,
59                 vfswrap_get_shadow_copy_data,
60         
61                 /* Directory operations */
62         
63                 vfswrap_opendir,
64                 vfswrap_readdir,
65                 vfswrap_seekdir,
66                 vfswrap_telldir,
67                 vfswrap_rewinddir,
68                 vfswrap_mkdir,
69                 vfswrap_rmdir,
70                 vfswrap_closedir,
71         
72                 /* File operations */
73         
74                 vfswrap_open,
75                 vfswrap_close,
76                 vfswrap_read,
77                 vfswrap_pread,
78                 vfswrap_write,
79                 vfswrap_pwrite,
80                 vfswrap_lseek,
81                 vfswrap_sendfile,
82                 vfswrap_rename,
83                 vfswrap_fsync,
84                 vfswrap_stat,
85                 vfswrap_fstat,
86                 vfswrap_lstat,
87                 vfswrap_unlink,
88                 vfswrap_chmod,
89                 vfswrap_fchmod,
90                 vfswrap_chown,
91                 vfswrap_fchown,
92                 vfswrap_chdir,
93                 vfswrap_getwd,
94                 vfswrap_utime,
95                 vfswrap_ftruncate,
96                 vfswrap_lock,
97                 vfswrap_symlink,
98                 vfswrap_readlink,
99                 vfswrap_link,
100                 vfswrap_mknod,
101                 vfswrap_realpath,
102         
103                 /* Windows ACL operations. */
104                 vfswrap_fget_nt_acl,
105                 vfswrap_get_nt_acl,
106                 vfswrap_fset_nt_acl,
107                 vfswrap_set_nt_acl,
108         
109                 /* POSIX ACL operations. */
110                 vfswrap_chmod_acl,
111                 vfswrap_fchmod_acl,
112
113                 vfswrap_sys_acl_get_entry,
114                 vfswrap_sys_acl_get_tag_type,
115                 vfswrap_sys_acl_get_permset,
116                 vfswrap_sys_acl_get_qualifier,
117                 vfswrap_sys_acl_get_file,
118                 vfswrap_sys_acl_get_fd,
119                 vfswrap_sys_acl_clear_perms,
120                 vfswrap_sys_acl_add_perm,
121                 vfswrap_sys_acl_to_text,
122                 vfswrap_sys_acl_init,
123                 vfswrap_sys_acl_create_entry,
124                 vfswrap_sys_acl_set_tag_type,
125                 vfswrap_sys_acl_set_qualifier,
126                 vfswrap_sys_acl_set_permset,
127                 vfswrap_sys_acl_valid,
128                 vfswrap_sys_acl_set_file,
129                 vfswrap_sys_acl_set_fd,
130                 vfswrap_sys_acl_delete_def_file,
131                 vfswrap_sys_acl_get_perm,
132                 vfswrap_sys_acl_free_text,
133                 vfswrap_sys_acl_free_acl,
134                 vfswrap_sys_acl_free_qualifier,
135
136                 /* EA operations. */
137                 vfswrap_getxattr,
138                 vfswrap_lgetxattr,
139                 vfswrap_fgetxattr,
140                 vfswrap_listxattr,
141                 vfswrap_llistxattr,
142                 vfswrap_flistxattr,
143                 vfswrap_removexattr,
144                 vfswrap_lremovexattr,
145                 vfswrap_fremovexattr,
146                 vfswrap_setxattr,
147                 vfswrap_lsetxattr,
148                 vfswrap_fsetxattr
149         }
150 };
151
152 /****************************************************************************
153     maintain the list of available backends
154 ****************************************************************************/
155
156 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
157 {
158         struct vfs_init_function_entry *entry = backends;
159  
160         while(entry) {
161                 if (strcmp(entry->name, name)==0) return entry;
162                 entry = entry->next;
163         }
164
165         return NULL;
166 }
167
168 NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples)
169 {
170         struct vfs_init_function_entry *entry = backends;
171
172         if ((version != SMB_VFS_INTERFACE_VERSION)) {
173                 DEBUG(0, ("Failed to register vfs module.\n"
174                           "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
175                           "current SMB_VFS_INTERFACE_VERSION is %d.\n"
176                           "Please recompile against the current Samba Version!\n",  
177                           version, SMB_VFS_INTERFACE_VERSION));
178                 return NT_STATUS_OBJECT_TYPE_MISMATCH;
179         }
180
181         if (!name || !name[0] || !vfs_op_tuples) {
182                 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
183                 return NT_STATUS_INVALID_PARAMETER;
184         }
185
186         if (vfs_find_backend_entry(name)) {
187                 DEBUG(0,("VFS module %s already loaded!\n", name));
188                 return NT_STATUS_OBJECT_NAME_COLLISION;
189         }
190
191         entry = SMB_XMALLOC_P(struct vfs_init_function_entry);
192         entry->name = smb_xstrdup(name);
193         entry->vfs_op_tuples = vfs_op_tuples;
194
195         DLIST_ADD(backends, entry);
196         DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
197         return NT_STATUS_OK;
198 }
199
200 /****************************************************************************
201   initialise default vfs hooks
202 ****************************************************************************/
203
204 static void vfs_init_default(connection_struct *conn)
205 {
206         DEBUG(3, ("Initialising default vfs hooks\n"));
207
208         memcpy(&conn->vfs.ops, &default_vfs.ops, sizeof(default_vfs.ops));
209         memcpy(&conn->vfs_opaque.ops, &default_vfs.ops, sizeof(default_vfs.ops));
210 }
211
212 /****************************************************************************
213   initialise custom vfs hooks
214  ****************************************************************************/
215
216 BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
217 {
218         vfs_op_tuple *ops;
219         char *module_name = NULL;
220         char *module_param = NULL, *p;
221         int i;
222         vfs_handle_struct *handle;
223         struct vfs_init_function_entry *entry;
224         
225         if (!conn||!vfs_object||!vfs_object[0]) {
226                 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
227                 return False;
228         }
229
230         if(!backends) {
231                 static_init_vfs;
232         }
233
234         DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
235
236         module_name = smb_xstrdup(vfs_object);
237
238         p = strchr_m(module_name, ':');
239
240         if (p) {
241                 *p = 0;
242                 module_param = p+1;
243                 trim_char(module_param, ' ', ' ');
244         }
245
246         trim_char(module_name, ' ', ' ');
247
248         /* First, try to load the module with the new module system */
249         if((entry = vfs_find_backend_entry(module_name)) || 
250            (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) && 
251                 (entry = vfs_find_backend_entry(module_name)))) {
252
253                 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
254                 
255                 if ((ops = entry->vfs_op_tuples) == NULL) {
256                         DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
257                         SAFE_FREE(module_name);
258                         return False;
259                 }
260         } else {
261                 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
262                 SAFE_FREE(module_name);
263                 return False;
264         }
265
266         handle = TALLOC_ZERO_P(conn->mem_ctx,vfs_handle_struct);
267         if (!handle) {
268                 DEBUG(0,("talloc_zero() failed!\n"));
269                 SAFE_FREE(module_name);
270                 return False;
271         }
272         memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
273         handle->conn = conn;
274         if (module_param) {
275                 handle->param = talloc_strdup(conn->mem_ctx, module_param);
276         }
277         DLIST_ADD(conn->vfs_handles, handle);
278
279         for(i=0; ops[i].op != NULL; i++) {
280           DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
281           if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
282             /* Check whether this operation was already made opaque by different module */
283             if(((void**)&conn->vfs_opaque.ops)[ops[i].type] == ((void**)&default_vfs.ops)[ops[i].type]) {
284               /* No, it isn't overloaded yet. Overload. */
285               DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
286               ((void**)&conn->vfs_opaque.ops)[ops[i].type] = ops[i].op;
287               ((vfs_handle_struct **)&conn->vfs_opaque.handles)[ops[i].type] = handle;
288             }
289           }
290           /* Change current VFS disposition*/
291           DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
292           ((void**)&conn->vfs.ops)[ops[i].type] = ops[i].op;
293           ((vfs_handle_struct **)&conn->vfs.handles)[ops[i].type] = handle;
294         }
295
296         SAFE_FREE(module_name);
297         return True;
298 }
299
300 /*****************************************************************
301  Generic VFS init.
302 ******************************************************************/
303
304 BOOL smbd_vfs_init(connection_struct *conn)
305 {
306         const char **vfs_objects;
307         unsigned int i = 0;
308         int j = 0;
309         
310         /* Normal share - initialise with disk access functions */
311         vfs_init_default(conn);
312         vfs_objects = lp_vfs_objects(SNUM(conn));
313
314         /* Override VFS functions if 'vfs object' was not specified*/
315         if (!vfs_objects || !vfs_objects[0])
316                 return True;
317         
318         for (i=0; vfs_objects[i] ;) {
319                 i++;
320         }
321
322         for (j=i-1; j >= 0; j--) {
323                 if (!vfs_init_custom(conn, vfs_objects[j])) {
324                         DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
325                         return False;
326                 }
327         }
328         return True;
329 }
330
331 /*******************************************************************
332  Check if directory exists.
333 ********************************************************************/
334
335 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
336 {
337         SMB_STRUCT_STAT st2;
338         BOOL ret;
339
340         if (!st)
341                 st = &st2;
342
343         if (SMB_VFS_STAT(conn,dname,st) != 0)
344                 return(False);
345
346         ret = S_ISDIR(st->st_mode);
347         if(!ret)
348                 errno = ENOTDIR;
349
350         return ret;
351 }
352
353 /*******************************************************************
354  vfs mkdir wrapper 
355 ********************************************************************/
356
357 int vfs_MkDir(connection_struct *conn, const char *name, mode_t mode)
358 {
359         int ret;
360         SMB_STRUCT_STAT sbuf;
361
362         if(!(ret=SMB_VFS_MKDIR(conn, name, mode))) {
363
364                 inherit_access_acl(conn, name, mode);
365
366                 /*
367                  * Check if high bits should have been set,
368                  * then (if bits are missing): add them.
369                  * Consider bits automagically set by UNIX, i.e. SGID bit from parent dir.
370                  */
371                 if(mode & ~(S_IRWXU|S_IRWXG|S_IRWXO) &&
372                                 !SMB_VFS_STAT(conn,name,&sbuf) && (mode & ~sbuf.st_mode))
373                         SMB_VFS_CHMOD(conn,name,sbuf.st_mode | (mode & ~sbuf.st_mode));
374         }
375         return ret;
376 }
377
378 /*******************************************************************
379  Check if an object exists in the vfs.
380 ********************************************************************/
381
382 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
383 {
384         SMB_STRUCT_STAT st;
385
386         if (!sbuf)
387                 sbuf = &st;
388
389         ZERO_STRUCTP(sbuf);
390
391         if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
392                 return(False);
393         return True;
394 }
395
396 /*******************************************************************
397  Check if a file exists in the vfs.
398 ********************************************************************/
399
400 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
401 {
402         SMB_STRUCT_STAT st;
403
404         if (!sbuf)
405                 sbuf = &st;
406
407         ZERO_STRUCTP(sbuf);
408
409         if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
410                 return False;
411         return(S_ISREG(sbuf->st_mode));
412 }
413
414 /****************************************************************************
415  Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
416 ****************************************************************************/
417
418 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
419 {
420         size_t total=0;
421
422         while (total < byte_count)
423         {
424                 ssize_t ret = SMB_VFS_READ(fsp, fsp->fd, buf + total,
425                                         byte_count - total);
426
427                 if (ret == 0) return total;
428                 if (ret == -1) {
429                         if (errno == EINTR)
430                                 continue;
431                         else
432                                 return -1;
433                 }
434                 total += ret;
435         }
436         return (ssize_t)total;
437 }
438
439 ssize_t vfs_pread_data(files_struct *fsp, char *buf,
440                 size_t byte_count, SMB_OFF_T offset)
441 {
442         size_t total=0;
443
444         while (total < byte_count)
445         {
446                 ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fd, buf + total,
447                                         byte_count - total, offset + total);
448
449                 if (ret == 0) return total;
450                 if (ret == -1) {
451                         if (errno == EINTR)
452                                 continue;
453                         else
454                                 return -1;
455                 }
456                 total += ret;
457         }
458         return (ssize_t)total;
459 }
460
461 /****************************************************************************
462  Write data to a fd on the vfs.
463 ****************************************************************************/
464
465 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
466 {
467         size_t total=0;
468         ssize_t ret;
469
470         while (total < N) {
471                 ret = SMB_VFS_WRITE(fsp,fsp->fd,buffer + total,N - total);
472
473                 if (ret == -1)
474                         return -1;
475                 if (ret == 0)
476                         return total;
477
478                 total += ret;
479         }
480         return (ssize_t)total;
481 }
482
483 ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer,
484                 size_t N, SMB_OFF_T offset)
485 {
486         size_t total=0;
487         ssize_t ret;
488
489         while (total < N) {
490                 ret = SMB_VFS_PWRITE(fsp, fsp->fd, buffer + total,
491                                 N - total, offset + total);
492
493                 if (ret == -1)
494                         return -1;
495                 if (ret == 0)
496                         return total;
497
498                 total += ret;
499         }
500         return (ssize_t)total;
501 }
502 /****************************************************************************
503  An allocate file space call using the vfs interface.
504  Allocates space for a file from a filedescriptor.
505  Returns 0 on success, -1 on failure.
506 ****************************************************************************/
507
508 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
509 {
510         int ret;
511         SMB_STRUCT_STAT st;
512         connection_struct *conn = fsp->conn;
513         SMB_BIG_UINT space_avail;
514         SMB_BIG_UINT bsize,dfree,dsize;
515
516         release_level_2_oplocks_on_change(fsp);
517
518         /*
519          * Actually try and commit the space on disk....
520          */
521
522         DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
523
524         if (((SMB_OFF_T)len) < 0) {
525                 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
526                 return -1;
527         }
528
529         ret = SMB_VFS_FSTAT(fsp,fsp->fd,&st);
530         if (ret == -1)
531                 return ret;
532
533         if (len == (SMB_BIG_UINT)st.st_size)
534                 return 0;
535
536         if (len < (SMB_BIG_UINT)st.st_size) {
537                 /* Shrink - use ftruncate. */
538
539                 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
540                                 fsp->fsp_name, (double)st.st_size ));
541
542                 flush_write_cache(fsp, SIZECHANGE_FLUSH);
543                 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, (SMB_OFF_T)len)) != -1) {
544                         set_filelen_write_cache(fsp, len);
545                 }
546                 return ret;
547         }
548
549         /* Grow - we need to test if we have enough space. */
550
551         if (!lp_strict_allocate(SNUM(fsp->conn)))
552                 return 0;
553
554         len -= st.st_size;
555         len /= 1024; /* Len is now number of 1k blocks needed. */
556         space_avail = SMB_VFS_DISK_FREE(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
557         if (space_avail == (SMB_BIG_UINT)-1) {
558                 return -1;
559         }
560
561         DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
562                         fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
563
564         if (len > space_avail) {
565                 errno = ENOSPC;
566                 return -1;
567         }
568
569         return 0;
570 }
571
572 /****************************************************************************
573  A vfs set_filelen call.
574  set the length of a file from a filedescriptor.
575  Returns 0 on success, -1 on failure.
576 ****************************************************************************/
577
578 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
579 {
580         int ret;
581
582         release_level_2_oplocks_on_change(fsp);
583         DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
584         flush_write_cache(fsp, SIZECHANGE_FLUSH);
585         if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fd, len)) != -1)
586                 set_filelen_write_cache(fsp, len);
587
588         return ret;
589 }
590
591 /****************************************************************************
592  A vfs fill sparse call.
593  Writes zeros from the end of file to len, if len is greater than EOF.
594  Used only by strict_sync.
595  Returns 0 on success, -1 on failure.
596 ****************************************************************************/
597
598 static char *sparse_buf;
599 #define SPARSE_BUF_WRITE_SIZE (32*1024)
600
601 int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
602 {
603         int ret;
604         SMB_STRUCT_STAT st;
605         SMB_OFF_T offset;
606         size_t total;
607         size_t num_to_write;
608         ssize_t pwrite_ret;
609
610         release_level_2_oplocks_on_change(fsp);
611         ret = SMB_VFS_FSTAT(fsp,fsp->fd,&st);
612         if (ret == -1) {
613                 return ret;
614         }
615
616         if (len <= st.st_size) {
617                 return 0;
618         }
619
620         DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
621                 fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
622
623         flush_write_cache(fsp, SIZECHANGE_FLUSH);
624
625         if (!sparse_buf) {
626                 sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
627                 if (!sparse_buf) {
628                         errno = ENOMEM;
629                         return -1;
630                 }
631         }
632
633         offset = st.st_size;
634         num_to_write = len - st.st_size;
635         total = 0;
636
637         while (total < num_to_write) {
638                 size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
639
640                 pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fd, sparse_buf, curr_write_size, offset + total);
641                 if (pwrite_ret == -1) {
642                         DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
643                                 fsp->fsp_name, strerror(errno) ));
644                         return -1;
645                 }
646                 if (pwrite_ret == 0) {
647                         return 0;
648                 }
649
650                 total += pwrite_ret;
651         }
652
653         set_filelen_write_cache(fsp, len);
654         return 0;
655 }
656
657 /****************************************************************************
658  Transfer some data (n bytes) between two file_struct's.
659 ****************************************************************************/
660
661 static files_struct *in_fsp;
662 static files_struct *out_fsp;
663
664 static ssize_t read_fn(int fd, void *buf, size_t len)
665 {
666         return SMB_VFS_READ(in_fsp, fd, buf, len);
667 }
668
669 static ssize_t write_fn(int fd, const void *buf, size_t len)
670 {
671         return SMB_VFS_WRITE(out_fsp, fd, buf, len);
672 }
673
674 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
675 {
676         in_fsp = in;
677         out_fsp = out;
678
679         return transfer_file_internal(in_fsp->fd, out_fsp->fd, n, read_fn, write_fn);
680 }
681
682 /*******************************************************************
683  A vfs_readdir wrapper which just returns the file name.
684 ********************************************************************/
685
686 char *vfs_readdirname(connection_struct *conn, void *p)
687 {
688         SMB_STRUCT_DIRENT *ptr= NULL;
689         char *dname;
690
691         if (!p)
692                 return(NULL);
693
694         ptr = SMB_VFS_READDIR(conn,p);
695         if (!ptr)
696                 return(NULL);
697
698         dname = ptr->d_name;
699
700 #ifdef NEXT2
701         if (telldir(p) < 0)
702                 return(NULL);
703 #endif
704
705 #ifdef HAVE_BROKEN_READDIR
706         /* using /usr/ucb/cc is BAD */
707         dname = dname - 2;
708 #endif
709
710         return(dname);
711 }
712
713 /*******************************************************************
714  A wrapper for vfs_chdir().
715 ********************************************************************/
716
717 int vfs_ChDir(connection_struct *conn, const char *path)
718 {
719         int res;
720         static pstring LastDir="";
721
722         if (strcsequal(path,"."))
723                 return(0);
724
725         if (*path == '/' && strcsequal(LastDir,path))
726                 return(0);
727
728         DEBUG(4,("vfs_ChDir to %s\n",path));
729
730         res = SMB_VFS_CHDIR(conn,path);
731         if (!res)
732                 pstrcpy(LastDir,path);
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 *dos_path; /* The pathname in DOS format. */
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(connection_struct *conn, char *path)
778 {
779         pstring s;
780         static BOOL getwd_cache_init = False;
781         SMB_STRUCT_STAT st, st2;
782         int i;
783
784         *s = 0;
785
786         if (!use_getwd_cache)
787                 return(SMB_VFS_GETWD(conn,path));
788
789         /* init the cache */
790         if (!getwd_cache_init) {
791                 getwd_cache_init = True;
792                 for (i=0;i<MAX_GETWDCACHE;i++) {
793                         string_set(&ino_list[i].dos_path,"");
794                         ino_list[i].valid = False;
795                 }
796         }
797
798         /*  Get the inode of the current directory, if this doesn't work we're
799                 in trouble :-) */
800
801         if (SMB_VFS_STAT(conn, ".",&st) == -1) {
802                 /* Known to fail for root: the directory may be
803                  * NFS-mounted and exported with root_squash (so has no root access). */
804                 DEBUG(1,("vfs_GetWd: couldn't stat \".\" path=%s error %s (NFS problem ?)\n", path, strerror(errno) ));
805                 return(SMB_VFS_GETWD(conn,path));
806         }
807
808
809         for (i=0; i<MAX_GETWDCACHE; i++) {
810                 if (ino_list[i].valid) {
811
812                         /*  If we have found an entry with a matching inode and dev number
813                                 then find the inode number for the directory in the cached string.
814                                 If this agrees with that returned by the stat for the current
815                                 directory then all is o.k. (but make sure it is a directory all
816                                 the same...) */
817
818                         if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
819                                 if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
820                                         if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
821                                                         (st2.st_mode & S_IFMT) == S_IFDIR) {
822                                                 pstrcpy (path, ino_list[i].dos_path);
823
824                                                 /* promote it for future use */
825                                                 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
826                                                 return (path);
827                                         } else {
828                                                 /*  If the inode is different then something's changed,
829                                                         scrub the entry and start from scratch. */
830                                                 ino_list[i].valid = False;
831                                         }
832                                 }
833                         }
834                 }
835         }
836
837         /*  We don't have the information to hand so rely on traditional methods.
838                 The very slow getcwd, which spawns a process on some systems, or the
839                 not quite so bad getwd. */
840
841         if (!SMB_VFS_GETWD(conn,s)) {
842                 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
843                 return (NULL);
844         }
845
846         pstrcpy(path,s);
847
848         DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
849
850         /* add it to the cache */
851         i = MAX_GETWDCACHE - 1;
852         string_set(&ino_list[i].dos_path,s);
853         ino_list[i].dev = st.st_dev;
854         ino_list[i].inode = st.st_ino;
855         ino_list[i].valid = True;
856
857         /* put it at the top of the list */
858         array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
859
860         return (path);
861 }
862
863 BOOL canonicalize_path(connection_struct *conn, pstring path)
864 {
865 #ifdef REALPATH_TAKES_NULL
866         char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
867         if (!resolved_name) {
868                 return False;
869         }
870         pstrcpy(path, resolved_name);
871         SAFE_FREE(resolved_name);
872         return True;
873 #else
874 #ifdef PATH_MAX
875         char resolved_name_buf[PATH_MAX+1];
876 #else
877         pstring resolved_name_buf;
878 #endif
879         char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
880         if (!resolved_name) {
881                 return False;
882         }
883         pstrcpy(path, resolved_name);
884         return True;
885 #endif /* REALPATH_TAKES_NULL */
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 BOOL reduce_name(connection_struct *conn, const pstring 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         int saved_errno = errno;
909
910         DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
911
912 #ifdef REALPATH_TAKES_NULL
913         resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
914 #else
915         resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
916 #endif
917
918         if (!resolved_name) {
919                 switch (errno) {
920                         case ENOTDIR:
921                                 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
922                                 errno = saved_errno;
923                                 return False;
924                         case ENOENT:
925                         {
926                                 pstring tmp_fname;
927                                 fstring last_component;
928                                 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
929
930                                 pstrcpy(tmp_fname, fname);
931                                 p = strrchr_m(tmp_fname, '/');
932                                 if (p) {
933                                         *p++ = '\0';
934                                         fstrcpy(last_component, p);
935                                 } else {
936                                         fstrcpy(last_component, tmp_fname);
937                                         pstrcpy(tmp_fname, ".");
938                                 }
939
940 #ifdef REALPATH_TAKES_NULL
941                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
942 #else
943                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
944 #endif
945                                 if (!resolved_name) {
946                                         DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
947                                         errno = saved_errno;
948                                         return False;
949                                 }
950                                 pstrcpy(tmp_fname, resolved_name);
951                                 pstrcat(tmp_fname, "/");
952                                 pstrcat(tmp_fname, last_component);
953 #ifdef REALPATH_TAKES_NULL
954                                 SAFE_FREE(resolved_name);
955                                 resolved_name = SMB_STRDUP(tmp_fname);
956                                 if (!resolved_name) {
957                                         DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
958                                         errno = saved_errno;
959                                         return False;
960                                 }
961 #else
962 #ifdef PATH_MAX
963                                 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
964 #else
965                                 pstrcpy(resolved_name_buf, tmp_fname);
966 #endif
967                                 resolved_name = resolved_name_buf;
968 #endif
969                                 break;
970                         }
971                         default:
972                                 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
973                                 /* Don't restore the saved errno. We need to return the error that
974                                    realpath caused here as it was not one of the cases we handle. JRA. */
975                                 return False;
976                 }
977         }
978
979         DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
980
981         if (*resolved_name != '/') {
982                 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
983                 if (free_resolved_name)
984                         SAFE_FREE(resolved_name);
985                 errno = saved_errno;
986                 return False;
987         }
988
989         /* Check for widelinks allowed. */
990         if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
991                 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
992                 if (free_resolved_name)
993                         SAFE_FREE(resolved_name);
994                 errno = EACCES;
995                 return False;
996         }
997
998         /* Check if we are allowing users to follow symlinks */
999         /* Patch from David Clerc <David.Clerc@cui.unige.ch>
1000                 University of Geneva */
1001                                                                                                                                                     
1002 #ifdef S_ISLNK
1003         if (!lp_symlinks(SNUM(conn))) {
1004                 SMB_STRUCT_STAT statbuf;
1005                 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
1006                                 (S_ISLNK(statbuf.st_mode)) ) {
1007                         if (free_resolved_name)
1008                                 SAFE_FREE(resolved_name);
1009                         DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
1010                         errno = EACCES;
1011                         return False;
1012                 }
1013         }
1014 #endif
1015
1016         DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
1017         if (free_resolved_name)
1018                 SAFE_FREE(resolved_name);
1019         errno = saved_errno;
1020         return(True);
1021 }