Exemplo n.º 1
0
/**
 * PVFSIOStore::Readlink:  read symbolic link
 *
 * @param link the link to read
 * @param buf the place the write the result
 * @param the size of the result buffer
 * @param readlen return size
 * @return PLFS_SUCCESS or PLFS_E* on error
 */
plfs_error_t PVFSIOStore::Readlink(const char *link, char *buf, size_t bufsize,
                                   ssize_t *readlen) {
    char *cpath;
    PVFS_object_ref ref;
    PVFS_credentials creds;
    size_t l;
    int nev, pev, cpy;
    PVFS_sysresp_getattr resp;

    cpath = pvfsios_dedup_slash(link);
    if (cpath) {
        nev = pvfsios_get_object(this->fsid, cpath, &ref, &creds,
                                 PVFS2_LOOKUP_LINK_NO_FOLLOW);
        free(cpath);
    } else {
        nev = -ENOMEM;
    }
    
    *readlen = -1;
    if (nev < 0) {
        return errno_to_plfs_error(-nev);
    }
    
    pev = PVFS_sys_getattr(ref, PVFS_ATTR_SYS_ALL_NOHINT, &creds, &resp);
    if (pev < 0) {
        return errno_to_plfs_error(-get_err(pev));
    }

    if (resp.attr.objtype != PVFS_TYPE_SYMLINK) {
        nev = -EINVAL;
    } else {
        l = strlen(resp.attr.link_target);
        cpy = (l < bufsize - 1) ? l : bufsize;
        memcpy(buf, resp.attr.link_target, cpy);
        buf[cpy] = 0;
        *readlen = l;   /* need to return length */
        /* nev still zero from get_obj call, no need to reset */
    }

    /* XXX: pvfs2fuse didn't release, memory leak? */
    PVFS_util_release_sys_attr(&resp.attr);  /* frees memory chained off ats */

    return errno_to_plfs_error(-nev);
}
Exemplo n.º 2
0
/**
 * PVFSIOSDirHandle::~PVFSIOSDirHandle: destruction
 */
PVFSIOSDirHandle::~PVFSIOSDirHandle() {
    int lcv;
    if (this->ncache) {
        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);
    }
    if (this->locklvl) {
        pthread_mutex_destroy(&this->poslock);
        this->locklvl--;
    }
    if (this->locklvl) {
        pthread_cond_destroy(&this->block);
        this->locklvl--;
    }
}
Exemplo n.º 3
0
/**
 * PVFSIOStore::Access: permission check
 *
 * @param path the path we are checking
 * @param mode the mode to check
 * @return PLFS_SUCCESS or PLFS_E* on error
 */
plfs_error_t PVFSIOStore::Access(const char* path, int mode)
{
    char *cpath;
    PVFS_object_ref ref;
    PVFS_credentials creds;
    int nev, pev;
    PVFS_sysresp_getattr rep;
    PVFS_uid auid;
    PVFS_gid agid;
    PVFS_permissions aperms;

    cpath = pvfsios_dedup_slash(path);
    if (cpath) {
        nev = pvfsios_get_object(this->fsid, cpath, &ref, &creds,
                                 PVFS2_LOOKUP_LINK_FOLLOW);
        free(cpath);
    } else {
        nev = -ENOMEM;
    }
    if (nev < 0) {
        return errno_to_plfs_error(-nev);
    }
    
    /* root or exist check */
    if (creds.uid == 0 || mode == F_OK) {
        return PLFS_SUCCESS;
    }
    
    pev = PVFS_sys_getattr(ref, PVFS_ATTR_SYS_ALL_NOHINT, &creds, &rep);
    if (pev < 0) {
        return errno_to_plfs_error(get_err(pev));
    }

#if 0
    /*
     * XXXCDC: we'd really like to call PINT_check_mode, but libpvfs2
     * includes don't provide a prototype for it even though it is
     * present in the lib.  does that mean it is a private interface?
     */
    pev = PINT_check_mode(&rep.attr, creds.uid, credis.gid, 0);
    PVFS_util_release_sys_attr(&rep.attr);  /* frees memory chained off ats */
    return(get_err(pev));
#endif
    
    /*
     * XXX: pvfs2fuse doesn't call PVFS_util_release_sys_attr on
     * repl.attr for access.  this seems like a memory leak mistake to
     * me.
     */
    auid = rep.attr.owner;
    agid = rep.attr.group;
    aperms = rep.attr.perms;
    PVFS_util_release_sys_attr(&rep.attr);  /* frees memory chained off ats */

    if (auid == creds.uid) {
        if ((mode & R_OK) && (aperms & PVFS_U_READ))
            return PLFS_SUCCESS;
        if ((mode & W_OK) && (aperms & PVFS_U_WRITE))
            return PLFS_SUCCESS;
        if ((mode & X_OK) && (aperms & PVFS_U_EXECUTE))
            return PLFS_SUCCESS;
    }
    /* XXXCDC: doesn't check group list, e.g. getgroups() */
    if (agid == creds.gid) {
        if ((mode & R_OK) && (aperms & PVFS_G_READ))
            return PLFS_SUCCESS;
        if ((mode & W_OK) && (aperms & PVFS_G_WRITE))
            return PLFS_SUCCESS;
        if ((mode & X_OK) && (aperms & PVFS_G_EXECUTE))
            return PLFS_SUCCESS;
    }
    if ((mode & R_OK) && (aperms & PVFS_O_READ))
        return PLFS_SUCCESS;
    if ((mode & W_OK) && (aperms & PVFS_O_WRITE))
        return PLFS_SUCCESS;
    if ((mode & X_OK) && (aperms & PVFS_O_EXECUTE))
        return PLFS_SUCCESS;

    return PLFS_EACCES;
}
Exemplo n.º 4
0
/**
 * pvfsios_object_stat: stat a pvfs object
 *
 * @param rp the object to state
 * @param cp the creds used to do the stat
 * @param stb the stat buffer to fill out
 * @return 0 or -err
 */
