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 /* 228934SJose.Borrego@Sun.COM * Copyright 2009 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 { 1047961SNatalie.Li@Sun.COM smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 1057961SNatalie.Li@Sun.COM smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 1065331Samw int rc; 1075331Samw 1085331Samw if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 1095772Sas200622 smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 1105331Samw ERRDOS, ERROR_ACCESS_DENIED); 1116139Sjb150015 return (SDRC_ERROR); 1125331Samw } 1135331Samw 11410966SJordan.Brown@Sun.COM rc = smb_common_rename(sr, src_fqi, dst_fqi); 1155331Samw 1165331Samw if (rc != 0) { 1179914Samw@Sun.COM smb_rename_set_error(sr, rc); 1186139Sjb150015 return (SDRC_ERROR); 1195331Samw } 1205331Samw 1216030Sjb150015 rc = smbsr_encode_empty_result(sr); 1226139Sjb150015 return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 1235331Samw } 1245331Samw 1255331Samw /* 1269914Samw@Sun.COM * smb_com_nt_rename 1279914Samw@Sun.COM * 1289914Samw@Sun.COM * Rename a file. Files OldFileName must exist and NewFileName must not. 1299914Samw@Sun.COM * Both pathnames must be relative to the Tid specified in the request. 1309914Samw@Sun.COM * Open files may be renamed. 1319914Samw@Sun.COM * 1329914Samw@Sun.COM * SearchAttributes indicates the attributes that the target file(s) must 1339914Samw@Sun.COM * have. If SearchAttributes is zero then only normal files are renamed. 1349914Samw@Sun.COM * If the system file or hidden attributes are specified then the rename 1359914Samw@Sun.COM * is inclusive - both the specified type(s) of files and normal files are 13610966SJordan.Brown@Sun.COM * renamed. 1379914Samw@Sun.COM */ 1389914Samw@Sun.COM smb_sdrc_t 1399914Samw@Sun.COM smb_pre_nt_rename(smb_request_t *sr) 1409914Samw@Sun.COM { 1419914Samw@Sun.COM smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 1429914Samw@Sun.COM smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 1439914Samw@Sun.COM uint32_t clusters; 1449914Samw@Sun.COM int rc; 1459914Samw@Sun.COM 1469914Samw@Sun.COM rc = smbsr_decode_vwv(sr, "wwl", &src_fqi->fq_sattr, 1479914Samw@Sun.COM &sr->arg.dirop.info_level, &clusters); 1489914Samw@Sun.COM if (rc == 0) { 1499914Samw@Sun.COM rc = smbsr_decode_data(sr, "%SS", sr, 1509914Samw@Sun.COM &src_fqi->fq_path.pn_path, &dst_fqi->fq_path.pn_path); 1519914Samw@Sun.COM 1529914Samw@Sun.COM dst_fqi->fq_sattr = 0; 1539914Samw@Sun.COM } 1549914Samw@Sun.COM 1559914Samw@Sun.COM DTRACE_SMB_2(op__NtRename__start, smb_request_t *, sr, 1569914Samw@Sun.COM struct dirop *, &sr->arg.dirop); 1579914Samw@Sun.COM 1589914Samw@Sun.COM return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 1599914Samw@Sun.COM } 1609914Samw@Sun.COM 1619914Samw@Sun.COM void 1629914Samw@Sun.COM smb_post_nt_rename(smb_request_t *sr) 1639914Samw@Sun.COM { 1649914Samw@Sun.COM DTRACE_SMB_1(op__NtRename__done, smb_request_t *, sr); 1659914Samw@Sun.COM } 1669914Samw@Sun.COM 1679914Samw@Sun.COM smb_sdrc_t 1689914Samw@Sun.COM smb_com_nt_rename(smb_request_t *sr) 1699914Samw@Sun.COM { 1709914Samw@Sun.COM smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 1719914Samw@Sun.COM smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 1729914Samw@Sun.COM int rc; 1739914Samw@Sun.COM 1749914Samw@Sun.COM if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { 1759914Samw@Sun.COM smbsr_error(sr, NT_STATUS_ACCESS_DENIED, 1769914Samw@Sun.COM ERRDOS, ERROR_ACCESS_DENIED); 1779914Samw@Sun.COM return (SDRC_ERROR); 1789914Samw@Sun.COM } 1799914Samw@Sun.COM 180*11337SWilliam.Krier@Sun.COM smb_convert_wildcards(src_fqi->fq_path.pn_path); 181*11337SWilliam.Krier@Sun.COM if (smb_contains_wildcards(src_fqi->fq_path.pn_path)) { 1829914Samw@Sun.COM smbsr_error(sr, NT_STATUS_OBJECT_PATH_SYNTAX_BAD, 1839914Samw@Sun.COM ERRDOS, ERROR_BAD_PATHNAME); 1849914Samw@Sun.COM return (SDRC_ERROR); 1859914Samw@Sun.COM } 1869914Samw@Sun.COM 1879914Samw@Sun.COM switch (sr->arg.dirop.info_level) { 1889914Samw@Sun.COM case SMB_NT_RENAME_SET_LINK_INFO: 1899914Samw@Sun.COM rc = smb_make_link(sr, src_fqi, dst_fqi); 1909914Samw@Sun.COM break; 1919914Samw@Sun.COM case SMB_NT_RENAME_RENAME_FILE: 1929914Samw@Sun.COM case SMB_NT_RENAME_MOVE_FILE: 19310966SJordan.Brown@Sun.COM rc = smb_common_rename(sr, src_fqi, dst_fqi); 1949914Samw@Sun.COM break; 1959914Samw@Sun.COM case SMB_NT_RENAME_MOVE_CLUSTER_INFO: 1969914Samw@Sun.COM rc = EINVAL; 1979914Samw@Sun.COM break; 1989914Samw@Sun.COM default: 1999914Samw@Sun.COM rc = EACCES; 2009914Samw@Sun.COM break; 2019914Samw@Sun.COM } 2029914Samw@Sun.COM 2039914Samw@Sun.COM if (rc != 0) { 2049914Samw@Sun.COM smb_rename_set_error(sr, rc); 2059914Samw@Sun.COM return (SDRC_ERROR); 2069914Samw@Sun.COM } 2079914Samw@Sun.COM 2089914Samw@Sun.COM rc = smbsr_encode_empty_result(sr); 2099914Samw@Sun.COM return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); 2109914Samw@Sun.COM } 2119914Samw@Sun.COM 2129914Samw@Sun.COM /* 21310966SJordan.Brown@Sun.COM * smb_nt_transact_rename 21410966SJordan.Brown@Sun.COM * 21510966SJordan.Brown@Sun.COM * Windows servers return SUCCESS without renaming file. 21610966SJordan.Brown@Sun.COM * The only check required is to check that the handle (fid) is valid. 21710966SJordan.Brown@Sun.COM */ 21810966SJordan.Brown@Sun.COM smb_sdrc_t 21910966SJordan.Brown@Sun.COM smb_nt_transact_rename(smb_request_t *sr, smb_xa_t *xa) 22010966SJordan.Brown@Sun.COM { 22110966SJordan.Brown@Sun.COM if (smb_mbc_decodef(&xa->req_param_mb, "w", &sr->smb_fid) != 0) 22210966SJordan.Brown@Sun.COM return (SDRC_ERROR); 22310966SJordan.Brown@Sun.COM 22410966SJordan.Brown@Sun.COM smbsr_lookup_file(sr); 22510966SJordan.Brown@Sun.COM if (sr->fid_ofile == NULL) { 22610966SJordan.Brown@Sun.COM smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); 22710966SJordan.Brown@Sun.COM return (SDRC_ERROR); 22810966SJordan.Brown@Sun.COM } 22910966SJordan.Brown@Sun.COM smbsr_release_file(sr); 23010966SJordan.Brown@Sun.COM 23110966SJordan.Brown@Sun.COM return (SDRC_SUCCESS); 23210966SJordan.Brown@Sun.COM } 23310966SJordan.Brown@Sun.COM 23410966SJordan.Brown@Sun.COM /* 23510966SJordan.Brown@Sun.COM * smb_trans2_rename 23610966SJordan.Brown@Sun.COM * 23710966SJordan.Brown@Sun.COM * Implements SMB_FILE_RENAME_INFORMATION level of Trans2_Set_FileInfo 23810966SJordan.Brown@Sun.COM * and Trans2_Set_PathInfo. 23910966SJordan.Brown@Sun.COM * If the new filename (dst_fqi) already exists it may be overwritten 24010966SJordan.Brown@Sun.COM * if flags == 1. 24110966SJordan.Brown@Sun.COM */ 24210966SJordan.Brown@Sun.COM int 24310966SJordan.Brown@Sun.COM smb_trans2_rename(smb_request_t *sr, smb_node_t *node, char *fname, int flags) 24410966SJordan.Brown@Sun.COM { 24510966SJordan.Brown@Sun.COM int rc; 24610966SJordan.Brown@Sun.COM smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 24710966SJordan.Brown@Sun.COM smb_fqi_t *dst_fqi = &sr->arg.dirop.dst_fqi; 24810966SJordan.Brown@Sun.COM 24910966SJordan.Brown@Sun.COM sr->arg.dirop.flags = flags ? SMB_RENAME_FLAG_OVERWRITE : 0; 25010966SJordan.Brown@Sun.COM sr->arg.dirop.info_level = SMB_NT_RENAME_RENAME_FILE; 25110966SJordan.Brown@Sun.COM 25210966SJordan.Brown@Sun.COM src_fqi->fq_sattr = SMB_SEARCH_ATTRIBUTES; 25310966SJordan.Brown@Sun.COM src_fqi->fq_fnode = node; 25410966SJordan.Brown@Sun.COM src_fqi->fq_dnode = node->n_dnode; 25510966SJordan.Brown@Sun.COM 25610966SJordan.Brown@Sun.COM dst_fqi->fq_path.pn_path = fname; 25710966SJordan.Brown@Sun.COM dst_fqi->fq_dnode = node->n_dnode; 25810966SJordan.Brown@Sun.COM (void) strlcpy(dst_fqi->fq_last_comp, fname, MAXNAMELEN); 25910966SJordan.Brown@Sun.COM 26010966SJordan.Brown@Sun.COM rc = smb_common_rename(sr, src_fqi, dst_fqi); 26110966SJordan.Brown@Sun.COM if (rc != 0) { 26210966SJordan.Brown@Sun.COM smb_rename_set_error(sr, rc); 26310966SJordan.Brown@Sun.COM return (-1); 26410966SJordan.Brown@Sun.COM } 26510966SJordan.Brown@Sun.COM 26610966SJordan.Brown@Sun.COM return (0); 26710966SJordan.Brown@Sun.COM } 26810966SJordan.Brown@Sun.COM 26910966SJordan.Brown@Sun.COM /* 27010966SJordan.Brown@Sun.COM * smb_common_rename 27110966SJordan.Brown@Sun.COM * 27210966SJordan.Brown@Sun.COM * Common code for renaming a file. 27310966SJordan.Brown@Sun.COM * 27410966SJordan.Brown@Sun.COM * If the source and destination are identical, we go through all 27510966SJordan.Brown@Sun.COM * the checks but we don't actually do the rename. If the source 27610966SJordan.Brown@Sun.COM * and destination files differ only in case, we do a case-sensitive 27710966SJordan.Brown@Sun.COM * rename. Otherwise, we do a full case-insensitive rename. 27810966SJordan.Brown@Sun.COM * 27910966SJordan.Brown@Sun.COM * Returns errno values. 28010966SJordan.Brown@Sun.COM */ 28110966SJordan.Brown@Sun.COM static int 28210966SJordan.Brown@Sun.COM smb_common_rename(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi) 28310966SJordan.Brown@Sun.COM { 28410966SJordan.Brown@Sun.COM smb_node_t *src_fnode, *src_dnode, *dst_fnode, *dst_dnode; 28510966SJordan.Brown@Sun.COM smb_node_t *tnode; 28610966SJordan.Brown@Sun.COM int rc, count; 28710966SJordan.Brown@Sun.COM DWORD status; 28810966SJordan.Brown@Sun.COM char *new_name, *path; 28910966SJordan.Brown@Sun.COM 29010966SJordan.Brown@Sun.COM path = dst_fqi->fq_path.pn_path; 29110966SJordan.Brown@Sun.COM 29210966SJordan.Brown@Sun.COM /* Check if attempting to rename a stream - not yet supported */ 29310966SJordan.Brown@Sun.COM rc = smb_rename_check_stream(src_fqi, dst_fqi); 29410966SJordan.Brown@Sun.COM if (rc != 0) 29510966SJordan.Brown@Sun.COM return (rc); 29610966SJordan.Brown@Sun.COM 29710966SJordan.Brown@Sun.COM /* The source node may already have been provided */ 29810966SJordan.Brown@Sun.COM if (src_fqi->fq_fnode) { 29910966SJordan.Brown@Sun.COM smb_node_start_crit(src_fqi->fq_fnode, RW_READER); 30010966SJordan.Brown@Sun.COM smb_node_ref(src_fqi->fq_fnode); 30110966SJordan.Brown@Sun.COM smb_node_ref(src_fqi->fq_dnode); 30210966SJordan.Brown@Sun.COM } else { 30310966SJordan.Brown@Sun.COM /* lookup and validate src node */ 30410966SJordan.Brown@Sun.COM rc = smb_rename_lookup_src(sr); 30510966SJordan.Brown@Sun.COM if (rc != 0) 30610966SJordan.Brown@Sun.COM return (rc); 30710966SJordan.Brown@Sun.COM } 30810966SJordan.Brown@Sun.COM 30910966SJordan.Brown@Sun.COM src_fnode = src_fqi->fq_fnode; 31010966SJordan.Brown@Sun.COM src_dnode = src_fqi->fq_dnode; 31110966SJordan.Brown@Sun.COM 31210966SJordan.Brown@Sun.COM /* Find destination dnode and last_comp */ 31310966SJordan.Brown@Sun.COM if (dst_fqi->fq_dnode) { 31410966SJordan.Brown@Sun.COM smb_node_ref(dst_fqi->fq_dnode); 31510966SJordan.Brown@Sun.COM } else { 31610966SJordan.Brown@Sun.COM tnode = sr->tid_tree->t_snode; 31710966SJordan.Brown@Sun.COM rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, 31810966SJordan.Brown@Sun.COM &dst_fqi->fq_dnode, dst_fqi->fq_last_comp); 31910966SJordan.Brown@Sun.COM if (rc != 0) { 32010966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 32110966SJordan.Brown@Sun.COM return (rc); 32210966SJordan.Brown@Sun.COM } 32310966SJordan.Brown@Sun.COM } 32410966SJordan.Brown@Sun.COM 32510966SJordan.Brown@Sun.COM dst_dnode = dst_fqi->fq_dnode; 32610966SJordan.Brown@Sun.COM new_name = dst_fqi->fq_last_comp; 32710966SJordan.Brown@Sun.COM 32810966SJordan.Brown@Sun.COM /* If exact name match in same directory, we're done */ 32910966SJordan.Brown@Sun.COM if ((src_dnode == dst_dnode) && 33010966SJordan.Brown@Sun.COM (strcmp(src_fnode->od_name, new_name) == 0)) { 33110966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 33210966SJordan.Brown@Sun.COM smb_node_release(dst_dnode); 33310966SJordan.Brown@Sun.COM return (0); 33410966SJordan.Brown@Sun.COM } 33510966SJordan.Brown@Sun.COM 33610966SJordan.Brown@Sun.COM /* Lookup destination node */ 33710966SJordan.Brown@Sun.COM rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode, 33810966SJordan.Brown@Sun.COM dst_dnode, new_name, &dst_fqi->fq_fnode); 33910966SJordan.Brown@Sun.COM 340*11337SWilliam.Krier@Sun.COM /* If the destination node doesn't already exist, validate new_name. */ 341*11337SWilliam.Krier@Sun.COM if (rc == ENOENT) { 342*11337SWilliam.Krier@Sun.COM if (smb_is_invalid_filename(new_name)) { 343*11337SWilliam.Krier@Sun.COM smb_rename_release_src(sr); 344*11337SWilliam.Krier@Sun.COM smb_node_release(dst_dnode); 345*11337SWilliam.Krier@Sun.COM return (EILSEQ); /* NT_STATUS_OBJECT_NAME_INVALID */ 346*11337SWilliam.Krier@Sun.COM } 347*11337SWilliam.Krier@Sun.COM } 348*11337SWilliam.Krier@Sun.COM 34910966SJordan.Brown@Sun.COM /* 35010966SJordan.Brown@Sun.COM * Handle case where changing case of the same directory entry. 35110966SJordan.Brown@Sun.COM * 35210966SJordan.Brown@Sun.COM * If we found the dst node in the same directory as the src node, 35310966SJordan.Brown@Sun.COM * and their names differ only in case: 35410966SJordan.Brown@Sun.COM * 35510966SJordan.Brown@Sun.COM * If the tree is case sensitive (or mixed): 35610966SJordan.Brown@Sun.COM * Do case sensitive lookup to see if exact match exists. 35710966SJordan.Brown@Sun.COM * If the exact match is the same node as src_node we're done. 35810966SJordan.Brown@Sun.COM * 35910966SJordan.Brown@Sun.COM * If the tree is case insensitive: 36010966SJordan.Brown@Sun.COM * There is currently no way to tell if the case is different 36110966SJordan.Brown@Sun.COM * or not, so do the rename (unless the specified new name was 36210966SJordan.Brown@Sun.COM * mangled). 36310966SJordan.Brown@Sun.COM */ 36410966SJordan.Brown@Sun.COM if ((rc == 0) && 36510966SJordan.Brown@Sun.COM (src_dnode == dst_dnode) && 36610966SJordan.Brown@Sun.COM (smb_strcasecmp(src_fnode->od_name, 36710966SJordan.Brown@Sun.COM dst_fqi->fq_fnode->od_name, 0) == 0)) { 36810966SJordan.Brown@Sun.COM smb_node_release(dst_fqi->fq_fnode); 36910966SJordan.Brown@Sun.COM dst_fqi->fq_fnode = NULL; 37010966SJordan.Brown@Sun.COM 37110966SJordan.Brown@Sun.COM if (smb_tree_has_feature(sr->tid_tree, 37210966SJordan.Brown@Sun.COM SMB_TREE_NO_CASESENSITIVE)) { 37310966SJordan.Brown@Sun.COM if (smb_strcasecmp(src_fnode->od_name, 37410966SJordan.Brown@Sun.COM dst_fqi->fq_last_comp, 0) != 0) { 37510966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 37610966SJordan.Brown@Sun.COM smb_node_release(dst_dnode); 37710966SJordan.Brown@Sun.COM return (0); 37810966SJordan.Brown@Sun.COM } 37910966SJordan.Brown@Sun.COM } else { 38010966SJordan.Brown@Sun.COM rc = smb_fsop_lookup(sr, sr->user_cr, 38110966SJordan.Brown@Sun.COM SMB_CASE_SENSITIVE, tnode, dst_dnode, new_name, 38210966SJordan.Brown@Sun.COM &dst_fqi->fq_fnode); 38310966SJordan.Brown@Sun.COM 38410966SJordan.Brown@Sun.COM if ((rc == 0) && 38510966SJordan.Brown@Sun.COM (dst_fqi->fq_fnode == src_fnode)) { 38610966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 38710966SJordan.Brown@Sun.COM smb_node_release(dst_fqi->fq_fnode); 38810966SJordan.Brown@Sun.COM smb_node_release(dst_dnode); 38910966SJordan.Brown@Sun.COM return (0); 39010966SJordan.Brown@Sun.COM } 39110966SJordan.Brown@Sun.COM } 39210966SJordan.Brown@Sun.COM } 39310966SJordan.Brown@Sun.COM 39410966SJordan.Brown@Sun.COM if ((rc != 0) && (rc != ENOENT)) { 39510966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 39610966SJordan.Brown@Sun.COM smb_node_release(dst_fqi->fq_dnode); 39710966SJordan.Brown@Sun.COM return (rc); 39810966SJordan.Brown@Sun.COM } 39910966SJordan.Brown@Sun.COM 40010966SJordan.Brown@Sun.COM if (dst_fqi->fq_fnode) { 40110966SJordan.Brown@Sun.COM dst_fnode = dst_fqi->fq_fnode; 40210966SJordan.Brown@Sun.COM 40310966SJordan.Brown@Sun.COM if (!(sr->arg.dirop.flags && SMB_RENAME_FLAG_OVERWRITE)) { 40410966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 40510966SJordan.Brown@Sun.COM smb_node_release(dst_fnode); 40610966SJordan.Brown@Sun.COM smb_node_release(dst_dnode); 40710966SJordan.Brown@Sun.COM return (EEXIST); 40810966SJordan.Brown@Sun.COM } 40910966SJordan.Brown@Sun.COM 41010966SJordan.Brown@Sun.COM (void) smb_oplock_break(dst_fnode, sr->session, B_FALSE); 41110966SJordan.Brown@Sun.COM 41210966SJordan.Brown@Sun.COM for (count = 0; count <= 3; count++) { 41310966SJordan.Brown@Sun.COM if (count) { 41410966SJordan.Brown@Sun.COM smb_node_end_crit(dst_fnode); 41510966SJordan.Brown@Sun.COM delay(MSEC_TO_TICK(400)); 41610966SJordan.Brown@Sun.COM } 41710966SJordan.Brown@Sun.COM 41810966SJordan.Brown@Sun.COM smb_node_start_crit(dst_fnode, RW_READER); 41910966SJordan.Brown@Sun.COM status = smb_node_delete_check(dst_fnode); 42010966SJordan.Brown@Sun.COM 42110966SJordan.Brown@Sun.COM if (status != NT_STATUS_SHARING_VIOLATION) 42210966SJordan.Brown@Sun.COM break; 42310966SJordan.Brown@Sun.COM } 42410966SJordan.Brown@Sun.COM 42510966SJordan.Brown@Sun.COM if (status != NT_STATUS_SHARING_VIOLATION) 42610966SJordan.Brown@Sun.COM status = smb_range_check(sr, dst_fnode, 42710966SJordan.Brown@Sun.COM 0, UINT64_MAX, B_TRUE); 42810966SJordan.Brown@Sun.COM 42910966SJordan.Brown@Sun.COM if (status != NT_STATUS_SUCCESS) { 43010966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 43110966SJordan.Brown@Sun.COM smb_node_end_crit(dst_fnode); 43210966SJordan.Brown@Sun.COM smb_node_release(dst_fnode); 43310966SJordan.Brown@Sun.COM smb_node_release(dst_dnode); 43410966SJordan.Brown@Sun.COM return (EACCES); 43510966SJordan.Brown@Sun.COM } 43610966SJordan.Brown@Sun.COM 437*11337SWilliam.Krier@Sun.COM new_name = dst_fnode->od_name; 43810966SJordan.Brown@Sun.COM } 43910966SJordan.Brown@Sun.COM 44010966SJordan.Brown@Sun.COM rc = smb_fsop_rename(sr, sr->user_cr, 44110966SJordan.Brown@Sun.COM src_dnode, src_fnode->od_name, 44210966SJordan.Brown@Sun.COM dst_dnode, new_name); 44310966SJordan.Brown@Sun.COM 44410966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 44510966SJordan.Brown@Sun.COM 44610966SJordan.Brown@Sun.COM if (rc == 0) 44710966SJordan.Brown@Sun.COM smb_node_notify_change(dst_dnode); 44810966SJordan.Brown@Sun.COM 44910966SJordan.Brown@Sun.COM if (dst_fqi->fq_fnode) { 45010966SJordan.Brown@Sun.COM smb_node_end_crit(dst_fnode); 45110966SJordan.Brown@Sun.COM smb_node_release(dst_fnode); 45210966SJordan.Brown@Sun.COM } 45310966SJordan.Brown@Sun.COM smb_node_release(dst_dnode); 45410966SJordan.Brown@Sun.COM 45510966SJordan.Brown@Sun.COM return (rc); 45610966SJordan.Brown@Sun.COM } 45710966SJordan.Brown@Sun.COM 45810966SJordan.Brown@Sun.COM /* 45910966SJordan.Brown@Sun.COM * smb_rename_check_stream 46010966SJordan.Brown@Sun.COM * 46110966SJordan.Brown@Sun.COM * For a stream rename the dst path must begin with ':', or "\\:". 46210966SJordan.Brown@Sun.COM * We don't yet support stream rename, Return EACCES. 46310966SJordan.Brown@Sun.COM * 46410966SJordan.Brown@Sun.COM * If not a stream rename, in accordance with the above rule, 46510966SJordan.Brown@Sun.COM * it is not valid for either the src or dst to be a stream. 46610966SJordan.Brown@Sun.COM * Return EINVAL. 46710966SJordan.Brown@Sun.COM */ 46810966SJordan.Brown@Sun.COM static int 46910966SJordan.Brown@Sun.COM smb_rename_check_stream(smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi) 47010966SJordan.Brown@Sun.COM { 47110966SJordan.Brown@Sun.COM smb_node_t *src_fnode = src_fqi->fq_fnode; 47210966SJordan.Brown@Sun.COM char *src_path = src_fqi->fq_path.pn_path; 47310966SJordan.Brown@Sun.COM char *dst_path = dst_fqi->fq_path.pn_path; 47410966SJordan.Brown@Sun.COM 47510966SJordan.Brown@Sun.COM /* We do not yet support named stream rename - ACCESS DENIED */ 47610966SJordan.Brown@Sun.COM if ((dst_path[0] == ':') || 47710966SJordan.Brown@Sun.COM ((dst_path[0] == '\\') && (dst_path[1] == ':'))) { 47810966SJordan.Brown@Sun.COM return (EACCES); 47910966SJordan.Brown@Sun.COM } 48010966SJordan.Brown@Sun.COM 48110966SJordan.Brown@Sun.COM /* 48210966SJordan.Brown@Sun.COM * If not stream rename (above) neither src or dst can be 48310966SJordan.Brown@Sun.COM * a named stream. 48410966SJordan.Brown@Sun.COM */ 48510966SJordan.Brown@Sun.COM 48610966SJordan.Brown@Sun.COM if (smb_is_stream_name(dst_path)) 48710966SJordan.Brown@Sun.COM return (EINVAL); 48810966SJordan.Brown@Sun.COM 48910966SJordan.Brown@Sun.COM if (src_fqi->fq_fnode) { 49010966SJordan.Brown@Sun.COM if (SMB_IS_STREAM(src_fnode)) 49110966SJordan.Brown@Sun.COM return (EINVAL); 49210966SJordan.Brown@Sun.COM } else { 49310966SJordan.Brown@Sun.COM if (smb_is_stream_name(src_path)) 49410966SJordan.Brown@Sun.COM return (EINVAL); 49510966SJordan.Brown@Sun.COM } 49610966SJordan.Brown@Sun.COM 49710966SJordan.Brown@Sun.COM return (0); 49810966SJordan.Brown@Sun.COM } 49910966SJordan.Brown@Sun.COM 50010966SJordan.Brown@Sun.COM 50110966SJordan.Brown@Sun.COM /* 5029914Samw@Sun.COM * smb_make_link 5039914Samw@Sun.COM * 50410966SJordan.Brown@Sun.COM * Creating a hard link (adding an additional name) for a file. 5059914Samw@Sun.COM * 5069914Samw@Sun.COM * If the source and destination are identical, we go through all 5079914Samw@Sun.COM * the checks but we don't create a link. 5089914Samw@Sun.COM * 50910966SJordan.Brown@Sun.COM * If the file is a symlink we create the hardlink on the target 51010966SJordan.Brown@Sun.COM * of the symlink (i.e. use SMB_FOLLOW_LINKS when looking up src). 51110966SJordan.Brown@Sun.COM * If the target of the symlink does not exist we fail with ENOENT. 51210966SJordan.Brown@Sun.COM * 5139914Samw@Sun.COM * Returns errno values. 5149914Samw@Sun.COM */ 5159914Samw@Sun.COM static int 5169914Samw@Sun.COM smb_make_link(smb_request_t *sr, smb_fqi_t *src_fqi, smb_fqi_t *dst_fqi) 5179914Samw@Sun.COM { 51810966SJordan.Brown@Sun.COM smb_node_t *tnode; 51910966SJordan.Brown@Sun.COM char *path; 52010966SJordan.Brown@Sun.COM int rc; 52110966SJordan.Brown@Sun.COM 52210966SJordan.Brown@Sun.COM /* Cannnot create link on named stream */ 52310966SJordan.Brown@Sun.COM if (smb_is_stream_name(src_fqi->fq_path.pn_path) || 52410966SJordan.Brown@Sun.COM smb_is_stream_name(dst_fqi->fq_path.pn_path)) { 52510966SJordan.Brown@Sun.COM return (EINVAL); 52610966SJordan.Brown@Sun.COM } 52710966SJordan.Brown@Sun.COM 52810966SJordan.Brown@Sun.COM /* lookup and validate src node */ 52910966SJordan.Brown@Sun.COM rc = smb_rename_lookup_src(sr); 53010966SJordan.Brown@Sun.COM if (rc != 0) 53110966SJordan.Brown@Sun.COM return (rc); 53210966SJordan.Brown@Sun.COM 53310966SJordan.Brown@Sun.COM /* if src and dest paths match we're done */ 53410966SJordan.Brown@Sun.COM if (smb_strcasecmp(src_fqi->fq_path.pn_path, 53510966SJordan.Brown@Sun.COM dst_fqi->fq_path.pn_path, 0) == 0) { 53610966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 53710966SJordan.Brown@Sun.COM return (0); 53810966SJordan.Brown@Sun.COM } 53910966SJordan.Brown@Sun.COM 54010966SJordan.Brown@Sun.COM /* find the destination dnode and last_comp */ 54110966SJordan.Brown@Sun.COM tnode = sr->tid_tree->t_snode; 54210966SJordan.Brown@Sun.COM path = dst_fqi->fq_path.pn_path; 54310966SJordan.Brown@Sun.COM rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, 54410966SJordan.Brown@Sun.COM &dst_fqi->fq_dnode, dst_fqi->fq_last_comp); 54510966SJordan.Brown@Sun.COM if (rc != 0) { 54610966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 54710966SJordan.Brown@Sun.COM return (rc); 54810966SJordan.Brown@Sun.COM } 54910966SJordan.Brown@Sun.COM 55010966SJordan.Brown@Sun.COM /* If name match in same directory, we're done */ 55110966SJordan.Brown@Sun.COM if ((src_fqi->fq_dnode == dst_fqi->fq_dnode) && 55210966SJordan.Brown@Sun.COM (smb_strcasecmp(src_fqi->fq_fnode->od_name, 55310966SJordan.Brown@Sun.COM dst_fqi->fq_last_comp, 0) == 0)) { 55410966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 55510966SJordan.Brown@Sun.COM smb_node_release(dst_fqi->fq_dnode); 55610966SJordan.Brown@Sun.COM return (0); 55710966SJordan.Brown@Sun.COM } 55810966SJordan.Brown@Sun.COM 559*11337SWilliam.Krier@Sun.COM if (smb_is_invalid_filename(dst_fqi->fq_last_comp)) { 560*11337SWilliam.Krier@Sun.COM smb_rename_release_src(sr); 561*11337SWilliam.Krier@Sun.COM smb_node_release(dst_fqi->fq_dnode); 562*11337SWilliam.Krier@Sun.COM return (EILSEQ); /* NT_STATUS_INVALID_OBJECT_NAME */ 563*11337SWilliam.Krier@Sun.COM } 564*11337SWilliam.Krier@Sun.COM 56510966SJordan.Brown@Sun.COM /* Lookup the destination node. It MUST NOT exist. */ 56610966SJordan.Brown@Sun.COM rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode, 56710966SJordan.Brown@Sun.COM dst_fqi->fq_dnode, dst_fqi->fq_last_comp, &dst_fqi->fq_fnode); 56810966SJordan.Brown@Sun.COM if (rc == 0) { 56910966SJordan.Brown@Sun.COM smb_node_release(dst_fqi->fq_fnode); 57010966SJordan.Brown@Sun.COM rc = EEXIST; 57110966SJordan.Brown@Sun.COM } 57210966SJordan.Brown@Sun.COM if (rc != ENOENT) { 57310966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 57410966SJordan.Brown@Sun.COM smb_node_release(dst_fqi->fq_dnode); 57510966SJordan.Brown@Sun.COM return (rc); 57610966SJordan.Brown@Sun.COM } 57710966SJordan.Brown@Sun.COM 57810966SJordan.Brown@Sun.COM rc = smb_fsop_link(sr, sr->user_cr, src_fqi->fq_fnode, 57910966SJordan.Brown@Sun.COM dst_fqi->fq_dnode, dst_fqi->fq_last_comp); 58010966SJordan.Brown@Sun.COM 58110966SJordan.Brown@Sun.COM smb_rename_release_src(sr); 58210966SJordan.Brown@Sun.COM if (rc == 0) 58310966SJordan.Brown@Sun.COM smb_node_notify_change(dst_fqi->fq_dnode); 58410966SJordan.Brown@Sun.COM smb_node_release(dst_fqi->fq_dnode); 58510966SJordan.Brown@Sun.COM return (rc); 58610966SJordan.Brown@Sun.COM } 58710966SJordan.Brown@Sun.COM 58810966SJordan.Brown@Sun.COM /* 58910966SJordan.Brown@Sun.COM * smb_rename_lookup_src 59010966SJordan.Brown@Sun.COM * 59110966SJordan.Brown@Sun.COM * Lookup the src node, checking for sharing violations and 59210966SJordan.Brown@Sun.COM * breaking any existing oplock. 59310966SJordan.Brown@Sun.COM * Populate sr->arg.dirop.fqi 59410966SJordan.Brown@Sun.COM * 59510966SJordan.Brown@Sun.COM * Upon success, the dnode and fnode will have holds and the 59610966SJordan.Brown@Sun.COM * fnode will be in a critical section. These should be 59710966SJordan.Brown@Sun.COM * released using smb_rename_release_src(). 59810966SJordan.Brown@Sun.COM * 59910966SJordan.Brown@Sun.COM * Returns errno values. 60010966SJordan.Brown@Sun.COM */ 60110966SJordan.Brown@Sun.COM static int 60210966SJordan.Brown@Sun.COM smb_rename_lookup_src(smb_request_t *sr) 60310966SJordan.Brown@Sun.COM { 60410966SJordan.Brown@Sun.COM smb_node_t *src_node, *tnode; 6059914Samw@Sun.COM DWORD status; 6069914Samw@Sun.COM int rc; 6079914Samw@Sun.COM int count; 60810504SKeyur.Desai@Sun.COM char *path; 6099914Samw@Sun.COM 61010966SJordan.Brown@Sun.COM struct dirop *dirop = &sr->arg.dirop; 61110966SJordan.Brown@Sun.COM smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 61210504SKeyur.Desai@Sun.COM 61310966SJordan.Brown@Sun.COM if (smb_is_stream_name(src_fqi->fq_path.pn_path)) 61410966SJordan.Brown@Sun.COM return (EINVAL); 61510966SJordan.Brown@Sun.COM 61610966SJordan.Brown@Sun.COM /* Lookup the source node */ 61710966SJordan.Brown@Sun.COM tnode = sr->tid_tree->t_snode; 61810504SKeyur.Desai@Sun.COM path = src_fqi->fq_path.pn_path; 61910504SKeyur.Desai@Sun.COM rc = smb_pathname_reduce(sr, sr->user_cr, path, tnode, tnode, 62010504SKeyur.Desai@Sun.COM &src_fqi->fq_dnode, src_fqi->fq_last_comp); 62110504SKeyur.Desai@Sun.COM if (rc != 0) 6229914Samw@Sun.COM return (rc); 6239914Samw@Sun.COM 62410966SJordan.Brown@Sun.COM rc = smb_fsop_lookup(sr, sr->user_cr, 0, tnode, 62510504SKeyur.Desai@Sun.COM src_fqi->fq_dnode, src_fqi->fq_last_comp, &src_fqi->fq_fnode); 62610504SKeyur.Desai@Sun.COM if (rc != 0) { 62710504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 62810504SKeyur.Desai@Sun.COM return (rc); 62910504SKeyur.Desai@Sun.COM } 6309914Samw@Sun.COM 63110966SJordan.Brown@Sun.COM /* Not valid to create hardlink for directory */ 63210966SJordan.Brown@Sun.COM if ((dirop->info_level == SMB_NT_RENAME_SET_LINK_INFO) && 63310966SJordan.Brown@Sun.COM (smb_node_is_dir(src_fqi->fq_fnode))) { 63410966SJordan.Brown@Sun.COM smb_node_release(src_fqi->fq_fnode); 63510966SJordan.Brown@Sun.COM smb_node_release(src_fqi->fq_dnode); 63610966SJordan.Brown@Sun.COM return (EISDIR); 63710966SJordan.Brown@Sun.COM } 63810966SJordan.Brown@Sun.COM 63910966SJordan.Brown@Sun.COM src_node = src_fqi->fq_fnode; 64010966SJordan.Brown@Sun.COM 64110966SJordan.Brown@Sun.COM rc = smb_rename_check_attr(sr, src_node, src_fqi->fq_sattr); 64210504SKeyur.Desai@Sun.COM if (rc != 0) { 64310504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 64410504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 64510504SKeyur.Desai@Sun.COM return (rc); 64610504SKeyur.Desai@Sun.COM } 6479914Samw@Sun.COM 6489914Samw@Sun.COM /* 6499914Samw@Sun.COM * Break the oplock before access checks. If a client 6509914Samw@Sun.COM * has a file open, this will force a flush or close, 6519914Samw@Sun.COM * which may affect the outcome of any share checking. 6529914Samw@Sun.COM */ 65310966SJordan.Brown@Sun.COM (void) smb_oplock_break(src_node, sr->session, B_FALSE); 6549914Samw@Sun.COM 6559914Samw@Sun.COM for (count = 0; count <= 3; count++) { 6569914Samw@Sun.COM if (count) { 65710966SJordan.Brown@Sun.COM smb_node_end_crit(src_node); 6589914Samw@Sun.COM delay(MSEC_TO_TICK(400)); 6599914Samw@Sun.COM } 6609914Samw@Sun.COM 66110966SJordan.Brown@Sun.COM smb_node_start_crit(src_node, RW_READER); 6629914Samw@Sun.COM 66310966SJordan.Brown@Sun.COM status = smb_node_rename_check(src_node); 6649914Samw@Sun.COM if (status != NT_STATUS_SHARING_VIOLATION) 6659914Samw@Sun.COM break; 6669914Samw@Sun.COM } 6679914Samw@Sun.COM 6689914Samw@Sun.COM if (status == NT_STATUS_SHARING_VIOLATION) { 66910966SJordan.Brown@Sun.COM smb_node_end_crit(src_node); 67010504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 67110504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 67210504SKeyur.Desai@Sun.COM return (EPIPE); /* = ERRbadshare */ 6739914Samw@Sun.COM } 6749914Samw@Sun.COM 67510966SJordan.Brown@Sun.COM status = smb_range_check(sr, src_node, 0, UINT64_MAX, B_TRUE); 6769914Samw@Sun.COM if (status != NT_STATUS_SUCCESS) { 67710966SJordan.Brown@Sun.COM smb_node_end_crit(src_node); 67810504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 67910504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_dnode); 68010504SKeyur.Desai@Sun.COM return (EACCES); 6819914Samw@Sun.COM } 6829914Samw@Sun.COM 68310966SJordan.Brown@Sun.COM return (0); 68410966SJordan.Brown@Sun.COM } 6859914Samw@Sun.COM 68610966SJordan.Brown@Sun.COM /* 68710966SJordan.Brown@Sun.COM * smb_rename_release_src 68810966SJordan.Brown@Sun.COM */ 68910966SJordan.Brown@Sun.COM static void 69010966SJordan.Brown@Sun.COM smb_rename_release_src(smb_request_t *sr) 69110966SJordan.Brown@Sun.COM { 69210966SJordan.Brown@Sun.COM smb_fqi_t *src_fqi = &sr->arg.dirop.fqi; 69310504SKeyur.Desai@Sun.COM 69410966SJordan.Brown@Sun.COM smb_node_end_crit(src_fqi->fq_fnode); 69510504SKeyur.Desai@Sun.COM smb_node_release(src_fqi->fq_fnode); 6969914Samw@Sun.COM smb_node_release(src_fqi->fq_dnode); 6979914Samw@Sun.COM } 6989914Samw@Sun.COM 69910966SJordan.Brown@Sun.COM 7009914Samw@Sun.COM static int 70110001SJoyce.McIntosh@Sun.COM smb_rename_check_attr(smb_request_t *sr, smb_node_t *node, uint16_t sattr) 7029914Samw@Sun.COM { 70310001SJoyce.McIntosh@Sun.COM smb_attr_t attr; 7049914Samw@Sun.COM 70510001SJoyce.McIntosh@Sun.COM if (smb_node_getattr(sr, node, &attr) != 0) 70610001SJoyce.McIntosh@Sun.COM return (EIO); 70710001SJoyce.McIntosh@Sun.COM 70810001SJoyce.McIntosh@Sun.COM if ((attr.sa_dosattr & FILE_ATTRIBUTE_HIDDEN) && 70910001SJoyce.McIntosh@Sun.COM !(SMB_SEARCH_HIDDEN(sattr))) 7109914Samw@Sun.COM return (ESRCH); 7119914Samw@Sun.COM 71210001SJoyce.McIntosh@Sun.COM if ((attr.sa_dosattr & FILE_ATTRIBUTE_SYSTEM) && 71310001SJoyce.McIntosh@Sun.COM !(SMB_SEARCH_SYSTEM(sattr))) 7149914Samw@Sun.COM return (ESRCH); 7159914Samw@Sun.COM 7169914Samw@Sun.COM return (0); 7179914Samw@Sun.COM } 7189914Samw@Sun.COM 7199914Samw@Sun.COM /* 7209914Samw@Sun.COM * The following values are based on observed WFWG, Windows 9x, Windows NT 7219914Samw@Sun.COM * and Windows 2000 behaviour. 7229914Samw@Sun.COM * 7239914Samw@Sun.COM * ERROR_FILE_EXISTS doesn't work for Windows 98 clients. 7249914Samw@Sun.COM * 7259914Samw@Sun.COM * Windows 95 clients don't see the problem because the target is deleted 7269914Samw@Sun.COM * before the rename request. 7279914Samw@Sun.COM */ 7289914Samw@Sun.COM static void 7299914Samw@Sun.COM smb_rename_set_error(smb_request_t *sr, int errnum) 7309914Samw@Sun.COM { 7319914Samw@Sun.COM static struct { 7329914Samw@Sun.COM int errnum; 7339914Samw@Sun.COM uint16_t errcode; 7349914Samw@Sun.COM uint32_t status32; 7359914Samw@Sun.COM } rc_map[] = { 7369914Samw@Sun.COM { EEXIST, ERROR_ALREADY_EXISTS, NT_STATUS_OBJECT_NAME_COLLISION }, 7379914Samw@Sun.COM { EPIPE, ERROR_SHARING_VIOLATION, NT_STATUS_SHARING_VIOLATION }, 7389914Samw@Sun.COM { ENOENT, ERROR_FILE_NOT_FOUND, NT_STATUS_OBJECT_NAME_NOT_FOUND }, 7399914Samw@Sun.COM { ESRCH, ERROR_FILE_NOT_FOUND, NT_STATUS_NO_SUCH_FILE }, 7409914Samw@Sun.COM { EINVAL, ERROR_INVALID_PARAMETER, NT_STATUS_INVALID_PARAMETER }, 74110001SJoyce.McIntosh@Sun.COM { EACCES, ERROR_ACCESS_DENIED, NT_STATUS_ACCESS_DENIED }, 74210966SJordan.Brown@Sun.COM { EISDIR, ERROR_ACCESS_DENIED, NT_STATUS_FILE_IS_A_DIRECTORY }, 74310001SJoyce.McIntosh@Sun.COM { EIO, ERROR_INTERNAL_ERROR, NT_STATUS_INTERNAL_ERROR } 7449914Samw@Sun.COM }; 7459914Samw@Sun.COM 7469914Samw@Sun.COM int i; 7479914Samw@Sun.COM 7489914Samw@Sun.COM if (errnum == 0) 7499914Samw@Sun.COM return; 7509914Samw@Sun.COM 7519914Samw@Sun.COM for (i = 0; i < sizeof (rc_map)/sizeof (rc_map[0]); ++i) { 7529914Samw@Sun.COM if (rc_map[i].errnum == errnum) { 7539914Samw@Sun.COM smbsr_error(sr, rc_map[i].status32, 7549914Samw@Sun.COM ERRDOS, rc_map[i].errcode); 7559914Samw@Sun.COM return; 7569914Samw@Sun.COM } 7579914Samw@Sun.COM } 7589914Samw@Sun.COM 7599914Samw@Sun.COM smbsr_errno(sr, errnum); 7609914Samw@Sun.COM } 761