LCOV - code coverage report
Current view: top level - pebble/vfs - clone.go (source / functions) Hit Total Coverage
Test: 2024-03-09 08:15Z 8df4320c - tests + meta.lcov Lines: 50 80 62.5 %
Date: 2024-03-09 08:16:52 Functions: 0 0 -

          Line data    Source code
       1             : // Copyright 2019 The LevelDB-Go and Pebble Authors. All rights reserved. Use
       2             : // of this source code is governed by a BSD-style license that can be found in
       3             : // the LICENSE file.
       4             : 
       5             : package vfs
       6             : 
       7             : import (
       8             :         "io"
       9             :         "sort"
      10             : 
      11             :         "github.com/cockroachdb/errors/oserror"
      12             : )
      13             : 
      14             : type cloneOpts struct {
      15             :         skip    func(string) bool
      16             :         sync    bool
      17             :         tryLink bool
      18             : }
      19             : 
      20             : // A CloneOption configures the behavior of Clone.
      21             : type CloneOption func(*cloneOpts)
      22             : 
      23             : // CloneSkip configures Clone to skip files for which the provided function
      24             : // returns true when passed the file's path.
      25           1 : func CloneSkip(fn func(string) bool) CloneOption {
      26           1 :         return func(co *cloneOpts) { co.skip = fn }
      27             : }
      28             : 
      29             : // CloneSync configures Clone to sync files and directories.
      30           1 : var CloneSync CloneOption = func(o *cloneOpts) { o.sync = true }
      31             : 
      32             : // CloneTryLink configures Clone to link files to the destination if the source and
      33             : // destination filesystems are the same. If the source and destination
      34             : // filesystems are not the same or the filesystem does not support linking, then
      35             : // Clone falls back to copying.
      36           1 : var CloneTryLink CloneOption = func(o *cloneOpts) { o.tryLink = true }
      37             : 
      38             : // Clone recursively copies a directory structure from srcFS to dstFS. srcPath
      39             : // specifies the path in srcFS to copy from and must be compatible with the
      40             : // srcFS path format. dstDir is the target directory in dstFS and must be
      41             : // compatible with the dstFS path format. Returns (true,nil) on a successful
      42             : // copy, (false,nil) if srcPath does not exist, and (false,err) if an error
      43             : // occurred.
      44           1 : func Clone(srcFS, dstFS FS, srcPath, dstPath string, opts ...CloneOption) (bool, error) {
      45           1 :         var o cloneOpts
      46           1 :         for _, opt := range opts {
      47           1 :                 opt(&o)
      48           1 :         }
      49             : 
      50           1 :         srcFile, err := srcFS.Open(srcPath)
      51           1 :         if err != nil {
      52           1 :                 if oserror.IsNotExist(err) {
      53           1 :                         // Ignore non-existent errors. Those will translate into non-existent
      54           1 :                         // files in the destination filesystem.
      55           1 :                         return false, nil
      56           1 :                 }
      57           0 :                 return false, err
      58             :         }
      59           1 :         defer srcFile.Close()
      60           1 : 
      61           1 :         stat, err := srcFile.Stat()
      62           1 :         if err != nil {
      63           0 :                 return false, err
      64           0 :         }
      65             : 
      66           1 :         if stat.IsDir() {
      67           1 :                 if err := dstFS.MkdirAll(dstPath, 0755); err != nil {
      68           0 :                         return false, err
      69           0 :                 }
      70           1 :                 list, err := srcFS.List(srcPath)
      71           1 :                 if err != nil {
      72           0 :                         return false, err
      73           0 :                 }
      74             :                 // Sort the paths so we get deterministic test output.
      75           1 :                 sort.Strings(list)
      76           1 :                 for _, name := range list {
      77           1 :                         if o.skip != nil && o.skip(srcFS.PathJoin(srcPath, name)) {
      78           0 :                                 continue
      79             :                         }
      80           1 :                         _, err := Clone(srcFS, dstFS, srcFS.PathJoin(srcPath, name), dstFS.PathJoin(dstPath, name), opts...)
      81           1 :                         if err != nil {
      82           0 :                                 return false, err
      83           0 :                         }
      84             :                 }
      85             : 
      86           1 :                 if o.sync {
      87           1 :                         dir, err := dstFS.OpenDir(dstPath)
      88           1 :                         if err != nil {
      89           0 :                                 return false, err
      90           0 :                         }
      91           1 :                         if err := dir.Sync(); err != nil {
      92           0 :                                 return false, err
      93           0 :                         }
      94           1 :                         if err := dir.Close(); err != nil {
      95           0 :                                 return false, err
      96           0 :                         }
      97             :                 }
      98             : 
      99           1 :                 return true, nil
     100             :         }
     101             : 
     102             :         // If the source and destination filesystems are the same and the user
     103             :         // specified they'd prefer to link if possible, try to use a hardlink,
     104             :         // falling back to copying if it fails.
     105           1 :         if srcFS == dstFS && o.tryLink {
     106           1 :                 if err := LinkOrCopy(srcFS, srcPath, dstPath); oserror.IsNotExist(err) {
     107           0 :                         // Clone's semantics are such that it returns (false,nil) if the
     108           0 :                         // source does not exist.
     109           0 :                         return false, nil
     110           1 :                 } else if err != nil {
     111           0 :                         return false, err
     112           1 :                 } else {
     113           1 :                         return true, nil
     114           1 :                 }
     115             :         }
     116             : 
     117           1 :         data, err := io.ReadAll(srcFile)
     118           1 :         if err != nil {
     119           0 :                 return false, err
     120           0 :         }
     121           1 :         dstFile, err := dstFS.Create(dstPath)
     122           1 :         if err != nil {
     123           0 :                 return false, err
     124           0 :         }
     125           1 :         if _, err = dstFile.Write(data); err != nil {
     126           0 :                 return false, err
     127           0 :         }
     128           1 :         if o.sync {
     129           1 :                 if err := dstFile.Sync(); err != nil {
     130           0 :                         return false, err
     131           0 :                 }
     132             :         }
     133           1 :         if err := dstFile.Close(); err != nil {
     134           0 :                 return false, err
     135           0 :         }
     136           1 :         return true, nil
     137             : }

Generated by: LCOV version 1.14