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