nfs-ganesha 1.4
|
00001 /* 00002 * vim:expandtab:shiftwidth=8:tabstop=8: 00003 * 00004 * Copyright CEA/DAM/DIF (2008) 00005 * contributeur : Philippe DENIEL philippe.deniel@cea.fr 00006 * Thomas LEIBOVICI thomas.leibovici@cea.fr 00007 * 00008 * 00009 * This program is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 3 of the License, or (at your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Lesser General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Lesser General Public 00020 * License along with this library; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00022 * 00023 * --------------------------------------- 00024 */ 00025 00037 #ifdef HAVE_CONFIG_H 00038 #include "config.h" 00039 #endif 00040 00041 #ifdef _SOLARIS 00042 #include "solaris_port.h" 00043 #endif 00044 00045 #include <stdio.h> 00046 #include <string.h> 00047 #include <pthread.h> 00048 #include <fcntl.h> 00049 #include <sys/file.h> /* for having FNDELAY */ 00050 #include "HashData.h" 00051 #include "HashTable.h" 00052 #include "log.h" 00053 #include "ganesha_rpc.h" 00054 #include "nfs23.h" 00055 #include "nfs4.h" 00056 #include "mount.h" 00057 #include "nfs_core.h" 00058 #include "cache_inode.h" 00059 #include "nfs_exports.h" 00060 #include "nfs_creds.h" 00061 #include "nfs_proto_functions.h" 00062 #include "nfs_tools.h" 00063 #include "nfs_proto_tools.h" 00064 #include "nfs_file_handle.h" 00065 00085 int nfs_Link(nfs_arg_t *parg, 00086 exportlist_t *pexport, 00087 fsal_op_context_t *pcontext, 00088 nfs_worker_data_t *pworker, 00089 struct svc_req *preq, 00090 nfs_res_t * pres) 00091 { 00092 char *str_link_name = NULL; 00093 fsal_name_t link_name; 00094 cache_entry_t *target_pentry = NULL; 00095 cache_entry_t *parent_pentry; 00096 cache_inode_status_t cache_status = CACHE_INODE_SUCCESS; 00097 fsal_attrib_list_t *ppre_attr; 00098 fsal_attrib_list_t parent_attr; 00099 fsal_attrib_list_t target_attr; 00100 fsal_attrib_list_t attr; 00101 fsal_attrib_list_t attr_parent_after; 00102 cache_inode_file_type_t parent_filetype; 00103 short to_exportid = 0; 00104 short from_exportid = 0; 00105 int rc = NFS_REQ_OK; 00106 00107 if(isDebug(COMPONENT_NFSPROTO)) 00108 { 00109 char strto[LEN_FH_STR], strfrom[LEN_FH_STR]; 00110 00111 switch (preq->rq_vers) 00112 { 00113 case NFS_V2: 00114 str_link_name = parg->arg_link2.to.name; 00115 break; 00116 00117 case NFS_V3: 00118 str_link_name = parg->arg_link3.link.name; 00119 break; 00120 } 00121 00122 nfs_FhandleToStr(preq->rq_vers, 00123 &(parg->arg_link2.from), 00124 &(parg->arg_link3.file), 00125 NULL, 00126 strfrom); 00127 00128 nfs_FhandleToStr(preq->rq_vers, 00129 &(parg->arg_link2.to.dir), 00130 &(parg->arg_link3.link.dir), 00131 NULL, 00132 strto); 00133 LogDebug(COMPONENT_NFSPROTO, 00134 "REQUEST PROCESSING: Calling nfs_Link handle: %s to handle: %s name: %s", 00135 strfrom, strto, str_link_name); 00136 } 00137 00138 if(preq->rq_vers == NFS_V3) 00139 { 00140 /* to avoid setting it on each error case */ 00141 pres->res_link3.LINK3res_u.resfail.file_attributes.attributes_follow = FALSE; 00142 pres->res_link3.LINK3res_u.resfail.linkdir_wcc.before.attributes_follow = FALSE; 00143 pres->res_link3.LINK3res_u.resfail.linkdir_wcc.after.attributes_follow = FALSE; 00144 ppre_attr = NULL; 00145 } 00146 00147 /* Get entry for parent directory */ 00148 if((parent_pentry = nfs_FhandleToCache(preq->rq_vers, 00149 &(parg->arg_link2.to.dir), 00150 &(parg->arg_link3.link.dir), 00151 NULL, 00152 &(pres->res_stat2), 00153 &(pres->res_link3.status), 00154 NULL, 00155 &parent_attr, 00156 pcontext, &rc)) == NULL) 00157 { 00158 /* Stale NFS FH ? */ 00159 goto out; 00160 } 00161 ppre_attr = &parent_attr; 00162 00163 if((target_pentry = nfs_FhandleToCache(preq->rq_vers, 00164 &(parg->arg_link2.from), 00165 &(parg->arg_link3.file), 00166 NULL, 00167 &(pres->res_stat2), 00168 &(pres->res_link3.status), 00169 NULL, 00170 &target_attr, 00171 pcontext, &rc)) == NULL) 00172 { 00173 /* Stale NFS FH ? */ 00174 goto out;; 00175 } 00176 00177 /* Extract the filetype */ 00178 parent_filetype = cache_inode_fsal_type_convert(parent_attr.type); 00179 00180 /* 00181 * Sanity checks: 00182 */ 00183 if(parent_filetype != DIRECTORY) 00184 { 00185 switch (preq->rq_vers) 00186 { 00187 case NFS_V2: 00188 pres->res_stat2 = NFSERR_NOTDIR; 00189 break; 00190 case NFS_V3: 00191 pres->res_link3.status = NFS3ERR_NOTDIR; 00192 break; 00193 } 00194 rc = NFS_REQ_OK; 00195 goto out; 00196 } 00197 00198 switch (preq->rq_vers) 00199 { 00200 case NFS_V2: 00201 { 00202 str_link_name = parg->arg_link2.to.name; 00203 to_exportid = nfs2_FhandleToExportId(&(parg->arg_link2.to.dir)); 00204 from_exportid = nfs2_FhandleToExportId(&(parg->arg_link2.from)); 00205 break; 00206 } 00207 case NFS_V3: 00208 { 00209 str_link_name = parg->arg_link3.link.name; 00210 to_exportid = nfs3_FhandleToExportId(&(parg->arg_link3.link.dir)); 00211 from_exportid = nfs3_FhandleToExportId(&(parg->arg_link3.file)); 00212 break; 00213 } 00214 } 00215 00216 // if(str_link_name == NULL || strlen(str_link_name) == 0) 00217 if(str_link_name == NULL || *str_link_name == '\0' ) 00218 { 00219 if(preq->rq_vers == NFS_V2) 00220 pres->res_stat2 = NFSERR_IO; 00221 if(preq->rq_vers == NFS_V3) 00222 pres->res_link3.status = NFS3ERR_INVAL; 00223 } 00224 else 00225 { 00226 /* 00227 * Both objects have to be in the same filesystem 00228 */ 00229 00230 if(to_exportid != from_exportid) 00231 { 00232 if(preq->rq_vers == NFS_V2) 00233 pres->res_stat2 = NFSERR_PERM; 00234 if(preq->rq_vers == NFS_V3) 00235 pres->res_link3.status = NFS3ERR_XDEV; 00236 } 00237 else 00238 { 00239 /* Make the link */ 00240 if((cache_status = cache_inode_error_convert(FSAL_str2name(str_link_name, 00241 FSAL_MAX_NAME_LEN, 00242 &link_name))) == 00243 CACHE_INODE_SUCCESS) 00244 { 00245 if(cache_inode_link(target_pentry, 00246 parent_pentry, 00247 &link_name, 00248 &attr, 00249 pcontext, &cache_status) == CACHE_INODE_SUCCESS) 00250 { 00251 if(cache_inode_getattr(parent_pentry, 00252 &attr_parent_after, 00253 pcontext, &cache_status) == CACHE_INODE_SUCCESS) 00254 { 00255 switch (preq->rq_vers) 00256 { 00257 case NFS_V2: 00258 pres->res_stat2 = NFS_OK; 00259 break; 00260 00261 case NFS_V3: 00262 /* 00263 * Build post op file 00264 * attributes 00265 */ 00266 00267 nfs_SetPostOpAttr(pexport, 00268 &attr, 00269 &(pres->res_link3.LINK3res_u.resok. 00270 file_attributes)); 00271 00272 /* 00273 * Build Weak Cache Coherency 00274 * data 00275 */ 00276 nfs_SetWccData(pexport, 00277 ppre_attr, 00278 &attr_parent_after, 00279 &(pres->res_link3.LINK3res_u.resok.linkdir_wcc)); 00280 00281 pres->res_link3.status = NFS3_OK; 00282 break; 00283 } /* switch */ 00284 00285 rc = NFS_REQ_OK; 00286 goto out; 00287 00288 } /* if( cache_inode_link ... */ 00289 } /* if( cache_inode_getattr ... */ 00290 } /* else */ 00291 } 00292 } 00293 00294 /* If we are here, there was an error */ 00295 if(nfs_RetryableError(cache_status)) 00296 { 00297 rc = NFS_REQ_DROP; 00298 goto out; 00299 } 00300 00301 nfs_SetFailedStatus(pcontext, pexport, 00302 preq->rq_vers, 00303 cache_status, 00304 &pres->res_stat2, 00305 &pres->res_link3.status, 00306 target_pentry, 00307 &(pres->res_link3.LINK3res_u.resfail.file_attributes), 00308 parent_pentry, 00309 ppre_attr, 00310 &(pres->res_link3.LINK3res_u.resfail.linkdir_wcc), 00311 NULL, NULL, NULL); 00312 00313 rc = NFS_REQ_OK; 00314 00315 out: 00316 /* return references */ 00317 if (target_pentry) 00318 cache_inode_put(target_pentry); 00319 00320 if (parent_pentry) 00321 cache_inode_put(parent_pentry); 00322 00323 return (rc); 00324 00325 } /* nfs_Link */ 00326 00335 void nfs_Link_Free(nfs_res_t * resp) 00336 { 00337 /* Nothing to do here */ 00338 return; 00339 } /* nfs_Link_Free */