in cmd/zc_processor.go [168:304]
func (s *copyTransferProcessor) scheduleCopyTransfer(storedObject StoredObject) (err error) {
// Escape paths on destinations where the characters are invalid
// And re-encode them where the characters are valid.
var srcRelativePath, dstRelativePath string
if storedObject.relativePath == "\x00" { // Short circuit when we're talking about root/, because the STE is funky about this.
srcRelativePath, dstRelativePath = storedObject.relativePath, storedObject.relativePath
} else {
srcRelativePath = pathEncodeRules(storedObject.relativePath, s.copyJobTemplate.FromTo, false, true)
dstRelativePath = pathEncodeRules(storedObject.relativePath, s.copyJobTemplate.FromTo, false, false)
if srcRelativePath != "" {
srcRelativePath = "/" + srcRelativePath
}
if dstRelativePath != "" {
dstRelativePath = "/" + dstRelativePath
}
}
copyTransfer, shouldSendToSte := storedObject.ToNewCopyTransfer(false, srcRelativePath, dstRelativePath, s.preserveAccessTier, s.folderPropertiesOption, s.symlinkHandlingType)
if s.copyJobTemplate.FromTo.To() == common.ELocation.None() {
copyTransfer.BlobTier = s.copyJobTemplate.BlobAttributes.BlockBlobTier.ToAccessTierType()
metadataString := s.copyJobTemplate.BlobAttributes.Metadata
metadataMap := common.Metadata{}
if len(metadataString) > 0 {
for _, keyAndValue := range strings.Split(metadataString, ";") { // key/value pairs are separated by ';'
kv := strings.Split(keyAndValue, "=") // key/value are separated by '='
metadataMap[kv[0]] = &kv[1]
}
}
copyTransfer.Metadata = metadataMap
copyTransfer.BlobTags = common.ToCommonBlobTagsMap(s.copyJobTemplate.BlobAttributes.BlobTagsString)
}
if !shouldSendToSte {
return nil // skip this one
}
if s.dryrunMode {
glcm.Dryrun(func(format common.OutputFormat) string {
prettySrcRelativePath, prettyDstRelativePath := srcRelativePath, dstRelativePath
fromTo := s.copyJobTemplate.FromTo
if fromTo.From().IsRemote() {
prettySrcRelativePath, err = url.PathUnescape(prettySrcRelativePath)
if err != nil {
prettySrcRelativePath = srcRelativePath // Fall back, because it's better than failing.
}
}
if fromTo.To().IsRemote() {
prettyDstRelativePath, err = url.PathUnescape(prettyDstRelativePath)
if err != nil {
prettyDstRelativePath = dstRelativePath // Fall back, because it's better than failing.
}
}
if format == common.EOutputFormat.Json() {
tx := DryrunTransfer{
EntityType: storedObject.entityType,
BlobType: common.FromBlobType(storedObject.blobType),
FromTo: s.copyJobTemplate.FromTo,
Source: common.GenerateFullPath(s.copyJobTemplate.SourceRoot.Value, prettySrcRelativePath),
Destination: "",
SourceSize: &storedObject.size,
HttpHeaders: blob.HTTPHeaders{
BlobCacheControl: &storedObject.cacheControl,
BlobContentDisposition: &storedObject.contentDisposition,
BlobContentEncoding: &storedObject.contentEncoding,
BlobContentLanguage: &storedObject.contentLanguage,
BlobContentMD5: storedObject.md5,
BlobContentType: &storedObject.contentType,
},
Metadata: storedObject.Metadata,
BlobTier: &storedObject.blobAccessTier,
BlobVersion: &storedObject.blobVersionID,
BlobTags: storedObject.blobTags,
BlobSnapshot: &storedObject.blobSnapshotID,
}
if fromTo.To() != common.ELocation.None() && fromTo.To() != common.ELocation.Unknown() {
tx.Destination = common.GenerateFullPath(s.copyJobTemplate.DestinationRoot.Value, prettyDstRelativePath)
}
jsonOutput, err := json.Marshal(tx)
common.PanicIfErr(err)
return string(jsonOutput)
} else {
// if remove then To() will equal to common.ELocation.Unknown()
if s.copyJobTemplate.FromTo.To() == common.ELocation.Unknown() { // remove
return fmt.Sprintf("DRYRUN: remove %v",
common.GenerateFullPath(s.copyJobTemplate.SourceRoot.Value, prettySrcRelativePath))
}
if s.copyJobTemplate.FromTo.To() == common.ELocation.None() { // set-properties
return fmt.Sprintf("DRYRUN: set-properties %v",
common.GenerateFullPath(s.copyJobTemplate.SourceRoot.Value, prettySrcRelativePath))
} else { // copy for sync
return fmt.Sprintf("DRYRUN: copy %v to %v",
common.GenerateFullPath(s.copyJobTemplate.SourceRoot.Value, prettySrcRelativePath),
common.GenerateFullPath(s.copyJobTemplate.DestinationRoot.Value, prettyDstRelativePath))
}
}
})
return nil
}
if len(s.copyJobTemplate.Transfers.List) == s.numOfTransfersPerPart {
resp := s.sendPartToSte()
// TODO: If we ever do launch errors outside of the final "no transfers" error, make them output nicer things here.
if resp.ErrorMsg != "" {
return errors.New(string(resp.ErrorMsg))
}
// reset the transfers buffer
s.copyJobTemplate.Transfers = common.Transfers{}
s.copyJobTemplate.PartNum++
}
// only append the transfer after we've checked and dispatched a part
// so that there is at least one transfer for the final part
s.copyJobTemplate.Transfers.List = append(s.copyJobTemplate.Transfers.List, copyTransfer)
s.copyJobTemplate.Transfers.TotalSizeInBytes += uint64(copyTransfer.SourceSize)
switch copyTransfer.EntityType {
case common.EEntityType.File():
s.copyJobTemplate.Transfers.FileTransferCount++
case common.EEntityType.Folder():
s.copyJobTemplate.Transfers.FolderTransferCount++
case common.EEntityType.Symlink():
s.copyJobTemplate.Transfers.SymlinkTransferCount++
}
return nil
}