/** * PVFSIOSDirHandle::Readdir_r: read a PVFS directory * * @param dst a dirent that we can fill out * @param dret we return a pointer to dst here on success, NULL on fail * @return PLFS_SUCCESS or PLFS_E* */ plfs_error_t PVFSIOSDirHandle::Readdir_r(struct dirent *dst, struct dirent **dret) { static int read_size = 32; /* we read this many entries at once */ int dowake, nev, lcv, pev; PVFS_ds_type pvtype; /* init and grab the lock so we can start the operation */ dowake = 0; nev = 0; pthread_mutex_lock(&this->poslock); /* wait for in-progress all i/o to complete */ while (this->in_io) { this->waiting = 1; pthread_cond_wait(&this->block, &this->poslock); } /* hack to make fake . and .. entries */ if (this->dot < 2) { *dret = dst; dst->d_ino = 0; dst->d_reclen = sizeof(struct dirent); dst->d_type = DT_DIR; #ifdef __linux__ dst->d_off = 0; /* XXX??? */ #endif strcpy(dst->d_name, (this->dot == 0) ? "." : ".."); this->dot++; goto done; } /* if the cache is empty and we are not atend, fill cache */ if (this->ncache == 0 && !this->atend) { this->in_io = 1; pthread_mutex_unlock(&this->poslock); memset(&this->cache, 0, sizeof(this->cache)); pev = PVFS_sys_readdirplus(this->ref, this->mydpos, read_size, &this->creds, PVFS_ATTR_SYS_TYPE, &this->cache, NULL); pthread_mutex_lock(&this->poslock); dowake = this->waiting; this->waiting = 0; this->in_io = 0; if (pev < 0) { nev = get_err(pev); goto done; } /* update our position for the next read */ this->mydpos = this->cache.token; /* check for atend, if not then load new cache */ if (this->cache.pvfs_dirent_outcount == 0) { /* check for EOD */ this->atend = 1; } else { this->cachepos = 0; this->ncache = this->cache.pvfs_dirent_outcount; } } /* loaded cache (if possible), see if we hit EOF */ if (this->atend) { /* check for end of directory */ *dret = NULL; goto done; } /* we can return an entry from the cache */ *dret = dst; dst->d_ino = this->cache.dirent_array[this->cachepos].handle; dst->d_reclen = sizeof(struct dirent); if (this->cache.stat_err_array[this->cachepos]) { dst->d_type = DT_UNKNOWN; /* we got an error */ } else { pvtype = this->cache.attr_array[this->cachepos].objtype; if (pvtype == PVFS_TYPE_METAFILE) dst->d_type = DT_REG; else if (pvtype == PVFS_TYPE_DIRECTORY) dst->d_type = DT_DIR; else if (pvtype == PVFS_TYPE_SYMLINK) dst->d_type = DT_LNK; else dst->d_type = DT_UNKNOWN; } #ifdef __linux__ dst->d_off = 0; /* XXX??? */ #endif strcpy(dst->d_name, this->cache.dirent_array[this->cachepos].d_name); this->cachepos++; /* if we used last cached item, dump cache */ if (this->ncache && this->cachepos == this->ncache) { if (this->ncache < read_size) { this->atend = 1; /* atend via short read */ } free(this->cache.dirent_array); free(this->cache.stat_err_array); for (lcv = 0 ; lcv < this->ncache ; lcv++) { PVFS_util_release_sys_attr(&this->cache.attr_array[lcv]); } free(this->cache.attr_array); memset(&this->cache, 0, sizeof(this->cache)); this->ncache = this->cachepos = 0; } done: pthread_mutex_unlock(&this->poslock); if (dowake) pthread_cond_signal(&this->block); return errno_to_plfs_error(-nev); }
int do_list( char *full_path, char *start, int fs_id, struct options *opts) { int i = 0, printed_dot_info = 0; int ret = -1; int pvfs_dirent_incount; char *name = NULL, *cur_file = NULL; PVFS_handle cur_handle; PVFS_sysresp_lookup lk_response; PVFS_sysresp_readdirplus rdplus_response; PVFS_sysresp_getattr getattr_response; PVFS_credentials credentials; PVFS_object_ref ref; PVFS_ds_position token; uint64_t dir_version = 0; double begin = 0., end; subdir *current, *head = NULL, *tail = NULL; name = start; memset(&lk_response,0,sizeof(PVFS_sysresp_lookup)); PVFS_util_gen_credentials(&credentials); if (opts->list_recursive || opts->num_starts > 1) { printf("%s%s:\n",full_path,start); } ret = PVFS_sys_lookup(fs_id, name, &credentials, &lk_response, PVFS2_LOOKUP_LINK_NO_FOLLOW, NULL); if(ret < 0) { PVFS_perror("PVFS_sys_lookup", ret); return -1; } ref.handle = lk_response.ref.handle; ref.fs_id = fs_id; pvfs_dirent_incount = MAX_NUM_DIRENTS; memset(&getattr_response,0,sizeof(PVFS_sysresp_getattr)); if (PVFS_sys_getattr(ref, PVFS_ATTR_SYS_ALL, &credentials, &getattr_response, NULL) == 0) { if ((getattr_response.attr.objtype == PVFS_TYPE_METAFILE) || (getattr_response.attr.objtype == PVFS_TYPE_SYMLINK) || ((getattr_response.attr.objtype == PVFS_TYPE_DIRECTORY) && (opts->list_directory))) { char segment[128] = {0}; PVFS_sysresp_getparent getparent_resp; PINT_remove_base_dir(name, segment, 128); if (strcmp(segment,"") == 0) { snprintf(segment,128,"/"); } if (getattr_response.attr.objtype == PVFS_TYPE_DIRECTORY) { if (PVFS_sys_getparent(ref.fs_id, name, &credentials, &getparent_resp, NULL) == 0) { print_dot_and_dot_dot_info_if_required( getparent_resp.parent_ref); } } if (opts->list_long) { print_entry_attr(ref.handle, segment, &getattr_response.attr, opts); } else { print_entry(segment, ref.handle, ref.fs_id, NULL, 0, opts); } return 0; } } if (do_timing) begin = Wtime(); token = 0; do { memset(&rdplus_response, 0, sizeof(PVFS_sysresp_readdirplus)); ret = PVFS_sys_readdirplus( ref, (!token ? PVFS_READDIR_START : token), pvfs_dirent_incount, &credentials, (opts->list_long) ? PVFS_ATTR_SYS_ALL : PVFS_ATTR_SYS_ALL_NOSIZE, &rdplus_response, NULL); if(ret < 0) { PVFS_perror("PVFS_sys_readdir", ret); return -1; } if (dir_version == 0) { dir_version = rdplus_response.directory_version; } else if (opts->list_verbose) { if (dir_version != rdplus_response.directory_version) { fprintf(stderr, "*** directory changed! listing may " "not be correct\n"); dir_version = rdplus_response.directory_version; } } if (!printed_dot_info) { /* the list_all option prints files starting with .; the almost_all option skips the '.', '..' printing */ print_dot_and_dot_dot_info_if_required(ref); printed_dot_info = 1; } for(i = 0; i < rdplus_response.pvfs_dirent_outcount; i++) { cur_file = rdplus_response.dirent_array[i].d_name; cur_handle = rdplus_response.dirent_array[i].handle; print_entry(cur_file, cur_handle, fs_id, &rdplus_response.attr_array[i], rdplus_response.stat_err_array[i], opts); PVFS_sys_attr *attr = &rdplus_response.attr_array[i]; if(attr->objtype == PVFS_TYPE_DIRECTORY && opts->list_recursive) { int path_len = strlen(start) + strlen(cur_file) + 1; current = (subdir *) malloc(sizeof(subdir)); /* Prevent duplicate slashes in path */ if(start[strlen(start)-1] == '/') { current->path = (char *) malloc(path_len); snprintf(current->path,path_len,"%s%s",start,cur_file); } else { current->path = (char *) malloc(path_len + 1); snprintf(current->path,path_len+1,"%s/%s",start,cur_file); } /* Update linked list of subdirectories to recurse */ current->next = NULL; if(!head) { head = current; tail = current; } else { tail->next = current; tail = current; } } } token = rdplus_response.token; if (rdplus_response.pvfs_dirent_outcount) { free(rdplus_response.dirent_array); rdplus_response.dirent_array = NULL; free(rdplus_response.stat_err_array); rdplus_response.stat_err_array = NULL; for (i = 0; i < rdplus_response.pvfs_dirent_outcount; i++) { if (rdplus_response.attr_array) { PVFS_util_release_sys_attr(&rdplus_response.attr_array[i]); } } free(rdplus_response.attr_array); rdplus_response.attr_array = NULL; } } while(rdplus_response.pvfs_dirent_outcount == pvfs_dirent_incount); if (do_timing) { end = Wtime(); printf("PVFS_sys_readdirplus took %g msecs\n", (end - begin)); } if (rdplus_response.pvfs_dirent_outcount) { free(rdplus_response.dirent_array); rdplus_response.dirent_array = NULL; free(rdplus_response.stat_err_array); rdplus_response.stat_err_array = NULL; for (i = 0; i < rdplus_response.pvfs_dirent_outcount; i++) { if (rdplus_response.attr_array) { PVFS_util_release_sys_attr(&rdplus_response.attr_array[i]); } } free(rdplus_response.attr_array); rdplus_response.attr_array = NULL; } if (opts->list_recursive) { current = head; while(current) { printf("\n"); do_list(full_path,current->path,fs_id,opts); current = current->next; free(head->path); free(head); head = current; } } return 0; }