nfs-ganesha 1.4
|
00001 /* 00002 * vim:expandtab:shiftwidth=4:tabstop=4: 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/access_check.h" 00021 #include "fsal_convert.h" 00022 #include <string.h> 00023 00044 fsal_status_t VFSFSAL_opendir(fsal_handle_t * p_dir_handle, /* IN */ 00045 fsal_op_context_t * p_context, /* IN */ 00046 fsal_dir_t * dir_desc, /* OUT */ 00047 fsal_attrib_list_t * p_dir_attributes /* [ IN/OUT ] */ 00048 ) 00049 { 00050 vfsfsal_dir_t * p_dir_descriptor = (vfsfsal_dir_t *) dir_desc; 00051 int rc, errsv; 00052 fsal_status_t status; 00053 00054 struct stat buffstat; 00055 00056 /* sanity checks 00057 * note : dir_attributes is optionnal. 00058 */ 00059 if(!p_dir_handle || !p_context || !p_dir_descriptor) 00060 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_opendir); 00061 00062 /* get the path of the directory */ 00063 TakeTokenFSCall(); 00064 status = 00065 fsal_internal_handle2fd(p_context, p_dir_handle, &p_dir_descriptor->fd, 00066 O_RDONLY | O_DIRECTORY); 00067 ReleaseTokenFSCall(); 00068 00069 if(FSAL_IS_ERROR(status)) 00070 ReturnStatus(status, INDEX_FSAL_opendir); 00071 00072 /* get directory metadata */ 00073 TakeTokenFSCall(); 00074 rc = fstat(p_dir_descriptor->fd, &buffstat); 00075 errsv = errno; 00076 ReleaseTokenFSCall(); 00077 00078 if(rc != 0) 00079 { 00080 close(p_dir_descriptor->fd); 00081 if(errsv == ENOENT) 00082 Return(ERR_FSAL_STALE, errsv, INDEX_FSAL_opendir); 00083 else 00084 Return(posix2fsal_error(errsv), errsv, INDEX_FSAL_opendir); 00085 } 00086 00087 /* Test access rights for this directory */ 00088 status = fsal_check_access(p_context, FSAL_R_OK, &buffstat, NULL); 00089 if(FSAL_IS_ERROR(status)) 00090 ReturnStatus(status, INDEX_FSAL_opendir); 00091 00092 /* if everything is OK, fills the dir_desc structure : */ 00093 00094 memcpy(&(p_dir_descriptor->context), p_context, sizeof(vfsfsal_op_context_t)); 00095 memcpy(&(p_dir_descriptor->handle), p_dir_handle, sizeof(vfsfsal_handle_t)); 00096 00097 if(p_dir_attributes) 00098 { 00099 status = posix2fsal_attributes(&buffstat, p_dir_attributes); 00100 if(FSAL_IS_ERROR(status)) 00101 { 00102 FSAL_CLEAR_MASK(p_dir_attributes->asked_attributes); 00103 FSAL_SET_MASK(p_dir_attributes->asked_attributes, FSAL_ATTR_RDATTR_ERR); 00104 } 00105 } 00106 00107 p_dir_descriptor->dir_offset = 0; 00108 00109 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_opendir); 00110 00111 } 00112 00147 struct linux_dirent 00148 { 00149 long d_ino; 00150 long d_off; /* Be careful, SYS_getdents is a 32 bits call */ 00151 unsigned short d_reclen; 00152 char d_name[]; 00153 }; 00154 00155 #define BUF_SIZE 1024 00156 00157 fsal_status_t VFSFSAL_readdir(fsal_dir_t * dir_descriptor, /* IN */ 00158 fsal_cookie_t startposition, /* IN */ 00159 fsal_attrib_mask_t get_attr_mask, /* IN */ 00160 fsal_mdsize_t buffersize, /* IN */ 00161 fsal_dirent_t * p_pdirent, /* OUT */ 00162 fsal_cookie_t * end_position, /* OUT */ 00163 fsal_count_t * p_nb_entries, /* OUT */ 00164 fsal_boolean_t * p_end_of_dir /* OUT */ 00165 ) 00166 { 00167 vfsfsal_dir_t * p_dir_descriptor = (vfsfsal_dir_t * ) dir_descriptor; 00168 vfsfsal_cookie_t start_position; 00169 vfsfsal_cookie_t * p_end_position = (vfsfsal_cookie_t *) end_position; 00170 fsal_status_t st; 00171 fsal_count_t max_dir_entries; 00172 fsal_name_t entry_name; 00173 char buff[BUF_SIZE]; 00174 struct linux_dirent *dp = NULL; 00175 int bpos = 0; 00176 00177 struct stat buffstat; 00178 00179 int rc = 0; 00180 00181 memset(buff, 0, BUF_SIZE); 00182 memset(&entry_name, 0, sizeof(fsal_name_t)); 00183 00184 /*****************/ 00185 /* sanity checks */ 00186 /*****************/ 00187 00188 if(!p_dir_descriptor || !p_pdirent || !p_end_position || !p_nb_entries || !p_end_of_dir) 00189 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_readdir); 00190 00191 max_dir_entries = (buffersize / sizeof(fsal_dirent_t)); 00192 00193 /***************************/ 00194 /* seek into the directory */ 00195 /***************************/ 00196 start_position.data.cookie = *((off_t*) &startposition.data); 00197 rc = errno = 0; 00198 lseek(p_dir_descriptor->fd, start_position.data.cookie, SEEK_SET); 00199 rc = errno; 00200 00201 if(rc) 00202 Return(posix2fsal_error(rc), rc, INDEX_FSAL_readdir); 00203 00204 /************************/ 00205 /* browse the directory */ 00206 /************************/ 00207 00208 *p_nb_entries = 0; 00209 while(*p_nb_entries < max_dir_entries) 00210 { 00211 /***********************/ 00212 /* read the next entry */ 00213 /***********************/ 00214 TakeTokenFSCall(); 00215 rc = syscall(SYS_getdents, p_dir_descriptor->fd, buff, BUF_SIZE); 00216 ReleaseTokenFSCall(); 00217 if(rc < 0) 00218 { 00219 rc = errno; 00220 Return(posix2fsal_error(rc), rc, INDEX_FSAL_readdir); 00221 } 00222 /* End of directory */ 00223 if(rc == 0) 00224 { 00225 *p_end_of_dir = 1; 00226 break; 00227 } 00228 00229 /***********************************/ 00230 /* Get information about the entry */ 00231 /***********************************/ 00232 00233 for(bpos = 0; bpos < rc;) 00234 { 00235 dp = (struct linux_dirent *)(buff + bpos); 00236 00237 bpos += dp->d_reclen; 00238 00239 if(!(*p_nb_entries < max_dir_entries)) 00240 break; 00241 00242 /* skip . and .. */ 00243 if(!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 00244 continue; 00245 00246 /* build the full path of the file into "fsalpath */ 00247 if(FSAL_IS_ERROR 00248 (st = 00249 FSAL_str2name(dp->d_name, FSAL_MAX_NAME_LEN, 00250 &(p_pdirent[*p_nb_entries].name)))) 00251 ReturnStatus(st, INDEX_FSAL_readdir); 00252 00253 00254 // TODO: there is a race here, because between handle fetch 00255 // and open at things might change. we need to figure out if there 00256 // is another way to open without the pcontext 00257 00258 strncpy(entry_name.name, dp->d_name, sizeof(entry_name.name)); 00259 entry_name.len = strlen(entry_name.name); 00260 00261 /* get object handle */ 00262 TakeTokenFSCall(); 00263 00264 00265 if(fstatat(p_dir_descriptor->fd, dp->d_name, &buffstat, AT_SYMLINK_NOFOLLOW) < 0 ) 00266 { 00267 ReleaseTokenFSCall(); 00268 Return(posix2fsal_error(errno), errno, INDEX_FSAL_readdir); 00269 } 00270 00271 st = fsal_internal_get_handle_at( p_dir_descriptor->fd, dp->d_name, 00272 &p_pdirent[*p_nb_entries].handle) ; 00273 if(FSAL_IS_ERROR(st)) 00274 { 00275 ReleaseTokenFSCall(); 00276 ReturnStatus(st, INDEX_FSAL_readdir); 00277 } 00278 p_pdirent[*p_nb_entries].attributes.asked_attributes = get_attr_mask; 00279 00280 st = posix2fsal_attributes(&buffstat, &p_pdirent[*p_nb_entries].attributes); 00281 if(FSAL_IS_ERROR(st)) 00282 { 00283 ReleaseTokenFSCall(); 00284 FSAL_CLEAR_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes); 00285 FSAL_SET_MASK(p_pdirent[*p_nb_entries].attributes.asked_attributes, 00286 FSAL_ATTR_RDATTR_ERR); 00287 ReturnStatus(st, INDEX_FSAL_getattrs); 00288 } 00289 00290 ReleaseTokenFSCall(); 00291 00292 //p_pdirent[*p_nb_entries].cookie.cookie = dp->d_off; 00293 ((vfsfsal_cookie_t *) (&p_pdirent[*p_nb_entries].cookie))->data.cookie = dp->d_off; 00294 p_pdirent[*p_nb_entries].nextentry = NULL; 00295 if(*p_nb_entries) 00296 p_pdirent[*p_nb_entries - 1].nextentry = &(p_pdirent[*p_nb_entries]); 00297 00298 //(*p_end_position) = p_pdirent[*p_nb_entries].cookie; 00299 memcpy((char *)p_end_position, (char *)&p_pdirent[*p_nb_entries].cookie, 00300 sizeof(vfsfsal_cookie_t)); 00301 00302 (*p_nb_entries)++; 00303 00304 } /* for */ 00305 } /* While */ 00306 00307 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_readdir); 00308 00309 } 00310 00322 fsal_status_t VFSFSAL_closedir(fsal_dir_t * p_dir_desc /* IN */ 00323 ) 00324 { 00325 vfsfsal_dir_t * p_dir_descriptor = (vfsfsal_dir_t *)p_dir_desc; 00326 int rc; 00327 00328 /* sanity checks */ 00329 if(!p_dir_descriptor) 00330 Return(ERR_FSAL_FAULT, 0, INDEX_FSAL_closedir); 00331 00332 rc = close(p_dir_descriptor->fd); 00333 if(rc != 0) 00334 Return(posix2fsal_error(errno), errno, INDEX_FSAL_closedir); 00335 00336 /* fill dir_descriptor with zeros */ 00337 memset(p_dir_descriptor, 0, sizeof(vfsfsal_dir_t)); 00338 00339 Return(ERR_FSAL_NO_ERROR, 0, INDEX_FSAL_closedir); 00340 00341 }