]> git.r.bdr.sh - rbdr/mobius/commitdiff
Adopt more fixed size array types for struct fields
authorJeff Halter <redacted>
Tue, 18 Jun 2024 22:34:50 +0000 (15:34 -0700)
committerJeff Halter <redacted>
Tue, 18 Jun 2024 22:34:50 +0000 (15:34 -0700)
hotline/field.go
hotline/field_test.go
hotline/file_wrapper.go
hotline/files.go
hotline/flattened_file_object.go
hotline/server_blackbox_test.go
hotline/server_test.go
hotline/tracker.go
hotline/transaction_handlers.go
hotline/transfer_test.go

index 045e09fce8aad3a6a2974a271f6a1faac1ad8eac..2fcb41a1a5451e070ba187fe17695af4d3f90171 100644 (file)
@@ -80,17 +80,11 @@ type requiredField struct {
 }
 
 func NewField(id uint16, data []byte) Field {
-       idBytes := make([]byte, 2)
-       binary.BigEndian.PutUint16(idBytes, id)
+       f := Field{Data: data}
+       binary.BigEndian.PutUint16(f.ID[:], id)
+       binary.BigEndian.PutUint16(f.FieldSize[:], uint16(len(data)))
 
-       bs := make([]byte, 2)
-       binary.BigEndian.PutUint16(bs, uint16(len(data)))
-
-       return Field{
-               ID:        [2]byte(idBytes),
-               FieldSize: [2]byte(bs),
-               Data:      data,
-       }
+       return f
 }
 
 // fieldScanner implements bufio.SplitFunc for parsing byte slices into complete tokens
index 317c2d94a99b482dda425a61c23198f524e2ad3a..ecae9c77351e76b6306085ba610c02af1ed972ea 100644 (file)
@@ -99,3 +99,90 @@ func Test_fieldScanner(t *testing.T) {
                })
        }
 }
+
+func TestField_Read(t *testing.T) {
+       type fields struct {
+               ID         [2]byte
+               FieldSize  [2]byte
+               Data       []byte
+               readOffset int
+       }
+       type args struct {
+               p []byte
+       }
+       tests := []struct {
+               name      string
+               fields    fields
+               args      args
+               want      int
+               wantErr   assert.ErrorAssertionFunc
+               wantBytes []byte
+       }{
+               {
+                       name: "returns field bytes",
+                       fields: fields{
+                               ID:        [2]byte{0x00, 0x62},
+                               FieldSize: [2]byte{0x00, 0x03},
+                               Data:      []byte("hai!"),
+                       },
+                       args: args{
+                               p: make([]byte, 512),
+                       },
+                       want:    8,
+                       wantErr: assert.NoError,
+                       wantBytes: []byte{
+                               0x00, 0x62,
+                               0x00, 0x03,
+                               0x68, 0x61, 0x69, 0x21,
+                       },
+               },
+               {
+                       name: "returns field bytes from readOffset",
+                       fields: fields{
+                               ID:         [2]byte{0x00, 0x62},
+                               FieldSize:  [2]byte{0x00, 0x03},
+                               Data:       []byte("hai!"),
+                               readOffset: 4,
+                       },
+                       args: args{
+                               p: make([]byte, 512),
+                       },
+                       want:    4,
+                       wantErr: assert.NoError,
+                       wantBytes: []byte{
+                               0x68, 0x61, 0x69, 0x21,
+                       },
+               },
+               {
+                       name: "returns io.EOF when all bytes read",
+                       fields: fields{
+                               ID:         [2]byte{0x00, 0x62},
+                               FieldSize:  [2]byte{0x00, 0x03},
+                               Data:       []byte("hai!"),
+                               readOffset: 8,
+                       },
+                       args: args{
+                               p: make([]byte, 512),
+                       },
+                       want:      0,
+                       wantErr:   assert.Error,
+                       wantBytes: []byte{},
+               },
+       }
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       f := &Field{
+                               ID:         tt.fields.ID,
+                               FieldSize:  tt.fields.FieldSize,
+                               Data:       tt.fields.Data,
+                               readOffset: tt.fields.readOffset,
+                       }
+                       got, err := f.Read(tt.args.p)
+                       if !tt.wantErr(t, err, fmt.Sprintf("Read(%v)", tt.args.p)) {
+                               return
+                       }
+                       assert.Equalf(t, tt.want, got, "Read(%v)", tt.args.p)
+                       assert.Equalf(t, tt.wantBytes, tt.args.p[:got], "Read(%v)", tt.args.p)
+               })
+       }
+}
index 342355bc50db7ddfad8d934202c6fb3cba628997..bc6319b4f7db2db50ba1a102b91a4366c5421b33 100644 (file)
@@ -248,24 +248,21 @@ func (f *fileWrapper) flattenedFileObject() (*flattenedFileObject, error) {
                if err != nil {
                        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},
+                       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),
-                       NameSize:         []byte{0, 0},
-                       CommentSize:      []byte{0, 0},
                        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{
index 6753cceb7ec5995d7f65ed75e67658c06b598f0c..f2fc171982a7026ead70b0e059ed4db71beaef64 100644 (file)
@@ -118,8 +118,8 @@ func getFileNameList(path string, ignoreList []string) (fields []Field, err erro
                        }
 
                        copy(fnwi.FileSize[:], hlFile.totalSize())
-                       copy(fnwi.Type[:], hlFile.ffo.FlatFileInformationFork.TypeSignature)
-                       copy(fnwi.Creator[:], hlFile.ffo.FlatFileInformationFork.CreatorSignature)
+                       copy(fnwi.Type[:], hlFile.ffo.FlatFileInformationFork.TypeSignature[:])
+                       copy(fnwi.Creator[:], hlFile.ffo.FlatFileInformationFork.CreatorSignature[:])
                }
 
                strippedName := strings.ReplaceAll(file.Name(), ".incomplete", "")
