Пример #1
0
func (be *Backend) UploadFile(bin string, filename string, data io.ReadCloser) (File, error) {
	be.Log.Println("Uploading file " + filename + " to bin " + bin)
	f := File{}
	f.Filename = filename
	f.Bin = bin

	if !isDir(be.tempdir) {
		if err := os.Mkdir(be.tempdir, 0700); err != nil {
			return f, err
		}
	}

	fp, err := ioutil.TempFile(be.tempdir, "upload")
	// Defer removal of the tempfile to clean up partially uploaded files.
	defer os.Remove(fp.Name())
	defer fp.Close()

	if err != nil {
		be.Log.Println(err)
		return f, err
	}

	bytes, err := io.Copy(fp, data)
	if err != nil {
		be.Log.Println("Error occurred during io.Copy: " + err.Error())
		return f, err
	}
	be.Log.Println("Uploaded " + strconv.FormatInt(bytes, 10) + " bytes")

	f.Bytes = bytes
	if bytes == 0 {
		be.Log.Println("Empty files are not allowed. Aborting.")

		if err := os.Remove(fp.Name()); err != nil {
			be.Log.Println(err)
			return f, err
		}

		err := errors.New("No content. The file size must be more than 0 bytes")
		return f, err
	}

	buffer := make([]byte, 512)
	_, err = fp.Seek(0, 0)
	if err != nil {
		return f, err
	}
	_, err = fp.Read(buffer)
	if err != nil {
		return f, err
	}
	f.MIME = http.DetectContentType(buffer)

	hash := sha256.New()
	fp.Seek(0, 0)
	if err != nil {
		return f, err
	}
	_, err = io.Copy(hash, fp)
	if err != nil {
		return f, err
	}

	var result []byte
	f.Checksum = hex.EncodeToString(hash.Sum(result))

	// Exif
	if strings.Split(f.MIME, "/")[0] == "image" {
		if _, err = fp.Seek(0, 0); err != nil {
			return f, err
		}
		exif, err := exif.Decode(fp)
		if err != nil {
			// XXX: Log
		} else {
			f.DateTime, err = exif.DateTime()
			if err != nil {
				// Could not read DateTime or DateTimeOriginal.
				// Certain Android phones (verified on Nexus 6) have a
				// bug where these fields may be missing from the EXIF
				// data in pictures. The capture time may be stored in
				// the GPS info, so let's try to assemble a valid
				// DateTime from it.
				dStamp, dErr := exif.Get("GPSDateStamp")
				tStamp, tErr := exif.Get("GPSTimeStamp")
				if dErr == nil && tErr == nil {
					s := dStamp.String() + " " + tStamp.String()
					s = strings.Replace(s, "\"", "", -1)
					s = strings.Replace(s, "[", "", -1)
					s = strings.Replace(s, "]", "", -1)
					s = strings.Replace(s, ":", "-", -1)
					s = strings.Replace(s, ",", " ", -1)
					s = strings.Replace(s, "/1", "", -1)
					be.Log.Println("String to parse: " + s)

					// After removing the special characters above, the
					// string to parse is on the following format:
					// 2016-05-21 12 26 12
					dt, err := time.Parse("2006-01-02 15 4 5", s)
					if err != nil {
						be.Log.Println("Unable to parse: ", err)
					} else {
						f.DateTime = dt.Local()
					}
				}
			}

			f.Latitude, f.Longitude, err = exif.LatLong()
			if err != nil {
				/// XXX: Log
			}
		}
	}

	// iOS devices provide only one filename even when uploading
	// multiple images. Providing some workaround for this below.
	// XXX: Refactoring needed. Can probably be done nicer.
	if strings.Split(f.MIME, "/")[0] == "image" && !f.DateTime.IsZero() {
		dt := f.DateTime.Format("060102-150405")
		var fname string

		// List of filenames to modify
		if filename == "image.jpeg" {
			fname = "img-" + dt + ".jpeg"
		}
		if filename == "image.gif" {
			fname = "img-" + dt + ".gif"
		}
		if filename == "image.png" {
			fname = "img-" + dt + ".png"
		}

		if fname != "" {
			be.Log.Println("Filename workaround triggered")
			be.Log.Println("Filename modified: " + fname)
			f.Filename = fname
		}
	}

	bindir := filepath.Join(be.filedir, bin)
	if !isDir(bindir) {
		if err := os.Mkdir(bindir, 0700); err != nil {
			return f, err
		}
	}

	dst := filepath.Join(bindir, f.Filename)
	be.Log.Println("Copying contents to " + dst)
	if err := CopyFile(fp.Name(), dst); err != nil {
		be.Log.Println(err)
		return f, err
	}

	fi, err := os.Lstat(dst)
	if err != nil {
		be.Log.Println(err)
		return f, err
	}

	f.CreatedAt = fi.ModTime()
	f.Links = be.GenerateLinks(bin, f.Filename)

	be.Lock()
	defer be.Unlock()
	id := f.Bin + f.Filename
	delete(be.files, id)
	be.files[id] = f

	return f, err
}
Пример #2
0
func (be *Backend) getFileMetaData(bin string, filename string) (File, error) {
	be.Log.Println("Reading file meta data: " + filename + " (" + bin + ")...")

	f := File{}
	path := filepath.Join(be.filedir, bin, filename)

	// File info
	fi, err := os.Lstat(path)
	if err != nil || fi.IsDir() == true {
		return f, errors.New("File does not exist.")
	}

	f.Bin = bin
	f.Filename = filename
	f.Bytes = fi.Size()
	f.CreatedAt = fi.ModTime()

	// Calculate checksum
	fp, err := os.Open(path)
	if err != nil {
		return f, err
	}
	defer fp.Close()

	hash := sha256.New()
	if _, err = io.Copy(hash, fp); err != nil {
		return f, err
	}
	var result []byte
	f.Checksum = hex.EncodeToString(hash.Sum(result))

	// MIME
	buffer := make([]byte, 512)
	if _, err = fp.Seek(0, 0); err != nil {
		return f, err
	}
	if _, err = fp.Read(buffer); err != nil {
		return f, err
	}
	f.MIME = http.DetectContentType(buffer)
	f.Links = be.GenerateLinks(bin, filename)

	// Exif
	if strings.Split(f.MIME, "/")[0] == "image" {
		if _, err = fp.Seek(0, 0); err != nil {
			return f, err
		}

		exif, err := exif.Decode(fp)
		if err != nil {
			// XXX: Log
		} else {
			f.DateTime, err = exif.DateTime()
			if err != nil {
				// Could not read DateTime or DateTimeOriginal.
				// Certain Android phones (verified on Nexus 6) have a
				// bug where these fields may be missing from the EXIF
				// data in pictures. The capture time may be stored in
				// the GPS info, so let's try to assemble a valid
				// DateTime from it.
				dStamp, dErr := exif.Get("GPSDateStamp")
				tStamp, tErr := exif.Get("GPSTimeStamp")
				if dErr == nil && tErr == nil {
					s := dStamp.String() + " " + tStamp.String()
					s = strings.Replace(s, "\"", "", -1)
					s = strings.Replace(s, "[", "", -1)
					s = strings.Replace(s, "]", "", -1)
					s = strings.Replace(s, ":", "-", -1)
					s = strings.Replace(s, ",", " ", -1)
					s = strings.Replace(s, "/1", "", -1)
					be.Log.Println("String to parse: " + s)

					// After removing the special characters above, the
					// string to parse is on the following format:
					// 2016-05-21 12 26 12
					dt, err := time.Parse("2006-01-02 15 4 5", s)
					if err != nil {
						be.Log.Println("Unable to parse: ", err)
					} else {
						f.DateTime = dt.Local()
					}
				}
			}

			f.Latitude, f.Longitude, err = exif.LatLong()
			if err != nil {
				/// XXX: Log
			}
		}
	}

	return f, nil
}