nfs-ganesha 1.4
|
00001 /* 00002 * vim:expandtab:shiftwidth=8:tabstop=8: 00003 */ 00004 00014 #ifdef HAVE_CONFIG_H 00015 #include "config.h" 00016 #endif 00017 00018 #include "fsal.h" 00019 #include "fsal_internal.h" 00020 #include "fsal_convert.h" 00021 00045 fsal_status_t POSIXFSAL_unlink(fsal_handle_t * parent_directory_handle, /* IN */ 00046 fsal_name_t * p_object_name, /* IN */ 00047 fsal_op_context_t * context, /* IN */ 00048 fsal_attrib_list_t * p_parent_directory_attributes /* [IN/OUT ] */ 00049 ) 00050 { 00051 posixfsal_handle_t * p_parent_directory_handle 00052 = (posixfsal_handle_t *) parent_directory_handle; 00053 posixfsal_op_context_t * p_context = (posixfsal_op_context_t *) context; 00054 fsal_status_t status; 00055 fsal_posixdb_status_t statusdb; 00056 int rc, errsv; 00057 struct stat buffstat, buffstat_parent; 00058 fsal_path_t fsalpath; 00059 fsal_posixdb_fileinfo_t info; 00060 00061 /* sanity checks. */ 00062 if(!p_parent_directory_handle || !p_context || !p_object_name) 00063 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_unlink); 00064 00065 /* check credential */ 00066 /* need to be able to 'read' the parent directory & to delete it */ 00067 00068 /* build the destination path */ 00069 status = 00070 fsal_internal_getPathFromHandle(p_context, p_parent_directory_handle, 1, &fsalpath, 00071 &buffstat_parent); 00072 if(FSAL_IS_ERROR(status)) 00073 Return(status.major, status.minor, INDEX_FSAL_unlink); 00074 00075 status = fsal_internal_appendFSALNameToFSALPath(&fsalpath, p_object_name); 00076 if(FSAL_IS_ERROR(status)) 00077 Return(status.major, status.minor, INDEX_FSAL_unlink); 00078 00079 /* 00080 * Action depends on the object type to be deleted. 00081 */ 00082 00083 TakeTokenFSCall(); 00084 rc = lstat(fsalpath.path, &buffstat); 00085 errsv = errno; 00086 ReleaseTokenFSCall(); 00087 if(rc) 00088 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_unlink); 00089 00090 if(FSAL_IS_ERROR(status = fsal_internal_posix2posixdb_fileinfo(&buffstat, &info))) 00091 Return(status.major, status.minor, INDEX_FSAL_unlink); 00092 00093 /************************************************************** 00094 * Lock the handle entry related to this file in the database * 00095 **************************************************************/ 00096 00097 statusdb = fsal_posixdb_lockHandleForUpdate(p_context->p_conn, &info); 00098 if(FSAL_IS_ERROR(status = posixdb2fsal_error(statusdb))) 00099 { 00100 fsal_posixdb_cancelHandleLock(p_context->p_conn); 00101 Return(status.major, status.minor, INDEX_FSAL_unlink); 00102 } 00103 00104 /**************** 00105 * CHECK ACCESS * 00106 ****************/ 00107 if((buffstat_parent.st_mode & S_ISVTX) /* Sticky bit on the directory => the user who wants to delete the file must own it or its parent dir */ 00108 && buffstat_parent.st_uid != p_context->credential.user 00109 && buffstat.st_uid != p_context->credential.user && p_context->credential.user != 0) 00110 { 00111 fsal_posixdb_cancelHandleLock(p_context->p_conn); 00112 Return(ERR_FSAL_ACCESS, 0, INDEX_FSAL_unlink); 00113 } 00114 00115 if(FSAL_IS_ERROR 00116 (status = 00117 fsal_internal_testAccess(p_context, FSAL_W_OK | FSAL_X_OK, &buffstat_parent, NULL))) 00118 { 00119 fsal_posixdb_cancelHandleLock(p_context->p_conn); 00120 Return(status.major, status.minor, INDEX_FSAL_unlink); 00121 } 00122 00123 /****************************** 00124 * DELETE FROM THE FILESYSTEM * 00125 ******************************/ 00126 TakeTokenFSCall(); 00127 /* If the object to delete is a directory, use 'rmdir' to delete the object, else use 'unlink' */ 00128 rc = (S_ISDIR(buffstat.st_mode)) ? rmdir(fsalpath.path) : unlink(fsalpath.path); 00129 errsv = errno; 00130 ReleaseTokenFSCall(); 00131 if(rc) 00132 { 00133 fsal_posixdb_cancelHandleLock(p_context->p_conn); 00134 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_unlink); 00135 } 00136 00137 /**************************** 00138 * DELETE FROM THE DATABASE * 00139 ****************************/ 00140 00141 /* We have to delete the path from the database, and the handle if the object was a directory or has no more hardlink */ 00142 statusdb = 00143 fsal_posixdb_delete(p_context->p_conn, p_parent_directory_handle, p_object_name, 00144 &info); 00145 /* After this operation, there's no need to 'fsal_posixdb_cancelHandleLock' because the transaction is ended */ 00146 switch (statusdb.major) 00147 { 00148 case ERR_FSAL_POSIXDB_NOERR: 00149 case ERR_FSAL_POSIXDB_NOENT: 00150 /* nothing to do */ 00151 break; 00152 default: 00153 if(FSAL_IS_ERROR(status = posixdb2fsal_error(statusdb))) 00154 Return(status.major, status.minor, INDEX_FSAL_unlink); 00155 } 00156 00157 /*********************** 00158 * FILL THE ATTRIBUTES * 00159 ***********************/ 00160 00161 if(p_parent_directory_attributes) 00162 { 00163 status = posix2fsal_attributes(&buffstat_parent, p_parent_directory_attributes); 00164 if(FSAL_IS_ERROR(status)) 00165 { 00166 FSAL_CLEAR_MASK(p_parent_directory_attributes->asked_attributes); 00167 FSAL_SET_MASK(p_parent_directory_attributes->asked_attributes, 00168 FSAL_ATTR_RDATTR_ERR); 00169 Return(status.major, status.minor, INDEX_FSAL_opendir); 00170 } 00171 } 00172 /* OK */ 00173 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_unlink); 00174 00175 }