cae.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. // Copyright 2013 Unknown
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License"): you may
  4. // not use this file except in compliance with the License. You may obtain
  5. // a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. // License for the specific language governing permissions and limitations
  13. // under the License.
  14. // Package cae implements PHP-like Compression and Archive Extensions.
  15. package cae
  16. import (
  17. "io"
  18. "os"
  19. "strings"
  20. )
  21. // A Streamer describes an streamable archive object.
  22. type Streamer interface {
  23. StreamFile(string, os.FileInfo, []byte) error
  24. StreamReader(string, os.FileInfo, io.Reader) error
  25. Close() error
  26. }
  27. // A HookFunc represents a middleware for packing and extracting archive.
  28. type HookFunc func(string, os.FileInfo) error
  29. // HasPrefix returns true if name has any string in given slice as prefix.
  30. func HasPrefix(name string, prefixes []string) bool {
  31. for _, prefix := range prefixes {
  32. if strings.HasPrefix(name, prefix) {
  33. return true
  34. }
  35. }
  36. return false
  37. }
  38. // IsEntry returns true if name equals to any string in given slice.
  39. func IsEntry(name string, entries []string) bool {
  40. for _, e := range entries {
  41. if e == name {
  42. return true
  43. }
  44. }
  45. return false
  46. }
  47. // IsFilter returns true if given name matches any of global filter rule.
  48. func IsFilter(name string) bool {
  49. if strings.Contains(name, ".DS_Store") {
  50. return true
  51. }
  52. return false
  53. }
  54. // IsExist returns true if given path is a file or directory.
  55. func IsExist(path string) bool {
  56. _, err := os.Stat(path)
  57. return err == nil || os.IsExist(err)
  58. }
  59. // Copy copies file from source to target path.
  60. func Copy(dest, src string) error {
  61. // Gather file information to set back later.
  62. si, err := os.Lstat(src)
  63. if err != nil {
  64. return err
  65. }
  66. // Handle symbolic link.
  67. if si.Mode()&os.ModeSymlink != 0 {
  68. target, err := os.Readlink(src)
  69. if err != nil {
  70. return err
  71. }
  72. // NOTE: os.Chmod and os.Chtimes don't recoganize symbolic link,
  73. // which will lead "no such file or directory" error.
  74. return os.Symlink(target, dest)
  75. }
  76. sr, err := os.Open(src)
  77. if err != nil {
  78. return err
  79. }
  80. defer sr.Close()
  81. dw, err := os.Create(dest)
  82. if err != nil {
  83. return err
  84. }
  85. defer dw.Close()
  86. if _, err = io.Copy(dw, sr); err != nil {
  87. return err
  88. }
  89. // Set back file information.
  90. if err = os.Chtimes(dest, si.ModTime(), si.ModTime()); err != nil {
  91. return err
  92. }
  93. return os.Chmod(dest, si.Mode())
  94. }