示例#1
0
/**
 * 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);
}
示例#2
0
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;
}