[PATCH] smbd: Added support for IO_REPARSE_TAG_MOUNTPOINT
Jeremy Allison
jra at samba.org
Sat Sep 30 01:14:12 UTC 2017
On Tue, Sep 19, 2017 at 11:21:19AM -0600, Jacob Holtom via samba-technical wrote:
> Hello all,
>
> Attached is an updated patch for IO_REPARSE_TAG_MOUNTPOINT.
>
> Please review,
>
> Thanks!
>
> Jacob Holtom
Hi Jacob, I really don't think this is the right way
to do this.
Give me a little time and I'll explain fully why later
next week, sorry.
Regards,
Jeremy.
> From 4c4595c8e8ab935d21a0eb5b99638ce1d5a64ca4 Mon Sep 17 00:00:00 2001
> From: Jacob Holtom <jacob at et.byu.edu>
> Date: Mon, 18 Sep 2017 16:25:30 -0600
> Subject: [PATCH] smbd: Added support for IO_REPARSE_TAG_MOUNTPOINT
>
> This patch adds support for returning IO_REPARSE_TAG_MOUNTPOINT when a device
> boundary is crossed. Doing so resolves issues with Windows Explorer's pre-copy
> freespace check incorrectly denying or allowing a copy operation based on the
> base_share_dev dfree/quota data, instead of the target device's dfree/quota
> data, where the target device is a separate submounted or widelinked device.
> Device boundary crossings are detected as a requested path is resolved, using a
> combination of the connection_struct's base_share_dev member, and a newly added
> curr_share_dev member.
>
> If the requested path's device is not equal to the base_share_dev or the
> curr_share_dev, the IO_REPARSE_TAG_MOUNTPOINT is added to the response, and the
> curr_share_dev is update to the resolved device's identifier.
>
> Using both base_share_dev and curr_share_dev members is required to correctly
> update dfree/quota data when descending and ascending a path tree, but also
> allows for nesting submounts (or widelinked devices) to any depth.
>
> In which case, curr_share_dev is updated with the target path's device, and
> IO_REPARSE_TAG_MOUNTPOINT is returned to the client.
>
> This added behavior improves how the client handles quota and dfree requests for
> different submounted/widelinked devices. The client is now aware when it
> crosses a device boundary and must re-request dfree/quota data.
>
> An administrator can now use this behavior to expand available space in an
> existing tree heirarchy using submounts (similar to file share's containing NTFS
> Junctions) without requiring DFS links to a separate share.
>
> An admin could also now create a basic equivalent of folder quota by widelinking
> (or bind mounting) to a directory on a separate device with a user and/or group
> quota specific to directory on the target device (e.g. user's "home" has a
> "subfolder" widelink to /mnt/quota_volume/subfolder, where the target
> /mnt/quota_volume/subfolder has setgid bit set and a quota applied to the
> primary group.
>
> It can also be seen that the correct directory paths are passed to the "get
> quota command" script, allowing the script to be queried as intended without the
> caveat stated in the man page that 'The directory is actually mostly just "." -
> It needs to be ...' Since quota's are maintained by device on Linux (with the
> exception of a few filesystems), this patch improves the behavior for a majority
> of quota using users.
>
> A possibly confusing behavior with the Windows Explorer UX is present when a
> widelink to an AutoFS mountpoint is not using the browse option. The widelink
> target is not resolved by the server until the widelink is traversed, and so the
> widelink will appear with a normal folder icon. If the client descends into the
> widelink, then moves up to the parent, the widelink changes to a folder with a
> blue link arrow in the corner of the icon. When the client attribute cache
> times out, the folder link icon returns to the normal folder icon. The
> here-again-gone-again nature of the folder link icon may be surprising to the
> user, or may be useful to communicate a resolution and/or automount status. We
> don't know if this happens on other operating systems and file managers.
> ---
> source3/include/vfs.h | 1 +
> source3/smbd/dosmode.c | 24 +++++++++++++++++++++++-
> source3/smbd/service.c | 1 +
> source3/smbd/trans2.c | 21 ++++++++++++++++++---
> 4 files changed, 43 insertions(+), 4 deletions(-)
>
> diff --git a/source3/include/vfs.h b/source3/include/vfs.h
> index d71d7cc4483..652986ca1a4 100644
> --- a/source3/include/vfs.h
> +++ b/source3/include/vfs.h
> @@ -467,6 +467,7 @@ typedef struct connection_struct {
> /* Device number of the directory of the share mount.
> Used to ensure unique FileIndex returns. */
> SMB_DEV_T base_share_dev;
> + SMB_DEV_T curr_share_dev;
>
> name_compare_entry *hide_list; /* Per-share list of files to return as hidden. */
> name_compare_entry *veto_list; /* Per-share list of files to veto (never show). */
> diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c
> index 3181f2e78a9..8274e4f1bc1 100644
> --- a/source3/smbd/dosmode.c
> +++ b/source3/smbd/dosmode.c
> @@ -65,7 +65,9 @@ static void dos_mode_debug_print(const char *func, uint32_t mode)
> if (mode & FILE_ATTRIBUTE_COMPRESSED) {
> fstrcat(modestr, "[compressed]");
> }
> -
> + if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
> + fstrcat(modestr, "[reparse point]");
> + }
> DBG_INFO("%s returning (0x%x): \"%s\"\n", func, (unsigned)mode,
> modestr);
> }
> @@ -247,6 +249,13 @@ static uint32_t dos_mode_from_sbuf(connection_struct *conn,
>
> if (S_ISDIR(smb_fname->st.st_ex_mode))
> result = FILE_ATTRIBUTE_DIRECTORY | (result & FILE_ATTRIBUTE_READONLY);
> +
> + if (conn->base_share_dev != smb_fname->st.st_ex_dev){
> + if(conn->curr_share_dev != smb_fname->st.st_ex_dev){
> + result |= FILE_ATTRIBUTE_REPARSE_POINT;
> + conn->curr_share_dev = smb_fname->st.st_ex_dev;
> + }
> + }
>
> result |= set_link_read_only_flag(&smb_fname->st);
>
> @@ -395,6 +404,12 @@ NTSTATUS get_ea_dos_attribute(connection_struct *conn,
> if (S_ISDIR(smb_fname->st.st_ex_mode)) {
> dosattr |= FILE_ATTRIBUTE_DIRECTORY;
> }
> + if (conn->base_share_dev != smb_fname->st.st_ex_dev){
> + if(conn->curr_share_dev != smb_fname->st.st_ex_dev){
> + dosattr |= FILE_ATTRIBUTE_REPARSE_POINT;
> + conn->curr_share_dev = smb_fname->st.st_ex_dev;
> + }
> + }
> /* FILE_ATTRIBUTE_SPARSE is valid on get but not on set. */
> *pattr |= (uint32_t)(dosattr & (SAMBA_ATTRIBUTES_MASK|FILE_ATTRIBUTE_SPARSE));
>
> @@ -682,6 +697,13 @@ uint32_t dos_mode(connection_struct *conn, struct smb_filename *smb_fname)
> } else if (result == 0) {
> result = FILE_ATTRIBUTE_NORMAL;
> }
> +
> + if (conn->base_share_dev != smb_fname->st.st_ex_dev){
> + if(conn->curr_share_dev != smb_fname->st.st_ex_dev){
> + result |= FILE_ATTRIBUTE_REPARSE_POINT;
> + conn->curr_share_dev = smb_fname->st.st_ex_dev;
> + }
> + }
>
> result = filter_mode_by_protocol(result);
>
> diff --git a/source3/smbd/service.c b/source3/smbd/service.c
> index 75a47dee0ca..52a14f8f92d 100644
> --- a/source3/smbd/service.c
> +++ b/source3/smbd/service.c
> @@ -821,6 +821,7 @@ static NTSTATUS make_connection_snum(struct smbXsrv_connection *xconn,
> goto err_root_exit;
> }
> conn->base_share_dev = smb_fname_cpath->st.st_ex_dev;
> + conn->curr_share_dev = conn->base_share_dev;
>
> talloc_free(conn->origpath);
> conn->origpath = talloc_strdup(conn, conn->connectpath);
> diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
> index de6073a973f..f1a17635d27 100644
> --- a/source3/smbd/trans2.c
> +++ b/source3/smbd/trans2.c
> @@ -2012,7 +2012,12 @@ static NTSTATUS smbd_marshall_dir_entry(TALLOC_CTX *ctx,
> SIVAL(p,0,mode); p += 4;
> q = p; p += 4; /* q is placeholder for name length. */
> if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
> - SIVAL(p, 0, IO_REPARSE_TAG_DFS);
> + if(conn->base_share_dev != conn->curr_share_dev){
> + SIVAL(p, 0, IO_REPARSE_TAG_MOUNT_POINT);
> + }
> + else {
> + SIVAL(p, 0, IO_REPARSE_TAG_DFS);
> + }
> } else {
> unsigned int ea_size = estimate_ea_size(conn, NULL,
> smb_fname);
> @@ -2206,7 +2211,12 @@ static NTSTATUS smbd_marshall_dir_entry(TALLOC_CTX *ctx,
> SIVAL(p,0,mode); p += 4;
> q = p; p += 4; /* q is placeholder for name length. */
> if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
> - SIVAL(p, 0, IO_REPARSE_TAG_DFS);
> + if(conn->base_share_dev != conn->curr_share_dev){
> + SIVAL(p, 0, IO_REPARSE_TAG_MOUNT_POINT);
> + }
> + else {
> + SIVAL(p, 0, IO_REPARSE_TAG_DFS);
> + }
> } else {
> unsigned int ea_size = estimate_ea_size(conn, NULL,
> smb_fname);
> @@ -2257,7 +2267,12 @@ static NTSTATUS smbd_marshall_dir_entry(TALLOC_CTX *ctx,
> SIVAL(p,0,mode); p += 4;
> q = p; p += 4; /* q is placeholder for name length */
> if (mode & FILE_ATTRIBUTE_REPARSE_POINT) {
> - SIVAL(p, 0, IO_REPARSE_TAG_DFS);
> + if(conn->base_share_dev != conn->curr_share_dev){
> + SIVAL(p, 0, IO_REPARSE_TAG_MOUNT_POINT);
> + }
> + else {
> + SIVAL(p, 0, IO_REPARSE_TAG_DFS);
> + }
> } else if (readdir_attr_data &&
> readdir_attr_data->type == RDATTR_AAPL) {
> /*
> --
> 2.11.0
>
More information about the samba-technical
mailing list