smbd/vfs.c

説明を見る。
00001 /*
00002    Unix SMB/Netbios implementation.
00003    Version 1.9.
00004    VFS initialisation and support functions
00005    Copyright (C) Tim Potter 1999
00006    Copyright (C) Alexander Bokovoy 2002
00007    Copyright (C) James Peach 2006
00008 
00009    This program is free software; you can redistribute it and/or modify
00010    it under the terms of the GNU General Public License as published by
00011    the Free Software Foundation; either version 2 of the License, or
00012    (at your option) any later version.
00013 
00014    This program is distributed in the hope that it will be useful,
00015    but WITHOUT ANY WARRANTY; without even the implied warranty of
00016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017    GNU General Public License for more details.
00018 
00019    You should have received a copy of the GNU General Public License
00020    along with this program; if not, write to the Free Software
00021    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00022 
00023    This work was sponsored by Optifacio Software Services, Inc.
00024 */
00025 
00026 #include "includes.h"
00027 
00028 #undef DBGC_CLASS
00029 #define DBGC_CLASS DBGC_VFS
00030 
00031 static_decl_vfs;
00032 
00033 struct vfs_init_function_entry {
00034         char *name;
00035         vfs_op_tuple *vfs_op_tuples;
00036         struct vfs_init_function_entry *prev, *next;
00037 };
00038 
00039 static struct vfs_init_function_entry *backends = NULL;
00040 
00041 /****************************************************************************
00042     maintain the list of available backends
00043 ****************************************************************************/
00044 
00045 static struct vfs_init_function_entry *vfs_find_backend_entry(const char *name)
00046 {
00047         struct vfs_init_function_entry *entry = backends;
00048  
00049         while(entry) {
00050                 if (strcmp(entry->name, name)==0) return entry;
00051                 entry = entry->next;
00052         }
00053 
00054         return NULL;
00055 }
00056 
00057 NTSTATUS smb_register_vfs(int version, const char *name, vfs_op_tuple *vfs_op_tuples)
00058 {
00059         struct vfs_init_function_entry *entry = backends;
00060 
00061         if ((version != SMB_VFS_INTERFACE_VERSION)) {
00062                 DEBUG(0, ("Failed to register vfs module.\n"
00063                           "The module was compiled against SMB_VFS_INTERFACE_VERSION %d,\n"
00064                           "current SMB_VFS_INTERFACE_VERSION is %d.\n"
00065                           "Please recompile against the current Samba Version!\n",  
00066                           version, SMB_VFS_INTERFACE_VERSION));
00067                 return NT_STATUS_OBJECT_TYPE_MISMATCH;
00068         }
00069 
00070         if (!name || !name[0] || !vfs_op_tuples) {
00071                 DEBUG(0,("smb_register_vfs() called with NULL pointer or empty name!\n"));
00072                 return NT_STATUS_INVALID_PARAMETER;
00073         }
00074 
00075         if (vfs_find_backend_entry(name)) {
00076                 DEBUG(0,("VFS module %s already loaded!\n", name));
00077                 return NT_STATUS_OBJECT_NAME_COLLISION;
00078         }
00079 
00080         entry = SMB_XMALLOC_P(struct vfs_init_function_entry);
00081         entry->name = smb_xstrdup(name);
00082         entry->vfs_op_tuples = vfs_op_tuples;
00083 
00084         DLIST_ADD(backends, entry);
00085         DEBUG(5, ("Successfully added vfs backend '%s'\n", name));
00086         return NT_STATUS_OK;
00087 }
00088 
00089 /****************************************************************************
00090   initialise default vfs hooks
00091 ****************************************************************************/
00092 
00093 static void vfs_init_default(connection_struct *conn)
00094 {
00095         DEBUG(3, ("Initialising default vfs hooks\n"));
00096         vfs_init_custom(conn, DEFAULT_VFS_MODULE_NAME);
00097 }
00098 
00099 /****************************************************************************
00100   initialise custom vfs hooks
00101  ****************************************************************************/
00102 
00103 static inline void vfs_set_operation(struct vfs_ops * vfs, vfs_op_type which,
00104                                 struct vfs_handle_struct * handle, void * op)
00105 {
00106         ((struct vfs_handle_struct **)&vfs->handles)[which] = handle;
00107         ((void **)(void *)&vfs->ops)[which] = op;
00108 }
00109 
00110 BOOL vfs_init_custom(connection_struct *conn, const char *vfs_object)
00111 {
00112         vfs_op_tuple *ops;
00113         char *module_name = NULL;
00114         char *module_param = NULL, *p;
00115         int i;
00116         vfs_handle_struct *handle;
00117         struct vfs_init_function_entry *entry;
00118         
00119         if (!conn||!vfs_object||!vfs_object[0]) {
00120                 DEBUG(0,("vfs_init_custon() called with NULL pointer or emtpy vfs_object!\n"));
00121                 return False;
00122         }
00123 
00124         if(!backends) {
00125                 static_init_vfs;
00126         }
00127 
00128         DEBUG(3, ("Initialising custom vfs hooks from [%s]\n", vfs_object));
00129 
00130         module_name = smb_xstrdup(vfs_object);
00131 
00132         p = strchr_m(module_name, ':');
00133 
00134         if (p) {
00135                 *p = 0;
00136                 module_param = p+1;
00137                 trim_char(module_param, ' ', ' ');
00138         }
00139 
00140         trim_char(module_name, ' ', ' ');
00141 
00142         /* First, try to load the module with the new module system */
00143         if((entry = vfs_find_backend_entry(module_name)) || 
00144            (NT_STATUS_IS_OK(smb_probe_module("vfs", module_name)) && 
00145                 (entry = vfs_find_backend_entry(module_name)))) {
00146 
00147                 DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object));
00148                 
00149                 if ((ops = entry->vfs_op_tuples) == NULL) {
00150                         DEBUG(0, ("entry->vfs_op_tuples==NULL for [%s] failed\n", vfs_object));
00151                         SAFE_FREE(module_name);
00152                         return False;
00153                 }
00154         } else {
00155                 DEBUG(0,("Can't find a vfs module [%s]\n",vfs_object));
00156                 SAFE_FREE(module_name);
00157                 return False;
00158         }
00159 
00160         handle = TALLOC_ZERO_P(conn->mem_ctx,vfs_handle_struct);
00161         if (!handle) {
00162                 DEBUG(0,("TALLOC_ZERO() failed!\n"));
00163                 SAFE_FREE(module_name);
00164                 return False;
00165         }
00166         memcpy(&handle->vfs_next, &conn->vfs, sizeof(struct vfs_ops));
00167         handle->conn = conn;
00168         if (module_param) {
00169                 handle->param = talloc_strdup(conn->mem_ctx, module_param);
00170         }
00171         DLIST_ADD(conn->vfs_handles, handle);
00172 
00173         for(i=0; ops[i].op != NULL; i++) {
00174                 DEBUG(5, ("Checking operation #%d (type %d, layer %d)\n", i, ops[i].type, ops[i].layer));
00175                 if(ops[i].layer == SMB_VFS_LAYER_OPAQUE) {
00176                         /* If this operation was already made opaque by different module, it
00177                          * will be overridden here.
00178                          */
00179                         DEBUGADD(5, ("Making operation type %d opaque [module %s]\n", ops[i].type, vfs_object));
00180                         vfs_set_operation(&conn->vfs_opaque, ops[i].type, handle, ops[i].op);
00181                 }
00182                 /* Change current VFS disposition*/
00183                 DEBUGADD(5, ("Accepting operation type %d from module %s\n", ops[i].type, vfs_object));
00184                 vfs_set_operation(&conn->vfs, ops[i].type, handle, ops[i].op);
00185         }
00186 
00187         SAFE_FREE(module_name);
00188         return True;
00189 }
00190 
00191 /*****************************************************************
00192  Allow VFS modules to extend files_struct with VFS-specific state.
00193  This will be ok for small numbers of extensions, but might need to
00194  be refactored if it becomes more widely used.
00195 ******************************************************************/
00196 
00197 #define EXT_DATA_AREA(e) ((uint8 *)(e) + sizeof(struct vfs_fsp_data))
00198 
00199 void *vfs_add_fsp_extension_notype(vfs_handle_struct *handle, files_struct *fsp, size_t ext_size)
00200 {
00201         struct vfs_fsp_data *ext;
00202         void * ext_data;
00203 
00204         /* Prevent VFS modules adding multiple extensions. */
00205         if ((ext_data = vfs_fetch_fsp_extension(handle, fsp))) {
00206                 return ext_data;
00207         }
00208 
00209         ext = (struct vfs_fsp_data *)TALLOC_ZERO(
00210                 handle->conn->mem_ctx, sizeof(struct vfs_fsp_data) + ext_size);
00211         if (ext == NULL) {
00212                 return NULL;
00213         }
00214 
00215         ext->owner = handle;
00216         ext->next = fsp->vfs_extension;
00217         fsp->vfs_extension = ext;
00218         return EXT_DATA_AREA(ext);
00219 }
00220 
00221 void vfs_remove_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
00222 {
00223         struct vfs_fsp_data *curr;
00224         struct vfs_fsp_data *prev;
00225 
00226         for (curr = fsp->vfs_extension, prev = NULL;
00227              curr;
00228              prev = curr, curr = curr->next) {
00229                 if (curr->owner == handle) {
00230                     if (prev) {
00231                             prev->next = curr->next;
00232                     } else {
00233                             fsp->vfs_extension = curr->next;
00234                     }
00235                     TALLOC_FREE(curr);
00236                     return;
00237                 }
00238         }
00239 }
00240 
00241 void *vfs_fetch_fsp_extension(vfs_handle_struct *handle, files_struct *fsp)
00242 {
00243         struct vfs_fsp_data *head;
00244 
00245         for (head = fsp->vfs_extension; head; head = head->next) {
00246                 if (head->owner == handle) {
00247                         return EXT_DATA_AREA(head);
00248                 }
00249         }
00250 
00251         return NULL;
00252 }
00253 
00254 #undef EXT_DATA_AREA
00255 
00256 /*****************************************************************
00257  Generic VFS init.
00258 ******************************************************************/
00259 
00260 BOOL smbd_vfs_init(connection_struct *conn)
00261 {
00262         const char **vfs_objects;
00263         unsigned int i = 0;
00264         int j = 0;
00265         
00266         /* Normal share - initialise with disk access functions */
00267         vfs_init_default(conn);
00268         vfs_objects = lp_vfs_objects(SNUM(conn));
00269 
00270         /* Override VFS functions if 'vfs object' was not specified*/
00271         if (!vfs_objects || !vfs_objects[0])
00272                 return True;
00273         
00274         for (i=0; vfs_objects[i] ;) {
00275                 i++;
00276         }
00277 
00278         for (j=i-1; j >= 0; j--) {
00279                 if (!vfs_init_custom(conn, vfs_objects[j])) {
00280                         DEBUG(0, ("smbd_vfs_init: vfs_init_custom failed for %s\n", vfs_objects[j]));
00281                         return False;
00282                 }
00283         }
00284         return True;
00285 }
00286 
00287 /*******************************************************************
00288  Check if directory exists.
00289 ********************************************************************/
00290 
00291 BOOL vfs_directory_exist(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *st)
00292 {
00293         SMB_STRUCT_STAT st2;
00294         BOOL ret;
00295 
00296         if (!st)
00297                 st = &st2;
00298 
00299         if (SMB_VFS_STAT(conn,dname,st) != 0)
00300                 return(False);
00301 
00302         ret = S_ISDIR(st->st_mode);
00303         if(!ret)
00304                 errno = ENOTDIR;
00305 
00306         return ret;
00307 }
00308 
00309 /*******************************************************************
00310  Check if an object exists in the vfs.
00311 ********************************************************************/
00312 
00313 BOOL vfs_object_exist(connection_struct *conn,const char *fname,SMB_STRUCT_STAT *sbuf)
00314 {
00315         SMB_STRUCT_STAT st;
00316 
00317         if (!sbuf)
00318                 sbuf = &st;
00319 
00320         ZERO_STRUCTP(sbuf);
00321 
00322         if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
00323                 return(False);
00324         return True;
00325 }
00326 
00327 /*******************************************************************
00328  Check if a file exists in the vfs.
00329 ********************************************************************/
00330 
00331 BOOL vfs_file_exist(connection_struct *conn, const char *fname,SMB_STRUCT_STAT *sbuf)
00332 {
00333         SMB_STRUCT_STAT st;
00334 
00335         if (!sbuf)
00336                 sbuf = &st;
00337 
00338         ZERO_STRUCTP(sbuf);
00339 
00340         if (SMB_VFS_STAT(conn,fname,sbuf) == -1)
00341                 return False;
00342         return(S_ISREG(sbuf->st_mode));
00343 }
00344 
00345 /****************************************************************************
00346  Read data from fsp on the vfs. (note: EINTR re-read differs from vfs_write_data)
00347 ****************************************************************************/
00348 
00349 ssize_t vfs_read_data(files_struct *fsp, char *buf, size_t byte_count)
00350 {
00351         size_t total=0;
00352 
00353         while (total < byte_count)
00354         {
00355                 ssize_t ret = SMB_VFS_READ(fsp, fsp->fh->fd, buf + total,
00356                                         byte_count - total);
00357 
00358                 if (ret == 0) return total;
00359                 if (ret == -1) {
00360                         if (errno == EINTR)
00361                                 continue;
00362                         else
00363                                 return -1;
00364                 }
00365                 total += ret;
00366         }
00367         return (ssize_t)total;
00368 }
00369 
00370 ssize_t vfs_pread_data(files_struct *fsp, char *buf,
00371                 size_t byte_count, SMB_OFF_T offset)
00372 {
00373         size_t total=0;
00374 
00375         while (total < byte_count)
00376         {
00377                 ssize_t ret = SMB_VFS_PREAD(fsp, fsp->fh->fd, buf + total,
00378                                         byte_count - total, offset + total);
00379 
00380                 if (ret == 0) return total;
00381                 if (ret == -1) {
00382                         if (errno == EINTR)
00383                                 continue;
00384                         else
00385                                 return -1;
00386                 }
00387                 total += ret;
00388         }
00389         return (ssize_t)total;
00390 }
00391 
00392 /****************************************************************************
00393  Write data to a fd on the vfs.
00394 ****************************************************************************/
00395 
00396 ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
00397 {
00398         size_t total=0;
00399         ssize_t ret;
00400 
00401         while (total < N) {
00402                 ret = SMB_VFS_WRITE(fsp,fsp->fh->fd,buffer + total,N - total);
00403 
00404                 if (ret == -1)
00405                         return -1;
00406                 if (ret == 0)
00407                         return total;
00408 
00409                 total += ret;
00410         }
00411         return (ssize_t)total;
00412 }
00413 
00414 ssize_t vfs_pwrite_data(files_struct *fsp,const char *buffer,
00415                 size_t N, SMB_OFF_T offset)
00416 {
00417         size_t total=0;
00418         ssize_t ret;
00419 
00420         while (total < N) {
00421                 ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, buffer + total,
00422                                 N - total, offset + total);
00423 
00424                 if (ret == -1)
00425                         return -1;
00426                 if (ret == 0)
00427                         return total;
00428 
00429                 total += ret;
00430         }
00431         return (ssize_t)total;
00432 }
00433 /****************************************************************************
00434  An allocate file space call using the vfs interface.
00435  Allocates space for a file from a filedescriptor.
00436  Returns 0 on success, -1 on failure.
00437 ****************************************************************************/
00438 
00439 int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len)
00440 {
00441         int ret;
00442         SMB_STRUCT_STAT st;
00443         connection_struct *conn = fsp->conn;
00444         SMB_BIG_UINT space_avail;
00445         SMB_BIG_UINT bsize,dfree,dsize;
00446 
00447         release_level_2_oplocks_on_change(fsp);
00448 
00449         /*
00450          * Actually try and commit the space on disk....
00451          */
00452 
00453         DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
00454 
00455         if (((SMB_OFF_T)len) < 0) {
00456                 DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name ));
00457                 errno = EINVAL;
00458                 return -1;
00459         }
00460 
00461         ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
00462         if (ret == -1)
00463                 return ret;
00464 
00465         if (len == (SMB_BIG_UINT)st.st_size)
00466                 return 0;
00467 
00468         if (len < (SMB_BIG_UINT)st.st_size) {
00469                 /* Shrink - use ftruncate. */
00470 
00471                 DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
00472                                 fsp->fsp_name, (double)st.st_size ));
00473 
00474                 flush_write_cache(fsp, SIZECHANGE_FLUSH);
00475                 if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, (SMB_OFF_T)len)) != -1) {
00476                         set_filelen_write_cache(fsp, len);
00477                 }
00478                 return ret;
00479         }
00480 
00481         /* Grow - we need to test if we have enough space. */
00482 
00483         if (!lp_strict_allocate(SNUM(fsp->conn)))
00484                 return 0;
00485 
00486         len -= st.st_size;
00487         len /= 1024; /* Len is now number of 1k blocks needed. */
00488         space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize);
00489         if (space_avail == (SMB_BIG_UINT)-1) {
00490                 return -1;
00491         }
00492 
00493         DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n",
00494                         fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail ));
00495 
00496         if (len > space_avail) {
00497                 errno = ENOSPC;
00498                 return -1;
00499         }
00500 
00501         return 0;
00502 }
00503 
00504 /****************************************************************************
00505  A vfs set_filelen call.
00506  set the length of a file from a filedescriptor.
00507  Returns 0 on success, -1 on failure.
00508 ****************************************************************************/
00509 
00510 int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
00511 {
00512         int ret;
00513 
00514         release_level_2_oplocks_on_change(fsp);
00515         DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len));
00516         flush_write_cache(fsp, SIZECHANGE_FLUSH);
00517         if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1) {
00518                 set_filelen_write_cache(fsp, len);
00519                 notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
00520                              FILE_NOTIFY_CHANGE_SIZE
00521                              | FILE_NOTIFY_CHANGE_ATTRIBUTES,
00522                              fsp->fsp_name);
00523         }
00524 
00525         return ret;
00526 }
00527 
00528 /****************************************************************************
00529  A vfs fill sparse call.
00530  Writes zeros from the end of file to len, if len is greater than EOF.
00531  Used only by strict_sync.
00532  Returns 0 on success, -1 on failure.
00533 ****************************************************************************/
00534 
00535 static char *sparse_buf;
00536 #define SPARSE_BUF_WRITE_SIZE (32*1024)
00537 
00538 int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len)
00539 {
00540         int ret;
00541         SMB_STRUCT_STAT st;
00542         SMB_OFF_T offset;
00543         size_t total;
00544         size_t num_to_write;
00545         ssize_t pwrite_ret;
00546 
00547         release_level_2_oplocks_on_change(fsp);
00548         ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st);
00549         if (ret == -1) {
00550                 return ret;
00551         }
00552 
00553         if (len <= st.st_size) {
00554                 return 0;
00555         }
00556 
00557         DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n",
00558                 fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size)));
00559 
00560         flush_write_cache(fsp, SIZECHANGE_FLUSH);
00561 
00562         if (!sparse_buf) {
00563                 sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE);
00564                 if (!sparse_buf) {
00565                         errno = ENOMEM;
00566                         return -1;
00567                 }
00568         }
00569 
00570         offset = st.st_size;
00571         num_to_write = len - st.st_size;
00572         total = 0;
00573 
00574         while (total < num_to_write) {
00575                 size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total));
00576 
00577                 pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, sparse_buf, curr_write_size, offset + total);
00578                 if (pwrite_ret == -1) {
00579                         DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n",
00580                                 fsp->fsp_name, strerror(errno) ));
00581                         return -1;
00582                 }
00583                 if (pwrite_ret == 0) {
00584                         return 0;
00585                 }
00586 
00587                 total += pwrite_ret;
00588         }
00589 
00590         set_filelen_write_cache(fsp, len);
00591         return 0;
00592 }
00593 
00594 /****************************************************************************
00595  Transfer some data (n bytes) between two file_struct's.
00596 ****************************************************************************/
00597 
00598 static files_struct *in_fsp;
00599 static files_struct *out_fsp;
00600 
00601 static ssize_t read_fn(int fd, void *buf, size_t len)
00602 {
00603         return SMB_VFS_READ(in_fsp, fd, buf, len);
00604 }
00605 
00606 static ssize_t write_fn(int fd, const void *buf, size_t len)
00607 {
00608         return SMB_VFS_WRITE(out_fsp, fd, buf, len);
00609 }
00610 
00611 SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n)
00612 {
00613         in_fsp = in;
00614         out_fsp = out;
00615 
00616         return transfer_file_internal(in_fsp->fh->fd, out_fsp->fh->fd, n, read_fn, write_fn);
00617 }
00618 
00619 /*******************************************************************
00620  A vfs_readdir wrapper which just returns the file name.
00621 ********************************************************************/
00622 
00623 char *vfs_readdirname(connection_struct *conn, void *p)
00624 {
00625         SMB_STRUCT_DIRENT *ptr= NULL;
00626         char *dname;
00627 
00628         if (!p)
00629                 return(NULL);
00630 
00631         ptr = SMB_VFS_READDIR(conn, (DIR *)p);
00632         if (!ptr)
00633                 return(NULL);
00634 
00635         dname = ptr->d_name;
00636 
00637 #ifdef NEXT2
00638         if (telldir(p) < 0)
00639                 return(NULL);
00640 #endif
00641 
00642 #ifdef HAVE_BROKEN_READDIR_NAME
00643         /* using /usr/ucb/cc is BAD */
00644         dname = dname - 2;
00645 #endif
00646 
00647         return(dname);
00648 }
00649 
00650 /*******************************************************************
00651  A wrapper for vfs_chdir().
00652 ********************************************************************/
00653 
00654 int vfs_ChDir(connection_struct *conn, const char *path)
00655 {
00656         int res;
00657         static pstring LastDir="";
00658 
00659         if (strcsequal(path,"."))
00660                 return(0);
00661 
00662         if (*path == '/' && strcsequal(LastDir,path))
00663                 return(0);
00664 
00665         DEBUG(4,("vfs_ChDir to %s\n",path));
00666 
00667         res = SMB_VFS_CHDIR(conn,path);
00668         if (!res)
00669                 pstrcpy(LastDir,path);
00670         return(res);
00671 }
00672 
00673 /* number of list structures for a caching GetWd function. */
00674 #define MAX_GETWDCACHE (50)
00675 
00676 static struct {
00677         SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */
00678         SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */
00679         char *dos_path; /* The pathname in DOS format. */
00680         BOOL valid;
00681 } ino_list[MAX_GETWDCACHE];
00682 
00683 extern BOOL use_getwd_cache;
00684 
00685 /****************************************************************************
00686  Prompte a ptr (to make it recently used)
00687 ****************************************************************************/
00688 
00689 static void array_promote(char *array,int elsize,int element)
00690 {
00691         char *p;
00692         if (element == 0)
00693                 return;
00694 
00695         p = (char *)SMB_MALLOC(elsize);
00696 
00697         if (!p) {
00698                 DEBUG(5,("array_promote: malloc fail\n"));
00699                 return;
00700         }
00701 
00702         memcpy(p,array + element * elsize, elsize);
00703         memmove(array + elsize,array,elsize*element);
00704         memcpy(array,p,elsize);
00705         SAFE_FREE(p);
00706 }
00707 
00708 /*******************************************************************
00709  Return the absolute current directory path - given a UNIX pathname.
00710  Note that this path is returned in DOS format, not UNIX
00711  format. Note this can be called with conn == NULL.
00712 ********************************************************************/
00713 
00714 char *vfs_GetWd(connection_struct *conn, char *path)
00715 {
00716         pstring s;
00717         static BOOL getwd_cache_init = False;
00718         SMB_STRUCT_STAT st, st2;
00719         int i;
00720 
00721         *s = 0;
00722 
00723         if (!use_getwd_cache)
00724                 return(SMB_VFS_GETWD(conn,path));
00725 
00726         /* init the cache */
00727         if (!getwd_cache_init) {
00728                 getwd_cache_init = True;
00729                 for (i=0;i<MAX_GETWDCACHE;i++) {
00730                         string_set(&ino_list[i].dos_path,"");
00731                         ino_list[i].valid = False;
00732                 }
00733         }
00734 
00735         /*  Get the inode of the current directory, if this doesn't work we're
00736                 in trouble :-) */
00737 
00738         if (SMB_VFS_STAT(conn, ".",&st) == -1) {
00739                 /* Known to fail for root: the directory may be
00740                  * NFS-mounted and exported with root_squash (so has no root access). */
00741                 DEBUG(1,("vfs_GetWd: couldn't stat \".\" path=%s error %s (NFS problem ?)\n", path, strerror(errno) ));
00742                 return(SMB_VFS_GETWD(conn,path));
00743         }
00744 
00745 
00746         for (i=0; i<MAX_GETWDCACHE; i++) {
00747                 if (ino_list[i].valid) {
00748 
00749                         /*  If we have found an entry with a matching inode and dev number
00750                                 then find the inode number for the directory in the cached string.
00751                                 If this agrees with that returned by the stat for the current
00752                                 directory then all is o.k. (but make sure it is a directory all
00753                                 the same...) */
00754 
00755                         if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) {
00756                                 if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) {
00757                                         if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev &&
00758                                                         (st2.st_mode & S_IFMT) == S_IFDIR) {
00759                                                 pstrcpy (path, ino_list[i].dos_path);
00760 
00761                                                 /* promote it for future use */
00762                                                 array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
00763                                                 return (path);
00764                                         } else {
00765                                                 /*  If the inode is different then something's changed,
00766                                                         scrub the entry and start from scratch. */
00767                                                 ino_list[i].valid = False;
00768                                         }
00769                                 }
00770                         }
00771                 }
00772         }
00773 
00774         /*  We don't have the information to hand so rely on traditional methods.
00775                 The very slow getcwd, which spawns a process on some systems, or the
00776                 not quite so bad getwd. */
00777 
00778         if (!SMB_VFS_GETWD(conn,s)) {
00779                 DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno)));
00780                 return (NULL);
00781         }
00782 
00783         pstrcpy(path,s);
00784 
00785         DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev));
00786 
00787         /* add it to the cache */
00788         i = MAX_GETWDCACHE - 1;
00789         string_set(&ino_list[i].dos_path,s);
00790         ino_list[i].dev = st.st_dev;
00791         ino_list[i].inode = st.st_ino;
00792         ino_list[i].valid = True;
00793 
00794         /* put it at the top of the list */
00795         array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i);
00796 
00797         return (path);
00798 }
00799 
00800 /*******************************************************************
00801  Reduce a file name, removing .. elements and checking that
00802  it is below dir in the heirachy. This uses realpath.
00803 ********************************************************************/
00804 
00805 NTSTATUS reduce_name(connection_struct *conn, const pstring fname)
00806 {
00807 #ifdef REALPATH_TAKES_NULL
00808         BOOL free_resolved_name = True;
00809 #else
00810 #ifdef PATH_MAX
00811         char resolved_name_buf[PATH_MAX+1];
00812 #else
00813         pstring resolved_name_buf;
00814 #endif
00815         BOOL free_resolved_name = False;
00816 #endif
00817         char *resolved_name = NULL;
00818         size_t con_path_len = strlen(conn->connectpath);
00819         char *p = NULL;
00820 
00821         DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));
00822 
00823 #ifdef REALPATH_TAKES_NULL
00824         resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);
00825 #else
00826         resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);
00827 #endif
00828 
00829         if (!resolved_name) {
00830                 switch (errno) {
00831                         case ENOTDIR:
00832                                 DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname));
00833                                 return map_nt_error_from_unix(errno);
00834                         case ENOENT:
00835                         {
00836                                 pstring tmp_fname;
00837                                 fstring last_component;
00838                                 /* Last component didn't exist. Remove it and try and canonicalise the directory. */
00839 
00840                                 pstrcpy(tmp_fname, fname);
00841                                 p = strrchr_m(tmp_fname, '/');
00842                                 if (p) {
00843                                         *p++ = '\0';
00844                                         fstrcpy(last_component, p);
00845                                 } else {
00846                                         fstrcpy(last_component, tmp_fname);
00847                                         pstrcpy(tmp_fname, ".");
00848                                 }
00849 
00850 #ifdef REALPATH_TAKES_NULL
00851                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);
00852 #else
00853                                 resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);
00854 #endif
00855                                 if (!resolved_name) {
00856                                         DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname));
00857                                         return map_nt_error_from_unix(errno);
00858                                 }
00859                                 pstrcpy(tmp_fname, resolved_name);
00860                                 pstrcat(tmp_fname, "/");
00861                                 pstrcat(tmp_fname, last_component);
00862 #ifdef REALPATH_TAKES_NULL
00863                                 SAFE_FREE(resolved_name);
00864                                 resolved_name = SMB_STRDUP(tmp_fname);
00865                                 if (!resolved_name) {
00866                                         DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname));
00867                                         return NT_STATUS_NO_MEMORY;
00868                                 }
00869 #else
00870 #ifdef PATH_MAX
00871                                 safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);
00872 #else
00873                                 pstrcpy(resolved_name_buf, tmp_fname);
00874 #endif
00875                                 resolved_name = resolved_name_buf;
00876 #endif
00877                                 break;
00878                         }
00879                         default:
00880                                 DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname));
00881                                 return map_nt_error_from_unix(errno);
00882                 }
00883         }
00884 
00885         DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name));
00886 
00887         if (*resolved_name != '/') {
00888                 DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n"));
00889                 if (free_resolved_name) {
00890                         SAFE_FREE(resolved_name);
00891                 }
00892                 return NT_STATUS_OBJECT_NAME_INVALID;
00893         }
00894 
00895         /* Check for widelinks allowed. */
00896         if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) {
00897                 DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname));
00898                 if (free_resolved_name) {
00899                         SAFE_FREE(resolved_name);
00900                 }
00901                 return NT_STATUS_ACCESS_DENIED;
00902         }
00903 
00904         /* Check if we are allowing users to follow symlinks */
00905         /* Patch from David Clerc <David.Clerc@cui.unige.ch>
00906                 University of Geneva */
00907                                                                                                                                                     
00908 #ifdef S_ISLNK
00909         if (!lp_symlinks(SNUM(conn))) {
00910                 SMB_STRUCT_STAT statbuf;
00911                 if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) &&
00912                                 (S_ISLNK(statbuf.st_mode)) ) {
00913                         if (free_resolved_name) {
00914                                 SAFE_FREE(resolved_name);
00915                         }
00916                         DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name));
00917                         return NT_STATUS_ACCESS_DENIED;
00918                 }
00919         }
00920 #endif
00921 
00922         DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name));
00923         if (free_resolved_name) {
00924                 SAFE_FREE(resolved_name);
00925         }
00926         return NT_STATUS_OK;
00927 }

Sambaに対してSat Aug 29 21:23:26 2009に生成されました。  doxygen 1.4.7