All of lore.kernel.org
 help / color / mirror / Atom feed
From: Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
To: "linux-cifs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org"
	<linux-cifs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
Cc: samba-technical
	<samba-technical-w/Ol4Ecudpl8XjKLYN78aQ@public.gmane.org>,
	linux-fsdevel
	<linux-fsdevel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
Subject: Re: [PATCH] [SMB3] Add mfsymlinks support for SMB2.1/SMB3. Part 1 create symlink
Date: Tue, 16 Sep 2014 00:52:24 -0500	[thread overview]
Message-ID: <CAH2r5muZNyC2eBxntmWE=dhb5-jnwCRpGqo9j1SacQvESs92CQ@mail.gmail.com> (raw)
In-Reply-To: <CAH2r5msPjpPvom=0G0-Sj3RdnXMRVJpXb=VBiRZ+E0RSqAPh6g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 5392 bytes --]

Resending patch series as attachments to avoid mailer issues



On Mon, Sep 15, 2014 at 1:39 PM, Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> Adds support on SMB2.1 and SMB3 mounts for emulation of symlinks
> via the "Minshall/French" symlink format already used for cifs
> mounts when mfsymlinks mount option is used (and also used by Apple).
> http://wiki.samba.org/index.php/UNIX_Extensions#Minshall.2BFrench_symlinks
> This first patch adds support to create them.  The next patch will
> add support for recognizing them and reading them.  Although CIFS/SMB3
> have other types of symlinks, in the many use cases they aren't
> practical (e.g. either require cifs only mounts with unix extensions
> to Samba, or require the user to be Administrator to Windows for SMB3).
> This also helps enable running additional xfstests over SMB3 (since some
> xfstests directly or indirectly require symlink support).
>
> Signed-off-by: Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> CC: Stefan Metzmacher <metze-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org>
> ---
>  fs/cifs/link.c      | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++
>  fs/cifs/smb2ops.c   |  2 ++
>  fs/cifs/smb2proto.h |  4 +++-
>  3 files changed, 68 insertions(+), 1 deletion(-)
>
> diff --git a/fs/cifs/link.c b/fs/cifs/link.c
> index a5c2812..11657f6 100644
> --- a/fs/cifs/link.c
> +++ b/fs/cifs/link.c
> @@ -28,6 +28,7 @@
>  #include "cifsproto.h"
>  #include "cifs_debug.h"
>  #include "cifs_fs_sb.h"
> +#include "smb2proto.h"
>
>  /*
>   * M-F Symlink Functions - Begin
> @@ -398,6 +399,68 @@ cifs_create_mf_symlink(unsigned int xid, struct
> cifs_tcon *tcon,
>      return rc;
>  }
>
> +int
> +smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
> +               struct cifs_sb_info *cifs_sb, const unsigned char *path,
> +               char *pbuf, unsigned int *pbytes_written)
> +{
> +    int rc;
> +    struct cifs_fid fid;
> +    struct cifs_open_parms oparms;
> +    struct cifs_io_parms io_parms;
> +    int create_options = CREATE_NOT_DIR;
> +    __le16 *utf16_path;
> +    __u8 oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
> +    struct kvec iov[2];
> +
> +    if (backup_cred(cifs_sb))
> +        create_options |= CREATE_OPEN_BACKUP_INTENT;
> +
> +    cifs_dbg(FYI, "%s: path: %s\n", __func__, path);
> +
> +    utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
> +    if (!utf16_path)
> +        return -ENOMEM;
> +
> +    oparms.tcon = tcon;
> +    oparms.cifs_sb = cifs_sb;
> +    oparms.desired_access = GENERIC_WRITE;
> +    oparms.create_options = create_options;
> +    oparms.disposition = FILE_CREATE;
> +    oparms.fid = &fid;
> +    oparms.reconnect = false;
> +
> +    rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
> +    if (rc) {
> +        kfree(utf16_path);
> +        return rc;
> +    }
> +
> +    io_parms.netfid = fid.netfid;
> +    io_parms.pid = current->tgid;
> +    io_parms.tcon = tcon;
> +    io_parms.offset = 0;
> +    io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
> +    io_parms.persistent_fid = fid.persistent_fid;
> +    io_parms.volatile_fid = fid.volatile_fid;
> +
> +    /* iov[0] is reserved for smb header */
> +    iov[1].iov_base = pbuf;
> +    iov[1].iov_len = CIFS_MF_SYMLINK_FILE_SIZE;
> +
> +    rc = SMB2_write(xid, &io_parms, pbytes_written, iov, 1);
> +
> +    /* Make sure we wrote all of the symlink data */
> +    if ((rc == 0) && (*pbytes_written != CIFS_MF_SYMLINK_FILE_SIZE))
> +        rc = -EIO;
> +
> +    SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
> +
> +    kfree(utf16_path);
> +    return rc;
> +}
> +
> +
>  /*
>   * M-F Symlink Functions - End
>   */
> diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
> index f522193..7d3fa29 100644
> --- a/fs/cifs/smb2ops.c
> +++ b/fs/cifs/smb2ops.c
> @@ -1452,6 +1452,7 @@ struct smb_version_operations smb21_operations = {
>      .rename = smb2_rename_path,
>      .create_hardlink = smb2_create_hardlink,
>      .query_symlink = smb2_query_symlink,
> +    .create_mf_symlink = smb3_create_mf_symlink,
>      .open = smb2_open_file,
>      .set_fid = smb2_set_fid,
>      .close = smb2_close_file,
> @@ -1531,6 +1532,7 @@ struct smb_version_operations smb30_operations = {
>      .rename = smb2_rename_path,
>      .create_hardlink = smb2_create_hardlink,
>      .query_symlink = smb2_query_symlink,
> +    .create_mf_symlink = smb3_create_mf_symlink,
>      .open = smb2_open_file,
>      .set_fid = smb2_set_fid,
>      .close = smb2_close_file,
> diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
> index 67e8ce8..e144ecf 100644
> --- a/fs/cifs/smb2proto.h
> +++ b/fs/cifs/smb2proto.h
> @@ -82,7 +82,9 @@ extern int smb2_rename_path(const unsigned int xid,
> struct cifs_tcon *tcon,
>  extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
>                  const char *from_name, const char *to_name,
>                  struct cifs_sb_info *cifs_sb);
> -
> +extern int smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
> +            struct cifs_sb_info *cifs_sb, const unsigned char *path,
> +            char *pbuf, unsigned int *pbytes_written);
>  extern int smb2_open_file(const unsigned int xid,
>                struct cifs_open_parms *oparms,
>                __u32 *oplock, FILE_ALL_INFO *buf);
> --
>
> --
> Thanks,
>
> Steve



-- 
Thanks,

Steve

[-- Attachment #2: 0004-SMB3-Add-mfsymlinks-support-for-SMB2.1-SMB3.-Part-2-.patch --]
[-- Type: text/x-patch, Size: 4589 bytes --]

From 409cdce61e48d19273722e331a427cd12aa1cecf Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@gmail.com>
Date: Mon, 15 Sep 2014 18:06:17 -0500
Subject: [PATCH 4/4] [SMB3] Add mfsymlinks support for SMB2.1/SMB3.  Part 2
 query symlink

    Adds support on SMB2.1 and SMB3 mounts for emulation of symlinks
    via the "Minshall/French" symlink format already used for cifs
    mounts when mfsymlinks mount option is used (and also used by Apple).
    http://wiki.samba.org/index.php/UNIX_Extensions#Minshall.2BFrench_symlinks
    This second patch adds support to query them (recognize them as symlinks
    and read them).

    Signed-off-by: Steve French <smfrench@gmail.com>
    CC: Stefan Metzmacher <metze@samba.org>
---
 fs/cifs/link.c      | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/cifs/smb2ops.c   |  2 ++
 fs/cifs/smb2proto.h |  4 ++++
 3 files changed, 71 insertions(+)

diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 11657f6..cf1113e 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -399,6 +399,71 @@ cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
 	return rc;
 }
 
+/*
+ * SMB 2.1/SMB3 Protocol specific functions
+ */
+
+int
+smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
+		      struct cifs_sb_info *cifs_sb, const unsigned char *path,
+		      char *pbuf, unsigned int *pbytes_read)
+{
+	int rc;
+	struct cifs_fid fid;
+	struct cifs_open_parms oparms;
+	struct cifs_io_parms io_parms;
+	int buf_type = CIFS_NO_BUFFER;
+	__le16 *utf16_path;
+	__u8 oplock = SMB2_OPLOCK_LEVEL_II;
+	struct smb2_file_all_info *pfile_info = NULL;
+
+	oparms.tcon = tcon;
+	oparms.cifs_sb = cifs_sb;
+	oparms.desired_access = GENERIC_READ;
+	oparms.create_options = CREATE_NOT_DIR;
+	if (backup_cred(cifs_sb))
+		oparms.create_options |= CREATE_OPEN_BACKUP_INTENT;
+	oparms.disposition = FILE_OPEN;
+	oparms.fid = &fid;
+	oparms.reconnect = false;
+
+	utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
+	if (utf16_path == NULL)
+		return -ENOMEM;
+
+	pfile_info = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
+			     GFP_KERNEL);
+
+	if (pfile_info == NULL) {
+		rc = -ENOMEM;
+		goto qmf_out;
+	}
+
+	rc = SMB2_open(xid, &oparms, utf16_path, &oplock, pfile_info, NULL);
+	if (rc)
+		goto qmf_out;
+
+	if (pfile_info->EndOfFile != cpu_to_le64(CIFS_MF_SYMLINK_FILE_SIZE)) {
+		/* it's not a symlink */
+		rc = -ENOENT; /* Is there a better rc to return? */
+		goto qmf_out;
+	}
+
+	io_parms.netfid = fid.netfid;
+	io_parms.pid = current->tgid;
+	io_parms.tcon = tcon;
+	io_parms.offset = 0;
+	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
+	io_parms.persistent_fid = fid.persistent_fid;
+	io_parms.volatile_fid = fid.volatile_fid;
+	rc = SMB2_read(xid, &io_parms, pbytes_read, &pbuf, &buf_type);
+qmf_out:
+	kfree(utf16_path);
+	kfree(pfile_info);
+	SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
+	return rc;
+}
+
 int
 smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
 		       struct cifs_sb_info *cifs_sb, const unsigned char *path,
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 7d3fa29..489f48b 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -1452,6 +1452,7 @@ struct smb_version_operations smb21_operations = {
 	.rename = smb2_rename_path,
 	.create_hardlink = smb2_create_hardlink,
 	.query_symlink = smb2_query_symlink,
+	.query_mf_symlink = smb3_query_mf_symlink,
 	.create_mf_symlink = smb3_create_mf_symlink,
 	.open = smb2_open_file,
 	.set_fid = smb2_set_fid,
@@ -1532,6 +1533,7 @@ struct smb_version_operations smb30_operations = {
 	.rename = smb2_rename_path,
 	.create_hardlink = smb2_create_hardlink,
 	.query_symlink = smb2_query_symlink,
+	.query_mf_symlink = smb3_query_mf_symlink,
 	.create_mf_symlink = smb3_create_mf_symlink,
 	.open = smb2_open_file,
 	.set_fid = smb2_set_fid,
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index e144ecf..79dc650 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -85,6 +85,10 @@ extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
 extern int smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
 			struct cifs_sb_info *cifs_sb, const unsigned char *path,
 			char *pbuf, unsigned int *pbytes_written);
+extern int smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
+			  struct cifs_sb_info *cifs_sb,
+			  const unsigned char *path, char *pbuf,
+			  unsigned int *pbytes_read);
 extern int smb2_open_file(const unsigned int xid,
 			  struct cifs_open_parms *oparms,
 			  __u32 *oplock, FILE_ALL_INFO *buf);
