MCPcopy Index your code
hub / github.com/tailscale/tailscale / runFileGet

Function runFileGet

cmd/tailscale/cli/file.go:765–808  ·  view source on GitHub ↗
(ctx context.Context, args []string)

Source from the content-addressed store, hash-verified

763}
764
765func runFileGet(ctx context.Context, args []string) error {
766 if len(args) != 1 {
767 return errors.New("usage: tailscale file get <target-directory>")
768 }
769 log.SetFlags(0)
770
771 dir := args[0]
772 if dir == "/dev/null" {
773 return wipeInbox(ctx)
774 }
775
776 if fi, err := os.Stat(dir); err != nil || !fi.IsDir() {
777 return fmt.Errorf("%q is not a directory", dir)
778 }
779 if fileGetArgs.loop {
780 for {
781 errs := runFileGetOneBatch(ctx, dir)
782 for _, err := range errs {
783 outln(err)
784 }
785 if len(errs) > 0 {
786 // It's possible whatever caused the error(s) (e.g. conflicting target file,
787 // full disk, unwritable target directory) will re-occur if we try again so
788 // let's back off and not busy loop on error.
789 //
790 // If we've been invoked as:
791 // tailscale file get --conflict=skip ~/Downloads
792 // then any file coming in named the same as one in ~/Downloads will always
793 // appear as an "error" until the user clears it, but other incoming files
794 // should be receivable when they arrive, so let's not wait too long to
795 // check again.
796 time.Sleep(5 * time.Second)
797 }
798 }
799 }
800 errs := runFileGetOneBatch(ctx, dir)
801 if len(errs) == 0 {
802 return nil
803 }
804 for _, err := range errs[:len(errs)-1] {
805 outln(err)
806 }
807 return errs[len(errs)-1]
808}
809
810func wipeInbox(ctx context.Context) error {
811 if fileGetArgs.wait {

Callers

nothing calls this directly

Calls 7

wipeInboxFunction · 0.85
runFileGetOneBatchFunction · 0.85
outlnFunction · 0.85
StatMethod · 0.65
ErrorfMethod · 0.65
NewMethod · 0.45
IsDirMethod · 0.45

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…