mirror of https://github.com/pkg/sftp.git
Marshal extended data if file info supports it
If the file information returned by ListAt supports the FileInfoExtendedData interface, use it to retrieve extended data and pass it back to the client. In similar fashion, we add the FileInfoUidGid interface to allow for implementations to return uid and gid data, even if the os lacks support in syscall.Stat_t. Signed-off-by: Peter Verraedt <peter@verraedt.be>
This commit is contained in:
parent
971c283182
commit
c632ce6285
31
attrs.go
31
attrs.go
|
@ -69,6 +69,20 @@ func fileInfoFromStat(stat *FileStat, name string) os.FileInfo {
|
|||
}
|
||||
}
|
||||
|
||||
// FileInfoUidGid extends os.FileInfo and adds callbacks for Uid and Gid retrieval,
|
||||
// as an alternative to *syscall.Stat_t objects on unix systems.
|
||||
type FileInfoUidGid interface {
|
||||
os.FileInfo
|
||||
Uid() uint32
|
||||
Gid() uint32
|
||||
}
|
||||
|
||||
// FileInfoUidGid extends os.FileInfo and adds a callbacks for extended data retrieval.
|
||||
type FileInfoExtendedData interface {
|
||||
os.FileInfo
|
||||
Extended() []StatExtended
|
||||
}
|
||||
|
||||
func fileStatFromInfo(fi os.FileInfo) (uint32, *FileStat) {
|
||||
mtime := fi.ModTime().Unix()
|
||||
atime := mtime
|
||||
|
@ -86,5 +100,22 @@ func fileStatFromInfo(fi os.FileInfo) (uint32, *FileStat) {
|
|||
// os specific file stat decoding
|
||||
fileStatFromInfoOs(fi, &flags, fileStat)
|
||||
|
||||
// The call above will include the sshFileXferAttrUIDGID in case
|
||||
// the os.FileInfo can be casted to *syscall.Stat_t on unix.
|
||||
// If fi implements FileInfoUidGid, retrieve Uid, Gid from it instead.
|
||||
if fiExt, ok := fi.(FileInfoUidGid); ok {
|
||||
flags |= sshFileXferAttrUIDGID
|
||||
fileStat.UID = fiExt.Uid()
|
||||
fileStat.GID = fiExt.Gid()
|
||||
}
|
||||
|
||||
// if fi implements FileInfoExtendedData, retrieve extended data from it
|
||||
if fiExt, ok := fi.(FileInfoExtendedData); ok {
|
||||
fileStat.Extended = fiExt.Extended()
|
||||
if len(fileStat.Extended) > 0 {
|
||||
flags |= sshFileXferAttrExtended
|
||||
}
|
||||
}
|
||||
|
||||
return flags, fileStat
|
||||
}
|
||||
|
|
|
@ -60,6 +60,13 @@ func runLs(idLookup NameLookupFileLister, dirent os.FileInfo) string {
|
|||
uid = lsFormatID(sys.UID)
|
||||
gid = lsFormatID(sys.GID)
|
||||
default:
|
||||
if fiExt, ok := dirent.(FileInfoUidGid); ok {
|
||||
uid = lsFormatID(fiExt.Uid())
|
||||
gid = lsFormatID(fiExt.Gid())
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
numLinks, uid, gid = lsLinksUIDGID(dirent)
|
||||
}
|
||||
|
||||
|
|
|
@ -71,6 +71,15 @@ func marshalFileInfo(b []byte, fi os.FileInfo) []byte {
|
|||
b = marshalUint32(b, fileStat.Mtime)
|
||||
}
|
||||
|
||||
if flags&sshFileXferAttrExtended != 0 {
|
||||
b = marshalUint32(b, uint32(len(fileStat.Extended)))
|
||||
|
||||
for _, attr := range fileStat.Extended {
|
||||
b = marshalString(b, attr.ExtType)
|
||||
b = marshalString(b, attr.ExtData)
|
||||
}
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ type StatVFSFileCmder interface {
|
|||
// Note in cases of an error, the error text will be sent to the client.
|
||||
// Called for Methods: List, Stat, Readlink
|
||||
//
|
||||
// Since Filelist returns an os.FileInfo, this can make it non-ideal for impelmenting Readlink.
|
||||
// Since Filelist returns an os.FileInfo, this can make it non-ideal for implementing Readlink.
|
||||
// This is because the Name receiver method defined by that interface defines that it should only return the base name.
|
||||
// However, Readlink is required to be capable of returning essentially any arbitrary valid path relative or absolute.
|
||||
// In order to implement this more expressive requirement, implement [ReadlinkFileLister] which will then be used instead.
|
||||
|
@ -131,11 +131,19 @@ type NameLookupFileLister interface {
|
|||
LookupGroupName(string) string
|
||||
}
|
||||
|
||||
// ListerAt does for file lists what io.ReaderAt does for files.
|
||||
// ListAt should return the number of entries copied and an io.EOF
|
||||
// error if at end of list. This is testable by comparing how many you
|
||||
// copied to how many could be copied (eg. n < len(ls) below).
|
||||
// ListerAt does for file lists what io.ReaderAt does for files, i.e. a []os.FileInfo buffer is passed to the ListAt function
|
||||
// and the entries that are populated in the buffer will be passed to the client.
|
||||
//
|
||||
// ListAt should return the number of entries copied and an io.EOF error if at end of list.
|
||||
// This is testable by comparing how many you copied to how many could be copied (eg. n < len(ls) below).
|
||||
// The copy() builtin is best for the copying.
|
||||
//
|
||||
// Uid and gid information will on unix systems be retrieved from [os.FileInfo.Sys]
|
||||
// if this function returns a [syscall.Stat_t] when called on a populated entry.
|
||||
// Alternatively, if the entry implements [FileInfoUidGid], it will be used for uid and gid information.
|
||||
//
|
||||
// If a populated entry implements [FileInfoExtendedData], extended attributes will also be returned to the client.
|
||||
//
|
||||
// Note in cases of an error, the error text will be sent to the client.
|
||||
type ListerAt interface {
|
||||
ListAt([]os.FileInfo, int64) (int, error)
|
||||
|
|
Loading…
Reference in New Issue