|
|
|
/*
|
|
|
|
* Minio Cloud Storage, (C) 2016 Minio, Inc.
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"io"
|
|
|
|
"strconv"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
// error type when key is not found.
|
|
|
|
var errMetadataKeyNotExist = errors.New("Key not found in fileMetadata.")
|
|
|
|
|
|
|
|
// This code is built on similar ideas of http.Header.
|
|
|
|
// Ref - https://golang.org/pkg/net/http/#Header
|
|
|
|
|
|
|
|
// A fileMetadata represents a metadata header mapping
|
|
|
|
// keys to sets of values.
|
|
|
|
type fileMetadata map[string][]string
|
|
|
|
|
|
|
|
// Add adds the key, value pair to the header.
|
|
|
|
// It appends to any existing values associated with key.
|
|
|
|
func (f fileMetadata) Add(key, value string) {
|
|
|
|
f[key] = append(f[key], value)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set sets the header entries associated with key to
|
|
|
|
// the single element value. It replaces any existing
|
|
|
|
// values associated with key.
|
|
|
|
func (f fileMetadata) Set(key, value string) {
|
|
|
|
f[key] = []string{value}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get gets the first value associated with the given key.
|
|
|
|
// If there are no values associated with the key, Get returns "".
|
|
|
|
// Get is a convenience method. For more complex queries,
|
|
|
|
// access the map directly.
|
|
|
|
func (f fileMetadata) Get(key string) []string {
|
|
|
|
if f == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
v, ok := f[key]
|
|
|
|
if !ok {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write writes a metadata in wire format.
|
|
|
|
func (f fileMetadata) Write(writer io.Writer) error {
|
|
|
|
metadataBytes, err := json.Marshal(f)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, err = writer.Write(metadataBytes)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get file size.
|
|
|
|
func (f fileMetadata) GetSize() (int64, error) {
|
|
|
|
sizes := f.Get("file.size")
|
|
|
|
if sizes == nil {
|
|
|
|
return 0, errMetadataKeyNotExist
|
|
|
|
}
|
|
|
|
sizeStr := sizes[0]
|
|
|
|
return strconv.ParseInt(sizeStr, 10, 64)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set file size.
|
|
|
|
func (f fileMetadata) SetSize(size int64) {
|
|
|
|
f.Set("file.size", strconv.FormatInt(size, 10))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get file Modification time.
|
|
|
|
func (f fileMetadata) GetModTime() (time.Time, error) {
|
|
|
|
timeStrs := f.Get("file.modTime")
|
|
|
|
if timeStrs == nil {
|
|
|
|
return time.Time{}, errMetadataKeyNotExist
|
|
|
|
}
|
|
|
|
return time.Parse(timeFormatAMZ, timeStrs[0])
|
|
|
|
}
|
|
|
|
|
|
|
|
// fileMetadataDecode - file metadata decode.
|
|
|
|
func fileMetadataDecode(reader io.Reader) (fileMetadata, error) {
|
|
|
|
metadata := make(fileMetadata)
|
|
|
|
decoder := json.NewDecoder(reader)
|
|
|
|
// Unmarshalling failed, file possibly corrupted.
|
|
|
|
if err := decoder.Decode(&metadata); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return metadata, nil
|
|
|
|
}
|