| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | package sftp | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-06 16:12:25 +08:00
										 |  |  | // ssh_FXP_ATTRS support
 | 
					
						
							| 
									
										
										
										
											2023-03-28 01:05:24 +08:00
										 |  |  | // see https://filezilla-project.org/specs/draft-ietf-secsh-filexfer-02.txt#section-5
 | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  | 	sshFileXferAttrSize        = 0x00000001 | 
					
						
							|  |  |  | 	sshFileXferAttrUIDGID      = 0x00000002 | 
					
						
							|  |  |  | 	sshFileXferAttrPermissions = 0x00000004 | 
					
						
							|  |  |  | 	sshFileXferAttrACmodTime   = 0x00000008 | 
					
						
							| 
									
										
										
										
											2021-03-20 18:46:58 +08:00
										 |  |  | 	sshFileXferAttrExtended    = 0x80000000 | 
					
						
							| 
									
										
										
										
											2019-12-27 17:56:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-31 07:36:04 +08:00
										 |  |  | 	sshFileXferAttrAll = sshFileXferAttrSize | sshFileXferAttrUIDGID | sshFileXferAttrPermissions | | 
					
						
							| 
									
										
										
										
											2021-03-20 18:46:58 +08:00
										 |  |  | 		sshFileXferAttrACmodTime | sshFileXferAttrExtended | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-23 11:11:28 +08:00
										 |  |  | // fileInfo is an artificial type designed to satisfy os.FileInfo.
 | 
					
						
							|  |  |  | type fileInfo struct { | 
					
						
							| 
									
										
										
										
											2021-08-11 21:20:30 +08:00
										 |  |  | 	name string | 
					
						
							|  |  |  | 	stat *FileStat | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Name returns the base name of the file.
 | 
					
						
							| 
									
										
										
										
											2014-06-23 18:55:00 +08:00
										 |  |  | func (fi *fileInfo) Name() string { return fi.name } | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Size returns the length in bytes for regular files; system-dependent for others.
 | 
					
						
							| 
									
										
										
										
											2021-08-11 21:20:30 +08:00
										 |  |  | func (fi *fileInfo) Size() int64 { return int64(fi.stat.Size) } | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Mode returns file mode bits.
 | 
					
						
							| 
									
										
										
										
											2024-01-19 08:20:23 +08:00
										 |  |  | func (fi *fileInfo) Mode() os.FileMode { return fi.stat.FileMode() } | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // ModTime returns the last modification time of the file.
 | 
					
						
							| 
									
										
										
										
											2024-01-19 08:20:23 +08:00
										 |  |  | func (fi *fileInfo) ModTime() time.Time { return fi.stat.ModTime() } | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // IsDir returns true if the file is a directory.
 | 
					
						
							| 
									
										
										
										
											2014-06-23 18:55:00 +08:00
										 |  |  | func (fi *fileInfo) IsDir() bool { return fi.Mode().IsDir() } | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-11 21:20:30 +08:00
										 |  |  | func (fi *fileInfo) Sys() interface{} { return fi.stat } | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-12 05:15:09 +08:00
										 |  |  | // FileStat holds the original unmarshalled values from a call to READDIR or
 | 
					
						
							|  |  |  | // *STAT. It is exported for the purposes of accessing the raw values via
 | 
					
						
							|  |  |  | // os.FileInfo.Sys(). It is also used server side to store the unmarshalled
 | 
					
						
							|  |  |  | // values for SetStat.
 | 
					
						
							| 
									
										
										
										
											2014-06-23 11:11:28 +08:00
										 |  |  | type FileStat struct { | 
					
						
							| 
									
										
										
										
											2014-09-27 05:56:26 +08:00
										 |  |  | 	Size     uint64 | 
					
						
							|  |  |  | 	Mode     uint32 | 
					
						
							|  |  |  | 	Mtime    uint32 | 
					
						
							|  |  |  | 	Atime    uint32 | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 	UID      uint32 | 
					
						
							|  |  |  | 	GID      uint32 | 
					
						
							| 
									
										
										
										
											2014-06-23 11:11:28 +08:00
										 |  |  | 	Extended []StatExtended | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-19 08:20:23 +08:00
										 |  |  | // ModTime returns the Mtime SFTP file attribute converted to a time.Time
 | 
					
						
							|  |  |  | func (fs *FileStat) ModTime() time.Time { | 
					
						
							|  |  |  | 	return time.Unix(int64(fs.Mtime), 0) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // AccessTime returns the Atime SFTP file attribute converted to a time.Time
 | 
					
						
							|  |  |  | func (fs *FileStat) AccessTime() time.Time { | 
					
						
							|  |  |  | 	return time.Unix(int64(fs.Atime), 0) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // FileMode returns the Mode SFTP file attribute converted to an os.FileMode
 | 
					
						
							|  |  |  | func (fs *FileStat) FileMode() os.FileMode { | 
					
						
							|  |  |  | 	return toFileMode(fs.Mode) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 04:11:16 +08:00
										 |  |  | // StatExtended contains additional, extended information for a FileStat.
 | 
					
						
							| 
									
										
										
										
											2014-06-23 11:11:28 +08:00
										 |  |  | type StatExtended struct { | 
					
						
							|  |  |  | 	ExtType string | 
					
						
							|  |  |  | 	ExtData string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-11 21:20:30 +08:00
										 |  |  | func fileInfoFromStat(stat *FileStat, name string) os.FileInfo { | 
					
						
							|  |  |  | 	return &fileInfo{ | 
					
						
							|  |  |  | 		name: name, | 
					
						
							|  |  |  | 		stat: stat, | 
					
						
							| 
									
										
										
										
											2014-06-23 11:11:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-15 20:21:45 +08:00
										 |  |  | // 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 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-11 21:20:30 +08:00
										 |  |  | func fileStatFromInfo(fi os.FileInfo) (uint32, *FileStat) { | 
					
						
							| 
									
										
										
										
											2015-09-20 10:09:03 +08:00
										 |  |  | 	mtime := fi.ModTime().Unix() | 
					
						
							|  |  |  | 	atime := mtime | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  | 	var flags uint32 = sshFileXferAttrSize | | 
					
						
							|  |  |  | 		sshFileXferAttrPermissions | | 
					
						
							|  |  |  | 		sshFileXferAttrACmodTime | 
					
						
							| 
									
										
										
										
											2015-09-20 10:09:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-11 21:20:30 +08:00
										 |  |  | 	fileStat := &FileStat{ | 
					
						
							| 
									
										
										
										
											2015-09-20 10:09:03 +08:00
										 |  |  | 		Size:  uint64(fi.Size()), | 
					
						
							|  |  |  | 		Mode:  fromFileMode(fi.Mode()), | 
					
						
							|  |  |  | 		Mtime: uint32(mtime), | 
					
						
							|  |  |  | 		Atime: uint32(atime), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// os specific file stat decoding
 | 
					
						
							| 
									
										
										
										
											2021-08-11 21:20:30 +08:00
										 |  |  | 	fileStatFromInfoOs(fi, &flags, fileStat) | 
					
						
							| 
									
										
										
										
											2015-09-20 10:09:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-15 20:21:45 +08:00
										 |  |  | 	// 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 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-20 10:09:03 +08:00
										 |  |  | 	return flags, fileStat | 
					
						
							|  |  |  | } |