index b178c6c1a739cd80eafa706bdea76d629498ec18..15ce94d8e4a27306ebaa2a8c23b725ee67acddae 100644 (file)
@@ -26,59 +26,55 @@ type FlatFileHeader struct {
 }
 
 type FlatFileInformationFork struct {
-       Platform         []byte // Operating System used. ("AMAC" or "MWIN")
-       TypeSignature    []byte // File type signature
-       CreatorSignature []byte // File creator signature
-       Flags            []byte
-       PlatformFlags    []byte
-       RSVD             []byte
-       CreateDate       []byte
-       ModifyDate       []byte
-       NameScript       []byte
-       NameSize         []byte // Length of file name (Maximum 128 characters)
-       Name             []byte // File name
-       CommentSize      []byte // Length of the comment
-       Comment          []byte // File comment
+       Platform         [4]byte // Operating System used. ("AMAC" or "MWIN")
+       TypeSignature    [4]byte // File type signature
+       CreatorSignature [4]byte // File creator signature
+       Flags            [4]byte
+       PlatformFlags    [4]byte
+       RSVD             [32]byte
+       CreateDate       [8]byte
+       ModifyDate       [8]byte
+       NameScript       [2]byte
+       NameSize         [2]byte // Length of file name (Maximum 128 characters)
+       Name             []byte  // File name
+       CommentSize      [2]byte // Length of the comment
+       Comment          []byte  // File comment
 
        readOffset int // Internal offset to track read progress
 }
 
