github.com/slspeek/camlistore_namedsearch@v0.0.0-20140519202248-ed6f70f7721a/cmd/camput/blobs.go (about) 1 /* 2 Copyright 2011 Google 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 main 18 19 import ( 20 "bytes" 21 "crypto/sha1" 22 "errors" 23 "flag" 24 "fmt" 25 "io" 26 "os" 27 28 "camlistore.org/pkg/blob" 29 "camlistore.org/pkg/client" 30 "camlistore.org/pkg/cmdmain" 31 "camlistore.org/pkg/constants" 32 ) 33 34 type blobCmd struct{} 35 36 func init() { 37 cmdmain.RegisterCommand("blob", func(flags *flag.FlagSet) cmdmain.CommandRunner { 38 return new(blobCmd) 39 }) 40 } 41 42 func (c *blobCmd) Describe() string { 43 return "Upload raw blob(s)." 44 } 45 46 func (c *blobCmd) Usage() { 47 fmt.Fprintf(cmdmain.Stderr, "Usage: camput [globalopts] blob <files>\n camput [globalopts] blob -\n") 48 } 49 50 func (c *blobCmd) Examples() []string { 51 return []string{ 52 "<files> (raw, without any metadata)", 53 "- (read from stdin)", 54 } 55 } 56 57 func (c *blobCmd) RunCommand(args []string) error { 58 if len(args) == 0 { 59 return errors.New("No files given.") 60 } 61 62 up := getUploader() 63 for _, arg := range args { 64 var ( 65 handle *client.UploadHandle 66 err error 67 ) 68 if arg == "-" { 69 handle, err = stdinBlobHandle() 70 } else { 71 handle, err = fileBlobHandle(up, arg) 72 } 73 if err != nil { 74 return err 75 } 76 put, err := up.Upload(handle) 77 handleResult("blob", put, err) 78 continue 79 } 80 return nil 81 } 82 83 func stdinBlobHandle() (uh *client.UploadHandle, err error) { 84 var buf bytes.Buffer 85 size, err := io.CopyN(&buf, cmdmain.Stdin, constants.MaxBlobSize+1) 86 if err == io.EOF { 87 err = nil 88 } 89 if err != nil { 90 return 91 } 92 if size > constants.MaxBlobSize { 93 err = fmt.Errorf("blob size cannot be bigger than %d", constants.MaxBlobSize) 94 } 95 file := buf.Bytes() 96 h := blob.NewHash() 97 size, err = io.Copy(h, bytes.NewReader(file)) 98 if err != nil { 99 return 100 } 101 return &client.UploadHandle{ 102 BlobRef: blob.RefFromHash(h), 103 Size: uint32(size), 104 Contents: io.LimitReader(bytes.NewReader(file), size), 105 }, nil 106 } 107 108 func fileBlobHandle(up *Uploader, path string) (uh *client.UploadHandle, err error) { 109 fi, err := up.stat(path) 110 if err != nil { 111 return 112 } 113 if fi.Mode()&os.ModeType != 0 { 114 return nil, fmt.Errorf("%q is not a regular file", path) 115 } 116 file, err := up.open(path) 117 if err != nil { 118 return 119 } 120 ref, size, err := blobDetails(file) 121 if err != nil { 122 return nil, err 123 } 124 return &client.UploadHandle{ 125 BlobRef: ref, 126 Size: size, 127 Contents: io.LimitReader(file, int64(size)), 128 }, nil 129 } 130 131 func blobDetails(contents io.ReadSeeker) (bref blob.Ref, size uint32, err error) { 132 s1 := sha1.New() 133 if _, err = contents.Seek(0, 0); err != nil { 134 return 135 } 136 defer func() { 137 if _, seekErr := contents.Seek(0, 0); seekErr != nil { 138 if err == nil { 139 err = seekErr 140 } else { 141 err = fmt.Errorf("%s, cannot seek back: %v", err, seekErr) 142 } 143 } 144 }() 145 sz, err := io.CopyN(s1, contents, constants.MaxBlobSize+1) 146 if err == nil || err == io.EOF { 147 bref, err = blob.RefFromHash(s1), nil 148 } else { 149 err = fmt.Errorf("error reading contents: %v", err) 150 return 151 } 152 if sz > constants.MaxBlobSize { 153 err = fmt.Errorf("blob size cannot be bigger than %d", constants.MaxBlobSize) 154 } 155 size = uint32(sz) 156 return 157 }