X-Git-Url: https://git.r.bdr.sh/rbdr/mobius/blobdiff_plain/95159e5585762c06c654945070ba54262b7dcec9..HEAD:/hotline/file_wrapper.go diff --git a/hotline/file_wrapper.go b/hotline/file_wrapper.go index a26c45a..b13e0dc 100644 --- a/hotline/file_wrapper.go +++ b/hotline/file_wrapper.go @@ -12,41 +12,41 @@ import ( ) const ( - incompleteFileSuffix = ".incomplete" - infoForkNameTemplate = ".info_%s" // template string for info fork filenames - rsrcForkNameTemplate = ".rsrc_%s" // template string for resource fork filenames + IncompleteFileSuffix = ".incomplete" + InfoForkNameTemplate = ".info_%s" // template string for info fork filenames + RsrcForkNameTemplate = ".rsrc_%s" // template string for resource fork filenames ) // fileWrapper encapsulates the data, info, and resource forks of a Hotline file and provides methods to manage the files. type fileWrapper struct { fs FileStore - name string // name of the file + Name string // Name of the file path string // path to file directory dataPath string // path to the file data fork dataOffset int64 rsrcPath string // path to the file resource fork infoPath string // path to the file information fork incompletePath string // path to partially transferred temp file - ffo *flattenedFileObject + Ffo *flattenedFileObject } -func newFileWrapper(fs FileStore, path string, dataOffset int64) (*fileWrapper, error) { +func NewFileWrapper(fs FileStore, path string, dataOffset int64) (*fileWrapper, error) { dir := filepath.Dir(path) fName := filepath.Base(path) f := fileWrapper{ fs: fs, - name: fName, + Name: fName, path: dir, dataPath: path, dataOffset: dataOffset, - rsrcPath: filepath.Join(dir, fmt.Sprintf(rsrcForkNameTemplate, fName)), - infoPath: filepath.Join(dir, fmt.Sprintf(infoForkNameTemplate, fName)), - incompletePath: filepath.Join(dir, fName+incompleteFileSuffix), - ffo: &flattenedFileObject{}, + rsrcPath: filepath.Join(dir, fmt.Sprintf(RsrcForkNameTemplate, fName)), + infoPath: filepath.Join(dir, fmt.Sprintf(InfoForkNameTemplate, fName)), + incompletePath: filepath.Join(dir, fName+IncompleteFileSuffix), + Ffo: &flattenedFileObject{}, } var err error - f.ffo, err = f.flattenedFileObject() + f.Ffo, err = f.flattenedFileObject() if err != nil { return nil, err } @@ -54,7 +54,7 @@ func newFileWrapper(fs FileStore, path string, dataOffset int64) (*fileWrapper, return &f, nil } -func (f *fileWrapper) totalSize() []byte { +func (f *fileWrapper) TotalSize() []byte { var s int64 size := make([]byte, 4) @@ -85,23 +85,21 @@ func (f *fileWrapper) rsrcForkSize() (s [4]byte) { func (f *fileWrapper) rsrcForkHeader() FlatFileForkHeader { return FlatFileForkHeader{ - ForkType: [4]byte{0x4D, 0x41, 0x43, 0x52}, // "MACR" - CompressionType: [4]byte{}, - RSVD: [4]byte{}, - DataSize: f.rsrcForkSize(), + ForkType: [4]byte{0x4D, 0x41, 0x43, 0x52}, // "MACR" + DataSize: f.rsrcForkSize(), } } func (f *fileWrapper) incompleteDataName() string { - return f.name + incompleteFileSuffix + return f.Name + IncompleteFileSuffix } func (f *fileWrapper) rsrcForkName() string { - return fmt.Sprintf(rsrcForkNameTemplate, f.name) + return fmt.Sprintf(RsrcForkNameTemplate, f.Name) } func (f *fileWrapper) infoForkName() string { - return fmt.Sprintf(infoForkNameTemplate, f.name) + return fmt.Sprintf(InfoForkNameTemplate, f.Name) } func (f *fileWrapper) rsrcForkWriter() (io.WriteCloser, error) { @@ -113,8 +111,8 @@ func (f *fileWrapper) rsrcForkWriter() (io.WriteCloser, error) { return file, nil } -func (f *fileWrapper) infoForkWriter() (io.WriteCloser, error) { - file, err := os.OpenFile(f.infoPath, os.O_CREATE|os.O_WRONLY, 0644) +func (f *fileWrapper) InfoForkWriter() (io.WriteCloser, error) { + file, err := os.OpenFile(f.infoPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644) if err != nil { return nil, err } @@ -139,7 +137,7 @@ func (f *fileWrapper) rsrcForkFile() (*os.File, error) { return f.fs.Open(f.rsrcPath) } -func (f *fileWrapper) dataFile() (os.FileInfo, error) { +func (f *fileWrapper) DataFile() (os.FileInfo, error) { if fi, err := f.fs.Stat(f.dataPath); err == nil { return fi, nil } @@ -150,14 +148,14 @@ func (f *fileWrapper) dataFile() (os.FileInfo, error) { return nil, errors.New("file or directory not found") } -// move a fileWrapper and its associated meta files to newPath. +// Move a file and its associated meta files to newPath. // Meta files include: // * Partially uploaded file ending with .incomplete // * Resource fork starting with .rsrc_ // * Info fork starting with .info -// During move of the meta files, os.ErrNotExist is ignored as these files may legitimately not exist. -func (f *fileWrapper) move(newPath string) error { - err := f.fs.Rename(f.dataPath, filepath.Join(newPath, f.name)) +// During Move of the meta files, os.ErrNotExist is ignored as these files may legitimately not exist. +func (f *fileWrapper) Move(newPath string) error { + err := f.fs.Rename(f.dataPath, filepath.Join(newPath, f.Name)) if err != nil { return err } @@ -180,8 +178,8 @@ func (f *fileWrapper) move(newPath string) error { return nil } -// delete a fileWrapper and its associated metadata files if they exist -func (f *fileWrapper) delete() error { +// Delete a file and its associated metadata files if they exist +func (f *fileWrapper) Delete() error { err := f.fs.RemoveAll(f.dataPath) if err != nil { return err @@ -218,20 +216,19 @@ func (f *fileWrapper) flattenedFileObject() (*flattenedFileObject, error) { if errors.Is(err, fs.ErrNotExist) { fileInfo, err = f.fs.Stat(f.incompletePath) if err == nil { - mTime = toHotlineTime(fileInfo.ModTime()) + mTime = NewTime(fileInfo.ModTime()) binary.BigEndian.PutUint32(dataSize, uint32(fileInfo.Size()-f.dataOffset)) ft, _ = fileTypeFromInfo(fileInfo) } } else { - mTime = toHotlineTime(fileInfo.ModTime()) + mTime = NewTime(fileInfo.ModTime()) binary.BigEndian.PutUint32(dataSize, uint32(fileInfo.Size()-f.dataOffset)) ft, _ = fileTypeFromInfo(fileInfo) } - f.ffo.FlatFileHeader = FlatFileHeader{ + f.Ffo.FlatFileHeader = FlatFileHeader{ Format: [4]byte{0x46, 0x49, 0x4c, 0x50}, // "FILP" Version: [2]byte{0, 1}, - RSVD: [16]byte{}, ForkCount: [2]byte{0, 2}, } @@ -242,46 +239,39 @@ func (f *fileWrapper) flattenedFileObject() (*flattenedFileObject, error) { return nil, err } - f.ffo.FlatFileHeader.ForkCount[1] = 3 + f.Ffo.FlatFileHeader.ForkCount[1] = 3 - _, err = io.Copy(&f.ffo.FlatFileInformationFork, bytes.NewReader(b)) + _, err = io.Copy(&f.Ffo.FlatFileInformationFork, bytes.NewReader(b)) if err != nil { - return nil, err + return nil, fmt.Errorf("error copying FlatFileInformationFork: %w", err) } - } else { - f.ffo.FlatFileInformationFork = FlatFileInformationFork{ - Platform: []byte("AMAC"), // TODO: Remove hardcode to support "AWIN" Platform (maybe?) - TypeSignature: []byte(ft.TypeCode), - CreatorSignature: []byte(ft.CreatorCode), - Flags: []byte{0, 0, 0, 0}, - PlatformFlags: []byte{0, 0, 1, 0}, // TODO: What is this? - RSVD: make([]byte, 32), - CreateDate: mTime[:], // some filesystems don't support createTime - ModifyDate: mTime[:], - NameScript: []byte{0, 0}, - Name: []byte(f.name), - NameSize: []byte{0, 0}, - CommentSize: []byte{0, 0}, + f.Ffo.FlatFileInformationFork = FlatFileInformationFork{ + Platform: [4]byte{0x41, 0x4D, 0x41, 0x43}, // "AMAC" TODO: Remove hardcode to support "AWIN" Platform (maybe?) + TypeSignature: [4]byte([]byte(ft.TypeCode)), + CreatorSignature: [4]byte([]byte(ft.CreatorCode)), + PlatformFlags: [4]byte{0, 0, 1, 0}, // TODO: What is this? + CreateDate: mTime, // some filesystems don't support createTime + ModifyDate: mTime, + Name: []byte(f.Name), Comment: []byte{}, } - binary.BigEndian.PutUint16(f.ffo.FlatFileInformationFork.NameSize, uint16(len(f.name))) + + ns := make([]byte, 2) + binary.BigEndian.PutUint16(ns, uint16(len(f.Name))) + f.Ffo.FlatFileInformationFork.NameSize = [2]byte(ns[:]) } - f.ffo.FlatFileInformationForkHeader = FlatFileForkHeader{ - ForkType: [4]byte{0x49, 0x4E, 0x46, 0x4F}, // "INFO" - CompressionType: [4]byte{}, - RSVD: [4]byte{}, - DataSize: f.ffo.FlatFileInformationFork.Size(), + f.Ffo.FlatFileInformationForkHeader = FlatFileForkHeader{ + ForkType: [4]byte{0x49, 0x4E, 0x46, 0x4F}, // "INFO" + DataSize: f.Ffo.FlatFileInformationFork.Size(), } - f.ffo.FlatFileDataForkHeader = FlatFileForkHeader{ - ForkType: [4]byte{0x44, 0x41, 0x54, 0x41}, // "DATA" - CompressionType: [4]byte{}, - RSVD: [4]byte{}, - DataSize: [4]byte{dataSize[0], dataSize[1], dataSize[2], dataSize[3]}, + f.Ffo.FlatFileDataForkHeader = FlatFileForkHeader{ + ForkType: [4]byte{0x44, 0x41, 0x54, 0x41}, // "DATA" + DataSize: [4]byte{dataSize[0], dataSize[1], dataSize[2], dataSize[3]}, } - f.ffo.FlatFileResForkHeader = f.rsrcForkHeader() + f.Ffo.FlatFileResForkHeader = f.rsrcForkHeader() - return f.ffo, nil + return f.Ffo, nil }