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