Blame SOURCES/0020-mount.cifs-detect-GMT-format-of-snapshot-version.patch

5eee7b
From afccae852f231e8982276fa53614b3dc999b6bf8 Mon Sep 17 00:00:00 2001
5eee7b
From: Pavel Shilovsky <pshilov@microsoft.com>
5eee7b
Date: Wed, 3 Apr 2019 22:42:10 +0000
5eee7b
Subject: [PATCH 20/36] mount.cifs: detect GMT format of snapshot version
5eee7b
5eee7b
In order to provide an easy way to access snapshots a GMT
5eee7b
token string should be allowed as a "snapshot" mount option
5eee7b
argument, not SMB 100-nanoseconds time only. Detect if the
5eee7b
argument is in GMT format and convert it to SMB 100-nanoseconds
5eee7b
time before passing to the kernel.
5eee7b
5eee7b
Signed-off-by: Pavel Shilovsky <pshilov@microsoft.com>
5eee7b
Reviewed-by: Paulo Alcantara <palcantara@suse.de>
5eee7b
(cherry picked from commit c52be345de22669c53a6ec41c28914183bf65d09)
5eee7b
Signed-off-by: Sachin Prabhu <sprabhu@redhat.com>
5eee7b
---
5eee7b
 mount.cifs.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++-------
5eee7b
 1 file changed, 47 insertions(+), 7 deletions(-)
5eee7b
5eee7b
diff --git a/mount.cifs.c b/mount.cifs.c
5eee7b
index c6a1bd6..b3235e4 100644
5eee7b
--- a/mount.cifs.c
5eee7b
+++ b/mount.cifs.c
5eee7b
@@ -43,6 +43,7 @@
5eee7b
 #include <limits.h>
5eee7b
 #include <paths.h>
5eee7b
 #include <libgen.h>
5eee7b
+#include <time.h>
5eee7b
 #include <sys/mman.h>
5eee7b
 #include <sys/wait.h>
5eee7b
 #ifdef HAVE_SYS_FSUID_H
5eee7b
@@ -161,10 +162,16 @@
5eee7b
 #define OPT_BKUPUID    30
5eee7b
 #define OPT_BKUPGID    31
5eee7b
 #define OPT_NOFAIL     32
5eee7b
+#define OPT_SNAPSHOT   33
5eee7b
 
5eee7b
 #define MNT_TMP_FILE "/.mtab.cifs.XXXXXX"
5eee7b
 
5eee7b
-/* struct for holding parsed mount info for use by privleged process */
5eee7b
+#define GMT_NAME_LEN 24 /* length of a @GMT- name */
5eee7b
+#define GMT_FORMAT "@GMT-%Y.%m.%d-%H.%M.%S"
5eee7b
+
5eee7b
+#define NTFS_TIME_OFFSET ((unsigned long long)(369*365 + 89) * 24 * 3600 * 10000000)
5eee7b
+
5eee7b
+/* struct for holding parsed mount info for use by privileged process */
5eee7b
 struct parsed_mount_info {
5eee7b
 	unsigned long flags;
5eee7b
 	char host[NI_MAXHOST + 1];
5eee7b
@@ -271,9 +278,9 @@ static int mount_usage(FILE * stream)
5eee7b
 	fprintf(stream,
5eee7b
 		"\n\tcache=<strict|none|loose>,nounix,cifsacl,sec=<authentication mechanism>,");
5eee7b
 	fprintf(stream,
5eee7b
-		"\n\tsign,seal,fsc,snapshot=<time>,nosharesock,persistenthandles,resilienthandles,");
5eee7b
+		"\n\tsign,seal,fsc,snapshot=<token|time>,nosharesock,persistenthandles,");
5eee7b
 	fprintf(stream,
5eee7b
-		"\n\trdma,vers=<smb_dialect>,cruid");
5eee7b
+		"\n\tresilienthandles,rdma,vers=<smb_dialect>,cruid");
5eee7b
 	fprintf(stream,
5eee7b
 		"\n\nOptions not needed for servers supporting CIFS Unix extensions");
5eee7b
 	fprintf(stream,
5eee7b
@@ -773,6 +780,8 @@ static int parse_opt_token(const char *token)
5eee7b
 		return OPT_NOFAIL;
5eee7b
 	if (strncmp(token, "x-", 2) == 0)
5eee7b
 		return OPT_IGNORE;
5eee7b
+	if (strncmp(token, "snapshot", 8) == 0)
5eee7b
+		return OPT_SNAPSHOT;
5eee7b
 
5eee7b
 	return OPT_ERROR;
5eee7b
 }
