diff --git a/cmd/camtool/exif.go b/cmd/camtool/exif.go index 2bb7215e5..01d14e43b 100644 --- a/cmd/camtool/exif.go +++ b/cmd/camtool/exif.go @@ -32,9 +32,18 @@ func showEXIF(file string) { defer f.Close() ex, err := exif.Decode(f) if err != nil { - log.Fatalf("exif.Decode: %v", err) + if exif.IsCriticalError(err) { + log.Fatalf("exif.Decode, critical error: %v", err) + } + log.Printf("exif.Decode, warning: %v", err) + } + fmt.Printf("%v\n", ex) + if exif.IsExifError(err) { + // the error happened while decoding the EXIF sub-IFD, so as DateTime is + // part of it, we have to assume (until there's a better "decode effort" + // strategy in goexif) that it's not usable. + return } - fmt.Printf("exif.Decode = %#v\n", ex) ct, err := ex.DateTime() fmt.Printf("exif.DateTime = %v, %v\n", ct, err) } diff --git a/pkg/index/receive.go b/pkg/index/receive.go index 6487b853d..86ba5bf87 100644 --- a/pkg/index/receive.go +++ b/pkg/index/receive.go @@ -410,6 +410,7 @@ func (ix *Index) populateFile(fetcher blob.Fetcher, b *schema.Blob, mm *mutation log.Printf("filename %q exif = %v, %v", b.FileName(), ft, err) } + // TODO(mpl): find (generate?) more broken EXIF images to experiment with. err = indexEXIF(wholeRef, bytes.NewReader(imageBuf.Bytes), mm) if err == io.EOF { var fr *schema.FileReader @@ -472,9 +473,14 @@ func (f exifWalkFunc) Walk(name exif.FieldName, tag *tiff.Tag) error { return f( var errEXIFPanic = errors.New("EXIF library panicked while walking fields") func indexEXIF(wholeRef blob.Ref, reader io.Reader, mm *mutationMap) (err error) { + var tiffErr error ex, err := exif.Decode(reader) if err != nil { - return + tiffErr = err + if exif.IsCriticalError(err) { + return + } + log.Printf("Non critical TIFF decoding error: %v", err) } defer func() { // The EXIF library panics if you access a field past @@ -549,6 +555,10 @@ func indexEXIF(wholeRef blob.Ref, reader io.Reader, mm *mutationMap) (err error) return } + if exif.IsGPSError(tiffErr) { + log.Printf("Invalid EXIF GPS data: %v", tiffErr) + return nil + } if lat, long, err := ex.LatLong(); err == nil { mm.Set(keyEXIFGPS.Key(wholeRef), keyEXIFGPS.Val(fmt.Sprint(lat), fmt.Sprint(long))) } else if !exif.IsTagNotPresentError(err) { diff --git a/pkg/schema/schema.go b/pkg/schema/schema.go index bfbe2bc26..39bb49f7c 100644 --- a/pkg/schema/schema.go +++ b/pkg/schema/schema.go @@ -958,9 +958,13 @@ func FileTime(f io.ReaderAt) (time.Time, error) { size = 256 << 10 // enough to get the EXIF } r := io.NewSectionReader(f, 0, size) + var tiffErr error ex, err := exif.Decode(r) if err != nil { - return defaultTime() + tiffErr = err + if exif.IsCriticalError(err) || exif.IsExifError(err) { + return defaultTime() + } } ct, err = ex.DateTime() if err != nil { @@ -969,6 +973,10 @@ func FileTime(f io.ReaderAt) (time.Time, error) { // If the EXIF file only had local timezone, but it did have // GPS, then lookup the timezone and correct the time. if ct.Location() == time.Local { + if exif.IsGPSError(tiffErr) { + log.Printf("Invalid EXIF GPS data: %v", tiffErr) + return ct, nil + } if lat, long, err := ex.LatLong(); err == nil { if loc := lookupLocation(latlong.LookupZoneName(lat, long)); loc != nil { if t, err := exifDateTimeInLocation(ex, loc); err == nil {