# HG changeset patch # User Gordon Ross # Date 1492116259 14400 # Node ID f50b088fc201b62d39a2ad6462d3880c43705534 # Parent 73da839a49e1e0c1cd4d020c09c1ad0630037da4 8583 Windows 10 fails to delete read-only files with SMB2 Reviewed by: Matt Barden Reviewed by: Evan Layton Approved by: Garrett D'Amore diff -r 73da839a49e1 -r f50b088fc201 usr/src/uts/common/fs/smbsrv/smb_common_open.c --- a/usr/src/uts/common/fs/smbsrv/smb_common_open.c Wed Jan 11 14:07:49 2017 -0500 +++ b/usr/src/uts/common/fs/smbsrv/smb_common_open.c Thu Apr 13 16:44:19 2017 -0400 @@ -529,6 +529,11 @@ smb_node_release(dnode); return (NT_STATUS_ACCESS_DENIED); } + if (op->create_options & FILE_DELETE_ON_CLOSE) { + smb_node_release(node); + smb_node_release(dnode); + return (NT_STATUS_CANNOT_DELETE); + } } } diff -r 73da839a49e1 -r f50b088fc201 usr/src/uts/common/fs/smbsrv/smb_node.c --- a/usr/src/uts/common/fs/smbsrv/smb_node.c Wed Jan 11 14:07:49 2017 -0500 +++ b/usr/src/uts/common/fs/smbsrv/smb_node.c Thu Apr 13 16:44:19 2017 -0400 @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2016 Nexenta Systems, Inc. All rights reserved. + * Copyright 2017 Nexenta Systems, Inc. All rights reserved. */ /* * SMB Node State Machine @@ -596,8 +596,8 @@ /* * Helper function for smb_node_set_delete_on_close(). Assumes node is a dir. * Return 0 if this is an empty dir. Otherwise return a NT_STATUS code. - * We distinguish between readdir failure and non-empty dir by returning - * different values. + * Unfortunately, to find out if a directory is empty, we have to read it + * and check for anything other than "." or ".." in the readdir buf. */ static uint32_t smb_rmdir_possible(smb_node_t *n, uint32_t flags) @@ -618,9 +618,9 @@ #define dp u.u_dp if (smb_vop_readdir(n->vp, 0, buf, &bsize, &eof, flags, zone_kcred())) - return (NT_STATUS_CANNOT_DELETE); + return (NT_STATUS_INTERNAL_ERROR); if (bsize == 0) - return (NT_STATUS_CANNOT_DELETE); + return (0); /* empty dir */ bufptr = buf; while ((bufptr += reclen) < buf + bsize) { if (edp) { @@ -647,23 +647,13 @@ * whichever the first file handle is closed will trigger the node to be * marked as delete-on-close. The credentials of that ofile will be used * as the delete-on-close credentials of the node. + * + * Note that "read-only" tests have already happened before this call. */ uint32_t smb_node_set_delete_on_close(smb_node_t *node, cred_t *cr, uint32_t flags) { - int rc = 0; uint32_t status; - smb_attr_t attr; - - if (node->n_pending_dosattr & FILE_ATTRIBUTE_READONLY) - return (NT_STATUS_CANNOT_DELETE); - - bzero(&attr, sizeof (smb_attr_t)); - attr.sa_mask = SMB_AT_DOSATTR; - rc = smb_fsop_getattr(NULL, zone_kcred(), node, &attr); - if ((rc != 0) || (attr.sa_dosattr & FILE_ATTRIBUTE_READONLY)) { - return (NT_STATUS_CANNOT_DELETE); - } /* * If the directory is not empty we should fail setting del-on-close @@ -679,8 +669,9 @@ mutex_enter(&node->n_mutex); if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) { + /* It was already marked. We're done. */ mutex_exit(&node->n_mutex); - return (NT_STATUS_CANNOT_DELETE); + return (NT_STATUS_SUCCESS); } crhold(cr);