source: branches/samba-3.0/source/smbd/vfs.c @ 431

Last change on this file since 431 was 431, checked in by Silvan Scherrer, 11 years ago

samba 3.0: ticket 132

File size: 25.9 KB
Line 
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
31static_decl_vfs;
32
33struct vfs_init_function_entry {
34        char *name;
35        vfs_op_tuple *vfs_op_tuples;
36        struct vfs_init_function_entry *prev, *next;
37};
38
39static struct vfs_init_function_entry *backends = NULL;
40
41/****************************************************************************
42    maintain the list of available backends
43****************************************************************************/
44
45static 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
57NTSTATUS 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
93static 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
103static 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
110BOOL 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
199void *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
221void 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
241void *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
260BOOL 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
291BOOL 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
313BOOL 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
331BOOL 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
349ssize_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
370ssize_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
396ssize_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
414ssize_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
439int 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
510int 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
535static char *sparse_buf;
536#define SPARSE_BUF_WRITE_SIZE (32*1024)
537
538int 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
598static files_struct *in_fsp;
599static files_struct *out_fsp;
600
601static ssize_t read_fn(int fd, void *buf, size_t len)
602{
603        return SMB_VFS_READ(in_fsp, fd, buf, len);
604}
605
606static 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
611SMB_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
623char *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
654int 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#ifdef __OS2__
663        if ((*path == '/' || *path == '\\' || (*path && path[1] == ':')) && strcsequal(LastDir,path))
664#else
665        if (*path == '/' && strcsequal(LastDir,path))
666#endif
667                return(0);
668
669        DEBUG(4,("vfs_ChDir to %s\n",path));
670
671        res = SMB_VFS_CHDIR(conn,path);
672        if (!res)
673                pstrcpy(LastDir,path);
674        return(res);
675}
676
677/* number of list structures for a caching GetWd function. */
678#define MAX_GETWDCACHE (50)
679
680static struct {
681        SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
682        SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
683        char *dos_path; /* The pathname in DOS format. */
684        BOOL valid;
685} ino_list[MAX_GETWDCACHE];
686
687extern BOOL use_getwd_cache;
688
689/****************************************************************************
690 Prompte a ptr (to make it recently used)
691****************************************************************************/
692
693static void array_promote(char *array,int elsize,int element)
694{
695        char *p;
696        if (element == 0)
697                return;
698
699        p = (char *)SMB_MALLOC(elsize);
700
701        if (!p) {
702                DEBUG(5,("array_promote: malloc fail\n"));
703                return;
704        }
705
706        memcpy(p,array + element * elsize, elsize);
707        memmove(array + elsize,array,elsize*element);
708        memcpy(array,p,elsize);
709        SAFE_FREE(p);
710}
711
712/*******************************************************************
713 Return the absolute current directory path - given a UNIX pathname.
714 Note that this path is returned in DOS format, not UNIX
715 format. Note this can be called with conn == NULL.
716********************************************************************/
717
718char *vfs_GetWd(connection_struct *conn, char *path)
719{
720        pstring s;
721        static BOOL getwd_cache_init = False;
722        SMB_STRUCT_STAT st, st2;
723        int i;
724
725        *s = 0;
726
727        if (!use_getwd_cache)
728                return(SMB_VFS_GETWD(conn,path));
729
730        /* init the cache */
731        if (!getwd_cache_init) {
732                getwd_cache_init = True;
733                for (i=0;i<MAX_GETWDCACHE;i++) {
734                        string_set(&ino_list[i].dos_path,"");
735                        ino_list[i].valid = False;
736                }
737        }
738
739        /*  Get the inode of the current directory, if this doesn't work we're
740                in trouble :-) */
741
742        if (SMB_VFS_STAT(conn, ".",&st) == -1) {
743                /* Known to fail for root: the directory may be
744                 * NFS-mounted and exported with root_squash (so has no root access). */
745                DEBUG(1,("vfs_GetWd: couldn't stat \".\" path=%s error %s (NFS problem ?)\n", path, strerror(errno) ));
746                return(SMB_VFS_GETWD(conn,path));
747        }
748
749
750        for (i=0; i<MAX_GETWDCACHE; i++) {
751                if (ino_list[i].valid) {
752
753                        /*  If we have found an entry with a matching inode and dev number
754                                then find the inode number for the directory in the cached string.
755                                If this agrees with that returned by the stat for the current
756                                directory then all is o.k. (but make sure it is a directory all
757                                the same...) */
758
759                        if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
760                                if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
761                                        if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
762                                                        (st2.st_mode & S_IFMT) == S_IFDIR) {
763                                                pstrcpy (path, ino_list[i].dos_path);
764
765                                                /* promote it for future use */
766                                                array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
767                                                return (path);
768                                        } else {
769                                                /*  If the inode is different then something's changed,
770                                                        scrub the entry and start from scratch. */
771                                                ino_list[i].valid = False;
772                                        }
773                                }
774                        }
775                }
776        }
777
778        /*  We don't have the information to hand so rely on traditional methods.
779                The very slow getcwd, which spawns a process on some systems, or the
780                not quite so bad getwd. */
781
782        if (!SMB_VFS_GETWD(conn,s)) {
783                DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
784                return (NULL);
785        }
786
787        pstrcpy(path,s);
788
789        DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
790
791        /* add it to the cache */
792        i = MAX_GETWDCACHE - 1;
793        string_set(&ino_list[i].dos_path,s);
794        ino_list[i].dev = st.st_dev;
795        ino_list[i].inode = st.st_ino;
796        ino_list[i].valid = True;
797
798        /* put it at the top of the list */
799        array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
800
801        return (path);
802}
803
804/*******************************************************************
805 Reduce a file name, removing .. elements and checking that
806 it is below dir in the heirachy. This uses realpath.
807********************************************************************/
808
809NTSTATUS reduce_name(connection_struct *conn, const pstring fname)
810{
811#ifdef REALPATH_TAKES_NULL
812        BOOL free_resolved_name = True;
813#else
814#ifdef PATH_MAX
815        char resolved_name_buf[PATH_MAX+1];
816#else
817        pstring resolved_name_buf;
818#endif
819        BOOL free_resolved_name = False;
820#endif
821        char *resolved_name = NULL;
822        size_t con_path_len = strlen(conn->connectpath);
823        char *p = NULL;
824
825        DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
826
827#ifdef REALPATH_TAKES_NULL
828        resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
829#else
830        resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
831#endif
832
833        if (!resolved_name) {
834                switch (errno) {
835                        case ENOTDIR:
836                                DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
837                                return map_nt_error_from_unix(errno);
838                        case ENOENT:
839                        {
840                                pstring tmp_fname;
841                                fstring last_component;
842                                /* Last component didn't exist. Remove it and try and canonicalise the directory. */
843
844                                pstrcpy(tmp_fname, fname);
845                                p = strrchr_m(tmp_fname, '/');
846                                if (p) {
847                                        *p++ = '\0';
848                                        fstrcpy(last_component, p);
849                                } else {
850                                        fstrcpy(last_component, tmp_fname);
851                                        pstrcpy(tmp_fname, ".");
852                                }
853
854#ifdef REALPATH_TAKES_NULL
855                                resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
856#else
857                                resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
858#endif
859                                if (!resolved_name) {
860                                        DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
861                                        return map_nt_error_from_unix(errno);
862                                }
863                                pstrcpy(tmp_fname, resolved_name);
864                                pstrcat(tmp_fname, "/");
865                                pstrcat(tmp_fname, last_component);
866#ifdef REALPATH_TAKES_NULL
867                                SAFE_FREE(resolved_name);
868                                resolved_name = SMB_STRDUP(tmp_fname);
869                                if (!resolved_name) {
870                                        DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
871                                        return NT_STATUS_NO_MEMORY;
872                                }
873#else
874#ifdef PATH_MAX
875                                safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
876#else
877                                pstrcpy(resolved_name_buf, tmp_fname);
878#endif
879                                resolved_name = resolved_name_buf;
880#endif
881                                break;
882                        }
883                        default:
884                                DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
885                                return map_nt_error_from_unix(errno);
886                }
887        }
888
889        DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
890
891#ifdef __OS2__
892        if (*resolved_name != '/' && *resolved_name != '\\' && (strlen(resolved_name) <= 1 || resolved_name[1] != ':')) {
893#else
894        if (*resolved_name != '/') {
895#endif
896                DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
897                if (free_resolved_name) {
898                        SAFE_FREE(resolved_name);
899                }
900                return NT_STATUS_OBJECT_NAME_INVALID;
901        }
902
903        /* Check for widelinks allowed. */
904        if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
905                DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
906                if (free_resolved_name) {
907                        SAFE_FREE(resolved_name);
908                }
909                return NT_STATUS_ACCESS_DENIED;
910        }
911
912        /* Check if we are allowing users to follow symlinks */
913        /* Patch from David Clerc <David.Clerc@cui.unige.ch>
914                University of Geneva */
915                                                                                                                                                   
916#ifdef S_ISLNK
917        if (!lp_symlinks(SNUM(conn))) {
918                SMB_STRUCT_STAT statbuf;
919                if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
920                                (S_ISLNK(statbuf.st_mode)) ) {
921                        if (free_resolved_name) {
922                                SAFE_FREE(resolved_name);
923                        }
924                        DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
925                        return NT_STATUS_ACCESS_DENIED;
926                }
927        }
928#endif
929
930        DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
931        if (free_resolved_name) {
932                SAFE_FREE(resolved_name);
933        }
934        return NT_STATUS_OK;
935}
Note: See TracBrowser for help on using the repository browser.