| package fat32 |
| |
| import ( |
| "fmt" |
| "io" |
| "time" |
| ) |
| |
| // Wraps a writer and provides support for writing padding up to a specified |
| // alignment. |
| // TODO(lorenz): Implement WriterTo when w implements it to allow for copy |
| // offload |
| type blockWriter struct { |
| w io.Writer |
| n int64 |
| } |
| |
| func newBlockWriter(w io.Writer) *blockWriter { |
| return &blockWriter{w: w} |
| } |
| |
| func (b *blockWriter) Write(p []byte) (n int, err error) { |
| n, err = b.w.Write(p) |
| b.n += int64(n) |
| return |
| } |
| |
| func (b *blockWriter) FinishBlock(alignment int64, mustZero bool) (err error) { |
| requiredBytes := (alignment - (b.n % alignment)) % alignment |
| if requiredBytes == 0 { |
| return nil |
| } |
| // Do not actually write out zeroes if not necessary |
| if s, ok := b.w.(io.Seeker); ok && !mustZero { |
| if _, err := s.Seek(requiredBytes-1, io.SeekCurrent); err != nil { |
| return fmt.Errorf("failed to seek to create hole for empty block: %w", err) |
| } |
| if _, err := b.w.Write([]byte{0x00}); err != nil { |
| return fmt.Errorf("failed to write last byte to create hole: %w", err) |
| } |
| b.n += requiredBytes |
| return |
| } |
| emptyBuf := make([]byte, 1*1024*1024) |
| for requiredBytes > 0 { |
| curBlockBytes := requiredBytes |
| if curBlockBytes > int64(len(emptyBuf)) { |
| curBlockBytes = int64(len(emptyBuf)) |
| } |
| _, err = b.Write(emptyBuf[:curBlockBytes]) |
| if err != nil { |
| return |
| } |
| requiredBytes -= curBlockBytes |
| } |
| return |
| } |
| |
| // timeToMsDosTime converts a time.Time to an MS-DOS date and time. |
| // The resolution is 2s with fTime and 10ms if fTenMils is also used. |
| // See: http://msdn.microsoft.com/en-us/library/ms724274(v=VS.85).aspx |
| func timeToMsDosTime(t time.Time) (fDate uint16, fTime uint16, fTenMils uint8) { |
| t = t.In(time.UTC) |
| if t.Year() < 1980 { |
| t = time.Date(1980, 1, 1, 0, 0, 0, 0, time.UTC) |
| } |
| if t.Year() > 2107 { |
| t = time.Date(2107, 12, 31, 23, 59, 59, 0, time.UTC) |
| } |
| fDate = uint16(t.Day() + int(t.Month())<<5 + (t.Year()-1980)<<9) |
| fTime = uint16(t.Second()/2 + t.Minute()<<5 + t.Hour()<<11) |
| fTenMils = uint8(t.Nanosecond()/1e7 + (t.Second()%2)*100) |
| return |
| } |