static int
set_random_metadata(struct wim_inode *inode, struct generation_context *ctx)
{
- u32 v = rand32();
- u32 attrib = (v & (FILE_ATTRIBUTE_READONLY |
- FILE_ATTRIBUTE_HIDDEN |
- FILE_ATTRIBUTE_SYSTEM |
- FILE_ATTRIBUTE_ARCHIVE |
- FILE_ATTRIBUTE_NOT_CONTENT_INDEXED |
- FILE_ATTRIBUTE_COMPRESSED |
- FILE_ATTRIBUTE_SPARSE_FILE));
+ u32 attrib = (rand32() & (FILE_ATTRIBUTE_READONLY |
+ FILE_ATTRIBUTE_HIDDEN |
+ FILE_ATTRIBUTE_SYSTEM |
+ FILE_ATTRIBUTE_ARCHIVE |
+ FILE_ATTRIBUTE_NOT_CONTENT_INDEXED |
+ FILE_ATTRIBUTE_COMPRESSED |
+ FILE_ATTRIBUTE_SPARSE_FILE));
/* File attributes */
inode->i_attributes |= attrib;
}
static int
-set_random_streams(struct wim_inode *inode, struct generation_context *ctx,
- bool reparse_ok)
+set_random_streams(struct wim_inode *inode, struct generation_context *ctx)
{
int ret;
u32 r;
/* Reparse point (sometimes) */
- if (reparse_ok && rand32() % 8 == 0) {
+ if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
ret = set_random_reparse_point(inode, ctx);
if (ret)
return ret;
}
len = min(len, max_len);
+retry:
/* Generate the characters in the name. */
for (int i = 0; i < len; i++) {
do {
/* Add a null terminator. */
name[len] = cpu_to_le16('\0');
+ /* Don't generate . and .. */
+ if (name[0] == cpu_to_le16('.') &&
+ (len == 1 || (len == 2 && name[1] == cpu_to_le16('.'))))
+ goto retry;
+
return len;
}
{
const utf16lechar *p;
- static const utf16lechar forbidden_names[][5] = {
- { cpu_to_le16('C'), cpu_to_le16('O'), cpu_to_le16('N'), },
- { cpu_to_le16('P'), cpu_to_le16('R'), cpu_to_le16('N'), },
- { cpu_to_le16('A'), cpu_to_le16('U'), cpu_to_le16('X'), },
- { cpu_to_le16('N'), cpu_to_le16('U'), cpu_to_le16('L'), },
- { cpu_to_le16('C'), cpu_to_le16('O'), cpu_to_le16('M'), cpu_to_le16('1'), },
- { cpu_to_le16('C'), cpu_to_le16('O'), cpu_to_le16('M'), cpu_to_le16('2'), },
- { cpu_to_le16('C'), cpu_to_le16('O'), cpu_to_le16('M'), cpu_to_le16('3'), },
- { cpu_to_le16('C'), cpu_to_le16('O'), cpu_to_le16('M'), cpu_to_le16('4'), },
- { cpu_to_le16('C'), cpu_to_le16('O'), cpu_to_le16('M'), cpu_to_le16('5'), },
- { cpu_to_le16('C'), cpu_to_le16('O'), cpu_to_le16('M'), cpu_to_le16('6'), },
- { cpu_to_le16('C'), cpu_to_le16('O'), cpu_to_le16('M'), cpu_to_le16('7'), },
- { cpu_to_le16('C'), cpu_to_le16('O'), cpu_to_le16('M'), cpu_to_le16('8'), },
- { cpu_to_le16('C'), cpu_to_le16('O'), cpu_to_le16('M'), cpu_to_le16('9'), },
- { cpu_to_le16('L'), cpu_to_le16('P'), cpu_to_le16('T'), cpu_to_le16('1'), },
- { cpu_to_le16('L'), cpu_to_le16('P'), cpu_to_le16('T'), cpu_to_le16('2'), },
- { cpu_to_le16('L'), cpu_to_le16('P'), cpu_to_le16('T'), cpu_to_le16('3'), },
- { cpu_to_le16('L'), cpu_to_le16('P'), cpu_to_le16('T'), cpu_to_le16('4'), },
- { cpu_to_le16('L'), cpu_to_le16('P'), cpu_to_le16('T'), cpu_to_le16('5'), },
- { cpu_to_le16('L'), cpu_to_le16('P'), cpu_to_le16('T'), cpu_to_le16('6'), },
- { cpu_to_le16('L'), cpu_to_le16('P'), cpu_to_le16('T'), cpu_to_le16('7'), },
- { cpu_to_le16('L'), cpu_to_le16('P'), cpu_to_le16('T'), cpu_to_le16('8'), },
- { cpu_to_le16('L'), cpu_to_le16('P'), cpu_to_le16('T'), cpu_to_le16('9'), },
+ static const char * const reserved_names[] = {
+ "CON", "PRN", "AUX", "NUL",
+ "COM1", "COM2", "COM3", "COM4", "COM5",
+ "COM6", "COM7", "COM8", "COM9",
+ "LPT1", "LPT2", "LPT3", "LPT4", "LPT5",
+ "LPT6", "LPT7", "LPT8", "LPT9",
};
/* The name must be nonempty. */
/* Note: a trailing dot or space is permitted, even though on Windows
* such a file can only be accessed using a WinNT-style path. */
- /* The name can't be one of the reserved names (case insensitively). */
- for (size_t i = 0; i < ARRAY_LEN(forbidden_names); i++)
- if (!cmp_utf16le_strings_z(forbidden_names[i], name, true))
- return false;
+ /* The name can't be one of the reserved names or be a reserved name
+ * with an extension. Case insensitive. */
+ for (size_t i = 0; i < ARRAY_LEN(reserved_names); i++) {
+ for (size_t j = 0; ; j++) {
+ u16 c1 = le16_to_cpu(name[j]);
+ u16 c2 = reserved_names[i][j];
+ if (c2 == '\0') {
+ if (c1 == '\0' || c1 == '.')
+ return false;
+ break;
+ }
+ if (upcase[c1] != upcase[c2])
+ break;
+ }
+ }
return true;
}
/* Generate the next child dentry. */
struct wim_inode *inode;
u64 ino;
- bool is_directory;
+ bool is_directory = (rand32() % 16 <= 6);
+ bool is_reparse = (rand32() % 8 == 0);
utf16lechar name[63 + 1]; /* for UNIX extraction: 63 * 4 <= 255 */
int name_len;
struct wim_dentry *duplicate;
- /* Decide whether to create a directory or not. If not a
- * directory, also decide on the inode number (i.e. we may
- * generate a "hard link" to an existing file). */
- is_directory = ((rand32() % 16) <= 6);
- if (is_directory)
+ /*
+ * Select an inode number for the new file. Sometimes choose an
+ * existing inode number (i.e. create a hard link). However,
+ * wimlib intentionally doesn't honor directory hard links, and
+ * reparse points cannot be represented in the WIM file format
+ * at all; so don't create hard links for such files.
+ */
+ if (is_directory || is_reparse)
ino = 0;
else
ino = select_inode_number(ctx);
/* Create the dentry. */
ret = inode_table_new_dentry(ctx->params->inode_table, NULL,
- ino, 0, is_directory, &child);
+ ino, 0, ino == 0, &child);
if (ret)
return ret;
if (is_directory)
inode->i_attributes |= FILE_ATTRIBUTE_DIRECTORY;
+ if (is_reparse)
+ inode->i_attributes |= FILE_ATTRIBUTE_REPARSE_POINT;
- ret = set_random_metadata(inode, ctx);
+ ret = set_random_streams(inode, ctx);
if (ret)
return ret;
- ret = set_random_streams(inode, ctx, true);
+ ret = set_random_metadata(inode, ctx);
if (ret)
return ret;
/* Recurse if it's a directory. */
- if (is_directory &&
- !(inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT))
- {
+ if (is_directory && !is_reparse) {
ret = generate_dentry_tree_recursive(child, depth + 1,
ctx);
if (ret)
ret = inode_table_new_dentry(params->inode_table, NULL, 0, 0, true, &root);
if (!ret) {
root->d_inode->i_attributes = FILE_ATTRIBUTE_DIRECTORY;
- ret = set_random_metadata(root->d_inode, &ctx);
+ ret = set_random_streams(root->d_inode, &ctx);
}
if (!ret)
- ret = set_random_streams(root->d_inode, &ctx, false);
+ ret = set_random_metadata(root->d_inode, &ctx);
if (!ret)
ret = generate_dentry_tree_recursive(root, 1, &ctx);
if (!ret)