blob: 8ddb1627219f8c1e2448b14237b4b85adf8905a9 [file] [log] [blame]
Tim Windelschmidt6d33a432025-02-04 14:34:25 +01001// Copyright The Monogon Project Authors.
2// SPDX-License-Identifier: Apache-2.0
3
Lorenz Brunbd2ce6d2022-07-22 00:00:13 +00004package fat32
5
6import (
7 "fmt"
8 "io"
9 "time"
10)
11
12// Wraps a writer and provides support for writing padding up to a specified
13// alignment.
14// TODO(lorenz): Implement WriterTo when w implements it to allow for copy
15// offload
16type blockWriter struct {
17 w io.Writer
18 n int64
19}
20
21func newBlockWriter(w io.Writer) *blockWriter {
22 return &blockWriter{w: w}
23}
24
25func (b *blockWriter) Write(p []byte) (n int, err error) {
26 n, err = b.w.Write(p)
27 b.n += int64(n)
28 return
29}
30
31func (b *blockWriter) FinishBlock(alignment int64, mustZero bool) (err error) {
32 requiredBytes := (alignment - (b.n % alignment)) % alignment
33 if requiredBytes == 0 {
34 return nil
35 }
36 // Do not actually write out zeroes if not necessary
37 if s, ok := b.w.(io.Seeker); ok && !mustZero {
38 if _, err := s.Seek(requiredBytes-1, io.SeekCurrent); err != nil {
39 return fmt.Errorf("failed to seek to create hole for empty block: %w", err)
40 }
41 if _, err := b.w.Write([]byte{0x00}); err != nil {
42 return fmt.Errorf("failed to write last byte to create hole: %w", err)
43 }
44 b.n += requiredBytes
45 return
46 }
47 emptyBuf := make([]byte, 1*1024*1024)
48 for requiredBytes > 0 {
49 curBlockBytes := requiredBytes
50 if curBlockBytes > int64(len(emptyBuf)) {
51 curBlockBytes = int64(len(emptyBuf))
52 }
53 _, err = b.Write(emptyBuf[:curBlockBytes])
54 if err != nil {
55 return
56 }
57 requiredBytes -= curBlockBytes
58 }
59 return
60}
61
62// timeToMsDosTime converts a time.Time to an MS-DOS date and time.
63// The resolution is 2s with fTime and 10ms if fTenMils is also used.
64// See: http://msdn.microsoft.com/en-us/library/ms724274(v=VS.85).aspx
65func timeToMsDosTime(t time.Time) (fDate uint16, fTime uint16, fTenMils uint8) {
66 t = t.In(time.UTC)
67 if t.Year() < 1980 {
68 t = time.Date(1980, 1, 1, 0, 0, 0, 0, time.UTC)
69 }
70 if t.Year() > 2107 {
71 t = time.Date(2107, 12, 31, 23, 59, 59, 0, time.UTC)
72 }
73 fDate = uint16(t.Day() + int(t.Month())<<5 + (t.Year()-1980)<<9)
74 fTime = uint16(t.Second()/2 + t.Minute()<<5 + t.Hour()<<11)
75 fTenMils = uint8(t.Nanosecond()/1e7 + (t.Second()%2)*100)
76 return
77}