...

Source file src/github.com/sassoftware/relic/lib/atomicfile/openany.go

Documentation: github.com/sassoftware/relic/lib/atomicfile

     1  //
     2  // Copyright (c) SAS Institute Inc.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  //
    16  
    17  package atomicfile
    18  
    19  import (
    20  	"io"
    21  	"os"
    22  )
    23  
    24  type nopAtomic struct {
    25  	*os.File
    26  	doClose bool
    27  }
    28  
    29  func (a nopAtomic) GetFile() *os.File {
    30  	return a.File
    31  }
    32  
    33  func (a nopAtomic) Commit() error {
    34  	if a.doClose {
    35  		return a.Close()
    36  	}
    37  	return nil
    38  }
    39  
    40  func isSpecial(path string) bool {
    41  	if stat, err := os.Stat(path); err == nil {
    42  		if !stat.Mode().IsRegular() {
    43  			return true
    44  		}
    45  	}
    46  	return false
    47  }
    48  
    49  // Pick the best strategy for writing to the given path. Pipes and devices will
    50  // be written to directly, otherwise write-rename.
    51  func WriteAny(path string) (AtomicFile, error) {
    52  	if path == "-" {
    53  		return nopAtomic{os.Stdout, false}, nil
    54  	}
    55  	if isSpecial(path) {
    56  		f, err := os.Create(path)
    57  		return nopAtomic{f, true}, err
    58  	}
    59  	return New(path)
    60  }
    61  
    62  // If src and dest are the same, use src for reading and writing. If they are
    63  // different, make a copy and open the destination as an atomicfile, after
    64  // which src will be closed.
    65  func WriteInPlace(src *os.File, dest string) (AtomicFile, error) {
    66  	if src.Name() == dest {
    67  		return nopAtomic{src, false}, nil
    68  	}
    69  	outfile, err := New(dest)
    70  	if err != nil {
    71  		return nil, err
    72  	}
    73  	src.Seek(0, 0)
    74  	if _, err := io.Copy(outfile, src); err != nil {
    75  		return nil, err
    76  	}
    77  	outfile.Seek(0, 0)
    78  	src.Close()
    79  	return outfile, nil
    80  }
    81  
    82  // Write bytes to a file, using write-rename when appropriate
    83  func WriteFile(path string, data []byte) error {
    84  	f, err := WriteAny(path)
    85  	if err != nil {
    86  		return err
    87  	}
    88  	defer f.Close()
    89  	if _, err := f.Write(data); err != nil {
    90  		return err
    91  	}
    92  	return f.Commit()
    93  }
    94  

View as plain text