diff --git a/commands/command_migrate_export.go b/commands/command_migrate_export.go index 6442e4d0..bc24a1a8 100644 --- a/commands/command_migrate_export.go +++ b/commands/command_migrate_export.go @@ -136,7 +136,7 @@ func migrateExportCommand(cmd *cobra.Command, args []string) { } if _, err := os.Stat(downloadPath); os.IsNotExist(err) { - q.Add(p.Name, downloadPath, p.Oid, p.Size, false) + q.Add(p.Name, downloadPath, p.Oid, p.Size, false, nil) } }) gs.ScanRefs(opts.Include, opts.Exclude, nil) diff --git a/commands/command_smudge.go b/commands/command_smudge.go index f11c86fb..f5d441ef 100644 --- a/commands/command_smudge.go +++ b/commands/command_smudge.go @@ -59,7 +59,7 @@ func delayedSmudge(gf *lfs.GitFilter, s *git.FilterProcessScanner, to io.Writer, if !skip && filter.Allows(filename) { if _, statErr := os.Stat(path); statErr != nil { - q.Add(filename, path, ptr.Oid, ptr.Size, false) + q.Add(filename, path, ptr.Oid, ptr.Size, false, err) return 0, true, ptr, nil } diff --git a/commands/commands.go b/commands/commands.go index b345be14..365be88d 100644 --- a/commands/commands.go +++ b/commands/commands.go @@ -131,9 +131,9 @@ func buildFilepathFilter(config *config.Configuration, includeArg, excludeArg *s return filepathfilter.New(inc, exc) } -func downloadTransfer(p *lfs.WrappedPointer) (name, path, oid string, size int64, missing bool) { - path, _ = cfg.Filesystem().ObjectPath(p.Oid) - return p.Name, path, p.Oid, p.Size, false +func downloadTransfer(p *lfs.WrappedPointer) (name, path, oid string, size int64, missing bool, err error) { + path, err = cfg.Filesystem().ObjectPath(p.Oid) + return p.Name, path, p.Oid, p.Size, false, err } // Get user-readable manual install steps for hooks diff --git a/commands/uploader.go b/commands/uploader.go index 3efd6ab4..c478c4c1 100644 --- a/commands/uploader.go +++ b/commands/uploader.go @@ -258,7 +258,7 @@ func (c *uploadContext) UploadPointers(q *tq.TransferQueue, unfiltered ...*lfs.W ExitWithError(err) } - q.Add(t.Name, t.Path, t.Oid, t.Size, t.Missing) + q.Add(t.Name, t.Path, t.Oid, t.Size, t.Missing, nil) c.SetUploaded(p.Oid) } } diff --git a/lfs/gitfilter_smudge.go b/lfs/gitfilter_smudge.go index 110a26d1..6e893a3c 100644 --- a/lfs/gitfilter_smudge.go +++ b/lfs/gitfilter_smudge.go @@ -101,7 +101,7 @@ func (f *GitFilter) downloadFile(writer io.Writer, ptr *Pointer, workingfile, me tq.WithProgressCallback(cb), tq.RemoteRef(f.RemoteRef()), ) - q.Add(filepath.Base(workingfile), mediafile, ptr.Oid, ptr.Size, false) + q.Add(filepath.Base(workingfile), mediafile, ptr.Oid, ptr.Size, false, nil) q.Wait() if errs := q.Errors(); len(errs) > 0 { diff --git a/t/git-lfs-test-server-api/main.go b/t/git-lfs-test-server-api/main.go index 310afd51..f173d723 100644 --- a/t/git-lfs-test-server-api/main.go +++ b/t/git-lfs-test-server-api/main.go @@ -206,7 +206,7 @@ func buildTestData(repo *t.Repo, manifest *tq.Manifest) (oidsExist, oidsMissing if err != nil { return nil, nil, err } - uploadQueue.Add(t.Name, t.Path, t.Oid, t.Size, false) + uploadQueue.Add(t.Name, t.Path, t.Oid, t.Size, false, nil) } uploadQueue.Wait() diff --git a/t/t-fetch.sh b/t/t-fetch.sh index c3119bff..529bc317 100755 --- a/t/t-fetch.sh +++ b/t/t-fetch.sh @@ -619,3 +619,23 @@ begin_test "fetch with invalid remote" grep "Invalid remote name" fetch.log ) end_test + +begin_test "fetch fails when LFS directory has wrong permissions" +( + set -e + + # Windows lacks POSIX permissions. + [ "$IS_WINDOWS" -eq 1 ] && exit 0 + + # Root is exempt from permissions. + [ "$(id -u)" -eq 0 ] && exit 0 + + cd shared + rm -rf .git/lfs/objects + mkdir .git/lfs/objects + chmod 400 .git/lfs/objects + + git lfs fetch 2>&1 | tee fetch.log + grep "error trying to create local storage directory" fetch.log +) +end_test diff --git a/tq/transfer_queue.go b/tq/transfer_queue.go index cfca31b8..abd54d00 100644 --- a/tq/transfer_queue.go +++ b/tq/transfer_queue.go @@ -324,7 +324,12 @@ func NewTransferQueue(dir Direction, manifest *Manifest, remote string, options // // Only one file will be transferred to/from the Path element of the first // transfer. -func (q *TransferQueue) Add(name, path, oid string, size int64, missing bool) { +func (q *TransferQueue) Add(name, path, oid string, size int64, missing bool, err error) { + if err != nil { + q.errorc <- err + return + } + t := &objectTuple{ Name: name, Path: path,