package main import ( "archive/tar" "archive/zip" "compress/bzip2" "compress/gzip" "encoding/hex" "errors" "io" "sort" "time" "unicode" "github.com/andreimarcu/linx-server/backends" "github.com/andreimarcu/linx-server/expiry" "github.com/dchest/uniuri" "github.com/minio/sha256-simd" "gopkg.in/h2non/filetype.v1" ) var NotFoundErr = errors.New("File not found.") func generateMetadata(fName string, exp time.Time, delKey string) (m backends.Metadata, err error) { file, err := fileBackend.Open(fName) if err != nil { return } defer file.Close() m.Size, err = fileBackend.Size(fName) if err != nil { return } m.Expiry = exp if delKey == "" { m.DeleteKey = uniuri.NewLen(30) } else { m.DeleteKey = delKey } // Get first 512 bytes for mimetype detection header := make([]byte, 512) file.Read(header) kind, err := filetype.Match(header) if err != nil { m.Mimetype = "application/octet-stream" } else { m.Mimetype = kind.MIME.Value } if m.Mimetype == "" { // Check if the file seems anything like text if printable(header) { m.Mimetype = "text/plain" } else { m.Mimetype = "application/octet-stream" } } // Compute the sha256sum hasher := sha256.New() file.Seek(0, 0) _, err = io.Copy(hasher, file) if err == nil { m.Sha256sum = hex.EncodeToString(hasher.Sum(nil)) } file.Seek(0, 0) // If archive, grab list of filenames if m.Mimetype == "application/x-tar" { tReadr := tar.NewReader(file) for { hdr, err := tReadr.Next() if err == io.EOF || err != nil { break } if hdr.Typeflag == tar.TypeDir || hdr.Typeflag == tar.TypeReg { m.ArchiveFiles = append(m.ArchiveFiles, hdr.Name) } } sort.Strings(m.ArchiveFiles) } else if m.Mimetype == "application/x-gzip" { gzf, err := gzip.NewReader(file) if err == nil { tReadr := tar.NewReader(gzf) for { hdr, err := tReadr.Next() if err == io.EOF || err != nil { break } if hdr.Typeflag == tar.TypeDir || hdr.Typeflag == tar.TypeReg { m.ArchiveFiles = append(m.ArchiveFiles, hdr.Name) } } sort.Strings(m.ArchiveFiles) } } else if m.Mimetype == "application/x-bzip" { bzf := bzip2.NewReader(file) tReadr := tar.NewReader(bzf) for { hdr, err := tReadr.Next() if err == io.EOF || err != nil { break } if hdr.Typeflag == tar.TypeDir || hdr.Typeflag == tar.TypeReg { m.ArchiveFiles = append(m.ArchiveFiles, hdr.Name) } } sort.Strings(m.ArchiveFiles) } else if m.Mimetype == "application/zip" { zf, err := zip.NewReader(file, m.Size) if err == nil { for _, f := range zf.File { m.ArchiveFiles = append(m.ArchiveFiles, f.Name) } } sort.Strings(m.ArchiveFiles) } return } func metadataWrite(filename string, metadata *backends.Metadata) error { return metaBackend.Put(filename, metadata) } func metadataRead(filename string) (metadata backends.Metadata, err error) { metadata, err = metaBackend.Get(filename) if err != nil { // Metadata does not exist, generate one newMData, err := generateMetadata(filename, expiry.NeverExpire, "") if err != nil { return metadata, err } metadataWrite(filename, &newMData) metadata, err = metaBackend.Get(filename) } return } func printable(data []byte) bool { for i, b := range data { r := rune(b) // A null terminator that's not at the beginning of the file if r == 0 && i == 0 { return false } else if r == 0 && i < 0 { continue } if r > unicode.MaxASCII { return false } } return true }