| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  |  * Minio Cloud Storage, (C) 2015-2016 Minio, Inc. | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * 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 fs | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2016-02-18 16:38:58 +08:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2016-01-27 13:55:50 +08:00
										 |  |  | 	"net/url" | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | 	"os" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-11 08:40:09 +08:00
										 |  |  | 	"github.com/minio/minio/pkg/probe" | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-18 16:38:58 +08:00
										 |  |  | // ListObjects - lists all objects for a given prefix, returns up to
 | 
					
						
							|  |  |  | // maxKeys number of objects per call.
 | 
					
						
							|  |  |  | func (fs Filesystem) ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsResult, *probe.Error) { | 
					
						
							|  |  |  | 	result := ListObjectsResult{} | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-18 16:38:58 +08:00
										 |  |  | 	// Input validation.
 | 
					
						
							|  |  |  | 	if !IsValidBucketName(bucket) { | 
					
						
							|  |  |  | 		return result, probe.NewError(BucketNameInvalid{Bucket: bucket}) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-18 16:38:58 +08:00
										 |  |  | 	bucket = fs.denormalizeBucket(bucket) | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-18 16:38:58 +08:00
										 |  |  | 	if status, err := IsDirExist(filepath.Join(fs.path, bucket)); !status { | 
					
						
							|  |  |  | 		if err == nil { | 
					
						
							|  |  |  | 			return result, probe.NewError(BucketNotFound{Bucket: bucket}) | 
					
						
							|  |  |  | 		} else if os.IsNotExist(err) { | 
					
						
							|  |  |  | 			return result, probe.NewError(BucketNotFound{Bucket: bucket}) | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2016-02-18 16:38:58 +08:00
										 |  |  | 			return result, probe.NewError(err) | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-02-18 16:38:58 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-18 16:38:58 +08:00
										 |  |  | 	if delimiter != "" && delimiter != "/" { | 
					
						
							|  |  |  | 		return result, probe.NewError(fmt.Errorf("delimiter '%s' is not supported", delimiter)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if marker != "" { | 
					
						
							|  |  |  | 		if markerUnescaped, err := url.QueryUnescape(marker); err == nil { | 
					
						
							|  |  |  | 			marker = markerUnescaped | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			return result, probe.NewError(err) | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-18 16:38:58 +08:00
										 |  |  | 		if !strings.HasPrefix(marker, prefix) { | 
					
						
							|  |  |  | 			return result, probe.NewError(fmt.Errorf("marker '%s' and prefix '%s' do not match", marker, prefix)) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-18 16:38:58 +08:00
										 |  |  | 	if maxKeys <= 0 || maxKeys > listObjectsLimit { | 
					
						
							|  |  |  | 		maxKeys = listObjectsLimit | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-18 16:38:58 +08:00
										 |  |  | 	bucketDir := filepath.Join(fs.path, bucket) | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-18 16:38:58 +08:00
										 |  |  | 	recursive := true | 
					
						
							|  |  |  | 	skipDir := true | 
					
						
							|  |  |  | 	if delimiter == "/" { | 
					
						
							|  |  |  | 		skipDir = false | 
					
						
							|  |  |  | 		recursive = false | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-18 16:38:58 +08:00
										 |  |  | 	prefixDir := filepath.Dir(filepath.FromSlash(prefix)) | 
					
						
							|  |  |  | 	rootDir := filepath.Join(bucketDir, prefixDir) | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-18 16:38:58 +08:00
										 |  |  | 	objectInfoCh := fs.popListObjectCh(ListObjectParams{bucket, delimiter, marker, prefix}) | 
					
						
							|  |  |  | 	if objectInfoCh == nil { | 
					
						
							|  |  |  | 		ch := treeWalk(rootDir, bucketDir, recursive) | 
					
						
							|  |  |  | 		objectInfoCh = &ch | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-18 16:38:58 +08:00
										 |  |  | 	nextMarker := "" | 
					
						
							|  |  |  | 	for i := 0; i < maxKeys; { | 
					
						
							|  |  |  | 		objInfo, ok := objectInfoCh.Read() | 
					
						
							|  |  |  | 		if !ok { | 
					
						
							|  |  |  | 			// closed channel
 | 
					
						
							|  |  |  | 			return result, nil | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-18 16:38:58 +08:00
										 |  |  | 		if objInfo.Err != nil { | 
					
						
							|  |  |  | 			return ListObjectsResult{}, probe.NewError(objInfo.Err) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-01-27 13:55:50 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-18 16:38:58 +08:00
										 |  |  | 		if strings.Contains(objInfo.Name, "$multiparts") || strings.Contains(objInfo.Name, "$tmpobject") { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-18 16:38:58 +08:00
										 |  |  | 		if objInfo.IsDir && skipDir { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-12 08:31:24 +08:00
										 |  |  | 		// Add the bucket.
 | 
					
						
							|  |  |  | 		objInfo.Bucket = bucket | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-18 16:38:58 +08:00
										 |  |  | 		if strings.HasPrefix(objInfo.Name, prefix) { | 
					
						
							|  |  |  | 			if objInfo.Name > marker { | 
					
						
							|  |  |  | 				if objInfo.IsDir { | 
					
						
							|  |  |  | 					result.Prefixes = append(result.Prefixes, objInfo.Name) | 
					
						
							|  |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2016-03-12 08:31:24 +08:00
										 |  |  | 					result.Objects = append(result.Objects, objInfo) | 
					
						
							| 
									
										
										
										
											2016-02-18 16:38:58 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				nextMarker = objInfo.Name | 
					
						
							|  |  |  | 				i++ | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-18 16:38:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if !objectInfoCh.IsClosed() { | 
					
						
							|  |  |  | 		result.IsTruncated = true | 
					
						
							|  |  |  | 		result.NextMarker = nextMarker | 
					
						
							|  |  |  | 		fs.pushListObjectCh(ListObjectParams{bucket, delimiter, nextMarker, prefix}, *objectInfoCh) | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-18 16:38:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return result, nil | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | } |