dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / smbsrv / smbd / smbd_vss.c
blob759c69651344bb713a55860520756ae67e36d8f2
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
25 * Copyright 2016 Martin Matuska. All rights reserved.
28 #include <synch.h>
29 #include <pthread.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <strings.h>
33 #include <sys/errno.h>
34 #include <libzfs.h>
36 #include <smbsrv/libsmb.h>
37 #include <smbsrv/libsmbns.h>
38 #include <smbsrv/libmlsvc.h>
39 #include <smbsrv/smbinfo.h>
40 #include "smbd.h"
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.
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
67 * The maximum number of snapshots returned per request.
69 #define SMBD_VSS_SNAPSHOT_MAX 725
71 static void smbd_vss_time2gmttoken(time_t time, char *gmttoken);
72 static int smbd_vss_cmp_time(const void *a, const void *b);
73 static int smbd_vss_iterate_count(zfs_handle_t *zhp, void *data);
74 static int smbd_vss_iterate_get_uint64_date(zfs_handle_t *zhp, void *data);
75 static int smbd_vss_iterate_map_gmttoken(zfs_handle_t *zhp, void *data);
77 typedef struct smbd_vss_count {
78 int vc_count;
79 } smbd_vss_count_t;
82 * gd_count how many @GMT tokens are expected
83 * gd_return_count how many @GMT tokens are being returned
84 * gd_gmt_array array of the @GMT token with max size of gd_count
86 typedef struct smbd_vss_get_uint64_date {
87 int gd_count;
88 int gd_return_count;
89 uint64_t *gd_gmt_array;
90 } smbd_vss_get_uint64_date_t;
92 typedef struct smbd_vss_map_gmttoken {
93 time_t mg_snaptime;
94 char *mg_snapname;
95 } smbd_vss_map_gmttoken_t;
99 * path - path of the dataset
100 * count - return value of the number of snapshots for the dataset
103 smbd_vss_get_count(const char *path, uint32_t *count)
105 char dataset[MAXPATHLEN];
106 libzfs_handle_t *libhd;
107 zfs_handle_t *zfshd;
108 smbd_vss_count_t vss_count;
110 bzero(&vss_count, sizeof (smbd_vss_count_t));
111 *count = 0;
113 if (smb_getdataset(path, dataset, MAXPATHLEN) != 0)
114 return (-1);
116 if ((libhd = libzfs_init()) == NULL)
117 return (-1);
119 if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_DATASET)) == NULL) {
120 libzfs_fini(libhd);
121 return (-1);
124 (void) zfs_iter_snapshots(zfshd, B_FALSE, smbd_vss_iterate_count,
125 (void *)&vss_count);
127 if (vss_count.vc_count > SMBD_VSS_SNAPSHOT_MAX)
128 vss_count.vc_count = SMBD_VSS_SNAPSHOT_MAX;
130 *count = vss_count.vc_count;
131 zfs_close(zfshd);
132 libzfs_fini(libhd);
133 return (0);
137 * path - is the path of the dataset
138 * count - is the maxium number of GMT tokens allowed to be returned
139 * return_count - is how many should be returned
140 * num_gmttokens - how many gmttokens in gmttokenp (0 if error)
141 * gmttokenp - array of @GMT tokens (even if zero, elements still need
142 * to be freed)
145 void
146 smbd_vss_get_snapshots(const char *path, uint32_t count,
147 uint32_t *return_count, uint32_t *num_gmttokens, char **gmttokenp)
149 char dataset[MAXPATHLEN];
150 libzfs_handle_t *libhd;
151 zfs_handle_t *zfshd;
152 smbd_vss_get_uint64_date_t vss_uint64_date;
153 int i;
154 uint64_t *timep;
156 *return_count = 0;
157 *num_gmttokens = 0;
159 if (count == 0)
160 return;
162 if (count > SMBD_VSS_SNAPSHOT_MAX)
163 count = SMBD_VSS_SNAPSHOT_MAX;
165 vss_uint64_date.gd_count = count;
166 vss_uint64_date.gd_return_count = 0;
167 vss_uint64_date.gd_gmt_array = malloc(count * sizeof (uint64_t));
168 if (vss_uint64_date.gd_gmt_array == NULL)
169 return;
171 if (smb_getdataset(path, dataset, MAXPATHLEN) != 0) {
172 free(vss_uint64_date.gd_gmt_array);
173 return;
176 if ((libhd = libzfs_init()) == NULL) {
177 free(vss_uint64_date.gd_gmt_array);
178 return;
181 if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_DATASET)) == NULL) {
182 free(vss_uint64_date.gd_gmt_array);
183 libzfs_fini(libhd);
184 return;
187 (void) zfs_iter_snapshots(zfshd, B_FALSE,
188 smbd_vss_iterate_get_uint64_date, (void *)&vss_uint64_date);
190 *num_gmttokens = vss_uint64_date.gd_return_count;
191 *return_count = vss_uint64_date.gd_return_count;
194 * Sort the list since neither zfs nor the client sorts it.
196 qsort((char *)vss_uint64_date.gd_gmt_array,
197 vss_uint64_date.gd_return_count,
198 sizeof (uint64_t), smbd_vss_cmp_time);
200 timep = vss_uint64_date.gd_gmt_array;
202 for (i = 0; i < vss_uint64_date.gd_return_count; i++) {
203 *gmttokenp = malloc(SMB_VSS_GMT_SIZE);
205 if (*gmttokenp)
206 smbd_vss_time2gmttoken(*timep, *gmttokenp);
207 else
208 vss_uint64_date.gd_return_count = 0;
210 timep++;
211 gmttokenp++;
214 free(vss_uint64_date.gd_gmt_array);
215 zfs_close(zfshd);
216 libzfs_fini(libhd);
219 static const char
220 smbd_vss_gmttoken_fmt[] = "@GMT-%Y.%m.%d-%H.%M.%S";
223 * path - path of the dataset for the operation
224 * gmttoken - the @GMT token to be looked up
225 * toktime - time_t used if gmttoken == NULL
226 * snapname - the snapshot name to be returned [MAXPATHLEN]
228 * Here we are going to get the snapshot name from the @GMT token
229 * The snapname returned by ZFS is : <dataset name>@<snapshot name>
230 * So we are going to make sure there is the @ symbol in
231 * the right place and then just return the snapshot name
234 smbd_vss_map_gmttoken(const char *path, char *gmttoken, time_t toktime,
235 char *snapname)
237 char dataset[MAXPATHLEN];
238 libzfs_handle_t *libhd;
239 zfs_handle_t *zfshd;
240 smbd_vss_map_gmttoken_t vss_map_gmttoken;
241 char *zsnap;
242 const char *lsnap;
243 struct tm tm;
245 if (gmttoken != NULL && *gmttoken == '@' &&
246 strptime(gmttoken, smbd_vss_gmttoken_fmt, &tm) != NULL) {
247 toktime = timegm(&tm);
250 vss_map_gmttoken.mg_snaptime = toktime;
251 vss_map_gmttoken.mg_snapname = snapname;
252 *snapname = '\0';
254 if (smb_getdataset(path, dataset, MAXPATHLEN) != 0)
255 return (-1);
257 if ((libhd = libzfs_init()) == NULL)
258 return (-1);
260 if ((zfshd = zfs_open(libhd, dataset, ZFS_TYPE_DATASET)) == NULL) {
261 libzfs_fini(libhd);
262 return (-1);
265 (void) zfs_iter_snapshots(zfshd, B_FALSE, smbd_vss_iterate_map_gmttoken,
266 (void *)&vss_map_gmttoken);
268 /* compare the zfs snapshot name and the local snap name */
269 zsnap = snapname;
270 lsnap = dataset;
271 while ((*lsnap != '\0') && (*zsnap != '\0') && (*lsnap == *zsnap)) {
272 zsnap++;
273 lsnap++;
276 /* Now we should be passed the dataset name */
277 if ((*zsnap == '@') && (*lsnap == '\0')) {
278 zsnap++;
279 (void) strlcpy(snapname, zsnap, MAXPATHLEN);
280 } else {
281 *snapname = '\0';
284 zfs_close(zfshd);
285 libzfs_fini(libhd);
286 return (0);
289 static void
290 smbd_vss_time2gmttoken(time_t time, char *gmttoken)
292 struct tm t;
294 (void) gmtime_r(&time, &t);
296 (void) strftime(gmttoken, SMB_VSS_GMT_SIZE,
297 smbd_vss_gmttoken_fmt, &t);
300 static int
301 smbd_vss_cmp_time(const void *a, const void *b)
303 if (*(uint64_t *)a < *(uint64_t *)b)
304 return (1);
305 if (*(uint64_t *)a == *(uint64_t *)b)
306 return (0);
307 return (-1);
311 * ZFS snapshot iterator to count snapshots.
312 * Note: libzfs expects us to close the handle.
313 * Return 0 to continue iterating or non-zreo to terminate the iteration.
315 static int
316 smbd_vss_iterate_count(zfs_handle_t *zhp, void *data)
318 smbd_vss_count_t *vss_data = data;
320 if (vss_data->vc_count < SMBD_VSS_SNAPSHOT_MAX) {
321 vss_data->vc_count++;
322 zfs_close(zhp);
323 return (0);
326 zfs_close(zhp);
327 return (-1);
331 * ZFS snapshot iterator to get snapshot creation time.
332 * Note: libzfs expects us to close the handle.
333 * Return 0 to continue iterating or non-zreo to terminate the iteration.
335 static int
336 smbd_vss_iterate_get_uint64_date(zfs_handle_t *zhp, void *data)
338 smbd_vss_get_uint64_date_t *vss_data = data;
339 int count;
341 count = vss_data->gd_return_count;
343 if (count < vss_data->gd_count) {
344 vss_data->gd_gmt_array[count] =
345 zfs_prop_get_int(zhp, ZFS_PROP_CREATION);
346 vss_data->gd_return_count++;
347 zfs_close(zhp);
348 return (0);
351 zfs_close(zhp);
352 return (-1);
356 * ZFS snapshot iterator to map a snapshot creation time to a token.
357 * Note: libzfs expects us to close the handle.
358 * Return 0 to continue iterating or non-zreo to terminate the iteration.
360 static int
361 smbd_vss_iterate_map_gmttoken(zfs_handle_t *zhp, void *data)
363 smbd_vss_map_gmttoken_t *vss_data = data;
364 time_t time;
366 time = (time_t)zfs_prop_get_int(zhp, ZFS_PROP_CREATION);
367 if (time == vss_data->mg_snaptime) {
368 (void) strlcpy(vss_data->mg_snapname, zfs_get_name(zhp),
369 MAXPATHLEN);
371 /* we found a match, do not process anymore snapshots */
372 zfs_close(zhp);
373 return (-1);
376 zfs_close(zhp);
377 return (0);