-- 
1.9.1


[-- Attachment #3: 0003-SMB3-Add-mfsymlinks-support-for-SMB2.1-SMB3.-Part-1-.patch --]
[-- Type: text/x-patch, Size: 4832 bytes --]

From f56301e370b53a96a595289ab54dab33573f82ce Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@gmail.com>
Date: Mon, 15 Sep 2014 04:49:28 -0500
Subject: [PATCH 3/4] [SMB3] Add mfsymlinks support for SMB2.1/SMB3.  Part 1
 create symlink

Adds support on SMB2.1 and SMB3 mounts for emulation of symlinks
via the "Minshall/French" symlink format already used for cifs
mounts when mfsymlinks mount option is used (and also used by Apple).
http://wiki.samba.org/index.php/UNIX_Extensions#Minshall.2BFrench_symlinks
This first patch adds support to create them.  The next patch will
add support for recognizing them and reading them.  Although CIFS/SMB3
have other types of symlinks, in the many use cases they aren't
practical (e.g. either require cifs only mounts with unix extensions
to Samba, or require the user to be Administrator to Windows for SMB3).
This also helps enable running additional xfstests over SMB3 (since some
xfstests directly or indirectly require symlink support).

Signed-off-by: Steve French <smfrench@gmail.com>
CC: Stefan Metzmacher <metze@samba.org>
---
 fs/cifs/link.c      | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 fs/cifs/smb2ops.c   |  2 ++
 fs/cifs/smb2proto.h |  4 +++-
 3 files changed, 68 insertions(+), 1 deletion(-)

diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index a5c2812..11657f6 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -28,6 +28,7 @@
 #include "cifsproto.h"
 #include "cifs_debug.h"
 #include "cifs_fs_sb.h"
+#include "smb2proto.h"
 
 /*
  * M-F Symlink Functions - Begin
@@ -398,6 +399,68 @@ cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
 	return rc;
 }
 
+int
+smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
+		       struct cifs_sb_info *cifs_sb, const unsigned char *path,
+		       char *pbuf, unsigned int *pbytes_written)
+{
+	int rc;
+	struct cifs_fid fid;
+	struct cifs_open_parms oparms;
+	struct cifs_io_parms io_parms;
+	int create_options = CREATE_NOT_DIR;
+	__le16 *utf16_path;
+	__u8 oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+	struct kvec iov[2];
+
+	if (backup_cred(cifs_sb))
+		create_options |= CREATE_OPEN_BACKUP_INTENT;
+
+	cifs_dbg(FYI, "%s: path: %s\n", __func__, path);
+
+	utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
+	if (!utf16_path)
+		return -ENOMEM;
+
+	oparms.tcon = tcon;
+	oparms.cifs_sb = cifs_sb;
+	oparms.desired_access = GENERIC_WRITE;
+	oparms.create_options = create_options;
+	oparms.disposition = FILE_CREATE;
+	oparms.fid = &fid;
+	oparms.reconnect = false;
+
+	rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
+	if (rc) {
+		kfree(utf16_path);
+		return rc;
+	}
+
+	io_parms.netfid = fid.netfid;
+	io_parms.pid = current->tgid;
+	io_parms.tcon = tcon;
+	io_parms.offset = 0;
+	io_parms.length = CIFS_MF_SYMLINK_FILE_SIZE;
+	io_parms.persistent_fid = fid.persistent_fid;
+	io_parms.volatile_fid = fid.volatile_fid;
+
+	/* iov[0] is reserved for smb header */
+	iov[1].iov_base = pbuf;
+	iov[1].iov_len = CIFS_MF_SYMLINK_FILE_SIZE;
+
+	rc = SMB2_write(xid, &io_parms, pbytes_written, iov, 1);
+
+	/* Make sure we wrote all of the symlink data */
+	if ((rc == 0) && (*pbytes_written != CIFS_MF_SYMLINK_FILE_SIZE))
+		rc = -EIO;
+
+	SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
+
+	kfree(utf16_path);
+	return rc;
+}
+
+
 /*
  * M-F Symlink Functions - End
  */
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index f522193..7d3fa29 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -1452,6 +1452,7 @@ struct smb_version_operations smb21_operations = {
 	.rename = smb2_rename_path,
 	.create_hardlink = smb2_create_hardlink,
 	.query_symlink = smb2_query_symlink,
+	.create_mf_symlink = smb3_create_mf_symlink,
 	.open = smb2_open_file,
 	.set_fid = smb2_set_fid,
 	.close = smb2_close_file,
@@ -1531,6 +1532,7 @@ struct smb_version_operations smb30_operations = {
 	.rename = smb2_rename_path,
 	.create_hardlink = smb2_create_hardlink,
 	.query_symlink = smb2_query_symlink,
+	.create_mf_symlink = smb3_create_mf_symlink,
 	.open = smb2_open_file,
 	.set_fid = smb2_set_fid,
 	.close = smb2_close_file,
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 67e8ce8..e144ecf 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -82,7 +82,9 @@ extern int smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
 extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
 				const char *from_name, const char *to_name,
 				struct cifs_sb_info *cifs_sb);
-
+extern int smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
+			struct cifs_sb_info *cifs_sb, const unsigned char *path,
+			char *pbuf, unsigned int *pbytes_written);
 extern int smb2_open_file(const unsigned int xid,
 			  struct cifs_open_parms *oparms,
 			  __u32 *oplock, FILE_ALL_INFO *buf);
