s3: VFS: shadow_copy2: Add two new variables to the private data. Not yet used.
[kai/samba-autobuild/.git] / source3 / modules / vfs_shadow_copy2.c
1 /*
2  * shadow_copy2: a shadow copy module (second implementation)
3  *
4  * Copyright (C) Andrew Tridgell   2007 (portions taken from shadow_copy2)
5  * Copyright (C) Ed Plese          2009
6  * Copyright (C) Volker Lendecke   2011
7  * Copyright (C) Christian Ambach  2011
8  * Copyright (C) Michael Adam      2013
9  * Copyright (C) Rajesh Joseph     2016
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24  */
25
26 /*
27  * This is a second implemetation of a shadow copy module for exposing
28  * file system snapshots to windows clients as shadow copies.
29  *
30  * See the manual page for documentation.
31  */
32
33 #include "includes.h"
34 #include "smbd/smbd.h"
35 #include "system/filesys.h"
36 #include "include/ntioctl.h"
37 #include "util_tdb.h"
38
39 struct shadow_copy2_config {
40         char *gmt_format;
41         bool use_sscanf;
42         bool use_localtime;
43         char *snapdir;
44         char *delimiter;
45         bool snapdirseverywhere;
46         bool crossmountpoints;
47         bool fixinodes;
48         char *sort_order;
49         bool snapdir_absolute;
50         char *mount_point;
51         char *rel_connectpath; /* share root, relative to a snapshot root */
52         char *snapshot_basepath; /* the absolute version of snapdir */
53 };
54
55 /* Data-structure to hold the list of snap entries */
56 struct shadow_copy2_snapentry {
57         char *snapname;
58         char *time_fmt;
59         struct shadow_copy2_snapentry *next;
60         struct shadow_copy2_snapentry *prev;
61 };
62
63 struct shadow_copy2_snaplist_info {
64         struct shadow_copy2_snapentry *snaplist; /* snapshot list */
65         regex_t *regex; /* Regex to filter snaps */
66         time_t fetch_time; /* snaplist update time */
67 };
68
69
70 /*
71  * shadow_copy2 private structure. This structure will be
72  * used to keep module specific information
73  */
74 struct shadow_copy2_private {
75         struct shadow_copy2_config *config;
76         struct shadow_copy2_snaplist_info *snaps;
77         char *shadow_cwd; /* Absolute $cwd path. */
78         /* Absolute connectpath - can vary depending on $cwd. */
79         char *shadow_connectpath;
80 };
81
82 static int shadow_copy2_get_shadow_copy_data(
83         vfs_handle_struct *handle, files_struct *fsp,
84         struct shadow_copy_data *shadow_copy2_data,
85         bool labels);
86
87 /**
88  *This function will create a new snapshot list entry and
89  * return to the caller. This entry will also be added to
90  * the global snapshot list.
91  *
92  * @param[in]   priv    shadow_copy2 specific data structure
93  * @return      Newly   created snapshot entry or NULL on failure
94  */
95 static struct shadow_copy2_snapentry *shadow_copy2_create_snapentry(
96                                         struct shadow_copy2_private *priv)
97 {
98         struct shadow_copy2_snapentry *tmpentry = NULL;
99
100         tmpentry = talloc_zero(priv->snaps, struct shadow_copy2_snapentry);
101         if (tmpentry == NULL) {
102                 DBG_ERR("talloc_zero() failed\n");
103                 errno = ENOMEM;
104                 return NULL;
105         }
106
107         DLIST_ADD(priv->snaps->snaplist, tmpentry);
108
109         return tmpentry;
110 }
111
112 /**
113  *This function will delete the entire snaplist and reset
114  * priv->snaps->snaplist to NULL.
115  *
116  * @param[in] priv shadow_copye specific data structure
117  */
118 static void shadow_copy2_delete_snaplist(struct shadow_copy2_private *priv)
119 {
120         struct shadow_copy2_snapentry *tmp = NULL;
121
122         while ((tmp = priv->snaps->snaplist) != NULL) {
123                 DLIST_REMOVE(priv->snaps->snaplist, tmp);
124                 talloc_free(tmp);
125         }
126 }
127
128 /**
129  * Given a timestamp this function searches the global snapshot list
130  * and returns the complete snapshot directory name saved in the entry.
131  *
132  * @param[in]   priv            shadow_copy2 specific structure
133  * @param[in]   timestamp       timestamp corresponding to one of the snapshot
134  * @param[out]  snap_str        buffer to copy the actual snapshot name
135  * @param[in]   len             length of snap_str buffer
136  *
137  * @return      Length of actual snapshot name, and -1 on failure
138  */
139 static ssize_t shadow_copy2_saved_snapname(struct shadow_copy2_private *priv,
140                                           struct tm *timestamp,
141                                           char *snap_str, size_t len)
142 {
143         ssize_t snaptime_len = -1;
144         struct shadow_copy2_snapentry *entry = NULL;
145
146         snaptime_len = strftime(snap_str, len, GMT_FORMAT, timestamp);
147         if (snaptime_len == 0) {
148                 DBG_ERR("strftime failed\n");
149                 return -1;
150         }
151
152         snaptime_len = -1;
153
154         for (entry = priv->snaps->snaplist; entry; entry = entry->next) {
155                 if (strcmp(entry->time_fmt, snap_str) == 0) {
156                         snaptime_len = snprintf(snap_str, len, "%s",
157                                                 entry->snapname);
158                         return snaptime_len;
159                 }
160         }
161
162         snap_str[0] = 0;
163         return snaptime_len;
164 }
165
166
167 /**
168  * This function will check if snaplist is updated or not. If snaplist
169  * is empty then it will create a new list. Each time snaplist is updated
170  * the time is recorded. If the snapshot time is greater than the snaplist
171  * update time then chances are we are working on an older list. Then discard
172  * the old list and fetch a new snaplist.
173  *
174  * @param[in]   handle          VFS handle struct
175  * @param[in]   snap_time       time of snapshot
176  *
177  * @return      true if the list is updated else false
178  */
179 static bool shadow_copy2_update_snaplist(struct vfs_handle_struct *handle,
180                 time_t snap_time)
181 {
182         int ret = -1;
183         bool snaplist_updated = false;
184         struct files_struct fsp = {0};
185         struct smb_filename smb_fname = {0};
186         double seconds = 0.0;
187         struct shadow_copy2_private *priv = NULL;
188
189         SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
190                                 return false);
191
192         seconds = difftime(snap_time, priv->snaps->fetch_time);
193
194         /*
195          * Fetch the snapshot list if either the snaplist is empty or the
196          * required snapshot time is greater than the last fetched snaplist
197          * time.
198          */
199         if (seconds > 0 || (priv->snaps->snaplist == NULL)) {
200                 smb_fname.base_name = discard_const_p(char, ".");
201                 fsp.fsp_name = &smb_fname;
202
203                 ret = shadow_copy2_get_shadow_copy_data(handle, &fsp,
204                                                         NULL, false);
205                 if (ret == 0) {
206                         snaplist_updated = true;
207                 } else {
208                         DBG_ERR("Failed to get shadow copy data\n");
209                 }
210
211         }
212
213         return snaplist_updated;
214 }
215
216 static bool shadow_copy2_find_slashes(TALLOC_CTX *mem_ctx, const char *str,
217                                       size_t **poffsets,
218                                       unsigned *pnum_offsets)
219 {
220         unsigned num_offsets;
221         size_t *offsets;
222         const char *p;
223
224         num_offsets = 0;
225
226         p = str;
227         while ((p = strchr(p, '/')) != NULL) {
228                 num_offsets += 1;
229                 p += 1;
230         }
231
232         offsets = talloc_array(mem_ctx, size_t, num_offsets);
233         if (offsets == NULL) {
234                 return false;
235         }
236
237         p = str;
238         num_offsets = 0;
239         while ((p = strchr(p, '/')) != NULL) {
240                 offsets[num_offsets] = p-str;
241                 num_offsets += 1;
242                 p += 1;
243         }
244
245         *poffsets = offsets;
246         *pnum_offsets = num_offsets;
247         return true;
248 }
249
250 /**
251  * Given a timestamp, build the posix level GMT-tag string
252  * based on the configurable format.
253  */
254 static ssize_t shadow_copy2_posix_gmt_string(struct vfs_handle_struct *handle,
255                                             time_t snapshot,
256                                             char *snaptime_string,
257                                             size_t len)
258 {
259         struct tm snap_tm;
260         ssize_t snaptime_len;
261         struct shadow_copy2_config *config;
262         struct shadow_copy2_private *priv;
263
264         SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
265                                 return 0);
266
267         config = priv->config;
268
269         if (config->use_sscanf) {
270                 snaptime_len = snprintf(snaptime_string,
271                                         len,
272                                         config->gmt_format,
273                                         (unsigned long)snapshot);
274                 if (snaptime_len <= 0) {
275                         DEBUG(10, ("snprintf failed\n"));
276                         return -1;
277                 }
278         } else {
279                 if (config->use_localtime) {
280                         if (localtime_r(&snapshot, &snap_tm) == 0) {
281                                 DEBUG(10, ("gmtime_r failed\n"));
282                                 return -1;
283                         }
284                 } else {
285                         if (gmtime_r(&snapshot, &snap_tm) == 0) {
286                                 DEBUG(10, ("gmtime_r failed\n"));
287                                 return -1;
288                         }
289                 }
290
291                 if (priv->snaps->regex != NULL) {
292                         snaptime_len = shadow_copy2_saved_snapname(priv,
293                                                 &snap_tm, snaptime_string, len);
294                         if (snaptime_len >= 0)
295                                 return snaptime_len;
296
297                         /*
298                          * If we fail to find the snapshot name, chances are
299                          * that we have not updated our snaplist. Make sure the
300                          * snaplist is updated.
301                          */
302                         if (!shadow_copy2_update_snaplist(handle, snapshot)) {
303                                 DBG_DEBUG("shadow_copy2_update_snaplist "
304                                           "failed\n");
305                                 return -1;
306                         }
307
308                         return shadow_copy2_saved_snapname(priv,
309                                                 &snap_tm, snaptime_string, len);
310                 }
311
312                 snaptime_len = strftime(snaptime_string,
313                                         len,
314                                         config->gmt_format,
315                                         &snap_tm);
316                 if (snaptime_len == 0) {
317                         DEBUG(10, ("strftime failed\n"));
318                         return -1;
319                 }
320         }
321
322         return snaptime_len;
323 }
324
325 /**
326  * Given a timestamp, build the string to insert into a path
327  * as a path component for creating the local path to the
328  * snapshot at the given timestamp of the input path.
329  *
330  * In the case of a parallel snapdir (specified with an
331  * absolute path), this is the inital portion of the
332  * local path of any snapshot file. The complete path is
333  * obtained by appending the portion of the file's path
334  * below the share root's mountpoint.
335  */
336 static char *shadow_copy2_insert_string(TALLOC_CTX *mem_ctx,
337                                         struct vfs_handle_struct *handle,
338                                         time_t snapshot)
339 {
340         fstring snaptime_string;
341         ssize_t snaptime_len = 0;
342         char *result = NULL;
343         struct shadow_copy2_config *config;
344         struct shadow_copy2_private *priv;
345
346         SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
347                                 return NULL);
348
349         config = priv->config;
350
351         snaptime_len = shadow_copy2_posix_gmt_string(handle,
352                                                      snapshot,
353                                                      snaptime_string,
354                                                      sizeof(snaptime_string));
355         if (snaptime_len <= 0) {
356                 return NULL;
357         }
358
359         if (config->snapdir_absolute) {
360                 result = talloc_asprintf(mem_ctx, "%s/%s",
361                                          config->snapdir, snaptime_string);
362         } else {
363                 result = talloc_asprintf(mem_ctx, "/%s/%s",
364                                          config->snapdir, snaptime_string);
365         }
366         if (result == NULL) {
367                 DEBUG(1, (__location__ " talloc_asprintf failed\n"));
368         }
369
370         return result;
371 }
372
373 /**
374  * Build the posix snapshot path for the connection
375  * at the given timestamp, i.e. the absolute posix path
376  * that contains the snapshot for this file system.
377  *
378  * This only applies to classical case, i.e. not
379  * to the "snapdirseverywhere" mode.
380  */
381 static char *shadow_copy2_snapshot_path(TALLOC_CTX *mem_ctx,
382                                         struct vfs_handle_struct *handle,
383                                         time_t snapshot)
384 {
385         fstring snaptime_string;
386         ssize_t snaptime_len = 0;
387         char *result = NULL;
388         struct shadow_copy2_private *priv;
389
390         SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
391                                 return NULL);
392
393         snaptime_len = shadow_copy2_posix_gmt_string(handle,
394                                                      snapshot,
395                                                      snaptime_string,
396                                                      sizeof(snaptime_string));
397         if (snaptime_len <= 0) {
398                 return NULL;
399         }
400
401         result = talloc_asprintf(mem_ctx, "%s/%s",
402                                  priv->config->snapshot_basepath, snaptime_string);
403         if (result == NULL) {
404                 DEBUG(1, (__location__ " talloc_asprintf failed\n"));
405         }
406
407         return result;
408 }
409
410 /**
411  * Strip a snapshot component from a filename as
412  * handed in via the smb layer.
413  * Returns the parsed timestamp and the stripped filename.
414  */
415 static bool shadow_copy2_strip_snapshot(TALLOC_CTX *mem_ctx,
416                                         struct vfs_handle_struct *handle,
417                                         const char *name,
418                                         time_t *ptimestamp,
419                                         char **pstripped)
420 {
421         struct tm tm;
422         time_t timestamp = 0;
423         const char *p;
424         char *q;
425         char *stripped = NULL;
426         size_t rest_len, dst_len;
427         struct shadow_copy2_private *priv;
428         const char *snapdir;
429         ssize_t snapdirlen;
430         ptrdiff_t len_before_gmt;
431
432         SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
433                                 return false);
434
435         DEBUG(10, (__location__ ": enter path '%s'\n", name));
436
437         p = strstr_m(name, "@GMT-");
438         if (p == NULL) {
439                 DEBUG(11, ("@GMT not found\n"));
440                 goto no_snapshot;
441         }
442         if ((p > name) && (p[-1] != '/')) {
443                 /* the GMT-token does not start a path-component */
444                 DEBUG(10, ("not at start, p=%p, name=%p, p[-1]=%d\n",
445                            p, name, (int)p[-1]));
446                 goto no_snapshot;
447         }
448
449         /*
450          * Figure out whether we got an already converted string. One
451          * case where this happens is in a smb2 create call with the
452          * mxac create blob set. We do the get_acl call on
453          * fsp->fsp_name, which is already converted. We are converted
454          * if we got a file name of the form ".snapshots/@GMT-",
455          * i.e. ".snapshots/" precedes "p".
456          */
457
458         snapdir = lp_parm_const_string(SNUM(handle->conn), "shadow", "snapdir",
459                                        ".snapshots");
460         snapdirlen = strlen(snapdir);
461         len_before_gmt = p - name;
462
463         if ((len_before_gmt >= (snapdirlen + 1)) && (p[-1] == '/')) {
464                 const char *parent_snapdir = p - (snapdirlen+1);
465
466                 DEBUG(10, ("parent_snapdir = %s\n", parent_snapdir));
467
468                 if (strncmp(parent_snapdir, snapdir, snapdirlen) == 0) {
469                         DEBUG(10, ("name=%s is already converted\n", name));
470                         goto no_snapshot;
471                 }
472         }
473         q = strptime(p, GMT_FORMAT, &tm);
474         if (q == NULL) {
475                 DEBUG(10, ("strptime failed\n"));
476                 goto no_snapshot;
477         }
478         tm.tm_isdst = -1;
479         timestamp = timegm(&tm);
480         if (timestamp == (time_t)-1) {
481                 DEBUG(10, ("timestamp==-1\n"));
482                 goto no_snapshot;
483         }
484         if (q[0] == '\0') {
485                 /*
486                  * The name consists of only the GMT token or the GMT
487                  * token is at the end of the path. XP seems to send
488                  * @GMT- at the end under certain circumstances even
489                  * with a path prefix.
490                  */
491                 if (pstripped != NULL) {
492                         if (len_before_gmt > 0) {
493                                 /*
494                                  * There is a slash before
495                                  * the @GMT-. Remove it.
496                                  */
497                                 len_before_gmt -= 1;
498                         }
499                         stripped = talloc_strndup(mem_ctx, name,
500                                         len_before_gmt);
501                         if (stripped == NULL) {
502                                 return false;
503                         }
504                         *pstripped = stripped;
505                 }
506                 *ptimestamp = timestamp;
507                 return true;
508         }
509         if (q[0] != '/') {
510                 /*
511                  * It is not a complete path component, i.e. the path
512                  * component continues after the gmt-token.
513                  */
514                 DEBUG(10, ("q[0] = %d\n", (int)q[0]));
515                 goto no_snapshot;
516         }
517         q += 1;
518
519         rest_len = strlen(q);
520         dst_len = len_before_gmt + rest_len;
521
522         if (priv->config->snapdirseverywhere) {
523                 char *insert;
524                 bool have_insert;
525                 insert = shadow_copy2_insert_string(talloc_tos(), handle,
526                                                     timestamp);
527                 if (insert == NULL) {
528                         errno = ENOMEM;
529                         return false;
530                 }
531
532                 DEBUG(10, (__location__ ": snapdirseverywhere mode.\n"
533                            "path '%s'.\n"
534                            "insert string '%s'\n", name, insert));
535
536                 have_insert = (strstr(name, insert+1) != NULL);
537                 DEBUG(10, ("have_insert=%d, name=%s, insert+1=%s\n",
538                            (int)have_insert, name, insert+1));
539                 if (have_insert) {
540                         DEBUG(10, (__location__ ": insert string '%s' found in "
541                                    "path '%s' found in snapdirseverywhere mode "
542                                    "==> already converted\n", insert, name));
543                         TALLOC_FREE(insert);
544                         goto no_snapshot;
545                 }
546                 TALLOC_FREE(insert);
547         } else {
548                 char *snapshot_path;
549                 char *s;
550
551                 snapshot_path = shadow_copy2_snapshot_path(talloc_tos(),
552                                                            handle,
553                                                            timestamp);
554                 if (snapshot_path == NULL) {
555                         errno = ENOMEM;
556                         return false;
557                 }
558
559                 DEBUG(10, (__location__ " path: '%s'.\n"
560                            "snapshot path: '%s'\n", name, snapshot_path));
561
562                 s = strstr(name, snapshot_path);
563                 if (s == name) {
564                         /*
565                          * this starts with "snapshot_basepath/GMT-Token"
566                          * so it is already a converted absolute
567                          * path. Don't process further.
568                          */
569                         DEBUG(10, (__location__ ": path '%s' starts with "
570                                    "snapshot path '%s' (not in "
571                                    "snapdirseverywhere mode) ==> "
572                                    "already converted\n", name, snapshot_path));
573                         talloc_free(snapshot_path);
574                         goto no_snapshot;
575                 }
576                 talloc_free(snapshot_path);
577         }
578
579         if (pstripped != NULL) {
580                 stripped = talloc_array(mem_ctx, char, dst_len+1);
581                 if (stripped == NULL) {
582                         errno = ENOMEM;
583                         return false;
584                 }
585                 if (p > name) {
586                         memcpy(stripped, name, len_before_gmt);
587                 }
588                 if (rest_len > 0) {
589                         memcpy(stripped + len_before_gmt, q, rest_len);
590                 }
591                 stripped[dst_len] = '\0';
592                 *pstripped = stripped;
593         }
594         *ptimestamp = timestamp;
595         return true;
596 no_snapshot:
597         *ptimestamp = 0;
598         return true;
599 }
600
601 static char *shadow_copy2_find_mount_point(TALLOC_CTX *mem_ctx,
602                                            vfs_handle_struct *handle)
603 {
604         char *path = talloc_strdup(mem_ctx, handle->conn->connectpath);
605         dev_t dev;
606         struct stat st;
607         char *p;
608
609         if (stat(path, &st) != 0) {
610                 talloc_free(path);
611                 return NULL;
612         }
613
614         dev = st.st_dev;
615
616         while ((p = strrchr(path, '/')) && p > path) {
617                 *p = 0;
618                 if (stat(path, &st) != 0) {
619                         talloc_free(path);
620                         return NULL;
621                 }
622                 if (st.st_dev != dev) {
623                         *p = '/';
624                         break;
625                 }
626         }
627
628         return path;
629 }
630
631 /**
632  * Convert from a name as handed in via the SMB layer
633  * and a timestamp into the local path of the snapshot
634  * of the provided file at the provided time.
635  * Also return the path in the snapshot corresponding
636  * to the file's share root.
637  */
638 static char *shadow_copy2_do_convert(TALLOC_CTX *mem_ctx,
639                                      struct vfs_handle_struct *handle,
640                                      const char *name, time_t timestamp,
641                                      size_t *snaproot_len)
642 {
643         struct smb_filename converted_fname;
644         char *result = NULL;
645         size_t *slashes = NULL;
646         unsigned num_slashes;
647         char *path = NULL;
648         size_t pathlen;
649         char *insert = NULL;
650         char *converted = NULL;
651         size_t insertlen, connectlen = 0;
652         int i, saved_errno;
653         size_t min_offset;
654         struct shadow_copy2_config *config;
655         struct shadow_copy2_private *priv;
656         size_t in_share_offset = 0;
657
658         SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
659                                 return NULL);
660
661         config = priv->config;
662
663         DEBUG(10, ("converting '%s'\n", name));
664
665         if (!config->snapdirseverywhere) {
666                 int ret;
667                 char *snapshot_path;
668
669                 snapshot_path = shadow_copy2_snapshot_path(talloc_tos(),
670                                                            handle,
671                                                            timestamp);
672                 if (snapshot_path == NULL) {
673                         goto fail;
674                 }
675
676                 if (config->rel_connectpath == NULL) {
677                         converted = talloc_asprintf(mem_ctx, "%s/%s",
678                                                     snapshot_path, name);
679                 } else {
680                         converted = talloc_asprintf(mem_ctx, "%s/%s/%s",
681                                                     snapshot_path,
682                                                     config->rel_connectpath,
683                                                     name);
684                 }
685                 if (converted == NULL) {
686                         goto fail;
687                 }
688
689                 ZERO_STRUCT(converted_fname);
690                 converted_fname.base_name = converted;
691
692                 ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname);
693                 DEBUG(10, ("Trying[not snapdirseverywhere] %s: %d (%s)\n",
694                            converted,
695                            ret, ret == 0 ? "ok" : strerror(errno)));
696                 if (ret == 0) {
697                         DEBUG(10, ("Found %s\n", converted));
698                         result = converted;
699                         converted = NULL;
700                         if (snaproot_len != NULL) {
701                                 *snaproot_len = strlen(snapshot_path);
702                                 if (config->rel_connectpath != NULL) {
703                                         *snaproot_len +=
704                                             strlen(config->rel_connectpath) + 1;
705                                 }
706                         }
707                         goto fail;
708                 } else {
709                         errno = ENOENT;
710                         goto fail;
711                 }
712                 /* never reached ... */
713         }
714
715         connectlen = strlen(handle->conn->connectpath);
716         if (name[0] == 0) {
717                 path = talloc_strdup(mem_ctx, handle->conn->connectpath);
718         } else {
719                 path = talloc_asprintf(
720                         mem_ctx, "%s/%s", handle->conn->connectpath, name);
721         }
722         if (path == NULL) {
723                 errno = ENOMEM;
724                 goto fail;
725         }
726         pathlen = talloc_get_size(path)-1;
727
728         if (!shadow_copy2_find_slashes(talloc_tos(), path,
729                                        &slashes, &num_slashes)) {
730                 goto fail;
731         }
732
733         insert = shadow_copy2_insert_string(talloc_tos(), handle, timestamp);
734         if (insert == NULL) {
735                 goto fail;
736         }
737         insertlen = talloc_get_size(insert)-1;
738
739         /*
740          * Note: We deliberatly don't expensively initialize the
741          * array with talloc_zero here: Putting zero into
742          * converted[pathlen+insertlen] below is sufficient, because
743          * in the following for loop, the insert string is inserted
744          * at various slash places. So the memory up to position
745          * pathlen+insertlen will always be initialized when the
746          * converted string is used.
747          */
748         converted = talloc_array(mem_ctx, char, pathlen + insertlen + 1);
749         if (converted == NULL) {
750                 goto fail;
751         }
752
753         if (path[pathlen-1] != '/') {
754                 /*
755                  * Append a fake slash to find the snapshot root
756                  */
757                 size_t *tmp;
758                 tmp = talloc_realloc(talloc_tos(), slashes,
759                                      size_t, num_slashes+1);
760                 if (tmp == NULL) {
761                         goto fail;
762                 }
763                 slashes = tmp;
764                 slashes[num_slashes] = pathlen;
765                 num_slashes += 1;
766         }
767
768         min_offset = 0;
769
770         if (!config->crossmountpoints) {
771                 min_offset = strlen(config->mount_point);
772         }
773
774         memcpy(converted, path, pathlen+1);
775         converted[pathlen+insertlen] = '\0';
776
777         ZERO_STRUCT(converted_fname);
778         converted_fname.base_name = converted;
779
780         for (i = num_slashes-1; i>=0; i--) {
781                 int ret;
782                 size_t offset;
783
784                 offset = slashes[i];
785
786                 if (offset < min_offset) {
787                         errno = ENOENT;
788                         goto fail;
789                 }
790
791                 if (offset >= connectlen) {
792                         in_share_offset = offset;
793                 }
794
795                 memcpy(converted+offset, insert, insertlen);
796
797                 offset += insertlen;
798                 memcpy(converted+offset, path + slashes[i],
799                        pathlen - slashes[i]);
800
801                 ret = SMB_VFS_NEXT_LSTAT(handle, &converted_fname);
802
803                 DEBUG(10, ("Trying[snapdirseverywhere] %s: %d (%s)\n",
804                            converted,
805                            ret, ret == 0 ? "ok" : strerror(errno)));
806                 if (ret == 0) {
807                         /* success */
808                         if (snaproot_len != NULL) {
809                                 *snaproot_len = in_share_offset + insertlen;
810                         }
811                         break;
812                 }
813                 if (errno == ENOTDIR) {
814                         /*
815                          * This is a valid condition: We appended the
816                          * .snaphots/@GMT.. to a file name. Just try
817                          * with the upper levels.
818                          */
819                         continue;
820                 }
821                 if (errno != ENOENT) {
822                         /* Other problem than "not found" */
823                         goto fail;
824                 }
825         }
826
827         if (i >= 0) {
828                 /*
829                  * Found something
830                  */
831                 DEBUG(10, ("Found %s\n", converted));
832                 result = converted;
833                 converted = NULL;
834         } else {
835                 errno = ENOENT;
836         }
837 fail:
838         saved_errno = errno;
839         TALLOC_FREE(converted);
840         TALLOC_FREE(insert);
841         TALLOC_FREE(slashes);
842         TALLOC_FREE(path);
843         errno = saved_errno;
844         return result;
845 }
846
847 /**
848  * Convert from a name as handed in via the SMB layer
849  * and a timestamp into the local path of the snapshot
850  * of the provided file at the provided time.
851  */
852 static char *shadow_copy2_convert(TALLOC_CTX *mem_ctx,
853                                   struct vfs_handle_struct *handle,
854                                   const char *name, time_t timestamp)
855 {
856         return shadow_copy2_do_convert(mem_ctx, handle, name, timestamp, NULL);
857 }
858
859 /*
860   modify a sbuf return to ensure that inodes in the shadow directory
861   are different from those in the main directory
862  */
863 static void convert_sbuf(vfs_handle_struct *handle, const char *fname,
864                          SMB_STRUCT_STAT *sbuf)
865 {
866         struct shadow_copy2_private *priv;
867
868         SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
869                                 return);
870
871         if (priv->config->fixinodes) {
872                 /* some snapshot systems, like GPFS, return the name
873                    device:inode for the snapshot files as the current
874                    files. That breaks the 'restore' button in the shadow copy
875                    GUI, as the client gets a sharing violation.
876
877                    This is a crude way of allowing both files to be
878                    open at once. It has a slight chance of inode
879                    number collision, but I can't see a better approach
880                    without significant VFS changes
881                 */
882                 TDB_DATA key = { .dptr = discard_const_p(uint8_t, fname),
883                                  .dsize = strlen(fname) };
884                 uint32_t shash;
885
886                 shash = tdb_jenkins_hash(&key) & 0xFF000000;
887                 if (shash == 0) {
888                         shash = 1;
889                 }
890                 sbuf->st_ex_ino ^= shash;
891         }
892 }
893
894 static DIR *shadow_copy2_opendir(vfs_handle_struct *handle,
895                         const struct smb_filename *smb_fname,
896                         const char *mask,
897                         uint32_t attr)
898 {
899         time_t timestamp = 0;
900         char *stripped = NULL;
901         DIR *ret;
902         int saved_errno;
903         char *conv;
904         struct smb_filename *conv_smb_fname = NULL;
905
906         if (!shadow_copy2_strip_snapshot(talloc_tos(),
907                                 handle,
908                                 smb_fname->base_name,
909                                 &timestamp,
910                                 &stripped)) {
911                 return NULL;
912         }
913         if (timestamp == 0) {
914                 return SMB_VFS_NEXT_OPENDIR(handle, smb_fname, mask, attr);
915         }
916         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
917         TALLOC_FREE(stripped);
918         if (conv == NULL) {
919                 return NULL;
920         }
921         conv_smb_fname = synthetic_smb_fname(talloc_tos(),
922                                         conv,
923                                         NULL,
924                                         NULL,
925                                         smb_fname->flags);
926         if (conv_smb_fname == NULL) {
927                 TALLOC_FREE(conv);
928                 return NULL;
929         }
930         ret = SMB_VFS_NEXT_OPENDIR(handle, conv_smb_fname, mask, attr);
931         saved_errno = errno;
932         TALLOC_FREE(conv);
933         TALLOC_FREE(conv_smb_fname);
934         errno = saved_errno;
935         return ret;
936 }
937
938 static int shadow_copy2_rename(vfs_handle_struct *handle,
939                                const struct smb_filename *smb_fname_src,
940                                const struct smb_filename *smb_fname_dst)
941 {
942         time_t timestamp_src = 0;
943         time_t timestamp_dst = 0;
944
945         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
946                                          smb_fname_src->base_name,
947                                          &timestamp_src, NULL)) {
948                 return -1;
949         }
950         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
951                                          smb_fname_dst->base_name,
952                                          &timestamp_dst, NULL)) {
953                 return -1;
954         }
955         if (timestamp_src != 0) {
956                 errno = EXDEV;
957                 return -1;
958         }
959         if (timestamp_dst != 0) {
960                 errno = EROFS;
961                 return -1;
962         }
963         return SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst);
964 }
965
966 static int shadow_copy2_symlink(vfs_handle_struct *handle,
967                                 const char *oldname, const char *newname)
968 {
969         time_t timestamp_old = 0;
970         time_t timestamp_new = 0;
971
972         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname,
973                                          &timestamp_old, NULL)) {
974                 return -1;
975         }
976         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname,
977                                          &timestamp_new, NULL)) {
978                 return -1;
979         }
980         if ((timestamp_old != 0) || (timestamp_new != 0)) {
981                 errno = EROFS;
982                 return -1;
983         }
984         return SMB_VFS_NEXT_SYMLINK(handle, oldname, newname);
985 }
986
987 static int shadow_copy2_link(vfs_handle_struct *handle,
988                              const char *oldname, const char *newname)
989 {
990         time_t timestamp_old = 0;
991         time_t timestamp_new = 0;
992
993         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, oldname,
994                                          &timestamp_old, NULL)) {
995                 return -1;
996         }
997         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, newname,
998                                          &timestamp_new, NULL)) {
999                 return -1;
1000         }
1001         if ((timestamp_old != 0) || (timestamp_new != 0)) {
1002                 errno = EROFS;
1003                 return -1;
1004         }
1005         return SMB_VFS_NEXT_LINK(handle, oldname, newname);
1006 }
1007
1008 static int shadow_copy2_stat(vfs_handle_struct *handle,
1009                              struct smb_filename *smb_fname)
1010 {
1011         time_t timestamp = 0;
1012         char *stripped = NULL;
1013         char *tmp;
1014         int ret, saved_errno;
1015
1016         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1017                                          smb_fname->base_name,
1018                                          &timestamp, &stripped)) {
1019                 return -1;
1020         }
1021         if (timestamp == 0) {
1022                 return SMB_VFS_NEXT_STAT(handle, smb_fname);
1023         }
1024
1025         tmp = smb_fname->base_name;
1026         smb_fname->base_name = shadow_copy2_convert(
1027                 talloc_tos(), handle, stripped, timestamp);
1028         TALLOC_FREE(stripped);
1029
1030         if (smb_fname->base_name == NULL) {
1031                 smb_fname->base_name = tmp;
1032                 return -1;
1033         }
1034
1035         ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
1036         saved_errno = errno;
1037
1038         TALLOC_FREE(smb_fname->base_name);
1039         smb_fname->base_name = tmp;
1040
1041         if (ret == 0) {
1042                 convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
1043         }
1044         errno = saved_errno;
1045         return ret;
1046 }
1047
1048 static int shadow_copy2_lstat(vfs_handle_struct *handle,
1049                               struct smb_filename *smb_fname)
1050 {
1051         time_t timestamp = 0;
1052         char *stripped = NULL;
1053         char *tmp;
1054         int ret, saved_errno;
1055
1056         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1057                                          smb_fname->base_name,
1058                                          &timestamp, &stripped)) {
1059                 return -1;
1060         }
1061         if (timestamp == 0) {
1062                 return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1063         }
1064
1065         tmp = smb_fname->base_name;
1066         smb_fname->base_name = shadow_copy2_convert(
1067                 talloc_tos(), handle, stripped, timestamp);
1068         TALLOC_FREE(stripped);
1069
1070         if (smb_fname->base_name == NULL) {
1071                 smb_fname->base_name = tmp;
1072                 return -1;
1073         }
1074
1075         ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
1076         saved_errno = errno;
1077
1078         TALLOC_FREE(smb_fname->base_name);
1079         smb_fname->base_name = tmp;
1080
1081         if (ret == 0) {
1082                 convert_sbuf(handle, smb_fname->base_name, &smb_fname->st);
1083         }
1084         errno = saved_errno;
1085         return ret;
1086 }
1087
1088 static int shadow_copy2_fstat(vfs_handle_struct *handle, files_struct *fsp,
1089                               SMB_STRUCT_STAT *sbuf)
1090 {
1091         time_t timestamp = 0;
1092         int ret;
1093
1094         ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
1095         if (ret == -1) {
1096                 return ret;
1097         }
1098         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1099                                          fsp->fsp_name->base_name,
1100                                          &timestamp, NULL)) {
1101                 return 0;
1102         }
1103         if (timestamp != 0) {
1104                 convert_sbuf(handle, fsp->fsp_name->base_name, sbuf);
1105         }
1106         return 0;
1107 }
1108
1109 static int shadow_copy2_open(vfs_handle_struct *handle,
1110                              struct smb_filename *smb_fname, files_struct *fsp,
1111                              int flags, mode_t mode)
1112 {
1113         time_t timestamp = 0;
1114         char *stripped = NULL;
1115         char *tmp;
1116         int ret, saved_errno;
1117
1118         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1119                                          smb_fname->base_name,
1120                                          &timestamp, &stripped)) {
1121                 return -1;
1122         }
1123         if (timestamp == 0) {
1124                 return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
1125         }
1126
1127         tmp = smb_fname->base_name;
1128         smb_fname->base_name = shadow_copy2_convert(
1129                 talloc_tos(), handle, stripped, timestamp);
1130         TALLOC_FREE(stripped);
1131
1132         if (smb_fname->base_name == NULL) {
1133                 smb_fname->base_name = tmp;
1134                 return -1;
1135         }
1136
1137         ret = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
1138         saved_errno = errno;
1139
1140         TALLOC_FREE(smb_fname->base_name);
1141         smb_fname->base_name = tmp;
1142
1143         errno = saved_errno;
1144         return ret;
1145 }
1146
1147 static int shadow_copy2_unlink(vfs_handle_struct *handle,
1148                                const struct smb_filename *smb_fname)
1149 {
1150         time_t timestamp = 0;
1151         char *stripped = NULL;
1152         int ret, saved_errno;
1153         struct smb_filename *conv;
1154
1155         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1156                                          smb_fname->base_name,
1157                                          &timestamp, &stripped)) {
1158                 return -1;
1159         }
1160         if (timestamp == 0) {
1161                 return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
1162         }
1163         conv = cp_smb_filename(talloc_tos(), smb_fname);
1164         if (conv == NULL) {
1165                 errno = ENOMEM;
1166                 return -1;
1167         }
1168         conv->base_name = shadow_copy2_convert(
1169                 conv, handle, stripped, timestamp);
1170         TALLOC_FREE(stripped);
1171         if (conv->base_name == NULL) {
1172                 return -1;
1173         }
1174         ret = SMB_VFS_NEXT_UNLINK(handle, conv);
1175         saved_errno = errno;
1176         TALLOC_FREE(conv);
1177         errno = saved_errno;
1178         return ret;
1179 }
1180
1181 static int shadow_copy2_chmod(vfs_handle_struct *handle,
1182                         const struct smb_filename *smb_fname,
1183                         mode_t mode)
1184 {
1185         time_t timestamp = 0;
1186         char *stripped = NULL;
1187         int ret, saved_errno;
1188         char *conv = NULL;
1189         struct smb_filename *conv_smb_fname;
1190
1191         if (!shadow_copy2_strip_snapshot(talloc_tos(),
1192                                 handle,
1193                                 smb_fname->base_name,
1194                                 &timestamp,
1195                                 &stripped)) {
1196                 return -1;
1197         }
1198         if (timestamp == 0) {
1199                 TALLOC_FREE(stripped);
1200                 return SMB_VFS_NEXT_CHMOD(handle, smb_fname, mode);
1201         }
1202         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1203         TALLOC_FREE(stripped);
1204         if (conv == NULL) {
1205                 return -1;
1206         }
1207         conv_smb_fname = synthetic_smb_fname(talloc_tos(),
1208                                         conv,
1209                                         NULL,
1210                                         NULL,
1211                                         smb_fname->flags);
1212         if (conv_smb_fname == NULL) {
1213                 TALLOC_FREE(conv);
1214                 errno = ENOMEM;
1215                 return -1;
1216         }
1217
1218         ret = SMB_VFS_NEXT_CHMOD(handle, conv_smb_fname, mode);
1219         saved_errno = errno;
1220         TALLOC_FREE(conv);
1221         TALLOC_FREE(conv_smb_fname);
1222         errno = saved_errno;
1223         return ret;
1224 }
1225
1226 static int shadow_copy2_chown(vfs_handle_struct *handle,
1227                         const struct smb_filename *smb_fname,
1228                         uid_t uid,
1229                         gid_t gid)
1230 {
1231         time_t timestamp = 0;
1232         char *stripped = NULL;
1233         int ret, saved_errno;
1234         char *conv = NULL;
1235         struct smb_filename *conv_smb_fname = NULL;
1236
1237         if (!shadow_copy2_strip_snapshot(talloc_tos(),
1238                                 handle,
1239                                 smb_fname->base_name,
1240                                 &timestamp,
1241                                 &stripped)) {
1242                 return -1;
1243         }
1244         if (timestamp == 0) {
1245                 return SMB_VFS_NEXT_CHOWN(handle, smb_fname, uid, gid);
1246         }
1247         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1248         TALLOC_FREE(stripped);
1249         if (conv == NULL) {
1250                 return -1;
1251         }
1252         conv_smb_fname = synthetic_smb_fname(talloc_tos(),
1253                                         conv,
1254                                         NULL,
1255                                         NULL,
1256                                         smb_fname->flags);
1257         if (conv_smb_fname == NULL) {
1258                 TALLOC_FREE(conv);
1259                 errno = ENOMEM;
1260                 return -1;
1261         }
1262         ret = SMB_VFS_NEXT_CHOWN(handle, conv_smb_fname, uid, gid);
1263         saved_errno = errno;
1264         TALLOC_FREE(conv);
1265         TALLOC_FREE(conv_smb_fname);
1266         errno = saved_errno;
1267         return ret;
1268 }
1269
1270 static int shadow_copy2_chdir(vfs_handle_struct *handle,
1271                               const char *fname)
1272 {
1273         time_t timestamp = 0;
1274         char *stripped = NULL;
1275         int ret, saved_errno;
1276         char *conv;
1277
1278         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1279                                          &timestamp, &stripped)) {
1280                 return -1;
1281         }
1282         if (timestamp == 0) {
1283                 return SMB_VFS_NEXT_CHDIR(handle, fname);
1284         }
1285         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1286         TALLOC_FREE(stripped);
1287         if (conv == NULL) {
1288                 return -1;
1289         }
1290         ret = SMB_VFS_NEXT_CHDIR(handle, conv);
1291         saved_errno = errno;
1292         TALLOC_FREE(conv);
1293         errno = saved_errno;
1294         return ret;
1295 }
1296
1297 static int shadow_copy2_ntimes(vfs_handle_struct *handle,
1298                                const struct smb_filename *smb_fname,
1299                                struct smb_file_time *ft)
1300 {
1301         time_t timestamp = 0;
1302         char *stripped = NULL;
1303         int ret, saved_errno;
1304         struct smb_filename *conv;
1305
1306         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1307                                          smb_fname->base_name,
1308                                          &timestamp, &stripped)) {
1309                 return -1;
1310         }
1311         if (timestamp == 0) {
1312                 return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
1313         }
1314         conv = cp_smb_filename(talloc_tos(), smb_fname);
1315         if (conv == NULL) {
1316                 errno = ENOMEM;
1317                 return -1;
1318         }
1319         conv->base_name = shadow_copy2_convert(
1320                 conv, handle, stripped, timestamp);
1321         TALLOC_FREE(stripped);
1322         if (conv->base_name == NULL) {
1323                 return -1;
1324         }
1325         ret = SMB_VFS_NEXT_NTIMES(handle, conv, ft);
1326         saved_errno = errno;
1327         TALLOC_FREE(conv);
1328         errno = saved_errno;
1329         return ret;
1330 }
1331
1332 static int shadow_copy2_readlink(vfs_handle_struct *handle,
1333                                  const char *fname, char *buf, size_t bufsiz)
1334 {
1335         time_t timestamp = 0;
1336         char *stripped = NULL;
1337         int ret, saved_errno;
1338         char *conv;
1339
1340         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1341                                          &timestamp, &stripped)) {
1342                 return -1;
1343         }
1344         if (timestamp == 0) {
1345                 return SMB_VFS_NEXT_READLINK(handle, fname, buf, bufsiz);
1346         }
1347         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1348         TALLOC_FREE(stripped);
1349         if (conv == NULL) {
1350                 return -1;
1351         }
1352         ret = SMB_VFS_NEXT_READLINK(handle, conv, buf, bufsiz);
1353         saved_errno = errno;
1354         TALLOC_FREE(conv);
1355         errno = saved_errno;
1356         return ret;
1357 }
1358
1359 static int shadow_copy2_mknod(vfs_handle_struct *handle,
1360                               const char *fname, mode_t mode, SMB_DEV_T dev)
1361 {
1362         time_t timestamp = 0;
1363         char *stripped = NULL;
1364         int ret, saved_errno;
1365         char *conv;
1366
1367         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1368                                          &timestamp, &stripped)) {
1369                 return -1;
1370         }
1371         if (timestamp == 0) {
1372                 return SMB_VFS_NEXT_MKNOD(handle, fname, mode, dev);
1373         }
1374         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1375         TALLOC_FREE(stripped);
1376         if (conv == NULL) {
1377                 return -1;
1378         }
1379         ret = SMB_VFS_NEXT_MKNOD(handle, conv, mode, dev);
1380         saved_errno = errno;
1381         TALLOC_FREE(conv);
1382         errno = saved_errno;
1383         return ret;
1384 }
1385
1386 static char *shadow_copy2_realpath(vfs_handle_struct *handle,
1387                                    const char *fname)
1388 {
1389         time_t timestamp = 0;
1390         char *stripped = NULL;
1391         char *tmp = NULL;
1392         char *result = NULL;
1393         int saved_errno;
1394
1395         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1396                                          &timestamp, &stripped)) {
1397                 goto done;
1398         }
1399         if (timestamp == 0) {
1400                 return SMB_VFS_NEXT_REALPATH(handle, fname);
1401         }
1402
1403         tmp = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1404         if (tmp == NULL) {
1405                 goto done;
1406         }
1407
1408         result = SMB_VFS_NEXT_REALPATH(handle, tmp);
1409
1410 done:
1411         saved_errno = errno;
1412         TALLOC_FREE(tmp);
1413         TALLOC_FREE(stripped);
1414         errno = saved_errno;
1415         return result;
1416 }
1417
1418 /**
1419  * Check whether a given directory contains a
1420  * snapshot directory as direct subdirectory.
1421  * If yes, return the path of the snapshot-subdir,
1422  * otherwise return NULL.
1423  */
1424 static char *have_snapdir(struct vfs_handle_struct *handle,
1425                           const char *path)
1426 {
1427         struct smb_filename smb_fname;
1428         int ret;
1429         struct shadow_copy2_private *priv;
1430
1431         SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
1432                                 return NULL);
1433
1434         ZERO_STRUCT(smb_fname);
1435         smb_fname.base_name = talloc_asprintf(talloc_tos(), "%s/%s",
1436                                               path, priv->config->snapdir);
1437         if (smb_fname.base_name == NULL) {
1438                 return NULL;
1439         }
1440
1441         ret = SMB_VFS_NEXT_STAT(handle, &smb_fname);
1442         if ((ret == 0) && (S_ISDIR(smb_fname.st.st_ex_mode))) {
1443                 return smb_fname.base_name;
1444         }
1445         TALLOC_FREE(smb_fname.base_name);
1446         return NULL;
1447 }
1448
1449 static bool check_access_snapdir(struct vfs_handle_struct *handle,
1450                                 const char *path)
1451 {
1452         struct smb_filename smb_fname;
1453         int ret;
1454         NTSTATUS status;
1455
1456         ZERO_STRUCT(smb_fname);
1457         smb_fname.base_name = talloc_asprintf(talloc_tos(),
1458                                                 "%s",
1459                                                 path);
1460         if (smb_fname.base_name == NULL) {
1461                 return false;
1462         }
1463
1464         ret = SMB_VFS_NEXT_STAT(handle, &smb_fname);
1465         if (ret != 0 || !S_ISDIR(smb_fname.st.st_ex_mode)) {
1466                 TALLOC_FREE(smb_fname.base_name);
1467                 return false;
1468         }
1469
1470         status = smbd_check_access_rights(handle->conn,
1471                                         &smb_fname,
1472                                         false,
1473                                         SEC_DIR_LIST);
1474         if (!NT_STATUS_IS_OK(status)) {
1475                 DEBUG(0,("user does not have list permission "
1476                         "on snapdir %s\n",
1477                         smb_fname.base_name));
1478                 TALLOC_FREE(smb_fname.base_name);
1479                 return false;
1480         }
1481         TALLOC_FREE(smb_fname.base_name);
1482         return true;
1483 }
1484
1485 /**
1486  * Find the snapshot directory (if any) for the given
1487  * filename (which is relative to the share).
1488  */
1489 static const char *shadow_copy2_find_snapdir(TALLOC_CTX *mem_ctx,
1490                                              struct vfs_handle_struct *handle,
1491                                              struct smb_filename *smb_fname)
1492 {
1493         char *path, *p;
1494         const char *snapdir;
1495         struct shadow_copy2_config *config;
1496         struct shadow_copy2_private *priv;
1497
1498         SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
1499                                 return NULL);
1500
1501         config = priv->config;
1502
1503         /*
1504          * If the non-snapdisrseverywhere mode, we should not search!
1505          */
1506         if (!config->snapdirseverywhere) {
1507                 return config->snapshot_basepath;
1508         }
1509
1510         path = talloc_asprintf(mem_ctx, "%s/%s",
1511                                handle->conn->connectpath,
1512                                smb_fname->base_name);
1513         if (path == NULL) {
1514                 return NULL;
1515         }
1516
1517         snapdir = have_snapdir(handle, path);
1518         if (snapdir != NULL) {
1519                 TALLOC_FREE(path);
1520                 return snapdir;
1521         }
1522
1523         while ((p = strrchr(path, '/')) && (p > path)) {
1524
1525                 p[0] = '\0';
1526
1527                 snapdir = have_snapdir(handle, path);
1528                 if (snapdir != NULL) {
1529                         TALLOC_FREE(path);
1530                         return snapdir;
1531                 }
1532         }
1533         TALLOC_FREE(path);
1534         return NULL;
1535 }
1536
1537 static bool shadow_copy2_snapshot_to_gmt(vfs_handle_struct *handle,
1538                                          const char *name,
1539                                          char *gmt, size_t gmt_len)
1540 {
1541         struct tm timestamp;
1542         time_t timestamp_t;
1543         unsigned long int timestamp_long;
1544         const char *fmt;
1545         struct shadow_copy2_config *config;
1546         struct shadow_copy2_private *priv;
1547         char *tmpstr = NULL;
1548         char *tmp = NULL;
1549         bool converted = false;
1550         int ret = -1;
1551
1552         SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
1553                                 return NULL);
1554
1555         config = priv->config;
1556
1557         fmt = config->gmt_format;
1558
1559         /*
1560          * If regex is provided, then we will have to parse the
1561          * filename which will contain both the prefix and the time format.
1562          * e.g. <prefix><delimiter><time_format>
1563          */
1564         if (priv->snaps->regex != NULL) {
1565                 tmpstr = talloc_strdup(talloc_tos(), name);
1566                 /* point "name" to the time format */
1567                 name = strstr(name, priv->config->delimiter);
1568                 if (name == NULL) {
1569                         goto done;
1570                 }
1571                 /* Extract the prefix */
1572                 tmp = strstr(tmpstr, priv->config->delimiter);
1573                 *tmp = '\0';
1574
1575                 /* Parse regex */
1576                 ret = regexec(priv->snaps->regex, tmpstr, 0, NULL, 0);
1577                 if (ret) {
1578                         DBG_DEBUG("shadow_copy2_snapshot_to_gmt: "
1579                                   "no regex match for %s\n", tmpstr);
1580                         goto done;
1581                 }
1582         }
1583
1584         ZERO_STRUCT(timestamp);
1585         if (config->use_sscanf) {
1586                 if (sscanf(name, fmt, &timestamp_long) != 1) {
1587                         DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1588                                    "no sscanf match %s: %s\n",
1589                                    fmt, name));
1590                         goto done;
1591                 }
1592                 timestamp_t = timestamp_long;
1593                 gmtime_r(&timestamp_t, &timestamp);
1594         } else {
1595                 if (strptime(name, fmt, &timestamp) == NULL) {
1596                         DEBUG(10, ("shadow_copy2_snapshot_to_gmt: "
1597                                    "no match %s: %s\n",
1598                                    fmt, name));
1599                         goto done;
1600                 }
1601                 DEBUG(10, ("shadow_copy2_snapshot_to_gmt: match %s: %s\n",
1602                            fmt, name));
1603                 
1604                 if (config->use_localtime) {
1605                         timestamp.tm_isdst = -1;
1606                         timestamp_t = mktime(&timestamp);
1607                         gmtime_r(&timestamp_t, &timestamp);
1608                 }
1609         }
1610
1611         strftime(gmt, gmt_len, GMT_FORMAT, &timestamp);
1612         converted = true;
1613
1614 done:
1615         TALLOC_FREE(tmpstr);
1616         return converted;
1617 }
1618
1619 static int shadow_copy2_label_cmp_asc(const void *x, const void *y)
1620 {
1621         return strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
1622 }
1623
1624 static int shadow_copy2_label_cmp_desc(const void *x, const void *y)
1625 {
1626         return -strncmp((const char *)x, (const char *)y, sizeof(SHADOW_COPY_LABEL));
1627 }
1628
1629 /*
1630   sort the shadow copy data in ascending or descending order
1631  */
1632 static void shadow_copy2_sort_data(vfs_handle_struct *handle,
1633                                    struct shadow_copy_data *shadow_copy2_data)
1634 {
1635         int (*cmpfunc)(const void *, const void *);
1636         const char *sort;
1637         struct shadow_copy2_private *priv;
1638
1639         SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
1640                                 return);
1641
1642         sort = priv->config->sort_order;
1643         if (sort == NULL) {
1644                 return;
1645         }
1646
1647         if (strcmp(sort, "asc") == 0) {
1648                 cmpfunc = shadow_copy2_label_cmp_asc;
1649         } else if (strcmp(sort, "desc") == 0) {
1650                 cmpfunc = shadow_copy2_label_cmp_desc;
1651         } else {
1652                 return;
1653         }
1654
1655         if (shadow_copy2_data && shadow_copy2_data->num_volumes > 0 &&
1656             shadow_copy2_data->labels)
1657         {
1658                 TYPESAFE_QSORT(shadow_copy2_data->labels,
1659                                shadow_copy2_data->num_volumes,
1660                                cmpfunc);
1661         }
1662 }
1663
1664 static int shadow_copy2_get_shadow_copy_data(
1665         vfs_handle_struct *handle, files_struct *fsp,
1666         struct shadow_copy_data *shadow_copy2_data,
1667         bool labels)
1668 {
1669         DIR *p;
1670         const char *snapdir;
1671         struct smb_filename *snapdir_smb_fname = NULL;
1672         struct dirent *d;
1673         TALLOC_CTX *tmp_ctx = talloc_stackframe();
1674         struct shadow_copy2_private *priv = NULL;
1675         struct shadow_copy2_snapentry *tmpentry = NULL;
1676         bool get_snaplist = false;
1677         bool access_granted = false;
1678         int ret = -1;
1679
1680         snapdir = shadow_copy2_find_snapdir(tmp_ctx, handle, fsp->fsp_name);
1681         if (snapdir == NULL) {
1682                 DEBUG(0,("shadow:snapdir not found for %s in get_shadow_copy_data\n",
1683                          handle->conn->connectpath));
1684                 errno = EINVAL;
1685                 goto done;
1686         }
1687
1688         access_granted = check_access_snapdir(handle, snapdir);
1689         if (!access_granted) {
1690                 DEBUG(0,("access denied on listing snapdir %s\n", snapdir));
1691                 errno = EACCES;
1692                 goto done;
1693         }
1694
1695         snapdir_smb_fname = synthetic_smb_fname(talloc_tos(),
1696                                         snapdir,
1697                                         NULL,
1698                                         NULL,
1699                                         fsp->fsp_name->flags);
1700         if (snapdir_smb_fname == NULL) {
1701                 errno = ENOMEM;
1702                 goto done;
1703         }
1704
1705         p = SMB_VFS_NEXT_OPENDIR(handle, snapdir_smb_fname, NULL, 0);
1706
1707         if (!p) {
1708                 DEBUG(2,("shadow_copy2: SMB_VFS_NEXT_OPENDIR() failed for '%s'"
1709                          " - %s\n", snapdir, strerror(errno)));
1710                 errno = ENOSYS;
1711                 goto done;
1712         }
1713
1714         if (shadow_copy2_data != NULL) {
1715                 shadow_copy2_data->num_volumes = 0;
1716                 shadow_copy2_data->labels      = NULL;
1717         }
1718
1719         SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private,
1720                                 goto done);
1721
1722         /*
1723          * Normally this function is called twice once with labels = false and
1724          * then with labels = true. When labels is false it will return the
1725          * number of volumes so that the caller can allocate memory for that
1726          * many labels. Therefore to eliminate snaplist both the times it is
1727          * good to check if labels is set or not.
1728          *
1729          * shadow_copy2_data is NULL when we only want to update the list and
1730          * don't want any labels.
1731          */
1732         if ((priv->snaps->regex != NULL) && (labels || shadow_copy2_data == NULL)) {
1733                 get_snaplist = true;
1734                 /* Reset the global snaplist */
1735                 shadow_copy2_delete_snaplist(priv);
1736
1737                 /* Set the current time as snaplist update time */
1738                 time(&(priv->snaps->fetch_time));
1739         }
1740
1741         while ((d = SMB_VFS_NEXT_READDIR(handle, p, NULL))) {
1742                 char snapshot[GMT_NAME_LEN+1];
1743                 SHADOW_COPY_LABEL *tlabels;
1744
1745                 /*
1746                  * ignore names not of the right form in the snapshot
1747                  * directory
1748                  */
1749                 if (!shadow_copy2_snapshot_to_gmt(
1750                             handle, d->d_name,
1751                             snapshot, sizeof(snapshot))) {
1752
1753                         DEBUG(6, ("shadow_copy2_get_shadow_copy_data: "
1754                                   "ignoring %s\n", d->d_name));
1755                         continue;
1756                 }
1757                 DEBUG(6,("shadow_copy2_get_shadow_copy_data: %s -> %s\n",
1758                          d->d_name, snapshot));
1759
1760                 if (get_snaplist) {
1761                         /*
1762                          * Create a snap entry for each successful
1763                          * pattern match.
1764                          */
1765                         tmpentry = shadow_copy2_create_snapentry(priv);
1766                         if (tmpentry == NULL) {
1767                                 DBG_ERR("talloc_zero() failed\n");
1768                                 goto done;
1769                         }
1770                         tmpentry->snapname = talloc_strdup(tmpentry, d->d_name);
1771                         tmpentry->time_fmt = talloc_strdup(tmpentry, snapshot);
1772                 }
1773
1774                 if (shadow_copy2_data == NULL) {
1775                         continue;
1776                 }
1777
1778                 if (!labels) {
1779                         /* the caller doesn't want the labels */
1780                         shadow_copy2_data->num_volumes++;
1781                         continue;
1782                 }
1783
1784                 tlabels = talloc_realloc(shadow_copy2_data,
1785                                          shadow_copy2_data->labels,
1786                                          SHADOW_COPY_LABEL,
1787                                          shadow_copy2_data->num_volumes+1);
1788                 if (tlabels == NULL) {
1789                         DEBUG(0,("shadow_copy2: out of memory\n"));
1790                         SMB_VFS_NEXT_CLOSEDIR(handle, p);
1791                         goto done;
1792                 }
1793
1794                 strlcpy(tlabels[shadow_copy2_data->num_volumes], snapshot,
1795                         sizeof(*tlabels));
1796
1797                 shadow_copy2_data->num_volumes++;
1798                 shadow_copy2_data->labels = tlabels;
1799         }
1800
1801         SMB_VFS_NEXT_CLOSEDIR(handle,p);
1802
1803         shadow_copy2_sort_data(handle, shadow_copy2_data);
1804         ret = 0;
1805
1806 done:
1807         TALLOC_FREE(tmp_ctx);
1808         return ret;
1809 }
1810
1811 static NTSTATUS shadow_copy2_fget_nt_acl(vfs_handle_struct *handle,
1812                                         struct files_struct *fsp,
1813                                         uint32_t security_info,
1814                                          TALLOC_CTX *mem_ctx,
1815                                         struct security_descriptor **ppdesc)
1816 {
1817         time_t timestamp = 0;
1818         char *stripped = NULL;
1819         NTSTATUS status;
1820         char *conv;
1821         struct smb_filename *smb_fname = NULL;
1822
1823         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle,
1824                                          fsp->fsp_name->base_name,
1825                                          &timestamp, &stripped)) {
1826                 return map_nt_error_from_unix(errno);
1827         }
1828         if (timestamp == 0) {
1829                 return SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info,
1830                                                 mem_ctx,
1831                                                 ppdesc);
1832         }
1833         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1834         TALLOC_FREE(stripped);
1835         if (conv == NULL) {
1836                 return map_nt_error_from_unix(errno);
1837         }
1838         smb_fname = synthetic_smb_fname(talloc_tos(),
1839                                         conv,
1840                                         NULL,
1841                                         NULL,
1842                                         fsp->fsp_name->flags);
1843         if (smb_fname == NULL) {
1844                 TALLOC_FREE(conv);
1845                 return NT_STATUS_NO_MEMORY;
1846         }
1847
1848         status = SMB_VFS_NEXT_GET_NT_ACL(handle, smb_fname, security_info,
1849                                          mem_ctx, ppdesc);
1850         TALLOC_FREE(conv);
1851         TALLOC_FREE(smb_fname);
1852         return status;
1853 }
1854
1855 static NTSTATUS shadow_copy2_get_nt_acl(vfs_handle_struct *handle,
1856                                         const struct smb_filename *smb_fname,
1857                                         uint32_t security_info,
1858                                         TALLOC_CTX *mem_ctx,
1859                                         struct security_descriptor **ppdesc)
1860 {
1861         time_t timestamp = 0;
1862         char *stripped = NULL;
1863         NTSTATUS status;
1864         char *conv;
1865         struct smb_filename *conv_smb_fname = NULL;
1866
1867         if (!shadow_copy2_strip_snapshot(talloc_tos(),
1868                                         handle,
1869                                         smb_fname->base_name,
1870                                         &timestamp,
1871                                         &stripped)) {
1872                 return map_nt_error_from_unix(errno);
1873         }
1874         if (timestamp == 0) {
1875                 return SMB_VFS_NEXT_GET_NT_ACL(handle, smb_fname, security_info,
1876                                                mem_ctx, ppdesc);
1877         }
1878         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1879         TALLOC_FREE(stripped);
1880         if (conv == NULL) {
1881                 return map_nt_error_from_unix(errno);
1882         }
1883         conv_smb_fname = synthetic_smb_fname(talloc_tos(),
1884                                         conv,
1885                                         NULL,
1886                                         NULL,
1887                                         smb_fname->flags);
1888         if (conv_smb_fname == NULL) {
1889                 TALLOC_FREE(conv);
1890                 return NT_STATUS_NO_MEMORY;
1891         }
1892         status = SMB_VFS_NEXT_GET_NT_ACL(handle, conv_smb_fname, security_info,
1893                                          mem_ctx, ppdesc);
1894         TALLOC_FREE(conv);
1895         TALLOC_FREE(conv_smb_fname);
1896         return status;
1897 }
1898
1899 static int shadow_copy2_mkdir(vfs_handle_struct *handle,
1900                                 const struct smb_filename *smb_fname,
1901                                 mode_t mode)
1902 {
1903         time_t timestamp = 0;
1904         char *stripped = NULL;
1905         int ret, saved_errno;
1906         char *conv;
1907         struct smb_filename *conv_smb_fname = NULL;
1908
1909         if (!shadow_copy2_strip_snapshot(talloc_tos(),
1910                                         handle,
1911                                         smb_fname->base_name,
1912                                         &timestamp,
1913                                         &stripped)) {
1914                 return -1;
1915         }
1916         if (timestamp == 0) {
1917                 return SMB_VFS_NEXT_MKDIR(handle, smb_fname, mode);
1918         }
1919         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1920         TALLOC_FREE(stripped);
1921         if (conv == NULL) {
1922                 return -1;
1923         }
1924         conv_smb_fname = synthetic_smb_fname(talloc_tos(),
1925                                         conv,
1926                                         NULL,
1927                                         NULL,
1928                                         smb_fname->flags);
1929         if (conv_smb_fname == NULL) {
1930                 TALLOC_FREE(conv);
1931                 return -1;
1932         }
1933         ret = SMB_VFS_NEXT_MKDIR(handle, conv_smb_fname, mode);
1934         saved_errno = errno;
1935         TALLOC_FREE(conv);
1936         TALLOC_FREE(conv_smb_fname);
1937         errno = saved_errno;
1938         return ret;
1939 }
1940
1941 static int shadow_copy2_rmdir(vfs_handle_struct *handle,
1942                                 const struct smb_filename *smb_fname)
1943 {
1944         time_t timestamp = 0;
1945         char *stripped = NULL;
1946         int ret, saved_errno;
1947         char *conv;
1948         struct smb_filename *conv_smb_fname = NULL;
1949
1950         if (!shadow_copy2_strip_snapshot(talloc_tos(),
1951                                         handle,
1952                                         smb_fname->base_name,
1953                                         &timestamp,
1954                                         &stripped)) {
1955                 return -1;
1956         }
1957         if (timestamp == 0) {
1958                 return SMB_VFS_NEXT_RMDIR(handle, smb_fname);
1959         }
1960         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1961         TALLOC_FREE(stripped);
1962         if (conv == NULL) {
1963                 return -1;
1964         }
1965         conv_smb_fname = synthetic_smb_fname(talloc_tos(),
1966                                         conv,
1967                                         NULL,
1968                                         NULL,
1969                                         smb_fname->flags);
1970         if (conv_smb_fname == NULL) {
1971                 TALLOC_FREE(conv);
1972                 return -1;
1973         }
1974         ret = SMB_VFS_NEXT_RMDIR(handle, conv_smb_fname);
1975         saved_errno = errno;
1976         TALLOC_FREE(conv_smb_fname);
1977         TALLOC_FREE(conv);
1978         errno = saved_errno;
1979         return ret;
1980 }
1981
1982 static int shadow_copy2_chflags(vfs_handle_struct *handle, const char *fname,
1983                                 unsigned int flags)
1984 {
1985         time_t timestamp = 0;
1986         char *stripped = NULL;
1987         int ret, saved_errno;
1988         char *conv;
1989
1990         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
1991                                          &timestamp, &stripped)) {
1992                 return -1;
1993         }
1994         if (timestamp == 0) {
1995                 return SMB_VFS_NEXT_CHFLAGS(handle, fname, flags);
1996         }
1997         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
1998         TALLOC_FREE(stripped);
1999         if (conv == NULL) {
2000                 return -1;
2001         }
2002         ret = SMB_VFS_NEXT_CHFLAGS(handle, conv, flags);
2003         saved_errno = errno;
2004         TALLOC_FREE(conv);
2005         errno = saved_errno;
2006         return ret;
2007 }
2008
2009 static ssize_t shadow_copy2_getxattr(vfs_handle_struct *handle,
2010                                      const char *fname, const char *aname,
2011                                      void *value, size_t size)
2012 {
2013         time_t timestamp = 0;
2014         char *stripped = NULL;
2015         ssize_t ret;
2016         int saved_errno;
2017         char *conv;
2018
2019         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
2020                                          &timestamp, &stripped)) {
2021                 return -1;
2022         }
2023         if (timestamp == 0) {
2024                 return SMB_VFS_NEXT_GETXATTR(handle, fname, aname, value,
2025                                              size);
2026         }
2027         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2028         TALLOC_FREE(stripped);
2029         if (conv == NULL) {
2030                 return -1;
2031         }
2032         ret = SMB_VFS_NEXT_GETXATTR(handle, conv, aname, value, size);
2033         saved_errno = errno;
2034         TALLOC_FREE(conv);
2035         errno = saved_errno;
2036         return ret;
2037 }
2038
2039 static ssize_t shadow_copy2_listxattr(struct vfs_handle_struct *handle,
2040                                       const char *fname,
2041                                       char *list, size_t size)
2042 {
2043         time_t timestamp = 0;
2044         char *stripped = NULL;
2045         ssize_t ret;
2046         int saved_errno;
2047         char *conv;
2048
2049         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
2050                                          &timestamp, &stripped)) {
2051                 return -1;
2052         }
2053         if (timestamp == 0) {
2054                 return SMB_VFS_NEXT_LISTXATTR(handle, fname, list, size);
2055         }
2056         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2057         TALLOC_FREE(stripped);
2058         if (conv == NULL) {
2059                 return -1;
2060         }
2061         ret = SMB_VFS_NEXT_LISTXATTR(handle, conv, list, size);
2062         saved_errno = errno;
2063         TALLOC_FREE(conv);
2064         errno = saved_errno;
2065         return ret;
2066 }
2067
2068 static int shadow_copy2_removexattr(vfs_handle_struct *handle,
2069                                     const char *fname, const char *aname)
2070 {
2071         time_t timestamp = 0;
2072         char *stripped = NULL;
2073         int ret, saved_errno;
2074         char *conv;
2075
2076         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
2077                                          &timestamp, &stripped)) {
2078                 return -1;
2079         }
2080         if (timestamp == 0) {
2081                 return SMB_VFS_NEXT_REMOVEXATTR(handle, fname, aname);
2082         }
2083         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2084         TALLOC_FREE(stripped);
2085         if (conv == NULL) {
2086                 return -1;
2087         }
2088         ret = SMB_VFS_NEXT_REMOVEXATTR(handle, conv, aname);
2089         saved_errno = errno;
2090         TALLOC_FREE(conv);
2091         errno = saved_errno;
2092         return ret;
2093 }
2094
2095 static int shadow_copy2_setxattr(struct vfs_handle_struct *handle,
2096                                  const char *fname,
2097                                  const char *aname, const void *value,
2098                                  size_t size, int flags)
2099 {
2100         time_t timestamp = 0;
2101         char *stripped = NULL;
2102         ssize_t ret;
2103         int saved_errno;
2104         char *conv;
2105
2106         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
2107                                          &timestamp, &stripped)) {
2108                 return -1;
2109         }
2110         if (timestamp == 0) {
2111                 return SMB_VFS_NEXT_SETXATTR(handle, fname, aname, value, size,
2112                                              flags);
2113         }
2114         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2115         TALLOC_FREE(stripped);
2116         if (conv == NULL) {
2117                 return -1;
2118         }
2119         ret = SMB_VFS_NEXT_SETXATTR(handle, conv, aname, value, size, flags);
2120         saved_errno = errno;
2121         TALLOC_FREE(conv);
2122         errno = saved_errno;
2123         return ret;
2124 }
2125
2126 static int shadow_copy2_chmod_acl(vfs_handle_struct *handle,
2127                         const struct smb_filename *smb_fname,
2128                         mode_t mode)
2129 {
2130         time_t timestamp = 0;
2131         char *stripped = NULL;
2132         ssize_t ret;
2133         int saved_errno;
2134         char *conv = NULL;
2135         struct smb_filename *conv_smb_fname = NULL;
2136
2137         if (!shadow_copy2_strip_snapshot(talloc_tos(),
2138                                 handle,
2139                                 smb_fname->base_name,
2140                                 &timestamp,
2141                                 &stripped)) {
2142                 return -1;
2143         }
2144         if (timestamp == 0) {
2145                 return SMB_VFS_NEXT_CHMOD_ACL(handle, smb_fname, mode);
2146         }
2147         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2148         TALLOC_FREE(stripped);
2149         if (conv == NULL) {
2150                 return -1;
2151         }
2152         conv_smb_fname = synthetic_smb_fname(talloc_tos(),
2153                                         conv,
2154                                         NULL,
2155                                         NULL,
2156                                         smb_fname->flags);
2157         if (conv_smb_fname == NULL) {
2158                 TALLOC_FREE(conv);
2159                 errno = ENOMEM;
2160                 return -1;
2161         }
2162         ret = SMB_VFS_NEXT_CHMOD_ACL(handle, conv_smb_fname, mode);
2163         saved_errno = errno;
2164         TALLOC_FREE(conv);
2165         TALLOC_FREE(conv_smb_fname);
2166         errno = saved_errno;
2167         return ret;
2168 }
2169
2170 static int shadow_copy2_get_real_filename(struct vfs_handle_struct *handle,
2171                                           const char *path,
2172                                           const char *name,
2173                                           TALLOC_CTX *mem_ctx,
2174                                           char **found_name)
2175 {
2176         time_t timestamp = 0;
2177         char *stripped = NULL;
2178         ssize_t ret;
2179         int saved_errno;
2180         char *conv;
2181
2182         DEBUG(10, ("shadow_copy2_get_real_filename called for path=[%s], "
2183                    "name=[%s]\n", path, name));
2184
2185         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path,
2186                                          &timestamp, &stripped)) {
2187                 DEBUG(10, ("shadow_copy2_strip_snapshot failed\n"));
2188                 return -1;
2189         }
2190         if (timestamp == 0) {
2191                 DEBUG(10, ("timestamp == 0\n"));
2192                 return SMB_VFS_NEXT_GET_REAL_FILENAME(handle, path, name,
2193                                                       mem_ctx, found_name);
2194         }
2195         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2196         TALLOC_FREE(stripped);
2197         if (conv == NULL) {
2198                 DEBUG(10, ("shadow_copy2_convert failed\n"));
2199                 return -1;
2200         }
2201         DEBUG(10, ("Calling NEXT_GET_REAL_FILE_NAME for conv=[%s], "
2202                    "name=[%s]\n", conv, name));
2203         ret = SMB_VFS_NEXT_GET_REAL_FILENAME(handle, conv, name,
2204                                              mem_ctx, found_name);
2205         DEBUG(10, ("NEXT_REAL_FILE_NAME returned %d\n", (int)ret));
2206         saved_errno = errno;
2207         TALLOC_FREE(conv);
2208         errno = saved_errno;
2209         return ret;
2210 }
2211
2212 static const char *shadow_copy2_connectpath(struct vfs_handle_struct *handle,
2213                                             const char *fname)
2214 {
2215         time_t timestamp = 0;
2216         char *stripped = NULL;
2217         char *tmp = NULL;
2218         char *result = NULL;
2219         char *parent_dir = NULL;
2220         int saved_errno;
2221         size_t rootpath_len = 0;
2222
2223         DBG_DEBUG("Calc connect path for [%s]\n", fname);
2224
2225         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, fname,
2226                                          &timestamp, &stripped)) {
2227                 goto done;
2228         }
2229         if (timestamp == 0) {
2230                 return SMB_VFS_NEXT_CONNECTPATH(handle, fname);
2231         }
2232
2233         tmp = shadow_copy2_do_convert(talloc_tos(), handle, stripped, timestamp,
2234                                       &rootpath_len);
2235         if (tmp == NULL) {
2236                 if (errno != ENOENT) {
2237                         goto done;
2238                 }
2239
2240                 /*
2241                  * If the converted path does not exist, and converting
2242                  * the parent yields something that does exist, then
2243                  * this path refers to something that has not been
2244                  * created yet, relative to the parent path.
2245                  * The snapshot finding is relative to the parent.
2246                  * (usually snapshots are read/only but this is not
2247                  * necessarily true).
2248                  * This code also covers getting a wildcard in the
2249                  * last component, because this function is called
2250                  * prior to sanitizing the path, and in SMB1 we may
2251                  * get wildcards in path names.
2252                  */
2253                 if (!parent_dirname(talloc_tos(), stripped, &parent_dir,
2254                                     NULL)) {
2255                         errno = ENOMEM;
2256                         goto done;
2257                 }
2258
2259                 tmp = shadow_copy2_do_convert(talloc_tos(), handle, parent_dir,
2260                                               timestamp, &rootpath_len);
2261                 if (tmp == NULL) {
2262                         goto done;
2263                 }
2264         }
2265
2266         DBG_DEBUG("converted path is [%s] root path is [%.*s]\n", tmp,
2267                   (int)rootpath_len, tmp);
2268
2269         tmp[rootpath_len] = '\0';
2270         result = SMB_VFS_NEXT_REALPATH(handle, tmp);
2271         if (result == NULL) {
2272                 goto done;
2273         }
2274
2275         DBG_DEBUG("connect path is [%s]\n", result);
2276
2277 done:
2278         saved_errno = errno;
2279         TALLOC_FREE(tmp);
2280         TALLOC_FREE(stripped);
2281         TALLOC_FREE(parent_dir);
2282         errno = saved_errno;
2283         return result;
2284 }
2285
2286 static uint64_t shadow_copy2_disk_free(vfs_handle_struct *handle,
2287                                        const char *path, uint64_t *bsize,
2288                                        uint64_t *dfree, uint64_t *dsize)
2289 {
2290         time_t timestamp = 0;
2291         char *stripped = NULL;
2292         ssize_t ret;
2293         int saved_errno;
2294         char *conv;
2295
2296         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path,
2297                                          &timestamp, &stripped)) {
2298                 return -1;
2299         }
2300         if (timestamp == 0) {
2301                 return SMB_VFS_NEXT_DISK_FREE(handle, path,
2302                                               bsize, dfree, dsize);
2303         }
2304
2305         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2306         TALLOC_FREE(stripped);
2307         if (conv == NULL) {
2308                 return -1;
2309         }
2310
2311         ret = SMB_VFS_NEXT_DISK_FREE(handle, conv, bsize, dfree, dsize);
2312
2313         saved_errno = errno;
2314         TALLOC_FREE(conv);
2315         errno = saved_errno;
2316
2317         return ret;
2318 }
2319
2320 static int shadow_copy2_get_quota(vfs_handle_struct *handle, const char *path,
2321                                   enum SMB_QUOTA_TYPE qtype, unid_t id,
2322                                   SMB_DISK_QUOTA *dq)
2323 {
2324         time_t timestamp = 0;
2325         char *stripped = NULL;
2326         int ret;
2327         int saved_errno;
2328         char *conv;
2329
2330         if (!shadow_copy2_strip_snapshot(talloc_tos(), handle, path, &timestamp,
2331                                          &stripped)) {
2332                 return -1;
2333         }
2334         if (timestamp == 0) {
2335                 return SMB_VFS_NEXT_GET_QUOTA(handle, path, qtype, id, dq);
2336         }
2337
2338         conv = shadow_copy2_convert(talloc_tos(), handle, stripped, timestamp);
2339         TALLOC_FREE(stripped);
2340         if (conv == NULL) {
2341                 return -1;
2342         }
2343
2344         ret = SMB_VFS_NEXT_GET_QUOTA(handle, conv, qtype, id, dq);
2345
2346         saved_errno = errno;
2347         TALLOC_FREE(conv);
2348         errno = saved_errno;
2349
2350         return ret;
2351 }
2352
2353 static int shadow_copy2_connect(struct vfs_handle_struct *handle,
2354                                 const char *service, const char *user)
2355 {
2356         struct shadow_copy2_config *config;
2357         struct shadow_copy2_private *priv;
2358         int ret;
2359         const char *snapdir;
2360         const char *snapprefix = NULL;
2361         const char *delimiter;
2362         const char *gmt_format;
2363         const char *sort_order;
2364         const char *basedir = NULL;
2365         const char *snapsharepath = NULL;
2366         const char *mount_point;
2367
2368         DEBUG(10, (__location__ ": cnum[%u], connectpath[%s]\n",
2369                    (unsigned)handle->conn->cnum,
2370                    handle->conn->connectpath));
2371
2372         ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
2373         if (ret < 0) {
2374                 return ret;
2375         }
2376
2377         priv = talloc_zero(handle->conn, struct shadow_copy2_private);
2378         if (priv == NULL) {
2379                 DBG_ERR("talloc_zero() failed\n");
2380                 errno = ENOMEM;
2381                 return -1;
2382         }
2383
2384         priv->snaps = talloc_zero(priv, struct shadow_copy2_snaplist_info);
2385         if (priv->snaps == NULL) {
2386                 DBG_ERR("talloc_zero() failed\n");
2387                 errno = ENOMEM;
2388                 return -1;
2389         }
2390
2391         config = talloc_zero(priv, struct shadow_copy2_config);
2392         if (config == NULL) {
2393                 DEBUG(0, ("talloc_zero() failed\n"));
2394                 errno = ENOMEM;
2395                 return -1;
2396         }
2397
2398         priv->config = config;
2399
2400         gmt_format = lp_parm_const_string(SNUM(handle->conn),
2401                                           "shadow", "format",
2402                                           GMT_FORMAT);
2403         config->gmt_format = talloc_strdup(config, gmt_format);
2404         if (config->gmt_format == NULL) {
2405                 DEBUG(0, ("talloc_strdup() failed\n"));
2406                 errno = ENOMEM;
2407                 return -1;
2408         }
2409
2410         config->use_sscanf = lp_parm_bool(SNUM(handle->conn),
2411                                           "shadow", "sscanf", false);
2412
2413         config->use_localtime = lp_parm_bool(SNUM(handle->conn),
2414                                              "shadow", "localtime",
2415                                              false);
2416
2417         snapdir = lp_parm_const_string(SNUM(handle->conn),
2418                                        "shadow", "snapdir",
2419                                        ".snapshots");
2420         config->snapdir = talloc_strdup(config, snapdir);
2421         if (config->snapdir == NULL) {
2422                 DEBUG(0, ("talloc_strdup() failed\n"));
2423                 errno = ENOMEM;
2424                 return -1;
2425         }
2426
2427         snapprefix = lp_parm_const_string(SNUM(handle->conn),
2428                                        "shadow", "snapprefix",
2429                                        NULL);
2430         if (snapprefix != NULL) {
2431                 priv->snaps->regex = talloc_zero(priv->snaps, regex_t);
2432                 if (priv->snaps->regex == NULL) {
2433                         DBG_ERR("talloc_zero() failed\n");
2434                         errno = ENOMEM;
2435                         return -1;
2436                 }
2437
2438                 /* pre-compute regex rule for matching pattern later */
2439                 ret = regcomp(priv->snaps->regex, snapprefix, 0);
2440                 if (ret) {
2441                         DBG_ERR("Failed to create regex object\n");
2442                         return -1;
2443                 }
2444         }
2445
2446         delimiter = lp_parm_const_string(SNUM(handle->conn),
2447                                        "shadow", "delimiter",
2448                                        "_GMT");
2449         if (delimiter != NULL) {
2450                 priv->config->delimiter = talloc_strdup(priv->config, delimiter);
2451                 if (priv->config->delimiter == NULL) {
2452                         DBG_ERR("talloc_strdup() failed\n");
2453                         errno = ENOMEM;
2454                         return -1;
2455                 }
2456         }
2457
2458         config->snapdirseverywhere = lp_parm_bool(SNUM(handle->conn),
2459                                                   "shadow",
2460                                                   "snapdirseverywhere",
2461                                                   false);
2462
2463         config->crossmountpoints = lp_parm_bool(SNUM(handle->conn),
2464                                                 "shadow", "crossmountpoints",
2465                                                 false);
2466
2467         if (config->crossmountpoints && !config->snapdirseverywhere) {
2468                 DBG_WARNING("Warning: 'crossmountpoints' depends on "
2469                             "'snapdirseverywhere'. Disabling crossmountpoints.\n");
2470         }
2471
2472         config->fixinodes = lp_parm_bool(SNUM(handle->conn),
2473                                          "shadow", "fixinodes",
2474                                          false);
2475
2476         sort_order = lp_parm_const_string(SNUM(handle->conn),
2477                                           "shadow", "sort", "desc");
2478         config->sort_order = talloc_strdup(config, sort_order);
2479         if (config->sort_order == NULL) {
2480                 DEBUG(0, ("talloc_strdup() failed\n"));
2481                 errno = ENOMEM;
2482                 return -1;
2483         }
2484
2485         mount_point = lp_parm_const_string(SNUM(handle->conn),
2486                                            "shadow", "mountpoint", NULL);
2487         if (mount_point != NULL) {
2488                 if (mount_point[0] != '/') {
2489                         DEBUG(1, (__location__ " Warning: 'mountpoint' is "
2490                                   "relative ('%s'), but it has to be an "
2491                                   "absolute path. Ignoring provided value.\n",
2492                                   mount_point));
2493                         mount_point = NULL;
2494                 } else {
2495                         char *p;
2496                         p = strstr(handle->conn->connectpath, mount_point);
2497                         if (p != handle->conn->connectpath) {
2498                                 DBG_WARNING("Warning: the share root (%s) is "
2499                                             "not a subdirectory of the "
2500                                             "specified mountpoint (%s). "
2501                                             "Ignoring provided value.\n",
2502                                             handle->conn->connectpath,
2503                                             mount_point);
2504                                 mount_point = NULL;
2505                         }
2506                 }
2507         }
2508
2509         if (mount_point != NULL) {
2510                 config->mount_point = talloc_strdup(config, mount_point);
2511                 if (config->mount_point == NULL) {
2512                         DEBUG(0, (__location__ " talloc_strdup() failed\n"));
2513                         return -1;
2514                 }
2515         } else {
2516                 config->mount_point = shadow_copy2_find_mount_point(config,
2517                                                                     handle);
2518                 if (config->mount_point == NULL) {
2519                         DBG_WARNING("shadow_copy2_find_mount_point "
2520                                     "of the share root '%s' failed: %s\n",
2521                                     handle->conn->connectpath, strerror(errno));
2522                         return -1;
2523                 }
2524         }
2525
2526         basedir = lp_parm_const_string(SNUM(handle->conn),
2527                                        "shadow", "basedir", NULL);
2528
2529         if (basedir != NULL) {
2530                 if (basedir[0] != '/') {
2531                         DEBUG(1, (__location__ " Warning: 'basedir' is "
2532                                   "relative ('%s'), but it has to be an "
2533                                   "absolute path. Disabling basedir.\n",
2534                                   basedir));
2535                         basedir = NULL;
2536                 } else {
2537                         char *p;
2538                         p = strstr(basedir, config->mount_point);
2539                         if (p != basedir) {
2540                                 DEBUG(1, ("Warning: basedir (%s) is not a "
2541                                           "subdirectory of the share root's "
2542                                           "mount point (%s). "
2543                                           "Disabling basedir\n",
2544                                           basedir, config->mount_point));
2545                                 basedir = NULL;
2546                         }
2547                 }
2548         }
2549
2550         if (config->snapdirseverywhere && basedir != NULL) {
2551                 DEBUG(1, (__location__ " Warning: 'basedir' is incompatible "
2552                           "with 'snapdirseverywhere'. Disabling basedir.\n"));
2553                 basedir = NULL;
2554         }
2555
2556         snapsharepath = lp_parm_const_string(SNUM(handle->conn), "shadow",
2557                                              "snapsharepath", NULL);
2558         if (snapsharepath != NULL) {
2559                 if (snapsharepath[0] == '/') {
2560                         DBG_WARNING("Warning: 'snapsharepath' is "
2561                                     "absolute ('%s'), but it has to be a "
2562                                     "relative path. Disabling snapsharepath.\n",
2563                                     snapsharepath);
2564                         snapsharepath = NULL;
2565                 }
2566                 if (config->snapdirseverywhere && snapsharepath != NULL) {
2567                         DBG_WARNING("Warning: 'snapsharepath' is incompatible "
2568                                     "with 'snapdirseverywhere'. Disabling "
2569                                     "snapsharepath.\n");
2570                         snapsharepath = NULL;
2571                 }
2572         }
2573
2574         if (basedir != NULL && snapsharepath != NULL) {
2575                 DBG_WARNING("Warning: 'snapsharepath' is incompatible with "
2576                             "'basedir'. Disabling snapsharepath\n");
2577                 snapsharepath = NULL;
2578         }
2579
2580         if (snapsharepath != NULL) {
2581                 config->rel_connectpath = talloc_strdup(config, snapsharepath);
2582                 if (config->rel_connectpath == NULL) {
2583                         DBG_ERR("talloc_strdup() failed\n");
2584                         errno = ENOMEM;
2585                         return -1;
2586                 }
2587         }
2588
2589         if (basedir == NULL) {
2590                 basedir = config->mount_point;
2591         }
2592
2593         if (config->rel_connectpath == NULL &&
2594             strlen(basedir) < strlen(handle->conn->connectpath)) {
2595                 config->rel_connectpath = talloc_strdup(config,
2596                         handle->conn->connectpath + strlen(basedir));
2597                 if (config->rel_connectpath == NULL) {
2598                         DEBUG(0, ("talloc_strdup() failed\n"));
2599                         errno = ENOMEM;
2600                         return -1;
2601                 }
2602         }
2603
2604         if (config->snapdir[0] == '/') {
2605                 config->snapdir_absolute = true;
2606
2607                 if (config->snapdirseverywhere == true) {
2608                         DEBUG(1, (__location__ " Warning: An absolute snapdir "
2609                                   "is incompatible with 'snapdirseverywhere', "
2610                                   "setting 'snapdirseverywhere' to false.\n"));
2611                         config->snapdirseverywhere = false;
2612                 }
2613
2614                 if (config->crossmountpoints == true) {
2615                         DEBUG(1, (__location__ " Warning: 'crossmountpoints' "
2616                                   "is not supported with an absolute snapdir. "
2617                                   "Disabling it.\n"));
2618                         config->crossmountpoints = false;
2619                 }
2620
2621                 config->snapshot_basepath = config->snapdir;
2622         } else {
2623                 config->snapshot_basepath = talloc_asprintf(config, "%s/%s",
2624                                 config->mount_point, config->snapdir);
2625                 if (config->snapshot_basepath == NULL) {
2626                         DEBUG(0, ("talloc_asprintf() failed\n"));
2627                         errno = ENOMEM;
2628                         return -1;
2629                 }
2630         }
2631
2632         trim_string(config->mount_point, NULL, "/");
2633         trim_string(config->rel_connectpath, "/", "/");
2634         trim_string(config->snapdir, NULL, "/");
2635         trim_string(config->snapshot_basepath, NULL, "/");
2636
2637         DEBUG(10, ("shadow_copy2_connect: configuration:\n"
2638                    "  share root: '%s'\n"
2639                    "  mountpoint: '%s'\n"
2640                    "  rel share root: '%s'\n"
2641                    "  snapdir: '%s'\n"
2642                    "  snapprefix: '%s'\n"
2643                    "  delimiter: '%s'\n"
2644                    "  snapshot base path: '%s'\n"
2645                    "  format: '%s'\n"
2646                    "  use sscanf: %s\n"
2647                    "  snapdirs everywhere: %s\n"
2648                    "  cross mountpoints: %s\n"
2649                    "  fix inodes: %s\n"
2650                    "  sort order: %s\n"
2651                    "",
2652                    handle->conn->connectpath,
2653                    config->mount_point,
2654                    config->rel_connectpath,
2655                    config->snapdir,
2656                    snapprefix,
2657                    config->delimiter,
2658                    config->snapshot_basepath,
2659                    config->gmt_format,
2660                    config->use_sscanf ? "yes" : "no",
2661                    config->snapdirseverywhere ? "yes" : "no",
2662                    config->crossmountpoints ? "yes" : "no",
2663                    config->fixinodes ? "yes" : "no",
2664                    config->sort_order
2665                    ));
2666
2667
2668         SMB_VFS_HANDLE_SET_DATA(handle, priv,
2669                                 NULL, struct shadow_copy2_private,
2670                                 return -1);
2671
2672         return 0;
2673 }
2674
2675 static struct vfs_fn_pointers vfs_shadow_copy2_fns = {
2676         .connect_fn = shadow_copy2_connect,
2677         .opendir_fn = shadow_copy2_opendir,
2678         .disk_free_fn = shadow_copy2_disk_free,
2679         .get_quota_fn = shadow_copy2_get_quota,
2680         .rename_fn = shadow_copy2_rename,
2681         .link_fn = shadow_copy2_link,
2682         .symlink_fn = shadow_copy2_symlink,
2683         .stat_fn = shadow_copy2_stat,
2684         .lstat_fn = shadow_copy2_lstat,
2685         .fstat_fn = shadow_copy2_fstat,
2686         .open_fn = shadow_copy2_open,
2687         .unlink_fn = shadow_copy2_unlink,
2688         .chmod_fn = shadow_copy2_chmod,
2689         .chown_fn = shadow_copy2_chown,
2690         .chdir_fn = shadow_copy2_chdir,
2691         .ntimes_fn = shadow_copy2_ntimes,
2692         .readlink_fn = shadow_copy2_readlink,
2693         .mknod_fn = shadow_copy2_mknod,
2694         .realpath_fn = shadow_copy2_realpath,
2695         .get_nt_acl_fn = shadow_copy2_get_nt_acl,
2696         .fget_nt_acl_fn = shadow_copy2_fget_nt_acl,
2697         .get_shadow_copy_data_fn = shadow_copy2_get_shadow_copy_data,
2698         .mkdir_fn = shadow_copy2_mkdir,
2699         .rmdir_fn = shadow_copy2_rmdir,
2700         .getxattr_fn = shadow_copy2_getxattr,
2701         .listxattr_fn = shadow_copy2_listxattr,
2702         .removexattr_fn = shadow_copy2_removexattr,
2703         .setxattr_fn = shadow_copy2_setxattr,
2704         .chmod_acl_fn = shadow_copy2_chmod_acl,
2705         .chflags_fn = shadow_copy2_chflags,
2706         .get_real_filename_fn = shadow_copy2_get_real_filename,
2707         .connectpath_fn = shadow_copy2_connectpath,
2708 };
2709
2710 NTSTATUS vfs_shadow_copy2_init(void);
2711 NTSTATUS vfs_shadow_copy2_init(void)
2712 {
2713         return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
2714                                 "shadow_copy2", &vfs_shadow_copy2_fns);
2715 }