Skip to content

Commit 7e3147d

Browse files
committed
fix: make exclusive SFTP creates atomic
1 parent 07fe037 commit 7e3147d

1 file changed

Lines changed: 11 additions & 3 deletions

File tree

sftp/handler.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,12 +149,20 @@ func (h *Handler) Filewrite(request *sftp.Request) (io.WriterAt, error) {
149149
if !h.can(permission) {
150150
return nil, sftp.ErrSSHFxPermissionDenied
151151
}
152-
if exists && flags.Creat && flags.Excl {
152+
openFlags := os.O_RDWR | os.O_TRUNC
153+
if flags.Creat && flags.Excl {
153154
// SSH_FXF_CREAT with SSH_FXF_EXCL is an exclusive create request.
154-
return nil, os.ErrExist
155+
if exists {
156+
return nil, os.ErrExist
157+
}
158+
openFlags = os.O_RDWR | os.O_CREATE | os.O_EXCL
155159
}
156-
f, err := h.fs.Touch(request.Filepath, os.O_RDWR|os.O_TRUNC)
160+
f, err := h.fs.Touch(request.Filepath, openFlags)
157161
if err != nil {
162+
if errors.Is(err, os.ErrExist) {
163+
// Preserve exclusive-create semantics if the file appeared after the pre-check.
164+
return nil, os.ErrExist
165+
}
158166
l.WithField("flags", request.Flags).WithField("error", err).Error("failed to open existing file on system")
159167
return nil, sftp.ErrSSHFxFailure
160168
}

0 commit comments

Comments
 (0)