diff --git a/header.go b/header.go index 5654436..5131fde 100644 --- a/header.go +++ b/header.go @@ -126,6 +126,7 @@ func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) { case fm&os.ModeSymlink != 0: h.Mode |= ModeSymlink h.Linkname = link + h.Size = 0 // adjusted to len(Linkname) while writing header case fm&os.ModeDevice != 0: if fm&os.ModeCharDevice != 0 { h.Mode |= ModeCharDevice diff --git a/svr4.go b/svr4.go index 43b0522..8a367b5 100644 --- a/svr4.go +++ b/svr4.go @@ -121,6 +121,9 @@ func writeSVR4Header(w io.Writer, hdr *Header) (pad int64, err error) { if !hdr.ModTime.IsZero() { writeHex(hdrBuf[46:54], hdr.ModTime.Unix()) } + if hdr.Mode&^ModePerm == ModeSymlink { + hdr.Size = int64(len(hdr.Linkname)) + } writeHex(hdrBuf[54:62], hdr.Size) writeHex(hdrBuf[94:102], int64(len(hdr.Name)+1)) if hdr.Checksum != 0 { @@ -146,6 +149,11 @@ func writeSVR4Header(w io.Writer, hdr *Header) (pad int64, err error) { return } + _, err = io.WriteString(w, hdr.Linkname) + if err != nil { + return + } + // compute padding to end of file pad = (4 - (hdr.Size % 4)) % 4 return diff --git a/writer_test.go b/writer_test.go index 5b163fd..c5961ce 100644 --- a/writer_test.go +++ b/writer_test.go @@ -10,23 +10,29 @@ import ( ) func store(w *cpio.Writer, fn string) error { - f, err := os.Open(fn) + fi, err := os.Lstat(fn) if err != nil { return err } - defer f.Close() - fi, err := f.Stat() - if err != nil { - return err + var link string + if fi.Mode()&os.ModeSymlink != 0 { + if link, err = os.Readlink(fn); err != nil { + return err + } } - hdr, err := cpio.FileInfoHeader(fi, "") + hdr, err := cpio.FileInfoHeader(fi, link) if err != nil { return err } if err := w.WriteHeader(hdr); err != nil { return err } - if !fi.IsDir() { + if fi.Mode().IsRegular() { + f, err := os.Open(fn) + if err != nil { + return err + } + defer f.Close() if _, err := io.Copy(w, f); err != nil { return err } @@ -47,3 +53,29 @@ func TestWriter(t *testing.T) { t.Fatalf("Close: %v", err) } } + +func TestWriter_Symlink(t *testing.T) { + var buf bytes.Buffer + w := cpio.NewWriter(&buf) + func() { + defer func() { + if err := w.Close(); err != nil { + t.Fatalf("Close: %v", err) + } + }() + if err := store(w, "testdata/checklist.txt"); err != nil { + t.Fatalf("store: %v", err) + } + }() + r := cpio.NewReader(&buf) + hdr, err := r.Next() + if err != nil { + t.Fatalf("Next: %v", err) + } + if hdr.Mode&^cpio.ModePerm != cpio.ModeSymlink { + t.Fatalf("file has mode %s, expected %s (ModeSymlink)", hdr.Mode, cpio.FileMode(cpio.ModeSymlink)) + } + if hdr.Linkname == "" { + t.Fatal("Empty Linkname on ModeSymlink file") + } +}