-- 
1.9.1


[-- Attachment #4: 0002-SMB3-Fix-oops-when-creating-symlinks-on-smb3.patch --]
[-- Type: text/x-patch, Size: 1163 bytes --]

From da80659d4aa758dc6935b10ec64513f0b67bc969 Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@gmail.com>
Date: Sun, 14 Sep 2014 23:27:09 -0500
Subject: [PATCH 2/4] [SMB3] Fix oops when creating symlinks on smb3

We were not checking for symlink support properly for SMB2/SMB3
mounts so could oops when mounted with mfsymlinks when try
to create symlink when mfsymlinks on smb2/smb3 mounts

Signed-off-by: Steve French <smfrench@gmail.com>
Cc: <stable@vger.kernel.org> # 3.14+
CC: Sachin Prabhu <sprabhu@redhat.com>
---
 fs/cifs/link.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index 68559fd..a5c2812 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -213,8 +213,12 @@ create_mf_symlink(const unsigned int xid, struct cifs_tcon *tcon,
 	if (rc)
 		goto out;
 
-	rc = tcon->ses->server->ops->create_mf_symlink(xid, tcon, cifs_sb,
-					fromName, buf, &bytes_written);
+	if (tcon->ses->server->ops->create_mf_symlink)
+		rc = tcon->ses->server->ops->create_mf_symlink(xid, tcon,
+					cifs_sb, fromName, buf, &bytes_written);
+	else
+		rc = -EOPNOTSUPP;
+
 	if (rc)
 		goto out;
 
-- 
1.9.1


      parent reply	other threads:[~2014-09-16  5:52 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-09-15 18:39 [PATCH] [SMB3] Add mfsymlinks support for SMB2.1/SMB3. Part 1 create symlink Steve French
     [not found] ` <CAH2r5msPjpPvom=0G0-Sj3RdnXMRVJpXb=VBiRZ+E0RSqAPh6g-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-09-16  5:52   ` Steve French [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAH2r5muZNyC2eBxntmWE=dhb5-jnwCRpGqo9j1SacQvESs92CQ@mail.gmail.com' \
    --to=smfrench-re5jqeeqqe8avxtiumwx3w@public.gmane.org \
    --cc=linux-cifs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-fsdevel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=samba-technical-w/Ol4Ecudpl8XjKLYN78aQ@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.