-func NewFlatFileInformationFork(fileName string, modifyTime []byte, typeSignature string, creatorSignature string) FlatFileInformationFork {
+func NewFlatFileInformationFork(fileName string, modifyTime [8]byte, typeSignature string, creatorSignature string) FlatFileInformationFork {
        return FlatFileInformationFork{
-               Platform:         []byte("AMAC"),           // TODO: Remove hardcode to support "AWIN" Platform (maybe?)
-               TypeSignature:    []byte(typeSignature),    // TODO: Don't infer types from filename
-               CreatorSignature: []byte(creatorSignature), // TODO: Don't infer types from filename
-               Flags:            []byte{0, 0, 0, 0},       // TODO: What is this?
-               PlatformFlags:    []byte{0, 0, 1, 0},       // TODO: What is this?
-               RSVD:             make([]byte, 32),         // Unimplemented in Hotline Protocol
-               CreateDate:       modifyTime,               // some filesystems don't support createTime
+               Platform:         [4]byte{0x41, 0x4D, 0x41, 0x43},   // "AMAC" TODO: Remove hardcode to support "AWIN" Platform (maybe?)
+               TypeSignature:    [4]byte([]byte(typeSignature)),    // TODO: Don't infer types from filename
+               CreatorSignature: [4]byte([]byte(creatorSignature)), // TODO: Don't infer types from filename
+               PlatformFlags:    [4]byte{0, 0, 1, 0},               // TODO: What is this?
+               CreateDate:       modifyTime,                        // some filesystems don't support createTime
                ModifyDate:       modifyTime,
-               NameScript:       make([]byte, 2), // TODO: What is this?
                Name:             []byte(fileName),
-               CommentSize:      []byte{0, 0},
                Comment:          []byte{}, // TODO: implement (maybe?)
        }
 }
 
 func (ffif *FlatFileInformationFork) friendlyType() []byte {
-       if name, ok := friendlyCreatorNames[string(ffif.TypeSignature)]; ok {
+       if name, ok := friendlyCreatorNames[string(ffif.TypeSignature[:])]; ok {
                return []byte(name)
        }
-       return ffif.TypeSignature
+       return ffif.TypeSignature[:]
 }
 
 func (ffif *FlatFileInformationFork) friendlyCreator() []byte {
-       if name, ok := friendlyCreatorNames[string(ffif.CreatorSignature)]; ok {
+       if name, ok := friendlyCreatorNames[string(ffif.CreatorSignature[:])]; ok {
                return []byte(name)
        }
-       return ffif.CreatorSignature
+       return ffif.CreatorSignature[:]
 }
 
 func (ffif *FlatFileInformationFork) setComment(comment []byte) error {
-       ffif.CommentSize = make([]byte, 2)
+       commentSize := make([]byte, 2)
        ffif.Comment = comment
-       binary.BigEndian.PutUint16(ffif.CommentSize, uint16(len(comment)))
-
+       binary.BigEndian.PutUint16(commentSize, uint16(len(comment)))
+       ffif.CommentSize = [2]byte(commentSize)
        // TODO: return err if comment is too long
        return nil
 }
@@ -138,18 +134,18 @@ type FlatFileForkHeader struct {
 
 func (ffif *FlatFileInformationFork) Read(p []byte) (int, error) {
        buf := slices.Concat(
-               ffif.Platform,
-               ffif.TypeSignature,
-               ffif.CreatorSignature,
-               ffif.Flags,
-               ffif.PlatformFlags,
-               ffif.RSVD,
-               ffif.CreateDate,
-               ffif.ModifyDate,
-               ffif.NameScript,
+               ffif.Platform[:],
+               ffif.TypeSignature[:],
+               ffif.CreatorSignature[:],
+               ffif.Flags[:],
+               ffif.PlatformFlags[:],
+               ffif.RSVD[:],
+               ffif.CreateDate[:],
+               ffif.ModifyDate[:],
+               ffif.NameScript[:],
                ffif.ReadNameSize(),
                ffif.Name,
-               ffif.CommentSize,
+               ffif.CommentSize[:],
                ffif.Comment,
        )
 
@@ -169,21 +165,21 @@ func (ffif *FlatFileInformationFork) Write(p []byte) (int, error) {
        bs := binary.BigEndian.Uint16(nameSize)
        total := 72 + bs
 
-       ffif.Platform = p[0:4]
-       ffif.TypeSignature = p[4:8]
-       ffif.CreatorSignature = p[8:12]
-       ffif.Flags = p[12:16]
-       ffif.PlatformFlags = p[16:20]
-       ffif.RSVD = p[20:52]
-       ffif.CreateDate = p[52:60]
-       ffif.ModifyDate = p[60:68]
-       ffif.NameScript = p[68:70]
-       ffif.NameSize = p[70:72]
+       ffif.Platform = [4]byte(p[0:4])
+       ffif.TypeSignature = [4]byte(p[4:8])
+       ffif.CreatorSignature = [4]byte(p[8:12])
+       ffif.Flags = [4]byte(p[12:16])
+       ffif.PlatformFlags = [4]byte(p[16:20])
+       ffif.RSVD = [32]byte(p[20:52])
+       ffif.CreateDate = [8]byte(p[52:60])
+       ffif.ModifyDate = [8]byte(p[60:68])
+       ffif.NameScript = [2]byte(p[68:70])
+       ffif.NameSize = [2]byte(p[70:72])
        ffif.Name = p[72:total]
 
        if len(p) > int(total) {
-               ffif.CommentSize = p[total : total+2]
-               commentLen := binary.BigEndian.Uint16(ffif.CommentSize)
+               ffif.CommentSize = [2]byte(p[total : total+2])
+               commentLen := binary.BigEndian.Uint16(ffif.CommentSize[:])
                commentStartPos := int(total) + 2
                commentEndPos := int(total) + 2 + int(commentLen)
 
@@ -200,21 +196,21 @@ func (ffif *FlatFileInformationFork) UnmarshalBinary(b []byte) error {
        bs := binary.BigEndian.Uint16(nameSize)
        nameEnd := 72 + bs
 
-       ffif.Platform = b[0:4]
-       ffif.TypeSignature = b[4:8]
-       ffif.CreatorSignature = b[8:12]
-       ffif.Flags = b[12:16]
-       ffif.PlatformFlags = b[16:20]
-       ffif.RSVD = b[20:52]
-       ffif.CreateDate = b[52:60]
-       ffif.ModifyDate = b[60:68]
-       ffif.NameScript = b[68:70]
-       ffif.NameSize = b[70:72]
+       ffif.Platform = [4]byte(b[0:4])
+       ffif.TypeSignature = [4]byte(b[4:8])
+       ffif.CreatorSignature = [4]byte(b[8:12])
+       ffif.Flags = [4]byte(b[12:16])
+       ffif.PlatformFlags = [4]byte(b[16:20])
+       ffif.RSVD = [32]byte(b[20:52])
+       ffif.CreateDate = [8]byte(b[52:60])
+       ffif.ModifyDate = [8]byte(b[60:68])
+       ffif.NameScript = [2]byte(b[68:70])
+       ffif.NameSize = [2]byte(b[70:72])
        ffif.Name = b[72:nameEnd]
 
        if len(b) > int(nameEnd) {
-               ffif.CommentSize = b[nameEnd : nameEnd+2]
-               commentLen := binary.BigEndian.Uint16(ffif.CommentSize)
+               ffif.CommentSize = [2]byte(b[nameEnd : nameEnd+2])
+               commentLen := binary.BigEndian.Uint16(ffif.CommentSize[:])
 
                commentStartPos := int(nameEnd) + 2
                commentEndPos := int(nameEnd) + 2 + int(commentLen)
@@ -236,18 +232,18 @@ func (ffo *flattenedFileObject) Read(p []byte) (int, error) {
                []byte{0, 0, 0, 0},
                make([]byte, 4),
                ffo.FlatFileInformationFork.DataSize(),
-               ffo.FlatFileInformationFork.Platform,
-               ffo.FlatFileInformationFork.TypeSignature,
-               ffo.FlatFileInformationFork.CreatorSignature,
-               ffo.FlatFileInformationFork.Flags,
-               ffo.FlatFileInformationFork.PlatformFlags,
-               ffo.FlatFileInformationFork.RSVD,
-               ffo.FlatFileInformationFork.CreateDate,
-               ffo.FlatFileInformationFork.ModifyDate,
-               ffo.FlatFileInformationFork.NameScript,
+               ffo.FlatFileInformationFork.Platform[:],
+               ffo.FlatFileInformationFork.TypeSignature[:],
+               ffo.FlatFileInformationFork.CreatorSignature[:],
+               ffo.FlatFileInformationFork.Flags[:],
+               ffo.FlatFileInformationFork.PlatformFlags[:],
+               ffo.FlatFileInformationFork.RSVD[:],
+               ffo.FlatFileInformationFork.CreateDate[:],
+               ffo.FlatFileInformationFork.ModifyDate[:],
+               ffo.FlatFileInformationFork.NameScript[:],
                ffo.FlatFileInformationFork.ReadNameSize(),
                ffo.FlatFileInformationFork.Name,
-               ffo.FlatFileInformationFork.CommentSize,
+               ffo.FlatFileInformationFork.CommentSize[:],
                ffo.FlatFileInformationFork.Comment,
                ffo.FlatFileDataForkHeader.ForkType[:],
                ffo.FlatFileDataForkHeader.CompressionType[:],
index 3e23d27f6ada00f9dde75623d0f2fabff3d1e921..28aecf08875c195772f6d88ba5c9f89577c0f63e 100644 (file)
@@ -45,7 +45,7 @@ func tranAssertEqual(t *testing.T, tran1, tran2 []Transaction) bool {
                        if field.ID == [2]byte{0x00, 0x72} { // FieldChatID
                                continue
                        }
-                       fs = append(fs, field)
+                       trans.Fields = append(trans.Fields, field)
                }
                trans.Fields = fs
                newT1 = append(newT1, trans)
@@ -61,7 +61,7 @@ func tranAssertEqual(t *testing.T, tran1, tran2 []Transaction) bool {
                        if field.ID == [2]byte{0x00, 0x72} { // FieldChatID
                                continue
                        }
-                       fs = append(fs, field)
+                       trans.Fields = append(trans.Fields, field)
                }
                trans.Fields = fs
                newT2 = append(newT2, trans)
index 3a368e0315786ebf0969c5b02fa5c974f38601e1..6ea88804d1faeb705d4bbc5dc19af9a13f304b7f 100644 (file)
@@ -114,7 +114,7 @@ func TestServer_handleFileTransfer(t *testing.T) {
                                Logger: NewTestLogger(),
                                Stats:  &Stats{},
                                fileTransfers: map[[4]byte]*FileTransfer{
-                                       [4]byte{0, 0, 0, 5}: {
+                                       {0, 0, 0, 5}: {
                                                ReferenceNumber: []byte{0, 0, 0, 5},
                                                Type:            FileDownload,
                                                FileName:        []byte("testfile-8b"),
index 8f8ddd15e259fd925c14523833e0d3de5d36f346..b927986ae65f27d922baf61139143f1e2b69a658 100644 (file)
@@ -135,6 +135,7 @@ func GetListing(addr string) ([]ServerRecord, error) {
        var servers []ServerRecord
        for {
                scanner.Scan()
+
                var srv ServerRecord
                _, err = srv.Write(scanner.Bytes())
                if err != nil {
index cff19d52d4630e2e8f67588c7330eb43820897a2..3d7ba14ec03931cf9a1119f927ac561bd410da7e 100644 (file)
@@ -373,6 +373,8 @@ func HandleSendInstantMsg(cc *ClientConn, t *Transaction) (res []Transaction, er
        return res, err
 }
 
+var fileTypeFLDR = [4]byte{0x66, 0x6c, 0x64, 0x72}
+
 func HandleGetFileInfo(cc *ClientConn, t *Transaction) (res []Transaction, err error) {
        fileName := t.GetField(FieldFileName).Data
        filePath := t.GetField(FieldFilePath).Data
@@ -396,9 +398,9 @@ func HandleGetFileInfo(cc *ClientConn, t *Transaction) (res []Transaction, err e
                NewField(FieldFileName, []byte(encodedName)),
                NewField(FieldFileTypeString, fw.ffo.FlatFileInformationFork.friendlyType()),
                NewField(FieldFileCreatorString, fw.ffo.FlatFileInformationFork.friendlyCreator()),
-               NewField(FieldFileType, fw.ffo.FlatFileInformationFork.TypeSignature),
-               NewField(FieldFileCreateDate, fw.ffo.FlatFileInformationFork.CreateDate),
-               NewField(FieldFileModifyDate, fw.ffo.FlatFileInformationFork.ModifyDate),
+               NewField(FieldFileType, fw.ffo.FlatFileInformationFork.TypeSignature[:]),
+               NewField(FieldFileCreateDate, fw.ffo.FlatFileInformationFork.CreateDate[:]),
+               NewField(FieldFileModifyDate, fw.ffo.FlatFileInformationFork.ModifyDate[:]),
        }
 
        // Include the optional FileComment field if there is a comment.
@@ -407,7 +409,7 @@ func HandleGetFileInfo(cc *ClientConn, t *Transaction) (res []Transaction, err e
        }
 
        // Include the FileSize field for files.
-       if !bytes.Equal(fw.ffo.FlatFileInformationFork.TypeSignature, []byte{0x66, 0x6c, 0x64, 0x72}) {
+       if fw.ffo.FlatFileInformationFork.TypeSignature != fileTypeFLDR {
                fields = append(fields, NewField(FieldFileSize, fw.totalSize()))
        }
 
@@ -773,7 +775,6 @@ func HandleListUsers(cc *ClientConn, t *Transaction) (res []Transaction, err err
 // performed.  This seems to be the only place in the Hotline protocol where a data field contains another data field.
 func HandleUpdateUser(cc *ClientConn, t *Transaction) (res []Transaction, err error) {
        for _, field := range t.Fields {
-
                var subFields []Field
 
                // Create a new scanner for parsing incoming bytes into transaction tokens
@@ -1937,7 +1938,6 @@ func HandleJoinChat(cc *ClientConn, t *Transaction) (res []Transaction, err erro
 
        replyFields := []Field{NewField(FieldChatSubject, []byte(privChat.Subject))}
        for _, c := range sortedClients(privChat.ClientConn) {
-
                b, err := io.ReadAll(&User{
                        ID:    *c.ID,
                        Icon:  c.Icon,
index 481e273acbbdbce0131ca52c3862a6f08ae2ad9e..3b6c44604ef70d1d17adb521192570f7c1756a13 100644 (file)
@@ -126,7 +126,7 @@ func Test_receiveFile(t *testing.T) {
                                                        ForkCount: [2]byte{0, 2},
                                                },
                                                FlatFileInformationForkHeader: FlatFileForkHeader{},
-                                               FlatFileInformationFork:       NewFlatFileInformationFork("testfile.txt", make([]byte, 8), "TEXT", "TEXT"),
+                                               FlatFileInformationFork:       NewFlatFileInformationFork("testfile.txt", [8]byte{}, "TEXT", "TEXT"),
                                                FlatFileDataForkHeader: FlatFileForkHeader{
                                                        ForkType:        [4]byte{0x4d, 0x41, 0x43, 0x52}, // DATA
                                                        CompressionType: [4]byte{0, 0, 0, 0},