vfs.c
来自「samba-3.0.22.tar.gz 编译smb服务器的源码」· C语言 代码 · 共 1,032 行 · 第 1/2 页
C
1,032 行
int vfs_allocate_file_space(files_struct *fsp, SMB_BIG_UINT len){ int ret; SMB_STRUCT_STAT st; connection_struct *conn = fsp->conn; SMB_BIG_UINT space_avail; SMB_BIG_UINT bsize,dfree,dsize; release_level_2_oplocks_on_change(fsp); /* * Actually try and commit the space on disk.... */ DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len )); if (((SMB_OFF_T)len) < 0) { DEBUG(0,("vfs_allocate_file_space: %s negative len requested.\n", fsp->fsp_name )); return -1; } ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st); if (ret == -1) return ret; if (len == (SMB_BIG_UINT)st.st_size) return 0; if (len < (SMB_BIG_UINT)st.st_size) { /* Shrink - use ftruncate. */ DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n", fsp->fsp_name, (double)st.st_size )); flush_write_cache(fsp, SIZECHANGE_FLUSH); if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, (SMB_OFF_T)len)) != -1) { set_filelen_write_cache(fsp, len); } return ret; } /* Grow - we need to test if we have enough space. */ if (!lp_strict_allocate(SNUM(fsp->conn))) return 0; len -= st.st_size; len /= 1024; /* Len is now number of 1k blocks needed. */ space_avail = get_dfree_info(conn,fsp->fsp_name,False,&bsize,&dfree,&dsize); if (space_avail == (SMB_BIG_UINT)-1) { return -1; } DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f, needed blocks = %.0f, space avail = %.0f\n", fsp->fsp_name, (double)st.st_size, (double)len, (double)space_avail )); if (len > space_avail) { errno = ENOSPC; return -1; } return 0;}/**************************************************************************** A vfs set_filelen call. set the length of a file from a filedescriptor. Returns 0 on success, -1 on failure.****************************************************************************/int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len){ int ret; release_level_2_oplocks_on_change(fsp); DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len)); flush_write_cache(fsp, SIZECHANGE_FLUSH); if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1) set_filelen_write_cache(fsp, len); return ret;}/**************************************************************************** A vfs fill sparse call. Writes zeros from the end of file to len, if len is greater than EOF. Used only by strict_sync. Returns 0 on success, -1 on failure.****************************************************************************/static char *sparse_buf;#define SPARSE_BUF_WRITE_SIZE (32*1024)int vfs_fill_sparse(files_struct *fsp, SMB_OFF_T len){ int ret; SMB_STRUCT_STAT st; SMB_OFF_T offset; size_t total; size_t num_to_write; ssize_t pwrite_ret; release_level_2_oplocks_on_change(fsp); ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st); if (ret == -1) { return ret; } if (len <= st.st_size) { return 0; } DEBUG(10,("vfs_fill_sparse: write zeros in file %s from len %.0f to len %.0f (%.0f bytes)\n", fsp->fsp_name, (double)st.st_size, (double)len, (double)(len - st.st_size))); flush_write_cache(fsp, SIZECHANGE_FLUSH); if (!sparse_buf) { sparse_buf = SMB_CALLOC_ARRAY(char, SPARSE_BUF_WRITE_SIZE); if (!sparse_buf) { errno = ENOMEM; return -1; } } offset = st.st_size; num_to_write = len - st.st_size; total = 0; while (total < num_to_write) { size_t curr_write_size = MIN(SPARSE_BUF_WRITE_SIZE, (num_to_write - total)); pwrite_ret = SMB_VFS_PWRITE(fsp, fsp->fh->fd, sparse_buf, curr_write_size, offset + total); if (pwrite_ret == -1) { DEBUG(10,("vfs_fill_sparse: SMB_VFS_PWRITE for file %s failed with error %s\n", fsp->fsp_name, strerror(errno) )); return -1; } if (pwrite_ret == 0) { return 0; } total += pwrite_ret; } set_filelen_write_cache(fsp, len); return 0;}/**************************************************************************** Transfer some data (n bytes) between two file_struct's.****************************************************************************/static files_struct *in_fsp;static files_struct *out_fsp;static ssize_t read_fn(int fd, void *buf, size_t len){ return SMB_VFS_READ(in_fsp, fd, buf, len);}static ssize_t write_fn(int fd, const void *buf, size_t len){ return SMB_VFS_WRITE(out_fsp, fd, buf, len);}SMB_OFF_T vfs_transfer_file(files_struct *in, files_struct *out, SMB_OFF_T n){ in_fsp = in; out_fsp = out; return transfer_file_internal(in_fsp->fh->fd, out_fsp->fh->fd, n, read_fn, write_fn);}/******************************************************************* A vfs_readdir wrapper which just returns the file name.********************************************************************/char *vfs_readdirname(connection_struct *conn, void *p){ SMB_STRUCT_DIRENT *ptr= NULL; char *dname; if (!p) return(NULL); ptr = SMB_VFS_READDIR(conn,p); if (!ptr) return(NULL); dname = ptr->d_name;#ifdef NEXT2 if (telldir(p) < 0) return(NULL);#endif#ifdef HAVE_BROKEN_READDIR /* using /usr/ucb/cc is BAD */ dname = dname - 2;#endif return(dname);}/******************************************************************* A wrapper for vfs_chdir().********************************************************************/int vfs_ChDir(connection_struct *conn, const char *path){ int res; static pstring LastDir=""; if (strcsequal(path,".")) return(0); if (*path == '/' && strcsequal(LastDir,path)) return(0); DEBUG(4,("vfs_ChDir to %s\n",path)); res = SMB_VFS_CHDIR(conn,path); if (!res) pstrcpy(LastDir,path); return(res);}/* number of list structures for a caching GetWd function. */#define MAX_GETWDCACHE (50)static struct { SMB_DEV_T dev; /* These *must* be compatible with the types returned in a stat() call. */ SMB_INO_T inode; /* These *must* be compatible with the types returned in a stat() call. */ char *dos_path; /* The pathname in DOS format. */ BOOL valid;} ino_list[MAX_GETWDCACHE];extern BOOL use_getwd_cache;/**************************************************************************** Prompte a ptr (to make it recently used)****************************************************************************/static void array_promote(char *array,int elsize,int element){ char *p; if (element == 0) return; p = (char *)SMB_MALLOC(elsize); if (!p) { DEBUG(5,("array_promote: malloc fail\n")); return; } memcpy(p,array + element * elsize, elsize); memmove(array + elsize,array,elsize*element); memcpy(array,p,elsize); SAFE_FREE(p);}/******************************************************************* Return the absolute current directory path - given a UNIX pathname. Note that this path is returned in DOS format, not UNIX format. Note this can be called with conn == NULL.********************************************************************/char *vfs_GetWd(connection_struct *conn, char *path){ pstring s; static BOOL getwd_cache_init = False; SMB_STRUCT_STAT st, st2; int i; *s = 0; if (!use_getwd_cache) return(SMB_VFS_GETWD(conn,path)); /* init the cache */ if (!getwd_cache_init) { getwd_cache_init = True; for (i=0;i<MAX_GETWDCACHE;i++) { string_set(&ino_list[i].dos_path,""); ino_list[i].valid = False; } } /* Get the inode of the current directory, if this doesn't work we're in trouble :-) */ if (SMB_VFS_STAT(conn, ".",&st) == -1) { /* Known to fail for root: the directory may be * NFS-mounted and exported with root_squash (so has no root access). */ DEBUG(1,("vfs_GetWd: couldn't stat \".\" path=%s error %s (NFS problem ?)\n", path, strerror(errno) )); return(SMB_VFS_GETWD(conn,path)); } for (i=0; i<MAX_GETWDCACHE; i++) { if (ino_list[i].valid) { /* If we have found an entry with a matching inode and dev number then find the inode number for the directory in the cached string. If this agrees with that returned by the stat for the current directory then all is o.k. (but make sure it is a directory all the same...) */ if (st.st_ino == ino_list[i].inode && st.st_dev == ino_list[i].dev) { if (SMB_VFS_STAT(conn,ino_list[i].dos_path,&st2) == 0) { if (st.st_ino == st2.st_ino && st.st_dev == st2.st_dev && (st2.st_mode & S_IFMT) == S_IFDIR) { pstrcpy (path, ino_list[i].dos_path); /* promote it for future use */ array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i); return (path); } else { /* If the inode is different then something's changed, scrub the entry and start from scratch. */ ino_list[i].valid = False; } } } } } /* We don't have the information to hand so rely on traditional methods. The very slow getcwd, which spawns a process on some systems, or the not quite so bad getwd. */ if (!SMB_VFS_GETWD(conn,s)) { DEBUG(0,("vfs_GetWd: SMB_VFS_GETWD call failed, errno %s\n",strerror(errno))); return (NULL); } pstrcpy(path,s); DEBUG(5,("vfs_GetWd %s, inode %.0f, dev %.0f\n",s,(double)st.st_ino,(double)st.st_dev)); /* add it to the cache */ i = MAX_GETWDCACHE - 1; string_set(&ino_list[i].dos_path,s); ino_list[i].dev = st.st_dev; ino_list[i].inode = st.st_ino; ino_list[i].valid = True; /* put it at the top of the list */ array_promote((char *)&ino_list[0],sizeof(ino_list[0]),i); return (path);}BOOL canonicalize_path(connection_struct *conn, pstring path){#ifdef REALPATH_TAKES_NULL char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL); if (!resolved_name) { return False; } pstrcpy(path, resolved_name); SAFE_FREE(resolved_name); return True;#else#ifdef PATH_MAX char resolved_name_buf[PATH_MAX+1];#else pstring resolved_name_buf;#endif char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf); if (!resolved_name) { return False; } pstrcpy(path, resolved_name); return True;#endif /* REALPATH_TAKES_NULL */}/******************************************************************* Reduce a file name, removing .. elements and checking that it is below dir in the heirachy. This uses realpath.********************************************************************/BOOL reduce_name(connection_struct *conn, const pstring fname){#ifdef REALPATH_TAKES_NULL BOOL free_resolved_name = True;#else#ifdef PATH_MAX char resolved_name_buf[PATH_MAX+1];#else pstring resolved_name_buf;#endif BOOL free_resolved_name = False;#endif char *resolved_name = NULL; size_t con_path_len = strlen(conn->connectpath); char *p = NULL; int saved_errno = errno; DEBUG(3,("reduce_name [%s] [%s]\n", fname, conn->connectpath));#ifdef REALPATH_TAKES_NULL resolved_name = SMB_VFS_REALPATH(conn,fname,NULL);#else resolved_name = SMB_VFS_REALPATH(conn,fname,resolved_name_buf);#endif if (!resolved_name) { switch (errno) { case ENOTDIR: DEBUG(3,("reduce_name: Component not a directory in getting realpath for %s\n", fname)); errno = saved_errno; return False; case ENOENT: { pstring tmp_fname; fstring last_component; /* Last component didn't exist. Remove it and try and canonicalise the directory. */ pstrcpy(tmp_fname, fname); p = strrchr_m(tmp_fname, '/'); if (p) { *p++ = '\0'; fstrcpy(last_component, p); } else { fstrcpy(last_component, tmp_fname); pstrcpy(tmp_fname, "."); }#ifdef REALPATH_TAKES_NULL resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,NULL);#else resolved_name = SMB_VFS_REALPATH(conn,tmp_fname,resolved_name_buf);#endif if (!resolved_name) { DEBUG(3,("reduce_name: couldn't get realpath for %s\n", fname)); errno = saved_errno; return False; } pstrcpy(tmp_fname, resolved_name); pstrcat(tmp_fname, "/"); pstrcat(tmp_fname, last_component);#ifdef REALPATH_TAKES_NULL SAFE_FREE(resolved_name); resolved_name = SMB_STRDUP(tmp_fname); if (!resolved_name) { DEBUG(0,("reduce_name: malloc fail for %s\n", tmp_fname)); errno = saved_errno; return False; }#else#ifdef PATH_MAX safe_strcpy(resolved_name_buf, tmp_fname, PATH_MAX);#else pstrcpy(resolved_name_buf, tmp_fname);#endif resolved_name = resolved_name_buf;#endif break; } default: DEBUG(1,("reduce_name: couldn't get realpath for %s\n", fname)); /* Don't restore the saved errno. We need to return the error that realpath caused here as it was not one of the cases we handle. JRA. */ return False; } } DEBUG(10,("reduce_name realpath [%s] -> [%s]\n", fname, resolved_name)); if (*resolved_name != '/') { DEBUG(0,("reduce_name: realpath doesn't return absolute paths !\n")); if (free_resolved_name) SAFE_FREE(resolved_name); errno = saved_errno; return False; } /* Check for widelinks allowed. */ if (!lp_widelinks(SNUM(conn)) && (strncmp(conn->connectpath, resolved_name, con_path_len) != 0)) { DEBUG(2, ("reduce_name: Bad access attempt: %s is a symlink outside the share path", fname)); if (free_resolved_name) SAFE_FREE(resolved_name); errno = EACCES; return False; } /* Check if we are allowing users to follow symlinks */ /* Patch from David Clerc <David.Clerc@cui.unige.ch> University of Geneva */ #ifdef S_ISLNK if (!lp_symlinks(SNUM(conn))) { SMB_STRUCT_STAT statbuf; if ( (SMB_VFS_LSTAT(conn,fname,&statbuf) != -1) && (S_ISLNK(statbuf.st_mode)) ) { if (free_resolved_name) SAFE_FREE(resolved_name); DEBUG(3,("reduce_name: denied: file path name %s is a symlink\n",resolved_name)); errno = EACCES; return False; } }#endif DEBUG(3,("reduce_name: %s reduced to %s\n", fname, resolved_name)); if (free_resolved_name) SAFE_FREE(resolved_name); errno = saved_errno; return(True);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?