aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhillip Lougher <phillip@squashfs.org.uk>2014-07-27 04:16:54 +0100
committerPhillip Lougher <phillip@squashfs.org.uk>2014-07-27 04:16:54 +0100
commit785921ea8eef0ed1fa02be40cd5fc436b429acd8 (patch)
tree9b86feaf2114b4fe8987398707b00721c6bbffec
parenteabd1e7d97e35c6c8506d3dad3b3f78183c144a6 (diff)
downloadsquashfs-tools-785921ea8eef0ed1fa02be40cd5fc436b429acd8.tar.gz
mksquashfs: move symlink reading from create_inode() to dir_scan1()
Up till now Mksquashfs did not read the contents of symlinks at directory scanning, but left this task to the final filesystem creation when the symlink inode in the output squashfs filesystem was created. Now that we're adding action test operations that operate on symlinks, this creates a problem. We want the values of the symlink when evaluating the symlink for existence, recursive evaluation via readlink() etc. Up till now when implementing these tests I have chosen to read the symlink from the source filesystem on demand and then discard the value. The over-arching reason for this is because symlinks can reference other symlinks, and because these tests were previously designed to be evaluated at exclude action time when the directory structure has not been fully scanned, we need to deal with symlinks that have not yet been scanned. In other words moving symlimk reading to directory scan time is no help when evaluating synlinks at exclude time because there is no guarantee that any referenced symlinks have been read. You have no option but to fall back to reading symlinks from the source filesystem at symlink test evaluation time. But evaluating symlinks by reading from the source filesystem is fraught with difficulties, not least the fact that the existence of the symlink in the source filesystem is no guarantee that the symlink exists in the output filesystem. Additionally there is never any guarantee that the source filesystem hasn't changed whilst evaluating it rendering any checks meaningless. The fix to this has been to decide evaluating symlinks at exclude time when the directory stucture has not been fully scanned causes insurmountable problems. The solution to this has been to introduce a new prune action, which is evaluated on the fully scanned directory structure. This alleviates all the aforementioned problems. So, now that the prune action has been implemented, this checkin moves reading of symlinks to the dir scanning phase, so that the snapshotted values are available for the symlink test operations. An additional minor improvement is that failure to read the symlink for some reason is discovered at dir scanning time allowing Mksquashfs to ignore the symlink. Previously because reading the symlink was performed at filesystem creation time, failure to read meant a dummy empty symlink had to be created. This is because at filesystem creation all the metadata for the filesystem has been computed and partially written, and this includes the count of the number of inodes. This is called a "minor improvement" because in practice this situation never occurs because due to the nature of symlinks if Mksquashfs could stat it at dir scanning time, then it is guaranteed to be able to read it at filesystem creation time, unless the symlink has been deleted in the meantime. Signed-off-by: Phillip Lougher <phillip@squashfs.org.uk>
-rw-r--r--squashfs-tools/mksquashfs.c94
-rw-r--r--squashfs-tools/mksquashfs.h1
2 files changed, 49 insertions, 46 deletions
diff --git a/squashfs-tools/mksquashfs.c b/squashfs-tools/mksquashfs.c
index eb78a9b..312d276 100644
--- a/squashfs-tools/mksquashfs.c
+++ b/squashfs-tools/mksquashfs.c
@@ -1034,58 +1034,28 @@ int create_inode(squashfs_inode *i_no, struct dir_info *dir_info,
}
else if(type == SQUASHFS_SYMLINK_TYPE) {
struct squashfs_symlink_inode_header *symlink = &inode_header.symlink;
- int byte;
- char buff[65536]; /* overflow safe */
+ int byte = strlen(dir_ent->inode->symlink);
size_t off = offsetof(struct squashfs_symlink_inode_header, symlink);
- byte = readlink(filename, buff, 65536);
- if(byte == -1) {
- ERROR_START("Failed to read symlink %s", filename);
- ERROR_EXIT(", creating empty symlink\n");
- byte = 0;
- }
-
- if(byte == 65536) {
- ERROR_START("Symlink %s is greater than 65536 bytes!",
- filename);
- ERROR_EXIT(" Creating empty symlink\n");
- byte = 0;
- }
-
inode = get_inode(sizeof(*symlink) + byte);
symlink->nlink = nlink;
symlink->symlink_size = byte;
SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
- strncpy(inode + off, buff, byte);
+ strncpy(inode + off, dir_ent->inode->symlink, byte);
TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
nlink);
}
else if(type == SQUASHFS_LSYMLINK_TYPE) {
struct squashfs_symlink_inode_header *symlink = &inode_header.symlink;
- int byte;
- char buff[65536]; /* overflow safe */
+ int byte = strlen(dir_ent->inode->symlink);
size_t off = offsetof(struct squashfs_symlink_inode_header, symlink);
- byte = readlink(filename, buff, 65536);
- if(byte == -1) {
- ERROR_START("Failed to read symlink %s", filename);
- ERROR_EXIT(", creating empty symlink\n");
- byte = 0;
- }
-
- if(byte == 65536) {
- ERROR_START("Symlink %s is greater than 65536 bytes!",
- filename);
- ERROR_EXIT(" Creating empty symlink\n");
- byte = 0;
- }
-
inode = get_inode(sizeof(*symlink) + byte +
sizeof(unsigned int));
symlink->nlink = nlink;
symlink->symlink_size = byte;
SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode);
- strncpy(inode + off, buff, byte);
+ strncpy(inode + off, dir_ent->inode->symlink, byte);
SQUASHFS_SWAP_INTS(&xattr, inode + off + byte, 1);
TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte,
nlink);
@@ -2963,7 +2933,8 @@ char *basename_r()
}
-struct inode_info *lookup_inode2(struct stat *buf, int pseudo, int id)
+struct inode_info *lookup_inode3(struct stat *buf, int pseudo, int id,
+ char *symlink, int bytes)
{
int ino_hash = INODE_HASH(buf->st_dev, buf->st_ino);
struct inode_info *inode;
@@ -2983,10 +2954,12 @@ struct inode_info *lookup_inode2(struct stat *buf, int pseudo, int id)
}
}
- inode = malloc(sizeof(struct inode_info));
+ inode = malloc(sizeof(struct inode_info) + bytes);
if(inode == NULL)
MEM_ERROR();
+ if(bytes)
+ memcpy(&inode->symlink, symlink, bytes);
memcpy(&inode->buf, buf, sizeof(struct stat));
inode->read = FALSE;
inode->root_entry = FALSE;
@@ -3014,6 +2987,12 @@ struct inode_info *lookup_inode2(struct stat *buf, int pseudo, int id)
}
+struct inode_info *lookup_inode2(struct stat *buf, int pseudo, int id)
+{
+ return lookup_inode3(buf, pseudo, id, NULL, 0);
+}
+
+
inline struct inode_info *lookup_inode(struct stat *buf)
{
return lookup_inode2(buf, 0, 0);
@@ -3421,23 +3400,46 @@ struct dir_info *dir_scan1(char *filename, char *subpath,
}
}
- if((buf.st_mode & S_IFMT) == S_IFDIR) {
+ switch(buf.st_mode & S_IFMT) {
+ case S_IFDIR:
if(subpath == NULL)
subpath = subpathname(dir_ent);
sub_dir = dir_scan1(filename, subpath, new,
scan1_readdir, depth + 1);
- if(sub_dir == NULL) {
+ if(sub_dir) {
+ dir->directory_count ++;
+ add_dir_entry(dir_ent, sub_dir,
+ lookup_inode(&buf));
+ } else
free_dir_entry(dir_ent);
- free(new);
- continue;
+ break;
+ case S_IFLNK: {
+ int byte;
+ static char buff[65536]; /* overflow safe */
+
+ byte = readlink(filename, buff, 65536);
+ if(byte == -1) {
+ ERROR_START("Failed to read symlink %s",
+ filename);
+ ERROR_EXIT(", ignoring\n");
+ } else if(byte == 65536) {
+ ERROR_START("Symlink %s is greater than 65536 "
+ "bytes!", filename);
+ ERROR_EXIT(", ignoring\n");
+ } else {
+ /* readlink doesn't 0 terminate the returned
+ * path */
+ buff[byte] = '\0';
+ add_dir_entry(dir_ent, NULL, lookup_inode3(&buf,
+ 0, 0, buff, byte + 1));
}
+ break;
+ }
+ default:
+ add_dir_entry(dir_ent, NULL, lookup_inode(&buf));
+ }
- dir->directory_count ++;
- } else
- sub_dir = NULL;
-
- add_dir_entry(dir_ent, sub_dir, lookup_inode(&buf));
free(new);
}
@@ -5075,7 +5077,7 @@ void calculate_queue_sizes(int mem, int *readq, int *fragq, int *bwriteq,
#define VERSION() \
- printf("mksquashfs version 4.3-git (2014/07/25)\n");\
+ printf("mksquashfs version 4.3-git (2014/07/26)\n");\
printf("copyright (C) 2014 Phillip Lougher "\
"<phillip@squashfs.org.uk>\n\n"); \
printf("This program is free software; you can redistribute it and/or"\
diff --git a/squashfs-tools/mksquashfs.h b/squashfs-tools/mksquashfs.h
index 397e17c..55708a3 100644
--- a/squashfs-tools/mksquashfs.h
+++ b/squashfs-tools/mksquashfs.h
@@ -63,6 +63,7 @@ struct inode_info {
char always_use_fragments;
char noD;
char noF;
+ char symlink[0];
};
/* in memory file info */