| 
									
										
										
										
											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 ( | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 	"hash/fnv" | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | 	"os" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/minio/minio-xl/pkg/probe" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-27 03:48:52 +08:00
										 |  |  | // listObjectsParams - list objects input parameters.
 | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | type listObjectsParams struct { | 
					
						
							| 
									
										
										
										
											2016-01-27 03:48:52 +08:00
										 |  |  | 	// Bucket name to list the objects for.
 | 
					
						
							|  |  |  | 	Bucket string | 
					
						
							|  |  |  | 	// list all objects with this parameter as common prefix.
 | 
					
						
							|  |  |  | 	Prefix string | 
					
						
							|  |  |  | 	// list all objects starting with object after marker in
 | 
					
						
							|  |  |  | 	// lexicographical order.
 | 
					
						
							|  |  |  | 	Marker string | 
					
						
							|  |  |  | 	// list all objects until the first occurrence of the delimtier
 | 
					
						
							|  |  |  | 	// after the prefix.
 | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 	Delimiter string | 
					
						
							| 
									
										
										
										
											2016-01-27 03:48:52 +08:00
										 |  |  | 	// maximum number of objects returned per listObjects()
 | 
					
						
							|  |  |  | 	// operation.
 | 
					
						
							|  |  |  | 	MaxKeys int | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-27 03:48:52 +08:00
										 |  |  | // listServiceReq
 | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | type listServiceReq struct { | 
					
						
							|  |  |  | 	reqParams listObjectsParams | 
					
						
							|  |  |  | 	respCh    chan ListObjectsResult | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type listWorkerReq struct { | 
					
						
							|  |  |  | 	respCh chan ListObjectsResult | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-27 03:48:52 +08:00
										 |  |  | // listObjects - list objects lists objects upto maxKeys for a given prefix.
 | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | func (fs Filesystem) listObjects(bucket, prefix, marker, delimiter string, maxKeys int) (chan<- listWorkerReq, *probe.Error) { | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 	quitWalker := make(chan bool) | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 	reqCh := make(chan listWorkerReq) | 
					
						
							|  |  |  | 	walkerCh := make(chan ObjectMetadata) | 
					
						
							|  |  |  | 	go func() { | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 		defer close(walkerCh) | 
					
						
							|  |  |  | 		var walkPath string | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 		bucketPath := filepath.Join(fs.path, bucket) | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 		// Bucket path prefix should always end with a separator.
 | 
					
						
							|  |  |  | 		bucketPathPrefix := bucketPath + string(os.PathSeparator) | 
					
						
							|  |  |  | 		prefixPath := bucketPathPrefix + prefix | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 		st, err := os.Stat(prefixPath) | 
					
						
							|  |  |  | 		if err != nil && os.IsNotExist(err) { | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 			walkPath = bucketPath | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			if st.IsDir() && !strings.HasSuffix(prefix, delimiter) { | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 				walkPath = bucketPath | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 				walkPath = prefixPath | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-01-27 03:48:52 +08:00
										 |  |  | 		Walk(walkPath, func(path string, info os.FileInfo, err error) error { | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 			// We don't need to list the walk path.
 | 
					
						
							|  |  |  | 			if path == walkPath { | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | 				return nil | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 			// For all incoming directories add a ending separator.
 | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 			if info.IsDir() { | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 				path = path + string(os.PathSeparator) | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 			// Extract object name.
 | 
					
						
							|  |  |  | 			objectName := strings.TrimPrefix(path, bucketPathPrefix) | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 			if strings.HasPrefix(objectName, prefix) { | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 				// For objectName lesser than marker, ignore.
 | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 				if marker >= objectName { | 
					
						
							|  |  |  | 					return nil | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				object := ObjectMetadata{ | 
					
						
							|  |  |  | 					Object:  objectName, | 
					
						
							|  |  |  | 					Created: info.ModTime(), | 
					
						
							|  |  |  | 					Mode:    info.Mode(), | 
					
						
							|  |  |  | 					Size:    info.Size(), | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				select { | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 				// Send object on walker channel.
 | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 				case walkerCh <- object: | 
					
						
							|  |  |  | 				case <-quitWalker: | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 					// Returning error ends the file tree Walk().
 | 
					
						
							|  |  |  | 					return errors.New("Quit list worker.") | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 				// If delimiter is set, we stop if current path is a
 | 
					
						
							|  |  |  | 				// directory.
 | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 				if delimiter != "" && info.IsDir() { | 
					
						
							| 
									
										
										
										
											2016-01-27 03:48:52 +08:00
										 |  |  | 					return ErrSkipDir | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 			return nil | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	}() | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 	go func() { | 
					
						
							|  |  |  | 		for { | 
					
						
							|  |  |  | 			select { | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 			// Timeout after 10 seconds if request did not arrive for
 | 
					
						
							|  |  |  | 			// the given list parameters.
 | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 			case <-time.After(10 * time.Second): | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 				quitWalker <- true // Quit file path walk if running.
 | 
					
						
							|  |  |  | 				// Send back the hash for this request.
 | 
					
						
							|  |  |  | 				fs.timeoutReqCh <- fnvSum(bucket, prefix, marker, delimiter) | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 				return | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 			case req, ok := <-reqCh: | 
					
						
							|  |  |  | 				if !ok { | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 					// If the request channel is closed, no more
 | 
					
						
							|  |  |  | 					// requests return here.
 | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 				resp := ListObjectsResult{} | 
					
						
							|  |  |  | 				var count int | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 				for object := range walkerCh { | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 					if count == maxKeys { | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 						resp.IsTruncated = true | 
					
						
							|  |  |  | 						break | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 					// If object is a directory.
 | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 					if object.Mode.IsDir() { | 
					
						
							|  |  |  | 						if delimiter == "" { | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 							// Skip directories for recursive listing.
 | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 							continue | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | 						} | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 						resp.Prefixes = append(resp.Prefixes, object.Object) | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | 					} else { | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 						resp.Objects = append(resp.Objects, object) | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 					// Set the next marker for the next request.
 | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 					resp.NextMarker = object.Object | 
					
						
							|  |  |  | 					count++ | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 				req.respCh <- resp | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 	return reqCh, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | // fnvSum calculates a hash for concatenation of all input strings.
 | 
					
						
							|  |  |  | func fnvSum(elements ...string) uint32 { | 
					
						
							|  |  |  | 	fnvHash := fnv.New32a() | 
					
						
							|  |  |  | 	for _, element := range elements { | 
					
						
							|  |  |  | 		fnvHash.Write([]byte(element)) | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 	return fnvHash.Sum32() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // listObjectsService - list objects service manages various incoming
 | 
					
						
							|  |  |  | // list object requests by delegating them to an existing listObjects
 | 
					
						
							|  |  |  | // routine or initializes a new listObjects routine.
 | 
					
						
							|  |  |  | func (fs *Filesystem) listObjectsService() *probe.Error { | 
					
						
							|  |  |  | 	// Initialize list service request channel.
 | 
					
						
							|  |  |  | 	listServiceReqCh := make(chan listServiceReq) | 
					
						
							|  |  |  | 	fs.listServiceReqCh = listServiceReqCh | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Initialize timeout request channel to receive request hashes of
 | 
					
						
							|  |  |  | 	// timed-out requests.
 | 
					
						
							|  |  |  | 	timeoutReqCh := make(chan uint32) | 
					
						
							|  |  |  | 	fs.timeoutReqCh = timeoutReqCh | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Initialize request hash to list worker map.
 | 
					
						
							|  |  |  | 	reqToListWorkerReqCh := make(map[uint32]chan<- listWorkerReq) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Start service in a go routine.
 | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 	go func() { | 
					
						
							|  |  |  | 		for { | 
					
						
							|  |  |  | 			select { | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 			case reqHash := <-timeoutReqCh: | 
					
						
							|  |  |  | 				// For requests which have timed-out, close the worker
 | 
					
						
							|  |  |  | 				// channels proactively, this may happen for idle
 | 
					
						
							|  |  |  | 				// workers once in 10seconds.
 | 
					
						
							|  |  |  | 				listWorkerReqCh, ok := reqToListWorkerReqCh[reqHash] | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 				if ok { | 
					
						
							|  |  |  | 					close(listWorkerReqCh) | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 				delete(reqToListWorkerReqCh, reqHash) | 
					
						
							|  |  |  | 			case srvReq := <-listServiceReqCh: | 
					
						
							|  |  |  | 				// Save the params for readability.
 | 
					
						
							|  |  |  | 				bucket := srvReq.reqParams.Bucket | 
					
						
							|  |  |  | 				prefix := srvReq.reqParams.Prefix | 
					
						
							|  |  |  | 				marker := srvReq.reqParams.Marker | 
					
						
							|  |  |  | 				delimiter := srvReq.reqParams.Delimiter | 
					
						
							|  |  |  | 				maxKeys := srvReq.reqParams.MaxKeys | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// Generate hash.
 | 
					
						
							|  |  |  | 				reqHash := fnvSum(bucket, prefix, marker, delimiter) | 
					
						
							|  |  |  | 				listWorkerReqCh, ok := reqToListWorkerReqCh[reqHash] | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 				if !ok { | 
					
						
							|  |  |  | 					var err *probe.Error | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 					listWorkerReqCh, err = fs.listObjects(bucket, prefix, marker, delimiter, maxKeys) | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 					if err != nil { | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 						srvReq.respCh <- ListObjectsResult{} | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 						return | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 					reqToListWorkerReqCh[reqHash] = listWorkerReqCh | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 				respCh := make(chan ListObjectsResult) | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 				listWorkerReqCh <- listWorkerReq{respCh} | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 				resp, ok := <-respCh | 
					
						
							|  |  |  | 				if !ok { | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 					srvReq.respCh <- ListObjectsResult{} | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 				delete(reqToListWorkerReqCh, reqHash) | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 				if !resp.IsTruncated { | 
					
						
							|  |  |  | 					close(listWorkerReqCh) | 
					
						
							|  |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 					nextMarker := resp.NextMarker | 
					
						
							|  |  |  | 					reqHash = fnvSum(bucket, prefix, nextMarker, delimiter) | 
					
						
							|  |  |  | 					reqToListWorkerReqCh[reqHash] = listWorkerReqCh | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 				srvReq.respCh <- resp | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 	}() | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | // ListObjects - lists all objects for a given prefix, returns upto
 | 
					
						
							|  |  |  | // maxKeys number of objects per call.
 | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | func (fs Filesystem) ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsResult, *probe.Error) { | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 	fs.lock.Lock() | 
					
						
							|  |  |  | 	defer fs.lock.Unlock() | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 	if !IsValidBucketName(bucket) { | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 		return ListObjectsResult{}, probe.NewError(BucketNameInvalid{Bucket: bucket}) | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bucket = fs.denormalizeBucket(bucket) | 
					
						
							|  |  |  | 	rootPrefix := filepath.Join(fs.path, bucket) | 
					
						
							|  |  |  | 	// check bucket exists
 | 
					
						
							|  |  |  | 	if _, e := os.Stat(rootPrefix); e != nil { | 
					
						
							|  |  |  | 		if os.IsNotExist(e) { | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 			return ListObjectsResult{}, probe.NewError(BucketNotFound{Bucket: bucket}) | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 		return ListObjectsResult{}, probe.NewError(e) | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 	reqParams := listObjectsParams{} | 
					
						
							|  |  |  | 	reqParams.Bucket = bucket | 
					
						
							|  |  |  | 	reqParams.Prefix = filepath.FromSlash(prefix) | 
					
						
							|  |  |  | 	reqParams.Marker = filepath.FromSlash(marker) | 
					
						
							|  |  |  | 	reqParams.Delimiter = filepath.FromSlash(delimiter) | 
					
						
							|  |  |  | 	reqParams.MaxKeys = maxKeys | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 	respCh := make(chan ListObjectsResult) | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 	fs.listServiceReqCh <- listServiceReq{reqParams, respCh} | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 	resp := <-respCh | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 	for i := range resp.Prefixes { | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 		resp.Prefixes[i] = filepath.ToSlash(resp.Prefixes[i]) | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 	for i := range resp.Objects { | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 		resp.Objects[i].Object = filepath.ToSlash(resp.Objects[i].Object) | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-01-26 18:19:55 +08:00
										 |  |  | 	if reqParams.Delimiter == "" { | 
					
						
							| 
									
										
										
										
											2016-01-20 09:49:48 +08:00
										 |  |  | 		// This element is set only if you have delimiter set.
 | 
					
						
							|  |  |  | 		// If response does not include the NextMaker and it is
 | 
					
						
							|  |  |  | 		// truncated, you can use the value of the last Key in the
 | 
					
						
							|  |  |  | 		// response as the marker in the subsequent request to get the
 | 
					
						
							|  |  |  | 		// next set of object keys.
 | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 		resp.NextMarker = "" | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-11-10 19:10:11 +08:00
										 |  |  | 	return resp, nil | 
					
						
							| 
									
										
										
										
											2015-10-23 06:37:45 +08:00
										 |  |  | } |