Skip to content

Commit

Permalink
Merge pull request #553 from peterverraedt/marshal-extended
Browse files Browse the repository at this point in the history
Marshal extended data if file info supports it
  • Loading branch information
puellanivis committed Jul 14, 2023
2 parents 72a484f + c632ce6 commit ec1c8ca
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 5 deletions.
31 changes: 31 additions & 0 deletions attrs.go
Expand Up @@ -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
Expand All @@ -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
}
7 changes: 7 additions & 0 deletions ls_formatting.go
Expand Up @@ -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)
}

Expand Down
9 changes: 9 additions & 0 deletions packet.go
Expand Up @@ -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
}

Expand Down
18 changes: 13 additions & 5 deletions request-interfaces.go
Expand Up @@ -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.
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit ec1c8ca

Please sign in to comment.