int ntfs_readdir(void *v) { struct vop_readdir_args /* { struct vnode *a_vp; struct uio *a_uio; kauth_cred_t a_cred; int *a_ncookies; u_int **cookies; } */ *ap = v; struct vnode *vp = ap->a_vp; struct fnode *fp = VTOF(vp); struct ntnode *ip = FTONT(fp); struct uio *uio = ap->a_uio; struct ntfsmount *ntmp = ip->i_mp; int i, error = 0; u_int32_t faked = 0, num; int ncookies = 0; struct dirent *cde; off_t off; dprintf(("ntfs_readdir %llu off: %qd resid: %qd\n", (unsigned long long)ip->i_number, (long long)uio->uio_offset, (long long)uio->uio_resid)); off = uio->uio_offset; cde = malloc(sizeof(struct dirent), M_TEMP, M_WAITOK); /* Simulate . in every dir except ROOT */ if (ip->i_number != NTFS_ROOTINO && uio->uio_offset < sizeof(struct dirent)) { cde->d_fileno = ip->i_number; cde->d_reclen = sizeof(struct dirent); cde->d_type = DT_DIR; cde->d_namlen = 1; strncpy(cde->d_name, ".", 2); error = uiomove((void *)cde, sizeof(struct dirent), uio); if (error) goto out; ncookies++; } /* Simulate .. in every dir including ROOT */ if (uio->uio_offset < 2 * sizeof(struct dirent)) { cde->d_fileno = NTFS_ROOTINO; /* XXX */ cde->d_reclen = sizeof(struct dirent); cde->d_type = DT_DIR; cde->d_namlen = 2; strncpy(cde->d_name, "..", 3); error = uiomove((void *) cde, sizeof(struct dirent), uio); if (error) goto out; ncookies++; } faked = (ip->i_number == NTFS_ROOTINO) ? 1 : 2; num = uio->uio_offset / sizeof(struct dirent) - faked; while (uio->uio_resid >= sizeof(struct dirent)) { struct attr_indexentry *iep; char *fname; size_t remains; int sz; error = ntfs_ntreaddir(ntmp, fp, num, &iep); if (error) goto out; if (NULL == iep) break; for(; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (uio->uio_resid >= sizeof(struct dirent)); iep = NTFS_NEXTREC(iep, struct attr_indexentry *)) { if(!ntfs_isnamepermitted(ntmp,iep)) continue; remains = sizeof(cde->d_name) - 1; fname = cde->d_name; for(i=0; i<iep->ie_fnamelen; i++) { sz = (*ntmp->ntm_wput)(fname, remains, iep->ie_fname[i]); fname += sz; remains -= sz; } *fname = '\0'; dprintf(("ntfs_readdir: elem: %d, fname:[%s] type: %d, flag: %d, ", num, cde->d_name, iep->ie_fnametype, iep->ie_flag)); cde->d_namlen = fname - (char *) cde->d_name; cde->d_fileno = iep->ie_number; cde->d_type = (iep->ie_fflag & NTFS_FFLAG_DIR) ? DT_DIR : DT_REG; cde->d_reclen = sizeof(struct dirent); dprintf(("%s\n", (cde->d_type == DT_DIR) ? "dir":"reg")); error = uiomove((void *)cde, sizeof(struct dirent), uio); if (error) goto out; ncookies++; num++; } } dprintf(("ntfs_readdir: %d entries (%d bytes) read\n", ncookies,(u_int)(uio->uio_offset - off))); dprintf(("ntfs_readdir: off: %qd resid: %qu\n", (long long)uio->uio_offset,(long long)uio->uio_resid)); if (!error && ap->a_ncookies != NULL) { struct dirent* dpStart; struct dirent* dp; off_t *cookies; off_t *cookiep; dprintf(("ntfs_readdir: %d cookies\n",ncookies)); dpStart = (struct dirent *) ((char *)uio->uio_iov->iov_base - (uio->uio_offset - off)); cookies = malloc(ncookies * sizeof(off_t), M_TEMP, M_WAITOK); for (dp = dpStart, cookiep = cookies, i=0; i < ncookies; dp = (struct dirent *)((char *) dp + dp->d_reclen), i++) { off += dp->d_reclen; *cookiep++ = (u_int) off; } *ap->a_ncookies = ncookies; *ap->a_cookies = cookies; } /* if (ap->a_eofflag) *ap->a_eofflag = VTONT(ap->a_vp)->i_size <= uio->uio_offset; */ out: free(cde, M_TEMP); return (error); }
int ntfs_readdir(void *v) { struct vop_readdir_args *ap = v; struct vnode *vp = ap->a_vp; struct fnode *fp = VTOF(vp); struct ntnode *ip = FTONT(fp); struct uio *uio = ap->a_uio; struct ntfsmount *ntmp = ip->i_mp; int i, error = 0; u_int32_t faked = 0, num; struct dirent cde; off_t off; DPRINTF("ntfs_readdir %u off: %lld resid: %zu\n", ip->i_number, uio->uio_offset, uio->uio_resid); off = uio->uio_offset; memset(&cde, 0, sizeof(cde)); /* Simulate . in every dir except ROOT */ if (ip->i_number != NTFS_ROOTINO && uio->uio_offset == 0) { cde.d_fileno = ip->i_number; cde.d_reclen = sizeof(struct dirent); cde.d_type = DT_DIR; cde.d_namlen = 1; cde.d_off = sizeof(struct dirent); cde.d_name[0] = '.'; cde.d_name[1] = '\0'; error = uiomove(&cde, sizeof(struct dirent), uio); if (error) goto out; } /* Simulate .. in every dir including ROOT */ if (uio->uio_offset < 2 * sizeof(struct dirent)) { cde.d_fileno = NTFS_ROOTINO; /* XXX */ cde.d_reclen = sizeof(struct dirent); cde.d_type = DT_DIR; cde.d_namlen = 2; cde.d_off = 2 * sizeof(struct dirent); cde.d_name[0] = '.'; cde.d_name[1] = '.'; cde.d_name[2] = '\0'; error = uiomove(&cde, sizeof(struct dirent), uio); if (error) goto out; } faked = (ip->i_number == NTFS_ROOTINO) ? 1 : 2; num = uio->uio_offset / sizeof(struct dirent) - faked; while (uio->uio_resid >= sizeof(struct dirent)) { struct attr_indexentry *iep; char *fname; size_t remains; int sz; error = ntfs_ntreaddir(ntmp, fp, num, &iep, uio->uio_procp); if (error) goto out; if (NULL == iep) break; for(; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (uio->uio_resid >= sizeof(struct dirent)); iep = NTFS_NEXTREC(iep, struct attr_indexentry *)) { if(!ntfs_isnamepermitted(ntmp,iep)) continue; remains = sizeof(cde.d_name) - 1; fname = cde.d_name; for(i=0; i<iep->ie_fnamelen; i++) { sz = (*ntmp->ntm_wput)(fname, remains, iep->ie_fname[i]); fname += sz; remains -= sz; } *fname = '\0'; DPRINTF("ntfs_readdir: elem: %u, fname:[%s] type: %u, " "flag: %u, ", num, cde.d_name, iep->ie_fnametype, iep->ie_flag); cde.d_namlen = fname - (char *) cde.d_name; cde.d_fileno = iep->ie_number; cde.d_type = (iep->ie_fflag & NTFS_FFLAG_DIR) ? DT_DIR : DT_REG; cde.d_reclen = sizeof(struct dirent); cde.d_off = uio->uio_offset + sizeof(struct dirent); DPRINTF("%s\n", cde.d_type == DT_DIR ? "dir" : "reg"); error = uiomove(&cde, sizeof(struct dirent), uio); if (error) goto out; num++; } } DPRINTF("ntfs_readdir: %u entries (%lld bytes) read\n", num, uio->uio_offset - off); DPRINTF("ntfs_readdir: off: %lld resid: %zu\n", uio->uio_offset, uio->uio_resid); /* if (ap->a_eofflag) *ap->a_eofflag = VTONT(ap->a_vp)->i_size <= uio->uio_offset; */ out: if (fp->f_dirblbuf != NULL) { free(fp->f_dirblbuf, M_NTFSDIR, 0); fp->f_dirblbuf = NULL; } return (error); }