1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
|
// Copyright 2012 Jonas mg
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
package file
import (
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
)
// Copy copies file in source to file in dest preserving the mode attributes.
func Copy(source, dest string) (err error) {
// Don't backup files of backup.
if dest[len(dest)-1] != '~' {
if err = Backup(dest); err != nil {
return
}
}
srcFile, err := os.Open(source)
if err != nil {
return err
}
defer func() {
err2 := srcFile.Close()
if err2 != nil && err == nil {
err = err2
}
}()
srcInfo, err := os.Stat(source)
if err != nil {
return err
}
dstFile, err := os.OpenFile(dest, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, srcInfo.Mode().Perm())
if err != nil {
return err
}
_, err = io.Copy(dstFile, srcFile)
err2 := dstFile.Close()
if err2 != nil && err == nil {
err = err2
}
return
}
// Create creates a new file with b bytes.
func Create(filename string, b []byte) (err error) {
file, err := os.Create(filename)
if err != nil {
return err
}
_, err = file.Write(b)
err2 := file.Close()
if err2 != nil && err == nil {
err = err2
}
return
}
// CreateString is like Create, but writes the contents of string s rather than
// an array of bytes.
func CreateString(filename, s string) error {
return Create(filename, []byte(s))
}
// Overwrite truncates the named file to zero and writes len(b) bytes. It
// returns an error, if any.
func Overwrite(filename string, b []byte) (err error) {
if err := Backup(filename); err != nil {
return err
}
file, err := os.Create(filename)
if err != nil {
return err
}
_, err = file.Write(b)
err2 := file.Close()
if err2 != nil && err == nil {
err = err2
}
return
}
// OverwriteString is like Overwrite, but writes the contents of string s rather
// than an array of bytes.
func OverwriteString(filename, s string) error {
return Overwrite(filename, []byte(s))
}
// == Utility
const _BACKUP_SUFFIX = "+[1-9]~" // Suffix pattern added to backup's file name.
const PREFIX_TEMP = "test-" // Prefix to add to temporary files.
// Backup creates a backup of the named file.
//
// The schema used for the new name is: {name}\+[1-9]~
// name: The original file name.
// + : Character used to separate the file name from rest.
// number: A number from 1 to 9, using rotation.
// ~ : To indicate that it is a backup, just like it is used in Unix systems.
func Backup(filename string) error {
// Check if it is empty
info, err := os.Stat(filename)
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
if info.Size() == 0 {
return nil
}
files, err := filepath.Glob(filename + _BACKUP_SUFFIX)
if err != nil {
return err
}
// Number rotation
numBackup := byte(1)
if len(files) != 0 {
lastFile := files[len(files)-1]
numBackup = lastFile[len(lastFile)-2] + 1 // next number
if numBackup > '9' {
numBackup = '1'
}
} else {
numBackup = '1'
}
return Copy(filename, fmt.Sprintf("%s+%s~", filename, string(numBackup)))
}
// CopytoTemp creates a temporary file from the source file into the default
// directory for temporary files (see os.TempDir), whose name begins with prefix.
// If prefix is the empty string, uses the default value PREFIX_TEMP.
// Returns the temporary file name.
func CopytoTemp(source, prefix string) (tmpFile string, err error) {
if prefix == "" {
prefix = PREFIX_TEMP
}
src, err := os.Open(source)
if err != nil {
return "", err
}
defer func() {
err2 := src.Close()
if err2 != nil && err == nil {
err = err2
}
}()
dest, err := ioutil.TempFile("", prefix)
if err != nil {
return "", err
}
defer func() {
err2 := dest.Close()
if err2 != nil && err == nil {
err = err2
}
}()
if _, err = io.Copy(dest, src); err != nil {
return "", err
}
return dest.Name(), nil
}
|