1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <synch.h> 27 #include <pthread.h> 28 #include <unistd.h> 29 #include <string.h> 30 #include <strings.h> 31 #include <sys/errno.h> 32 33 #include <smbsrv/libsmb.h> 34 #include <smbsrv/libsmbrdr.h> 35 #include <smbsrv/libsmbns.h> 36 #include <smbsrv/libmlsvc.h> 37 38 #include <smbsrv/smbinfo.h> 39 #include <smbsrv/ntstatus.h> 40 #include "smbd.h" 41 42 #include <libzfs.h> 43 44 /* 45 * This file supports three basic functions that all use the 46 * the zfs_iter_snapshots function to get the snapshot info 47 * from ZFS. If the filesystem is not ZFS, the an error is sent 48 * to the caller (door functions in this case) with the count of 49 * zero in the case of smbd_vss_get_count. Each function 50 * is expecting a path that is the root of the dataset. 51 * The basic idea is to define a structure for the data and 52 * an iterator function that will be called for every snapshot 53 * in the dataset that was opened. The iterator function gets 54 * a zfs_handle_t(that needs to be closed) for the snapshot 55 * and a pointer to the structure of data defined passed to it. 56 * If the iterator function returns a non-zero value, no more 57 * snapshots will be processed. There is no guarantee in the 58 * order in which the snapshots are processed. 59 * 60 * The structure of this file is: 61 * Three structures that are used between the iterator functions 62 * and "main" functions 63 * The 3 "main" functions 64 * Support functions 65 * The 3 iterator functions 66 */ 67 68 static void smbd_vss_time2gmttoken(time_t time, char *gmttoken); 69 static int smbd_vss_cmp_time(const void *a, const void *b); 70 static int smbd_vss_iterate_count(zfs_handle_t *zhp, void *data); 71 static int smbd_vss_iterate_get_uint64_date(zfs_handle_t *zhp, void *data); 72 static int smbd_vss_iterate_map_gmttoken(zfs_handle_t *zhp, void *data); 73 74 typedef struct smbd_vss_count { 75 int vc_count; 76 } smbd_vss_count_t; 77 78 /* 79 * gd_count how many @GMT tokens are expected 80 * gd_return_count how many @GMT tokens are being returned 81 * gd_gmt_array array of the @GMT token with max size of gd_count 82 */ 83 typedef struct smbd_vss_get_uint64_date { 84 int gd_count; 85 int gd_return_count; 86 uint64_t *gd_gmt_array; 87 } smbd_vss_get_uint64_date_t; 88 89 typedef struct smbd_vss_map_gmttoken { 90 char *mg_gmttoken; 91 char *mg_snapname; 92 } smbd_vss_map_gmttoken_t; 93 94 95 /* 96 * path - path of the dataset 97 * count - return value of the number of snapshots for the dataset 98 */ 99 int 100 smbd_vss_get_count(char *path, uint32_t *count) 101 { 102 libzfs_handle_t *hdl; 103 zfs_handle_t *zfshp; 104 smbd_vss_count_t vss_count; 105 106 bzero(&vss_count, sizeof (smbd_vss_count_t)); 107 108 *count = 0; 109 110 /* ZFS doesn't want a leading slash for the path */ 111 path += strspn(path, "/"); 112 113 hdl = libzfs_init(); 114 115 if ((zfshp = zfs_open(hdl, path, ZFS_TYPE_DATASET)) == NULL) { 116 libzfs_fini(hdl); 117 return (-1); 118 } 119 120 (void) zfs_iter_snapshots(zfshp, smbd_vss_iterate_count, 121 (void *)&vss_count); 122 123 *count = vss_count.vc_count; 124 zfs_close(zfshp); 125 libzfs_fini(hdl); 126 return (0); 127 } 128 129 /* 130 * path - is the path of the dataset 131 * count - is the maxium number of GMT tokens allowed to be returned 132 * return_count - is how many should be returned 133 * num_gmttokens - how many gmttokens in gmttokenp (0 if error) 134 * gmttokenp - array of @GMT tokens (even if zero, elements still need 135 * to be freed) 136 */ 137 138 void 139 smbd_vss_get_snapshots(char *path, uint32_t count, uint32_t *return_count, 140 uint32_t *num_gmttokens, char **gmttokenp) 141 { 142 libzfs_handle_t *hdl; 143 zfs_handle_t *zfshp; 144 smbd_vss_get_uint64_date_t vss_uint64_date; 145 int i; 146 uint64_t *timep; 147 148 *return_count = 0; 149 *num_gmttokens = 0; 150 151 /* ZFS doesn't want a leading slash for the path */ 152 path += strspn(path, "/"); 153 154 hdl = libzfs_init(); 155 156 if ((zfshp = zfs_open(hdl, path, ZFS_TYPE_DATASET)) == NULL) { 157 libzfs_fini(hdl); 158 return; 159 } 160 161 vss_uint64_date.gd_count = count; 162 vss_uint64_date.gd_return_count = 0; 163 vss_uint64_date.gd_gmt_array = malloc(count * sizeof (uint64_t)); 164 165 if (vss_uint64_date.gd_gmt_array != NULL) { 166 167 (void) zfs_iter_snapshots(zfshp, 168 smbd_vss_iterate_get_uint64_date, 169 (void *)&vss_uint64_date); 170 171 *num_gmttokens = vss_uint64_date.gd_return_count; 172 *return_count = vss_uint64_date.gd_return_count; 173 174 if (vss_uint64_date.gd_return_count <= count) { 175 /* we need to sort them as the client & zfs does not */ 176 qsort((char *)vss_uint64_date.gd_gmt_array, 177 vss_uint64_date.gd_return_count, 178 sizeof (uint64_t), smbd_vss_cmp_time); 179 180 timep = vss_uint64_date.gd_gmt_array; 181 182 for (i = 0; i < vss_uint64_date.gd_return_count; i++) { 183 184 *gmttokenp = malloc(SMB_VSS_GMT_SIZE); 185 186 if (*gmttokenp) { 187 smbd_vss_time2gmttoken(*timep, 188 *gmttokenp); 189 } else { 190 vss_uint64_date.gd_return_count = 0; 191 } 192 193 timep++; 194 gmttokenp++; 195 } 196 } 197 198 free(vss_uint64_date.gd_gmt_array); 199 } 200 201 zfs_close(zfshp); 202 libzfs_fini(hdl); 203 } 204 205 /* 206 * path - path of the dataset for the operation 207 * gmttoken - the @GMT token to be looked up 208 * snapname - the snapshot name to be returned 209 * 210 * Here we are going to get the snapshot name from the @GMT token 211 * The snapname returned by ZFS is : <dataset name>@<snapshot name> 212 * So we are going to make sure there is the @ symbol in 213 * the right place and then just return the snapshot name 214 */ 215 int 216 smbd_vss_map_gmttoken(char *path, char *gmttoken, char *snapname) 217 { 218 libzfs_handle_t *hdl; 219 zfs_handle_t *zfshp; 220 smbd_vss_map_gmttoken_t vss_map_gmttoken; 221 char *zsnap, *lsnap; 222 223 224 vss_map_gmttoken.mg_gmttoken = gmttoken; 225 vss_map_gmttoken.mg_snapname = snapname; 226 *snapname = '\0'; 227 228 /* ZFS doesn't want a leading slash for the path */ 229 path += strspn(path, "/"); 230 231 hdl = libzfs_init(); 232 233 if ((zfshp = zfs_open(hdl, path, ZFS_TYPE_DATASET)) == NULL) { 234 libzfs_fini(hdl); 235 return (-1); 236 } 237 238 (void) zfs_iter_snapshots(zfshp, smbd_vss_iterate_map_gmttoken, 239 (void *)&vss_map_gmttoken); 240 241 /* compare the zfs snapshot name and the local snap name */ 242 zsnap = snapname; 243 lsnap = path; 244 while ((*lsnap != '\0') && (*zsnap != '\0') && (*lsnap == *zsnap)) { 245 zsnap++; 246 lsnap++; 247 } 248 249 /* Now we should be passed the dataset name */ 250 if ((*zsnap == '@') && (*lsnap == '\0')) { 251 zsnap++; 252 (void) strlcpy(snapname, zsnap, MAXPATHLEN); 253 } else { 254 *snapname = '\0'; 255 } 256 257 zfs_close(zfshp); 258 libzfs_fini(hdl); 259 return (0); 260 } 261 262 static void 263 smbd_vss_time2gmttoken(time_t time, char *gmttoken) 264 { 265 struct tm t; 266 267 (void) gmtime_r(&time, &t); 268 269 (void) strftime(gmttoken, SMB_VSS_GMT_SIZE, 270 "@GMT-%Y.%m.%d-%H.%M.%S", &t); 271 } 272 273 static int 274 smbd_vss_cmp_time(const void *a, const void *b) 275 { 276 if (*(uint64_t *)a < *(uint64_t *)b) 277 return (1); 278 if (*(uint64_t *)a == *(uint64_t *)b) 279 return (0); 280 return (-1); 281 } 282 283 static int 284 smbd_vss_iterate_count(zfs_handle_t *zhp, void *data) 285 { 286 smbd_vss_count_t *vss_data; 287 vss_data = data; 288 vss_data->vc_count++; 289 /* the zfslib expects us to close it */ 290 zfs_close(zhp); 291 return (0); 292 } 293 294 static int 295 smbd_vss_iterate_get_uint64_date(zfs_handle_t *zhp, void *data) 296 { 297 smbd_vss_get_uint64_date_t *vss_data; 298 299 vss_data = data; 300 301 if (vss_data->gd_return_count < vss_data->gd_count) { 302 vss_data->gd_gmt_array[vss_data->gd_return_count] = 303 zfs_prop_get_int(zhp, ZFS_PROP_CREATION); 304 } 305 306 vss_data->gd_return_count += 1; 307 /* the zfslib expects us to close it */ 308 zfs_close(zhp); 309 310 return (0); 311 } 312 313 static int 314 smbd_vss_iterate_map_gmttoken(zfs_handle_t *zhp, void *data) 315 { 316 smbd_vss_map_gmttoken_t *vss_data; 317 time_t time; 318 char gmttoken[SMB_VSS_GMT_SIZE]; 319 320 vss_data = data; 321 322 time = (time_t)zfs_prop_get_int(zhp, ZFS_PROP_CREATION); 323 smbd_vss_time2gmttoken(time, gmttoken); 324 325 if (strncmp(gmttoken, vss_data->mg_gmttoken, SMB_VSS_GMT_SIZE) 326 == 0) { 327 (void) strlcpy(vss_data->mg_snapname, zfs_get_name(zhp), 328 MAXPATHLEN); 329 330 /* the zfslib expects us to close it */ 331 zfs_close(zhp); 332 333 /* we found a match, do not process anymore snapshots */ 334 return (-1); 335 } 336 337 zfs_close(zhp); 338 339 return (0); 340 } 341