github.com/chrislusf/greenpack@v3.7.1-0.20170911073826-ad5bd10b7c47+incompatible/cmd/addzid/cpfile.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 "path" 8 ) 9 10 // Cp implements a portable version of /bin/cp for use in golang 11 // code that wants to work on many platforms. If the destinationPath 12 // directory hierarchy does not exist, we will attempt to make it, 13 // like mkdir -p would. 14 func Cp(originPath, destinationPath string) (err error) { 15 if !FileExists(originPath) { 16 return fmt.Errorf("Cp error: source path '%s' does not exist", originPath) 17 } 18 19 var dirname, target string 20 21 ostat, err := os.Stat(originPath) 22 if err != nil { 23 return err 24 } 25 if !ostat.Mode().IsRegular() { 26 return fmt.Errorf("Cp: can only copy regular files, origin is '%s' of mode: '%s'", ostat.Name(), ostat.Mode().String()) 27 } 28 29 if FileExists(destinationPath) { 30 // okay, good to go 31 //fmt.Printf("\n okay, destinationPath '%s' exists as a file\n", destinationPath) 32 dirname = path.Dir(destinationPath) 33 target = path.Base(destinationPath) 34 } else { 35 // no such file yet 36 //fmt.Printf("\n okay, destinationPath '%s': no such file yet.\n", destinationPath) 37 38 // set dirname and target 39 40 // do we end in "/" or "\"? 41 if IsDirPath(destinationPath) { 42 dirname = destinationPath 43 target = path.Base(originPath) 44 } else { 45 // the final path component is taken to be the target file name, unless 46 // it names an existing directory. 47 if DirExists(destinationPath) { 48 //fmt.Printf("\n okay, destinationPath '%s' exists as a directory\n", destinationPath) 49 dirname = path.Dir(destinationPath) 50 target = path.Base(originPath) 51 52 } else { 53 dirname = path.Dir(destinationPath) 54 target = path.Base(destinationPath) 55 } 56 } 57 58 //fmt.Printf("\n dirname = '%s' target = '%s'\n", dirname, target) 59 60 // is it a directory that exists? 61 if DirExists(dirname) { 62 //fmt.Printf("\n okay, dirname '%s' exists as a directory\n", dirname) 63 } else { 64 //fmt.Printf("\n okay, dirname '%s' is not an existing directory, try to make needed directories\n", dirname) 65 // dirname is not an existing directory, try to mkdir -p make the needed dirs. 66 67 err = os.MkdirAll(dirname, 0755) 68 if err != nil { 69 return fmt.Errorf("could not create destination directory path(s) with MkdirAll on '%s', error: '%s'", dirname, err) 70 } else { 71 //fmt.Printf("\n made dirname: '%s'\n", dirname) 72 } 73 } 74 75 } 76 // INVAR: we should be good to copy to dirname 77 //fmt.Printf("\n INVAR: we should be good to copy to dirname: '%s'\n", dirname) 78 79 fullpath := appendFilename(dirname, target) 80 81 dstat, err := os.Stat(fullpath) 82 if err != nil { 83 if !os.IsNotExist(err) { 84 return err 85 } 86 } else { 87 // we have an existing file, don't bother writing atop ourselves. 88 if os.SameFile(ostat, dstat) { 89 return nil // don't error out here, the copy is actually already done. 90 } 91 } 92 93 // proceed to copy 94 //fmt.Printf("os.Open with originPath = '%s'\n", originPath) 95 src, err := os.Open(originPath) 96 if err != nil { 97 return err 98 } 99 defer src.Close() 100 101 //fmt.Printf("os.Create with fullpath = '%s'\n", fullpath) 102 dest, err := os.Create(fullpath) 103 if err != nil { 104 //fmt.Printf("returning early after attempt os.Create with fullpath = '%s'\n", fullpath) 105 return err 106 } 107 defer func() { 108 closeError := dest.Close() 109 // only substitute closeError if there was 110 // no previous earlier error 111 if err == nil { 112 err = closeError 113 } 114 }() 115 _, err = io.Copy(dest, src) 116 if err != nil { 117 return err 118 } 119 return nil 120 } 121 122 func appendFilename(dir, fn string) string { 123 // but don't double // or \\ it 124 if IsDirPath(dir) { 125 return dir + fn 126 } 127 return dir + string(os.PathSeparator) + fn 128 } 129 130 func IsDirPath(dir string) bool { 131 n := len(dir) 132 if n == 0 { 133 return false 134 } 135 if dir[n-1] == os.PathSeparator { 136 return true 137 } 138 return false 139 }