static int pvfsios_object_stat(PVFS_object_ref *rp, PVFS_credentials *cp,
                               struct stat *stb) {
    PVFS_sysresp_getattr reply;
    PVFS_sys_attr *ats;
    int pev, m;

    memset(stb, 0, sizeof(*stb));
    memset(&reply, 0, sizeof(reply));

    /* do the RPC */
    pev = PVFS_sys_getattr(*rp, PVFS_ATTR_SYS_ALL_NOHINT, cp, &reply);
    if (pev != 0) {
        return(get_err(pev));
    }

    ats = &reply.attr;

    /* set st_blocks, st_size and type bits of st_mode */
    switch (ats->objtype) {
    case PVFS_TYPE_METAFILE:   /* a file */
        stb->st_mode |= S_IFREG;
        if (ats->mask & PVFS_ATTR_SYS_SIZE) {
            stb->st_size = ats->size;
            stb->st_blocks = (((ats->size + 4095)/4096)*4096)/512;
        }
        break;
    case PVFS_TYPE_SYMLINK:
        stb->st_mode |= S_IFLNK;
        if (ats->link_target)
            stb->st_size = strlen(ats->link_target);
        break;
    case PVFS_TYPE_DIRECTORY:
        stb->st_mode |= S_IFDIR;
        break;
    default:
        /* just leave the values at zero */
        break;
    }

    stb->st_nlink = 1;
    stb->st_uid = ats->owner;
    stb->st_gid = ats->group;
    stb->st_atime = ats->atime;
    stb->st_mtime = ats->mtime;
    stb->st_ctime = ats->ctime;
    
    m = 0;   /* yuck */
    if (ats->perms & PVFS_O_EXECUTE)
        m |= S_IXOTH;
    if (ats->perms & PVFS_O_WRITE)
        m |= S_IWOTH;
    if (ats->perms & PVFS_O_READ)
        m |= S_IROTH;
    
    if (ats->perms & PVFS_G_EXECUTE)
        m |= S_IXGRP;
    if (ats->perms & PVFS_G_WRITE)
        m |= S_IWGRP;
    if (ats->perms & PVFS_G_READ)
        m |= S_IRGRP;

    if (ats->perms & PVFS_U_EXECUTE)
        m |= S_IXUSR;
    if (ats->perms & PVFS_U_WRITE)
        m |= S_IWUSR;
    if (ats->perms & PVFS_U_READ)
        m |= S_IRUSR;

    if (ats->perms & PVFS_G_SGID)
        m |= S_ISGID;
    if (ats->perms & PVFS_U_SUID)
        m |= S_ISUID;

    stb->st_mode |= m;

    stb->st_dev = rp->fs_id;
    stb->st_ino = rp->handle;
    stb->st_rdev = 0;
    stb->st_blksize = 4096;

    PVFS_util_release_sys_attr(ats);  /* frees memory chained off ats */
    return(0);
}
Exemplo n.º 5
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);
}
Exemplo n.º 6
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;
}