| 
									
										
										
										
											2021-08-11 23:09:43 +08:00
										 |  |  | package sftp | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2021-08-17 19:40:30 +08:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2021-08-11 23:09:43 +08:00
										 |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"os/user" | 
					
						
							|  |  |  | 	"strconv" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sshfx "github.com/pkg/sftp/internal/encoding/ssh/filexfer" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func lsFormatID(id uint32) string { | 
					
						
							|  |  |  | 	return strconv.FormatUint(uint64(id), 10) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-17 19:40:30 +08:00
										 |  |  | type osIDLookup struct{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (osIDLookup) Filelist(*Request) (ListerAt, error) { | 
					
						
							|  |  |  | 	return nil, errors.New("unimplemented stub") | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (osIDLookup) LookupUserName(uid string) string { | 
					
						
							| 
									
										
										
										
											2021-08-11 23:09:43 +08:00
										 |  |  | 	u, err := user.LookupId(uid) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return uid | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return u.Username | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-17 19:40:30 +08:00
										 |  |  | func (osIDLookup) LookupGroupName(gid string) string { | 
					
						
							| 
									
										
										
										
											2021-08-11 23:09:43 +08:00
										 |  |  | 	g, err := user.LookupGroupId(gid) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return gid | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return g.Name | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // runLs formats the FileInfo as per `ls -l` style, which is in the 'longname' field of a SSH_FXP_NAME entry.
 | 
					
						
							|  |  |  | // This is a fairly simple implementation, just enough to look close to openssh in simple cases.
 | 
					
						
							| 
									
										
										
										
											2021-08-17 19:40:30 +08:00
										 |  |  | func runLs(idLookup NameLookupFileLister, dirent os.FileInfo) string { | 
					
						
							| 
									
										
										
										
											2021-08-11 23:09:43 +08:00
										 |  |  | 	// example from openssh sftp server:
 | 
					
						
							|  |  |  | 	// crw-rw-rw-    1 root     wheel           0 Jul 31 20:52 ttyvd
 | 
					
						
							|  |  |  | 	// format:
 | 
					
						
							|  |  |  | 	// {directory / char device / etc}{rwxrwxrwx}  {number of links} owner group size month day [time (this year) | year (otherwise)] name
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	symPerms := sshfx.FileMode(fromFileMode(dirent.Mode())).String() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var numLinks uint64 = 1 | 
					
						
							|  |  |  | 	uid, gid := "0", "0" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch sys := dirent.Sys().(type) { | 
					
						
							|  |  |  | 	case *sshfx.Attributes: | 
					
						
							|  |  |  | 		uid = lsFormatID(sys.UID) | 
					
						
							|  |  |  | 		gid = lsFormatID(sys.GID) | 
					
						
							|  |  |  | 	case *FileStat: | 
					
						
							|  |  |  | 		uid = lsFormatID(sys.UID) | 
					
						
							|  |  |  | 		gid = lsFormatID(sys.GID) | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2023-03-15 20:21:45 +08:00
										 |  |  | 		if fiExt, ok := dirent.(FileInfoUidGid); ok { | 
					
						
							|  |  |  | 			uid = lsFormatID(fiExt.Uid()) | 
					
						
							|  |  |  | 			gid = lsFormatID(fiExt.Gid()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-11 23:09:43 +08:00
										 |  |  | 		numLinks, uid, gid = lsLinksUIDGID(dirent) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-17 19:40:30 +08:00
										 |  |  | 	if idLookup != nil { | 
					
						
							|  |  |  | 		uid, gid = idLookup.LookupUserName(uid), idLookup.LookupGroupName(gid) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-11 23:09:43 +08:00
										 |  |  | 	mtime := dirent.ModTime() | 
					
						
							|  |  |  | 	date := mtime.Format("Jan 2") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var yearOrTime string | 
					
						
							|  |  |  | 	if mtime.Before(time.Now().AddDate(0, -6, 0)) { | 
					
						
							|  |  |  | 		yearOrTime = mtime.Format("2006") | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		yearOrTime = mtime.Format("15:04") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return fmt.Sprintf("%s %4d %-8s %-8s %8d %s %5s %s", symPerms, numLinks, uid, gid, dirent.Size(), date, yearOrTime, dirent.Name()) | 
					
						
							|  |  |  | } |