1/* 2 * implementation of an Shadow Copy module 3 * 4 * Copyright (C) Stefan Metzmacher 2003-2004 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 20#include "includes.h" 21 22/* 23 Please read the VFS module Samba-HowTo-Collection. 24 there's a chapter about this module 25 26 For this share 27 Z:\ 28 29 the ShadowCopies are in this directories 30 31 Z:\@GMT-2003.08.05-12.00.00\ 32 Z:\@GMT-2003.08.05-12.01.00\ 33 Z:\@GMT-2003.08.05-12.02.00\ 34 35 e.g. 36 37 Z:\testfile.txt 38 Z:\@GMT-2003.08.05-12.02.00\testfile.txt 39 40 or: 41 42 Z:\testdir\testfile.txt 43 Z:\@GMT-2003.08.05-12.02.00\testdir\testfile.txt 44 45 46 Note: Files must differ to be displayed via Windows Explorer! 47 Directories are always displayed... 48*/ 49 50static int vfs_shadow_copy_debug_level = DBGC_VFS; 51 52#undef DBGC_CLASS 53#define DBGC_CLASS vfs_shadow_copy_debug_level 54 55#define SHADOW_COPY_PREFIX "@GMT-" 56#define SHADOW_COPY_SAMPLE "@GMT-2004.02.18-15.44.00" 57 58typedef struct { 59 int pos; 60 int num; 61 SMB_STRUCT_DIRENT *dirs; 62} shadow_copy_Dir; 63 64static bool shadow_copy_match_name(const char *name) 65{ 66 if (strncmp(SHADOW_COPY_PREFIX,name, sizeof(SHADOW_COPY_PREFIX)-1)==0 && 67 (strlen(SHADOW_COPY_SAMPLE) == strlen(name))) { 68 return True; 69 } 70 71 return False; 72} 73 74static SMB_STRUCT_DIR *shadow_copy_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attr) 75{ 76 shadow_copy_Dir *dirp; 77 SMB_STRUCT_DIR *p = SMB_VFS_NEXT_OPENDIR(handle,fname,mask,attr); 78 79 if (!p) { 80 DEBUG(0,("shadow_copy_opendir: SMB_VFS_NEXT_OPENDIR() failed for [%s]\n",fname)); 81 return NULL; 82 } 83 84 dirp = SMB_MALLOC_P(shadow_copy_Dir); 85 if (!dirp) { 86 DEBUG(0,("shadow_copy_opendir: Out of memory\n")); 87 SMB_VFS_NEXT_CLOSEDIR(handle,p); 88 return NULL; 89 } 90 91 ZERO_STRUCTP(dirp); 92 93 while (True) { 94 SMB_STRUCT_DIRENT *d; 95 96 d = SMB_VFS_NEXT_READDIR(handle, p, NULL); 97 if (d == NULL) { 98 break; 99 } 100 101 if (shadow_copy_match_name(d->d_name)) { 102 DEBUG(8,("shadow_copy_opendir: hide [%s]\n",d->d_name)); 103 continue; 104 } 105 106 DEBUG(10,("shadow_copy_opendir: not hide [%s]\n",d->d_name)); 107 108 dirp->dirs = SMB_REALLOC_ARRAY(dirp->dirs,SMB_STRUCT_DIRENT, dirp->num+1); 109 if (!dirp->dirs) { 110 DEBUG(0,("shadow_copy_opendir: Out of memory\n")); 111 break; 112 } 113 114 dirp->dirs[dirp->num++] = *d; 115 } 116 117 SMB_VFS_NEXT_CLOSEDIR(handle,p); 118 return((SMB_STRUCT_DIR *)dirp); 119} 120 121static SMB_STRUCT_DIRENT *shadow_copy_readdir(vfs_handle_struct *handle, 122 SMB_STRUCT_DIR *_dirp, 123 SMB_STRUCT_STAT *sbuf) 124{ 125 shadow_copy_Dir *dirp = (shadow_copy_Dir *)_dirp; 126 127 if (dirp->pos < dirp->num) { 128 return &(dirp->dirs[dirp->pos++]); 129 } 130 131 return NULL; 132} 133 134static void shadow_copy_seekdir(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *_dirp, long offset) 135{ 136 shadow_copy_Dir *dirp = (shadow_copy_Dir *)_dirp; 137 138 if (offset < dirp->num) { 139 dirp->pos = offset ; 140 } 141} 142 143static long shadow_copy_telldir(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *_dirp) 144{ 145 shadow_copy_Dir *dirp = (shadow_copy_Dir *)_dirp; 146 return( dirp->pos ) ; 147} 148 149static void shadow_copy_rewinddir(struct vfs_handle_struct *handle, SMB_STRUCT_DIR *_dirp) 150{ 151 shadow_copy_Dir *dirp = (shadow_copy_Dir *)_dirp; 152 dirp->pos = 0 ; 153} 154 155static int shadow_copy_closedir(vfs_handle_struct *handle, SMB_STRUCT_DIR *_dirp) 156{ 157 shadow_copy_Dir *dirp = (shadow_copy_Dir *)_dirp; 158 159 SAFE_FREE(dirp->dirs); 160 SAFE_FREE(dirp); 161 162 return 0; 163} 164 165static int shadow_copy_get_shadow_copy_data(vfs_handle_struct *handle, files_struct *fsp, SHADOW_COPY_DATA *shadow_copy_data, bool labels) 166{ 167 SMB_STRUCT_DIR *p = SMB_VFS_NEXT_OPENDIR(handle,fsp->conn->connectpath,NULL,0); 168 169 shadow_copy_data->num_volumes = 0; 170 shadow_copy_data->labels = NULL; 171 172 if (!p) { 173 DEBUG(0,("shadow_copy_get_shadow_copy_data: SMB_VFS_NEXT_OPENDIR() failed for [%s]\n",fsp->conn->connectpath)); 174 return -1; 175 } 176 177 while (True) { 178 SHADOW_COPY_LABEL *tlabels; 179 SMB_STRUCT_DIRENT *d; 180 181 d = SMB_VFS_NEXT_READDIR(handle, p, NULL); 182 if (d == NULL) { 183 break; 184 } 185 186 /* */ 187 if (!shadow_copy_match_name(d->d_name)) { 188 DEBUG(10,("shadow_copy_get_shadow_copy_data: ignore [%s]\n",d->d_name)); 189 continue; 190 } 191 192 DEBUG(7,("shadow_copy_get_shadow_copy_data: not ignore [%s]\n",d->d_name)); 193 194 if (!labels) { 195 shadow_copy_data->num_volumes++; 196 continue; 197 } 198 199 tlabels = (SHADOW_COPY_LABEL *)TALLOC_REALLOC(shadow_copy_data->mem_ctx, 200 shadow_copy_data->labels, 201 (shadow_copy_data->num_volumes+1)*sizeof(SHADOW_COPY_LABEL)); 202 if (tlabels == NULL) { 203 DEBUG(0,("shadow_copy_get_shadow_copy_data: Out of memory\n")); 204 SMB_VFS_NEXT_CLOSEDIR(handle,p); 205 return -1; 206 } 207 208 snprintf(tlabels[shadow_copy_data->num_volumes++], sizeof(*tlabels), "%s",d->d_name); 209 210 shadow_copy_data->labels = tlabels; 211 } 212 213 SMB_VFS_NEXT_CLOSEDIR(handle,p); 214 return 0; 215} 216 217static struct vfs_fn_pointers vfs_shadow_copy_fns = { 218 .opendir = shadow_copy_opendir, 219 .readdir = shadow_copy_readdir, 220 .seekdir = shadow_copy_seekdir, 221 .telldir = shadow_copy_telldir, 222 .rewind_dir = shadow_copy_rewinddir, 223 .closedir = shadow_copy_closedir, 224 .get_shadow_copy_data = shadow_copy_get_shadow_copy_data, 225}; 226 227NTSTATUS vfs_shadow_copy_init(void); 228NTSTATUS vfs_shadow_copy_init(void) 229{ 230 NTSTATUS ret = smb_register_vfs(SMB_VFS_INTERFACE_VERSION, 231 "shadow_copy", &vfs_shadow_copy_fns); 232 233 if (!NT_STATUS_IS_OK(ret)) 234 return ret; 235 236 vfs_shadow_copy_debug_level = debug_add_class("shadow_copy"); 237 if (vfs_shadow_copy_debug_level == -1) { 238 vfs_shadow_copy_debug_level = DBGC_VFS; 239 DEBUG(0, ("%s: Couldn't register custom debugging class!\n", 240 "vfs_shadow_copy_init")); 241 } else { 242 DEBUG(10, ("%s: Debug class number of '%s': %d\n", 243 "vfs_shadow_copy_init","shadow_copy",vfs_shadow_copy_debug_level)); 244 } 245 246 return ret; 247} 248