/* This, and hence fuse_reply, are called on a different thread to the one the * request came in on. This doesn't seem to matter. */ static void chunk_done (void *read_ctxt, int rc, size_t size) { read_context_t *ctxt = (read_context_t *)read_ctxt; if (size != ctxt->size) { read_trace("bytes read != request size => EOF / error\n"); } /* As a result of this read() operation we can say certain things * about the direntry. These professions can be made with confidence * because we've just performed an actual network transaction, so * our information is "live": * - If we actually read data from the file then it definitely still * exists, now. * - If we tried to read from it and found it didn't exist, then it * definitely doesn't exist any more. * - Any other error doesn't give enough info. */ if (!rc) { direntry_still_exists(ctxt->de); } else if (rc == ENOENT) { direntry_no_longer_exists(ctxt->de); } if (!rc) { assert(!fuse_reply_buf(ctxt->req, ctxt->buf, size)); } else { assert(!fuse_reply_err(ctxt->req, rc)); } direntry_delete(CALLER_INFO ctxt->de); free(ctxt->buf); free(read_ctxt); }
static void serve_read(fuse_req_t req, fuse_ino_t fuse_ino, size_t size, off_t off, struct fuse_file_info * fi) { fdesc_t * fdesc = fi_get_fdesc(fi); uint32_t offset = off; char * buf; int r; Dprintf("%s(ino = %lu, fdesc = %p, size = %u, off = %lld)\n", __FUNCTION__, fuse_ino, fdesc, size, off); if (offset != off) { fprintf(stderr, "%s:%d: fstitchd offset not able to satisfy request for %lld\n", __FILE__, __LINE__, off); r = fuse_reply_err(req, EINVAL); fuse_reply_assert(!r); return; } buf = malloc(size); assert(buf); r = CALL(reqcfs(req), read, fdesc, NULL, buf, off, size); if (r <= 0) { // TODO: handle EOF? r = fuse_reply_buf(req, NULL, 0); fuse_reply_assert(!r); return; } r = fuse_reply_buf(req, buf, r); free(buf); assert(r >= 0); return; }
static int reply_buf_limited(fuse_req_t req, const char *buf, size_t bufsize, off_t off, size_t maxsize) { if (off < bufsize) return fuse_reply_buf(req, buf + off, min(bufsize - off, maxsize)); else return fuse_reply_buf(req, NULL, 0); }
static void sqfs_ll_op_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, size_t size #ifdef FUSE_XATTR_POSITION , uint32_t position #endif ) { sqfs_ll_i lli; char *buf = NULL; size_t real = size; #ifdef FUSE_XATTR_POSITION if (position != 0) { /* We don't support resource forks */ fuse_reply_err(req, EINVAL); return; } #endif if (sqfs_ll_iget(req, &lli, ino)) return; if (!(buf = malloc(size))) fuse_reply_err(req, ENOMEM); else if (sqfs_xattr_lookup(&lli.ll->fs, &lli.inode, name, buf, &real)) fuse_reply_err(req, EIO); else if (real == 0) fuse_reply_err(req, sqfs_enoattr()); else if (size == 0) fuse_reply_xattr(req, real); else if (size < real) fuse_reply_err(req, ERANGE); else fuse_reply_buf(req, buf, real); free(buf); }
static void overlay_readdirplus(fuse_req_t req, size_t size, off_t offset, struct workspace_dh_struct *dh) { if (dh->mode & _WORKSPACE_READDIR_MODE_FINISH) { fuse_reply_buf(req, NULL, 0); } else { struct overlay_readdir_struct *overlay_readdir=(struct overlay_readdir_struct *)dh->handle.data; if (overlay_readdir->mode & _FW_READDIR_MODE_VIRTUAL) { overlay_readdirplus_virtual(req, size, offset, dh); } else if (overlay_readdir->mode & _FW_READDIR_MODE_SIMPLE) { overlay_readdirplus_simple(req, size, offset, dh); } else if (overlay_readdir->mode & _FW_READDIR_MODE_FULL) { overlay_readdirplus_full(req, size, offset, dh); } } }
void hsx_fuse_readdir_plus(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { struct hsfs_readdir_ctx *saved_ctx, *ctx = NULL; struct hsfs_inode *parent; struct hsfs_super *sb; size_t res, len = 0; char * buf; int err, count = 0; DEBUG_IN("P_I(%lu), Size(%lld), Off(0x%llx)", ino, size, off); (void)fi; sb = fuse_req_userdata(req); FUSE_ASSERT(sb != NULL); parent = hsfs_ilookup(sb, ino); FUSE_ASSERT(parent != NULL); err = hsi_nfs3_readdir_plus(parent, size, off, &ctx, size); if(err) goto out1; saved_ctx = ctx; buf = (char *) malloc(size); if( NULL == buf){ err = ENOMEM; goto out2; } while(ctx != NULL){ struct fuse_entry_param e; hsx_fuse_fill_reply(ctx->inode, &e); res = fuse_add_direntry_plus(req, buf + len, size - len, ctx->name, &e, ctx->off); if(res > size - len) break; else if (res == size - len){ ctx = ctx->next; break; } count++; hsx_fuse_ref_inc(ctx->inode, 1); len += res; ctx = ctx->next; } if (!err) fuse_reply_buf(req, buf, len); free(buf); out2: __free_ctx(saved_ctx, 0); out1: if(err) fuse_reply_err(req, err); DEBUG_OUT("with %d, %d entries returned", err, count); return; }
void blob_ll_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { blob_mirror_t *lm = (blob_mirror_t *)fi->fh; char *buf; boost::uint64_t read_size = lm->read(size, off, buf); fuse_reply_buf(req, buf, read_size); }
static void serve_readdir(fuse_req_t req, fuse_ino_t fuse_ino, size_t size, off_t foff, struct fuse_file_info * fi) { fdesc_t * fdesc = fi_get_fdesc(fi); uint32_t off = foff; uint32_t total_size = 0; char * buf = NULL; int r; Dprintf("%s(ino = %lu, size = %u, off = %lld)\n", __FUNCTION__, fuse_ino, size, foff); while (1) { dirent_t dirent; int nbytes; struct stat stbuf; inode_t entry_cfs_ino; size_t oldsize = total_size; nbytes = CALL(reqcfs(req), get_dirent, fdesc, &dirent, sizeof(dirent), &off); if (nbytes == -1) break; else if (nbytes < 0) { fprintf(stderr, "%s:%s(): CALL(cfs, get_dirent, fdesc = %p, off = %d) = %d (%s)\n", __FILE__, __FUNCTION__, fdesc, off, nbytes, strerror(nbytes)); assert(nbytes >= 0); } if (total_size + fuse_dirent_size(dirent.d_namelen) > size) break; Dprintf("%s: \"%s\"\n", __FUNCTION__, dirent.d_name); total_size += fuse_dirent_size(dirent.d_namelen); buf = (char *) realloc(buf, total_size); if (!buf) kpanic("realloc() failed"); memset(&stbuf, 0, sizeof(stbuf)); // Generate "." and ".." here rather than in the base file system // because they are not able to find ".."'s inode from just // "."'s inode if (!strcmp(dirent.d_name, ".")) entry_cfs_ino = fusecfsino(req, fuse_ino); else if (!strcmp(dirent.d_name, "..")) entry_cfs_ino = fdesc->common->parent; else { r = CALL(reqcfs(req), lookup, fusecfsino(req, fuse_ino), dirent.d_name, &entry_cfs_ino); assert(r >= 0); } stbuf.st_ino = cfsfuseino(req, entry_cfs_ino); fuse_add_dirent(buf + oldsize, dirent.d_name, &stbuf, off); } r = fuse_reply_buf(req, buf, total_size); fuse_reply_assert(!r); free(buf); }
static void cusexmp_read(fuse_req_t req, size_t size, off_t off, struct fuse_file_info *fi) { (void)fi; if (off >= cusexmp_size) off = cusexmp_size; if (size > cusexmp_size - off) size = cusexmp_size - off; fuse_reply_buf(req, cusexmp_buf + off, size); }
void hsx_fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { struct hsfs_readdir_ctx *saved_ctx, *ctx = NULL; struct hsfs_inode *parent; struct hsfs_super *sb; size_t res, len = 0; char * buf; int err, count = 0; DEBUG_IN("P_I(%lu), Size(%lld), Off(0x%llx)", ino, size, off); (void)fi; sb = fuse_req_userdata(req); FUSE_ASSERT(sb != NULL); parent = hsfs_ilookup(sb, ino); FUSE_ASSERT(parent != NULL); err = hsi_nfs3_readdir(parent, size, off, &ctx); if(err) goto out1; saved_ctx = ctx; buf = (char *) malloc(size); if( NULL == buf){ err = ENOMEM; goto out2; } while(ctx != NULL){ res = fuse_add_direntry(req, buf + len, size - len, ctx->name, &ctx->stbuf, ctx->off); /* From fuse doc, buf is not copied if res larger than * requested */ if(res >= size - len) break; len += res; ctx = ctx->next; count++; } /* If EOF, we will return an empty buffer here. */ if (!err) fuse_reply_buf(req, buf, len); free(buf); out2: __free_ctx(saved_ctx, 0); out1: if(err) fuse_reply_err(req, err); DEBUG_OUT("with %d, %d entries returned.", err, count); }
static void sqfs_ll_op_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { sqfs_ll *ll = fuse_req_userdata(req); sqfs_inode *inode = (sqfs_inode*)(intptr_t)fi->fh; sqfs_err err = SQFS_OK; off_t osize; char *buf = malloc(size); if (!buf) { fuse_reply_err(req, ENOMEM); return; } osize = size; err = sqfs_read_range(&ll->fs, inode, off, &osize, buf); if (err) { fuse_reply_err(req, EIO); } else if (osize == 0) { /* EOF */ fuse_reply_buf(req, NULL, 0); } else { fuse_reply_buf(req, buf, osize); } free(buf); }
static int zfsfuse_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { file_info_t *info = (file_info_t *)(uintptr_t) fi->fh; vnode_t *vp = info->vp; ASSERT(vp != NULL); ASSERT(VTOZ(vp) != NULL); ASSERT(VTOZ(vp)->z_id == ino); vfs_t *vfs = (vfs_t *) fuse_req_userdata(req); zfsvfs_t *zfsvfs = vfs->vfs_data; char *outbuf = kmem_alloc(size, KM_NOSLEEP); if(outbuf == NULL) return ENOMEM; ZFS_ENTER(zfsvfs); iovec_t iovec; uio_t uio; uio.uio_iov = &iovec; uio.uio_iovcnt = 1; uio.uio_segflg = UIO_SYSSPACE; uio.uio_fmode = 0; uio.uio_llimit = RLIM64_INFINITY; iovec.iov_base = outbuf; iovec.iov_len = size; uio.uio_resid = iovec.iov_len; uio.uio_loffset = off; cred_t cred; zfsfuse_getcred(req, &cred); int error = VOP_READ(vp, &uio, info->flags, &cred, NULL); ZFS_EXIT(zfsvfs); if(!error) fuse_reply_buf(req, outbuf, uio.uio_loffset - off); kmem_free(outbuf, size); return error; }
static void sqfs_ll_op_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { sqfs_err sqerr; sqfs_dir dir; sqfs_name namebuf; sqfs_dir_entry entry; size_t esize; struct stat st; char *buf = NULL, *bufpos = NULL; sqfs_ll_i *lli = (sqfs_ll_i*)(intptr_t)fi->fh; int err = 0; if (sqfs_dir_open(&lli->ll->fs, &lli->inode, &dir, off)) err = EINVAL; if (!err && !(bufpos = buf = malloc(size))) err = ENOMEM; if (!err) { memset(&st, 0, sizeof(st)); sqfs_dentry_init(&entry, namebuf); while (sqfs_dir_next(&lli->ll->fs, &dir, &entry, &sqerr)) { st.st_ino = lli->ll->ino_fuse_num(lli->ll, &entry); st.st_mode = sqfs_dentry_mode(&entry); esize = sqfs_ll_add_direntry(req, bufpos, size, sqfs_dentry_name(&entry), &st, sqfs_dentry_next_offset(&entry)); if (esize > size) break; bufpos += esize; size -= esize; } if (sqerr) err = EIO; } if (err) fuse_reply_err(req, err); else fuse_reply_buf(req, buf, bufpos - buf); free(buf); }
/** * Read data from a file @param thread_ctx_p: pointer to the thread context @param msg : address of the message received @retval: none */ static inline void rozofs_fuse_th_fuse_reply_buf(rozofs_fuse_thread_ctx_t *thread_ctx_p,rozofs_fuse_thread_msg_t * msg) { struct timeval timeDay; unsigned long long timeBefore, timeAfter; char *buf_sharem = (char *)msg->payload; gettimeofday(&timeDay,(struct timezone *)0); timeBefore = MICROLONG(timeDay); /* ** update statistics */ thread_ctx_p->stat.write_count++; thread_ctx_p->stat.write_Byte_count+=msg->size; fuse_reply_buf(msg->req, (char *) buf_sharem, msg->size); rozofs_fuse_th_send_response(thread_ctx_p,msg,0); /* ** Update statistics */ gettimeofday(&timeDay,(struct timezone *)0); timeAfter = MICROLONG(timeDay); thread_ctx_p->stat.write_time +=(timeAfter-timeBefore); }
static void workspace_nfs_read(fuse_req_t req, size_t size, off_t offset, struct workspace_fh_struct *fh) { struct resource_struct *resource=fh->object->resource; struct net_nfs_export_struct *nfs_export=(struct net_nfs_export_struct *) resource->data; struct nfs_context *nfs_ctx=(struct nfs_context *) nfs_export->data; struct nfsfh *nfsfh=(struct nfsfh *) fh->handle.data; int result=0; char *buff; buff=malloc(size); if (! buff) { fuse_reply_err(req, ENOMEM); return; } logoutput("workspace_nfs_read"); pthread_mutex_lock(&nfs_export->mutex); result=nfs_pread(nfs_ctx, nfsfh, offset, size, buff); pthread_mutex_unlock(&nfs_export->mutex); if (result>=0) { fuse_reply_buf(req, buff, result); } else { fuse_reply_err(req, abs(result)); } }
static void sqfs_ll_op_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) { sqfs_ll_i lli; char *buf; int ferr; if (sqfs_ll_iget(req, &lli, ino)) return; buf = NULL; if (size && !(buf = malloc(size))) { fuse_reply_err(req, ENOMEM); return; } ferr = sqfs_listxattr(&lli.ll->fs, &lli.inode, buf, &size); if (ferr) { fuse_reply_err(req, ferr); } else if (buf) { fuse_reply_buf(req, buf, size); } else { fuse_reply_xattr(req, size); } free(buf); }
void mfs_meta_read(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { pathbuf *pathinfo = (pathbuf *)((unsigned long)(fi->fh)); if (ino==MASTERINFO_INODE) { uint8_t masterinfo[14]; fs_getmasterlocation(masterinfo); masterproxy_getlocation(masterinfo); #ifdef MASTERINFO_WITH_VERSION if (off>=14) { fuse_reply_buf(req,NULL,0); } else if (off+size>14) { fuse_reply_buf(req,(char*)(masterinfo+off),14-off); #else if (off>=10) { fuse_reply_buf(req,NULL,0); } else if (off+size>10) { fuse_reply_buf(req,(char*)(masterinfo+off),10-off); #endif } else { fuse_reply_buf(req,(char*)(masterinfo+off),size); } return; } if (pathinfo==NULL) { fuse_reply_err(req,EBADF); return; } // if (ino==MASTER_INODE) { // minfo *masterinfo = (minfo*)(unsigned long)(fi->fh); // if (masterinfo->sent) { // int rsize; // uint8_t *buff; // buff = malloc(size); // rsize = fs_direct_read(masterinfo->sd,buff,size); // fuse_reply_buf(req,(char*)buff,rsize); //syslog(LOG_WARNING,"master received: %d/%u",rsize,size); // free(buff); // } else { // syslog(LOG_WARNING,"master: read before write"); // fuse_reply_buf(req,NULL,0); // } // return; // } pthread_mutex_lock(&(pathinfo->lock)); if (off<0) { pthread_mutex_unlock(&(pathinfo->lock)); fuse_reply_err(req,EINVAL); return; } if ((size_t)off>pathinfo->size) { fuse_reply_buf(req, NULL, 0); } else if (off + size > pathinfo->size) { fuse_reply_buf(req, (pathinfo->p)+off,(pathinfo->size)-off); } else { fuse_reply_buf(req, (pathinfo->p)+off,size); } pthread_mutex_unlock(&(pathinfo->lock)); } void mfs_meta_write(fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi) { pathbuf *pathinfo = (pathbuf *)((unsigned long)(fi->fh)); if (ino==MASTERINFO_INODE) { fuse_reply_err(req,EACCES); return; } if (pathinfo==NULL) { fuse_reply_err(req,EBADF); return; } // if (ino==MASTER_INODE) { // minfo *masterinfo = (minfo*)(unsigned long)(fi->fh); // int wsize; // masterinfo->sent=1; // wsize = fs_direct_write(masterinfo->sd,(const uint8_t*)buf,size); //syslog(LOG_WARNING,"master sent: %d/%u",wsize,size); // fuse_reply_write(req,wsize); // return; // } if (off + size > PATH_SIZE_LIMIT) { fuse_reply_err(req,EINVAL); return; } pthread_mutex_lock(&(pathinfo->lock)); if (pathinfo->changed==0) { pathinfo->size = 0; } if (off+size > pathinfo->size) { size_t s = pathinfo->size; pathinfo->p = realloc(pathinfo->p,off+size); pathinfo->size = off+size; memset(pathinfo->p+s,0,off+size-s); } memcpy((pathinfo->p)+off,buf,size); pathinfo->changed = 1; pthread_mutex_unlock(&(pathinfo->lock)); fuse_reply_write(req,size); }
void mfs_meta_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { dirbuf *dirinfo = (dirbuf *)((unsigned long)(fi->fh)); char buffer[READDIR_BUFFSIZE]; char *name,c; const uint8_t *ptr,*eptr; uint8_t end; size_t opos,oleng; uint8_t nleng; uint32_t inode; uint8_t type; struct stat stbuf; if (off<0) { fuse_reply_err(req,EINVAL); return; } pthread_mutex_lock(&(dirinfo->lock)); if (dirinfo->wasread==0 || (dirinfo->wasread==1 && off==0)) { if (dirinfo->p!=NULL) { free(dirinfo->p); } dirbuf_meta_fill(dirinfo,ino); // syslog(LOG_WARNING,"inode: %lu , dirinfo->p: %p , dirinfo->size: %lu",(unsigned long)ino,dirinfo->p,(unsigned long)dirinfo->size); } dirinfo->wasread=1; if (off>=(off_t)(dirinfo->size)) { fuse_reply_buf(req, NULL, 0); } else { if (size>READDIR_BUFFSIZE) { size=READDIR_BUFFSIZE; } ptr = (const uint8_t*)(dirinfo->p)+off; eptr = (const uint8_t*)(dirinfo->p)+dirinfo->size; opos = 0; end = 0; while (ptr<eptr && end==0) { nleng = ptr[0]; ptr++; name = (char*)ptr; ptr+=nleng; off+=nleng+6; if (ptr+5<=eptr) { inode = get32bit(&ptr); type = get8bit(&ptr); mfs_meta_type_to_stat(inode,type,&stbuf); c = name[nleng]; name[nleng]=0; oleng = fuse_add_direntry(req, buffer + opos, size - opos, name, &stbuf, off); name[nleng] = c; if (opos+oleng>size) { end=1; } else { opos+=oleng; } } } fuse_reply_buf(req,buffer,opos); } pthread_mutex_unlock(&(dirinfo->lock)); }
static void overlay_readdirplus_full(fuse_req_t req, size_t size, off_t offset, struct workspace_dh_struct *dh) { unsigned int error=0; char *buff=NULL; size_t pos=0; size_t dirent_size; struct fuse_entry_param e; char *name=NULL; struct directory_struct *directory=dh->directory; struct overlay_readdir_struct *overlay_readdir=(struct overlay_readdir_struct *)dh->handle.data; struct entry_struct *entry, *result; struct inode_struct *inode; unsigned char dtype; struct name_struct xname={NULL, 0, 0}; int res=0; memset(&e, 0, sizeof(struct fuse_entry_param)); e.generation = 1; e.attr_timeout = fs_options.attr_timeout; e.entry_timeout = fs_options.entry_timeout; e.attr.st_blksize=4096; e.attr.st_blocks=0; buff=malloc(size); if (! buff) { error=ENOMEM; goto error; } if (lock_directory(directory, _DIRECTORY_LOCK_EXCL)==-1) { free(buff); buff=NULL; error=EAGAIN; goto error; } while (pos<size) { if (offset==0) { inode=dh->parent->inode; /* the . entry */ e.ino = inode->ino; e.attr.st_ino = e.ino; e.attr.st_mode = inode->mode; e.attr.st_nlink = inode->nlink; e.attr.st_uid = inode->uid; e.attr.st_gid = inode->gid; e.attr.st_rdev = inode->rdev; e.attr.st_size = 0; e.attr.st_atim.tv_sec = 0; e.attr.st_atim.tv_nsec = 0; e.attr.st_mtim.tv_sec = inode->mtim.tv_sec; e.attr.st_mtim.tv_nsec = inode->mtim.tv_nsec; e.attr.st_ctim.tv_sec = inode->ctim.tv_sec; e.attr.st_ctim.tv_nsec = inode->ctim.tv_nsec; name = (char *) dotname; inode->nlookup++; } else if (offset==1) { /* the .. entry */ if ( ! dh->parent->parent ) { inode=dh->parent->inode; } else { inode=dh->parent->parent->inode; } e.ino = inode->ino; e.attr.st_ino = e.ino; e.attr.st_mode = inode->mode; e.attr.st_nlink = inode->nlink; e.attr.st_uid = inode->uid; e.attr.st_gid = inode->gid; e.attr.st_rdev = inode->rdev; e.attr.st_size = 0; e.attr.st_atim.tv_sec = 0; e.attr.st_atim.tv_nsec = 0; e.attr.st_mtim.tv_sec = inode->mtim.tv_sec; e.attr.st_mtim.tv_nsec = inode->mtim.tv_nsec; e.attr.st_ctim.tv_sec = inode->ctim.tv_sec; e.attr.st_ctim.tv_nsec = inode->ctim.tv_nsec; name = (char *) dotdotname; inode->nlookup++; } else { if (! dh->entry) { readdir: res=get_direntry(overlay_readdir, &xname, &dtype, &error); if (res<=0) { if (res==-1) { free(buff); unlock_directory(directory, _DIRECTORY_LOCK_EXCL); goto error; } dh->mode |= _WORKSPACE_READDIR_MODE_FINISH; break; } if (fstatat(overlay_readdir->fd, xname.name, &e.attr, AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT)==-1) { goto readdir; } logoutput("overlayfs_readdirplus_real_full: read %s", xname.name); xname.len=strlen(xname.name); calculate_nameindex(&xname); error=0; entry=create_entry(dh->parent, &xname); inode=create_inode(); if (entry && inode) { result=insert_entry_batch(directory, entry, &error, 0); if (result==entry) { memcpy(&entry->synctime, &dh->synctime, sizeof(struct timespec)); inode->mode=DTTOIF(dtype); add_inode_hashtable(inode, increase_inodes_workspace, (void *) dh->object->workspace_mount); inode->alias=entry; entry->inode=inode; adjust_pathmax(dh->pathinfo.len + 1 + xname.len); } else { if (error==EEXIST) { destroy_entry(entry); entry=result; memcpy(&entry->synctime, &dh->synctime, sizeof(struct timespec)); free(inode); inode=entry->inode; } else { free(buff); destroy_entry(entry); free(inode); goto error; } } e.attr.st_ino=inode->ino; e.ino=inode->ino; e.attr.st_rdev = inode->rdev; e.attr.st_dev = 0; name=entry->name.name; } else { if (entry) { destroy_entry(entry); entry=NULL; } if (inode) { free(inode); inode=NULL; } error=ENOMEM; free(buff); goto error; } name=entry->name.name; dh->entry=entry; inode->mode = e.attr.st_mode; inode->nlink = e.attr.st_nlink; inode->uid = e.attr.st_uid; inode->gid = e.attr.st_gid; inode->rdev = e.attr.st_rdev; inode->mtim.tv_sec = e.attr.st_mtim.tv_sec; inode->mtim.tv_nsec = e.attr.st_mtim.tv_nsec; inode->ctim.tv_sec = e.attr.st_ctim.tv_sec; inode->ctim.tv_nsec = e.attr.st_ctim.tv_nsec; if (S_ISDIR(e.attr.st_mode)) { e.attr.st_size=0; } else { inode->size=e.attr.st_size; } } else { entry=dh->entry; inode=entry->inode; name=entry->name.name; e.attr.st_mode = inode->mode; e.attr.st_nlink = inode->nlink; e.attr.st_uid = inode->uid; e.attr.st_gid = inode->gid; e.attr.st_rdev = inode->rdev; if (S_ISDIR(inode->mode)) { e.attr.st_size = 0; } else { e.attr.st_size = inode->size; } e.attr.st_atim.tv_sec = 0; e.attr.st_atim.tv_nsec = 0; e.attr.st_mtim.tv_sec = inode->mtim.tv_sec; e.attr.st_mtim.tv_nsec = inode->mtim.tv_nsec; e.attr.st_ctim.tv_sec = inode->ctim.tv_sec; e.attr.st_ctim.tv_nsec = inode->ctim.tv_nsec; inode->nlookup++; } e.ino = inode->ino; e.attr.st_ino = e.ino; } dirent_size=fuse_add_direntry_plus(req, buff+pos, size-pos, name, &e, offset+1); if (pos + dirent_size > size) { dh->offset=offset+1; break; } /* increase counter and clear the various fields */ dh->entry=NULL; /* forget current entry to force readdir */ offset++; pos += dirent_size; } unlock_directory(directory, _DIRECTORY_LOCK_EXCL); fuse_reply_buf(req, buff, pos); free(buff); buff=NULL; return; error: fuse_reply_err(req, error); }
static void overlay_readdirplus_virtual(fuse_req_t req, size_t size, off_t offset, struct workspace_dh_struct *dh) { unsigned int error=0; char *buff=NULL; size_t pos=0; size_t dirent_size; struct fuse_entry_param e; char *name=NULL; struct name_struct xname={NULL, 0, 0}; unsigned char dtype=0; struct directory_struct *directory=dh->directory; struct overlay_readdir_struct *overlay_readdir=(struct overlay_readdir_struct *)dh->handle.data; struct entry_struct *entry=NULL; struct inode_struct *inode=NULL; memset(&e, 0, sizeof(struct fuse_entry_param)); e.generation = 1; e.attr_timeout = fs_options.attr_timeout; e.entry_timeout = fs_options.entry_timeout; e.attr.st_blksize=4096; e.attr.st_blocks=0; buff=malloc(size); if (! buff) { error=ENOMEM; goto error; } if (lock_directory(directory, _DIRECTORY_LOCK_READ)==-1) { free(buff); buff=NULL; error=EAGAIN; goto error; } while (pos<size) { if (offset==0) { inode=dh->parent->inode; /* the . entry */ e.ino = inode->ino; e.attr.st_ino = e.ino; e.attr.st_mode = inode->mode; e.attr.st_nlink = inode->nlink; e.attr.st_uid = inode->uid; e.attr.st_gid = inode->gid; e.attr.st_rdev = inode->rdev; e.attr.st_size = 0; e.attr.st_atim.tv_sec = 0; e.attr.st_atim.tv_nsec = 0; e.attr.st_mtim.tv_sec = inode->mtim.tv_sec; e.attr.st_mtim.tv_nsec = inode->mtim.tv_nsec; e.attr.st_ctim.tv_sec = inode->ctim.tv_sec; e.attr.st_ctim.tv_nsec = inode->ctim.tv_nsec; name = (char *) dotname; inode->nlookup++; } else if (offset==1) { /* the .. entry */ if ( ! dh->parent->parent) { inode=dh->parent->inode; } else { inode=dh->parent->parent->inode; } e.ino = inode->ino; e.attr.st_ino = e.ino; e.attr.st_mode = inode->mode; e.attr.st_nlink = inode->nlink; e.attr.st_uid = inode->uid; e.attr.st_gid = inode->gid; e.attr.st_rdev = inode->rdev; e.attr.st_size = 0; e.attr.st_atim.tv_sec = 0; e.attr.st_atim.tv_nsec = 0; e.attr.st_mtim.tv_sec = inode->mtim.tv_sec; e.attr.st_mtim.tv_nsec = inode->mtim.tv_nsec; e.attr.st_ctim.tv_sec = inode->ctim.tv_sec; e.attr.st_ctim.tv_nsec = inode->ctim.tv_nsec; name = (char *) dotdotname; inode->nlookup++; } else { if (! dh->entry) { readdir: entry=(struct entry_struct *) overlay_readdir->data; if (entry) { overlay_readdir->data=(void *) entry->name_next; } else { dh->mode |= _WORKSPACE_READDIR_MODE_FINISH; break; } dh->entry=entry; } else { entry=dh->entry; } inode=entry->inode; e.ino = inode->ino; e.attr.st_ino = e.ino; e.attr.st_mode = inode->mode; e.attr.st_nlink = inode->nlink; e.attr.st_uid = inode->uid; e.attr.st_gid = inode->gid; e.attr.st_rdev = inode->rdev; if (S_ISDIR(inode->mode)) { e.attr.st_size = 0; } else { e.attr.st_size = inode->size; } e.attr.st_atim.tv_sec = 0; e.attr.st_atim.tv_nsec = 0; e.attr.st_mtim.tv_sec = inode->mtim.tv_sec; e.attr.st_mtim.tv_nsec = inode->mtim.tv_nsec; e.attr.st_ctim.tv_sec = inode->ctim.tv_sec; e.attr.st_ctim.tv_nsec = inode->ctim.tv_nsec; name=entry->name.name; inode->nlookup++; } dirent_size=fuse_add_direntry_plus(req, buff+pos, size-pos, name, &e, offset+1); if (pos + dirent_size > size) { dh->offset=offset+1; break; } /* increase counter and clear the various fields */ dh->entry=NULL; /* forget current entry to force readdir */ offset++; pos += dirent_size; } unlock_directory(directory, _DIRECTORY_LOCK_READ); fuse_reply_buf(req, buff, pos); free(buff); buff=NULL; return; error: fuse_reply_err(req, error); }
static int zfsfuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) { vnode_t *vp = ((file_info_t *)(uintptr_t) fi->fh)->vp; ASSERT(vp != NULL); ASSERT(VTOZ(vp) != NULL); ASSERT(VTOZ(vp)->z_id == ino); if(vp->v_type != VDIR) return ENOTDIR; vfs_t *vfs = (vfs_t *) fuse_req_userdata(req); zfsvfs_t *zfsvfs = vfs->vfs_data; char *outbuf = kmem_alloc(size, KM_NOSLEEP); if(outbuf == NULL) return ENOMEM; ZFS_ENTER(zfsvfs); cred_t cred; zfsfuse_getcred(req, &cred); union { char buf[DIRENT64_RECLEN(MAXNAMELEN)]; struct dirent64 dirent; } entry; struct stat fstat = { 0 }; iovec_t iovec; uio_t uio; uio.uio_iov = &iovec; uio.uio_iovcnt = 1; uio.uio_segflg = UIO_SYSSPACE; uio.uio_fmode = 0; uio.uio_llimit = RLIM64_INFINITY; int eofp = 0; int outbuf_off = 0; int outbuf_resid = size; off_t next = off; int error; for(;;) { iovec.iov_base = entry.buf; iovec.iov_len = sizeof(entry.buf); uio.uio_resid = iovec.iov_len; uio.uio_loffset = next; error = VOP_READDIR(vp, &uio, &cred, &eofp, NULL, 0); if(error) goto out; /* No more directory entries */ if(iovec.iov_base == entry.buf) break; fstat.st_ino = entry.dirent.d_ino; fstat.st_mode = 0; int dsize = fuse_dirent_size(strlen(entry.dirent.d_name)); if(dsize > outbuf_resid) break; fuse_add_dirent(outbuf + outbuf_off, entry.dirent.d_name, &fstat, entry.dirent.d_off); outbuf_off += dsize; outbuf_resid -= dsize; next = entry.dirent.d_off; } out: ZFS_EXIT(zfsvfs); if(!error) fuse_reply_buf(req, outbuf, outbuf_off); kmem_free(outbuf, size); return error; }
static void workspace_nfs_readdirplus_simple(fuse_req_t req, size_t size, off_t offset, struct workspace_dh_struct *dh) { struct resource_struct *resource=dh->object->resource; struct net_nfs_export_struct *nfs_export=(struct net_nfs_export_struct *) resource->data; struct nfs_context *nfs_ctx=(struct nfs_context *) nfs_export->data; unsigned int error=0; char *buff=NULL; size_t pos=0; size_t dirent_size; struct fuse_entry_param e; char *name=NULL; struct directory_struct *directory=dh->directory; struct nfsdir *dir=(struct nfsdir *) dh->handle.data; struct entry_struct *entry, *result; struct inode_struct *inode; struct name_struct xname={NULL, 0, 0}; memset(&e, 0, sizeof(struct fuse_entry_param)); e.generation = 1; e.attr_timeout = fs_options.attr_timeout; e.entry_timeout = fs_options.entry_timeout; e.attr.st_blksize=_DEFAULT_BLOCKSIZE; buff=malloc(size); if (! buff) { error=ENOMEM; goto error; } if (lock_directory(directory, _DIRECTORY_LOCK_EXCL)==-1) { free(buff); buff=NULL; error=EAGAIN; goto error; } while (pos<size) { if (offset==0) { inode=dh->parent->inode; /* the . entry */ e.ino = inode->ino; e.attr.st_ino = e.ino; e.attr.st_mode = inode->mode; e.attr.st_nlink = inode->nlink; e.attr.st_uid = inode->uid; e.attr.st_gid = inode->gid; e.attr.st_rdev = inode->rdev; e.attr.st_size = inode->size; e.attr.st_atim.tv_sec = 0; e.attr.st_atim.tv_nsec = 0; e.attr.st_mtim.tv_sec = inode->mtim.tv_sec; e.attr.st_mtim.tv_nsec = inode->mtim.tv_nsec; e.attr.st_ctim.tv_sec = inode->ctim.tv_sec; e.attr.st_ctim.tv_nsec = inode->ctim.tv_nsec; name = (char *) dotname; inode->nlookup++; } else if (offset==1) { /* the .. entry */ if ( ! dh->parent->parent ) { inode=dh->parent->inode; } else { inode=dh->parent->parent->inode; } e.ino = inode->ino; e.attr.st_ino = e.ino; e.attr.st_mode = inode->mode; e.attr.st_nlink = inode->nlink; e.attr.st_uid = inode->uid; e.attr.st_gid = inode->gid; e.attr.st_rdev = inode->rdev; e.attr.st_size = inode->size; e.attr.st_atim.tv_sec = 0; e.attr.st_atim.tv_nsec = 0; e.attr.st_mtim.tv_sec = inode->mtim.tv_sec; e.attr.st_mtim.tv_nsec = inode->mtim.tv_nsec; e.attr.st_ctim.tv_sec = inode->ctim.tv_sec; e.attr.st_ctim.tv_nsec = inode->ctim.tv_nsec; name = (char *) dotdotname; inode->nlookup++; } else { if (! dh->entry) { struct nfsdirent *de; readdir: pthread_mutex_lock(&nfs_export->mutex); de=nfs_readdir(nfs_ctx, dir); pthread_mutex_unlock(&nfs_export->mutex); if (de) { if (strcmp(de->name, ".")==0 || strcmp(de->name, "..")==0) continue; xname.name=de->name; xname.len=strlen(xname.name); calculate_nameindex(&xname); } else { dh->mode |= _WORKSPACE_READDIR_MODE_FINISH; break; } error=0; entry=create_entry(dh->parent, &xname); inode=create_inode(); if (entry && inode) { result=insert_entry_batch(directory, entry, &error, 0); if (result==entry) { struct workspace_object_struct *export_object=NULL; inode->mode = translate_libnfs_type(de->type); inode->mode |= de->mode; add_inode_hashtable(inode, increase_inodes_workspace, (void *) dh->object->workspace_mount); inode->alias=entry; entry->inode=inode; memcpy(&entry->synctime, &dh->synctime, sizeof(struct timespec)); inode->nlookup++; inode->nlink=2; inode->uid=0; /* ?? */ inode->gid=0; /* ?? */ inode->size=de->size; /* struct timeval convert to timespec */ inode->mtim.tv_sec=de->mtime.tv_sec; inode->mtim.tv_nsec=1000 * de->mtime.tv_usec; inode->ctim.tv_sec=de->ctime.tv_sec; inode->ctim.tv_nsec=1000 * de->ctime.tv_usec; adjust_pathmax(dh->pathinfo.len + 1 + xname.len); } else { if (error==EEXIST) { destroy_entry(entry); entry=result; memcpy(&entry->synctime, &dh->synctime, sizeof(struct timespec)); free(inode); inode=entry->inode; } else { free(buff); destroy_entry(entry); free(inode); goto error; } } } else { if (entry) { destroy_entry(entry); entry=NULL; } if (inode) { free(inode); inode=NULL; } error=ENOMEM; free(buff); goto error; } name=entry->name.name; dh->entry=entry; } else { entry=dh->entry; inode=entry->inode; name=entry->name.name; } e.ino = inode->ino; e.attr.st_ino = e.ino; e.attr.st_mode = inode->mode; e.attr.st_nlink = inode->nlink; e.attr.st_uid = inode->uid; e.attr.st_gid = inode->gid; e.attr.st_rdev = inode->rdev; e.attr.st_size = inode->size; e.attr.st_atim.tv_sec = 0; e.attr.st_atim.tv_nsec = 0; e.attr.st_mtim.tv_sec = inode->mtim.tv_sec; e.attr.st_mtim.tv_nsec = inode->mtim.tv_nsec; e.attr.st_ctim.tv_sec = inode->ctim.tv_sec; e.attr.st_ctim.tv_nsec = inode->ctim.tv_nsec; if (inode->size % e.attr.st_blksize == 0) { e.attr.st_blocks=inode->size / e.attr.st_blksize; } else { e.attr.st_blocks=1 + inode->size / e.attr.st_blksize; } } dirent_size=fuse_add_direntry_plus(req, buff+pos, size-pos, name, &e, offset+1); if (pos + dirent_size > size) { dh->offset=offset; break; } /* increase counter and clear the various fields */ dh->entry=NULL; /* forget current entry to force readdir */ offset++; pos += dirent_size; } unlock_directory(directory, _DIRECTORY_LOCK_EXCL); fuse_reply_buf(req, buff, pos); free(buff); buff=NULL; return; error: fuse_reply_err(req, error); }
static void workspace_nfs_readdir_simple(fuse_req_t req, size_t size, off_t offset, struct workspace_dh_struct *dh) { struct resource_struct *resource=dh->object->resource; struct net_nfs_export_struct *nfs_export=(struct net_nfs_export_struct *) resource->data; struct nfs_context *nfs_ctx=(struct nfs_context *) nfs_export->data; unsigned int error=0; char *buff=NULL; size_t pos=0; size_t dirent_size; char *name=NULL; struct directory_struct *directory=dh->directory; struct nfsdir *dir=(struct nfsdir *) dh->handle.data; struct entry_struct *entry, *result; struct inode_struct *inode; struct name_struct xname={NULL, 0, 0}; struct stat st; memset(&st, 0, sizeof(struct stat)); buff=malloc(size); if (! buff) { error=ENOMEM; goto error; } if (lock_directory(directory, _DIRECTORY_LOCK_EXCL)==-1) { free(buff); buff=NULL; error=EAGAIN; goto error; } while (pos<size) { if (offset==0) { inode=dh->parent->inode; /* the . entry */ st.st_ino = inode->ino; st.st_mode = S_IFDIR; name = (char *) dotname; } else if (offset==1) { /* the .. entry */ if (! dh->parent->parent ) { inode=dh->parent->inode; st.st_ino = inode->ino; } else { struct entry_struct *parent=dh->parent->parent; inode=parent->inode; st.st_ino=inode->ino; } st.st_mode = S_IFDIR; name = (char *) dotdotname; } else { if (! dh->entry) { struct nfsdirent *de; readdir: pthread_mutex_lock(&nfs_export->mutex); de=nfs_readdir(nfs_ctx, dir); pthread_mutex_unlock(&nfs_export->mutex); if (de) { if (strcmp(de->name, ".")==0 || strcmp(de->name, "..")==0) continue; xname.name=de->name; xname.len=strlen(xname.name); calculate_nameindex(&xname); } else { dh->mode |= _WORKSPACE_READDIR_MODE_FINISH; break; } error=0; entry=create_entry(dh->parent, &xname); inode=create_inode(); if (entry && inode) { result=insert_entry_batch(directory, entry, &error, 0); if (result==entry) { struct workspace_object_struct *export_object=NULL; inode->mode = translate_libnfs_type(de->type); inode->mode |= de->mode; add_inode_hashtable(inode, increase_inodes_workspace, (void *) dh->object->workspace_mount); inode->alias=entry; entry->inode=inode; adjust_pathmax(dh->pathinfo.len + 1 + xname.len); } else { if (error==EEXIST) { destroy_entry(entry); entry=result; free(inode); inode=entry->inode; } else { free(buff); destroy_entry(entry); free(inode); goto error; } } st.st_mode=entry->inode->mode; st.st_ino=entry->inode->ino; name=entry->name.name; } else { if (entry) { destroy_entry(entry); entry=NULL; } if (inode) { free(inode); inode=NULL; } error=ENOMEM; free(buff); goto error; } dh->entry=entry; } else { st.st_ino=dh->entry->inode->ino; st.st_mode=dh->entry->inode->mode; name=dh->entry->name.name; } } dirent_size=fuse_add_direntry(req, buff+pos, size-pos, name, &st, offset+1); if (pos + dirent_size > size) { dh->offset = offset + 1; break; } /* increase counter and clear the various fields */ dh->entry=NULL; /* forget current entry to force readdir */ offset++; pos += dirent_size; } unlock_directory(directory, _DIRECTORY_LOCK_EXCL); fuse_reply_buf(req, buff, pos); free(buff); buff=NULL; return; error: fuse_reply_err(req, error); }
static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t offset, struct fuse_file_info *fi, int plus) { struct lo_dirp *d = lo_dirp(fi); char *buf; char *p; size_t rem; int err; (void) ino; buf = calloc(size, 1); if (!buf) return (void) fuse_reply_err(req, ENOMEM); if (offset != d->offset) { seekdir(d->dp, offset); d->entry = NULL; d->offset = offset; } p = buf; rem = size; while (1) { size_t entsize; off_t nextoff; if (!d->entry) { errno = 0; d->entry = readdir(d->dp); if (!d->entry) { if (errno && rem == size) { err = errno; goto error; } break; } } nextoff = telldir(d->dp); if (plus) { struct fuse_entry_param e; err = lo_do_lookup(req, ino, d->entry->d_name, &e); if (err) goto error; entsize = fuse_add_direntry_plus(req, p, rem, d->entry->d_name, &e, nextoff); } else { struct stat st = { .st_ino = d->entry->d_ino, .st_mode = d->entry->d_type << 12, }; entsize = fuse_add_direntry(req, p, rem, d->entry->d_name, &st, nextoff); } if (entsize > rem) break; p += entsize; rem -= entsize; d->entry = NULL; d->offset = nextoff; } fuse_reply_buf(req, buf, size - rem); free(buf); return; error: free(buf); fuse_reply_err(req, err); } static void lo_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t offset, struct fuse_file_info *fi) { lo_do_readdir(req, ino, size, offset, fi, 0); }
static void overlay_readdir_virtual(fuse_req_t req, size_t size, off_t offset, struct workspace_dh_struct *dh) { unsigned int error=0; char *buff=NULL; size_t pos=0; size_t dirent_size; struct stat st; char *name=NULL; struct name_struct xname={NULL, 0, 0}; struct entry_struct *entry=NULL; struct inode_struct *inode=NULL; struct directory_struct *directory=dh->directory; struct overlay_readdir_struct *overlay_readdir=(struct overlay_readdir_struct *)dh->handle.data; unsigned char dtype=0; memset(&st, 0, sizeof(struct stat)); buff=malloc(size); if (! buff) { error=ENOMEM; goto error; } if (lock_directory(directory, _DIRECTORY_LOCK_READ)==-1) { free(buff); buff=NULL; error=EAGAIN; goto error; } while (pos<size) { if (offset==0) { inode=dh->parent->inode; /* the . entry */ st.st_ino = inode->ino; st.st_mode = S_IFDIR; name = (char *) dotname; } else if (offset==1) { /* the .. entry */ if (! dh->parent->parent ) { inode=dh->parent->inode; st.st_ino = inode->ino; } else { struct entry_struct *parent=dh->parent->parent; inode=parent->inode; st.st_ino=inode->ino; } st.st_mode = S_IFDIR; name = (char *) dotdotname; } else { if (! dh->entry) { readdir: entry=(struct entry_struct *) overlay_readdir->data; if (entry) { overlay_readdir->data=(void *) entry->name_next; } else { dh->mode |= _WORKSPACE_READDIR_MODE_FINISH; break; } dh->entry=entry; } else { entry=dh->entry; } name=entry->name.name; st.st_mode=entry->inode->mode; st.st_ino=entry->inode->ino; } dirent_size=fuse_add_direntry(req, buff+pos, size-pos, name, &st, offset+1); if (pos + dirent_size > size) { dh->offset=offset + 1; break; } /* increase counter and clear the various fields */ offset++; pos += dirent_size; dh->entry=NULL; } fuse_reply_buf(req, buff, pos); unlock_directory(directory, _DIRECTORY_LOCK_READ); free(buff); buff=NULL; return; error: fuse_reply_err(req, error); }
static void overlay_readdir_full(fuse_req_t req, size_t size, off_t offset, struct workspace_dh_struct *dh) { unsigned int error=0; char *buff=NULL; size_t pos=0; size_t dirent_size; struct stat st; char *name=NULL; struct directory_struct *directory=dh->directory; struct overlay_readdir_struct *overlay_readdir=(struct overlay_readdir_struct *)dh->handle.data; struct entry_struct *entry, *result; struct inode_struct *inode; struct name_struct xname={NULL, 0, 0}; unsigned char dtype=0; int res; memset(&st, 0, sizeof(struct stat)); buff=malloc(size); if (! buff) { error=ENOMEM; goto error; } if (lock_directory(directory, _DIRECTORY_LOCK_EXCL)==-1) { free(buff); buff=NULL; error=EAGAIN; goto error; } while (pos<size) { if (offset==0) { inode=dh->parent->inode; /* the . entry */ st.st_ino = inode->ino; st.st_mode = S_IFDIR; name = (char *) dotname; } else if (offset==1) { /* the .. entry */ if ( ! dh->parent->parent ) { inode=dh->parent->inode; st.st_ino = inode->ino; } else { struct entry_struct *parent=dh->parent->parent; inode=parent->inode; st.st_ino=inode->ino; } st.st_mode = S_IFDIR; name = (char *) dotdotname; } else { if (! dh->entry) { readdir: res=get_direntry(overlay_readdir, &xname, &dtype, &error); if (res<=0) { if (res==-1) { free(buff); unlock_directory(directory, _DIRECTORY_LOCK_EXCL); goto error; } dh->mode |= _WORKSPACE_READDIR_MODE_FINISH; break; } xname.len=strlen(xname.name); calculate_nameindex(&xname); error=0; entry=create_entry(dh->parent, &xname); inode=create_inode(); if (entry && inode) { result=insert_entry_batch(directory, entry, &error, 0); if (result==entry) { entry->inode->mode=DTTOIF(dtype); add_inode_hashtable(inode, increase_inodes_workspace, (void *) dh->object->workspace_mount); inode->alias=entry; entry->inode=inode; adjust_pathmax(dh->pathinfo.len + 1 + xname.len); } else { if (error==EEXIST) { destroy_entry(entry); entry=result; free(inode); inode=entry->inode; } else { free(buff); destroy_entry(entry); free(inode); goto error; } } st.st_mode=entry->inode->mode; st.st_ino=entry->inode->ino; name=entry->name.name; } else { if (entry) { destroy_entry(entry); entry=NULL; } if (inode) { free(inode); inode=NULL; } error=ENOMEM; free(buff); goto error; } dh->entry=entry; } else { entry=dh->entry; st.st_ino=entry->inode->ino; st.st_mode=entry->inode->mode; name=entry->name.name; } } dirent_size=fuse_add_direntry(req, buff+pos, size-pos, name, &st, offset+1); if (pos + dirent_size > size) { dh->offset = offset + 1; break; } /* increase counter and clear the various fields */ dh->entry=NULL; /* forget current entry to force readdir */ offset++; pos += dirent_size; } unlock_directory(directory, _DIRECTORY_LOCK_EXCL); fuse_reply_buf(req, buff, pos); free(buff); buff=NULL; return; error: fuse_reply_err(req, error); }
static bool read_bulk_cb(struct dfuse_request *request) { struct dfuse_rb *rb = container_of(request, struct dfuse_rb, rb_req); struct dfuse_readx_out *out = request->out; int rc = 0; size_t bytes_read = 0; void *buff = NULL; if (out->err) { DFUSE_TRA_ERROR(rb, "Error from target %d", out->err); rb->failure = true; D_GOTO(out, request->rc = EIO); } DFUSE_REQUEST_RESOLVE(request, out); if (request->rc) D_GOTO(out, 0); if (out->iov_len > 0) { if (out->data.iov_len != out->iov_len) D_GOTO(out, request->rc = EIO); buff = out->data.iov_buf; bytes_read = out->data.iov_len; } else if (out->bulk_len > 0) { bytes_read = out->bulk_len; } out: if (request->rc) { DFUSE_REPLY_ERR(request, request->rc); } else { /* It's not clear without benchmarking which approach is better * here, fuse_reply_buf() is a small wrapper around writev() * which is a much shorter code-path however fuse_reply_data() * attempts to use splice which may well be faster. * * For now it's easy to pick between them, and both of them are * passing valgrind tests. */ if (request->fsh->flags & DFUSE_FUSE_READ_BUF) { rc = fuse_reply_buf(request->req, buff, bytes_read); if (rc != 0) DFUSE_TRA_ERROR(rb, "fuse_reply_buf returned %d:%s", rc, strerror(-rc)); } else { rb->fbuf.buf[0].size = bytes_read; rb->fbuf.buf[0].mem = buff; rc = fuse_reply_data(request->req, &rb->fbuf, 0); if (rc != 0) DFUSE_TRA_ERROR(rb, "fuse_reply_data returned %d:%s", rc, strerror(-rc)); } } dfuse_da_release(rb->pt, rb); return false; }