5eee7b
@@ -793,16 +802,19 @@ parse_options(const char *data, struct parsed_mount_info *parsed_info)
5eee7b
 	int got_uid = 0;
5eee7b
 	int got_cruid = 0;
5eee7b
 	int got_gid = 0;
5eee7b
+	int got_snapshot = 0;
5eee7b
 	uid_t uid, cruid = 0, bkupuid = 0;
5eee7b
 	gid_t gid, bkupgid = 0;
5eee7b
 	char *ep;
5eee7b
 	struct passwd *pw;
5eee7b
 	struct group *gr;
5eee7b
 	/*
5eee7b
-	 * max 32-bit uint in decimal is 4294967295 which is 10 chars wide
5eee7b
-	 * +1 for NULL, and +1 for good measure
5eee7b
+	 * max 64-bit uint in decimal is 18446744073709551615 which is 20 chars
5eee7b
+	 * wide +1 for NULL, and +1 for good measure
5eee7b
 	 */
5eee7b
-	char txtbuf[12];
5eee7b
+	char txtbuf[22];
5eee7b
+	unsigned long long snapshot;
5eee7b
+	struct tm tm;
5eee7b
 
5eee7b
 	/* make sure we're starting from beginning */
5eee7b
 	out[0] = '\0';
5eee7b
@@ -1130,6 +1142,19 @@ parse_options(const char *data, struct parsed_mount_info *parsed_info)
5eee7b
 		case OPT_NOFAIL:
5eee7b
 			parsed_info->nofail = 1;
5eee7b
 			goto nocopy;
5eee7b
+		case OPT_SNAPSHOT:
5eee7b
+			if (!value || !*value)
5eee7b
+				goto nocopy;
5eee7b
+			if (strncmp(value, "@GMT-", 5))
5eee7b
+				break;
5eee7b
+			if ((strlen(value) != GMT_NAME_LEN) ||
5eee7b
+			    (strptime(value, GMT_FORMAT, &tm) == NULL)) {
5eee7b
+				fprintf(stderr, "bad snapshot token\n");
5eee7b
+				return EX_USAGE;
5eee7b
+			}
5eee7b
+			snapshot = timegm(&tm) * 10000000 + NTFS_TIME_OFFSET;
5eee7b
+			got_snapshot = 1;
5eee7b
+			goto nocopy;
5eee7b
 		}
5eee7b
 
5eee7b
 		/* check size before copying option to buffer */
5eee7b
@@ -1225,7 +1250,7 @@ nocopy:
5eee7b
 	if (got_bkupgid) {
5eee7b
 		word_len = snprintf(txtbuf, sizeof(txtbuf), "%u", bkupgid);
5eee7b
 
5eee7b
-		/* comma + "backkupgid=" + terminating NULL == 12 */
5eee7b
+		/* comma + "backupgid=" + terminating NULL == 12 */
5eee7b
 		if (out_len + word_len + 12 > MAX_OPTIONS_LEN) {
5eee7b
 			fprintf(stderr, "Options string too long\n");
5eee7b
 			return EX_USAGE;
5eee7b
@@ -1237,6 +1262,21 @@ nocopy:
5eee7b
 		}
5eee7b
 		snprintf(out + out_len, word_len + 11, "backupgid=%s", txtbuf);
5eee7b
 	}
5eee7b
+	if (got_snapshot) {
5eee7b
+		word_len = snprintf(txtbuf, sizeof(txtbuf), "%llu", snapshot);
5eee7b
+
5eee7b
+		/* comma + "snapshot=" + terminating NULL == 11 */
5eee7b
+		if (out_len + word_len + 11 > MAX_OPTIONS_LEN) {
5eee7b
+			fprintf(stderr, "Options string too long\n");
5eee7b
+			return EX_USAGE;
5eee7b
+		}
5eee7b
+
5eee7b
+		if (out_len) {
5eee7b
+			strlcat(out, ",", MAX_OPTIONS_LEN);
5eee7b
+			out_len++;
5eee7b
+		}
5eee7b
+		snprintf(out + out_len, word_len + 11, "snapshot=%s", txtbuf);
5eee7b
+	}
5eee7b
 
5eee7b
 	return 0;
5eee7b
 }
5eee7b
-- 
5eee7b
1.8.3.1
5eee7b