diff --git a/api-put-object.go b/api-put-object.go index 99e2a71523..637804e4cb 100644 --- a/api-put-object.go +++ b/api-put-object.go @@ -109,14 +109,24 @@ func getReaderSize(reader io.Reader) (size int64, err error) { case "|0", "|1": return } - size = st.Size() + var pos int64 + pos, err = v.Seek(0, io.SeekCurrent) + if err != nil { + return -1, err + } + size = st.Size() - pos case *Object: var st ObjectInfo st, err = v.Stat() if err != nil { return } - size = st.Size + var pos int64 + pos, err = v.Seek(0, io.SeekCurrent) + if err != nil { + return -1, err + } + size = st.Size - pos } } // Returns the size here. diff --git a/api_functional_v4_test.go b/api_functional_v4_test.go index b5e6d128a5..92d89d42a9 100644 --- a/api_functional_v4_test.go +++ b/api_functional_v4_test.go @@ -2498,3 +2498,72 @@ func TestGetObjectObjectModified(t *testing.T) { t.Errorf("Expected ReadAt to fail with error %s but received %s", s3ErrorResponseMap["PreconditionFailed"], err.Error()) } } + +// Test validates putObject to upload a file seeked at a given offset. +func TestPutObjectUploadSeekedObject(t *testing.T) { + if testing.Short() { + t.Skip("skipping functional tests for the short runs") + } + + // Instantiate new minio client object. + c, err := NewV4( + os.Getenv("S3_ADDRESS"), + os.Getenv("ACCESS_KEY"), + os.Getenv("SECRET_KEY"), + mustParseBool(os.Getenv("S3_SECURE")), + ) + if err != nil { + t.Fatal("Error:", err) + } + + // Enable tracing, write to stderr. + // c.TraceOn(os.Stderr) + + // Set user agent. + c.SetAppInfo("Minio-go-FunctionalTest", "0.1.0") + + // Make a new bucket. + bucketName := randString(60, rand.NewSource(time.Now().UnixNano()), "minio-go-test") + err = c.MakeBucket(bucketName, "us-east-1") + if err != nil { + t.Fatal("Error:", err, bucketName) + } + defer c.RemoveBucket(bucketName) + + tempfile, err := ioutil.TempFile("", "minio-go-upload-test-") + if err != nil { + t.Fatal("Error:", err) + } + + if err = tempfile.Close(); err != nil { + t.Fatal("Error:", err) + } + + var length = 120000 + data := bytes.Repeat([]byte("1"), length) + + if err = ioutil.WriteFile(tempfile.Name(), data, 0600); err != nil { + t.Fatal("Error:", err) + } + + tempfile, err = os.Open(tempfile.Name()) + if err != nil { + t.Fatal("Error:", err) + } + + objectName := fmt.Sprintf("test-file-%v", rand.Uint32()) + + offset := 123 + if _, err := tempfile.Seek(int64(offset), io.SeekStart); err != nil { + t.Fatal("Error:", err) + } + + n, err := c.PutObject(bucketName, objectName, tempfile, "binary/octet-stream") + if n != int64(length-offset) { + t.Fatalf("Invalid length returned, want %v, got %v", int64(length-offset), n) + } + + if err = c.RemoveObject(bucketName, objectName); err != nil { + t.Fatal("Error:", err) + } +}