@@ -21,6 +21,7 @@ type Host struct {
2121 Alias string `json:"alias"`
2222 Hostname string `json:"hostname"`
2323 Port int `json:"port"`
24+ TimeoutSec int `json:"timeout_sec,omitempty"`
2425 Group string `json:"group,omitempty"`
2526 Tags []string `json:"tags,omitempty"`
2627 DefaultUser string `json:"default_user,omitempty"`
@@ -92,11 +93,7 @@ func (s *Store) Save() error {
9293 if err != nil {
9394 return err
9495 }
95- tmp := s .path + ".tmp"
96- if err := os .WriteFile (tmp , data , 0600 ); err != nil {
97- return err
98- }
99- return os .Rename (tmp , s .path )
96+ return atomicWrite (s .path , data , 0600 )
10097}
10198
10299func (s * Store ) Add (h Host ) error {
@@ -117,6 +114,9 @@ func (s *Store) Add(h Host) error {
117114 if h .Port == 0 {
118115 h .Port = 22
119116 }
117+ if h .TimeoutSec == 0 {
118+ h .TimeoutSec = 10
119+ }
120120 h .Normalize ()
121121 s .Hosts = append (s .Hosts , h )
122122 return s .Save ()
@@ -199,6 +199,9 @@ func (h *Host) Normalize() {
199199 if h .Port == 0 {
200200 h .Port = 22
201201 }
202+ if h .TimeoutSec <= 0 {
203+ h .TimeoutSec = 10
204+ }
202205
203206 defaultAuth := normalizeAuthType (h .DefaultAuthType )
204207 if defaultAuth == "" {
@@ -403,3 +406,44 @@ func cloneBytes(src []byte) []byte {
403406 copy (out , src )
404407 return out
405408}
409+
410+ func atomicWrite (path string , data []byte , perm os.FileMode ) error {
411+ tmpFile , err := os .CreateTemp (filepath .Dir (path ), filepath .Base (path )+ ".tmp-*" )
412+ if err != nil {
413+ return err
414+ }
415+ tmpPath := tmpFile .Name ()
416+ closed := false
417+ defer func () {
418+ if ! closed {
419+ _ = tmpFile .Close ()
420+ }
421+ _ = os .Remove (tmpPath )
422+ }()
423+
424+ if err := tmpFile .Chmod (perm ); err != nil {
425+ return err
426+ }
427+ if _ , err := tmpFile .Write (data ); err != nil {
428+ return err
429+ }
430+ if err := tmpFile .Sync (); err != nil {
431+ return err
432+ }
433+ if err := tmpFile .Close (); err != nil {
434+ return err
435+ }
436+ closed = true
437+
438+ if err := os .Rename (tmpPath , path ); err != nil {
439+ return err
440+ }
441+
442+ dir , err := os .Open (filepath .Dir (path ))
443+ if err == nil {
444+ _ = dir .Sync ()
445+ _ = dir .Close ()
446+ }
447+
448+ return nil
449+ }
0 commit comments