static int dir_scopeiter(void *arg, psirp_id_t *idp) { int error = 0; ps_pubi_t pi; enum ps_pub_type type; struct dir_iter *di = arg; struct uio *uio = di->di_uio; struct dirent dent; error = ps_pit_get(*idp, &pi); if (error) return error; error = ps_obj_get_type(pi, &type); if (error) { PS_OBJ_PUBI_UNLOCK(pi); return error; } switch (type) { case PS_PUB_SCOPE: break; case PS_PUB_DATA: case PS_PUB_UNKNOWN: if (di->di_only_sids) { PS_OBJ_PUBI_UNLOCK(pi); return 0; } break; default: /* XXX: May crash here on subscribe-before-publish. If so, make a test case * and go to talk to Pekka. */ panic("dir_scopeiter: bad publication type %d", type); } dent.d_fileno = pi->pi_ino + di->di_type; dent.d_type = DT_DIR; dent.d_namlen = PSIRP_ID_LEN * 2; dent.d_reclen = GENERIC_DIRSIZ(&dent); PS_OBJ_PUBI_UNLOCK(pi); psfs_id2str(*idp, dent.d_name); di->di_count++; error = uiomove(&dent, dent.d_reclen, uio); if (di->di_cookies) *(di->di_cookies++) = uio->uio_offset; return error; }
/* * Vnode op for readdir */ static int devfs_readdir(struct vnop_readdir_args *ap) /*struct vnop_readdir_args { struct vnode *a_vp; struct uio *a_uio; int a_flags; int *a_eofflag; int *a_numdirent; vfs_context_t a_context; } */ { struct vnode *vp = ap->a_vp; struct uio *uio = ap->a_uio; struct dirent dirent; devnode_t * dir_node; devdirent_t * name_node; const char *name; int error = 0; int reclen; int nodenumber; int startpos,pos; if (ap->a_flags & (VNODE_READDIR_EXTENDED | VNODE_READDIR_REQSEEKOFF)) return (EINVAL); /* set up refs to dir */ dir_node = VTODN(vp); if (dir_node->dn_type != DEV_DIR) return(ENOTDIR); pos = 0; startpos = uio->uio_offset; DEVFS_LOCK(); name_node = dir_node->dn_typeinfo.Dir.dirlist; nodenumber = 0; dir_node->dn_access = 1; while ((name_node || (nodenumber < 2)) && (uio_resid(uio) > 0)) { switch(nodenumber) { case 0: dirent.d_fileno = (int32_t)(void *)dir_node; name = "."; dirent.d_namlen = 1; dirent.d_type = DT_DIR; break; case 1: if(dir_node->dn_typeinfo.Dir.parent) dirent.d_fileno = (int32_t)dir_node->dn_typeinfo.Dir.parent; else dirent.d_fileno = (u_int32_t)dir_node; name = ".."; dirent.d_namlen = 2; dirent.d_type = DT_DIR; break; default: dirent.d_fileno = (int32_t)(void *)name_node->de_dnp; dirent.d_namlen = strlen(name_node->de_name); name = name_node->de_name; switch(name_node->de_dnp->dn_type) { case DEV_BDEV: dirent.d_type = DT_BLK; break; case DEV_CDEV: dirent.d_type = DT_CHR; break; case DEV_DIR: dirent.d_type = DT_DIR; break; case DEV_SLNK: dirent.d_type = DT_LNK; break; default: dirent.d_type = DT_UNKNOWN; } } #define GENERIC_DIRSIZ(dp) \ ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) reclen = dirent.d_reclen = GENERIC_DIRSIZ(&dirent); if(pos >= startpos) /* made it to the offset yet? */ { if (uio_resid(uio) < reclen) /* will it fit? */ break; strlcpy(dirent.d_name, name, DEVMAXNAMESIZE); if ((error = uiomove ((caddr_t)&dirent, dirent.d_reclen, uio)) != 0) break; } pos += reclen; if((nodenumber >1) && name_node) name_node = name_node->de_next; nodenumber++; } DEVFS_UNLOCK(); uio->uio_offset = pos; return (error); }
int reiserfs_readdir(struct vop_readdir_args /* { struct vnode *a_vp; struct uio *a_uio; struct ucred *a_cred; int *a_eofflag; int *a_ncookies; u_long **a_cookies; } */*ap) { int error = 0; struct dirent dstdp; struct uio *uio = ap->a_uio; off_t next_pos; struct buf *bp; struct item_head *ih; struct cpu_key pos_key; const struct key *rkey; struct reiserfs_node *ip; struct reiserfs_dir_entry de; INITIALIZE_PATH(path_to_entry); int entry_num, item_num, search_res; /* The NFS part */ int ncookies = 0; u_long *cookies = NULL; /* * Form key for search the next directory entry using f_pos field of * file structure */ ip = VTOI(ap->a_vp); make_cpu_key(&pos_key, ip, uio->uio_offset ? uio->uio_offset : DOT_OFFSET, TYPE_DIRENTRY, 3); next_pos = cpu_key_k_offset(&pos_key); reiserfs_log(LOG_DEBUG, "listing entries for " "(objectid=%d, dirid=%d)\n", pos_key.on_disk_key.k_objectid, pos_key.on_disk_key.k_dir_id); reiserfs_log(LOG_DEBUG, "uio_offset = %jd, uio_resid = %d\n", (intmax_t)uio->uio_offset, uio->uio_resid); if (ap->a_ncookies && ap->a_cookies) { cookies = (u_long *)malloc( uio->uio_resid / 16 * sizeof(u_long), M_REISERFSCOOKIES, M_WAITOK); } while (1) { //research: /* * Search the directory item, containing entry with * specified key */ reiserfs_log(LOG_DEBUG, "search directory to read\n"); search_res = search_by_entry_key(ip->i_reiserfs, &pos_key, &path_to_entry, &de); if (search_res == IO_ERROR) { error = EIO; goto out; } entry_num = de.de_entry_num; item_num = de.de_item_num; bp = de.de_bp; ih = de.de_ih; if (search_res == POSITION_FOUND || entry_num < I_ENTRY_COUNT(ih)) { /* * Go through all entries in the directory item * beginning from the entry, that has been found. */ struct reiserfs_de_head *deh = B_I_DEH(bp, ih) + entry_num; if (ap->a_ncookies == NULL) { cookies = NULL; } else { //ncookies = } reiserfs_log(LOG_DEBUG, "walking through directory entries\n"); for (; entry_num < I_ENTRY_COUNT(ih); entry_num++, deh++) { int d_namlen; char *d_name; off_t d_off; ino_t d_ino; if (!de_visible(deh)) { /* It is hidden entry */ continue; } d_namlen = entry_length(bp, ih, entry_num); d_name = B_I_DEH_ENTRY_FILE_NAME(bp, ih, deh); if (!d_name[d_namlen - 1]) d_namlen = strlen(d_name); reiserfs_log(LOG_DEBUG, " - `%s' (len=%d)\n", d_name, d_namlen); if (d_namlen > REISERFS_MAX_NAME( ip->i_reiserfs->s_blocksize)) { /* Too big to send back to VFS */ continue; } #if 0 /* Ignore the .reiserfs_priv entry */ if (reiserfs_xattrs(ip->i_reiserfs) && !old_format_only(ip->i_reiserfs) && filp->f_dentry == ip->i_reiserfs->s_root && REISERFS_SB(ip->i_reiserfs)->priv_root && REISERFS_SB(ip->i_reiserfs)->priv_root->d_inode && deh_objectid(deh) == le32toh(INODE_PKEY(REISERFS_SB( ip->i_reiserfs)->priv_root->d_inode)->k_objectid)) { continue; } #endif d_off = deh_offset(deh); d_ino = deh_objectid(deh); uio->uio_offset = d_off; /* Copy to user land */ dstdp.d_fileno = d_ino; dstdp.d_type = DT_UNKNOWN; dstdp.d_namlen = d_namlen; dstdp.d_reclen = GENERIC_DIRSIZ(&dstdp); bcopy(d_name, dstdp.d_name, dstdp.d_namlen); bzero(dstdp.d_name + dstdp.d_namlen, dstdp.d_reclen - offsetof(struct dirent, d_name) - dstdp.d_namlen); if (d_namlen > 0) { if (dstdp.d_reclen <= uio->uio_resid) { reiserfs_log(LOG_DEBUG, " copying to user land\n"); error = uiomove(&dstdp, dstdp.d_reclen, uio); if (error) goto end; if (cookies != NULL) { cookies[ncookies] = d_off; ncookies++; } } else break; } else { error = EIO; break; } next_pos = deh_offset(deh) + 1; } reiserfs_log(LOG_DEBUG, "...done\n"); } reiserfs_log(LOG_DEBUG, "checking item num (%d == %d ?)\n", item_num, B_NR_ITEMS(bp) - 1); if (item_num != B_NR_ITEMS(bp) - 1) { /* End of directory has been reached */ reiserfs_log(LOG_DEBUG, "end reached\n"); if (ap->a_eofflag) *ap->a_eofflag = 1; goto end; } /* * Item we went through is last item of node. Using right * delimiting key check is it directory end */ reiserfs_log(LOG_DEBUG, "get right key\n"); rkey = get_rkey(&path_to_entry, ip->i_reiserfs); reiserfs_log(LOG_DEBUG, "right key = (objectid=%d, dirid=%d)\n", rkey->k_objectid, rkey->k_dir_id); reiserfs_log(LOG_DEBUG, "compare it to MIN_KEY\n"); reiserfs_log(LOG_DEBUG, "MIN KEY = (objectid=%d, dirid=%d)\n", MIN_KEY.k_objectid, MIN_KEY.k_dir_id); if (comp_le_keys(rkey, &MIN_KEY) == 0) { /* Set pos_key to key, that is the smallest and greater * that key of the last entry in the item */ reiserfs_log(LOG_DEBUG, "continuing on the right\n"); set_cpu_key_k_offset(&pos_key, next_pos); continue; } reiserfs_log(LOG_DEBUG, "compare it to pos_key\n"); reiserfs_log(LOG_DEBUG, "pos key = (objectid=%d, dirid=%d)\n", pos_key.on_disk_key.k_objectid, pos_key.on_disk_key.k_dir_id); if (COMP_SHORT_KEYS(rkey, &pos_key)) { /* End of directory has been reached */ reiserfs_log(LOG_DEBUG, "end reached (right)\n"); if (ap->a_eofflag) *ap->a_eofflag = 1; goto end; } /* Directory continues in the right neighboring block */ reiserfs_log(LOG_DEBUG, "continuing with a new offset\n"); set_cpu_key_k_offset(&pos_key, le_key_k_offset(KEY_FORMAT_3_5, rkey)); reiserfs_log(LOG_DEBUG, "new pos key = (objectid=%d, dirid=%d)\n", pos_key.on_disk_key.k_objectid, pos_key.on_disk_key.k_dir_id); } end: uio->uio_offset = next_pos; pathrelse(&path_to_entry); reiserfs_check_path(&path_to_entry); out: if (error && cookies != NULL) { free(cookies, M_REISERFSCOOKIES); } else if (ap->a_ncookies != NULL && ap->a_cookies != NULL) { *ap->a_ncookies = ncookies; *ap->a_cookies = cookies; } return (error); }
/* * Vnode op for reading directories. * * This function has to convert directory entries from the on-disk * format to the format defined by <sys/dirent.h>. Unfortunately, the * conversion will blow up some entries by four bytes, so it can't be * done in place. Instead, the conversion is done entry by entry and * the converted entry is sent via uiomove. * * XXX allocate a buffer, convert as many entries as possible, then send * the whole buffer to uiomove */ int ext2_readdir(struct vop_readdir_args *ap) { struct uio *uio = ap->a_uio; int count, error; struct ext2fs_direct_2 *edp, *dp; int ncookies; struct dirent dstdp; struct uio auio; struct iovec aiov; caddr_t dirbuf; int DIRBLKSIZ = VTOI(ap->a_vp)->i_e2fs->e2fs_bsize; int readcnt; off_t startoffset = uio->uio_offset; count = uio->uio_resid; /* * Avoid complications for partial directory entries by adjusting * the i/o to end at a block boundary. Don't give up (like ufs * does) if the initial adjustment gives a negative count, since * many callers don't supply a large enough buffer. The correct * size is a little larger than DIRBLKSIZ to allow for expansion * of directory entries, but some callers just use 512. */ count -= (uio->uio_offset + count) & (DIRBLKSIZ -1); if (count <= 0) count += DIRBLKSIZ; auio = *uio; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_resid = count; auio.uio_segflg = UIO_SYSSPACE; aiov.iov_len = count; dirbuf = malloc(count, M_TEMP, M_WAITOK); aiov.iov_base = dirbuf; error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred); if (error == 0) { readcnt = count - auio.uio_resid; edp = (struct ext2fs_direct_2 *)&dirbuf[readcnt]; ncookies = 0; bzero(&dstdp, offsetof(struct dirent, d_name)); for (dp = (struct ext2fs_direct_2 *)dirbuf; !error && uio->uio_resid > 0 && dp < edp; ) { /*- * "New" ext2fs directory entries differ in 3 ways * from ufs on-disk ones: * - the name is not necessarily NUL-terminated. * - the file type field always exists and always * follows the name length field. * - the file type is encoded in a different way. * * "Old" ext2fs directory entries need no special * conversions, since they are binary compatible * with "new" entries having a file type of 0 (i.e., * EXT2_FT_UNKNOWN). Splitting the old name length * field didn't make a mess like it did in ufs, * because ext2fs uses a machine-independent disk * layout. */ dstdp.d_fileno = dp->e2d_ino; dstdp.d_type = FTTODT(dp->e2d_type); dstdp.d_namlen = dp->e2d_namlen; dstdp.d_reclen = GENERIC_DIRSIZ(&dstdp); bcopy(dp->e2d_name, dstdp.d_name, dstdp.d_namlen); bzero(dstdp.d_name + dstdp.d_namlen, dstdp.d_reclen - offsetof(struct dirent, d_name) - dstdp.d_namlen); if (dp->e2d_reclen > 0) { if(dstdp.d_reclen <= uio->uio_resid) { /* advance dp */ dp = (struct ext2fs_direct_2 *) ((char *)dp + dp->e2d_reclen); error = uiomove(&dstdp, dstdp.d_reclen, uio); if (!error) ncookies++; } else break; } else { error = EIO; break; } } /* we need to correct uio_offset */ uio->uio_offset = startoffset + (caddr_t)dp - dirbuf; if (!error && ap->a_ncookies != NULL) { u_long *cookiep, *cookies, *ecookies; off_t off; if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1) panic("ext2_readdir: unexpected uio from NFS server"); cookies = malloc(ncookies * sizeof(u_long), M_TEMP, M_WAITOK); off = startoffset; for (dp = (struct ext2fs_direct_2 *)dirbuf, cookiep = cookies, ecookies = cookies + ncookies; cookiep < ecookies; dp = (struct ext2fs_direct_2 *)((caddr_t) dp + dp->e2d_reclen)) { off += dp->e2d_reclen; *cookiep++ = (u_long) off; } *ap->a_ncookies = ncookies; *ap->a_cookies = cookies; } }
static int dir_vers2dents(struct psfs_node *pnode, struct uio *uio, u_long *cookies, off_t maxcount, int *eofflag) { int error = 0; off_t off; ps_pubi_t pi; ps_meta_t meta; int index, i; KASSERT(0 == uio->uio_offset % DIRSIZ_RID && uio->uio_offset >= DIRSIZ_RID, ("Invalid uio_offset %ld", uio->uio_offset)); off = uio->uio_offset; PS_PRINTF(PS_DEBUG_DIR, "off=%ld, maxcount=%ld, eofflag=%p\n", off, maxcount, eofflag); error = ps_pit_get(pnode->pn_rid, &pi); if (error) return error; error = ps_obj_get_page(pi, VMO_META, 0, (void **)&meta); if (error) { PS_OBJ_PUBI_UNLOCK(pi); return error; } #ifdef INVARIANTS PS_PRINTF(PS_DEBUG_DIR, "meta->pm_interlock=%p:\n", meta->pm_interlock); if (ps_debug_mask & PS_DEBUG_DIR) { db_show_mtx(meta->pm_interlock); } #endif PS_OBJ_META_LOCK(meta); PS_OBJ_PUBI_UNLOCK(pi); index = (uio->uio_offset / DIRSIZ_RID) - 1; for (i = index; i < meta->pm_vers_count; i++) { ps_pubi_t vpi; struct dirent dent; error = ps_pit_get(meta->pm_sub_object[i], &vpi); if (error) { PS_PRINTF(PS_DEBUG_WARNING, "version %s not found in pit\n", psfs_id2str(meta->pm_sub_object[i], NULL)); error = 0; continue; } dent.d_fileno = vpi->pi_ino + IPUB; dent.d_type = DT_DIR; dent.d_namlen = PSIRP_ID_LEN * 2; dent.d_reclen = GENERIC_DIRSIZ(&dent); PS_OBJ_PUBI_UNLOCK(vpi); psfs_id2str(meta->pm_sub_object[i], dent.d_name); error = uiomove(&dent, dent.d_reclen, uio); if (cookies) *cookies++ = uio->uio_offset; if (error) break; } if (eofflag && i >= meta->pm_vers_count) *eofflag = TRUE; /* * Note that we have to unlock meta first, before locking pi, * as the locking order is always pi->meta->... */ PS_OBJ_META_UNLOCK(meta); /* XXX: Is there any possibility for some race condition here? */ PS_OBJ_PUBI_LOCK(pi); ps_obj_put_page(pi, VMO_META, FALSE); PS_OBJ_PUBI_UNLOCK(pi); if (error) return error; PS_PRINTF(PS_DEBUG_DIR, "i=%d, *eofflag=%d -> %d\n", i, eofflag? *eofflag: 4077, error); KASSERT((0 == uio->uio_offset % DIRSIZ_RID && uio->uio_offset >= DIRSIZ_RID), ("Invalid uio_offset %ld", uio->uio_offset)); return error; }
int fuse_internal_readdir_processdata(struct uio *uio, size_t reqsize, void *buf, size_t bufsize, void *param) { int err = 0; int cou = 0; int bytesavail; size_t freclen; struct dirent *de; struct fuse_dirent *fudge; struct fuse_iov *cookediov = param; if (bufsize < FUSE_NAME_OFFSET) { return -1; } for (;;) { if (bufsize < FUSE_NAME_OFFSET) { err = -1; break; } fudge = (struct fuse_dirent *)buf; freclen = FUSE_DIRENT_SIZE(fudge); cou++; if (bufsize < freclen) { err = ((cou == 1) ? -1 : 0); break; } #ifdef ZERO_PAD_INCOMPLETE_BUFS if (isbzero(buf, FUSE_NAME_OFFSET)) { err = -1; break; } #endif if (!fudge->namelen || fudge->namelen > MAXNAMLEN) { err = EINVAL; break; } bytesavail = GENERIC_DIRSIZ((struct pseudo_dirent *) &fudge->namelen); if (bytesavail > uio_resid(uio)) { err = -1; break; } fiov_refresh(cookediov); fiov_adjust(cookediov, bytesavail); de = (struct dirent *)cookediov->base; de->d_fileno = fudge->ino; /* XXX: truncation */ de->d_reclen = bytesavail; de->d_type = fudge->type; de->d_namlen = fudge->namelen; memcpy((char *)cookediov->base + sizeof(struct dirent) - MAXNAMLEN - 1, (char *)buf + FUSE_NAME_OFFSET, fudge->namelen); ((char *)cookediov->base)[bytesavail] = '\0'; err = uiomove(cookediov->base, cookediov->len, uio); if (err) { break; } buf = (char *)buf + freclen; bufsize -= freclen; uio_setoffset(uio, fudge->off); } return err; }
__private_extern__ int fuse_internal_readdir_processdata(vnode_t vp, uio_t uio, __unused size_t reqsize, void *buf, size_t bufsize, struct fuse_iov *cookediov, int *numdirent) { int err = 0; int cou = 0; int n = 0; size_t bytesavail; size_t freclen; struct dirent *de; struct fuse_dirent *fudge; if (bufsize < FUSE_NAME_OFFSET) { return -1; } for (;;) { if (bufsize < FUSE_NAME_OFFSET) { err = -1; break; } fudge = (struct fuse_dirent *)buf; freclen = FUSE_DIRENT_SIZE(fudge); cou++; if (bufsize < freclen) { err = ((cou == 1) ? -1 : 0); break; } /* * if (isbzero(buf, FUSE_NAME_OFFSET)) { * // zero-pad incomplete buffer * ... * err = -1; * break; * } */ if (!fudge->namelen) { err = EINVAL; break; } if (fudge->namelen > FUSE_MAXNAMLEN) { err = EIO; break; } #define GENERIC_DIRSIZ(dp) \ ((sizeof(struct dirent) - (FUSE_MAXNAMLEN + 1)) + \ (((dp)->d_namlen + 1 + 3) & ~3)) bytesavail = GENERIC_DIRSIZ((struct pseudo_dirent *)&fudge->namelen); if (bytesavail > (size_t)uio_resid(uio)) { err = -1; break; } fiov_refresh(cookediov); fiov_adjust(cookediov, bytesavail); de = (struct dirent *)cookediov->base; #if __DARWIN_64_BIT_INO_T de->d_fileno = fudge->ino; #else de->d_fileno = (ino_t)fudge->ino; /* XXX: truncation */ #endif /* __DARWIN_64_BIT_INO_T */ de->d_reclen = bytesavail; de->d_type = fudge->type; de->d_namlen = fudge->namelen; /* Filter out any ._* files if the mount is configured as such. */ if (fuse_skip_apple_double_mp(vnode_mount(vp), fudge->name, fudge->namelen)) { de->d_fileno = 0; de->d_type = DT_WHT; } memcpy((char *)cookediov->base + sizeof(struct dirent) - FUSE_MAXNAMLEN - 1, (char *)buf + FUSE_NAME_OFFSET, fudge->namelen); ((char *)cookediov->base)[bytesavail] = '\0'; err = uiomove(cookediov->base, (int)cookediov->len, uio); if (err) { break; } n++; buf = (char *)buf + freclen; bufsize -= freclen; uio_setoffset(uio, fudge->off); } if (!err && numdirent) { *numdirent = n; } return err; }