diff options
author | Phillip Lougher <phillip@squashfs.org.uk> | 2014-07-27 04:16:54 +0100 |
---|---|---|
committer | Phillip Lougher <phillip@squashfs.org.uk> | 2014-07-27 04:16:54 +0100 |
commit | 785921ea8eef0ed1fa02be40cd5fc436b429acd8 (patch) | |
tree | 9b86feaf2114b4fe8987398707b00721c6bbffec | |
parent | eabd1e7d97e35c6c8506d3dad3b3f78183c144a6 (diff) | |
download | squashfs-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.c | 94 | ||||
-rw-r--r-- | squashfs-tools/mksquashfs.h | 1 |
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 */ |