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 */ 215331Samw /* 22*11963SAfshin.Ardakani@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw #include <sys/synch.h> 2710966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h> 285331Samw #include <smbsrv/smb_fsops.h> 295772Sas200622 #include <sys/nbmlock.h> 305331Samw 319914Samw@Sun.COM /* 329914Samw@Sun.COM * NT_RENAME InformationLevels: 339914Samw@Sun.COM * 349914Samw@Sun.COM * SMB_NT_RENAME_MOVE_CLUSTER_INFO Server returns invalid parameter. 359914Samw@Sun.COM * SMB_NT_RENAME_SET_LINK_INFO Create a hard link to a file. 369914Samw@Sun.COM * SMB_NT_RENAME_RENAME_FILE In-place rename of a file. 379914Samw@Sun.COM * SMB_NT_RENAME_MOVE_FILE Move (rename) a file. 389914Samw@Sun.COM */ 399914Samw@Sun.COM #define SMB_NT_RENAME_MOVE_CLUSTER_INFO 0x0102 409914Samw@Sun.COM #define SMB_NT_RENAME_SET_LINK_INFO 0x0103 419914Samw@Sun.COM #define SMB_NT_RENAME_RENAME_FILE 0x0104 429914Samw@Sun.COM #define SMB_NT_RENAME_MOVE_FILE 0x0105 439914Samw@Sun.COM 4410966SJordan.Brown@Sun.COM /* 4510966SJordan.Brown@Sun.COM * SMB_TRANS2_SET_FILE/PATH_INFO (RENAME_INFORMATION level) flag 4610966SJordan.Brown@Sun.COM */ 4710966SJordan.Brown@Sun.COM #define SMB_RENAME_FLAG_OVERWRITE 0x001 4810966SJordan.Brown@Sun.COM 4910966SJordan.Brown@Sun.COM static int smb_common_rename(smb_request_t *, smb_fqi_t *, smb_fqi_t *); 509914Samw@Sun.COM static int smb_make_link(smb_request_t *, smb_fqi_t *, smb_fqi_t *); 5110966SJordan.Brown@Sun.COM static int smb_rename_check_stream(smb_fqi_t *, smb_fqi_t *); 5210001SJoyce.McIntosh@Sun.COM static int smb_rename_check_attr(smb_request_t *, smb_node_t *, uint16_t); 539914Samw@Sun.COM static void smb_rename_set_error(smb_request_t *, int); 545331Samw 5510966SJordan.Brown@Sun.COM static int smb_rename_lookup_src(smb_request_t *); 5610966SJordan.Brown@Sun.COM static void smb_rename_release_src(smb_request_t *); 5710966SJordan.Brown@Sun.COM 585331Samw /* 595331Samw * smb_com_rename 605331Samw * 615331Samw * Rename a file. Files OldFileName must exist and NewFileName must not. 625331Samw * Both pathnames must be relative to the Tid specified in the request. 635331Samw * Open files may be renamed. 645331Samw * 655331Samw * Multiple files may be renamed in response to a single request as Rename 665331Samw * File supports wildcards in the file name (last component of the path). 675331Samw * NOTE: we don't support rename with wildcards. 685331Samw * 695331Samw * SearchAttributes indicates the attributes that the target file(s) must 705331Samw * have. If SearchAttributes is zero then only normal files are renamed. 715331Samw * If the system file or hidden attributes are specified then the rename 725331Samw * is inclusive - both the specified type(s) of files and normal files are 7310966SJordan.Brown@Sun.COM * renamed. 745331Samw */ 756030Sjb150015 smb_sdrc_t 766139Sjb150015 smb_pre_rename(smb_request_t *sr) 776139Sjb150015 { 787961SNatalie.Li@Sun.COM smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 797961SNatalie.Li@Sun.COM smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 806139Sjb150015 int rc; 816139Sjb150015 829343SAfshin.Ardakani@Sun.COM if ((rc = smbsr_decode_vwv(sr, "w", &src_fqi->fq_sattr)) == 0) { 839343SAfshin.Ardakani@Sun.COM rc = smbsr_decode_data(sr, "%SS", sr, &src_fqi->fq_path.pn_path, 849343SAfshin.Ardakani@Sun.COM &dst_fqi->fq_path.pn_path); 856139Sjb150015 869343SAfshin.Ardakani@Sun.COM dst_fqi->fq_sattr = 0; 876139Sjb150015 } 886139Sjb150015 896139Sjb150015 DTRACE_SMB_2(op__Rename__start, smb_request_t *, sr, 906139Sjb150015 struct dirop *, &sr->arg.dirop); 916139Sjb150015 926139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 936139Sjb150015 } 946139Sjb150015 956139Sjb150015 void 966139Sjb150015 smb_post_rename(smb_request_t *sr) 976139Sjb150015 { 986139Sjb150015 DTRACE_SMB_1(op__Rename__done, smb_request_t *, sr); 996139Sjb150015 } 1006139Sjb150015 1016139Sjb150015 smb_sdrc_t 1026139Sjb150015 smb_com_rename(smb_request_t *sr) 1035331Samw { 104*11963SAfshin.Ardakani@Sun.COM int rc; 105*11963SAfshin.Ardakani@Sun.COM smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 106*11963SAfshin.Ardakani@Sun.COM smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 107*11963SAfshin.Ardakani@Sun.COM smb_pathname_t *src_pn = &src_fqi->fq_path; 108*11963SAfshin.Ardakani@Sun.COM smb_pathname_t *dst_pn = &dst_fqi->fq_path; 1095331Samw 1105331Samw if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 1115772Sas200622 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 1125331Samw ERRDOS, ERROR_ACCESS_DENIED); 1136139Sjb150015 return (SDRC_ERROR); 1145331Samw } 1155331Samw 116*11963SAfshin.Ardakani@Sun.COM smb_pathname_init(sr, src_pn, src_pn->pn_path); 117*11963SAfshin.Ardakani@Sun.COM smb_pathname_init(sr, dst_pn, dst_pn->pn_path); 118*11963SAfshin.Ardakani@Sun.COM if (!smb_pathname_validate(sr, src_pn) || 119*11963SAfshin.Ardakani@Sun.COM !smb_pathname_validate(sr, dst_pn)) { 120*11963SAfshin.Ardakani@Sun.COM return (SDRC_ERROR); 121*11963SAfshin.Ardakani@Sun.COM } 122*11963SAfshin.Ardakani@Sun.COM 12310966SJordan.Brown@Sun.COM rc = smb_common_rename(sr, src_fqi, dst_fqi); 1245331Samw 1255331Samw if (rc != 0) { 1269914Samw@Sun.COM smb_rename_set_error(sr, rc); 1276139Sjb150015 return (SDRC_ERROR); 1285331Samw } 1295331Samw 1306030Sjb150015 rc = smbsr_encode_empty_result(sr); 1316139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 1325331Samw } 1335331Samw 1345331Samw /* 1359914Samw@Sun.COM * smb_com_nt_rename 1369914Samw@Sun.COM * 1379914Samw@Sun.COM * Rename a file. Files OldFileName must exist and NewFileName must not. 1389914Samw@Sun.COM * Both pathnames must be relative to the Tid specified in the request. 1399914Samw@Sun.COM * Open files may be renamed. 1409914Samw@Sun.COM * 1419914Samw@Sun.COM * SearchAttributes indicates the attributes that the target file(s) must 1429914Samw@Sun.COM * have. If SearchAttributes is zero then only normal files are renamed. 1439914Samw@Sun.COM * If the system file or hidden attributes are specified then the rename 1449914Samw@Sun.COM * is inclusive - both the specified type(s) of files and normal files are 14510966SJordan.Brown@Sun.COM * renamed. 1469914Samw@Sun.COM */ 1479914Samw@Sun.COM smb_sdrc_t 1489914Samw@Sun.COM smb_pre_nt_rename(smb_request_t *sr) 1499914Samw@Sun.COM { 1509914Samw@Sun.COM smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 1519914Samw@Sun.COM smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 1529914Samw@Sun.COM uint32_t clusters; 1539914Samw@Sun.COM int rc; 1549914Samw@Sun.COM 1559914Samw@Sun.COM rc = smbsr_decode_vwv(sr, "wwl", &src_fqi->fq_sattr, 1569914Samw@Sun.COM &sr->arg.dirop.info_level, &clusters); 1579914Samw@Sun.COM if (rc == 0) { 1589914Samw@Sun.COM rc = smbsr_decode_data(sr, "%SS", sr, 1599914Samw@Sun.COM &src_fqi->fq_path.pn_path, &dst_fqi->fq_path.pn_path); 1609914Samw@Sun.COM 1619914Samw@Sun.COM dst_fqi->fq_sattr = 0; 1629914Samw@Sun.COM } 1639914Samw@Sun.COM 1649914Samw@Sun.COM DTRACE_SMB_2(op__NtRename__start, smb_request_t *, sr, 1659914Samw@Sun.COM struct dirop *, &sr->arg.dirop); 1669914Samw@Sun.COM 1679914Samw@Sun.COM return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 1689914Samw@Sun.COM } 1699914Samw@Sun.COM 1709914Samw@Sun.COM void 1719914Samw@Sun.COM smb_post_nt_rename(smb_request_t *sr) 1729914Samw@Sun.COM { 1739914Samw@Sun.COM DTRACE_SMB_1(op__NtRename__done, smb_request_t *, sr); 1749914Samw@Sun.COM } 1759914Samw@Sun.COM 1769914Samw@Sun.COM smb_sdrc_t 1779914Samw@Sun.COM smb_com_nt_rename(smb_request_t *sr) 1789914Samw@Sun.COM { 179*11963SAfshin.Ardakani@Sun.COM int rc; 180*11963SAfshin.Ardakani@Sun.COM smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 181*11963SAfshin.Ardakani@Sun.COM smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 182*11963SAfshin.Ardakani@Sun.COM smb_pathname_t *src_pn = &src_fqi->fq_path; 183*11963SAfshin.Ardakani@Sun.COM smb_pathname_t *dst_pn = &dst_fqi->fq_path; 1849914Samw@Sun.COM 1859914Samw@Sun.COM if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 1869914Samw@Sun.COM smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 1879914Samw@Sun.COM ERRDOS, ERROR_ACCESS_DENIED); 1889914Samw@Sun.COM return (SDRC_ERROR); 1899914Samw@Sun.COM } 1909914Samw@Sun.COM 191*11963SAfshin.Ardakani@Sun.COM smb_pathname_init(sr, src_pn, src_pn->pn_path); 192*11963SAfshin.Ardakani@Sun.COM smb_pathname_init(sr, dst_pn, dst_pn->pn_path); 193*11963SAfshin.Ardakani@Sun.COM if (!smb_pathname_validate(sr, src_pn) || 194*11963SAfshin.Ardakani@Sun.COM !smb_pathname_validate(sr, dst_pn)) { 195*11963SAfshin.Ardakani@Sun.COM return (SDRC_ERROR); 196*11963SAfshin.Ardakani@Sun.COM } 197*11963SAfshin.Ardakani@Sun.COM 198*11963SAfshin.Ardakani@Sun.COM if (smb_contains_wildcards(src_pn->pn_path)) { 1999914Samw@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD, 2009914Samw@Sun.COM ERRDOS, ERROR_BAD_PATHNAME); 2019914Samw@Sun.COM return (SDRC_ERROR); 2029914Samw@Sun.COM } 2039914Samw@Sun.COM 2049914Samw@Sun.COM switch (sr->arg.dirop.info_level) { 2059914Samw@Sun.COM case SMB_NT_RENAME_SET_LINK_INFO: 2069914Samw@Sun.COM rc = smb_make_link(sr, src_fqi, dst_fqi); 2079914Samw@Sun.COM break; 2089914Samw@Sun.COM case SMB_NT_RENAME_RENAME_FILE: 2099914Samw@Sun.COM case SMB_NT_RENAME_MOVE_FILE: 21010966SJordan.Brown@Sun.COM rc = smb_common_rename(sr, src_fqi, dst_fqi); 2119914Samw@Sun.COM break; 2129914Samw@Sun.COM case SMB_NT_RENAME_MOVE_CLUSTER_INFO: 2139914Samw@Sun.COM rc = EINVAL; 2149914Samw@Sun.COM break; 2159914Samw@Sun.COM default: 2169914Samw@Sun.COM rc = EACCES; 2179914Samw@Sun.COM break; 2189914Samw@Sun.COM } 2199914Samw@Sun.COM 2209914Samw@Sun.COM if (rc != 0) { 2219914Samw@Sun.COM smb_rename_set_error(sr, rc); 2229914Samw@Sun.COM return (SDRC_ERROR); 2239914Samw@Sun.COM } 2249914Samw@Sun.COM 2259914Samw@Sun.COM rc = smbsr_encode_empty_result(sr); 2269914Samw@Sun.COM return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 2279914Samw@Sun.COM } 2289914Samw@Sun.COM 2299914Samw@Sun.COM /* 23010966SJordan.Brown@Sun.COM * smb_nt_transact_rename 23110966SJordan.Brown@Sun.COM * 23210966SJordan.Brown@Sun.COM * Windows servers return SUCCESS without renaming file. 23310966SJordan.Brown@Sun.COM * The only check required is to check that the handle (fid) is valid. 23410966SJordan.Brown@Sun.COM */ 23510966SJordan.Brown@Sun.COM smb_sdrc_t 23610966SJordan.Brown@Sun.COM smb_nt_transact_rename(smb_request_t *sr, smb_xa_t *xa) 23710966SJordan.Brown@Sun.COM { 23810966SJordan.Brown@Sun.COM if (smb_mbc_decodef(&xa->req_param_mb, "w", &sr->smb_fid) != 0) 23910966SJordan.Brown@Sun.COM return (SDRC_ERROR); 24010966SJordan.Brown@Sun.COM 24110966SJordan.Brown@Sun.COM smbsr_lookup_file(sr); 24210966SJordan.Brown@Sun.COM if (sr->fid_ofile == NULL) { 24310966SJordan.Brown@Sun.COM smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 24410966SJordan.Brown@Sun.COM return (SDRC_ERROR); 24510966SJordan.Brown@Sun.COM } 24610966SJordan.Brown@Sun.COM smbsr_release_file(sr); 24710966SJordan.Brown@Sun.COM 24810966SJordan.Brown@Sun.COM return (SDRC_SUCCESS); 24910966SJordan.Brown@Sun.COM } 25010966SJordan.Brown@Sun.COM 25110966SJordan.Brown@Sun.COM /* 25210966SJordan.Brown@Sun.COM * smb_trans2_rename 25310966SJordan.Brown@Sun.COM * 25410966SJordan.Brown@Sun.COM * Implements SMB_FILE_RENAME_INFORMATION level of Trans2_Set_FileInfo 25510966SJordan.Brown@Sun.COM * and Trans2_Set_PathInfo. 25610966SJordan.Brown@Sun.COM * If the new filename (dst_fqi) already exists it may be overwritten 25710966SJordan.Brown@Sun.COM * if flags == 1. 25810966SJordan.Brown@Sun.COM */ 25910966SJordan.Brown@Sun.COM int 26010966SJordan.Brown@Sun.COM smb_trans2_rename(smb_request_t *sr, smb_node_t *node, char *fname, int flags) 26110966SJordan.Brown@Sun.COM { 262*11963SAfshin.Ardakani@Sun.COM int rc = 0; 263*11963SAfshin.Ardakani@Sun.COM smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 264*11963SAfshin.Ardakani@Sun.COM smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 265*11963SAfshin.Ardakani@Sun.COM smb_pathname_t *dst_pn = &dst_fqi->fq_path; 266*11963SAfshin.Ardakani@Sun.COM char *path; 267*11963SAfshin.Ardakani@Sun.COM int len; 26810966SJordan.Brown@Sun.COM 26910966SJordan.Brown@Sun.COM sr->arg.dirop.flags = flags ? SMB_RENAME_FLAG_OVERWRITE : 0; 27010966SJordan.Brown@Sun.COM sr->arg.dirop.info_level = SMB_NT_RENAME_RENAME_FILE; 27110966SJordan.Brown@Sun.COM 27210966SJordan.Brown@Sun.COM src_fqi->fq_sattr = SMB_SEARCH_ATTRIBUTES; 27310966SJordan.Brown@Sun.COM src_fqi->fq_fnode = node; 27410966SJordan.Brown@Sun.COM src_fqi->fq_dnode = node->n_dnode; 27510966SJordan.Brown@Sun.COM 276*11963SAfshin.Ardakani@Sun.COM /* costruct and validate the dst pathname */ 277*11963SAfshin.Ardakani@Sun.COM path = smb_srm_zalloc(sr, MAXPATHLEN); 278*11963SAfshin.Ardakani@Sun.COM if (src_fqi->fq_path.pn_pname) { 279*11963SAfshin.Ardakani@Sun.COM (void) snprintf(path, MAXPATHLEN, "%s\\%s", 280*11963SAfshin.Ardakani@Sun.COM src_fqi->fq_path.pn_pname, fname); 281*11963SAfshin.Ardakani@Sun.COM } else { 282*11963SAfshin.Ardakani@Sun.COM rc = smb_node_getshrpath(node->n_dnode, sr->tid_tree, 283*11963SAfshin.Ardakani@Sun.COM path, MAXPATHLEN); 284*11963SAfshin.Ardakani@Sun.COM if (rc != 0) { 285*11963SAfshin.Ardakani@Sun.COM smb_rename_set_error(sr, rc); 286*11963SAfshin.Ardakani@Sun.COM return (-1); 287*11963SAfshin.Ardakani@Sun.COM } 288*11963SAfshin.Ardakani@Sun.COM len = strlen(path); 289*11963SAfshin.Ardakani@Sun.COM (void) snprintf(path + len, MAXPATHLEN - len, "\\%s", fname); 290*11963SAfshin.Ardakani@Sun.COM } 291*11963SAfshin.Ardakani@Sun.COM 292*11963SAfshin.Ardakani@Sun.COM smb_pathname_init(sr, dst_pn, path); 293*11963SAfshin.Ardakani@Sun.COM if (!smb_pathname_validate(sr, dst_pn)) 294*11963SAfshin.Ardakani@Sun.COM return (-1); 295*11963SAfshin.Ardakani@Sun.COM 29610966SJordan.Brown@Sun.COM dst_fqi->fq_dnode = node->n_dnode; 297*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(dst_fqi->fq_last_comp, dst_pn->pn_fname, MAXNAMELEN); 29810966SJordan.Brown@Sun.COM 29910966SJordan.Brown@Sun.COM rc = smb_common_rename(sr, src_fqi, dst_fqi); 30010966SJordan.Brown@Sun.COM if (rc != 0) { 30110966SJordan.Brown@Sun.COM smb_rename_set_error(sr, rc); 30210966SJordan.Brown@Sun.COM return (-1); 30310966SJordan.Brown@Sun.COM } 30410966SJordan.Brown@Sun.COM 30510966SJordan.Brown@Sun.COM return (0); 30610966SJordan.Brown@Sun.COM } 30710966SJordan.Brown@Sun.COM 30810966SJordan.Brown@Sun.COM /* 30910966SJordan.Brown@Sun.COM * smb_common_rename 31010966SJordan.Brown@Sun.COM * 31110966SJordan.Brown@Sun.COM * Common code for renaming a file. 31210966SJordan.Brown@Sun.COM * 31310966SJordan.Brown@Sun.COM * If the source and destination are identical, we go through all 31410966SJordan.Brown@Sun.COM * the checks but we don't actually do the rename. If the source 31510966SJordan.Brown@Sun.COM * and destination files differ only in case, we do a case-sensitive 31610966SJordan.Brown@Sun.COM * rename. Otherwise, we do a full case-insensitive rename. 31710966SJordan.Brown@Sun.COM * 31810966SJordan.Brown@Sun.COM * Returns errno values. 31910966SJordan.Brown@Sun.COM */ 32010966SJordan.Brown@Sun.COM static int 32110966SJordan.Brown@Sun.COM smb_common_rename(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi) 32210966SJordan.Brown@Sun.COM { 32310966SJordan.Brown@Sun.COM smb_node_t *src_fnode, *src_dnode, *dst_fnode, *dst_dnode; 32410966SJordan.Brown@Sun.COM smb_node_t *tnode; 32510966SJordan.Brown@Sun.COM int rc, count; 32610966SJordan.Brown@Sun.COM DWORD status; 32710966SJordan.Brown@Sun.COM char *new_name, *path; 32810966SJordan.Brown@Sun.COM 32910966SJordan.Brown@Sun.COM path = dst_fqi->fq_path.pn_path; 33010966SJordan.Brown@Sun.COM 33110966SJordan.Brown@Sun.COM /* Check if attempting to rename a stream - not yet supported */ 33210966SJordan.Brown@Sun.COM rc = smb_rename_check_stream(src_fqi, dst_fqi); 33310966SJordan.Brown@Sun.COM if (rc != 0) 33410966SJordan.Brown@Sun.COM return (rc); 33510966SJordan.Brown@Sun.COM 33610966SJordan.Brown@Sun.COM /* The source node may already have been provided */ 33710966SJordan.Brown@Sun.COM if (src_fqi->fq_fnode) { 33810966SJordan.Brown@Sun.COM smb_node_start_crit(src_fqi->fq_fnode, RW_READER); 33910966SJordan.Brown@Sun.COM smb_node_ref(src_fqi->fq_fnode); 34010966SJordan.Brown@Sun.COM smb_node_ref(src_fqi->fq_dnode); 34110966SJordan.Brown@Sun.COM } else { 34210966SJordan.Brown@Sun.COM /* lookup and validate src node */ 34310966SJordan.Brown@Sun.COM rc = smb_rename_lookup_src(sr); 34410966SJordan.Brown@Sun.COM if (rc != 0) 34510966SJordan.Brown@Sun.COM return (rc); 34610966SJordan.Brown@Sun.COM } 34710966SJordan.Brown@Sun.COM 34810966SJordan.Brown@Sun.COM src_fnode = src_fqi->fq_fnode; 34910966SJordan.Brown@Sun.COM src_dnode = src_fqi->fq_dnode; 35010966SJordan.Brown@Sun.COM 35110966SJordan.Brown@Sun.COM /* Find destination dnode and last_comp */ 35210966SJordan.Brown@Sun.COM if (dst_fqi->fq_dnode) { 35310966SJordan.Brown@Sun.COM smb_node_ref(dst_fqi->fq_dnode); 35410966SJordan.Brown@Sun.COM } else { 35510966SJordan.Brown@Sun.COM tnode = sr->tid_tree->t_snode; 35610966SJordan.Brown@Sun.COM rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, 35710966SJordan.Brown@Sun.COM &dst_fqi->fq_dnode, dst_fqi->fq_last_comp); 35810966SJordan.Brown@Sun.COM if (rc != 0) { 35910966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 36010966SJordan.Brown@Sun.COM return (rc); 36110966SJordan.Brown@Sun.COM } 36210966SJordan.Brown@Sun.COM } 36310966SJordan.Brown@Sun.COM 36410966SJordan.Brown@Sun.COM dst_dnode = dst_fqi->fq_dnode; 36510966SJordan.Brown@Sun.COM new_name = dst_fqi->fq_last_comp; 36610966SJordan.Brown@Sun.COM 36710966SJordan.Brown@Sun.COM /* If exact name match in same directory, we're done */ 36810966SJordan.Brown@Sun.COM if ((src_dnode == dst_dnode) && 36910966SJordan.Brown@Sun.COM (strcmp(src_fnode->od_name, new_name) == 0)) { 37010966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 37110966SJordan.Brown@Sun.COM smb_node_release(dst_dnode); 37210966SJordan.Brown@Sun.COM return (0); 37310966SJordan.Brown@Sun.COM } 37410966SJordan.Brown@Sun.COM 37510966SJordan.Brown@Sun.COM /* Lookup destination node */ 37610966SJordan.Brown@Sun.COM rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode, 37710966SJordan.Brown@Sun.COM dst_dnode, new_name, &dst_fqi->fq_fnode); 37810966SJordan.Brown@Sun.COM 37911337SWilliam.Krier@Sun.COM /* If the destination node doesn't already exist, validate new_name. */ 38011337SWilliam.Krier@Sun.COM if (rc == ENOENT) { 38111337SWilliam.Krier@Sun.COM if (smb_is_invalid_filename(new_name)) { 38211337SWilliam.Krier@Sun.COM smb_rename_release_src(sr); 38311337SWilliam.Krier@Sun.COM smb_node_release(dst_dnode); 38411337SWilliam.Krier@Sun.COM return (EILSEQ); /* NT_STATUS_OBJECT_NAME_INVALID */ 38511337SWilliam.Krier@Sun.COM } 38611337SWilliam.Krier@Sun.COM } 38711337SWilliam.Krier@Sun.COM 38810966SJordan.Brown@Sun.COM /* 38910966SJordan.Brown@Sun.COM * Handle case where changing case of the same directory entry. 39010966SJordan.Brown@Sun.COM * 39110966SJordan.Brown@Sun.COM * If we found the dst node in the same directory as the src node, 39210966SJordan.Brown@Sun.COM * and their names differ only in case: 39310966SJordan.Brown@Sun.COM * 39410966SJordan.Brown@Sun.COM * If the tree is case sensitive (or mixed): 39510966SJordan.Brown@Sun.COM * Do case sensitive lookup to see if exact match exists. 39610966SJordan.Brown@Sun.COM * If the exact match is the same node as src_node we're done. 39710966SJordan.Brown@Sun.COM * 39810966SJordan.Brown@Sun.COM * If the tree is case insensitive: 39910966SJordan.Brown@Sun.COM * There is currently no way to tell if the case is different 40010966SJordan.Brown@Sun.COM * or not, so do the rename (unless the specified new name was 40110966SJordan.Brown@Sun.COM * mangled). 40210966SJordan.Brown@Sun.COM */ 40310966SJordan.Brown@Sun.COM if ((rc == 0) && 40410966SJordan.Brown@Sun.COM (src_dnode == dst_dnode) && 40510966SJordan.Brown@Sun.COM (smb_strcasecmp(src_fnode->od_name, 40610966SJordan.Brown@Sun.COM dst_fqi->fq_fnode->od_name, 0) == 0)) { 40710966SJordan.Brown@Sun.COM smb_node_release(dst_fqi->fq_fnode); 40810966SJordan.Brown@Sun.COM dst_fqi->fq_fnode = NULL; 40910966SJordan.Brown@Sun.COM 41010966SJordan.Brown@Sun.COM if (smb_tree_has_feature(sr->tid_tree, 41110966SJordan.Brown@Sun.COM SMB_TREE_NO_CASESENSITIVE)) { 41210966SJordan.Brown@Sun.COM if (smb_strcasecmp(src_fnode->od_name, 41310966SJordan.Brown@Sun.COM dst_fqi->fq_last_comp, 0) != 0) { 41410966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 41510966SJordan.Brown@Sun.COM smb_node_release(dst_dnode); 41610966SJordan.Brown@Sun.COM return (0); 41710966SJordan.Brown@Sun.COM } 41810966SJordan.Brown@Sun.COM } else { 41910966SJordan.Brown@Sun.COM rc = smb_fsop_lookup(sr, sr->user_cr, 42010966SJordan.Brown@Sun.COM SMB_CASE_SENSITIVE, tnode, dst_dnode, new_name, 42110966SJordan.Brown@Sun.COM &dst_fqi->fq_fnode); 42210966SJordan.Brown@Sun.COM 42310966SJordan.Brown@Sun.COM if ((rc == 0) && 42410966SJordan.Brown@Sun.COM (dst_fqi->fq_fnode == src_fnode)) { 42510966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 42610966SJordan.Brown@Sun.COM smb_node_release(dst_fqi->fq_fnode); 42710966SJordan.Brown@Sun.COM smb_node_release(dst_dnode); 42810966SJordan.Brown@Sun.COM return (0); 42910966SJordan.Brown@Sun.COM } 43010966SJordan.Brown@Sun.COM } 43110966SJordan.Brown@Sun.COM } 43210966SJordan.Brown@Sun.COM 43310966SJordan.Brown@Sun.COM if ((rc != 0) && (rc != ENOENT)) { 43410966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 43510966SJordan.Brown@Sun.COM smb_node_release(dst_fqi->fq_dnode); 43610966SJordan.Brown@Sun.COM return (rc); 43710966SJordan.Brown@Sun.COM } 43810966SJordan.Brown@Sun.COM 43910966SJordan.Brown@Sun.COM if (dst_fqi->fq_fnode) { 44010966SJordan.Brown@Sun.COM dst_fnode = dst_fqi->fq_fnode; 44110966SJordan.Brown@Sun.COM 44210966SJordan.Brown@Sun.COM if (!(sr->arg.dirop.flags && SMB_RENAME_FLAG_OVERWRITE)) { 44310966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 44410966SJordan.Brown@Sun.COM smb_node_release(dst_fnode); 44510966SJordan.Brown@Sun.COM smb_node_release(dst_dnode); 44610966SJordan.Brown@Sun.COM return (EEXIST); 44710966SJordan.Brown@Sun.COM } 44810966SJordan.Brown@Sun.COM 44910966SJordan.Brown@Sun.COM (void) smb_oplock_break(dst_fnode, sr->session, B_FALSE); 45010966SJordan.Brown@Sun.COM 45110966SJordan.Brown@Sun.COM for (count = 0; count <= 3; count++) { 45210966SJordan.Brown@Sun.COM if (count) { 45310966SJordan.Brown@Sun.COM smb_node_end_crit(dst_fnode); 45410966SJordan.Brown@Sun.COM delay(MSEC_TO_TICK(400)); 45510966SJordan.Brown@Sun.COM } 45610966SJordan.Brown@Sun.COM 45710966SJordan.Brown@Sun.COM smb_node_start_crit(dst_fnode, RW_READER); 45810966SJordan.Brown@Sun.COM status = smb_node_delete_check(dst_fnode); 45910966SJordan.Brown@Sun.COM 46010966SJordan.Brown@Sun.COM if (status != NT_STATUS_SHARING_VIOLATION) 46110966SJordan.Brown@Sun.COM break; 46210966SJordan.Brown@Sun.COM } 46310966SJordan.Brown@Sun.COM 46410966SJordan.Brown@Sun.COM if (status != NT_STATUS_SHARING_VIOLATION) 46510966SJordan.Brown@Sun.COM status = smb_range_check(sr, dst_fnode, 46610966SJordan.Brown@Sun.COM 0, UINT64_MAX, B_TRUE); 46710966SJordan.Brown@Sun.COM 46810966SJordan.Brown@Sun.COM if (status != NT_STATUS_SUCCESS) { 46910966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 47010966SJordan.Brown@Sun.COM smb_node_end_crit(dst_fnode); 47110966SJordan.Brown@Sun.COM smb_node_release(dst_fnode); 47210966SJordan.Brown@Sun.COM smb_node_release(dst_dnode); 47310966SJordan.Brown@Sun.COM return (EACCES); 47410966SJordan.Brown@Sun.COM } 47510966SJordan.Brown@Sun.COM 47611337SWilliam.Krier@Sun.COM new_name = dst_fnode->od_name; 47710966SJordan.Brown@Sun.COM } 47810966SJordan.Brown@Sun.COM 47910966SJordan.Brown@Sun.COM rc = smb_fsop_rename(sr, sr->user_cr, 48010966SJordan.Brown@Sun.COM src_dnode, src_fnode->od_name, 48110966SJordan.Brown@Sun.COM dst_dnode, new_name); 48210966SJordan.Brown@Sun.COM 48310966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 48410966SJordan.Brown@Sun.COM 48510966SJordan.Brown@Sun.COM if (rc == 0) 48610966SJordan.Brown@Sun.COM smb_node_notify_change(dst_dnode); 48710966SJordan.Brown@Sun.COM 48810966SJordan.Brown@Sun.COM if (dst_fqi->fq_fnode) { 48910966SJordan.Brown@Sun.COM smb_node_end_crit(dst_fnode); 49010966SJordan.Brown@Sun.COM smb_node_release(dst_fnode); 49110966SJordan.Brown@Sun.COM } 49210966SJordan.Brown@Sun.COM smb_node_release(dst_dnode); 49310966SJordan.Brown@Sun.COM 49410966SJordan.Brown@Sun.COM return (rc); 49510966SJordan.Brown@Sun.COM } 49610966SJordan.Brown@Sun.COM 49710966SJordan.Brown@Sun.COM /* 49810966SJordan.Brown@Sun.COM * smb_rename_check_stream 49910966SJordan.Brown@Sun.COM * 50010966SJordan.Brown@Sun.COM * For a stream rename the dst path must begin with ':', or "\\:". 50110966SJordan.Brown@Sun.COM * We don't yet support stream rename, Return EACCES. 50210966SJordan.Brown@Sun.COM * 50310966SJordan.Brown@Sun.COM * If not a stream rename, in accordance with the above rule, 50410966SJordan.Brown@Sun.COM * it is not valid for either the src or dst to be a stream. 50510966SJordan.Brown@Sun.COM * Return EINVAL. 50610966SJordan.Brown@Sun.COM */ 50710966SJordan.Brown@Sun.COM static int 50810966SJordan.Brown@Sun.COM smb_rename_check_stream(smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi) 50910966SJordan.Brown@Sun.COM { 51010966SJordan.Brown@Sun.COM smb_node_t *src_fnode = src_fqi->fq_fnode; 51110966SJordan.Brown@Sun.COM char *src_path = src_fqi->fq_path.pn_path; 51210966SJordan.Brown@Sun.COM char *dst_path = dst_fqi->fq_path.pn_path; 51310966SJordan.Brown@Sun.COM 51410966SJordan.Brown@Sun.COM /* We do not yet support named stream rename - ACCESS DENIED */ 51510966SJordan.Brown@Sun.COM if ((dst_path[0] == ':') || 51610966SJordan.Brown@Sun.COM ((dst_path[0] == '\\') && (dst_path[1] == ':'))) { 51710966SJordan.Brown@Sun.COM return (EACCES); 51810966SJordan.Brown@Sun.COM } 51910966SJordan.Brown@Sun.COM 52010966SJordan.Brown@Sun.COM /* 52110966SJordan.Brown@Sun.COM * If not stream rename (above) neither src or dst can be 52210966SJordan.Brown@Sun.COM * a named stream. 52310966SJordan.Brown@Sun.COM */ 52410966SJordan.Brown@Sun.COM 52510966SJordan.Brown@Sun.COM if (smb_is_stream_name(dst_path)) 52610966SJordan.Brown@Sun.COM return (EINVAL); 52710966SJordan.Brown@Sun.COM 52810966SJordan.Brown@Sun.COM if (src_fqi->fq_fnode) { 52910966SJordan.Brown@Sun.COM if (SMB_IS_STREAM(src_fnode)) 53010966SJordan.Brown@Sun.COM return (EINVAL); 53110966SJordan.Brown@Sun.COM } else { 53210966SJordan.Brown@Sun.COM if (smb_is_stream_name(src_path)) 53310966SJordan.Brown@Sun.COM return (EINVAL); 53410966SJordan.Brown@Sun.COM } 53510966SJordan.Brown@Sun.COM 53610966SJordan.Brown@Sun.COM return (0); 53710966SJordan.Brown@Sun.COM } 53810966SJordan.Brown@Sun.COM 53910966SJordan.Brown@Sun.COM 54010966SJordan.Brown@Sun.COM /* 5419914Samw@Sun.COM * smb_make_link 5429914Samw@Sun.COM * 54310966SJordan.Brown@Sun.COM * Creating a hard link (adding an additional name) for a file. 5449914Samw@Sun.COM * 5459914Samw@Sun.COM * If the source and destination are identical, we go through all 5469914Samw@Sun.COM * the checks but we don't create a link. 5479914Samw@Sun.COM * 54810966SJordan.Brown@Sun.COM * If the file is a symlink we create the hardlink on the target 54910966SJordan.Brown@Sun.COM * of the symlink (i.e. use SMB_FOLLOW_LINKS when looking up src). 55010966SJordan.Brown@Sun.COM * If the target of the symlink does not exist we fail with ENOENT. 55110966SJordan.Brown@Sun.COM * 5529914Samw@Sun.COM * Returns errno values. 5539914Samw@Sun.COM */ 5549914Samw@Sun.COM static int 5559914Samw@Sun.COM smb_make_link(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi) 5569914Samw@Sun.COM { 55710966SJordan.Brown@Sun.COM smb_node_t *tnode; 55810966SJordan.Brown@Sun.COM char *path; 55910966SJordan.Brown@Sun.COM int rc; 56010966SJordan.Brown@Sun.COM 56110966SJordan.Brown@Sun.COM /* Cannnot create link on named stream */ 56210966SJordan.Brown@Sun.COM if (smb_is_stream_name(src_fqi->fq_path.pn_path) || 56310966SJordan.Brown@Sun.COM smb_is_stream_name(dst_fqi->fq_path.pn_path)) { 56410966SJordan.Brown@Sun.COM return (EINVAL); 56510966SJordan.Brown@Sun.COM } 56610966SJordan.Brown@Sun.COM 56710966SJordan.Brown@Sun.COM /* lookup and validate src node */ 56810966SJordan.Brown@Sun.COM rc = smb_rename_lookup_src(sr); 56910966SJordan.Brown@Sun.COM if (rc != 0) 57010966SJordan.Brown@Sun.COM return (rc); 57110966SJordan.Brown@Sun.COM 57210966SJordan.Brown@Sun.COM /* if src and dest paths match we're done */ 57310966SJordan.Brown@Sun.COM if (smb_strcasecmp(src_fqi->fq_path.pn_path, 57410966SJordan.Brown@Sun.COM dst_fqi->fq_path.pn_path, 0) == 0) { 57510966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 57610966SJordan.Brown@Sun.COM return (0); 57710966SJordan.Brown@Sun.COM } 57810966SJordan.Brown@Sun.COM 57910966SJordan.Brown@Sun.COM /* find the destination dnode and last_comp */ 58010966SJordan.Brown@Sun.COM tnode = sr->tid_tree->t_snode; 58110966SJordan.Brown@Sun.COM path = dst_fqi->fq_path.pn_path; 58210966SJordan.Brown@Sun.COM rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, 58310966SJordan.Brown@Sun.COM &dst_fqi->fq_dnode, dst_fqi->fq_last_comp); 58410966SJordan.Brown@Sun.COM if (rc != 0) { 58510966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 58610966SJordan.Brown@Sun.COM return (rc); 58710966SJordan.Brown@Sun.COM } 58810966SJordan.Brown@Sun.COM 58910966SJordan.Brown@Sun.COM /* If name match in same directory, we're done */ 59010966SJordan.Brown@Sun.COM if ((src_fqi->fq_dnode == dst_fqi->fq_dnode) && 59110966SJordan.Brown@Sun.COM (smb_strcasecmp(src_fqi->fq_fnode->od_name, 59210966SJordan.Brown@Sun.COM dst_fqi->fq_last_comp, 0) == 0)) { 59310966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 59410966SJordan.Brown@Sun.COM smb_node_release(dst_fqi->fq_dnode); 59510966SJordan.Brown@Sun.COM return (0); 59610966SJordan.Brown@Sun.COM } 59710966SJordan.Brown@Sun.COM 59811337SWilliam.Krier@Sun.COM if (smb_is_invalid_filename(dst_fqi->fq_last_comp)) { 59911337SWilliam.Krier@Sun.COM smb_rename_release_src(sr); 60011337SWilliam.Krier@Sun.COM smb_node_release(dst_fqi->fq_dnode); 60111337SWilliam.Krier@Sun.COM return (EILSEQ); /* NT_STATUS_INVALID_OBJECT_NAME */ 60211337SWilliam.Krier@Sun.COM } 60311337SWilliam.Krier@Sun.COM 60410966SJordan.Brown@Sun.COM /* Lookup the destination node. It MUST NOT exist. */ 60510966SJordan.Brown@Sun.COM rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode, 60610966SJordan.Brown@Sun.COM dst_fqi->fq_dnode, dst_fqi->fq_last_comp, &dst_fqi->fq_fnode); 60710966SJordan.Brown@Sun.COM if (rc == 0) { 60810966SJordan.Brown@Sun.COM smb_node_release(dst_fqi->fq_fnode); 60910966SJordan.Brown@Sun.COM rc = EEXIST; 61010966SJordan.Brown@Sun.COM } 61110966SJordan.Brown@Sun.COM if (rc != ENOENT) { 61210966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 61310966SJordan.Brown@Sun.COM smb_node_release(dst_fqi->fq_dnode); 61410966SJordan.Brown@Sun.COM return (rc); 61510966SJordan.Brown@Sun.COM } 61610966SJordan.Brown@Sun.COM 61710966SJordan.Brown@Sun.COM rc = smb_fsop_link(sr, sr->user_cr, src_fqi->fq_fnode, 61810966SJordan.Brown@Sun.COM dst_fqi->fq_dnode, dst_fqi->fq_last_comp); 61910966SJordan.Brown@Sun.COM 62010966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 62110966SJordan.Brown@Sun.COM if (rc == 0) 62210966SJordan.Brown@Sun.COM smb_node_notify_change(dst_fqi->fq_dnode); 62310966SJordan.Brown@Sun.COM smb_node_release(dst_fqi->fq_dnode); 62410966SJordan.Brown@Sun.COM return (rc); 62510966SJordan.Brown@Sun.COM } 62610966SJordan.Brown@Sun.COM 62710966SJordan.Brown@Sun.COM /* 62810966SJordan.Brown@Sun.COM * smb_rename_lookup_src 62910966SJordan.Brown@Sun.COM * 63010966SJordan.Brown@Sun.COM * Lookup the src node, checking for sharing violations and 63110966SJordan.Brown@Sun.COM * breaking any existing oplock. 63210966SJordan.Brown@Sun.COM * Populate sr->arg.dirop.fqi 63310966SJordan.Brown@Sun.COM * 63410966SJordan.Brown@Sun.COM * Upon success, the dnode and fnode will have holds and the 63510966SJordan.Brown@Sun.COM * fnode will be in a critical section. These should be 63610966SJordan.Brown@Sun.COM * released using smb_rename_release_src(). 63710966SJordan.Brown@Sun.COM * 63810966SJordan.Brown@Sun.COM * Returns errno values. 63910966SJordan.Brown@Sun.COM */ 64010966SJordan.Brown@Sun.COM static int 64110966SJordan.Brown@Sun.COM smb_rename_lookup_src(smb_request_t *sr) 64210966SJordan.Brown@Sun.COM { 64310966SJordan.Brown@Sun.COM smb_node_t *src_node, *tnode; 6449914Samw@Sun.COM DWORD status; 6459914Samw@Sun.COM int rc; 6469914Samw@Sun.COM int count; 64710504SKeyur.Desai@Sun.COM char *path; 6489914Samw@Sun.COM 64910966SJordan.Brown@Sun.COM struct dirop *dirop = &sr->arg.dirop; 65010966SJordan.Brown@Sun.COM smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 65110504SKeyur.Desai@Sun.COM 65210966SJordan.Brown@Sun.COM if (smb_is_stream_name(src_fqi->fq_path.pn_path)) 65310966SJordan.Brown@Sun.COM return (EINVAL); 65410966SJordan.Brown@Sun.COM 65510966SJordan.Brown@Sun.COM /* Lookup the source node */ 65610966SJordan.Brown@Sun.COM tnode = sr->tid_tree->t_snode; 65710504SKeyur.Desai@Sun.COM path = src_fqi->fq_path.pn_path; 65810504SKeyur.Desai@Sun.COM rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, 65910504SKeyur.Desai@Sun.COM &src_fqi->fq_dnode, src_fqi->fq_last_comp); 66010504SKeyur.Desai@Sun.COM if (rc != 0) 6619914Samw@Sun.COM return (rc); 6629914Samw@Sun.COM 66310966SJordan.Brown@Sun.COM rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode, 66410504SKeyur.Desai@Sun.COM src_fqi->fq_dnode, src_fqi->fq_last_comp, &src_fqi->fq_fnode); 66510504SKeyur.Desai@Sun.COM if (rc != 0) { 66610504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 66710504SKeyur.Desai@Sun.COM return (rc); 66810504SKeyur.Desai@Sun.COM } 6699914Samw@Sun.COM 67010966SJordan.Brown@Sun.COM /* Not valid to create hardlink for directory */ 67110966SJordan.Brown@Sun.COM if ((dirop->info_level == SMB_NT_RENAME_SET_LINK_INFO) && 67210966SJordan.Brown@Sun.COM (smb_node_is_dir(src_fqi->fq_fnode))) { 67310966SJordan.Brown@Sun.COM smb_node_release(src_fqi->fq_fnode); 67410966SJordan.Brown@Sun.COM smb_node_release(src_fqi->fq_dnode); 67510966SJordan.Brown@Sun.COM return (EISDIR); 67610966SJordan.Brown@Sun.COM } 67710966SJordan.Brown@Sun.COM 67810966SJordan.Brown@Sun.COM src_node = src_fqi->fq_fnode; 67910966SJordan.Brown@Sun.COM 68010966SJordan.Brown@Sun.COM rc = smb_rename_check_attr(sr, src_node, src_fqi->fq_sattr); 68110504SKeyur.Desai@Sun.COM if (rc != 0) { 68210504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 68310504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 68410504SKeyur.Desai@Sun.COM return (rc); 68510504SKeyur.Desai@Sun.COM } 6869914Samw@Sun.COM 6879914Samw@Sun.COM /* 6889914Samw@Sun.COM * Break the oplock before access checks. If a client 6899914Samw@Sun.COM * has a file open, this will force a flush or close, 6909914Samw@Sun.COM * which may affect the outcome of any share checking. 6919914Samw@Sun.COM */ 69210966SJordan.Brown@Sun.COM (void) smb_oplock_break(src_node, sr->session, B_FALSE); 6939914Samw@Sun.COM 6949914Samw@Sun.COM for (count = 0; count <= 3; count++) { 6959914Samw@Sun.COM if (count) { 69610966SJordan.Brown@Sun.COM smb_node_end_crit(src_node); 6979914Samw@Sun.COM delay(MSEC_TO_TICK(400)); 6989914Samw@Sun.COM } 6999914Samw@Sun.COM 70010966SJordan.Brown@Sun.COM smb_node_start_crit(src_node, RW_READER); 7019914Samw@Sun.COM 70210966SJordan.Brown@Sun.COM status = smb_node_rename_check(src_node); 7039914Samw@Sun.COM if (status != NT_STATUS_SHARING_VIOLATION) 7049914Samw@Sun.COM break; 7059914Samw@Sun.COM } 7069914Samw@Sun.COM 7079914Samw@Sun.COM if (status == NT_STATUS_SHARING_VIOLATION) { 70810966SJordan.Brown@Sun.COM smb_node_end_crit(src_node); 70910504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 71010504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 71110504SKeyur.Desai@Sun.COM return (EPIPE); /* = ERRbadshare */ 7129914Samw@Sun.COM } 7139914Samw@Sun.COM 71410966SJordan.Brown@Sun.COM status = smb_range_check(sr, src_node, 0, UINT64_MAX, B_TRUE); 7159914Samw@Sun.COM if (status != NT_STATUS_SUCCESS) { 71610966SJordan.Brown@Sun.COM smb_node_end_crit(src_node); 71710504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 71810504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 71910504SKeyur.Desai@Sun.COM return (EACCES); 7209914Samw@Sun.COM } 7219914Samw@Sun.COM 72210966SJordan.Brown@Sun.COM return (0); 72310966SJordan.Brown@Sun.COM } 7249914Samw@Sun.COM 72510966SJordan.Brown@Sun.COM /* 72610966SJordan.Brown@Sun.COM * smb_rename_release_src 72710966SJordan.Brown@Sun.COM */ 72810966SJordan.Brown@Sun.COM static void 72910966SJordan.Brown@Sun.COM smb_rename_release_src(smb_request_t *sr) 73010966SJordan.Brown@Sun.COM { 73110966SJordan.Brown@Sun.COM smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 73210504SKeyur.Desai@Sun.COM 73310966SJordan.Brown@Sun.COM smb_node_end_crit(src_fqi->fq_fnode); 73410504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 7359914Samw@Sun.COM smb_node_release(src_fqi->fq_dnode); 7369914Samw@Sun.COM } 7379914Samw@Sun.COM 73810966SJordan.Brown@Sun.COM 7399914Samw@Sun.COM static int 74010001SJoyce.McIntosh@Sun.COM smb_rename_check_attr(smb_request_t *sr, smb_node_t *node, uint16_t sattr) 7419914Samw@Sun.COM { 74210001SJoyce.McIntosh@Sun.COM smb_attr_t attr; 7439914Samw@Sun.COM 74410001SJoyce.McIntosh@Sun.COM if (smb_node_getattr(sr, node, &attr) != 0) 74510001SJoyce.McIntosh@Sun.COM return (EIO); 74610001SJoyce.McIntosh@Sun.COM 74710001SJoyce.McIntosh@Sun.COM if ((attr.sa_dosattr & FILE_ATTRIBUTE_HIDDEN) && 74810001SJoyce.McIntosh@Sun.COM !(SMB_SEARCH_HIDDEN(sattr))) 7499914Samw@Sun.COM return (ESRCH); 7509914Samw@Sun.COM 75110001SJoyce.McIntosh@Sun.COM if ((attr.sa_dosattr & FILE_ATTRIBUTE_SYSTEM) && 75210001SJoyce.McIntosh@Sun.COM !(SMB_SEARCH_SYSTEM(sattr))) 7539914Samw@Sun.COM return (ESRCH); 7549914Samw@Sun.COM 7559914Samw@Sun.COM return (0); 7569914Samw@Sun.COM } 7579914Samw@Sun.COM 7589914Samw@Sun.COM /* 7599914Samw@Sun.COM * The following values are based on observed WFWG, Windows 9x, Windows NT 7609914Samw@Sun.COM * and Windows 2000 behaviour. 7619914Samw@Sun.COM * 7629914Samw@Sun.COM * ERROR_FILE_EXISTS doesn't work for Windows 98 clients. 7639914Samw@Sun.COM * 7649914Samw@Sun.COM * Windows 95 clients don't see the problem because the target is deleted 7659914Samw@Sun.COM * before the rename request. 7669914Samw@Sun.COM */ 7679914Samw@Sun.COM static void 7689914Samw@Sun.COM smb_rename_set_error(smb_request_t *sr, int errnum) 7699914Samw@Sun.COM { 7709914Samw@Sun.COM static struct { 7719914Samw@Sun.COM int errnum; 7729914Samw@Sun.COM uint16_t errcode; 7739914Samw@Sun.COM uint32_t status32; 7749914Samw@Sun.COM } rc_map[] = { 7759914Samw@Sun.COM { EEXIST, ERROR_ALREADY_EXISTS, NT_STATUS_OBJECT_NAME_COLLISION }, 7769914Samw@Sun.COM { EPIPE, ERROR_SHARING_VIOLATION, NT_STATUS_SHARING_VIOLATION }, 7779914Samw@Sun.COM { ENOENT, ERROR_FILE_NOT_FOUND, NT_STATUS_OBJECT_NAME_NOT_FOUND }, 7789914Samw@Sun.COM { ESRCH, ERROR_FILE_NOT_FOUND, NT_STATUS_NO_SUCH_FILE }, 7799914Samw@Sun.COM { EINVAL, ERROR_INVALID_PARAMETER, NT_STATUS_INVALID_PARAMETER }, 78010001SJoyce.McIntosh@Sun.COM { EACCES, ERROR_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED }, 78110966SJordan.Brown@Sun.COM { EISDIR, ERROR_ACCESS_DENIED, NT_STATUS_FILE_IS_A_DIRECTORY }, 78210001SJoyce.McIntosh@Sun.COM { EIO, ERROR_INTERNAL_ERROR, NT_STATUS_INTERNAL_ERROR } 7839914Samw@Sun.COM }; 7849914Samw@Sun.COM 7859914Samw@Sun.COM int i; 7869914Samw@Sun.COM 7879914Samw@Sun.COM if (errnum == 0) 7889914Samw@Sun.COM return; 7899914Samw@Sun.COM 7909914Samw@Sun.COM for (i = 0; i < sizeof (rc_map)/sizeof (rc_map[0]); ++i) { 7919914Samw@Sun.COM if (rc_map[i].errnum == errnum) { 7929914Samw@Sun.COM smbsr_error(sr, rc_map[i].status32, 7939914Samw@Sun.COM ERRDOS, rc_map[i].errcode); 7949914Samw@Sun.COM return; 7959914Samw@Sun.COM } 7969914Samw@Sun.COM } 7979914Samw@Sun.COM 7989914Samw@Sun.COM smbsr_errno(sr, errnum); 7999914Samw@Sun.COM } 800