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 #include "namespace.h" 00022 #include <string.h> 00023 00048 fsal_status_t FUSEFSAL_opendir(fsal_handle_t * dir_hdl, /* IN */ 00049 fsal_op_context_t * p_context, /* IN */ 00050 fsal_dir_t * dir_desc, /* OUT */ 00051 fsal_attrib_list_t * dir_attributes /* [ IN/OUT ] */ 00052 ) 00053 { 00054 int rc; 00055 char object_path[FSAL_MAX_PATH_LEN]; 00056 fusefsal_dir_t * dir_descriptor = (fusefsal_dir_t *)dir_desc; 00057 fusefsal_handle_t * dir_handle = (fusefsal_handle_t *)dir_hdl; 00058 00059 /* sanity checks 00060 * note : dir_attributes is optionnal. 00061 */ 00062 if(!dir_handle || !p_context || !dir_descriptor) 00063 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_opendir); 00064 00065 /* get the full path for this directory */ 00066 rc = NamespacePath(dir_handle->data.inode, dir_handle->data.device, dir_handle->data.validator, 00067 object_path); 00068 if(rc) 00069 Return(ERR_FSAL_STALE, rc, INDEX_FSAL_opendir); 00070 00071 memset(dir_descriptor, 0, sizeof(fsal_dir_t)); 00072 00073 /* set context for the next operation, so it can be retrieved by FS thread */ 00074 fsal_set_thread_context(p_context); 00075 00076 /* check opendir call */ 00077 00078 if(p_fs_ops->opendir) 00079 { 00080 TakeTokenFSCall(); 00081 rc = p_fs_ops->opendir(object_path, &(dir_descriptor->dir_info)); 00082 ReleaseTokenFSCall(); 00083 00084 if(rc) 00085 Return(fuse2fsal_error(rc, TRUE), rc, INDEX_FSAL_opendir); 00086 } 00087 else 00088 { 00089 /* ignoring opendir */ 00090 memset(&(dir_descriptor->dir_info), 0, sizeof(struct ganefuse_file_info)); 00091 } 00092 00093 /* fill the dir descriptor structure */ 00094 dir_descriptor->dir_handle = *dir_handle; 00095 00096 /* backup context */ 00097 dir_descriptor->context = *(fusefsal_op_context_t *)p_context; 00098 00099 /* optionaly get attributes */ 00100 if(dir_attributes) 00101 { 00102 fsal_status_t status; 00103 00104 status = FUSEFSAL_getattrs(dir_hdl, p_context, dir_attributes); 00105 00106 /* on error, we set a special bit in the mask. */ 00107 if(FSAL_IS_ERROR(status)) 00108 { 00109 FSAL_CLEAR_MASK(dir_attributes->asked_attributes); 00110 FSAL_SET_MASK(dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); 00111 } 00112 } 00113 00114 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_opendir); 00115 00116 } 00117 00118 typedef struct __fsal_dirbuff 00119 { 00120 fsal_attrib_mask_t getattr_mask; 00121 fsal_count_t nb_entries; 00122 fsal_count_t max_entries; 00123 fsal_dirent_t *p_entries; 00124 fsal_status_t status; 00125 00126 /* for filesystems that do not support readdir offset */ 00127 fsal_off_t begin_off; 00128 fsal_off_t curr_off; 00129 00130 } fsal_dirbuff_t; 00131 00132 #define INODE_TO_BE_COMPLETED ((ino_t)(-1)) 00133 00134 static void fill_dirent(fsal_dirent_t * to_be_filled, 00135 fsal_attrib_mask_t getattr_mask, 00136 const char *name, const struct stat *stbuf, off_t off) 00137 { 00138 fsal_status_t status; 00139 struct stat tmp_statbuff; 00140 int err = FALSE; 00141 fusefsal_handle_t *fill_handle = (fusefsal_handle_t *) &to_be_filled->handle; 00142 00143 if(stbuf) 00144 { 00145 if(stbuf->st_ino == 0) 00146 { 00147 LogDebug(COMPONENT_FSAL, 00148 "WARNING in fill_dirent: Filesystem doesn't provide inode numbers !!!"); 00149 } 00150 00151 fill_handle->data.inode = stbuf->st_ino; 00152 fill_handle->data.device = stbuf->st_dev; 00153 FSAL_str2name(name, strlen(name) + 1, &(to_be_filled->name)); 00154 ((fusefsal_cookie_t *) &to_be_filled->cookie)->data = off; 00155 00156 /* local copy for non "const" calls */ 00157 tmp_statbuff = *stbuf; 00158 00159 /* set attributes */ 00160 to_be_filled->attributes.asked_attributes = getattr_mask; 00161 status = posix2fsal_attributes(&tmp_statbuff, &to_be_filled->attributes); 00162 00163 LogFullDebug(COMPONENT_FSAL, 00164 "getattr_mask = %X, recupere = %X, status=%d, inode=%llX.%llu, type=%d, posixmode=%#o, mode=%#o", 00165 (unsigned int)getattr_mask, (unsigned int)to_be_filled->attributes.asked_attributes, status.major, 00166 to_be_filled->attributes.fsid.major, to_be_filled->attributes.fileid, 00167 to_be_filled->attributes.type, tmp_statbuff.st_mode, 00168 to_be_filled->attributes.mode); 00169 00170 if(FSAL_IS_ERROR(status)) 00171 { 00172 FSAL_CLEAR_MASK(to_be_filled->attributes.asked_attributes); 00173 /* set getattr error bit in attr mask */ 00174 FSAL_SET_MASK(to_be_filled->attributes.asked_attributes, FSAL_ATTR_RDATTR_ERR); 00175 err = TRUE; 00176 } 00177 } 00178 00179 /* if any error occured during conversion, 00180 * or if values seem to be inconsistent, 00181 * proceed a lookup afterward */ 00182 00183 if(!stbuf 00184 || (stbuf->st_ino == 0) 00185 || err 00186 || to_be_filled->attributes.type == (fsal_nodetype_t) - 1 00187 || to_be_filled->attributes.mode == 0 || to_be_filled->attributes.numlinks == 0) 00188 { 00189 FSAL_CLEAR_MASK(to_be_filled->attributes.asked_attributes); 00190 /* we only known entry name, we tag it for a later lookup. 00191 */ 00192 fill_handle->data.inode = INODE_TO_BE_COMPLETED; 00193 FSAL_str2name(name, strlen(name) + 1, &(to_be_filled->name)); 00194 ((fusefsal_cookie_t *) &to_be_filled->cookie)->data = off; 00195 } 00196 00197 } /* fill_dirent */ 00198 00199 /* this function is used by FUSE dir reader to fill the output buffer */ 00200 00201 static int ganefuse_fill_dir(void *buf, const char *name, 00202 const struct stat *stbuf, off_t off) 00203 { 00204 fsal_dirbuff_t *dirbuff = (fsal_dirbuff_t *) buf; 00205 fsal_dirent_t *tab; 00206 unsigned int i; 00207 00208 if(!dirbuff) 00209 return 1; 00210 00211 /* missing name parameter */ 00212 if(!name) 00213 { 00214 dirbuff->status.major = ERR_FSAL_INVAL; 00215 dirbuff->status.minor = 0; 00216 return 1; 00217 } 00218 00219 /* if this is . or .., ignore */ 00220 if(!strcmp(name, ".") || !strcmp(name, "..")) 00221 return 0; 00222 00223 /* full output buffer */ 00224 if(dirbuff->nb_entries == dirbuff->max_entries) 00225 { 00226 /* should not have been called */ 00227 dirbuff->status.major = ERR_FSAL_SERVERFAULT; 00228 dirbuff->status.minor = 0; 00229 return 1; 00230 } 00231 00232 tab = dirbuff->p_entries; 00233 00234 /* offset is provided */ 00235 if(off) 00236 { 00237 i = dirbuff->nb_entries; 00238 fill_dirent(&(tab[i]), dirbuff->getattr_mask, name, stbuf, off); 00239 } 00240 else 00241 { 00242 /* no offset is provided, we must skip some entries */ 00243 00244 if(dirbuff->curr_off < dirbuff->begin_off) 00245 { 00246 /* skip entry and go to the next */ 00247 dirbuff->curr_off++; 00248 return 0; 00249 } 00250 00251 /* entry is to be added */ 00252 dirbuff->curr_off++; 00253 00254 i = dirbuff->nb_entries; 00255 fill_dirent(&(tab[i]), dirbuff->getattr_mask, name, stbuf, dirbuff->curr_off); 00256 } 00257 00258 dirbuff->nb_entries++; 00259 00260 if(dirbuff->nb_entries == dirbuff->max_entries) 00261 return 1; 00262 else 00263 return 0; 00264 } 00265 00266 /* this function is used by filesystems binded to old version of FUSE 00267 * that use getdir() instead of readdir(). 00268 */ 00269 static int ganefuse_dirfil_old(ganefuse_dirh_t h, const char *name, int type, ino_t ino) 00270 { 00271 return ganefuse_fill_dir((void *)h, name, NULL, 0); 00272 } 00273 00309 fsal_status_t FUSEFSAL_readdir(fsal_dir_t * dir_desc, /* IN */ 00310 fsal_cookie_t start_position, /* IN */ 00311 fsal_attrib_mask_t get_attr_mask, /* IN */ 00312 fsal_mdsize_t buffersize, /* IN */ 00313 fsal_dirent_t * pdirent, /* OUT */ 00314 fsal_cookie_t * end_position, /* OUT */ 00315 fsal_count_t * nb_entries, /* OUT */ 00316 fsal_boolean_t * end_of_dir /* OUT */ 00317 ) 00318 { 00319 int rc; 00320 char dir_path[FSAL_MAX_PATH_LEN]; 00321 fsal_dirbuff_t reqbuff; 00322 unsigned int i; 00323 fsal_status_t st; 00324 fusefsal_dir_t * dir_descriptor = (fusefsal_dir_t *)dir_desc; 00325 00326 /* sanity checks */ 00327 00328 if(!dir_descriptor || !pdirent || !end_position || !nb_entries || !end_of_dir) 00329 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readdir); 00330 00331 /* get the full path for dir inode */ 00332 rc = NamespacePath(dir_descriptor->dir_handle.data.inode, 00333 dir_descriptor->dir_handle.data.device, 00334 dir_descriptor->dir_handle.data.validator, dir_path); 00335 if(rc) 00336 Return(ERR_FSAL_STALE, rc, INDEX_FSAL_readdir); 00337 00338 if(!p_fs_ops->readdir && !p_fs_ops->getdir) 00339 Return(ERR_FSAL_NOTSUPP, 0, INDEX_FSAL_readdir); 00340 00341 /* set context so it can be retrieved by FS */ 00342 fsal_set_thread_context((fsal_op_context_t *) &dir_descriptor->context); 00343 00344 /* prepare reaadir structure */ 00345 00346 reqbuff.getattr_mask = get_attr_mask; 00347 reqbuff.nb_entries = 0; 00348 reqbuff.max_entries = (buffersize / sizeof(fsal_dirent_t)); 00349 reqbuff.p_entries = pdirent; 00350 reqbuff.status.major = 0; 00351 reqbuff.status.minor = 0; 00352 memcpy( (char *)&reqbuff.begin_off, (char *)&start_position.data, sizeof( off_t ) ) ; 00353 reqbuff.curr_off = 0 ; 00354 00355 TakeTokenFSCall(); 00356 00357 if(p_fs_ops->readdir) 00358 rc = p_fs_ops->readdir(dir_path, (void *)&reqbuff, ganefuse_fill_dir, 00359 (off_t)start_position.data, &dir_descriptor->dir_info); 00360 else 00361 rc = p_fs_ops->getdir(dir_path, (ganefuse_dirh_t) & reqbuff, ganefuse_dirfil_old); 00362 00363 ReleaseTokenFSCall(); 00364 00365 if(rc) 00366 Return(fuse2fsal_error(rc, TRUE), rc, INDEX_FSAL_readdir); 00367 else if(FSAL_IS_ERROR(reqbuff.status)) 00368 Return(reqbuff.status.major, reqbuff.status.minor, INDEX_FSAL_readdir); 00369 00370 /* if no entry found */ 00371 00372 if(reqbuff.nb_entries == 0) 00373 { 00374 *end_position = start_position; 00375 *end_of_dir = TRUE; 00376 *nb_entries = 0; 00377 00378 LogFullDebug(COMPONENT_FSAL, "No entries found"); 00379 00380 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir); 00381 } 00382 00383 /* at least 1 entry found */ 00384 00385 /* we must do some operations on the final dirent array: 00386 * - chaining entries together 00387 * - if the filesystem did not provide stat buffers, 00388 * we must do lookup operations. 00389 * - adding dir entries to namespace 00390 */ 00391 00392 for(i = 0; i < reqbuff.nb_entries; i++) 00393 { 00394 /* 1) chaining entries together */ 00395 00396 if(i == reqbuff.nb_entries - 1) 00397 { /* last entry */ 00398 pdirent[i].nextentry = NULL; 00399 *end_position = pdirent[i].cookie; 00400 } 00401 else 00402 pdirent[i].nextentry = &(pdirent[i + 1]); 00403 00404 /* 2) check weither the filesystem provided stat buff */ 00405 00406 if(((fusefsal_handle_t *) &pdirent[i].handle)->data.inode == INODE_TO_BE_COMPLETED) 00407 { 00408 /* If not, make a lookup operation for this entry. 00409 * (this with automatically add it to namespace) */ 00410 00411 pdirent[i].attributes.asked_attributes = get_attr_mask; 00412 00413 LogFullDebug(COMPONENT_FSAL, "Inode to be completed"); 00414 00415 st = FUSEFSAL_lookup((fsal_handle_t *) &dir_descriptor->dir_handle, 00416 &pdirent[i].name, 00417 (fsal_op_context_t *) &dir_descriptor->context, 00418 &pdirent[i].handle, &pdirent[i].attributes); 00419 00420 if(FSAL_IS_ERROR(st)) 00421 Return(st.major, st.minor, INDEX_FSAL_readdir); 00422 } 00423 else 00424 { 00425 /* 3) just add entry to namespace except for '.' and '..' 00426 * Also set a validator for this entry. 00427 */ 00428 00429 if(strcmp(pdirent[i].name.name, ".") && strcmp(pdirent[i].name.name, "..")) 00430 { 00431 LogFullDebug(COMPONENT_FSAL, "adding entry to namespace: %lX.%ld %s", 00432 ((fusefsal_handle_t *) &pdirent[i].handle)->data.device, 00433 ((fusefsal_handle_t *) &pdirent[i].handle)->data.inode, pdirent[i].name.name); 00434 00435 ((fusefsal_handle_t *) &pdirent[i].handle)->data.validator = pdirent[i].attributes.ctime.seconds; 00436 00437 NamespaceAdd(dir_descriptor->dir_handle.data.inode, 00438 dir_descriptor->dir_handle.data.device, 00439 dir_descriptor->dir_handle.data.validator, 00440 pdirent[i].name.name, 00441 ((fusefsal_handle_t *) &pdirent[i].handle)->data.inode, 00442 ((fusefsal_handle_t *) &pdirent[i].handle)->data.device, 00443 &(((fusefsal_handle_t *) &pdirent[i].handle)->data.validator)); 00444 } 00445 } 00446 00447 } 00448 00449 /* end of dir was reached if not enough entries were provided */ 00450 *end_of_dir = (reqbuff.nb_entries < reqbuff.max_entries); 00451 *nb_entries = reqbuff.nb_entries; 00452 00453 LogFullDebug(COMPONENT_FSAL, "EOD = %d", *end_of_dir); 00454 00455 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir); 00456 00457 } 00458 00472 fsal_status_t FUSEFSAL_closedir(fsal_dir_t * dir_desc /* IN */ 00473 ) 00474 { 00475 00476 int rc; 00477 char dir_path[FSAL_MAX_PATH_LEN]; 00478 fusefsal_dir_t * dir_descriptor = (fusefsal_dir_t *)dir_desc; 00479 00480 /* sanity checks */ 00481 if(!dir_descriptor) 00482 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_closedir); 00483 00484 /* get the full path for dir inode */ 00485 rc = NamespacePath(dir_descriptor->dir_handle.data.inode, 00486 dir_descriptor->dir_handle.data.device, 00487 dir_descriptor->dir_handle.data.validator, dir_path); 00488 if(rc) 00489 Return(ERR_FSAL_STALE, rc, INDEX_FSAL_closedir); 00490 00491 if(!p_fs_ops->releasedir) 00492 /* ignore this call */ 00493 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_closedir); 00494 00495 /* set context so it can be retrieved by FS */ 00496 fsal_set_thread_context((fsal_op_context_t *) &dir_descriptor->context); 00497 00498 /* release the resources used for reading directory */ 00499 00500 TakeTokenFSCall(); 00501 00502 rc = p_fs_ops->releasedir(dir_path, &dir_descriptor->dir_info); 00503 00504 ReleaseTokenFSCall(); 00505 00506 if(rc) 00507 Return(fuse2fsal_error(rc, TRUE), rc, INDEX_FSAL_closedir); 00508 00509 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_closedir); 00510 00511 }