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 #include <libzfs.h> 33 34 #include <smbsrv/libsmb.h> 35 #include <smbsrv/libsmbrdr.h> 36 #include <smbsrv/libsmbns.h> 37 #include <smbsrv/libmlsvc.h> 38 #include <smbsrv/smbinfo.h> 39 #include <smbsrv/ntstatus.h> 40 #include "smbd.h" 41 42 /* 43 * This file supports three basic functions that all use the 44 * the zfs_iter_snapshots function to get the snapshot info 45 * from ZFS. If the filesystem is not ZFS, the an error is sent 46 * to the caller (door functions in this case) with the count of 47 * zero in the case of smbd_vss_get_count. Each function 48 * is expecting a path that is the root of the dataset. 49 * The basic idea is to define a structure for the data and 50 * an iterator function that will be called for every snapshot 51 * in the dataset that was opened. The iterator function gets 52 * a zfs_handle_t(that needs to be closed) for the snapshot 53 * and a pointer to the structure of data defined passed to it. 54 * If the iterator function returns a non-zero value, no more 55 * snapshots will be processed. There is no guarantee in the 56 * order in which the snapshots are processed. 57 * 58 * The structure of this file is: 59 * Three structures that are used between the iterator functions 60 * and "main" functions 61 * The 3 "main" functions 62 * Support functions 63 * The 3 iterator functions 64 */ 65 66 static void smbd_vss_time2gmttoken(time_t time, char *gmttoken); 67 static int smbd_vss_cmp_time(const void *a, const void *b); 68 static int smbd_vss_iterate_count(zfs_handle_t *zhp, void *data); 69 static int smbd_vss_iterate_get_uint64_date(zfs_handle_t *zhp, void *data); 70 static int smbd_vss_iterate_map_gmttoken(zfs_handle_t *zhp, void *data); 71 72 typedef struct smbd_vss_count { 73 int vc_count; 74 } smbd_vss_count_t; 75 76 /* 77 * gd_count how many @GMT tokens are expected 78 * gd_return_count how many @GMT tokens are being returned 79 * gd_gmt_array array of the @GMT token with max size of gd_count 80 */ 81 typedef struct smbd_vss_get_uint64_date { 82 int gd_count; 83 int gd_return_count; 84 uint64_t *gd_gmt_array; 85 } smbd_vss_get_uint64_date_t; 86 87 typedef struct smbd_vss_map_gmttoken { 88 char *mg_gmttoken; 89 char *mg_snapname; 90 } smbd_vss_map_gmttoken_t; 91 92 93 /* 94 * path - path of the dataset 95 * count - return value of the number of snapshots for the dataset 96 */ 97 int 98 smbd_vss_get_count(const char *path, uint32_t *count) 99 { 100 char dataset[MAXPATHLEN]; 101 libzfs_handle_t *libhd; 102 zfs_handle_t *zfshd; 103 smbd_vss_count_t vss_count; 104 105 bzero(&vss_count, sizeof (smbd_vss_count_t)); 106 *count = 0; 107 108 if (smb_getdataset(path, dataset, MAXPATHLEN) != 0) 109 return (-1); 110 111 if ((libhd = libzfs_init()) == NULL) 112 return (-1); 113 114 if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_DATASET)) == NULL) { 115 libzfs_fini(libhd); 116 return (-1); 117 } 118 119 (void) zfs_iter_snapshots(zfshd, smbd_vss_iterate_count, 120 (void *)&vss_count); 121 122 *count = vss_count.vc_count; 123 zfs_close(zfshd); 124 libzfs_fini(libhd); 125 return (0); 126 } 127 128 /* 129 * path - is the path of the dataset 130 * count - is the maxium number of GMT tokens allowed to be returned 131 * return_count - is how many should be returned 132 * num_gmttokens - how many gmttokens in gmttokenp (0 if error) 133 * gmttokenp - array of @GMT tokens (even if zero, elements still need 134 * to be freed) 135 */ 136 137 void 138 smbd_vss_get_snapshots(const char *path, uint32_t count, 139 uint32_t *return_count, uint32_t *num_gmttokens, char **gmttokenp) 140 { 141 char dataset[MAXPATHLEN]; 142 libzfs_handle_t *libhd; 143 zfs_handle_t *zfshd; 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 if (smb_getdataset(path, dataset, MAXPATHLEN) != 0) 152 return; 153 154 if ((libhd = libzfs_init()) == NULL) 155 return; 156 157 if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_DATASET)) == NULL) { 158 libzfs_fini(libhd); 159 return; 160 } 161 162 vss_uint64_date.gd_count = count; 163 vss_uint64_date.gd_return_count = 0; 164 vss_uint64_date.gd_gmt_array = malloc(count * sizeof (uint64_t)); 165 166 if (vss_uint64_date.gd_gmt_array != NULL) { 167 (void) zfs_iter_snapshots(zfshd, 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 /* 176 * Sort the list since neither 177 * zfs nor the client sorts it. 178 */ 179 qsort((char *)vss_uint64_date.gd_gmt_array, 180 vss_uint64_date.gd_return_count, 181 sizeof (uint64_t), smbd_vss_cmp_time); 182 183 timep = vss_uint64_date.gd_gmt_array; 184 185 for (i = 0; i < vss_uint64_date.gd_return_count; i++) { 186 *gmttokenp = malloc(SMB_VSS_GMT_SIZE); 187 188 if (*gmttokenp) { 189 smbd_vss_time2gmttoken(*timep, 190 *gmttokenp); 191 } else { 192 vss_uint64_date.gd_return_count = 0; 193 } 194 195 timep++; 196 gmttokenp++; 197 } 198 } 199 200 free(vss_uint64_date.gd_gmt_array); 201 } 202 203 zfs_close(zfshd); 204 libzfs_fini(libhd); 205 } 206 207 /* 208 * path - path of the dataset for the operation 209 * gmttoken - the @GMT token to be looked up 210 * snapname - the snapshot name to be returned 211 * 212 * Here we are going to get the snapshot name from the @GMT token 213 * The snapname returned by ZFS is : <dataset name>@<snapshot name> 214 * So we are going to make sure there is the @ symbol in 215 * the right place and then just return the snapshot name 216 */ 217 int 218 smbd_vss_map_gmttoken(const char *path, char *gmttoken, char *snapname) 219 { 220 char dataset[MAXPATHLEN]; 221 libzfs_handle_t *libhd; 222 zfs_handle_t *zfshd; 223 smbd_vss_map_gmttoken_t vss_map_gmttoken; 224 char *zsnap; 225 const char *lsnap; 226 227 vss_map_gmttoken.mg_gmttoken = gmttoken; 228 vss_map_gmttoken.mg_snapname = snapname; 229 *snapname = '\0'; 230 231 if (smb_getdataset(path, dataset, MAXPATHLEN) != 0) 232 return (-1); 233 234 if ((libhd = libzfs_init()) == NULL) 235 return (-1); 236 237 if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_DATASET)) == NULL) { 238 libzfs_fini(libhd); 239 return (-1); 240 } 241 242 (void) zfs_iter_snapshots(zfshd, smbd_vss_iterate_map_gmttoken, 243 (void *)&vss_map_gmttoken); 244 245 /* compare the zfs snapshot name and the local snap name */ 246 zsnap = snapname; 247 lsnap = dataset; 248 while ((*lsnap != '\0') && (*zsnap != '\0') && (*lsnap == *zsnap)) { 249 zsnap++; 250 lsnap++; 251 } 252 253 /* Now we should be passed the dataset name */ 254 if ((*zsnap == '@') && (*lsnap == '\0')) { 255 zsnap++; 256 (void) strlcpy(snapname, zsnap, MAXPATHLEN); 257 } else { 258 *snapname = '\0'; 259 } 260 261 zfs_close(zfshd); 262 libzfs_fini(libhd); 263 return (0); 264 } 265 266 static void 267 smbd_vss_time2gmttoken(time_t time, char *gmttoken) 268 { 269 struct tm t; 270 271 (void) gmtime_r(&time, &t); 272 273 (void) strftime(gmttoken, SMB_VSS_GMT_SIZE, 274 "@GMT-%Y.%m.%d-%H.%M.%S", &t); 275 } 276 277 static int 278 smbd_vss_cmp_time(const void *a, const void *b) 279 { 280 if (*(uint64_t *)a < *(uint64_t *)b) 281 return (1); 282 if (*(uint64_t *)a == *(uint64_t *)b) 283 return (0); 284 return (-1); 285 } 286 287 static int 288 smbd_vss_iterate_count(zfs_handle_t *zhp, void *data) 289 { 290 smbd_vss_count_t *vss_data; 291 vss_data = data; 292 vss_data->vc_count++; 293 /* libzfs expects us to close the handle */ 294 zfs_close(zhp); 295 return (0); 296 } 297 298 static int 299 smbd_vss_iterate_get_uint64_date(zfs_handle_t *zhp, void *data) 300 { 301 smbd_vss_get_uint64_date_t *vss_data; 302 303 vss_data = data; 304 305 if (vss_data->gd_return_count < vss_data->gd_count) { 306 vss_data->gd_gmt_array[vss_data->gd_return_count] = 307 zfs_prop_get_int(zhp, ZFS_PROP_CREATION); 308 } 309 310 vss_data->gd_return_count += 1; 311 /* libzfs expects us to close the handle */ 312 zfs_close(zhp); 313 return (0); 314 } 315 316 static int 317 smbd_vss_iterate_map_gmttoken(zfs_handle_t *zhp, void *data) 318 { 319 smbd_vss_map_gmttoken_t *vss_data; 320 time_t time; 321 char gmttoken[SMB_VSS_GMT_SIZE]; 322 323 vss_data = data; 324 325 time = (time_t)zfs_prop_get_int(zhp, ZFS_PROP_CREATION); 326 smbd_vss_time2gmttoken(time, gmttoken); 327 328 if (strncmp(gmttoken, vss_data->mg_gmttoken, SMB_VSS_GMT_SIZE) == 0) { 329 (void) strlcpy(vss_data->mg_snapname, zfs_get_name(zhp), 330 MAXPATHLEN); 331 332 /* libzfs expects us to close the handle */ 333 zfs_close(zhp); 334 335 /* we found a match, do not process anymore snapshots */ 336 return (-1); 337 } 338 339 /* libzfs expects us to close the handle */ 340 zfs_close(zhp); 341 return (0); 342 } 343