diff --git a/superblock.go b/superblock.go index 8134304..0f846b8 100644 --- a/superblock.go +++ b/superblock.go @@ -35,30 +35,36 @@ type superblock struct { //SuperblockFlags is the series of flags describing how a squashfs archive is packed. type SuperblockFlags struct { - //If true, inodes are stored uncompressed + //If true, inodes are stored uncompressed. UncompressedInodes bool - //If true, data is stored uncompressed + //If true, data is stored uncompressed. UncompressedData bool check bool - //If true, fragments are stored uncompressed + //If true, fragments are stored uncompressed. UncompressedFragments bool - //If true, ALL data is stored in sequential data blocks instead of utilizing fragments + //If true, ALL data is stored in sequential data blocks instead of utilizing fragments. NoFragments bool //If true, the last block of data will always be stored as a fragment if it's less then the block size. AlwaysFragments bool - //If true, duplicate files are only stored once. - Duplicates bool - //If true, the export table is populated + //If true, duplicate files are only stored once. (Currently unsupported) + RemoveDuplicates bool + //If true, the export table is populated. (Currently unsupported) Exportable bool - //If true, the xattr table is uncompressed + //If true, the xattr table is uncompressed. (Currently unsupported) UncompressedXattr bool - //If true, the xattr table is not populated + //If true, the xattr table is not populated. (Currently unsupported) NoXattr bool compressorOptions bool - //If true, the UID/GID table is stored uncompressed + //If true, the UID/GID table is stored uncompressed. UncompressedIDs bool } +//DefaultFlags are the default SuperblockFlags that are used. +var DefaultFlags = SuperblockFlags{ + RemoveDuplicates: true, + Exportable: true, +} + //GetFlags returns a SuperblockFlags for a given superblock. func (s *superblock) GetFlags() SuperblockFlags { return SuperblockFlags{ @@ -68,7 +74,7 @@ func (s *superblock) GetFlags() SuperblockFlags { UncompressedFragments: s.Flags&0x8 == 0x8, NoFragments: s.Flags&0x10 == 0x10, AlwaysFragments: s.Flags&0x20 == 0x20, - Duplicates: s.Flags&0x40 == 0x40, + RemoveDuplicates: s.Flags&0x40 == 0x40, Exportable: s.Flags&0x80 == 0x80, UncompressedXattr: s.Flags&0x100 == 0x100, NoXattr: s.Flags&0x200 == 0x200, @@ -98,7 +104,7 @@ func (s *SuperblockFlags) ToUint() uint16 { if s.AlwaysFragments { out = out | 0x20 } - if s.Duplicates { + if s.RemoveDuplicates { out = out | 0x40 } if s.Exportable { diff --git a/writer.go b/writer.go index 6521210..5939109 100644 --- a/writer.go +++ b/writer.go @@ -3,6 +3,7 @@ package squashfs import ( "errors" "io" + "io/fs" "log" "os" "path" @@ -29,6 +30,9 @@ type Writer struct { //Currently Duplicates, Exportable, UncompressedXattr, NoXattr values are ignored Flags SuperblockFlags allowErrors bool + + //variables used when actually writing. + superblock superblock } //NewWriter creates a new with the default options (Gzip compression and allow errors) @@ -54,6 +58,7 @@ func NewWriterWithOptions(compressionType int, allowErrors bool) (*Writer, error compressionType: compressionType, allowErrors: allowErrors, BlockSize: uint32(1048576), + Flags: DefaultFlags, }, nil } @@ -95,7 +100,8 @@ func (w *Writer) AddFileTo(filepath string, file *os.File) error { return errors.New("File already exists at " + filepath) } var holder fileHolder - holder.path, holder.name = path.Split(filepath) + holder.path = path.Dir(filepath) + holder.name = path.Base(filepath) holder.reader = file stat, err := file.Stat() if err != nil { @@ -167,12 +173,35 @@ func (w *Writer) AddReaderTo(filepath string, reader io.Reader) error { return errors.New("File already exists at " + filepath) } var holder fileHolder - holder.path, holder.name = path.Split(filepath) + holder.path = path.Dir(filepath) + holder.name = path.Base(filepath) holder.reader = reader w.structure[holder.path] = append(w.structure[holder.path], &holder) return nil } +//AddFolderTo adds a folder at the given path. IF the folder is already present, it sets the folder's permissions. +//If the path points to a non-folder (such as a file or symlink), an error is returned +func (w *Writer) AddFolderTo(folderpath string, permission fs.FileMode) error { + folderpath = path.Clean(folderpath) + tmp := w.holderAt(folderpath) + if tmp != nil { + if !tmp.folder { + return errors.New("Path is not a folder: " + folderpath) + } + tmp.perm = int(permission.Perm()) + return nil + } + file := fileHolder{ + path: path.Dir(folderpath), + name: path.Base(folderpath), + perm: int(permission | fs.ModePerm), + folder: true, + } + w.structure[file.path] = append(w.structure[file.path], &file) + return nil +} + //Remove tries to remove the file(s) at the given filepath. If wildcards are used, it will remove all files that match. //Returns true if one or more files are removed. func (w *Writer) Remove(filepath string) bool { diff --git a/writer_write.go b/writer_write.go index 0ee8bab..5f3de19 100644 --- a/writer_write.go +++ b/writer_write.go @@ -4,8 +4,18 @@ import ( "errors" "io" "math" + "path" ) +func (w *Writer) fixFolders() error { + for folder := range w.structure { + if folder == "/" { + continue + } + dir, name := path.Dir(folder), path.Base(folder) + } +} + //WriteTo attempts to write the archive to the given io.Writer. func (w *Writer) WriteTo(write io.Writer) (int64, error) { if w.BlockSize > 1048576 { @@ -13,8 +23,10 @@ func (w *Writer) WriteTo(write io.Writer) (int64, error) { } else if w.BlockSize < 4096 { w.BlockSize = 4096 } - //TODO: set forced Flag values - _ = superblock{ + w.Flags.RemoveDuplicates = false + w.Flags.Exportable = false + w.Flags.NoXattr = true + w.superblock = superblock{ Magic: magic, BlockSize: w.BlockSize, BlockLog: uint16(math.Log2(float64(w.BlockSize))),