2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								package  repo 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								import  ( 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-09 15:35:13 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"encoding/hex" 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									"encoding/json" 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-21 13:43:51 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"errors" 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									"fmt" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									"io" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									"log" 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-24 22:53:45 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"math/rand" 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									"net/http" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									"os" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									"path/filepath" 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"regexp" 
							 
						 
					
						
							
								
									
										
										
										
											2021-07-16 21:47:35 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"runtime" 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-24 22:53:45 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"strconv" 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									"strings" 
							 
						 
					
						
							
								
									
										
										
										
											2022-12-02 21:08:15 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"sync" 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-21 13:43:51 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"syscall" 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									"time" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-08-27 18:00:50 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"github.com/minio/sha256-simd" 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									"github.com/miolini/datacounter" 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-04 01:28:13 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									"github.com/restic/rest-server/quota" 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// Options are options for the Handler accepted by New 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								type  Options  struct  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-09 15:40:50 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									AppendOnly      bool  // if set, delete actions are not allowed 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									Debug           bool 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									NoVerifyUpload  bool 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-31 21:39:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									// If set, we will panic when an internal server error happens. This 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// makes it easier to debug such errors. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									PanicOnError  bool 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									BlobMetricFunc  BlobMetricFunc 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-04 01:28:13 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									QuotaManager    * quota . Manager 
							 
						 
					
						
							
								
									
										
										
										
											2023-05-13 21:50:39 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									FsyncWarning    * sync . Once 
							 
						 
					
						
							
								
									
										
										
										
											2025-02-17 22:17:54 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// If set makes files group accessible 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									GroupAccessible  bool 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// Defaults dir and file mode 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									dirMode   os . FileMode 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									fileMode  os . FileMode 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// DefaultDirMode is the file mode used for directory creation if not 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// overridden in the Options 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								const  DefaultDirMode  os . FileMode  =  0700 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// DefaultFileMode is the file mode used for file creation if not 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// overridden in the Options 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								const  DefaultFileMode  os . FileMode  =  0600 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-02-17 22:17:54 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// GroupAccessibleDirMode is the file mode used for directory creation when 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// group access is enabled 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								const  GroupAccessibleDirMode  os . FileMode  =  0770 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// GroupAccessibleFileMode is the file mode used for file creation when 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// group access is enabled 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								const  GroupAccessibleFileMode  os . FileMode  =  0660 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// New creates a new Handler for a single Restic backup repo. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// path is the full filesystem path to this repo directory. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// opt is a set of options. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  New ( path  string ,  opt  Options )  ( * Handler ,  error )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  path  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  nil ,  fmt . Errorf ( "path is required" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2025-02-17 22:17:54 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									opt . dirMode  =  DefaultDirMode 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									opt . fileMode  =  DefaultFileMode 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  opt . GroupAccessible  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										opt . dirMode  =  GroupAccessibleDirMode 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										opt . fileMode  =  GroupAccessibleFileMode 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2025-02-17 22:17:54 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									h  :=  Handler { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										path :  path , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										opt :   opt , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  & h ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// Handler handles all REST API requests for a single Restic backup repo 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-04 01:28:13 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// Spec: https://restic.readthedocs.io/en/latest/100_references.html#rest-backend 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								type  Handler  struct  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									path  string  // filesystem path of repo 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									opt   Options 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// httpDefaultError write a HTTP error with the default description 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  httpDefaultError ( w  http . ResponseWriter ,  code  int )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									http . Error ( w ,  http . StatusText ( code ) ,  code ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// httpMethodNotAllowed writes a 405 Method Not Allowed HTTP error with 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// the required Allow header listing the methods that are allowed. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  httpMethodNotAllowed ( w  http . ResponseWriter ,  allowed  [ ] string )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									w . Header ( ) . Set ( "Allow" ,  strings . Join ( allowed ,  ", " ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									httpDefaultError ( w ,  http . StatusMethodNotAllowed ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-09-06 22:13:33 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// errFileContentDoesntMatchHash is the error raised when the file content hash 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// doesn't match the hash provided in the URL 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								var  errFileContentDoesntMatchHash  =  errors . New ( "file content does not match hash" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// BlobPathRE matches valid blob URI paths with optional object IDs 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								var  BlobPathRE  =  regexp . MustCompile ( ` ^/(data|index|keys|locks|snapshots)/([0-9a-f] { 64})?$ ` ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// ObjectTypes are subdirs that are used for object storage 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								var  ObjectTypes  =  [ ] string { "data" ,  "index" ,  "keys" ,  "locks" ,  "snapshots" } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// FileTypes are files stored directly under the repo direct that are accessible 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// through a request 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								var  FileTypes  =  [ ] string { "config" } 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  isHashed ( objectType  string )  bool  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  objectType  ==  "data" 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-08-09 10:43:33 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// BlobOperation describe the current blob operation in the BlobMetricFunc callback. 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								type  BlobOperation  byte 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-08-09 10:43:33 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// Define all valid operations. 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								const  ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									BlobRead    =  'R'  // A blob has been read 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									BlobWrite   =  'W'  // A blob has been written 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									BlobDelete  =  'D'  // A blob has been deleted 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// BlobMetricFunc is the callback signature for blob metrics. Such a callback 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// can be passed in the Options to keep track of various metrics. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// objectType: one of ObjectTypes 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// operation: one of the BlobOperations above 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// nBytes: the number of bytes affected, or 0 if not relevant 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-04 01:28:13 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// TODO: Perhaps add http.Request for the username so that this can be cached? 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								type  BlobMetricFunc  func ( objectType  string ,  operation  BlobOperation ,  nBytes  uint64 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// ServeHTTP performs strict matching on the repo part of the URL path and 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// dispatches the request to the appropriate handler. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( h  * Handler )  ServeHTTP ( w  http . ResponseWriter ,  r  * http . Request )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									urlPath  :=  r . URL . Path 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  urlPath  ==  "/"  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// TODO: add HEAD and GET 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										switch  r . Method  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										case  "POST" : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											h . createRepo ( w ,  r ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										default : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											httpMethodNotAllowed ( w ,  [ ] string { "POST" } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									}  else  if  urlPath  ==  "/config"  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										switch  r . Method  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										case  "HEAD" : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											h . checkConfig ( w ,  r ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										case  "GET" : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											h . getConfig ( w ,  r ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										case  "POST" : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											h . saveConfig ( w ,  r ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										case  "DELETE" : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											h . deleteConfig ( w ,  r ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										default : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											httpMethodNotAllowed ( w ,  [ ] string { "HEAD" ,  "GET" ,  "POST" ,  "DELETE" } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									}  else  if  objectType ,  objectID  :=  h . getObject ( urlPath ) ;  objectType  !=  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  objectID  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											// TODO: add HEAD 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											switch  r . Method  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											case  "GET" : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												h . listBlobs ( w ,  r ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											default : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												httpMethodNotAllowed ( w ,  [ ] string { "GET" } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-09 10:43:33 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-09 10:43:33 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										switch  r . Method  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										case  "HEAD" : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											h . checkBlob ( w ,  r ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										case  "GET" : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											h . getBlob ( w ,  r ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										case  "POST" : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											h . saveBlob ( w ,  r ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										case  "DELETE" : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											h . deleteBlob ( w ,  r ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										default : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											httpMethodNotAllowed ( w ,  [ ] string { "HEAD" ,  "GET" ,  "POST" ,  "DELETE" } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									httpDefaultError ( w ,  http . StatusNotFound ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// getObject parses the URL path and returns the objectType and objectID, 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// if any. The objectID is optional. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( h  * Handler )  getObject ( urlPath  string )  ( objectType ,  objectID  string )  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-31 21:36:39 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									m  :=  BlobPathRE . FindStringSubmatch ( urlPath ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  len ( m )  ==  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  "" ,  ""  // no match 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  len ( m )  ==  2  ||  m [ 2 ]  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  m [ 1 ] ,  ""  // no objectID 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-31 21:36:39 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return  m [ 1 ] ,  m [ 2 ] 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// getSubPath returns the path for a file or subdir in the root of the repo. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( h  * Handler )  getSubPath ( name  string )  string  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  filepath . Join ( h . path ,  name ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// getObjectPath returns the path for an object file in the repo. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// The passed in objectType and objectID must be valid due to earlier validation 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( h  * Handler )  getObjectPath ( objectType ,  objectID  string )  string  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// If we hit an error, this is a programming error, because all of these 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// must have been validated before. We still check them here as a safeguard. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  objectType  ==  ""  ||  objectID  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										panic ( "invalid objectType or objectID" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  isHashed ( objectType )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  len ( objectID )  <  2  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											// Should never happen, because BlobPathRE checked this 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											panic ( "getObjectPath: objectID shorter than 2 chars" ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// Added another dir in between with the first two characters of the hash 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  filepath . Join ( h . path ,  objectType ,  objectID [ : 2 ] ,  objectID ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return  filepath . Join ( h . path ,  objectType ,  objectID ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// sendMetric calls op.BlobMetricFunc if set. See its signature for details. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( h  * Handler )  sendMetric ( objectType  string ,  operation  BlobOperation ,  nBytes  uint64 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  f  :=  h . opt . BlobMetricFunc ;  f  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										f ( objectType ,  operation ,  nBytes ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// needSize tells you if we need the file size for metrics of quota accounting 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( h  * Handler )  needSize ( )  bool  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-04 01:28:13 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return  h . opt . BlobMetricFunc  !=  nil  ||  h . opt . QuotaManager  !=  nil 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// incrementRepoSpaceUsage increments the repo space usage if quota are enabled 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( h  * Handler )  incrementRepoSpaceUsage ( by  int64 )  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-04 01:28:13 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  h . opt . QuotaManager  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										h . opt . QuotaManager . IncUsage ( by ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// wrapFileWriter wraps the file writer if repo quota are enabled, and returns it 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// as is if not. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// If an error occurs, it returns both an error and the appropriate HTTP error code. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( h  * Handler )  wrapFileWriter ( r  * http . Request ,  w  io . Writer )  ( io . Writer ,  int ,  error )  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-04 01:28:13 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  h . opt . QuotaManager  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  w ,  0 ,  nil  // unmodified 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-04 01:28:13 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									return  h . opt . QuotaManager . WrapWriter ( r ,  w ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// checkConfig checks whether a configuration exists. 
							 
						 
					
						
							
								
									
										
										
										
											2025-02-02 22:45:41 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  ( h  * Handler )  checkConfig ( w  http . ResponseWriter ,  _  * http . Request )  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  h . opt . Debug  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										log . Println ( "checkConfig()" ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									cfg  :=  h . getSubPath ( "config" ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									st ,  err  :=  os . Stat ( cfg ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-29 22:26:34 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . fileAccessError ( w ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									w . Header ( ) . Add ( "Content-Length" ,  fmt . Sprint ( st . Size ( ) ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// getConfig allows for a config to be retrieved. 
							 
						 
					
						
							
								
									
										
										
										
											2025-02-02 22:45:41 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  ( h  * Handler )  getConfig ( w  http . ResponseWriter ,  _  * http . Request )  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  h . opt . Debug  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										log . Println ( "getConfig()" ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									cfg  :=  h . getSubPath ( "config" ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-02-02 22:45:41 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									bytes ,  err  :=  os . ReadFile ( cfg ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-29 22:26:34 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . fileAccessError ( w ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									_ ,  _  =  w . Write ( bytes ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// saveConfig allows for a config to be saved. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( h  * Handler )  saveConfig ( w  http . ResponseWriter ,  r  * http . Request )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  h . opt . Debug  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										log . Println ( "saveConfig()" ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									cfg  :=  h . getSubPath ( "config" ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-02-17 22:17:54 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									f ,  err  :=  os . OpenFile ( cfg ,  os . O_CREATE | os . O_WRONLY | os . O_EXCL ,  h . opt . fileMode ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  &&  os . IsExist ( err )  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										if  h . opt . Debug  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
											log . Print ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										httpDefaultError ( w ,  http . StatusForbidden ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									_ ,  err  =  io . Copy ( f ,  r . Body ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-31 21:39:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . internalServerError ( w ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									err  =  f . Close ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-31 21:39:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . internalServerError ( w ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									_  =  r . Body . Close ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// deleteConfig removes a config. 
							 
						 
					
						
							
								
									
										
										
										
											2025-02-02 22:45:41 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  ( h  * Handler )  deleteConfig ( w  http . ResponseWriter ,  _  * http . Request )  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  h . opt . Debug  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										log . Println ( "deleteConfig()" ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  h . opt . AppendOnly  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										httpDefaultError ( w ,  http . StatusForbidden ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									cfg  :=  h . getSubPath ( "config" ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  :=  os . Remove ( cfg ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-02 23:22:42 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										// ignore not exist errors to make deleting idempotent, which is 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// necessary to properly handle request retries 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  ! errors . Is ( err ,  os . ErrNotExist )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											h . fileAccessError ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								const  ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									mimeTypeAPIV1  =  "application/vnd.x.restic.rest.v1" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									mimeTypeAPIV2  =  "application/vnd.x.restic.rest.v2" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// listBlobs lists all blobs of a given type in an arbitrary order. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( h  * Handler )  listBlobs ( w  http . ResponseWriter ,  r  * http . Request )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  h . opt . Debug  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										log . Println ( "listBlobs()" ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									switch  r . Header . Get ( "Accept" )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									case  mimeTypeAPIV2 : 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . listBlobsV2 ( w ,  r ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									default : 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . listBlobsV1 ( w ,  r ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// listBlobsV1 lists all blobs of a given type in an arbitrary order. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// TODO: unify listBlobsV1 and listBlobsV2 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( h  * Handler )  listBlobsV1 ( w  http . ResponseWriter ,  r  * http . Request )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  h . opt . Debug  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										log . Println ( "listBlobsV1()" ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									objectType ,  _  :=  h . getObject ( r . URL . Path ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  objectType  ==  ""  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-31 21:39:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . internalServerError ( w ,  fmt . Errorf ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											"cannot determine object type: %s" ,  r . URL . Path ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									path  :=  h . getSubPath ( objectType ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-02-02 22:45:41 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									items ,  err  :=  os . ReadDir ( path ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-29 22:26:34 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . fileAccessError ( w ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-06-16 21:52:50 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									names  :=  [ ] string { } 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									for  _ ,  i  :=  range  items  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										if  isHashed ( objectType )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-04-08 19:57:20 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											if  ! i . IsDir ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												// ignore files in intermediate directories 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
											subpath  :=  filepath . Join ( path ,  i . Name ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-02-02 22:45:41 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											var  subitems  [ ] os . DirEntry 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											subitems ,  err  =  os . ReadDir ( subpath ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-29 22:26:34 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												h . fileAccessError ( w ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
												return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											for  _ ,  f  :=  range  subitems  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												names  =  append ( names ,  f . Name ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											names  =  append ( names ,  i . Name ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									data ,  err  :=  json . Marshal ( names ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-04 14:33:31 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . internalServerError ( w ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									w . Header ( ) . Set ( "Content-Type" ,  mimeTypeAPIV1 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									_ ,  _  =  w . Write ( data ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Blob represents a single blob, its name and its size. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								type  Blob  struct  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									Name  string  ` json:"name" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									Size  int64   ` json:"size" ` 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// listBlobsV2 lists all blobs of a given type, together with their sizes, in an arbitrary order. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// TODO: unify listBlobsV1 and listBlobsV2 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( h  * Handler )  listBlobsV2 ( w  http . ResponseWriter ,  r  * http . Request )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  h . opt . Debug  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										log . Println ( "listBlobsV2()" ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									objectType ,  _  :=  h . getObject ( r . URL . Path ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  objectType  ==  ""  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-31 21:39:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . internalServerError ( w ,  fmt . Errorf ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											"cannot determine object type: %s" ,  r . URL . Path ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									path  :=  h . getSubPath ( objectType ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-02-02 22:45:41 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									items ,  err  :=  os . ReadDir ( path ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-29 22:26:34 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . fileAccessError ( w ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-06-16 21:52:50 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									blobs  :=  [ ] Blob { } 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									for  _ ,  i  :=  range  items  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										if  isHashed ( objectType )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-04-08 19:57:20 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											if  ! i . IsDir ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												// ignore files in intermediate directories 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
											subpath  :=  filepath . Join ( path ,  i . Name ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-02-02 22:45:41 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											var  subitems  [ ] os . DirEntry 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											subitems ,  err  =  os . ReadDir ( subpath ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-29 22:26:34 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												h . fileAccessError ( w ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
												return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											for  _ ,  f  :=  range  subitems  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-02-02 22:45:41 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
												fi ,  err  :=  f . Info ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													h . fileAccessError ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
													return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												blobs  =  append ( blobs ,  Blob { Name :  f . Name ( ) ,  Size :  fi . Size ( ) } ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										}  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-02-02 22:45:41 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											fi ,  err  :=  i . Info ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												h . fileAccessError ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											blobs  =  append ( blobs ,  Blob { Name :  i . Name ( ) ,  Size :  fi . Size ( ) } ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									data ,  err  :=  json . Marshal ( blobs ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-31 21:39:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . internalServerError ( w ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									w . Header ( ) . Set ( "Content-Type" ,  mimeTypeAPIV2 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									_ ,  _  =  w . Write ( data ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// checkBlob tests whether a blob exists. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( h  * Handler )  checkBlob ( w  http . ResponseWriter ,  r  * http . Request )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  h . opt . Debug  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										log . Println ( "checkBlob()" ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									objectType ,  objectID  :=  h . getObject ( r . URL . Path ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-31 21:39:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  objectType  ==  ""  ||  objectID  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										h . internalServerError ( w ,  fmt . Errorf ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											"cannot determine object type or id: %s" ,  r . URL . Path ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									path  :=  h . getObjectPath ( objectType ,  objectID ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									st ,  err  :=  os . Stat ( path ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-29 22:26:34 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . fileAccessError ( w ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									w . Header ( ) . Add ( "Content-Length" ,  fmt . Sprint ( st . Size ( ) ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// getBlob retrieves a blob from the repository. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( h  * Handler )  getBlob ( w  http . ResponseWriter ,  r  * http . Request )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  h . opt . Debug  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										log . Println ( "getBlob()" ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									objectType ,  objectID  :=  h . getObject ( r . URL . Path ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-31 21:39:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  objectType  ==  ""  ||  objectID  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										h . internalServerError ( w ,  fmt . Errorf ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											"cannot determine object type or id: %s" ,  r . URL . Path ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									path  :=  h . getObjectPath ( objectType ,  objectID ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									file ,  err  :=  os . Open ( path ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-29 22:26:34 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . fileAccessError ( w ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									wc  :=  datacounter . NewResponseWriterCounter ( w ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									http . ServeContent ( wc ,  r ,  "" ,  time . Unix ( 0 ,  0 ) ,  file ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  =  file . Close ( ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-31 21:39:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . internalServerError ( w ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									h . sendMetric ( objectType ,  BlobRead ,  wc . Count ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// saveBlob saves a blob to the repository. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( h  * Handler )  saveBlob ( w  http . ResponseWriter ,  r  * http . Request )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  h . opt . Debug  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										log . Println ( "saveBlob()" ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									objectType ,  objectID  :=  h . getObject ( r . URL . Path ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-31 21:39:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  objectType  ==  ""  ||  objectID  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										h . internalServerError ( w ,  fmt . Errorf ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											"cannot determine object type or id: %s" ,  r . URL . Path ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									path  :=  h . getObjectPath ( objectType ,  objectID ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-01-29 18:32:33 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									_ ,  err  :=  os . Stat ( path ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										httpDefaultError ( w ,  http . StatusForbidden ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  ! os . IsNotExist ( err )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										h . internalServerError ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-09-24 22:53:45 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									tmpFn  :=  filepath . Join ( filepath . Dir ( path ) ,  objectID + ".rest-server-temp" ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-02-17 22:17:54 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									tf ,  err  :=  tempFile ( tmpFn ,  h . opt . fileMode ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									if  os . IsNotExist ( err )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// the error is caused by a missing directory, create it and retry 
							 
						 
					
						
							
								
									
										
										
										
											2025-02-17 22:17:54 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										mkdirErr  :=  os . MkdirAll ( filepath . Dir ( path ) ,  h . opt . dirMode ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										if  mkdirErr  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											log . Print ( mkdirErr ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											// try again 
							 
						 
					
						
							
								
									
										
										
										
											2025-02-17 22:17:54 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											tf ,  err  =  tempFile ( tmpFn ,  h . opt . fileMode ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-31 21:39:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . internalServerError ( w ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									// ensure this blob does not put us over the quota size limit (if there is one) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									outFile ,  errCode ,  err  :=  h . wrapFileWriter ( r ,  tf ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  h . opt . Debug  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											log . Println ( err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										httpDefaultError ( w ,  errCode ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-08-09 15:40:50 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									var  written  int64 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-09 15:35:13 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-08-09 15:40:50 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  h . opt . NoVerifyUpload  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// just write the file without checking the contents 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										written ,  err  =  io . Copy ( outFile ,  r . Body ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// calculate hash for current request 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										hasher  :=  sha256 . New ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										written ,  err  =  io . Copy ( outFile ,  io . TeeReader ( r . Body ,  hasher ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// reject if file content doesn't match file name 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  ==  nil  &&  hex . EncodeToString ( hasher . Sum ( nil ) )  !=  objectID  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-06 22:13:33 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											err  =  errFileContentDoesntMatchHash 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-09 15:40:50 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-09 15:35:13 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										_  =  tf . Close ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-29 18:32:33 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										_  =  os . Remove ( tf . Name ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . incrementRepoSpaceUsage ( - written ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  h . opt . Debug  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
											log . Print ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-21 13:43:51 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										var  pathError  * os . PathError 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-06 22:13:33 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										if  errors . As ( err ,  & pathError )  &&  ( pathError . Err  ==  syscall . ENOSPC  || 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											pathError . Err  ==  syscall . EDQUOT )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											// The error is disk-related (no space left, no quota left), 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											// notify the client using the correct HTTP status 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-21 13:43:51 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											httpDefaultError ( w ,  http . StatusInsufficientStorage ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-06 22:13:33 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										}  else  if  errors . Is ( err ,  errFileContentDoesntMatchHash )  || 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											errors . Is ( err ,  io . ErrUnexpectedEOF )  || 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											errors . Is ( err ,  http . ErrMissingBoundary )  || 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											errors . Is ( err ,  http . ErrNotMultipart )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											// The error is connection-related, send a client-side HTTP status 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											httpDefaultError ( w ,  http . StatusBadRequest ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-21 13:43:51 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										}  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-06 22:13:33 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											// Otherwise we have a different internal error, reply with 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											// server-side HTTP status 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											h . internalServerError ( w ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-08-21 13:43:51 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-11-11 22:37:02 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									syncNotSup ,  err  :=  syncFile ( tf ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										_  =  tf . Close ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-29 18:32:33 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										_  =  os . Remove ( tf . Name ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . incrementRepoSpaceUsage ( - written ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-31 21:39:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . internalServerError ( w ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  :=  tf . Close ( ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-29 18:32:33 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										_  =  os . Remove ( tf . Name ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										h . incrementRepoSpaceUsage ( - written ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										h . internalServerError ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  :=  os . Rename ( tf . Name ( ) ,  path ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										_  =  os . Remove ( tf . Name ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . incrementRepoSpaceUsage ( - written ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-31 21:39:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . internalServerError ( w ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2023-05-08 21:40:23 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  syncNotSup  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-05-13 21:50:39 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . opt . FsyncWarning . Do ( func ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2023-05-08 21:40:23 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											log . Print ( "WARNING: fsync is not supported by the data storage. This can lead to data loss, if the system crashes or the storage is unexpectedly disconnected." ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									}  else  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-11-11 22:37:02 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										if  err  :=  syncDir ( filepath . Dir ( path ) ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											// Don't call os.Remove(path) as this is prone to race conditions with parallel upload retries 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											h . internalServerError ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-29 19:02:22 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									h . sendMetric ( objectType ,  BlobWrite ,  uint64 ( written ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-02-02 22:45:41 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// tempFile implements a custom version of os.CreateTemp which allows modifying the file permissions 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-24 22:53:45 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  tempFile ( fn  string ,  perm  os . FileMode )  ( f  * os . File ,  err  error )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									for  i  :=  0 ;  i  <  10 ;  i ++  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										name  :=  fn  +  strconv . FormatInt ( rand . Int63 ( ) ,  10 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										f ,  err  =  os . OpenFile ( name ,  os . O_RDWR | os . O_CREATE | os . O_EXCL ,  perm ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  os . IsExist ( err )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											continue 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										break 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-11-11 22:37:02 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  syncFile ( f  * os . File )  ( bool ,  error )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									err  :=  f . Sync ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									// Ignore error if filesystem does not support fsync. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									syncNotSup  :=  err  !=  nil  &&  ( errors . Is ( err ,  syscall . ENOTSUP )  ||  isMacENOTTY ( err ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  syncNotSup  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										err  =  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  syncNotSup ,  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-01-29 19:02:22 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								func  syncDir ( dirname  string )  error  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-07-16 21:47:35 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  runtime . GOOS  ==  "windows"  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// syncing a directory is not possible on windows 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-01-29 19:02:22 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									dir ,  err  :=  os . Open ( dirname ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									err  =  dir . Sync ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2022-11-11 22:37:02 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									// Ignore error if filesystem does not support fsync. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  errors . Is ( err ,  syscall . ENOTSUP )  ||  errors . Is ( err ,  syscall . ENOENT )  ||  errors . Is ( err ,  syscall . EINVAL )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										err  =  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-29 19:02:22 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										_  =  dir . Close ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									return  dir . Close ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// deleteBlob deletes a blob from the repository. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( h  * Handler )  deleteBlob ( w  http . ResponseWriter ,  r  * http . Request )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  h . opt . Debug  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										log . Println ( "deleteBlob()" ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									objectType ,  objectID  :=  h . getObject ( r . URL . Path ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-31 21:39:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  objectType  ==  ""  ||  objectID  ==  ""  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										h . internalServerError ( w ,  fmt . Errorf ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											"cannot determine object type or id: %s" ,  r . URL . Path ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  h . opt . AppendOnly  &&  objectType  !=  "locks"  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										httpDefaultError ( w ,  http . StatusForbidden ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									path  :=  h . getObjectPath ( objectType ,  objectID ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									var  size  int64 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  h . needSize ( )  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										stat ,  err  :=  os . Stat ( path ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  err  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											size  =  stat . Size ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  err  :=  os . Remove ( path ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2022-09-02 23:22:42 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										// ignore not exist errors to make deleting idempotent, which is 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										// necessary to properly handle request retries 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if  ! errors . Is ( err ,  os . ErrNotExist )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											h . fileAccessError ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									h . incrementRepoSpaceUsage ( - size ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									h . sendMetric ( objectType ,  BlobDelete ,  uint64 ( size ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// createRepo creates repository directories. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( h  * Handler )  createRepo ( w  http . ResponseWriter ,  r  * http . Request )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  h . opt . Debug  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										log . Println ( "createRepo()" ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  r . URL . Query ( ) . Get ( "create" )  !=  "true"  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										httpDefaultError ( w ,  http . StatusBadRequest ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									log . Printf ( "Creating repository directories in %s\n" ,  h . path ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-02-17 22:17:54 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									if  err  :=  os . MkdirAll ( h . path ,  h . opt . dirMode ) ;  err  !=  nil  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-31 21:39:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										h . internalServerError ( w ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
										return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
									for  _ ,  d  :=  range  ObjectTypes  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-02-17 22:17:54 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										if  err  :=  os . Mkdir ( filepath . Join ( h . path ,  d ) ,  h . opt . dirMode ) ;  err  !=  nil  &&  ! os . IsExist ( err )  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-31 21:39:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											h . internalServerError ( w ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
											return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									for  i  :=  0 ;  i  <  256 ;  i ++  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:57:56 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										dirPath  :=  filepath . Join ( h . path ,  "data" ,  fmt . Sprintf ( "%02x" ,  i ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-02-17 22:17:54 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
										if  err  :=  os . Mkdir ( dirPath ,  h . opt . dirMode ) ;  err  !=  nil  &&  ! os . IsExist ( err )  { 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-31 21:39:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
											h . internalServerError ( w ,  err ) 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-03 19:56:59 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
											return 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-31 21:39:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-08-29 22:26:34 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// internalServerError is called to report an internal server error. 
							 
						 
					
						
							
								
									
										
										
										
											2020-05-31 21:39:27 +08:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// The error message will be reported in the server logs. If PanicOnError 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// is set, this will panic instead, which makes debugging easier. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( h  * Handler )  internalServerError ( w  http . ResponseWriter ,  err  error )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									log . Printf ( "ERROR: %v" ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  h . opt . PanicOnError  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										panic ( fmt . Sprintf ( "internal server error: %v" ,  err ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									httpDefaultError ( w ,  http . StatusInternalServerError ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
									
										
										
										
											2022-08-29 22:26:34 +02:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// internalServerError is called to report an error that occurred while 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// accessing a file. If the does not exist, the corresponding http status code 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// will be returned to the client. All other errors are passed on to 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// internalServerError 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								func  ( h  * Handler )  fileAccessError ( w  http . ResponseWriter ,  err  error )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  h . opt . Debug  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										log . Print ( err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if  errors . Is ( err ,  os . ErrNotExist )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										httpDefaultError ( w ,  http . StatusNotFound ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										h . internalServerError ( w ,  err ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								}