| 
									
										
										
										
											2018-11-07 02:19:42 +08:00
										 |  |  | // Copyright 2018 The Prometheus Authors
 | 
					
						
							|  |  |  | // Licensed under the Apache License, Version 2.0 (the "License");
 | 
					
						
							|  |  |  | // you may not use this file except in compliance with the License.
 | 
					
						
							|  |  |  | // You may obtain a copy of the License at
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Unless required by applicable law or agreed to in writing, software
 | 
					
						
							|  |  |  | // distributed under the License is distributed on an "AS IS" BASIS,
 | 
					
						
							|  |  |  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
					
						
							|  |  |  | // See the License for the specific language governing permissions and
 | 
					
						
							|  |  |  | // limitations under the License.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-04 16:23:41 +08:00
										 |  |  | // Package fileutil provides utility methods used when dealing with the filesystem in tsdb.
 | 
					
						
							|  |  |  | // It is largely copied from github.com/coreos/etcd/pkg/fileutil to avoid the
 | 
					
						
							|  |  |  | // dependency chain it brings with it.
 | 
					
						
							|  |  |  | // Please check github.com/coreos/etcd for licensing information.
 | 
					
						
							|  |  |  | package fileutil | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2018-05-17 21:02:47 +08:00
										 |  |  | 	"path/filepath" | 
					
						
							| 
									
										
										
										
											2018-09-22 01:35:33 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2017-10-04 16:23:41 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-22 01:35:33 +08:00
										 |  |  | // CopyDirs copies all directories, subdirectories and files recursively including the empty folders.
 | 
					
						
							|  |  |  | // Source and destination must be full paths.
 | 
					
						
							|  |  |  | func CopyDirs(src, dest string) error { | 
					
						
							| 
									
										
										
										
											2021-10-22 16:06:44 +08:00
										 |  |  | 	if err := os.MkdirAll(dest, 0o777); err != nil { | 
					
						
							| 
									
										
										
										
											2018-09-22 01:35:33 +08:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	files, err := readDirs(src) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, f := range files { | 
					
						
							|  |  |  | 		dp := filepath.Join(dest, f) | 
					
						
							|  |  |  | 		sp := filepath.Join(src, f) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		stat, err := os.Stat(sp) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Empty directories are also created.
 | 
					
						
							|  |  |  | 		if stat.IsDir() { | 
					
						
							| 
									
										
										
										
											2021-10-22 16:06:44 +08:00
										 |  |  | 			if err := os.MkdirAll(dp, 0o777); err != nil { | 
					
						
							| 
									
										
										
										
											2018-09-22 01:35:33 +08:00
										 |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if err := copyFile(sp, dp); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func copyFile(src, dest string) error { | 
					
						
							| 
									
										
										
										
											2022-04-27 17:24:36 +08:00
										 |  |  | 	data, err := os.ReadFile(src) | 
					
						
							| 
									
										
										
										
											2018-09-22 01:35:33 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-27 17:24:36 +08:00
										 |  |  | 	err = os.WriteFile(dest, data, 0o666) | 
					
						
							| 
									
										
										
										
											2018-09-22 01:35:33 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // readDirs reads the source directory recursively and
 | 
					
						
							|  |  |  | // returns relative paths to all files and empty directories.
 | 
					
						
							|  |  |  | func readDirs(src string) ([]string, error) { | 
					
						
							|  |  |  | 	var files []string | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-04 22:45:50 +08:00
										 |  |  | 	err := filepath.Walk(src, func(path string, f os.FileInfo, err error) error { | 
					
						
							| 
									
										
										
										
											2018-09-22 01:35:33 +08:00
										 |  |  | 		relativePath := strings.TrimPrefix(path, src) | 
					
						
							|  |  |  | 		if len(relativePath) > 0 { | 
					
						
							|  |  |  | 			files = append(files, relativePath) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return files, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-17 21:02:47 +08:00
										 |  |  | // Rename safely renames a file.
 | 
					
						
							|  |  |  | func Rename(from, to string) error { | 
					
						
							|  |  |  | 	if err := os.Rename(from, to); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Directory was renamed; sync parent dir to persist rename.
 | 
					
						
							|  |  |  | 	pdir, err := OpenDir(filepath.Dir(to)) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-03 16:16:54 +08:00
										 |  |  | 	if err = pdir.Sync(); err != nil { | 
					
						
							| 
									
										
										
										
											2018-05-17 21:02:47 +08:00
										 |  |  | 		pdir.Close() | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return pdir.Close() | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-08-03 05:46:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Replace moves a file or directory to a new location and deletes any previous data.
 | 
					
						
							|  |  |  | // It is not atomic.
 | 
					
						
							|  |  |  | func Replace(from, to string) error { | 
					
						
							| 
									
										
										
										
											2019-06-19 19:27:19 +08:00
										 |  |  | 	// Remove destination only if it is a dir otherwise leave it to os.Rename
 | 
					
						
							| 
									
										
										
										
											2019-06-24 16:51:49 +08:00
										 |  |  | 	// as it replaces the destination file and is atomic.
 | 
					
						
							| 
									
										
										
										
											2019-06-19 17:10:51 +08:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		f, err := os.Stat(to) | 
					
						
							| 
									
										
										
										
											2019-06-19 19:27:19 +08:00
										 |  |  | 		if !os.IsNotExist(err) { | 
					
						
							|  |  |  | 			if err == nil && f.IsDir() { | 
					
						
							|  |  |  | 				if err := os.RemoveAll(to); err != nil { | 
					
						
							|  |  |  | 					return err | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2019-06-19 17:10:51 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-08-03 05:46:45 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-06-19 17:10:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-14 17:29:28 +08:00
										 |  |  | 	return Rename(from, to) | 
					
						
							| 
									
										
										
										
											2018-08-03 05:46:45 +08:00
										 |  |  | } |