18474SJose.Borrego@Sun.COM /* 28474SJose.Borrego@Sun.COM * CDDL HEADER START 38474SJose.Borrego@Sun.COM * 48474SJose.Borrego@Sun.COM * The contents of this file are subject to the terms of the 58474SJose.Borrego@Sun.COM * Common Development and Distribution License (the "License"). 68474SJose.Borrego@Sun.COM * You may not use this file except in compliance with the License. 78474SJose.Borrego@Sun.COM * 88474SJose.Borrego@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 98474SJose.Borrego@Sun.COM * or http://www.opensolaris.org/os/licensing. 108474SJose.Borrego@Sun.COM * See the License for the specific language governing permissions 118474SJose.Borrego@Sun.COM * and limitations under the License. 128474SJose.Borrego@Sun.COM * 138474SJose.Borrego@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 148474SJose.Borrego@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 158474SJose.Borrego@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 168474SJose.Borrego@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 178474SJose.Borrego@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 188474SJose.Borrego@Sun.COM * 198474SJose.Borrego@Sun.COM * CDDL HEADER END 208474SJose.Borrego@Sun.COM */ 218474SJose.Borrego@Sun.COM /* 228474SJose.Borrego@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 238474SJose.Borrego@Sun.COM * Use is subject to license terms. 248474SJose.Borrego@Sun.COM */ 258474SJose.Borrego@Sun.COM 268474SJose.Borrego@Sun.COM #include <synch.h> 278474SJose.Borrego@Sun.COM #include <pthread.h> 288474SJose.Borrego@Sun.COM #include <unistd.h> 298474SJose.Borrego@Sun.COM #include <string.h> 308474SJose.Borrego@Sun.COM #include <strings.h> 318474SJose.Borrego@Sun.COM #include <sys/errno.h> 32*8871Samw@Sun.COM #include <libzfs.h> 338474SJose.Borrego@Sun.COM 348474SJose.Borrego@Sun.COM #include <smbsrv/libsmb.h> 358474SJose.Borrego@Sun.COM #include <smbsrv/libsmbrdr.h> 368474SJose.Borrego@Sun.COM #include <smbsrv/libsmbns.h> 378474SJose.Borrego@Sun.COM #include <smbsrv/libmlsvc.h> 388474SJose.Borrego@Sun.COM #include <smbsrv/smbinfo.h> 398474SJose.Borrego@Sun.COM #include <smbsrv/ntstatus.h> 408474SJose.Borrego@Sun.COM #include "smbd.h" 418474SJose.Borrego@Sun.COM 428474SJose.Borrego@Sun.COM /* 438474SJose.Borrego@Sun.COM * This file supports three basic functions that all use the 448474SJose.Borrego@Sun.COM * the zfs_iter_snapshots function to get the snapshot info 458474SJose.Borrego@Sun.COM * from ZFS. If the filesystem is not ZFS, the an error is sent 468474SJose.Borrego@Sun.COM * to the caller (door functions in this case) with the count of 478474SJose.Borrego@Sun.COM * zero in the case of smbd_vss_get_count. Each function 488474SJose.Borrego@Sun.COM * is expecting a path that is the root of the dataset. 498474SJose.Borrego@Sun.COM * The basic idea is to define a structure for the data and 508474SJose.Borrego@Sun.COM * an iterator function that will be called for every snapshot 518474SJose.Borrego@Sun.COM * in the dataset that was opened. The iterator function gets 528474SJose.Borrego@Sun.COM * a zfs_handle_t(that needs to be closed) for the snapshot 538474SJose.Borrego@Sun.COM * and a pointer to the structure of data defined passed to it. 548474SJose.Borrego@Sun.COM * If the iterator function returns a non-zero value, no more 558474SJose.Borrego@Sun.COM * snapshots will be processed. There is no guarantee in the 568474SJose.Borrego@Sun.COM * order in which the snapshots are processed. 578474SJose.Borrego@Sun.COM * 588474SJose.Borrego@Sun.COM * The structure of this file is: 598474SJose.Borrego@Sun.COM * Three structures that are used between the iterator functions 608474SJose.Borrego@Sun.COM * and "main" functions 618474SJose.Borrego@Sun.COM * The 3 "main" functions 628474SJose.Borrego@Sun.COM * Support functions 638474SJose.Borrego@Sun.COM * The 3 iterator functions 648474SJose.Borrego@Sun.COM */ 658474SJose.Borrego@Sun.COM 668474SJose.Borrego@Sun.COM static void smbd_vss_time2gmttoken(time_t time, char *gmttoken); 678474SJose.Borrego@Sun.COM static int smbd_vss_cmp_time(const void *a, const void *b); 688474SJose.Borrego@Sun.COM static int smbd_vss_iterate_count(zfs_handle_t *zhp, void *data); 698474SJose.Borrego@Sun.COM static int smbd_vss_iterate_get_uint64_date(zfs_handle_t *zhp, void *data); 708474SJose.Borrego@Sun.COM static int smbd_vss_iterate_map_gmttoken(zfs_handle_t *zhp, void *data); 718474SJose.Borrego@Sun.COM 728474SJose.Borrego@Sun.COM typedef struct smbd_vss_count { 738474SJose.Borrego@Sun.COM int vc_count; 748474SJose.Borrego@Sun.COM } smbd_vss_count_t; 758474SJose.Borrego@Sun.COM 768474SJose.Borrego@Sun.COM /* 778474SJose.Borrego@Sun.COM * gd_count how many @GMT tokens are expected 788474SJose.Borrego@Sun.COM * gd_return_count how many @GMT tokens are being returned 798474SJose.Borrego@Sun.COM * gd_gmt_array array of the @GMT token with max size of gd_count 808474SJose.Borrego@Sun.COM */ 818474SJose.Borrego@Sun.COM typedef struct smbd_vss_get_uint64_date { 828474SJose.Borrego@Sun.COM int gd_count; 838474SJose.Borrego@Sun.COM int gd_return_count; 848474SJose.Borrego@Sun.COM uint64_t *gd_gmt_array; 858474SJose.Borrego@Sun.COM } smbd_vss_get_uint64_date_t; 868474SJose.Borrego@Sun.COM 878474SJose.Borrego@Sun.COM typedef struct smbd_vss_map_gmttoken { 888474SJose.Borrego@Sun.COM char *mg_gmttoken; 898474SJose.Borrego@Sun.COM char *mg_snapname; 908474SJose.Borrego@Sun.COM } smbd_vss_map_gmttoken_t; 918474SJose.Borrego@Sun.COM 928474SJose.Borrego@Sun.COM 938474SJose.Borrego@Sun.COM /* 948474SJose.Borrego@Sun.COM * path - path of the dataset 958474SJose.Borrego@Sun.COM * count - return value of the number of snapshots for the dataset 968474SJose.Borrego@Sun.COM */ 978474SJose.Borrego@Sun.COM int 98*8871Samw@Sun.COM smbd_vss_get_count(const char *path, uint32_t *count) 998474SJose.Borrego@Sun.COM { 100*8871Samw@Sun.COM char dataset[MAXPATHLEN]; 101*8871Samw@Sun.COM libzfs_handle_t *libhd; 102*8871Samw@Sun.COM zfs_handle_t *zfshd; 1038474SJose.Borrego@Sun.COM smbd_vss_count_t vss_count; 1048474SJose.Borrego@Sun.COM 1058474SJose.Borrego@Sun.COM bzero(&vss_count, sizeof (smbd_vss_count_t)); 1068474SJose.Borrego@Sun.COM *count = 0; 1078474SJose.Borrego@Sun.COM 108*8871Samw@Sun.COM if (smb_getdataset(path, dataset, MAXPATHLEN) != 0) 109*8871Samw@Sun.COM return (-1); 1108474SJose.Borrego@Sun.COM 111*8871Samw@Sun.COM if ((libhd = libzfs_init()) == NULL) 112*8871Samw@Sun.COM return (-1); 1138474SJose.Borrego@Sun.COM 114*8871Samw@Sun.COM if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_DATASET)) == NULL) { 115*8871Samw@Sun.COM libzfs_fini(libhd); 1168474SJose.Borrego@Sun.COM return (-1); 1178474SJose.Borrego@Sun.COM } 1188474SJose.Borrego@Sun.COM 119*8871Samw@Sun.COM (void) zfs_iter_snapshots(zfshd, smbd_vss_iterate_count, 1208474SJose.Borrego@Sun.COM (void *)&vss_count); 1218474SJose.Borrego@Sun.COM 1228474SJose.Borrego@Sun.COM *count = vss_count.vc_count; 123*8871Samw@Sun.COM zfs_close(zfshd); 124*8871Samw@Sun.COM libzfs_fini(libhd); 1258474SJose.Borrego@Sun.COM return (0); 1268474SJose.Borrego@Sun.COM } 1278474SJose.Borrego@Sun.COM 1288474SJose.Borrego@Sun.COM /* 1298474SJose.Borrego@Sun.COM * path - is the path of the dataset 1308474SJose.Borrego@Sun.COM * count - is the maxium number of GMT tokens allowed to be returned 1318474SJose.Borrego@Sun.COM * return_count - is how many should be returned 1328474SJose.Borrego@Sun.COM * num_gmttokens - how many gmttokens in gmttokenp (0 if error) 1338474SJose.Borrego@Sun.COM * gmttokenp - array of @GMT tokens (even if zero, elements still need 1348474SJose.Borrego@Sun.COM * to be freed) 1358474SJose.Borrego@Sun.COM */ 1368474SJose.Borrego@Sun.COM 1378474SJose.Borrego@Sun.COM void 138*8871Samw@Sun.COM smbd_vss_get_snapshots(const char *path, uint32_t count, 139*8871Samw@Sun.COM uint32_t *return_count, uint32_t *num_gmttokens, char **gmttokenp) 1408474SJose.Borrego@Sun.COM { 141*8871Samw@Sun.COM char dataset[MAXPATHLEN]; 142*8871Samw@Sun.COM libzfs_handle_t *libhd; 143*8871Samw@Sun.COM zfs_handle_t *zfshd; 1448474SJose.Borrego@Sun.COM smbd_vss_get_uint64_date_t vss_uint64_date; 1458474SJose.Borrego@Sun.COM int i; 1468474SJose.Borrego@Sun.COM uint64_t *timep; 1478474SJose.Borrego@Sun.COM 1488474SJose.Borrego@Sun.COM *return_count = 0; 1498474SJose.Borrego@Sun.COM *num_gmttokens = 0; 1508474SJose.Borrego@Sun.COM 151*8871Samw@Sun.COM if (smb_getdataset(path, dataset, MAXPATHLEN) != 0) 152*8871Samw@Sun.COM return; 1538474SJose.Borrego@Sun.COM 154*8871Samw@Sun.COM if ((libhd = libzfs_init()) == NULL) 155*8871Samw@Sun.COM return; 1568474SJose.Borrego@Sun.COM 157*8871Samw@Sun.COM if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_DATASET)) == NULL) { 158*8871Samw@Sun.COM libzfs_fini(libhd); 1598474SJose.Borrego@Sun.COM return; 1608474SJose.Borrego@Sun.COM } 1618474SJose.Borrego@Sun.COM 1628474SJose.Borrego@Sun.COM vss_uint64_date.gd_count = count; 1638474SJose.Borrego@Sun.COM vss_uint64_date.gd_return_count = 0; 1648474SJose.Borrego@Sun.COM vss_uint64_date.gd_gmt_array = malloc(count * sizeof (uint64_t)); 1658474SJose.Borrego@Sun.COM 1668474SJose.Borrego@Sun.COM if (vss_uint64_date.gd_gmt_array != NULL) { 167*8871Samw@Sun.COM (void) zfs_iter_snapshots(zfshd, 1688474SJose.Borrego@Sun.COM smbd_vss_iterate_get_uint64_date, 1698474SJose.Borrego@Sun.COM (void *)&vss_uint64_date); 1708474SJose.Borrego@Sun.COM 1718474SJose.Borrego@Sun.COM *num_gmttokens = vss_uint64_date.gd_return_count; 1728474SJose.Borrego@Sun.COM *return_count = vss_uint64_date.gd_return_count; 1738474SJose.Borrego@Sun.COM 1748474SJose.Borrego@Sun.COM if (vss_uint64_date.gd_return_count <= count) { 175*8871Samw@Sun.COM /* 176*8871Samw@Sun.COM * Sort the list since neither 177*8871Samw@Sun.COM * zfs nor the client sorts it. 178*8871Samw@Sun.COM */ 1798474SJose.Borrego@Sun.COM qsort((char *)vss_uint64_date.gd_gmt_array, 1808474SJose.Borrego@Sun.COM vss_uint64_date.gd_return_count, 1818474SJose.Borrego@Sun.COM sizeof (uint64_t), smbd_vss_cmp_time); 1828474SJose.Borrego@Sun.COM 1838474SJose.Borrego@Sun.COM timep = vss_uint64_date.gd_gmt_array; 1848474SJose.Borrego@Sun.COM 1858474SJose.Borrego@Sun.COM for (i = 0; i < vss_uint64_date.gd_return_count; i++) { 1868474SJose.Borrego@Sun.COM *gmttokenp = malloc(SMB_VSS_GMT_SIZE); 1878474SJose.Borrego@Sun.COM 1888474SJose.Borrego@Sun.COM if (*gmttokenp) { 1898474SJose.Borrego@Sun.COM smbd_vss_time2gmttoken(*timep, 1908474SJose.Borrego@Sun.COM *gmttokenp); 1918474SJose.Borrego@Sun.COM } else { 1928474SJose.Borrego@Sun.COM vss_uint64_date.gd_return_count = 0; 1938474SJose.Borrego@Sun.COM } 1948474SJose.Borrego@Sun.COM 1958474SJose.Borrego@Sun.COM timep++; 1968474SJose.Borrego@Sun.COM gmttokenp++; 1978474SJose.Borrego@Sun.COM } 1988474SJose.Borrego@Sun.COM } 1998474SJose.Borrego@Sun.COM 2008474SJose.Borrego@Sun.COM free(vss_uint64_date.gd_gmt_array); 2018474SJose.Borrego@Sun.COM } 2028474SJose.Borrego@Sun.COM 203*8871Samw@Sun.COM zfs_close(zfshd); 204*8871Samw@Sun.COM libzfs_fini(libhd); 2058474SJose.Borrego@Sun.COM } 2068474SJose.Borrego@Sun.COM 2078474SJose.Borrego@Sun.COM /* 2088474SJose.Borrego@Sun.COM * path - path of the dataset for the operation 2098474SJose.Borrego@Sun.COM * gmttoken - the @GMT token to be looked up 2108474SJose.Borrego@Sun.COM * snapname - the snapshot name to be returned 2118474SJose.Borrego@Sun.COM * 2128474SJose.Borrego@Sun.COM * Here we are going to get the snapshot name from the @GMT token 2138474SJose.Borrego@Sun.COM * The snapname returned by ZFS is : <dataset name>@<snapshot name> 2148474SJose.Borrego@Sun.COM * So we are going to make sure there is the @ symbol in 2158474SJose.Borrego@Sun.COM * the right place and then just return the snapshot name 2168474SJose.Borrego@Sun.COM */ 2178474SJose.Borrego@Sun.COM int 218*8871Samw@Sun.COM smbd_vss_map_gmttoken(const char *path, char *gmttoken, char *snapname) 2198474SJose.Borrego@Sun.COM { 220*8871Samw@Sun.COM char dataset[MAXPATHLEN]; 221*8871Samw@Sun.COM libzfs_handle_t *libhd; 222*8871Samw@Sun.COM zfs_handle_t *zfshd; 2238474SJose.Borrego@Sun.COM smbd_vss_map_gmttoken_t vss_map_gmttoken; 224*8871Samw@Sun.COM char *zsnap; 225*8871Samw@Sun.COM const char *lsnap; 2268474SJose.Borrego@Sun.COM 2278474SJose.Borrego@Sun.COM vss_map_gmttoken.mg_gmttoken = gmttoken; 2288474SJose.Borrego@Sun.COM vss_map_gmttoken.mg_snapname = snapname; 2298474SJose.Borrego@Sun.COM *snapname = '\0'; 2308474SJose.Borrego@Sun.COM 231*8871Samw@Sun.COM if (smb_getdataset(path, dataset, MAXPATHLEN) != 0) 232*8871Samw@Sun.COM return (-1); 2338474SJose.Borrego@Sun.COM 234*8871Samw@Sun.COM if ((libhd = libzfs_init()) == NULL) 235*8871Samw@Sun.COM return (-1); 2368474SJose.Borrego@Sun.COM 237*8871Samw@Sun.COM if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_DATASET)) == NULL) { 238*8871Samw@Sun.COM libzfs_fini(libhd); 2398474SJose.Borrego@Sun.COM return (-1); 2408474SJose.Borrego@Sun.COM } 2418474SJose.Borrego@Sun.COM 242*8871Samw@Sun.COM (void) zfs_iter_snapshots(zfshd, smbd_vss_iterate_map_gmttoken, 2438474SJose.Borrego@Sun.COM (void *)&vss_map_gmttoken); 2448474SJose.Borrego@Sun.COM 2458474SJose.Borrego@Sun.COM /* compare the zfs snapshot name and the local snap name */ 2468474SJose.Borrego@Sun.COM zsnap = snapname; 247*8871Samw@Sun.COM lsnap = dataset; 2488474SJose.Borrego@Sun.COM while ((*lsnap != '\0') && (*zsnap != '\0') && (*lsnap == *zsnap)) { 2498474SJose.Borrego@Sun.COM zsnap++; 2508474SJose.Borrego@Sun.COM lsnap++; 2518474SJose.Borrego@Sun.COM } 2528474SJose.Borrego@Sun.COM 2538474SJose.Borrego@Sun.COM /* Now we should be passed the dataset name */ 2548474SJose.Borrego@Sun.COM if ((*zsnap == '@') && (*lsnap == '\0')) { 2558474SJose.Borrego@Sun.COM zsnap++; 2568474SJose.Borrego@Sun.COM (void) strlcpy(snapname, zsnap, MAXPATHLEN); 2578474SJose.Borrego@Sun.COM } else { 2588474SJose.Borrego@Sun.COM *snapname = '\0'; 2598474SJose.Borrego@Sun.COM } 2608474SJose.Borrego@Sun.COM 261*8871Samw@Sun.COM zfs_close(zfshd); 262*8871Samw@Sun.COM libzfs_fini(libhd); 2638474SJose.Borrego@Sun.COM return (0); 2648474SJose.Borrego@Sun.COM } 2658474SJose.Borrego@Sun.COM 2668474SJose.Borrego@Sun.COM static void 2678474SJose.Borrego@Sun.COM smbd_vss_time2gmttoken(time_t time, char *gmttoken) 2688474SJose.Borrego@Sun.COM { 2698474SJose.Borrego@Sun.COM struct tm t; 2708474SJose.Borrego@Sun.COM 2718474SJose.Borrego@Sun.COM (void) gmtime_r(&time, &t); 2728474SJose.Borrego@Sun.COM 2738474SJose.Borrego@Sun.COM (void) strftime(gmttoken, SMB_VSS_GMT_SIZE, 2748474SJose.Borrego@Sun.COM "@GMT-%Y.%m.%d-%H.%M.%S", &t); 2758474SJose.Borrego@Sun.COM } 2768474SJose.Borrego@Sun.COM 2778474SJose.Borrego@Sun.COM static int 2788474SJose.Borrego@Sun.COM smbd_vss_cmp_time(const void *a, const void *b) 2798474SJose.Borrego@Sun.COM { 2808474SJose.Borrego@Sun.COM if (*(uint64_t *)a < *(uint64_t *)b) 2818474SJose.Borrego@Sun.COM return (1); 2828474SJose.Borrego@Sun.COM if (*(uint64_t *)a == *(uint64_t *)b) 2838474SJose.Borrego@Sun.COM return (0); 2848474SJose.Borrego@Sun.COM return (-1); 2858474SJose.Borrego@Sun.COM } 2868474SJose.Borrego@Sun.COM 2878474SJose.Borrego@Sun.COM static int 2888474SJose.Borrego@Sun.COM smbd_vss_iterate_count(zfs_handle_t *zhp, void *data) 2898474SJose.Borrego@Sun.COM { 2908474SJose.Borrego@Sun.COM smbd_vss_count_t *vss_data; 2918474SJose.Borrego@Sun.COM vss_data = data; 2928474SJose.Borrego@Sun.COM vss_data->vc_count++; 293*8871Samw@Sun.COM /* libzfs expects us to close the handle */ 2948474SJose.Borrego@Sun.COM zfs_close(zhp); 2958474SJose.Borrego@Sun.COM return (0); 2968474SJose.Borrego@Sun.COM } 2978474SJose.Borrego@Sun.COM 2988474SJose.Borrego@Sun.COM static int 2998474SJose.Borrego@Sun.COM smbd_vss_iterate_get_uint64_date(zfs_handle_t *zhp, void *data) 3008474SJose.Borrego@Sun.COM { 3018474SJose.Borrego@Sun.COM smbd_vss_get_uint64_date_t *vss_data; 3028474SJose.Borrego@Sun.COM 3038474SJose.Borrego@Sun.COM vss_data = data; 3048474SJose.Borrego@Sun.COM 3058474SJose.Borrego@Sun.COM if (vss_data->gd_return_count < vss_data->gd_count) { 3068474SJose.Borrego@Sun.COM vss_data->gd_gmt_array[vss_data->gd_return_count] = 3078474SJose.Borrego@Sun.COM zfs_prop_get_int(zhp, ZFS_PROP_CREATION); 3088474SJose.Borrego@Sun.COM } 3098474SJose.Borrego@Sun.COM 3108474SJose.Borrego@Sun.COM vss_data->gd_return_count += 1; 311*8871Samw@Sun.COM /* libzfs expects us to close the handle */ 3128474SJose.Borrego@Sun.COM zfs_close(zhp); 3138474SJose.Borrego@Sun.COM return (0); 3148474SJose.Borrego@Sun.COM } 3158474SJose.Borrego@Sun.COM 3168474SJose.Borrego@Sun.COM static int 3178474SJose.Borrego@Sun.COM smbd_vss_iterate_map_gmttoken(zfs_handle_t *zhp, void *data) 3188474SJose.Borrego@Sun.COM { 3198474SJose.Borrego@Sun.COM smbd_vss_map_gmttoken_t *vss_data; 3208474SJose.Borrego@Sun.COM time_t time; 3218474SJose.Borrego@Sun.COM char gmttoken[SMB_VSS_GMT_SIZE]; 3228474SJose.Borrego@Sun.COM 3238474SJose.Borrego@Sun.COM vss_data = data; 3248474SJose.Borrego@Sun.COM 3258474SJose.Borrego@Sun.COM time = (time_t)zfs_prop_get_int(zhp, ZFS_PROP_CREATION); 3268474SJose.Borrego@Sun.COM smbd_vss_time2gmttoken(time, gmttoken); 3278474SJose.Borrego@Sun.COM 328*8871Samw@Sun.COM if (strncmp(gmttoken, vss_data->mg_gmttoken, SMB_VSS_GMT_SIZE) == 0) { 3298474SJose.Borrego@Sun.COM (void) strlcpy(vss_data->mg_snapname, zfs_get_name(zhp), 3308474SJose.Borrego@Sun.COM MAXPATHLEN); 3318474SJose.Borrego@Sun.COM 332*8871Samw@Sun.COM /* libzfs expects us to close the handle */ 3338474SJose.Borrego@Sun.COM zfs_close(zhp); 3348474SJose.Borrego@Sun.COM 3358474SJose.Borrego@Sun.COM /* we found a match, do not process anymore snapshots */ 3368474SJose.Borrego@Sun.COM return (-1); 3378474SJose.Borrego@Sun.COM } 3388474SJose.Borrego@Sun.COM 339*8871Samw@Sun.COM /* libzfs expects us to close the handle */ 3408474SJose.Borrego@Sun.COM zfs_close(zhp); 3418474SJose.Borrego@Sun.COM return (0); 3428474SJose.Borrego@Sun.COM } 343