15331Samw /*
25331Samw * CDDL HEADER START
35331Samw *
45331Samw * The contents of this file are subject to the terms of the
55331Samw * Common Development and Distribution License (the "License").
65331Samw * You may not use this file except in compliance with the License.
75331Samw *
85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw * or http://www.opensolaris.org/os/licensing.
105331Samw * See the License for the specific language governing permissions
115331Samw * and limitations under the License.
125331Samw *
135331Samw * When distributing Covered Code, include this CDDL HEADER in each
145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw * If applicable, add the following below this CDDL HEADER, with the
165331Samw * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw *
195331Samw * CDDL HEADER END
205331Samw */
2112508Samw@Sun.COM
225331Samw /*
2312508Samw@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
245331Samw */
255331Samw
265331Samw /*
275331Samw * This module provides the common open functionality to the various
285331Samw * open and create SMB interface functions.
295331Samw */
305331Samw
3110966SJordan.Brown@Sun.COM #include <sys/types.h>
3210966SJordan.Brown@Sun.COM #include <sys/cmn_err.h>
335331Samw #include <sys/fcntl.h>
345772Sas200622 #include <sys/nbmlock.h>
3510966SJordan.Brown@Sun.COM #include <smbsrv/string.h>
3610966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h>
3710966SJordan.Brown@Sun.COM #include <smbsrv/smb_fsops.h>
3810966SJordan.Brown@Sun.COM #include <smbsrv/smbinfo.h>
395331Samw
406139Sjb150015 volatile uint32_t smb_fids = 0;
416030Sjb150015
426030Sjb150015 static uint32_t smb_open_subr(smb_request_t *);
436139Sjb150015 extern uint32_t smb_is_executable(char *);
449231SAfshin.Ardakani@Sun.COM static void smb_delete_new_object(smb_request_t *);
4510001SJoyce.McIntosh@Sun.COM static int smb_set_open_timestamps(smb_request_t *, smb_ofile_t *, boolean_t);
46*12890SJoyce.McIntosh@Sun.COM static void smb_open_oplock_break(smb_request_t *, smb_node_t *);
47*12890SJoyce.McIntosh@Sun.COM static boolean_t smb_open_attr_only(smb_arg_open_t *);
48*12890SJoyce.McIntosh@Sun.COM static boolean_t smb_open_overwrite(smb_arg_open_t *);
495331Samw
505331Samw /*
515331Samw * smb_access_generic_to_file
525331Samw *
535331Samw * Search MSDN for IoCreateFile to see following mapping.
545331Samw *
555331Samw * GENERIC_READ STANDARD_RIGHTS_READ, FILE_READ_DATA,
565331Samw * FILE_READ_ATTRIBUTES and FILE_READ_EA
575331Samw *
585331Samw * GENERIC_WRITE STANDARD_RIGHTS_WRITE, FILE_WRITE_DATA,
595331Samw * FILE_WRITE_ATTRIBUTES, FILE_WRITE_EA, and FILE_APPEND_DATA
605331Samw *
615331Samw * GENERIC_EXECUTE STANDARD_RIGHTS_EXECUTE, SYNCHRONIZE, and FILE_EXECUTE.
625331Samw */
635331Samw uint32_t
smb_access_generic_to_file(uint32_t desired_access)645331Samw smb_access_generic_to_file(uint32_t desired_access)
655331Samw {
665331Samw uint32_t access = 0;
675331Samw
685331Samw if (desired_access & GENERIC_ALL)
695331Samw return (FILE_ALL_ACCESS & ~SYNCHRONIZE);
705331Samw
715331Samw if (desired_access & GENERIC_EXECUTE) {
725331Samw desired_access &= ~GENERIC_EXECUTE;
735331Samw access |= (STANDARD_RIGHTS_EXECUTE |
745331Samw SYNCHRONIZE | FILE_EXECUTE);
755331Samw }
765331Samw
775331Samw if (desired_access & GENERIC_WRITE) {
785331Samw desired_access &= ~GENERIC_WRITE;
795331Samw access |= (FILE_GENERIC_WRITE & ~SYNCHRONIZE);
805331Samw }
815331Samw
825331Samw if (desired_access & GENERIC_READ) {
835331Samw desired_access &= ~GENERIC_READ;
845331Samw access |= FILE_GENERIC_READ;
855331Samw }
865331Samw
875331Samw return (access | desired_access);
885331Samw }
895331Samw
905331Samw /*
915331Samw * smb_omode_to_amask
925331Samw *
935331Samw * This function converts open modes used by Open and Open AndX
945331Samw * commands to desired access bits used by NT Create AndX command.
955331Samw */
965331Samw uint32_t
smb_omode_to_amask(uint32_t desired_access)975331Samw smb_omode_to_amask(uint32_t desired_access)
985331Samw {
995331Samw switch (desired_access & SMB_DA_ACCESS_MASK) {
1005331Samw case SMB_DA_ACCESS_READ:
1015331Samw return (FILE_GENERIC_READ);
1025331Samw
1035331Samw case SMB_DA_ACCESS_WRITE:
1045331Samw return (FILE_GENERIC_WRITE);
1055331Samw
1065331Samw case SMB_DA_ACCESS_READ_WRITE:
1075331Samw return (FILE_GENERIC_READ | FILE_GENERIC_WRITE);
1085331Samw
1095331Samw case SMB_DA_ACCESS_EXECUTE:
1105331Samw return (FILE_GENERIC_EXECUTE);
1118934SJose.Borrego@Sun.COM
1128934SJose.Borrego@Sun.COM default:
1138934SJose.Borrego@Sun.COM return (FILE_GENERIC_ALL);
1145331Samw }
1155331Samw }
1165331Samw
1175331Samw /*
1185331Samw * smb_denymode_to_sharemode
1195331Samw *
1205331Samw * This function converts deny modes used by Open and Open AndX
1215331Samw * commands to share access bits used by NT Create AndX command.
1225331Samw */
1235331Samw uint32_t
smb_denymode_to_sharemode(uint32_t desired_access,char * fname)1245331Samw smb_denymode_to_sharemode(uint32_t desired_access, char *fname)
1255331Samw {
1265331Samw switch (desired_access & SMB_DA_SHARE_MASK) {
1275331Samw case SMB_DA_SHARE_COMPATIBILITY:
1285331Samw if (smb_is_executable(fname))
1295331Samw return (FILE_SHARE_READ | FILE_SHARE_WRITE);
1307348SJose.Borrego@Sun.COM
1317348SJose.Borrego@Sun.COM return (FILE_SHARE_ALL);
1325331Samw
1335331Samw case SMB_DA_SHARE_EXCLUSIVE:
1345331Samw return (FILE_SHARE_NONE);
1355331Samw
1365331Samw case SMB_DA_SHARE_DENY_WRITE:
1375331Samw return (FILE_SHARE_READ);
1385331Samw
1395331Samw case SMB_DA_SHARE_DENY_READ:
1405331Samw return (FILE_SHARE_WRITE);
1415331Samw
1425331Samw case SMB_DA_SHARE_DENY_NONE:
1438934SJose.Borrego@Sun.COM default:
1445331Samw return (FILE_SHARE_READ | FILE_SHARE_WRITE);
1455331Samw }
1465331Samw }
1475331Samw
1485331Samw /*
1495331Samw * smb_ofun_to_crdisposition
1505331Samw *
1515331Samw * This function converts open function values used by Open and Open AndX
1525331Samw * commands to create disposition values used by NT Create AndX command.
1535331Samw */
1545331Samw uint32_t
smb_ofun_to_crdisposition(uint16_t ofun)1555331Samw smb_ofun_to_crdisposition(uint16_t ofun)
1565331Samw {
1575331Samw static int ofun_cr_map[3][2] =
1585331Samw {
1595331Samw { -1, FILE_CREATE },
1605331Samw { FILE_OPEN, FILE_OPEN_IF },
1615331Samw { FILE_OVERWRITE, FILE_OVERWRITE_IF }
1625331Samw };
1635331Samw
1645331Samw int row = ofun & SMB_OFUN_OPEN_MASK;
1655331Samw int col = (ofun & SMB_OFUN_CREATE_MASK) >> 4;
1665331Samw
1675331Samw if (row == 3)
1688934SJose.Borrego@Sun.COM return (FILE_MAXIMUM_DISPOSITION + 1);
1695331Samw
1705331Samw return (ofun_cr_map[row][col]);
1715331Samw }
1725331Samw
1735331Samw /*
1746030Sjb150015 * Retry opens to avoid spurious sharing violations, due to timing
1756030Sjb150015 * issues between closes and opens. The client that already has the
1766030Sjb150015 * file open may be in the process of closing it.
1776030Sjb150015 */
1786030Sjb150015 uint32_t
smb_common_open(smb_request_t * sr)1796030Sjb150015 smb_common_open(smb_request_t *sr)
1806030Sjb150015 {
18112508Samw@Sun.COM smb_arg_open_t *parg;
18210966SJordan.Brown@Sun.COM uint32_t status = NT_STATUS_SUCCESS;
18310966SJordan.Brown@Sun.COM int count;
18410966SJordan.Brown@Sun.COM
18510966SJordan.Brown@Sun.COM parg = kmem_alloc(sizeof (*parg), KM_SLEEP);
18610966SJordan.Brown@Sun.COM bcopy(&sr->arg.open, parg, sizeof (*parg));
1876030Sjb150015
1886030Sjb150015 for (count = 0; count <= 4; count++) {
18910966SJordan.Brown@Sun.COM if (count != 0)
1906030Sjb150015 delay(MSEC_TO_TICK(400));
1916030Sjb150015
1926139Sjb150015 status = smb_open_subr(sr);
1936139Sjb150015 if (status != NT_STATUS_SHARING_VIOLATION)
1946030Sjb150015 break;
19510966SJordan.Brown@Sun.COM
19610966SJordan.Brown@Sun.COM bcopy(parg, &sr->arg.open, sizeof (*parg));
1976030Sjb150015 }
1986030Sjb150015
1996139Sjb150015 if (status == NT_STATUS_SHARING_VIOLATION) {
2006030Sjb150015 smbsr_error(sr, NT_STATUS_SHARING_VIOLATION,
2016030Sjb150015 ERRDOS, ERROR_SHARING_VIOLATION);
2026030Sjb150015 }
2036030Sjb150015
2048934SJose.Borrego@Sun.COM if (status == NT_STATUS_NO_SUCH_FILE) {
2058934SJose.Borrego@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
2068934SJose.Borrego@Sun.COM ERRDOS, ERROR_FILE_NOT_FOUND);
2078934SJose.Borrego@Sun.COM }
2088934SJose.Borrego@Sun.COM
20910966SJordan.Brown@Sun.COM kmem_free(parg, sizeof (*parg));
2106030Sjb150015 return (status);
2116030Sjb150015 }
2126030Sjb150015
2136030Sjb150015 /*
2145331Samw * smb_open_subr
2155331Samw *
2165331Samw * Notes on write-through behaviour. It looks like pre-LM0.12 versions
2175331Samw * of the protocol specify the write-through mode when a file is opened,
2185331Samw * (SmbOpen, SmbOpenAndX) so the write calls (SmbWrite, SmbWriteAndClose,
2195331Samw * SmbWriteAndUnlock) don't need to contain a write-through flag.
2205331Samw *
2215331Samw * With LM0.12, the open calls (SmbCreateAndX, SmbNtTransactCreate)
2225331Samw * don't indicate which write-through mode to use. Instead the write
2235331Samw * calls (SmbWriteAndX, SmbWriteRaw) specify the mode on a per call
2245331Samw * basis.
2255331Samw *
2265331Samw * We don't care which open call was used to get us here, we just need
2275331Samw * to ensure that the write-through mode flag is copied from the open
2285331Samw * parameters to the node. We test the omode write-through flag in all
2295331Samw * write functions.
2305331Samw *
2315331Samw * This function will return NT status codes but it also raises errors,
2325331Samw * in which case it won't return to the caller. Be careful how you
2335331Samw * handle things in here.
2346600Sas200622 *
2356600Sas200622 * The following rules apply when processing a file open request:
2366600Sas200622 *
237*12890SJoyce.McIntosh@Sun.COM * - Oplocks must be broken prior to share checking as the break may
238*12890SJoyce.McIntosh@Sun.COM * cause other clients to close the file, which would affect sharing
239*12890SJoyce.McIntosh@Sun.COM * checks.
2406600Sas200622 *
2416600Sas200622 * - Share checks must take place prior to access checks for correct
2426600Sas200622 * Windows semantics and to prevent unnecessary NFS delegation recalls.
2436600Sas200622 *
2446600Sas200622 * - Oplocks must be acquired after open to ensure the correct
2456600Sas200622 * synchronization with NFS delegation and FEM installation.
2467348SJose.Borrego@Sun.COM *
2477348SJose.Borrego@Sun.COM * DOS readonly bit rules
2487348SJose.Borrego@Sun.COM *
2497348SJose.Borrego@Sun.COM * 1. The creator of a readonly file can write to/modify the size of the file
2507348SJose.Borrego@Sun.COM * using the original create fid, even though the file will appear as readonly
2517348SJose.Borrego@Sun.COM * to all other fids and via a CIFS getattr call.
25210001SJoyce.McIntosh@Sun.COM * The readonly bit therefore cannot be set in the filesystem until the file
25310001SJoyce.McIntosh@Sun.COM * is closed (smb_ofile_close). It is accounted for via ofile and node flags.
2547348SJose.Borrego@Sun.COM *
2557348SJose.Borrego@Sun.COM * 2. A setinfo operation (using either an open fid or a path) to set/unset
2567348SJose.Borrego@Sun.COM * readonly will be successful regardless of whether a creator of a readonly
2577348SJose.Borrego@Sun.COM * file has an open fid (and has the special privilege mentioned in #1,
2587348SJose.Borrego@Sun.COM * above). I.e., the creator of a readonly fid holding that fid will no longer
2597348SJose.Borrego@Sun.COM * have a special privilege.
2607348SJose.Borrego@Sun.COM *
2617348SJose.Borrego@Sun.COM * 3. The DOS readonly bit affects only data and some metadata.
2627348SJose.Borrego@Sun.COM * The following metadata can be changed regardless of the readonly bit:
2637348SJose.Borrego@Sun.COM * - security descriptors
2647348SJose.Borrego@Sun.COM * - DOS attributes
2657348SJose.Borrego@Sun.COM * - timestamps
2667348SJose.Borrego@Sun.COM *
2677348SJose.Borrego@Sun.COM * In the current implementation, the file size cannot be changed (except for
2687348SJose.Borrego@Sun.COM * the exceptions in #1 and #2, above).
2697619SJose.Borrego@Sun.COM *
2707619SJose.Borrego@Sun.COM *
2717619SJose.Borrego@Sun.COM * DOS attribute rules
2727619SJose.Borrego@Sun.COM *
2737619SJose.Borrego@Sun.COM * These rules are specific to creating / opening files and directories.
2747619SJose.Borrego@Sun.COM * How the attribute value (specifically ZERO or FILE_ATTRIBUTE_NORMAL)
2757619SJose.Borrego@Sun.COM * should be interpreted may differ in other requests.
2767619SJose.Borrego@Sun.COM *
2777619SJose.Borrego@Sun.COM * - An attribute value equal to ZERO or FILE_ATTRIBUTE_NORMAL means that the
2787619SJose.Borrego@Sun.COM * file's attributes should be cleared.
2797619SJose.Borrego@Sun.COM * - If FILE_ATTRIBUTE_NORMAL is specified with any other attributes,
2807619SJose.Borrego@Sun.COM * FILE_ATTRIBUTE_NORMAL is ignored.
2817619SJose.Borrego@Sun.COM *
2827619SJose.Borrego@Sun.COM * 1. Creating a new file
2837619SJose.Borrego@Sun.COM * - The request attributes + FILE_ATTRIBUTE_ARCHIVE are applied to the file.
2847619SJose.Borrego@Sun.COM *
2857619SJose.Borrego@Sun.COM * 2. Creating a new directory
2867619SJose.Borrego@Sun.COM * - The request attributes + FILE_ATTRIBUTE_DIRECTORY are applied to the file.
2877619SJose.Borrego@Sun.COM * - FILE_ATTRIBUTE_ARCHIVE does not get set.
2887619SJose.Borrego@Sun.COM *
2897619SJose.Borrego@Sun.COM * 3. Overwriting an existing file
2907619SJose.Borrego@Sun.COM * - the request attributes are used as search attributes. If the existing
2917619SJose.Borrego@Sun.COM * file does not meet the search criteria access is denied.
2927619SJose.Borrego@Sun.COM * - otherwise, applies attributes + FILE_ATTRIBUTE_ARCHIVE.
2937619SJose.Borrego@Sun.COM *
2947619SJose.Borrego@Sun.COM * 4. Opening an existing file or directory
2957619SJose.Borrego@Sun.COM * The request attributes are ignored.
2965331Samw */
2976030Sjb150015 static uint32_t
smb_open_subr(smb_request_t * sr)2986030Sjb150015 smb_open_subr(smb_request_t *sr)
2995331Samw {
3009343SAfshin.Ardakani@Sun.COM boolean_t created = B_FALSE;
3019343SAfshin.Ardakani@Sun.COM boolean_t last_comp_found = B_FALSE;
3028934SJose.Borrego@Sun.COM smb_node_t *node = NULL;
3038934SJose.Borrego@Sun.COM smb_node_t *dnode = NULL;
3049343SAfshin.Ardakani@Sun.COM smb_node_t *cur_node = NULL;
30512508Samw@Sun.COM smb_arg_open_t *op = &sr->sr_open;
3068934SJose.Borrego@Sun.COM int rc;
3078934SJose.Borrego@Sun.COM smb_ofile_t *of;
3088934SJose.Borrego@Sun.COM smb_attr_t new_attr;
3098934SJose.Borrego@Sun.COM int max_requested = 0;
3108934SJose.Borrego@Sun.COM uint32_t max_allowed;
3118934SJose.Borrego@Sun.COM uint32_t status = NT_STATUS_SUCCESS;
3128934SJose.Borrego@Sun.COM int is_dir;
3138934SJose.Borrego@Sun.COM smb_error_t err;
3148934SJose.Borrego@Sun.COM boolean_t is_stream = B_FALSE;
3158934SJose.Borrego@Sun.COM int lookup_flags = SMB_FOLLOW_LINKS;
3168934SJose.Borrego@Sun.COM uint32_t uniq_fid;
3179343SAfshin.Ardakani@Sun.COM smb_pathname_t *pn = &op->fqi.fq_path;
318*12890SJoyce.McIntosh@Sun.COM smb_server_t *sv = sr->sr_server;
3195331Samw
3205331Samw is_dir = (op->create_options & FILE_DIRECTORY_FILE) ? 1 : 0;
3215331Samw
32210001SJoyce.McIntosh@Sun.COM /*
32310001SJoyce.McIntosh@Sun.COM * If the object being created or opened is a directory
32410001SJoyce.McIntosh@Sun.COM * the Disposition parameter must be one of FILE_CREATE,
32510001SJoyce.McIntosh@Sun.COM * FILE_OPEN, or FILE_OPEN_IF
32610001SJoyce.McIntosh@Sun.COM */
3275331Samw if (is_dir) {
3285331Samw if ((op->create_disposition != FILE_CREATE) &&
3295331Samw (op->create_disposition != FILE_OPEN_IF) &&
3305331Samw (op->create_disposition != FILE_OPEN)) {
3315772Sas200622 smbsr_error(sr, NT_STATUS_INVALID_PARAMETER,
3325331Samw ERRDOS, ERROR_INVALID_ACCESS);
3336030Sjb150015 return (NT_STATUS_INVALID_PARAMETER);
3345331Samw }
3355331Samw }
3365331Samw
3375331Samw if (op->desired_access & MAXIMUM_ALLOWED) {
3385331Samw max_requested = 1;
3395331Samw op->desired_access &= ~MAXIMUM_ALLOWED;
3405331Samw }
3415331Samw op->desired_access = smb_access_generic_to_file(op->desired_access);
3425331Samw
3435331Samw if (sr->session->s_file_cnt >= SMB_SESSION_OFILE_MAX) {
3445331Samw ASSERT(sr->uid_user);
345*12890SJoyce.McIntosh@Sun.COM cmn_err(CE_NOTE, "smbsrv[%s\\%s]: TOO_MANY_OPENED_FILES",
34612508Samw@Sun.COM sr->uid_user->u_domain, sr->uid_user->u_name);
3475331Samw
3485772Sas200622 smbsr_error(sr, NT_STATUS_TOO_MANY_OPENED_FILES,
3495331Samw ERRDOS, ERROR_TOO_MANY_OPEN_FILES);
3506030Sjb150015 return (NT_STATUS_TOO_MANY_OPENED_FILES);
3515331Samw }
3525331Samw
3535331Samw /* This must be NULL at this point */
3545331Samw sr->fid_ofile = NULL;
3555331Samw
3565331Samw op->devstate = 0;
3575331Samw
3585331Samw switch (sr->tid_tree->t_res_type & STYPE_MASK) {
3595331Samw case STYPE_DISKTREE:
36011447Samw@Sun.COM case STYPE_PRINTQ:
3615331Samw break;
3625331Samw
3635331Samw case STYPE_IPC:
364*12890SJoyce.McIntosh@Sun.COM
365*12890SJoyce.McIntosh@Sun.COM if ((rc = smb_threshold_enter(&sv->sv_opipe_ct)) != 0) {
366*12890SJoyce.McIntosh@Sun.COM status = RPC_NT_SERVER_TOO_BUSY;
367*12890SJoyce.McIntosh@Sun.COM smbsr_error(sr, status, 0, 0);
368*12890SJoyce.McIntosh@Sun.COM return (status);
369*12890SJoyce.McIntosh@Sun.COM }
370*12890SJoyce.McIntosh@Sun.COM
3715331Samw /*
3725331Samw * No further processing for IPC, we need to either
3735331Samw * raise an exception or return success here.
3745331Samw */
3757052Samw if ((status = smb_opipe_open(sr)) != NT_STATUS_SUCCESS)
3766030Sjb150015 smbsr_error(sr, status, 0, 0);
377*12890SJoyce.McIntosh@Sun.COM
378*12890SJoyce.McIntosh@Sun.COM smb_threshold_exit(&sv->sv_opipe_ct, sv);
3796030Sjb150015 return (status);
3805331Samw
3815331Samw default:
3826030Sjb150015 smbsr_error(sr, NT_STATUS_BAD_DEVICE_TYPE,
3836030Sjb150015 ERRDOS, ERROR_BAD_DEV_TYPE);
3846030Sjb150015 return (NT_STATUS_BAD_DEVICE_TYPE);
3855331Samw }
3865331Samw
38711337SWilliam.Krier@Sun.COM smb_pathname_init(sr, pn, pn->pn_path);
38811337SWilliam.Krier@Sun.COM if (!smb_pathname_validate(sr, pn))
38911337SWilliam.Krier@Sun.COM return (sr->smb_error.status);
39011337SWilliam.Krier@Sun.COM
39111337SWilliam.Krier@Sun.COM if (strlen(pn->pn_path) >= MAXPATHLEN) {
3925772Sas200622 smbsr_error(sr, 0, ERRSRV, ERRfilespecs);
3936030Sjb150015 return (NT_STATUS_NAME_TOO_LONG);
3945331Samw }
3955331Samw
39611337SWilliam.Krier@Sun.COM if (is_dir) {
39711337SWilliam.Krier@Sun.COM if (!smb_validate_dirname(sr, pn))
39811337SWilliam.Krier@Sun.COM return (sr->smb_error.status);
39911337SWilliam.Krier@Sun.COM } else {
40011337SWilliam.Krier@Sun.COM if (!smb_validate_object_name(sr, pn))
40111337SWilliam.Krier@Sun.COM return (sr->smb_error.status);
4025331Samw }
4035331Samw
4049343SAfshin.Ardakani@Sun.COM cur_node = op->fqi.fq_dnode ?
4059343SAfshin.Ardakani@Sun.COM op->fqi.fq_dnode : sr->tid_tree->t_snode;
4069343SAfshin.Ardakani@Sun.COM
4079343SAfshin.Ardakani@Sun.COM /*
4089343SAfshin.Ardakani@Sun.COM * if no path or filename are specified the stream should be
4099343SAfshin.Ardakani@Sun.COM * created on cur_node
4109343SAfshin.Ardakani@Sun.COM */
4119343SAfshin.Ardakani@Sun.COM if (!is_dir && !pn->pn_pname && !pn->pn_fname && pn->pn_sname) {
41211963SAfshin.Ardakani@Sun.COM /*
41311963SAfshin.Ardakani@Sun.COM * Can't currently handle a stream on the tree root.
41411963SAfshin.Ardakani@Sun.COM * If a stream is being opened return "not found", otherwise
41511963SAfshin.Ardakani@Sun.COM * return "access denied".
41611963SAfshin.Ardakani@Sun.COM */
4179343SAfshin.Ardakani@Sun.COM if (cur_node == sr->tid_tree->t_snode) {
41811963SAfshin.Ardakani@Sun.COM if (op->create_disposition == FILE_OPEN) {
41911963SAfshin.Ardakani@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
42011963SAfshin.Ardakani@Sun.COM ERRDOS, ERROR_FILE_NOT_FOUND);
42111963SAfshin.Ardakani@Sun.COM return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
42211963SAfshin.Ardakani@Sun.COM }
4239343SAfshin.Ardakani@Sun.COM smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
4249343SAfshin.Ardakani@Sun.COM ERROR_ACCESS_DENIED);
4259343SAfshin.Ardakani@Sun.COM return (NT_STATUS_ACCESS_DENIED);
4269343SAfshin.Ardakani@Sun.COM }
4279343SAfshin.Ardakani@Sun.COM
4289343SAfshin.Ardakani@Sun.COM (void) snprintf(op->fqi.fq_last_comp,
4299343SAfshin.Ardakani@Sun.COM sizeof (op->fqi.fq_last_comp),
4309343SAfshin.Ardakani@Sun.COM "%s%s", cur_node->od_name, pn->pn_sname);
4319343SAfshin.Ardakani@Sun.COM
43210122SJordan.Brown@Sun.COM op->fqi.fq_dnode = cur_node->n_dnode;
4339343SAfshin.Ardakani@Sun.COM smb_node_ref(op->fqi.fq_dnode);
4349343SAfshin.Ardakani@Sun.COM } else {
4359343SAfshin.Ardakani@Sun.COM if (rc = smb_pathname_reduce(sr, sr->user_cr, pn->pn_path,
4369343SAfshin.Ardakani@Sun.COM sr->tid_tree->t_snode, cur_node, &op->fqi.fq_dnode,
4379343SAfshin.Ardakani@Sun.COM op->fqi.fq_last_comp)) {
4389343SAfshin.Ardakani@Sun.COM smbsr_errno(sr, rc);
4399343SAfshin.Ardakani@Sun.COM return (sr->smb_error.status);
4409343SAfshin.Ardakani@Sun.COM }
4415331Samw }
4425331Samw
4435331Samw /*
4445331Samw * If the access mask has only DELETE set (ignore
4455331Samw * FILE_READ_ATTRIBUTES), then assume that this
4465331Samw * is a request to delete the link (if a link)
4475331Samw * and do not follow links. Otherwise, follow
4485331Samw * the link to the target.
4495331Samw */
45010001SJoyce.McIntosh@Sun.COM if ((op->desired_access & ~FILE_READ_ATTRIBUTES) == DELETE)
4515331Samw lookup_flags &= ~SMB_FOLLOW_LINKS;
4525331Samw
4535331Samw rc = smb_fsop_lookup_name(sr, kcred, lookup_flags,
4549343SAfshin.Ardakani@Sun.COM sr->tid_tree->t_snode, op->fqi.fq_dnode, op->fqi.fq_last_comp,
45510001SJoyce.McIntosh@Sun.COM &op->fqi.fq_fnode);
4565331Samw
4575331Samw if (rc == 0) {
4589343SAfshin.Ardakani@Sun.COM last_comp_found = B_TRUE;
45910001SJoyce.McIntosh@Sun.COM rc = smb_node_getattr(sr, op->fqi.fq_fnode,
46010001SJoyce.McIntosh@Sun.COM &op->fqi.fq_fattr);
46110001SJoyce.McIntosh@Sun.COM if (rc != 0) {
46210001SJoyce.McIntosh@Sun.COM smb_node_release(op->fqi.fq_fnode);
46310001SJoyce.McIntosh@Sun.COM smb_node_release(op->fqi.fq_dnode);
46410001SJoyce.McIntosh@Sun.COM smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
46510001SJoyce.McIntosh@Sun.COM ERRDOS, ERROR_INTERNAL_ERROR);
46610001SJoyce.McIntosh@Sun.COM return (sr->smb_error.status);
46710001SJoyce.McIntosh@Sun.COM }
4685331Samw } else if (rc == ENOENT) {
4699343SAfshin.Ardakani@Sun.COM last_comp_found = B_FALSE;
4709343SAfshin.Ardakani@Sun.COM op->fqi.fq_fnode = NULL;
4715331Samw rc = 0;
4725331Samw } else {
4739343SAfshin.Ardakani@Sun.COM smb_node_release(op->fqi.fq_dnode);
4745772Sas200622 smbsr_errno(sr, rc);
4756030Sjb150015 return (sr->smb_error.status);
4765331Samw }
4775331Samw
47810001SJoyce.McIntosh@Sun.COM
4795772Sas200622 /*
4805772Sas200622 * The uniq_fid is a CIFS-server-wide unique identifier for an ofile
4815772Sas200622 * which is used to uniquely identify open instances for the
4827348SJose.Borrego@Sun.COM * VFS share reservation and POSIX locks.
4835772Sas200622 */
4845772Sas200622
4855772Sas200622 uniq_fid = SMB_UNIQ_FID();
4865772Sas200622
4879343SAfshin.Ardakani@Sun.COM if (last_comp_found) {
4886432Sas200622
48911963SAfshin.Ardakani@Sun.COM node = op->fqi.fq_fnode;
49011963SAfshin.Ardakani@Sun.COM dnode = op->fqi.fq_dnode;
4916432Sas200622
49211963SAfshin.Ardakani@Sun.COM if (!smb_node_is_file(node) && !smb_node_is_dir(node) &&
49311963SAfshin.Ardakani@Sun.COM !smb_node_is_symlink(node)) {
49411963SAfshin.Ardakani@Sun.COM smb_node_release(node);
49511963SAfshin.Ardakani@Sun.COM smb_node_release(dnode);
4966432Sas200622 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS,
4976432Sas200622 ERRnoaccess);
4986432Sas200622 return (NT_STATUS_ACCESS_DENIED);
4996432Sas200622 }
5006432Sas200622
5015331Samw /*
5027619SJose.Borrego@Sun.COM * Reject this request if either:
5037619SJose.Borrego@Sun.COM * - the target IS a directory and the client requires that
5047619SJose.Borrego@Sun.COM * it must NOT be (required by Lotus Notes)
5057619SJose.Borrego@Sun.COM * - the target is NOT a directory and client requires that
5067619SJose.Borrego@Sun.COM * it MUST be.
5075331Samw */
50811963SAfshin.Ardakani@Sun.COM if (smb_node_is_dir(node)) {
5097619SJose.Borrego@Sun.COM if (op->create_options & FILE_NON_DIRECTORY_FILE) {
5105331Samw smb_node_release(node);
5115331Samw smb_node_release(dnode);
5125772Sas200622 smbsr_error(sr, NT_STATUS_FILE_IS_A_DIRECTORY,
5135331Samw ERRDOS, ERROR_ACCESS_DENIED);
5146030Sjb150015 return (NT_STATUS_FILE_IS_A_DIRECTORY);
5155331Samw }
5167619SJose.Borrego@Sun.COM } else {
5177619SJose.Borrego@Sun.COM if ((op->create_options & FILE_DIRECTORY_FILE) ||
5188934SJose.Borrego@Sun.COM (op->nt_flags & NT_CREATE_FLAG_OPEN_TARGET_DIR)) {
5197619SJose.Borrego@Sun.COM smb_node_release(node);
5207619SJose.Borrego@Sun.COM smb_node_release(dnode);
5217619SJose.Borrego@Sun.COM smbsr_error(sr, NT_STATUS_NOT_A_DIRECTORY,
5227619SJose.Borrego@Sun.COM ERRDOS, ERROR_DIRECTORY);
5237619SJose.Borrego@Sun.COM return (NT_STATUS_NOT_A_DIRECTORY);
5247619SJose.Borrego@Sun.COM }
5255331Samw }
5265331Samw
5275331Samw /*
5285331Samw * No more open should be accepted when "Delete on close"
5295331Samw * flag is set.
5305331Samw */
5315331Samw if (node->flags & NODE_FLAGS_DELETE_ON_CLOSE) {
5325331Samw smb_node_release(node);
5335331Samw smb_node_release(dnode);
5345772Sas200622 smbsr_error(sr, NT_STATUS_DELETE_PENDING,
5355331Samw ERRDOS, ERROR_ACCESS_DENIED);
5366030Sjb150015 return (NT_STATUS_DELETE_PENDING);
5375331Samw }
5385331Samw
5395331Samw /*
5405331Samw * Specified file already exists so the operation should fail.
5415331Samw */
5425331Samw if (op->create_disposition == FILE_CREATE) {
5435331Samw smb_node_release(node);
5445331Samw smb_node_release(dnode);
5455772Sas200622 smbsr_error(sr, NT_STATUS_OBJECT_NAME_COLLISION,
5467961SNatalie.Li@Sun.COM ERRDOS, ERROR_FILE_EXISTS);
5476030Sjb150015 return (NT_STATUS_OBJECT_NAME_COLLISION);
5485331Samw }
5495331Samw
5505331Samw /*
5515331Samw * Windows seems to check read-only access before file
5525331Samw * sharing check.
5537348SJose.Borrego@Sun.COM *
5547348SJose.Borrego@Sun.COM * Check to see if the file is currently readonly (irrespective
5557348SJose.Borrego@Sun.COM * of whether this open will make it readonly).
5565331Samw */
5577348SJose.Borrego@Sun.COM if (SMB_PATHFILE_IS_READONLY(sr, node)) {
5585331Samw /* Files data only */
55910001SJoyce.McIntosh@Sun.COM if (!smb_node_is_dir(node)) {
5605331Samw if (op->desired_access & (FILE_WRITE_DATA |
5615331Samw FILE_APPEND_DATA)) {
5625331Samw smb_node_release(node);
5635331Samw smb_node_release(dnode);
5645772Sas200622 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
5655772Sas200622 ERRDOS, ERRnoaccess);
5666030Sjb150015 return (NT_STATUS_ACCESS_DENIED);
5675331Samw }
5685331Samw }
5695331Samw }
5705331Samw
571*12890SJoyce.McIntosh@Sun.COM /*
572*12890SJoyce.McIntosh@Sun.COM * Oplock break is done prior to sharing checks as the break
573*12890SJoyce.McIntosh@Sun.COM * may cause other clients to close the file which would
574*12890SJoyce.McIntosh@Sun.COM * affect the sharing checks.
575*12890SJoyce.McIntosh@Sun.COM */
576*12890SJoyce.McIntosh@Sun.COM smb_node_inc_opening_count(node);
577*12890SJoyce.McIntosh@Sun.COM smb_open_oplock_break(sr, node);
5786600Sas200622
5798934SJose.Borrego@Sun.COM smb_node_wrlock(node);
5805772Sas200622
5815772Sas200622 if ((op->create_disposition == FILE_SUPERSEDE) ||
5825772Sas200622 (op->create_disposition == FILE_OVERWRITE_IF) ||
5835772Sas200622 (op->create_disposition == FILE_OVERWRITE)) {
5845772Sas200622
5857619SJose.Borrego@Sun.COM if ((!(op->desired_access &
5866600Sas200622 (FILE_WRITE_DATA | FILE_APPEND_DATA |
5877619SJose.Borrego@Sun.COM FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA))) ||
58810001SJoyce.McIntosh@Sun.COM (!smb_sattr_check(op->fqi.fq_fattr.sa_dosattr,
5898934SJose.Borrego@Sun.COM op->dattr))) {
5908934SJose.Borrego@Sun.COM smb_node_unlock(node);
591*12890SJoyce.McIntosh@Sun.COM smb_node_dec_opening_count(node);
5925772Sas200622 smb_node_release(node);
5935772Sas200622 smb_node_release(dnode);
5945772Sas200622 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
5955772Sas200622 ERRDOS, ERRnoaccess);
5966030Sjb150015 return (NT_STATUS_ACCESS_DENIED);
5975772Sas200622 }
5985772Sas200622 }
5995772Sas200622
6005772Sas200622 status = smb_fsop_shrlock(sr->user_cr, node, uniq_fid,
6017348SJose.Borrego@Sun.COM op->desired_access, op->share_access);
6025772Sas200622
6035331Samw if (status == NT_STATUS_SHARING_VIOLATION) {
6048934SJose.Borrego@Sun.COM smb_node_unlock(node);
605*12890SJoyce.McIntosh@Sun.COM smb_node_dec_opening_count(node);
6065331Samw smb_node_release(node);
6075331Samw smb_node_release(dnode);
6085331Samw return (status);
6095331Samw }
6105331Samw
6115331Samw status = smb_fsop_access(sr, sr->user_cr, node,
6125331Samw op->desired_access);
6135331Samw
6145331Samw if (status != NT_STATUS_SUCCESS) {
6155772Sas200622 smb_fsop_unshrlock(sr->user_cr, node, uniq_fid);
6165772Sas200622
6178934SJose.Borrego@Sun.COM smb_node_unlock(node);
618*12890SJoyce.McIntosh@Sun.COM smb_node_dec_opening_count(node);
6195331Samw smb_node_release(node);
6205331Samw smb_node_release(dnode);
6215772Sas200622
6225331Samw if (status == NT_STATUS_PRIVILEGE_NOT_HELD) {
6235772Sas200622 smbsr_error(sr, status,
6245772Sas200622 ERRDOS, ERROR_PRIVILEGE_NOT_HELD);
6256030Sjb150015 return (status);
6265331Samw } else {
6275772Sas200622 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
6285772Sas200622 ERRDOS, ERROR_ACCESS_DENIED);
6296030Sjb150015 return (NT_STATUS_ACCESS_DENIED);
6305331Samw }
6315331Samw }
6325331Samw
6335331Samw switch (op->create_disposition) {
6345331Samw case FILE_SUPERSEDE:
6355331Samw case FILE_OVERWRITE_IF:
6365331Samw case FILE_OVERWRITE:
63710001SJoyce.McIntosh@Sun.COM if (smb_node_is_dir(node)) {
6385772Sas200622 smb_fsop_unshrlock(sr->user_cr, node, uniq_fid);
6398934SJose.Borrego@Sun.COM smb_node_unlock(node);
640*12890SJoyce.McIntosh@Sun.COM smb_node_dec_opening_count(node);
6415331Samw smb_node_release(node);
6425331Samw smb_node_release(dnode);
6435772Sas200622 smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
6445772Sas200622 ERRDOS, ERROR_ACCESS_DENIED);
6456030Sjb150015 return (NT_STATUS_ACCESS_DENIED);
6465331Samw }
6475331Samw
6487619SJose.Borrego@Sun.COM op->dattr |= FILE_ATTRIBUTE_ARCHIVE;
64910001SJoyce.McIntosh@Sun.COM /* Don't apply readonly bit until smb_ofile_close */
6507619SJose.Borrego@Sun.COM if (op->dattr & FILE_ATTRIBUTE_READONLY) {
6517619SJose.Borrego@Sun.COM op->created_readonly = B_TRUE;
6527619SJose.Borrego@Sun.COM op->dattr &= ~FILE_ATTRIBUTE_READONLY;
6537619SJose.Borrego@Sun.COM }
6547619SJose.Borrego@Sun.COM
65510001SJoyce.McIntosh@Sun.COM bzero(&new_attr, sizeof (new_attr));
65610001SJoyce.McIntosh@Sun.COM new_attr.sa_dosattr = op->dattr;
65710001SJoyce.McIntosh@Sun.COM new_attr.sa_vattr.va_size = op->dsize;
65810001SJoyce.McIntosh@Sun.COM new_attr.sa_mask = SMB_AT_DOSATTR | SMB_AT_SIZE;
65910001SJoyce.McIntosh@Sun.COM rc = smb_fsop_setattr(sr, sr->user_cr, node, &new_attr);
66010001SJoyce.McIntosh@Sun.COM if (rc != 0) {
66110001SJoyce.McIntosh@Sun.COM smb_fsop_unshrlock(sr->user_cr, node, uniq_fid);
66210001SJoyce.McIntosh@Sun.COM smb_node_unlock(node);
663*12890SJoyce.McIntosh@Sun.COM smb_node_dec_opening_count(node);
66410001SJoyce.McIntosh@Sun.COM smb_node_release(node);
66510001SJoyce.McIntosh@Sun.COM smb_node_release(dnode);
66610001SJoyce.McIntosh@Sun.COM smbsr_errno(sr, rc);
66710001SJoyce.McIntosh@Sun.COM return (sr->smb_error.status);
66810001SJoyce.McIntosh@Sun.COM }
6697619SJose.Borrego@Sun.COM
6705331Samw /*
67110001SJoyce.McIntosh@Sun.COM * If file is being replaced, remove existing streams
6725331Samw */
6739343SAfshin.Ardakani@Sun.COM if (SMB_IS_STREAM(node) == 0) {
67410001SJoyce.McIntosh@Sun.COM rc = smb_fsop_remove_streams(sr, sr->user_cr,
67510001SJoyce.McIntosh@Sun.COM node);
67610001SJoyce.McIntosh@Sun.COM if (rc != 0) {
6779343SAfshin.Ardakani@Sun.COM smb_fsop_unshrlock(sr->user_cr, node,
6789343SAfshin.Ardakani@Sun.COM uniq_fid);
6799343SAfshin.Ardakani@Sun.COM smb_node_unlock(node);
680*12890SJoyce.McIntosh@Sun.COM smb_node_dec_opening_count(node);
6819343SAfshin.Ardakani@Sun.COM smb_node_release(node);
6829343SAfshin.Ardakani@Sun.COM smb_node_release(dnode);
6839343SAfshin.Ardakani@Sun.COM return (sr->smb_error.status);
6849343SAfshin.Ardakani@Sun.COM }
6859343SAfshin.Ardakani@Sun.COM }
6865331Samw
6875331Samw op->action_taken = SMB_OACT_TRUNCATED;
6885331Samw break;
6895331Samw
6905331Samw default:
6915331Samw /*
6925331Samw * FILE_OPEN or FILE_OPEN_IF.
6935331Samw */
6945331Samw op->action_taken = SMB_OACT_OPENED;
6955331Samw break;
6965331Samw }
6975331Samw } else {
6985331Samw /* Last component was not found. */
6999343SAfshin.Ardakani@Sun.COM dnode = op->fqi.fq_dnode;
7005331Samw
7016030Sjb150015 if (is_dir == 0)
7029343SAfshin.Ardakani@Sun.COM is_stream = smb_is_stream_name(pn->pn_path);
7036030Sjb150015
7045331Samw if ((op->create_disposition == FILE_OPEN) ||
7055331Samw (op->create_disposition == FILE_OVERWRITE)) {
7065331Samw smb_node_release(dnode);
7076139Sjb150015 smbsr_error(sr, NT_STATUS_OBJECT_NAME_NOT_FOUND,
7086139Sjb150015 ERRDOS, ERROR_FILE_NOT_FOUND);
7096030Sjb150015 return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
7105331Samw }
7115331Samw
71211963SAfshin.Ardakani@Sun.COM if (pn->pn_fname && smb_is_invalid_filename(pn->pn_fname)) {
7138934SJose.Borrego@Sun.COM smb_node_release(dnode);
7148934SJose.Borrego@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID,
7158934SJose.Borrego@Sun.COM ERRDOS, ERROR_INVALID_NAME);
7168934SJose.Borrego@Sun.COM return (NT_STATUS_OBJECT_NAME_INVALID);
7178934SJose.Borrego@Sun.COM }
7188934SJose.Borrego@Sun.COM
7195331Samw /*
7205331Samw * lock the parent dir node in case another create
7215331Samw * request to the same parent directory comes in.
7225331Samw */
7238934SJose.Borrego@Sun.COM smb_node_wrlock(dnode);
7245331Samw
72510001SJoyce.McIntosh@Sun.COM /* Don't apply readonly bit until smb_ofile_close */
72610001SJoyce.McIntosh@Sun.COM if (op->dattr & FILE_ATTRIBUTE_READONLY) {
72710001SJoyce.McIntosh@Sun.COM op->dattr &= ~FILE_ATTRIBUTE_READONLY;
72810001SJoyce.McIntosh@Sun.COM op->created_readonly = B_TRUE;
72910001SJoyce.McIntosh@Sun.COM }
7307348SJose.Borrego@Sun.COM
73110001SJoyce.McIntosh@Sun.COM bzero(&new_attr, sizeof (new_attr));
7327348SJose.Borrego@Sun.COM if ((op->crtime.tv_sec != 0) &&
7337348SJose.Borrego@Sun.COM (op->crtime.tv_sec != UINT_MAX)) {
7347348SJose.Borrego@Sun.COM
7357348SJose.Borrego@Sun.COM new_attr.sa_mask |= SMB_AT_CRTIME;
7367348SJose.Borrego@Sun.COM new_attr.sa_crtime = op->crtime;
7377348SJose.Borrego@Sun.COM }
7387348SJose.Borrego@Sun.COM
7395331Samw if (is_dir == 0) {
74010001SJoyce.McIntosh@Sun.COM op->dattr |= FILE_ATTRIBUTE_ARCHIVE;
74110001SJoyce.McIntosh@Sun.COM new_attr.sa_dosattr = op->dattr;
7425331Samw new_attr.sa_vattr.va_type = VREG;
7436030Sjb150015 new_attr.sa_vattr.va_mode = is_stream ? S_IRUSR :
7446030Sjb150015 S_IRUSR | S_IRGRP | S_IROTH |
7456030Sjb150015 S_IWUSR | S_IWGRP | S_IWOTH;
74610001SJoyce.McIntosh@Sun.COM new_attr.sa_mask |=
74710001SJoyce.McIntosh@Sun.COM SMB_AT_DOSATTR | SMB_AT_TYPE | SMB_AT_MODE;
7485772Sas200622
7496432Sas200622 if (op->dsize) {
7506432Sas200622 new_attr.sa_vattr.va_size = op->dsize;
7516432Sas200622 new_attr.sa_mask |= SMB_AT_SIZE;
7525772Sas200622 }
7535772Sas200622
7545331Samw rc = smb_fsop_create(sr, sr->user_cr, dnode,
75510001SJoyce.McIntosh@Sun.COM op->fqi.fq_last_comp, &new_attr, &op->fqi.fq_fnode);
7565772Sas200622
7575331Samw if (rc != 0) {
7588934SJose.Borrego@Sun.COM smb_node_unlock(dnode);
7595331Samw smb_node_release(dnode);
7605772Sas200622 smbsr_errno(sr, rc);
7616030Sjb150015 return (sr->smb_error.status);
7625331Samw }
7635331Samw
7649343SAfshin.Ardakani@Sun.COM node = op->fqi.fq_fnode;
765*12890SJoyce.McIntosh@Sun.COM smb_node_inc_opening_count(node);
7668934SJose.Borrego@Sun.COM smb_node_wrlock(node);
7675772Sas200622
7686139Sjb150015 status = smb_fsop_shrlock(sr->user_cr, node, uniq_fid,
7697348SJose.Borrego@Sun.COM op->desired_access, op->share_access);
7705772Sas200622
7715772Sas200622 if (status == NT_STATUS_SHARING_VIOLATION) {
7728934SJose.Borrego@Sun.COM smb_node_unlock(node);
773*12890SJoyce.McIntosh@Sun.COM smb_node_dec_opening_count(node);
77410001SJoyce.McIntosh@Sun.COM smb_delete_new_object(sr);
7755772Sas200622 smb_node_release(node);
7768934SJose.Borrego@Sun.COM smb_node_unlock(dnode);
7775772Sas200622 smb_node_release(dnode);
7785772Sas200622 return (status);
7795772Sas200622 }
7805331Samw } else {
7817052Samw op->dattr |= FILE_ATTRIBUTE_DIRECTORY;
78210001SJoyce.McIntosh@Sun.COM new_attr.sa_dosattr = op->dattr;
7835331Samw new_attr.sa_vattr.va_type = VDIR;
7845331Samw new_attr.sa_vattr.va_mode = 0777;
78510001SJoyce.McIntosh@Sun.COM new_attr.sa_mask |=
78610001SJoyce.McIntosh@Sun.COM SMB_AT_DOSATTR | SMB_AT_TYPE | SMB_AT_MODE;
7877348SJose.Borrego@Sun.COM
7885331Samw rc = smb_fsop_mkdir(sr, sr->user_cr, dnode,
78910001SJoyce.McIntosh@Sun.COM op->fqi.fq_last_comp, &new_attr, &op->fqi.fq_fnode);
7905331Samw if (rc != 0) {
7918934SJose.Borrego@Sun.COM smb_node_unlock(dnode);
7925331Samw smb_node_release(dnode);
7935772Sas200622 smbsr_errno(sr, rc);
7946030Sjb150015 return (sr->smb_error.status);
7955331Samw }
7965772Sas200622
7979343SAfshin.Ardakani@Sun.COM node = op->fqi.fq_fnode;
798*12890SJoyce.McIntosh@Sun.COM smb_node_inc_opening_count(node);
7998934SJose.Borrego@Sun.COM smb_node_wrlock(node);
8005331Samw }
8015331Samw
8029343SAfshin.Ardakani@Sun.COM created = B_TRUE;
8035331Samw op->action_taken = SMB_OACT_CREATED;
8047348SJose.Borrego@Sun.COM }
8057348SJose.Borrego@Sun.COM
8067619SJose.Borrego@Sun.COM if (max_requested) {
8077619SJose.Borrego@Sun.COM smb_fsop_eaccess(sr, sr->user_cr, node, &max_allowed);
8087619SJose.Borrego@Sun.COM op->desired_access |= max_allowed;
8097619SJose.Borrego@Sun.COM }
8107619SJose.Borrego@Sun.COM
81110001SJoyce.McIntosh@Sun.COM status = NT_STATUS_SUCCESS;
8127619SJose.Borrego@Sun.COM
8137348SJose.Borrego@Sun.COM of = smb_ofile_open(sr->tid_tree, node, sr->smb_pid, op, SMB_FTYPE_DISK,
8147348SJose.Borrego@Sun.COM uniq_fid, &err);
81510001SJoyce.McIntosh@Sun.COM if (of == NULL) {
81610001SJoyce.McIntosh@Sun.COM smbsr_error(sr, err.status, err.errcls, err.errcode);
81710001SJoyce.McIntosh@Sun.COM status = err.status;
81810001SJoyce.McIntosh@Sun.COM }
8195331Samw
82010001SJoyce.McIntosh@Sun.COM if (status == NT_STATUS_SUCCESS) {
82110001SJoyce.McIntosh@Sun.COM if (!smb_tree_is_connected(sr->tid_tree)) {
82210001SJoyce.McIntosh@Sun.COM smbsr_error(sr, 0, ERRSRV, ERRinvnid);
82310001SJoyce.McIntosh@Sun.COM status = NT_STATUS_UNSUCCESSFUL;
82410001SJoyce.McIntosh@Sun.COM }
82510001SJoyce.McIntosh@Sun.COM }
82610001SJoyce.McIntosh@Sun.COM
82710001SJoyce.McIntosh@Sun.COM /*
82810001SJoyce.McIntosh@Sun.COM * This MUST be done after ofile creation, so that explicitly
82910001SJoyce.McIntosh@Sun.COM * set timestamps can be remembered on the ofile.
83010001SJoyce.McIntosh@Sun.COM */
83110001SJoyce.McIntosh@Sun.COM if (status == NT_STATUS_SUCCESS) {
83210001SJoyce.McIntosh@Sun.COM if ((rc = smb_set_open_timestamps(sr, of, created)) != 0) {
83310001SJoyce.McIntosh@Sun.COM smbsr_errno(sr, rc);
83410001SJoyce.McIntosh@Sun.COM status = sr->smb_error.status;
83510001SJoyce.McIntosh@Sun.COM }
83610001SJoyce.McIntosh@Sun.COM }
83710001SJoyce.McIntosh@Sun.COM
83810001SJoyce.McIntosh@Sun.COM if (status == NT_STATUS_SUCCESS) {
83910001SJoyce.McIntosh@Sun.COM if (smb_node_getattr(sr, node, &op->fqi.fq_fattr) != 0) {
84010001SJoyce.McIntosh@Sun.COM smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
84110001SJoyce.McIntosh@Sun.COM ERRDOS, ERROR_INTERNAL_ERROR);
84210001SJoyce.McIntosh@Sun.COM status = NT_STATUS_INTERNAL_ERROR;
84310001SJoyce.McIntosh@Sun.COM }
84410001SJoyce.McIntosh@Sun.COM }
84510001SJoyce.McIntosh@Sun.COM
84610001SJoyce.McIntosh@Sun.COM /*
84710001SJoyce.McIntosh@Sun.COM * smb_fsop_unshrlock is a no-op if node is a directory
84810001SJoyce.McIntosh@Sun.COM * smb_fsop_unshrlock is done in smb_ofile_close
84910001SJoyce.McIntosh@Sun.COM */
85010001SJoyce.McIntosh@Sun.COM if (status != NT_STATUS_SUCCESS) {
85110001SJoyce.McIntosh@Sun.COM if (of == NULL) {
85210001SJoyce.McIntosh@Sun.COM smb_fsop_unshrlock(sr->user_cr, node, uniq_fid);
85310001SJoyce.McIntosh@Sun.COM } else {
85410001SJoyce.McIntosh@Sun.COM smb_ofile_close(of, 0);
85510001SJoyce.McIntosh@Sun.COM smb_ofile_release(of);
85610001SJoyce.McIntosh@Sun.COM }
8579231SAfshin.Ardakani@Sun.COM if (created)
8589231SAfshin.Ardakani@Sun.COM smb_delete_new_object(sr);
8598934SJose.Borrego@Sun.COM smb_node_unlock(node);
860*12890SJoyce.McIntosh@Sun.COM smb_node_dec_opening_count(node);
8615331Samw smb_node_release(node);
8625331Samw if (created)
8638934SJose.Borrego@Sun.COM smb_node_unlock(dnode);
8645331Samw smb_node_release(dnode);
86510001SJoyce.McIntosh@Sun.COM return (status);
8669231SAfshin.Ardakani@Sun.COM }
8679231SAfshin.Ardakani@Sun.COM
8686600Sas200622 /*
8696600Sas200622 * Propagate the write-through mode from the open params
8706600Sas200622 * to the node: see the notes in the function header.
8716600Sas200622 */
8726600Sas200622 if (sr->sr_cfg->skc_sync_enable ||
8736600Sas200622 (op->create_options & FILE_WRITE_THROUGH))
8746600Sas200622 node->flags |= NODE_FLAGS_WRITE_THROUGH;
8756600Sas200622
87610001SJoyce.McIntosh@Sun.COM /*
87710001SJoyce.McIntosh@Sun.COM * Set up the fileid and dosattr in open_param for response
87810001SJoyce.McIntosh@Sun.COM */
8799343SAfshin.Ardakani@Sun.COM op->fileid = op->fqi.fq_fattr.sa_vattr.va_nodeid;
88010001SJoyce.McIntosh@Sun.COM op->dattr = op->fqi.fq_fattr.sa_dosattr;
8816600Sas200622
8825331Samw /*
8835331Samw * Set up the file type in open_param for the response
8845331Samw */
8855331Samw op->ftype = SMB_FTYPE_DISK;
8865331Samw sr->smb_fid = of->f_fid;
8875331Samw sr->fid_ofile = of;
8885331Samw
88911963SAfshin.Ardakani@Sun.COM if (smb_node_is_file(node)) {
890*12890SJoyce.McIntosh@Sun.COM smb_oplock_acquire(sr, node, of);
8919343SAfshin.Ardakani@Sun.COM op->dsize = op->fqi.fq_fattr.sa_vattr.va_size;
89211963SAfshin.Ardakani@Sun.COM } else {
89311963SAfshin.Ardakani@Sun.COM /* directory or symlink */
8948934SJose.Borrego@Sun.COM op->op_oplock_level = SMB_OPLOCK_NONE;
8958934SJose.Borrego@Sun.COM op->dsize = 0;
8968934SJose.Borrego@Sun.COM }
8975772Sas200622
898*12890SJoyce.McIntosh@Sun.COM smb_node_dec_opening_count(node);
899*12890SJoyce.McIntosh@Sun.COM
900*12890SJoyce.McIntosh@Sun.COM smb_node_unlock(node);
901*12890SJoyce.McIntosh@Sun.COM if (created)
902*12890SJoyce.McIntosh@Sun.COM smb_node_unlock(dnode);
903*12890SJoyce.McIntosh@Sun.COM
9049231SAfshin.Ardakani@Sun.COM smb_node_release(node);
9055331Samw smb_node_release(dnode);
9065331Samw
9075331Samw return (NT_STATUS_SUCCESS);
9085331Samw }
9095331Samw
9105331Samw /*
911*12890SJoyce.McIntosh@Sun.COM * smb_open_oplock_break
912*12890SJoyce.McIntosh@Sun.COM *
913*12890SJoyce.McIntosh@Sun.COM * If the node has an ofile opened with share access none,
914*12890SJoyce.McIntosh@Sun.COM * (smb_node_share_check = FALSE) only break BATCH oplock.
915*12890SJoyce.McIntosh@Sun.COM * Otherwise:
916*12890SJoyce.McIntosh@Sun.COM * If overwriting, break to SMB_OPLOCK_NONE, else
917*12890SJoyce.McIntosh@Sun.COM * If opening for anything other than attribute access,
918*12890SJoyce.McIntosh@Sun.COM * break oplock to LEVEL_II.
919*12890SJoyce.McIntosh@Sun.COM */
920*12890SJoyce.McIntosh@Sun.COM static void
smb_open_oplock_break(smb_request_t * sr,smb_node_t * node)921*12890SJoyce.McIntosh@Sun.COM smb_open_oplock_break(smb_request_t *sr, smb_node_t *node)
922*12890SJoyce.McIntosh@Sun.COM {
923*12890SJoyce.McIntosh@Sun.COM smb_arg_open_t *op = &sr->sr_open;
924*12890SJoyce.McIntosh@Sun.COM uint32_t flags = 0;
925*12890SJoyce.McIntosh@Sun.COM
926*12890SJoyce.McIntosh@Sun.COM if (!smb_node_share_check(node))
927*12890SJoyce.McIntosh@Sun.COM flags |= SMB_OPLOCK_BREAK_BATCH;
928*12890SJoyce.McIntosh@Sun.COM
929*12890SJoyce.McIntosh@Sun.COM if (smb_open_overwrite(op)) {
930*12890SJoyce.McIntosh@Sun.COM flags |= SMB_OPLOCK_BREAK_TO_NONE;
931*12890SJoyce.McIntosh@Sun.COM (void) smb_oplock_break(sr, node, flags);
932*12890SJoyce.McIntosh@Sun.COM } else if (!smb_open_attr_only(op)) {
933*12890SJoyce.McIntosh@Sun.COM flags |= SMB_OPLOCK_BREAK_TO_LEVEL_II;
934*12890SJoyce.McIntosh@Sun.COM (void) smb_oplock_break(sr, node, flags);
935*12890SJoyce.McIntosh@Sun.COM }
936*12890SJoyce.McIntosh@Sun.COM }
937*12890SJoyce.McIntosh@Sun.COM
938*12890SJoyce.McIntosh@Sun.COM /*
939*12890SJoyce.McIntosh@Sun.COM * smb_open_attr_only
940*12890SJoyce.McIntosh@Sun.COM *
941*12890SJoyce.McIntosh@Sun.COM * Determine if file is being opened for attribute access only.
942*12890SJoyce.McIntosh@Sun.COM * This is used to determine whether it is necessary to break
943*12890SJoyce.McIntosh@Sun.COM * existing oplocks on the file.
944*12890SJoyce.McIntosh@Sun.COM */
945*12890SJoyce.McIntosh@Sun.COM static boolean_t
smb_open_attr_only(smb_arg_open_t * op)946*12890SJoyce.McIntosh@Sun.COM smb_open_attr_only(smb_arg_open_t *op)
947*12890SJoyce.McIntosh@Sun.COM {
948*12890SJoyce.McIntosh@Sun.COM if (((op->desired_access & ~(FILE_READ_ATTRIBUTES |
949*12890SJoyce.McIntosh@Sun.COM FILE_WRITE_ATTRIBUTES | SYNCHRONIZE)) == 0) &&
950*12890SJoyce.McIntosh@Sun.COM (op->create_disposition != FILE_SUPERSEDE) &&
951*12890SJoyce.McIntosh@Sun.COM (op->create_disposition != FILE_OVERWRITE)) {
952*12890SJoyce.McIntosh@Sun.COM return (B_TRUE);
953*12890SJoyce.McIntosh@Sun.COM }
954*12890SJoyce.McIntosh@Sun.COM return (B_FALSE);
955*12890SJoyce.McIntosh@Sun.COM }
956*12890SJoyce.McIntosh@Sun.COM
957*12890SJoyce.McIntosh@Sun.COM static boolean_t
smb_open_overwrite(smb_arg_open_t * op)958*12890SJoyce.McIntosh@Sun.COM smb_open_overwrite(smb_arg_open_t *op)
959*12890SJoyce.McIntosh@Sun.COM {
960*12890SJoyce.McIntosh@Sun.COM if ((op->create_disposition == FILE_SUPERSEDE) ||
961*12890SJoyce.McIntosh@Sun.COM (op->create_disposition == FILE_OVERWRITE_IF) ||
962*12890SJoyce.McIntosh@Sun.COM (op->create_disposition == FILE_OVERWRITE)) {
963*12890SJoyce.McIntosh@Sun.COM return (B_TRUE);
964*12890SJoyce.McIntosh@Sun.COM }
965*12890SJoyce.McIntosh@Sun.COM return (B_FALSE);
966*12890SJoyce.McIntosh@Sun.COM }
967*12890SJoyce.McIntosh@Sun.COM /*
96810001SJoyce.McIntosh@Sun.COM * smb_set_open_timestamps
96910001SJoyce.McIntosh@Sun.COM *
97010001SJoyce.McIntosh@Sun.COM * Last write time:
97110001SJoyce.McIntosh@Sun.COM * - If the last_write time specified in the open params is not 0 or -1,
97210001SJoyce.McIntosh@Sun.COM * use it as file's mtime. This will be considered an explicitly set
97310001SJoyce.McIntosh@Sun.COM * timestamps, not reset by subsequent writes.
97410001SJoyce.McIntosh@Sun.COM *
97510001SJoyce.McIntosh@Sun.COM * Opening existing file (not directory):
97610001SJoyce.McIntosh@Sun.COM * - If opening an existing file for overwrite set initial ATIME, MTIME
97710001SJoyce.McIntosh@Sun.COM * & CTIME to now. (This is achieved by setting them as pending then forcing
97810001SJoyce.McIntosh@Sun.COM * an smb_node_setattr() to apply pending times.)
97910001SJoyce.McIntosh@Sun.COM *
98010001SJoyce.McIntosh@Sun.COM * - Note If opening an existing file NOT for overwrite, windows would
98110001SJoyce.McIntosh@Sun.COM * set the atime on file close, however setting the atime would cause
98210001SJoyce.McIntosh@Sun.COM * the ARCHIVE attribute to be set, which does not occur on windows,
98310001SJoyce.McIntosh@Sun.COM * so we do not do the atime update.
98410001SJoyce.McIntosh@Sun.COM *
98510001SJoyce.McIntosh@Sun.COM * Returns: errno
98610001SJoyce.McIntosh@Sun.COM */
98710001SJoyce.McIntosh@Sun.COM static int
smb_set_open_timestamps(smb_request_t * sr,smb_ofile_t * of,boolean_t created)98810001SJoyce.McIntosh@Sun.COM smb_set_open_timestamps(smb_request_t *sr, smb_ofile_t *of, boolean_t created)
98910001SJoyce.McIntosh@Sun.COM {
99010001SJoyce.McIntosh@Sun.COM int rc = 0;
99112508Samw@Sun.COM smb_arg_open_t *op = &sr->sr_open;
99210001SJoyce.McIntosh@Sun.COM smb_node_t *node = of->f_node;
99310001SJoyce.McIntosh@Sun.COM boolean_t existing_file, set_times;
99410001SJoyce.McIntosh@Sun.COM smb_attr_t attr;
99510001SJoyce.McIntosh@Sun.COM
99610001SJoyce.McIntosh@Sun.COM bzero(&attr, sizeof (smb_attr_t));
99710001SJoyce.McIntosh@Sun.COM set_times = B_FALSE;
99810001SJoyce.McIntosh@Sun.COM
99910001SJoyce.McIntosh@Sun.COM if ((op->mtime.tv_sec != 0) && (op->mtime.tv_sec != UINT_MAX)) {
100010001SJoyce.McIntosh@Sun.COM attr.sa_mask = SMB_AT_MTIME;
100110001SJoyce.McIntosh@Sun.COM attr.sa_vattr.va_mtime = op->mtime;
100210001SJoyce.McIntosh@Sun.COM set_times = B_TRUE;
100310001SJoyce.McIntosh@Sun.COM }
100410001SJoyce.McIntosh@Sun.COM
100510001SJoyce.McIntosh@Sun.COM existing_file = !(created || smb_node_is_dir(node));
100610001SJoyce.McIntosh@Sun.COM if (existing_file) {
100710001SJoyce.McIntosh@Sun.COM switch (op->create_disposition) {
100810001SJoyce.McIntosh@Sun.COM case FILE_SUPERSEDE:
100910001SJoyce.McIntosh@Sun.COM case FILE_OVERWRITE_IF:
101010001SJoyce.McIntosh@Sun.COM case FILE_OVERWRITE:
101110001SJoyce.McIntosh@Sun.COM smb_ofile_set_write_time_pending(of);
101210001SJoyce.McIntosh@Sun.COM set_times = B_TRUE;
101310001SJoyce.McIntosh@Sun.COM break;
101410001SJoyce.McIntosh@Sun.COM default:
101510001SJoyce.McIntosh@Sun.COM break;
101610001SJoyce.McIntosh@Sun.COM }
101710001SJoyce.McIntosh@Sun.COM }
101810001SJoyce.McIntosh@Sun.COM
101910001SJoyce.McIntosh@Sun.COM if (set_times)
102010001SJoyce.McIntosh@Sun.COM rc = smb_node_setattr(sr, node, sr->user_cr, of, &attr);
102110001SJoyce.McIntosh@Sun.COM
102210001SJoyce.McIntosh@Sun.COM return (rc);
102310001SJoyce.McIntosh@Sun.COM }
102410001SJoyce.McIntosh@Sun.COM
102510001SJoyce.McIntosh@Sun.COM /*
10269231SAfshin.Ardakani@Sun.COM * This function is used to delete a newly created object (file or
10279231SAfshin.Ardakani@Sun.COM * directory) if an error occurs after creation of the object.
10285331Samw */
10299231SAfshin.Ardakani@Sun.COM static void
smb_delete_new_object(smb_request_t * sr)10309231SAfshin.Ardakani@Sun.COM smb_delete_new_object(smb_request_t *sr)
10315331Samw {
103212508Samw@Sun.COM smb_arg_open_t *op = &sr->sr_open;
10339231SAfshin.Ardakani@Sun.COM smb_fqi_t *fqi = &(op->fqi);
10349231SAfshin.Ardakani@Sun.COM uint32_t flags = 0;
10359231SAfshin.Ardakani@Sun.COM
10369231SAfshin.Ardakani@Sun.COM if (SMB_TREE_IS_CASEINSENSITIVE(sr))
10379231SAfshin.Ardakani@Sun.COM flags |= SMB_IGNORE_CASE;
10389231SAfshin.Ardakani@Sun.COM if (SMB_TREE_SUPPORTS_CATIA(sr))
10399231SAfshin.Ardakani@Sun.COM flags |= SMB_CATIA;
10409231SAfshin.Ardakani@Sun.COM
10419231SAfshin.Ardakani@Sun.COM if (op->create_options & FILE_DIRECTORY_FILE)
10429343SAfshin.Ardakani@Sun.COM (void) smb_fsop_rmdir(sr, sr->user_cr, fqi->fq_dnode,
10439343SAfshin.Ardakani@Sun.COM fqi->fq_last_comp, flags);
10449231SAfshin.Ardakani@Sun.COM else
10459343SAfshin.Ardakani@Sun.COM (void) smb_fsop_remove(sr, sr->user_cr, fqi->fq_dnode,
10469343SAfshin.Ardakani@Sun.COM fqi->fq_last_comp, flags);
10475331Samw }
1048