Skip to content

Commit

Permalink
api: getReaderSize() should honor seeked file descriptors.
Browse files Browse the repository at this point in the history
In situations where a file has been Seeked, we need to
start reading from the offset which it indeed happens.
But our reader size calculation needs to honor this to
be accurate.

Fixes #680
  • Loading branch information
harshavardhana authored and minio-trusted committed May 14, 2017
1 parent 5d7ee33 commit b8b7560
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 2 deletions.
14 changes: 12 additions & 2 deletions api-put-object.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
69 changes: 69 additions & 0 deletions api_functional_v4_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

0 comments on commit b8b7560

Please sign in to comment.