Skip to content

Conversation

@theraphim
Copy link
Contributor

The error codes starting from 9 are defined internally and can be returned by the server, but without exported error constants it's impractical to match on and handle these errors.

This change adds Err constants and text error strings for these codes.

Copy link
Collaborator

@puellanivis puellanivis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error codes starting from 32 can also possibly be returned from the server. But we’re not supporting them because they are not yet defined.

In a similar vein, this package specifically only supports https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt for which these errors are also not defined, and so no server using this package should be returning them, and since this package’s client has not negotiated an upgrade of version, a properly compliant server should also never return these codes.

If anyone does want to use these extended error codes, then I would recommend they instead switch to the dev-v2 branch, which has taken an intentional approach towards supporting these errors in its encoding/ssh/filexfer package.

ErrSshFxNoConnection = ErrSSHFxNoConnection
ErrSshFxConnectionLost = ErrSSHFxConnectionLost
ErrSshFxOpUnsupported = ErrSSHFxOpUnsupported
ErrSshFxInvalidHandle = ErrSSHFxInvalidHandle
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These error codes are deprecated. We should not be adding any new ones.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines 35 to 76
case ErrSSHFxOk:
return "OK"
return "Success"
case ErrSSHFxEOF:
return "EOF"
return "An attempt to read past the end-of-file was made; or, there are no more directory entries to return."
case ErrSSHFxNoSuchFile:
return "no such file"
return "A reference was made to a file which does not exist."
case ErrSSHFxPermissionDenied:
return "permission denied"
return "The user does not have sufficient permissions to perform the operation."
case ErrSSHFxFailure:
return "An error occurred, but no specific error code exists to describe the failure."
case ErrSSHFxBadMessage:
return "bad message"
return "A badly formatted packet or other SFTP protocol incompatibility was detected."
case ErrSSHFxNoConnection:
return "no connection"
return "There is no connection to the server."
case ErrSSHFxConnectionLost:
return "connection lost"
return "The connection to the server was lost."
case ErrSSHFxOpUnsupported:
return "operation unsupported"
return "An attempted operation could not be completed by the server because the server does not support the operation."
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not change the error strings returned by any previously provided errors, as this would be a breaking change of behavior.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines 77 to 122
case ErrSSHFxInvalidHandle:
return "The handle value was invalid."
case ErrSSHFxNoSuchPath:
return "The file path does not exist or is invalid."
case ErrSSHFxFileAlreadyExists:
return "The file already exists."
case ErrSSHFxWriteProtect:
return "The file is on read-only media, or the media is write protected."
case ErrSSHFxNoMedia:
return "The requested operation cannot be completed because there is no media available in the drive."
case ErrSSHFxNoSpaceOnFilesystem:
return "The requested operation cannot be completed because there is insufficient free space on the filesystem."
case ErrSSHFxQuotaExceeded:
return "The operation cannot be completed because it would exceed the user's storage quota."
case ErrSSHFxUnknownPrincipal:
return "A principal referenced by the request (either the 'owner', 'group', or 'who' field of an ACL), was unknown."
case ErrSSHFxLockConflict:
return "The file could not be opened because it is locked by another process."
case ErrSSHFxDirNotEmpty:
return "The directory is not empty."
case ErrSSHFxNotADirectory:
return "The specified file is not a directory."
case ErrSSHFxInvalidFilename:
return "The filename is not valid."
case ErrSSHFxLinkLoop:
return "Too many symbolic links encountered or, an SSH_FXF_NOFOLLOW open encountered a symbolic link as the final component."
case ErrSSHFxCannotDelete:
return "The file cannot be deleted."
case ErrSSHFxInvalidParameter:
return "One of the parameters was out of range, or the parameters specified cannot be used together."
case ErrSSHFxFileIsADirectory:
return "The specified file was a directory in a context where a directory cannot be used."
case ErrSSHFxByteRangeLockConflict:
return "A read or write operation failed because another process's mandatory byte-range lock overlaps with the request."
case ErrSSHFxByteRangeLockRefused:
return "A request for a byte range lock was refused."
case ErrSSHFxDeletePending:
return "An operation was attempted on a file for which a delete operation is pending."
case ErrSSHFxFileCorrupt:
return "The file is corrupt; an filesystem integrity check should be run."
case ErrSSHFxOwnerInvalid:
return "The principal specified can not be assigned as an owner of a file."
case ErrSSHFxGroupInvalid:
return "The principal specified can not be assigned as the primary group of a file."
case ErrSSHFxNoMatchingByteRangeLock:
return "The requested operation could not be completed because the specified byte range lock has not been granted."
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://go.dev/wiki/CodeReviewComments#error-strings Do not capitalize error strings, and do not replace short simple codes with long verbose explanations of those errors.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed the capitalization and the dot at the end. As for the text, I think there's an opportunity to return a meaningful message if we do not need to care about backwards compatibility. That said, if you insist, I can put in some boring names based on the error constant.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As for the text, I think there's an opportunity to return a meaningful message if we do not need to care about backwards compatibility.

Hyrum’s law dictates that we cannot ever know exactly who is depending on what. That’s why I’m recommending keeping the old strings. If you’ll notice, dev-v2 switches the error strings. This is the appropriate place to recommend new error strings, where the v1 compat guarantees are not applicable.

With the original strings for the original messages in place, now the overly verbose new messages do not fit in context. While I can understand the depiction of these strings as “boring”, that’s what is already here. Having such a dichotomy between the two kinds of errors is dissonant, and a violation of the principle of least surprise.

The error codes starting from 9 are defined internally and can be
returned by the server, but without exported error constants it's
impractical to match on and handle these errors.

This change adds Err constants and text error strings for these codes.
@puellanivis
Copy link
Collaborator

I repeat that adding this feature to the v1 branch seems inappropriate when this functionality is already provided intentionally by the v2 branch. If we had more testers using the dev-v2 branch, then we could be confident enough to release a v2.0.0-alpha (perhaps I should just do this anyways).

With a v2 in the wings, I feel a feature freeze of the v1 implementation is appropriate. There are already bugs that impact v1 branch but not the v2 branch, because implementing them in the v1 branch would require major refactoring that would be essentially equivalent to just redoing most of the dev-v2 branch anyways.

@theraphim
Copy link
Contributor Author

Some of my colleagues use this package, to some extent because I used it 10 years ago, to talk to various network devices (and you know how quirky the protocol support can be for these; there should be a commit in the history with my name on it related to that).
While I moved on from that project, the ongoing maintenance is done by someone else. I don't think it's realistic to ask them to rewrite that piece of infrastructure on a short notice to a branch which is essentially unpublished and untested (at least what the readme says). So I thought that exposing the error codes should be relatively simple change - it doesn't add any functionality per se, just makes it possible to match on errors, and I thought it will be useful to community.

It's your decision after all, if this is not accepted I'll just update my private fork.

Thanks.

@puellanivis
Copy link
Collaborator

Yeah, I understand how simple the change is, and why it might be useful… it’s just more of a “yeah, but technically all of those are explicitly unsupported by the version we’re supporting.” They might be defined, but also… not really. 😩

It’s a rough choice especially when just about everything stopped supporting any version except the one we’re on. Like, I believe they’re trying to start up a newest version, and the plan is basically to reset back to this version, because no one was really ever supporting anything beyond this version. 🤦‍♀️

@drakkan What’s your perspective on this? I don’t want to be heavy handed here, especially when I’m conflicted even myself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants