mkfs: substitute slashes with spaces in protofiles
A user requested the ability to specify directory entry names in a
protofile that have spaces in them. The protofile format itself does
not allow spaces (yay 1973-era protofiles!) but it does allow slashes.
Slashes aren't allowed in directory entry names, so we'll permit this
one gross hack. After this, the protofile:
/
0 0
d--775 1000 1000
: Descending path /code/t/fstests
get/isk.sh ---775 1000 1000 /code/t/fstests/getdisk.sh
$
Will produce "get isk.h" in the root directory when used thusly:
# mkfs.xfs -p slashes_are_spaces=1,/tmp/protofile -f /dev/sda
Requested-by: Daan De Meyer <daan.j.demeyer@gmail.com>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
diff --git a/man/man8/mkfs.xfs.8.in b/man/man8/mkfs.xfs.8.in
index e1ca40e..49e64d4 100644
--- a/man/man8/mkfs.xfs.8.in
+++ b/man/man8/mkfs.xfs.8.in
@@ -996,6 +996,12 @@
always terminated with the dollar (
.B $
) token.
+.TP
+.BI slashes_are_spaces= value
+If set to 1, slashes ("/") in the first token of each line of the protofile
+are converted to spaces.
+This enables the creation of a filesystem containing filenames with spaces.
+By default, this is set to 0.
.RE
.TP
.B \-q
diff --git a/mkfs/proto.c b/mkfs/proto.c
index 7e3fc1b..ea31cfe 100644
--- a/mkfs/proto.c
+++ b/mkfs/proto.c
@@ -21,6 +21,7 @@
static char *newregfile(char **pp, int *len);
static void rtinit(xfs_mount_t *mp);
static long filesize(int fd);
+static int slashes_are_spaces;
/*
* Use this for block reservations needed for mkfs's conditions
@@ -171,6 +172,30 @@
return NULL;
}
+/* Extract directory entry name from a protofile. */
+static char *
+getdirentname(
+ char **pp)
+{
+ char *p = getstr(pp);
+ char *c = p;
+
+ if (!p)
+ return NULL;
+
+ if (!slashes_are_spaces)
+ return p;
+
+ /* Replace slash with space because slashes aren't allowed. */
+ while (*c) {
+ if (*c == '/')
+ *c = ' ';
+ c++;
+ }
+
+ return p;
+}
+
static void
rsvfile(
xfs_mount_t *mp,
@@ -586,7 +611,7 @@
rtinit(mp);
tp = NULL;
for (;;) {
- name = getstr(pp);
+ name = getdirentname(pp);
if (!name)
break;
if (strcmp(name, "$") == 0)
@@ -612,8 +637,10 @@
parse_proto(
xfs_mount_t *mp,
struct fsxattr *fsx,
- char **pp)
+ char **pp,
+ int proto_slashes_are_spaces)
{
+ slashes_are_spaces = proto_slashes_are_spaces;
parseproto(mp, NULL, fsx, pp, NULL);
}
diff --git a/mkfs/proto.h b/mkfs/proto.h
index 3c4010a..be1ceb4 100644
--- a/mkfs/proto.h
+++ b/mkfs/proto.h
@@ -7,7 +7,8 @@
#define MKFS_PROTO_H_
char *setup_proto(char *fname);
-void parse_proto(struct xfs_mount *mp, struct fsxattr *fsx, char **pp);
+void parse_proto(struct xfs_mount *mp, struct fsxattr *fsx, char **pp,
+ int proto_slashes_are_spaces);
void res_failed(int err);
#endif /* MKFS_PROTO_H_ */
diff --git a/mkfs/xfs_mkfs.c b/mkfs/xfs_mkfs.c
index 4248e6e..4399bf3 100644
--- a/mkfs/xfs_mkfs.c
+++ b/mkfs/xfs_mkfs.c
@@ -115,6 +115,7 @@
enum {
P_FILE = 0,
+ P_SLASHES,
P_MAX_OPTS,
};
@@ -651,6 +652,7 @@
.ini_section = "proto",
.subopts = {
[P_FILE] = "file",
+ [P_SLASHES] = "slashes_are_spaces",
[P_MAX_OPTS] = NULL,
},
.subopt_params = {
@@ -658,6 +660,12 @@
.conflicts = { { NULL, LAST_CONFLICT } },
.defaultval = SUBOPT_NEEDS_VAL,
},
+ { .index = P_SLASHES,
+ .conflicts = { { NULL, LAST_CONFLICT } },
+ .minval = 0,
+ .maxval = 1,
+ .defaultval = 1,
+ },
},
};
@@ -881,6 +889,7 @@
int loginternal;
int lsunit;
int is_supported;
+ int proto_slashes_are_spaces;
/* parameters where 0 is not a valid value */
int64_t agcount;
@@ -1779,6 +1788,9 @@
struct cli_params *cli)
{
switch (subopt) {
+ case P_SLASHES:
+ cli->proto_slashes_are_spaces = getnum(value, opts, subopt);
+ break;
case P_FILE:
fallthrough;
default:
@@ -4368,7 +4380,7 @@
/*
* Allocate the root inode and anything else in the proto file.
*/
- parse_proto(mp, &cli.fsx, &protostring);
+ parse_proto(mp, &cli.fsx, &protostring, cli.proto_slashes_are_spaces);
/*
* Protect ourselves against possible stupidity