Message ID | CAH2r5mvQ+KmoBgoxT51SRMpCXZ4OFwg+B1x_SD3DFkcrUcdZQQ@mail.gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [smbinfo,cifsutils] | expand |
Rewieved-by me. As this is a pretty useful addition we can add an update to the manpage as a followup. On Thu, Mar 28, 2019 at 8:05 PM Steve French <smfrench@gmail.com> wrote: > > Patch to smbinfo tool (in cifs-utils) to allow listing previous > versions (snapshots) of an SMB3 mounted share. Note that cifs.ko has > a mount option "snapshot=" which can be used to mount the previous > version of a share. > > Sample output: > > $ ./smbinfo list-snapshots /mnt/file > Number of snapshots: 5 Number of snapshots returned: 5 > Snapshot list: > 1) @GMT-2019.03.27-20.52.19 > 2) @GMT-2019.03.27-20.50.20 > 3) @GMT-2019.03.16-22.25.54 > 4) @GMT-2019.03.16-22.22.28 > 5) @GMT-2018.10.12-08.30.11 > > > -- > Thanks, > > Steve
On Thu, 28 Mar 2019 05:05:35 -0500, Steve French wrote: > + /* Now that we know the size, query the list from the server */ > + > + /* Make sure the buf size is big enough even to handle unexpected server behavior */ > + buf = malloc(snap_inf.snapshot_array_size + 300); The buffer length calculations seem pretty arbitrary here, wouldn't it make sense to use something like the following (with a maximum limit)? sizeof(struct smb_snapshot_array) + (snap_inf.number_of_snapshots * GMT_TOKEN_LEN) Cheers, David
As requested I changed the buffer size malloced to be more obvious - in this case to match exactly what is returned from the first call (ie snapshot length + the sizeof the snapshot info structure which precedes the snapshot list, ie 16 bytes). The snapshot array size is 12 bytes, but rounding it to 8 byte boundary causes the minimum to be 16 bytes. On Thu, Mar 28, 2019 at 11:02 AM David Disseldorp <ddiss@suse.de> wrote: > > On Thu, 28 Mar 2019 05:05:35 -0500, Steve French wrote: > > > + /* Now that we know the size, query the list from the server */ > > + > > + /* Make sure the buf size is big enough even to handle unexpected server behavior */ > > + buf = malloc(snap_inf.snapshot_array_size + 300); > > The buffer length calculations seem pretty arbitrary here, wouldn't it > make sense to use something like the following (with a maximum limit)? > sizeof(struct smb_snapshot_array) + > (snap_inf.number_of_snapshots * GMT_TOKEN_LEN) > > Cheers, David
Added man page update for this new smbinfo parm On Fri, Mar 29, 2019 at 3:14 AM Steve French <smfrench@gmail.com> wrote: > > As requested I changed the buffer size malloced to be more obvious - > in this case to match exactly what is returned from the first call (ie > snapshot length + the sizeof the snapshot info structure which > precedes the snapshot list, ie 16 bytes). The snapshot array size is > 12 bytes, but rounding it to 8 byte boundary causes the minimum to be > 16 bytes. > > On Thu, Mar 28, 2019 at 11:02 AM David Disseldorp <ddiss@suse.de> wrote: > > > > On Thu, 28 Mar 2019 05:05:35 -0500, Steve French wrote: > > > > > + /* Now that we know the size, query the list from the server */ > > > + > > > + /* Make sure the buf size is big enough even to handle unexpected server behavior */ > > > + buf = malloc(snap_inf.snapshot_array_size + 300); > > > > The buffer length calculations seem pretty arbitrary here, wouldn't it > > make sense to use something like the following (with a maximum limit)? > > sizeof(struct smb_snapshot_array) + > > (snap_inf.number_of_snapshots * GMT_TOKEN_LEN) > > > > Cheers, David > > > > -- > Thanks, > > Steve
Looks good, thanks. -- Best regards, Pavel Shilovsky пт, 29 мар. 2019 г. в 11:44, Steve French <smfrench@gmail.com>: > > Added man page update for this new smbinfo parm > > > On Fri, Mar 29, 2019 at 3:14 AM Steve French <smfrench@gmail.com> wrote: > > > > As requested I changed the buffer size malloced to be more obvious - > > in this case to match exactly what is returned from the first call (ie > > snapshot length + the sizeof the snapshot info structure which > > precedes the snapshot list, ie 16 bytes). The snapshot array size is > > 12 bytes, but rounding it to 8 byte boundary causes the minimum to be > > 16 bytes. > > > > On Thu, Mar 28, 2019 at 11:02 AM David Disseldorp <ddiss@suse.de> wrote: > > > > > > On Thu, 28 Mar 2019 05:05:35 -0500, Steve French wrote: > > > > > > > + /* Now that we know the size, query the list from the server */ > > > > + > > > > + /* Make sure the buf size is big enough even to handle unexpected server behavior */ > > > > + buf = malloc(snap_inf.snapshot_array_size + 300); > > > > > > The buffer length calculations seem pretty arbitrary here, wouldn't it > > > make sense to use something like the following (with a maximum limit)? > > > sizeof(struct smb_snapshot_array) + > > > (snap_inf.number_of_snapshots * GMT_TOKEN_LEN) > > > > > > Cheers, David > > > > > > > > -- > > Thanks, > > > > Steve > > > > -- > Thanks, > > Steve
From dd4650114a9b31f210f359327735dcffdc8139d9 Mon Sep 17 00:00:00 2001 From: Steve French <stfrench@microsoft.com> Date: Thu, 28 Mar 2019 04:58:19 -0500 Subject: [PATCH] smbinfo: Add ability to query snapshots (previous versions) Allow listing SMB3 snapshots (previous versions of shares) Signed-off-by: Steve French <stfrench@microsoft.com> --- smbinfo.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/smbinfo.c b/smbinfo.c index 33fca95..8f6566a 100644 --- a/smbinfo.c +++ b/smbinfo.c @@ -89,6 +89,8 @@ usage(char *name) " Prints the security descriptor for a cifs file.\n" " quota:\n" " Prints the quota for a cifs file.\n" + " list-snapshots:\n" + " List the previous versions of the volume that backs this file.\n" " fsctl-getobjid:\n" " Prints the objectid of the file and GUID of the underlying volume.\n", name); @@ -966,6 +968,88 @@ quota(int f) free(qi); } + +struct smb_snapshot_array { + int32_t number_of_snapshots; + int32_t number_of_snapshots_returned; + int32_t snapshot_array_size; + char snapshot_data[0]; +}; + + +static void print_snapshots(struct smb_snapshot_array *psnap) +{ + int current_snapshot_entry = 0; + + printf("Number of snapshots: %d Number of snapshots returned: %d\n", + psnap->number_of_snapshots, + psnap->number_of_snapshots_returned); + printf("Snapshot list:"); + + for (int i = 0; i < psnap->snapshot_array_size; i++) { + if (psnap->snapshot_data[i] == '@') { + current_snapshot_entry++; + printf("\n%d) ", current_snapshot_entry); + } + printf("%c", psnap->snapshot_data[i]); + } + printf("\n"); +} + +#define CIFS_ENUMERATE_SNAPSHOTS _IOR(CIFS_IOCTL_MAGIC, 6, struct smb_snapshot_array) + +static void +list_snapshots(int f) +{ + + struct smb_snapshot_array snap_inf; + struct smb_snapshot_array *buf; + + /* + * When first field in structure we pass in here is zero, cifs.ko can + * recognize that this is the first query and that it must set the SMB3 + * FSCTL response buffer size (in the request) to exactly 16 bytes + * (which is required by some servers to process the initial query) + */ + snap_inf.number_of_snapshots = 0; + snap_inf.number_of_snapshots_returned = 0; + snap_inf.snapshot_array_size = sizeof(struct smb_snapshot_array); + + /* Query the number of snapshots so we know how much to allocate */ + if (ioctl(f, CIFS_ENUMERATE_SNAPSHOTS, &snap_inf) < 0) { + fprintf(stderr, "Querying snapshots failed with %s\n", strerror(errno)); + exit(1); + } + + if (snap_inf.number_of_snapshots == 0) + return; + + /* Now that we know the size, query the list from the server */ + + /* Make sure the buf size is big enough even to handle unexpected server behavior */ + buf = malloc(snap_inf.snapshot_array_size + 300); + + if (buf == NULL) { + printf("Failed, out of memory.\n"); + exit(1); + } + /* + * first parm is non-zero which allows cifs.ko to recognize that this is + * the second query (it has to set response buf size larger) + */ + buf->number_of_snapshots = snap_inf.number_of_snapshots; + + buf->snapshot_array_size = snap_inf.snapshot_array_size + 200; + + if (ioctl(f, CIFS_ENUMERATE_SNAPSHOTS, buf) < 0) { + fprintf(stderr, "Querying snapshots failed with %s\n", strerror(errno)); + exit(1); + } + + print_snapshots(buf); + free(buf); +} + int main(int argc, char *argv[]) { int c; @@ -1016,6 +1100,8 @@ int main(int argc, char *argv[]) secdesc(f); else if (!strcmp(argv[optind], "quota")) quota(f); + else if (!strcmp(argv[optind], "list-snapshots")) + list_snapshots(f); else if (!strcmp(argv[1], "fsctl-getobjid")) fsctlgetobjid(f); else { -- 2.17.1