aboutsummaryrefslogtreecommitdiff
path: root/hotline
diff options
context:
space:
mode:
authorjhalter <868228+jhalter@users.noreply.github.com>2022-05-25 19:53:34 -0700
committerGitHub <noreply@github.com>2022-05-25 19:53:34 -0700
commit5433ca327290cc235c1524a4e64b32a4b45f6d99 (patch)
tree9bc21e1e3ff6412f85af23fef7a885bafec8fe1e /hotline
parentc62f0b470f0ce33d5f52897f2cae7fd355f04b80 (diff)
parent29f329aedcdcf4e07a6dc3d9161439dd35ecfe11 (diff)
Merge pull request #10 from jhalter/implement_file_timestamps
Add partial support for file create/modify timestamps
Diffstat (limited to 'hotline')
-rw-r--r--hotline/flattened_file_object.go26
-rw-r--r--hotline/flattened_file_object_test.go9
-rw-r--r--hotline/time.go25
-rw-r--r--hotline/transaction_handlers_test.go14
4 files changed, 57 insertions, 17 deletions
diff --git a/hotline/flattened_file_object.go b/hotline/flattened_file_object.go
index bd281e0..0a14df0 100644
--- a/hotline/flattened_file_object.go
+++ b/hotline/flattened_file_object.go
@@ -55,17 +55,17 @@ type FlatFileInformationFork struct {
Comment []byte // File comment
}
-func NewFlatFileInformationFork(fileName string) FlatFileInformationFork {
+func NewFlatFileInformationFork(fileName string, modifyTime []byte) FlatFileInformationFork {
return FlatFileInformationFork{
- Platform: []byte("AMAC"), // TODO: Remove hardcode to support "AWIN" Platform (maybe?)
- TypeSignature: []byte(fileTypeFromFilename(fileName).TypeCode), // TODO: Don't infer types from filename
- CreatorSignature: []byte(fileTypeFromFilename(fileName).CreatorCode), // 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: []byte{0x07, 0x70, 0x00, 0x00, 0xba, 0x74, 0x24, 0x73}, // TODO: implement
- ModifyDate: []byte{0x07, 0x70, 0x00, 0x00, 0xba, 0x74, 0x24, 0x73}, // TODO: implement
- NameScript: make([]byte, 2), // TODO: What is this?
+ Platform: []byte("AMAC"), // TODO: Remove hardcode to support "AWIN" Platform (maybe?)
+ TypeSignature: []byte(fileTypeFromFilename(fileName).TypeCode), // TODO: Don't infer types from filename
+ CreatorSignature: []byte(fileTypeFromFilename(fileName).CreatorCode), // 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
+ ModifyDate: modifyTime,
+ NameScript: make([]byte, 2), // TODO: What is this?
Name: []byte(fileName),
CommentSize: []byte{0, 4},
Comment: []byte("TODO"), // TODO: implement (maybe?)
@@ -204,7 +204,7 @@ func NewFlattenedFileObject(fileRoot string, filePath, fileName []byte) (*flatte
if err != nil {
return nil, err
}
- defer file.Close()
+ defer func(file *os.File) { _ = file.Close() }(file)
fileInfo, err := file.Stat()
if err != nil {
@@ -214,9 +214,11 @@ func NewFlattenedFileObject(fileRoot string, filePath, fileName []byte) (*flatte
dataSize := make([]byte, 4)
binary.BigEndian.PutUint32(dataSize, uint32(fileInfo.Size()))
+ mTime := toHotlineTime(fileInfo.ModTime())
+
return &flattenedFileObject{
FlatFileHeader: NewFlatFileHeader(),
- FlatFileInformationFork: NewFlatFileInformationFork(string(fileName)),
+ FlatFileInformationFork: NewFlatFileInformationFork(string(fileName), mTime),
FlatFileDataForkHeader: FlatFileDataForkHeader{
ForkType: []byte("DATA"),
CompressionType: []byte{0, 0, 0, 0},
diff --git a/hotline/flattened_file_object_test.go b/hotline/flattened_file_object_test.go
index 5bbaf1d..12b6d32 100644
--- a/hotline/flattened_file_object_test.go
+++ b/hotline/flattened_file_object_test.go
@@ -43,7 +43,7 @@ func TestNewFlattenedFileObject(t *testing.T) {
want: &flattenedFileObject{
FlatFileHeader: NewFlatFileHeader(),
FlatFileInformationForkHeader: FlatFileInformationForkHeader{},
- FlatFileInformationFork: NewFlatFileInformationFork("testfile.txt"),
+ FlatFileInformationFork: NewFlatFileInformationFork("testfile.txt", make([]byte, 8)),
FlatFileDataForkHeader: FlatFileDataForkHeader{
ForkType: []byte("DATA"),
CompressionType: []byte{0, 0, 0, 0},
@@ -67,9 +67,14 @@ func TestNewFlattenedFileObject(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := NewFlattenedFileObject(tt.args.fileRoot, tt.args.filePath, tt.args.fileName)
- if !tt.wantErr(t, err, fmt.Sprintf("NewFlattenedFileObject(%v, %v, %v)", tt.args.fileRoot, tt.args.filePath, tt.args.fileName)) {
+ if tt.wantErr(t, err, fmt.Sprintf("NewFlattenedFileObject(%v, %v, %v)", tt.args.fileRoot, tt.args.filePath, tt.args.fileName)) {
return
}
+
+ // Clear the file timestamp fields to work around problems running the tests in multiple timezones
+ // TODO: revisit how to test this by mocking the stat calls
+ got.FlatFileInformationFork.CreateDate = make([]byte, 8)
+ got.FlatFileInformationFork.ModifyDate = make([]byte, 8)
assert.Equalf(t, tt.want, got, "NewFlattenedFileObject(%v, %v, %v)", tt.args.fileRoot, tt.args.filePath, tt.args.fileName)
})
}
diff --git a/hotline/time.go b/hotline/time.go
new file mode 100644
index 0000000..3b87864
--- /dev/null
+++ b/hotline/time.go
@@ -0,0 +1,25 @@
+package hotline
+
+import (
+ "encoding/binary"
+ "time"
+)
+
+// toHotlineTime converts a time.Time to the 8 byte Hotline time format:
+// Year (2 bytes), milliseconds (2 bytes) and seconds (4 bytes)
+func toHotlineTime(t time.Time) (b []byte) {
+ yearBytes := make([]byte, 2)
+ secondBytes := make([]byte, 4)
+
+ // Get a time.Time for January 1st 00:00 from t so we can calculate the difference in seconds from t
+ startOfYear := time.Date(t.Year(), time.January, 1, 0, 0, 0, 0, time.Local)
+
+ binary.BigEndian.PutUint16(yearBytes, uint16(t.Year()))
+ binary.BigEndian.PutUint32(secondBytes, uint32(t.Sub(startOfYear).Seconds()))
+
+ b = append(b, yearBytes...)
+ b = append(b, []byte{0, 0}...)
+ b = append(b, secondBytes...)
+
+ return b
+}
diff --git a/hotline/transaction_handlers_test.go b/hotline/transaction_handlers_test.go
index f8d3b2e..b734049 100644
--- a/hotline/transaction_handlers_test.go
+++ b/hotline/transaction_handlers_test.go
@@ -469,7 +469,10 @@ func TestHandleGetFileInfo(t *testing.T) {
ID: &[]byte{0x00, 0x01},
Server: &Server{
Config: &Config{
- FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
+ FileRoot: func() string {
+ path, _ := os.Getwd()
+ return path + "/test/config/Files"
+ }(),
},
},
},
@@ -493,8 +496,8 @@ func TestHandleGetFileInfo(t *testing.T) {
NewField(fieldFileCreatorString, []byte("ttxt")),
NewField(fieldFileComment, []byte("TODO")),
NewField(fieldFileType, []byte("TEXT")),
- NewField(fieldFileCreateDate, []byte{0x07, 0x70, 0x00, 0x00, 0xba, 0x74, 0x24, 0x73}),
- NewField(fieldFileModifyDate, []byte{0x07, 0x70, 0x00, 0x00, 0xba, 0x74, 0x24, 0x73}),
+ NewField(fieldFileCreateDate, make([]byte, 8)),
+ NewField(fieldFileModifyDate, make([]byte, 8)),
NewField(fieldFileSize, []byte{0x0, 0x0, 0x0, 0x17}),
},
},
@@ -511,6 +514,11 @@ func TestHandleGetFileInfo(t *testing.T) {
t.Errorf("HandleGetFileInfo() error = %v, wantErr %v", err, tt.wantErr)
return
}
+
+ // Clear the file timestamp fields to work around problems running the tests in multiple timezones
+ // TODO: revisit how to test this by mocking the stat calls
+ gotRes[0].Fields[5].Data = make([]byte, 8)
+ gotRes[0].Fields[6].Data = make([]byte, 8)
if !assert.Equal(t, tt.wantRes, gotRes) {
t.Errorf("HandleGetFileInfo() gotRes = %v, want %v", gotRes, tt.wantRes)
}