From ed4fe689b4eeb5b89cc3c20bee970c983b5bff91 Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Mon, 13 Jun 2016 15:23:09 +0530 Subject: [PATCH] posix: Support UNC paths on windows. (#1887) This allows us to now use 32K paths names on windows. Fixes #1620 --- config-migrate.go | 2 +- object-api-getobjectinfo_test.go | 3 +- object-api-listobjects_test.go | 2 +- object-api_test.go | 2 +- posix-list-dir-others.go | 8 +- posix-prepare-path.go | 56 +++++++++ posix-utils_common.go | 37 ++++++ posix-utils.go => posix-utils_nix.go | 61 ++++----- posix-utils_windows.go | 177 +++++++++++++++++++++++++++ posix.go | 65 +++++----- server_test.go | 31 ++++- server_xl_test.go | 14 ++- test-utils_test.go | 4 +- 13 files changed, 379 insertions(+), 83 deletions(-) create mode 100644 posix-prepare-path.go create mode 100644 posix-utils_common.go rename posix-utils.go => posix-utils_nix.go (55%) create mode 100644 posix-utils_windows.go diff --git a/config-migrate.go b/config-migrate.go index 9383ba5e2..e54dde104 100644 --- a/config-migrate.go +++ b/config-migrate.go @@ -49,7 +49,7 @@ func purgeV1() { fatalIf(err, "Unable to retrieve config path.") configFile := filepath.Join(configPath, "fsUsers.json") - os.RemoveAll(configFile) + removeAll(configFile) } fatalIf(errors.New(""), "Failed to migrate unrecognized config version ‘"+cv1.Version+"’.") } diff --git a/object-api-getobjectinfo_test.go b/object-api-getobjectinfo_test.go index 963523bed..5c9f06daa 100644 --- a/object-api-getobjectinfo_test.go +++ b/object-api-getobjectinfo_test.go @@ -21,7 +21,6 @@ import ( "crypto/md5" "encoding/hex" "io/ioutil" - "os" "strconv" "testing" ) @@ -116,7 +115,7 @@ func BenchmarkGetObjectFS(b *testing.B) { if err != nil { b.Fatal(err) } - defer os.RemoveAll(directory) + defer removeAll(directory) // Create the obj. obj, err := newFSObjects(directory) diff --git a/object-api-listobjects_test.go b/object-api-listobjects_test.go index b02d742bc..8bf0ba01f 100644 --- a/object-api-listobjects_test.go +++ b/object-api-listobjects_test.go @@ -577,7 +577,7 @@ func BenchmarkListObjects(b *testing.B) { if err != nil { b.Fatal(err) } - defer os.RemoveAll(directory) + defer removeAll(directory) // Create the obj. obj, err := newFSObjects(directory) diff --git a/object-api_test.go b/object-api_test.go index f6faf0ccf..61fc75c3d 100644 --- a/object-api_test.go +++ b/object-api_test.go @@ -69,6 +69,6 @@ func (s *MySuite) TestXLAPISuite(c *C) { func removeRootsC(c *C, roots []string) { for _, root := range roots { - os.RemoveAll(root) + removeAll(root) } } diff --git a/posix-list-dir-others.go b/posix-list-dir-others.go index 19efd0290..e9abcc3db 100644 --- a/posix-list-dir-others.go +++ b/posix-list-dir-others.go @@ -19,6 +19,7 @@ package main import ( + "fmt" "io" "os" "strings" @@ -26,10 +27,11 @@ import ( // Return all the entries at the directory dirPath. func readDir(dirPath string) (entries []string, err error) { - d, err := os.Open(dirPath) + d, err := os.Open(preparePath(dirPath)) if err != nil { // File is really not found. if os.IsNotExist(err) { + fmt.Println(preparePath(dirPath), err) return nil, errFileNotFound } @@ -50,12 +52,12 @@ func readDir(dirPath string) (entries []string, err error) { return nil, err } for _, fi := range fis { - // Skip special files. + // Skip special files, if found. if hasPosixReservedPrefix(fi.Name()) { continue } if fi.Mode().IsDir() { - // append "/" instead of "\" so that sorting is done as expected. + // Append "/" instead of "\" so that sorting is achieved as expected. entries = append(entries, fi.Name()+slashSeparator) } else if fi.Mode().IsRegular() { entries = append(entries, fi.Name()) diff --git a/posix-prepare-path.go b/posix-prepare-path.go new file mode 100644 index 000000000..9925217b8 --- /dev/null +++ b/posix-prepare-path.go @@ -0,0 +1,56 @@ +/* + * 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 ( + "path/filepath" + "runtime" + "strings" +) + +// preparePath rewrites path to handle any OS specific details. +func preparePath(path string) string { + if runtime.GOOS == "windows" { + // Microsoft Windows supports long path names using + // uniform naming convention (UNC). + return UNCPath(path) + } + return path +} + +// UNCPath converts a absolute windows path to a UNC long path. +func UNCPath(path string) string { + // Clean the path for any trailing "/". + path = filepath.Clean(path) + + // UNC can NOT use "/", so convert all to "\". + path = filepath.FromSlash(path) + + // If prefix is "\\", we already have a UNC path or server. + if strings.HasPrefix(path, `\\`) { + + // If already long path, just keep it + if strings.HasPrefix(path, `\\?\`) { + return path + } + + // Trim "\\" from path and add UNC prefix. + return `\\?\UNC\` + strings.TrimPrefix(path, `\\`) + } + path = `\\?\` + path + return path +} diff --git a/posix-utils_common.go b/posix-utils_common.go new file mode 100644 index 000000000..e846d5cb3 --- /dev/null +++ b/posix-utils_common.go @@ -0,0 +1,37 @@ +/* + * 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 "strings" + +// List of reserved words for files, includes old and new ones. +var posixReservedPrefix = []string{ + "$tmpfile", + // Add new reserved words if any used in future. +} + +// hasPosixReservedPrefix - has reserved prefix. +func hasPosixReservedPrefix(name string) (isReserved bool) { + for _, reservedKey := range posixReservedPrefix { + if strings.HasPrefix(name, reservedKey) { + isReserved = true + break + } + isReserved = false + } + return isReserved +} diff --git a/posix-utils.go b/posix-utils_nix.go similarity index 55% rename from posix-utils.go rename to posix-utils_nix.go index 493eae578..011af11e3 100644 --- a/posix-utils.go +++ b/posix-utils_nix.go @@ -1,3 +1,5 @@ +// +build linux darwin dragonfly freebsd netbsd openbsd + /* * Minio Cloud Storage, (C) 2016 Minio, Inc. * @@ -17,33 +19,15 @@ package main import ( - "runtime" + "os" "strings" "unicode/utf8" ) -// isValidVolname verifies a volname name in accordance with object -// layer requirements. -func isValidVolname(volname string) bool { - if len(volname) < 3 || len(volname) > 63 { - return false - } - switch runtime.GOOS { - case "windows": - // Volname shouldn't have reserved characters on windows in it. - return !strings.ContainsAny(volname, "/\\:*?\"<>|") - default: - // Volname shouldn't have '/' in it. - return !strings.ContainsAny(volname, "/") - } -} - -// Keeping this as lower bound value supporting Linux, Darwin and Windows operating systems. -const pathMax = 4096 +const pathMax = 4096 // 4k limit on all unixes. // isValidPath verifies if a path name is in accordance with FS limitations. func isValidPath(path string) bool { - // TODO: Make this FSType or Operating system specific. if len(path) > pathMax || len(path) == 0 { return false } @@ -53,20 +37,29 @@ func isValidPath(path string) bool { return true } -// List of reserved words for files, includes old and new ones. -var posixReservedPrefix = []string{ - "$tmpfile", - // Add new reserved words if any used in future. +// isValidVolname verifies a volname name in accordance with object +// layer requirements. +func isValidVolname(volname string) bool { + if len(volname) < 3 || len(volname) > 63 { + return false + } + // Volname shouldn't have '/' in it. + return !strings.ContainsAny(volname, "/") } -// hasPosixReservedPrefix - has reserved prefix. -func hasPosixReservedPrefix(name string) (isReserved bool) { - for _, reservedKey := range posixReservedPrefix { - if strings.HasPrefix(name, reservedKey) { - isReserved = true - break - } - isReserved = false - } - return isReserved +// mkdirAll creates a directory named path, +// along with any necessary parents, and returns nil, +// or else returns an error. The permission bits perm are used +// for all directories that mkdirAll creates. If path is already +// a directory, mkdirAll does nothing and returns nil. +func mkdirAll(path string, perm os.FileMode) error { + return os.MkdirAll(path, perm) +} + +// removeAll removes path and any children it contains. +// It removes everything it can but returns the first error +// it encounters. If the path does not exist, RemoveAll +// returns nil (no error). +func removeAll(path string) error { + return os.RemoveAll(path) } diff --git a/posix-utils_windows.go b/posix-utils_windows.go new file mode 100644 index 000000000..fc43d2743 --- /dev/null +++ b/posix-utils_windows.go @@ -0,0 +1,177 @@ +// +build windows + +/* + * 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 ( + "io" + "os" + "path/filepath" + "strings" + "syscall" + "unicode/utf8" +) + +const pathMax = 32 * 1024 // 32K is the maximum limit for UNC paths. + +// isValidPath verifies if a path name is in accordance with FS limitations. +func isValidPath(path string) bool { + if len(path) > pathMax || len(path) == 0 { + return false + } + if !utf8.ValidString(path) { + return false + } + return true +} + +// isValidVolname verifies a volname name in accordance with object +// layer requirements. +func isValidVolname(volname string) bool { + if len(volname) < 3 || len(volname) > 63 { + return false + } + // Volname shouldn't have reserved characters on windows in it. + return !strings.ContainsAny(volname, "/\\:*?\"<>|") +} + +// mkdirAll creates a directory named path, +// along with any necessary parents, and returns nil, +// or else returns an error. The permission bits perm are used +// for all directories that mkdirAll creates. If path is already +// a directory, mkdirAll does nothing and returns nil. +func mkdirAll(path string, perm os.FileMode) error { + // Fast path: if we can tell whether path is a directory or file, stop with success or error. + dir, err := os.Stat(preparePath(path)) + if err == nil { + if dir.IsDir() { + return nil + } + return &os.PathError{ + Op: "mkdir", + Path: path, + Err: syscall.ENOTDIR, + } + } + + // Slow path: make sure parent exists and then call Mkdir for path. + i := len(path) + for i > 0 && os.IsPathSeparator(path[i-1]) { // Skip trailing path separator. + i-- + } + + j := i + for j > 0 && !os.IsPathSeparator(path[j-1]) { // Scan backward over element. + j-- + } + + if j > 1 { + // Create parent + parent := path[0 : j-1] + if parent != filepath.VolumeName(parent) { + err = mkdirAll(parent, perm) + if err != nil { + return err + } + } + } + + // Parent now exists; invoke Mkdir and use its result. + err = os.Mkdir(preparePath(path), perm) + if err != nil { + // Handle arguments like "foo/." by + // double-checking that directory doesn't exist. + dir, err1 := os.Lstat(preparePath(path)) + if err1 == nil && dir.IsDir() { + return nil + } + return err + } + return nil +} + +// removeAll removes path and any children it contains. +// It removes everything it can but returns the first error +// it encounters. If the path does not exist, RemoveAll +// returns nil (no error). +func removeAll(path string) error { + // Simple case: if Remove works, we're done. + err := os.Remove(preparePath(path)) + if err == nil || os.IsNotExist(err) { + return nil + } + + // Otherwise, is this a directory we need to recurse into? + dir, serr := os.Lstat(preparePath(path)) + if serr != nil { + if serr, ok := serr.(*os.PathError); ok && (os.IsNotExist(serr.Err) || serr.Err == syscall.ENOTDIR) { + return nil + } + return serr + } + if !dir.IsDir() { + // Not a directory; return the error from Remove. + return err + } + + // Directory. + fd, err := os.Open(preparePath(path)) + if err != nil { + if os.IsNotExist(err) { + // Race. It was deleted between the Lstat and Open. + // Return nil per RemoveAll's docs. + return nil + } + return err + } + + // Remove contents & return first error. + err = nil + for { + names, err1 := fd.Readdirnames(4096) // Get 4k entries. + for _, name := range names { + err1 = removeAll(path + string(os.PathSeparator) + name) + if err == nil { + err = err1 + } + } + if err1 == io.EOF { + break + } + // If Readdirnames returned an error, use it. + if err == nil { + err = err1 + } + if len(names) == 0 { + break + } + } + + // Close directory, because windows won't remove opened directory. + fd.Close() + + // Remove directory. + err1 := os.Remove(preparePath(path)) + if err1 == nil || os.IsNotExist(err1) { + return nil + } + if err == nil { + err = err1 + } + return err +} diff --git a/posix.go b/posix.go index 17a967ef7..682f00812 100644 --- a/posix.go +++ b/posix.go @@ -23,7 +23,6 @@ import ( "os" slashpath "path" "path/filepath" - "runtime" "strings" "syscall" @@ -46,16 +45,7 @@ var errFaultyDisk = errors.New("Faulty disk") // checkPathLength - returns error if given path name length more than 255 func checkPathLength(pathName string) error { - // For MS Windows, the maximum path length is 255 - if runtime.GOOS == "windows" { - if len(pathName) > 255 { - return errFileNameTooLong - } - - return nil - } - - // For non-windows system, check each path segment length is > 255 + // Check each path segment length is > 255 for len(pathName) > 0 && pathName != "." && pathName != "/" { dir, file := slashpath.Dir(pathName), slashpath.Base(pathName) @@ -64,8 +54,7 @@ func checkPathLength(pathName string) error { } pathName = dir - } - + } // Success. return nil } @@ -96,11 +85,17 @@ func newPosix(diskPath string) (StorageAPI, error) { if diskPath == "" { return nil, errInvalidArgument } + var err error + // Disallow relative paths, figure out absolute paths. + diskPath, err = filepath.Abs(diskPath) + if err != nil { + return nil, err + } fs := posix{ diskPath: diskPath, minFreeDisk: fsMinSpacePercent, // Minimum 5% disk should be free. } - st, err := os.Stat(diskPath) + st, err := os.Stat(preparePath(diskPath)) if err != nil { if os.IsNotExist(err) { return fs, errDiskNotFound @@ -153,7 +148,7 @@ func listVols(dirPath string) ([]VolInfo, error) { continue } var fi os.FileInfo - fi, err = os.Stat(pathJoin(dirPath, entry)) + fi, err = os.Stat(preparePath(pathJoin(dirPath, entry))) if err != nil { // If the file does not exist, skip the entry. if os.IsNotExist(err) { @@ -208,7 +203,7 @@ func (s posix) MakeVol(volume string) (err error) { return err } // Make a volume entry. - err = os.Mkdir(volumeDir, 0700) + err = os.Mkdir(preparePath(volumeDir), 0700) if err != nil && os.IsExist(err) { return errVolumeExists } @@ -266,7 +261,7 @@ func (s posix) StatVol(volume string) (volInfo VolInfo, err error) { } // Stat a volume entry. var st os.FileInfo - st, err = os.Stat(volumeDir) + st, err = os.Stat(preparePath(volumeDir)) if err != nil { if os.IsNotExist(err) { return VolInfo{}, errVolumeNotFound @@ -304,7 +299,7 @@ func (s posix) DeleteVol(volume string) (err error) { if err != nil { return err } - err = os.Remove(volumeDir) + err = os.Remove(preparePath(volumeDir)) if err != nil { if os.IsNotExist(err) { return errVolumeNotFound @@ -345,7 +340,7 @@ func (s posix) ListDir(volume, dirPath string) (entries []string, err error) { return nil, err } // Stat a volume entry. - _, err = os.Stat(volumeDir) + _, err = os.Stat(preparePath(volumeDir)) if err != nil { if os.IsNotExist(err) { return nil, errVolumeNotFound @@ -381,7 +376,7 @@ func (s posix) ReadFile(volume string, path string, offset int64, buf []byte) (n return 0, err } // Stat a volume entry. - _, err = os.Stat(volumeDir) + _, err = os.Stat(preparePath(volumeDir)) if err != nil { if os.IsNotExist(err) { return 0, errVolumeNotFound @@ -393,7 +388,7 @@ func (s posix) ReadFile(volume string, path string, offset int64, buf []byte) (n if err = checkPathLength(filePath); err != nil { return 0, err } - file, err := os.Open(filePath) + file, err := os.Open(preparePath(filePath)) if err != nil { if os.IsNotExist(err) { return 0, errFileNotFound @@ -456,7 +451,7 @@ func (s posix) AppendFile(volume, path string, buf []byte) (n int64, err error) return 0, err } // Stat a volume entry. - _, err = os.Stat(volumeDir) + _, err = os.Stat(preparePath(volumeDir)) if err != nil { if os.IsNotExist(err) { return 0, errVolumeNotFound @@ -472,16 +467,16 @@ func (s posix) AppendFile(volume, path string, buf []byte) (n int64, err error) } // Verify if the file already exists and is not of regular type. var st os.FileInfo - if st, err = os.Stat(filePath); err == nil { + if st, err = os.Stat(preparePath(filePath)); err == nil { if st.IsDir() { return 0, errIsNotRegular } } // Create top level directories if they don't exist. - if err = os.MkdirAll(filepath.Dir(filePath), 0700); err != nil { + if err = mkdirAll(filepath.Dir(filePath), 0700); err != nil { return 0, err } - w, err := os.OpenFile(filePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600) + w, err := os.OpenFile(preparePath(filePath), os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600) if err != nil { // File path cannot be verified since one of the parents is a file. if strings.Contains(err.Error(), "not a directory") { @@ -518,7 +513,7 @@ func (s posix) StatFile(volume, path string) (file FileInfo, err error) { return FileInfo{}, err } // Stat a volume entry. - _, err = os.Stat(volumeDir) + _, err = os.Stat(preparePath(volumeDir)) if err != nil { if os.IsNotExist(err) { return FileInfo{}, errVolumeNotFound @@ -530,7 +525,7 @@ func (s posix) StatFile(volume, path string) (file FileInfo, err error) { if err = checkPathLength(filePath); err != nil { return FileInfo{}, err } - st, err := os.Stat(filePath) + st, err := os.Stat(preparePath(filePath)) if err != nil { // File is really not found. if os.IsNotExist(err) { @@ -564,7 +559,7 @@ func deleteFile(basePath, deletePath string) error { return nil } // Verify if the path exists. - pathSt, err := os.Stat(deletePath) + pathSt, err := os.Stat(preparePath(deletePath)) if err != nil { if os.IsNotExist(err) { return errFileNotFound @@ -578,7 +573,7 @@ func deleteFile(basePath, deletePath string) error { return nil } // Attempt to remove path. - if err := os.Remove(deletePath); err != nil { + if err := os.Remove(preparePath(deletePath)); err != nil { return err } // Recursively go down the next path and delete again. @@ -610,7 +605,7 @@ func (s posix) DeleteFile(volume, path string) (err error) { return err } // Stat a volume entry. - _, err = os.Stat(volumeDir) + _, err = os.Stat(preparePath(volumeDir)) if err != nil { if os.IsNotExist(err) { return errVolumeNotFound @@ -655,14 +650,14 @@ func (s posix) RenameFile(srcVolume, srcPath, dstVolume, dstPath string) (err er return err } // Stat a volume entry. - _, err = os.Stat(srcVolumeDir) + _, err = os.Stat(preparePath(srcVolumeDir)) if err != nil { if os.IsNotExist(err) { return errVolumeNotFound } return err } - _, err = os.Stat(dstVolumeDir) + _, err = os.Stat(preparePath(dstVolumeDir)) if err != nil { if os.IsNotExist(err) { return errVolumeNotFound @@ -677,7 +672,7 @@ func (s posix) RenameFile(srcVolume, srcPath, dstVolume, dstPath string) (err er } if srcIsDir { // If source is a directory we expect the destination to be non-existent always. - _, err = os.Stat(slashpath.Join(dstVolumeDir, dstPath)) + _, err = os.Stat(preparePath(slashpath.Join(dstVolumeDir, dstPath))) if err == nil { return errFileAccessDenied } @@ -686,14 +681,14 @@ func (s posix) RenameFile(srcVolume, srcPath, dstVolume, dstPath string) (err er } // Destination does not exist, hence proceed with the rename. } - if err = os.MkdirAll(slashpath.Dir(slashpath.Join(dstVolumeDir, dstPath)), 0755); err != nil { + if err = mkdirAll(preparePath(slashpath.Dir(slashpath.Join(dstVolumeDir, dstPath))), 0755); err != nil { // File path cannot be verified since one of the parents is a file. if strings.Contains(err.Error(), "not a directory") { return errFileAccessDenied } return err } - err = os.Rename(slashpath.Join(srcVolumeDir, srcPath), slashpath.Join(dstVolumeDir, dstPath)) + err = os.Rename(preparePath(slashpath.Join(srcVolumeDir, srcPath)), preparePath(slashpath.Join(dstVolumeDir, dstPath))) if err != nil { if os.IsNotExist(err) { return errFileNotFound diff --git a/server_test.go b/server_test.go index dbfc8ad46..2b8d7d228 100644 --- a/server_test.go +++ b/server_test.go @@ -19,6 +19,7 @@ package main import ( "bytes" "crypto/md5" + "fmt" "io" "io/ioutil" "os" @@ -86,7 +87,7 @@ func (s *MyAPISuite) SetUpSuite(c *C) { } func (s *MyAPISuite) TearDownSuite(c *C) { - os.RemoveAll(s.root) + removeAll(s.root) testAPIFSCacheServer.Close() } @@ -686,6 +687,34 @@ func (s *MyAPISuite) TestListBuckets(c *C) { c.Assert(err, IsNil) } +// Tests put object with long names. +func (s *MyAPISuite) TestPutObjectLongName(c *C) { + request, err := s.newRequest("PUT", testAPIFSCacheServer.URL+"/put-object-long-name", 0, nil) + c.Assert(err, IsNil) + + client := http.Client{} + response, err := client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + buffer := bytes.NewReader([]byte("hello world")) + longObjName := fmt.Sprintf("%0255d/%0255d/%0255d", 1, 1, 1) + request, err = s.newRequest("PUT", testAPIFSCacheServer.URL+"/put-object-long-name/"+longObjName, int64(buffer.Len()), buffer) + c.Assert(err, IsNil) + + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + longObjName = fmt.Sprintf("%0256d", 1) + request, err = s.newRequest("PUT", testAPIFSCacheServer.URL+"/put-object-long-name/"+longObjName, int64(buffer.Len()), buffer) + c.Assert(err, IsNil) + + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusNotFound) +} + func (s *MyAPISuite) TestNotBeAbleToCreateObjectInNonexistentBucket(c *C) { buffer1 := bytes.NewReader([]byte("hello world")) request, err := s.newRequest("PUT", testAPIFSCacheServer.URL+"/innonexistentbucket/object", int64(buffer1.Len()), buffer1) diff --git a/server_xl_test.go b/server_xl_test.go index 69cf96d75..276cf3268 100644 --- a/server_xl_test.go +++ b/server_xl_test.go @@ -94,9 +94,9 @@ func (s *MyAPIXLSuite) SetUpSuite(c *C) { } func (s *MyAPIXLSuite) TearDownSuite(c *C) { - os.RemoveAll(s.root) + removeAll(s.root) for _, disk := range s.erasureDisks { - os.RemoveAll(disk) + removeAll(disk) } testAPIXLServer.Close() } @@ -706,7 +706,15 @@ func (s *MyAPIXLSuite) TestPutObjectLongName(c *C) { c.Assert(response.StatusCode, Equals, http.StatusOK) buffer := bytes.NewReader([]byte("hello world")) - longObjName := fmt.Sprintf("%0256d", 1) + longObjName := fmt.Sprintf("%0255d/%0255d/%0255d", 1, 1, 1) + request, err = s.newRequest("PUT", testAPIXLServer.URL+"/put-object-long-name/"+longObjName, int64(buffer.Len()), buffer) + c.Assert(err, IsNil) + + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusOK) + + longObjName = fmt.Sprintf("%0256d", 1) request, err = s.newRequest("PUT", testAPIXLServer.URL+"/put-object-long-name/"+longObjName, int64(buffer.Len()), buffer) c.Assert(err, IsNil) diff --git a/test-utils_test.go b/test-utils_test.go index 9b15dfb13..4a5ae781f 100644 --- a/test-utils_test.go +++ b/test-utils_test.go @@ -73,7 +73,7 @@ func getSingleNodeObjectLayer() (ObjectLayer, string, error) { // removeRoots - Cleans up initialized directories during tests. func removeRoots(roots []string) { for _, root := range roots { - os.RemoveAll(root) + removeAll(root) } } @@ -81,7 +81,7 @@ func removeRoots(roots []string) { func removeRandomDisk(disks []string, removeCount int) { ints := randInts(len(disks)) for _, i := range ints[:removeCount] { - os.RemoveAll(disks[i-1]) + removeAll(disks[i-1]) } }