*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
+#include "smbd/smbd.h"
+#include "ntioctl.h"
+#include "source3/smbd/dir.h"
/*
Please read the VFS module Samba-HowTo-Collection.
struct dirent *dirs;
} shadow_copy_Dir;
-static BOOL shadow_copy_match_name(const char *name)
+static bool shadow_copy_match_name(const char *name)
{
if (strncmp(SHADOW_COPY_PREFIX,name, sizeof(SHADOW_COPY_PREFIX)-1)==0 &&
(strlen(SHADOW_COPY_SAMPLE) == strlen(name))) {
return False;
}
-static DIR *shadow_copy_opendir(vfs_handle_struct *handle, connection_struct *conn, const char *fname)
+static DIR *shadow_copy_fdopendir(vfs_handle_struct *handle, files_struct *fsp, const char *mask, uint32_t attr)
{
shadow_copy_Dir *dirp;
- DIR *p = SMB_VFS_NEXT_OPENDIR(handle,conn,fname);
+ DIR *p = SMB_VFS_NEXT_FDOPENDIR(handle,fsp,mask,attr);
if (!p) {
- DEBUG(0,("shadow_copy_opendir: SMB_VFS_NEXT_OPENDIR() failed for [%s]\n",fname));
+ DEBUG(10,("shadow_copy_opendir: SMB_VFS_NEXT_FDOPENDIR() failed for [%s]\n",
+ smb_fname_str_dbg(fsp->fsp_name)));
return NULL;
}
- dirp = (shadow_copy_Dir *)malloc(sizeof(shadow_copy_Dir));
+ dirp = SMB_MALLOC_P(shadow_copy_Dir);
if (!dirp) {
- DEBUG(0,("shadow_copy_opendir: Out of memory\n"));
- SMB_VFS_NEXT_CLOSEDIR(handle,conn,p);
+ DEBUG(0,("shadow_copy_fdopendir: Out of memory\n"));
+ SMB_VFS_NEXT_CLOSEDIR(handle,p);
+ /* We have now closed the fd in fsp. */
+ fsp_set_fd(fsp, -1);
return NULL;
}
while (True) {
struct dirent *d;
- struct dirent *r;
-
- d = SMB_VFS_NEXT_READDIR(handle, conn, p);
+ d = SMB_VFS_NEXT_READDIR(handle, fsp, p);
if (d == NULL) {
break;
}
if (shadow_copy_match_name(d->d_name)) {
- DEBUG(8,("shadow_copy_opendir: hide [%s]\n",d->d_name));
+ DEBUG(8,("shadow_copy_fdopendir: hide [%s]\n",d->d_name));
continue;
}
- DEBUG(10,("shadow_copy_opendir: not hide [%s]\n",d->d_name));
+ DEBUG(10,("shadow_copy_fdopendir: not hide [%s]\n",d->d_name));
- r = (struct dirent *)Realloc(dirp->dirs,(dirp->num+1)*sizeof(struct dirent));
- if (!r) {
- DEBUG(0,("shadow_copy_opendir: Out of memory\n"));
+ dirp->dirs = SMB_REALLOC_ARRAY(dirp->dirs,struct dirent, dirp->num+1);
+ if (!dirp->dirs) {
+ DEBUG(0,("shadow_copy_fdopendir: Out of memory\n"));
break;
}
- dirp->dirs = r;
dirp->dirs[dirp->num++] = *d;
}
- SMB_VFS_NEXT_CLOSEDIR(handle,conn,p);
+ SMB_VFS_NEXT_CLOSEDIR(handle,p);
+ /* We have now closed the fd in fsp. */
+ fsp_set_fd(fsp, -1);
return((DIR *)dirp);
}
-struct dirent *shadow_copy_readdir(vfs_handle_struct *handle, connection_struct *conn, DIR *_dirp)
+static struct dirent *shadow_copy_readdir(vfs_handle_struct *handle,
+ struct files_struct *dirfsp,
+ DIR *_dirp)
{
shadow_copy_Dir *dirp = (shadow_copy_Dir *)_dirp;
return NULL;
}
-int shadow_copy_closedir(vfs_handle_struct *handle, connection_struct *conn, DIR *_dirp)
+static void shadow_copy_rewinddir(struct vfs_handle_struct *handle, DIR *_dirp)
+{
+ shadow_copy_Dir *dirp = (shadow_copy_Dir *)_dirp;
+ dirp->pos = 0 ;
+}
+
+static int shadow_copy_closedir(vfs_handle_struct *handle, DIR *_dirp)
{
shadow_copy_Dir *dirp = (shadow_copy_Dir *)_dirp;
+ SAFE_FREE(dirp->dirs);
SAFE_FREE(dirp);
return 0;
}
-static int shadow_copy_get_shadow_copy_data(vfs_handle_struct *handle, files_struct *fsp, SHADOW_COPY_DATA *shadow_copy_data, BOOL labels)
+static int shadow_copy_get_shadow_copy_data(vfs_handle_struct *handle,
+ files_struct *fsp,
+ struct shadow_copy_data *shadow_copy_data,
+ bool labels)
{
- DIR *p = SMB_VFS_NEXT_OPENDIR(handle,fsp->conn,fsp->conn->connectpath);
-
- shadow_copy_data->num_volumes = 0;
- shadow_copy_data->labels = NULL;
+ struct smb_Dir *dir_hnd = NULL;
+ const char *dname = NULL;
+ char *talloced = NULL;
+ NTSTATUS status;
+ struct smb_filename *smb_fname = synthetic_smb_fname(talloc_tos(),
+ fsp->conn->connectpath,
+ NULL,
+ NULL,
+ 0,
+ 0);
+ if (smb_fname == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
- if (!p) {
- DEBUG(0,("shadow_copy_get_shadow_copy_data: SMB_VFS_NEXT_OPENDIR() failed for [%s]\n",fsp->conn->connectpath));
+ status = OpenDir(talloc_tos(),
+ handle->conn,
+ smb_fname,
+ NULL,
+ 0,
+ &dir_hnd);
+ TALLOC_FREE(smb_fname);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_ERR("OpenDir() failed for [%s]\n", fsp->conn->connectpath);
+ errno = map_errno_from_nt_status(status);
return -1;
}
+ shadow_copy_data->num_volumes = 0;
+ shadow_copy_data->labels = NULL;
+
while (True) {
SHADOW_COPY_LABEL *tlabels;
- struct dirent *d;
+ int ret;
- d = SMB_VFS_NEXT_READDIR(handle, fsp->conn, p);
- if (d == NULL) {
+ dname = ReadDirName(dir_hnd, &talloced);
+ if (dname == NULL) {
break;
}
/* */
- if (!shadow_copy_match_name(d->d_name)) {
- DEBUG(10,("shadow_copy_get_shadow_copy_data: ignore [%s]\n",d->d_name));
+ if (!shadow_copy_match_name(dname)) {
+ DBG_DEBUG("ignore [%s]\n", dname);
+ TALLOC_FREE(talloced);
continue;
}
- DEBUG(7,("shadow_copy_get_shadow_copy_data: not ignore [%s]\n",d->d_name));
+ DBG_DEBUG("not ignore [%s]\n", dname);
if (!labels) {
shadow_copy_data->num_volumes++;
+ TALLOC_FREE(talloced);
continue;
}
- tlabels = (SHADOW_COPY_LABEL *)talloc_realloc(shadow_copy_data->mem_ctx,
+ tlabels = (SHADOW_COPY_LABEL *)TALLOC_REALLOC(shadow_copy_data,
shadow_copy_data->labels,
(shadow_copy_data->num_volumes+1)*sizeof(SHADOW_COPY_LABEL));
if (tlabels == NULL) {
DEBUG(0,("shadow_copy_get_shadow_copy_data: Out of memory\n"));
- SMB_VFS_NEXT_CLOSEDIR(handle,fsp->conn,p);
+ TALLOC_FREE(talloced);
+ TALLOC_FREE(dir_hnd);
return -1;
}
- snprintf(tlabels[shadow_copy_data->num_volumes++], sizeof(*tlabels), "%s",d->d_name);
+ ret = strlcpy(tlabels[shadow_copy_data->num_volumes], dname,
+ sizeof(tlabels[shadow_copy_data->num_volumes]));
+ if (ret != sizeof(tlabels[shadow_copy_data->num_volumes]) - 1) {
+ DBG_ERR("malformed label %s\n", dname);
+ TALLOC_FREE(talloced);
+ TALLOC_FREE(dir_hnd);
+ return -1;
+ }
+ shadow_copy_data->num_volumes++;
shadow_copy_data->labels = tlabels;
+ TALLOC_FREE(talloced);
}
- SMB_VFS_NEXT_CLOSEDIR(handle,fsp->conn,p);
+ TALLOC_FREE(dir_hnd);
return 0;
}
-/* VFS operations structure */
-
-static vfs_op_tuple shadow_copy_ops[] = {
- {SMB_VFS_OP(shadow_copy_opendir), SMB_VFS_OP_OPENDIR, SMB_VFS_LAYER_TRANSPARENT},
- {SMB_VFS_OP(shadow_copy_readdir), SMB_VFS_OP_READDIR, SMB_VFS_LAYER_TRANSPARENT},
- {SMB_VFS_OP(shadow_copy_closedir), SMB_VFS_OP_CLOSEDIR, SMB_VFS_LAYER_TRANSPARENT},
-
- {SMB_VFS_OP(shadow_copy_get_shadow_copy_data), SMB_VFS_OP_GET_SHADOW_COPY_DATA,SMB_VFS_LAYER_OPAQUE},
-
- {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+static struct vfs_fn_pointers vfs_shadow_copy_fns = {
+ .fdopendir_fn = shadow_copy_fdopendir,
+ .readdir_fn = shadow_copy_readdir,
+ .rewind_dir_fn = shadow_copy_rewinddir,
+ .closedir_fn = shadow_copy_closedir,
+ .get_shadow_copy_data_fn = shadow_copy_get_shadow_copy_data,
};
-NTSTATUS vfs_shadow_copy_init(void)
+static_decl_vfs;
+NTSTATUS vfs_shadow_copy_init(TALLOC_CTX *ctx)
{
- NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "shadow_copy", shadow_copy_ops);
+ NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
+ "shadow_copy", &vfs_shadow_copy_fns);
if (!NT_STATUS_IS_OK(ret))
return ret;