Page MenuHomeFreeBSD

D5266.diff
No OneTemporary

D5266.diff

Index: head/sys/fs/autofs/autofs.h
===================================================================
--- head/sys/fs/autofs/autofs.h
+++ head/sys/fs/autofs/autofs.h
@@ -120,13 +120,6 @@
int sc_last_request_id;
};
-/*
- * Limits and constants
- */
-#define AUTOFS_NAMELEN 24
-#define AUTOFS_FSNAMELEN 16 /* equal to MFSNAMELEN */
-#define AUTOFS_DELEN (8 + AUTOFS_NAMELEN)
-
int autofs_init(struct vfsconf *vfsp);
int autofs_uninit(struct vfsconf *vfsp);
int autofs_trigger(struct autofs_node *anp, const char *component,
Index: head/sys/fs/autofs/autofs_vnops.c
===================================================================
--- head/sys/fs/autofs/autofs_vnops.c
+++ head/sys/fs/autofs/autofs_vnops.c
@@ -330,26 +330,52 @@
return (error);
}
+/*
+ * Write out a single 'struct dirent', based on 'name' and 'fileno' arguments.
+ */
static int
-autofs_readdir_one(struct uio *uio, const char *name, int fileno)
+autofs_readdir_one(struct uio *uio, const char *name, int fileno,
+ size_t *reclenp)
{
struct dirent dirent;
- int error, i;
+ size_t namlen, padded_namlen, reclen;
+ int error;
+
+ namlen = strlen(name);
+ padded_namlen = roundup2(namlen + 1, __alignof(struct dirent));
+ KASSERT(padded_namlen <= MAXNAMLEN, ("%zd > MAXNAMLEN", padded_namlen));
+ reclen = offsetof(struct dirent, d_name) + padded_namlen;
+
+ if (reclenp != NULL)
+ *reclenp = reclen;
+
+ if (uio == NULL)
+ return (0);
+
+ if (uio->uio_resid < reclen)
+ return (EINVAL);
- memset(&dirent, 0, sizeof(dirent));
- dirent.d_type = DT_DIR;
- dirent.d_reclen = AUTOFS_DELEN;
dirent.d_fileno = fileno;
- /* PFS_DELEN was picked to fit PFS_NAMLEN */
- for (i = 0; i < AUTOFS_NAMELEN - 1 && name[i] != '\0'; ++i)
- dirent.d_name[i] = name[i];
- dirent.d_name[i] = 0;
- dirent.d_namlen = i;
+ dirent.d_reclen = reclen;
+ dirent.d_type = DT_DIR;
+ dirent.d_namlen = namlen;
+ memcpy(dirent.d_name, name, namlen);
+ memset(dirent.d_name + namlen, 0, padded_namlen - namlen);
+ error = uiomove(&dirent, reclen, uio);
- error = uiomove(&dirent, AUTOFS_DELEN, uio);
return (error);
}
+static size_t
+autofs_dirent_reclen(const char *name)
+{
+ size_t reclen;
+
+ autofs_readdir_one(NULL, name, -1, &reclen);
+
+ return (reclen);
+}
+
static int
autofs_readdir(struct vop_readdir_args *ap)
{
@@ -357,13 +383,15 @@
struct autofs_mount *amp;
struct autofs_node *anp, *child;
struct uio *uio;
- off_t offset;
- int error, i, resid;
+ size_t reclen, reclens;
+ ssize_t initial_resid;
+ int error;
vp = ap->a_vp;
amp = VFSTOAUTOFS(vp->v_mount);
anp = vp->v_data;
uio = ap->a_uio;
+ initial_resid = ap->a_uio->uio_resid;
KASSERT(vp->v_type == VDIR, ("!VDIR"));
@@ -381,70 +409,94 @@
}
}
- /* only allow reading entire entries */
- offset = uio->uio_offset;
- resid = uio->uio_resid;
- if (offset < 0 || offset % AUTOFS_DELEN != 0 ||
- (resid && resid < AUTOFS_DELEN))
+ if (uio->uio_offset < 0)
return (EINVAL);
- if (resid == 0)
- return (0);
if (ap->a_eofflag != NULL)
- *ap->a_eofflag = TRUE;
+ *ap->a_eofflag = FALSE;
- if (offset == 0 && resid >= AUTOFS_DELEN) {
- error = autofs_readdir_one(uio, ".", anp->an_fileno);
+ /*
+ * Write out the directory entry for ".". This is conditional
+ * on the current offset into the directory; same applies to the
+ * other two cases below.
+ */
+ if (uio->uio_offset == 0) {
+ error = autofs_readdir_one(uio, ".", anp->an_fileno, &reclen);
if (error != 0)
- return (error);
- offset += AUTOFS_DELEN;
- resid -= AUTOFS_DELEN;
+ goto out;
}
+ reclens = autofs_dirent_reclen(".");
- if (offset == AUTOFS_DELEN && resid >= AUTOFS_DELEN) {
+ /*
+ * Write out the directory entry for "..".
+ */
+ if (uio->uio_offset <= reclens) {
+ if (uio->uio_offset != reclens)
+ return (EINVAL);
if (anp->an_parent == NULL) {
- /*
- * XXX: Right?
- */
- error = autofs_readdir_one(uio, "..", anp->an_fileno);
+ error = autofs_readdir_one(uio, "..",
+ anp->an_fileno, &reclen);
} else {
error = autofs_readdir_one(uio, "..",
- anp->an_parent->an_fileno);
+ anp->an_parent->an_fileno, &reclen);
}
if (error != 0)
- return (error);
- offset += AUTOFS_DELEN;
- resid -= AUTOFS_DELEN;
+ goto out;
}
- i = 2; /* Account for "." and "..". */
+ reclens += autofs_dirent_reclen("..");
+
+ /*
+ * Write out the directory entries for subdirectories.
+ */
AUTOFS_SLOCK(amp);
TAILQ_FOREACH(child, &anp->an_children, an_next) {
- if (resid < AUTOFS_DELEN) {
- if (ap->a_eofflag != NULL)
- *ap->a_eofflag = 0;
- break;
+ /*
+ * Check the offset to skip entries returned by previous
+ * calls to getdents().
+ */
+ if (uio->uio_offset > reclens) {
+ reclens += autofs_dirent_reclen(child->an_name);
+ continue;
}
/*
- * Skip entries returned by previous call to getdents().
+ * Prevent seeking into the middle of dirent.
*/
- i++;
- if (i * AUTOFS_DELEN <= offset)
- continue;
+ if (uio->uio_offset != reclens) {
+ AUTOFS_SUNLOCK(amp);
+ return (EINVAL);
+ }
error = autofs_readdir_one(uio, child->an_name,
- child->an_fileno);
+ child->an_fileno, &reclen);
+ reclens += reclen;
if (error != 0) {
AUTOFS_SUNLOCK(amp);
- return (error);
+ goto out;
}
- offset += AUTOFS_DELEN;
- resid -= AUTOFS_DELEN;
}
-
AUTOFS_SUNLOCK(amp);
+
+ if (ap->a_eofflag != NULL)
+ *ap->a_eofflag = TRUE;
+
return (0);
+
+out:
+ /*
+ * Return error if the initial buffer was too small to do anything.
+ */
+ if (uio->uio_resid == initial_resid)
+ return (error);
+
+ /*
+ * Don't return an error if we managed to copy out some entries.
+ */
+ if (uio->uio_resid < reclen)
+ return (0);
+
+ return (error);
}
static int

File Metadata

Mime Type
text/plain
Expires
Tue, Jan 14, 4:20 AM (21 h, 35 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15790939
Default Alt Text
D5266.diff (5 KB)

Event Timeline