github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/utils/fileutil/fileutil.go (about)

     1  /*
     2   * Copyright (C) 2020 The "MysteriumNetwork/node" Authors.
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License as published by
     6   * the Free Software Foundation, either version 3 of the License, or
     7   * (at your option) any later version.
     8   *
     9   * This program is distributed in the hope that it will be useful,
    10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   * GNU General Public License for more details.
    13   *
    14   * You should have received a copy of the GNU General Public License
    15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16   */
    17  
    18  // Copyright 2018 The Prometheus Authors
    19  // Licensed under the Apache License, Version 2.0 (the "License");
    20  // you may not use this file except in compliance with the License.
    21  // You may obtain a copy of the License at
    22  //
    23  // http://www.apache.org/licenses/LICENSE-2.0
    24  //
    25  // Unless required by applicable law or agreed to in writing, software
    26  // distributed under the License is distributed on an "AS IS" BASIS,
    27  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    28  // See the License for the specific language governing permissions and
    29  // limitations under the License.
    30  
    31  // Package fileutil provides utility methods used when dealing with the filesystem in tsdb.
    32  // It is largely copied from github.com/coreos/etcd/pkg/fileutil to avoid the
    33  // dependency chain it brings with it.
    34  // Please check github.com/coreos/etcd for licensing information.
    35  
    36  package fileutil
    37  
    38  import (
    39  	"os"
    40  	"path/filepath"
    41  	"sort"
    42  	"strings"
    43  )
    44  
    45  // CopyDirs copies all directories, subdirectories and files recursively including the empty folders.
    46  // Source and destination must be full paths.
    47  func CopyDirs(src, dest string) error {
    48  	if err := os.MkdirAll(dest, 0777); err != nil {
    49  		return err
    50  	}
    51  	files, err := readDirs(src)
    52  	if err != nil {
    53  		return err
    54  	}
    55  
    56  	for _, f := range files {
    57  		dp := filepath.Join(dest, f)
    58  		sp := filepath.Join(src, f)
    59  
    60  		stat, err := os.Stat(sp)
    61  		if err != nil {
    62  			return err
    63  		}
    64  
    65  		// Empty directories are also created.
    66  		if stat.IsDir() {
    67  			if err := os.MkdirAll(dp, 0777); err != nil {
    68  				return err
    69  			}
    70  			continue
    71  		}
    72  
    73  		if err := copyFile(sp, dp); err != nil {
    74  			return err
    75  		}
    76  	}
    77  	return nil
    78  }
    79  
    80  // copyFile copies a file from `src` to `dest`.
    81  // It tries to also copy it with the same permissions,
    82  // if thats not possible 0644 is used.
    83  func copyFile(src, dest string) error {
    84  	data, err := os.ReadFile(src)
    85  	if err != nil {
    86  		return err
    87  	}
    88  
    89  	perm := os.FileMode(0644)
    90  	if info, err := os.Stat(src); err == nil {
    91  		perm = info.Mode().Perm()
    92  	}
    93  
    94  	err = os.WriteFile(dest, data, perm)
    95  	if err != nil {
    96  		return err
    97  	}
    98  	return nil
    99  }
   100  
   101  // readDirs reads the source directory recursively and
   102  // returns relative paths to all files and empty directories.
   103  func readDirs(src string) ([]string, error) {
   104  	var files []string
   105  
   106  	err := filepath.Walk(src, func(path string, f os.FileInfo, err error) error {
   107  		relativePath := strings.TrimPrefix(path, src)
   108  		if len(relativePath) > 0 {
   109  			files = append(files, relativePath)
   110  		}
   111  		return nil
   112  	})
   113  	if err != nil {
   114  		return nil, err
   115  	}
   116  	return files, nil
   117  }
   118  
   119  // ReadDir returns the filenames in the given directory in sorted order.
   120  func ReadDir(dirpath string) ([]string, error) {
   121  	dir, err := os.Open(dirpath)
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  	defer dir.Close()
   126  	names, err := dir.Readdirnames(-1)
   127  	if err != nil {
   128  		return nil, err
   129  	}
   130  	sort.Strings(names)
   131  	return names, nil
   132  }