| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | package sftp | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-06 16:12:25 +08:00
										 |  |  | // ssh_FXP_ATTRS support
 | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | // see http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-5
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  | 	sshFileXferAttrSize        = 0x00000001 | 
					
						
							|  |  |  | 	sshFileXferAttrUIDGID      = 0x00000002 | 
					
						
							|  |  |  | 	sshFileXferAttrPermissions = 0x00000004 | 
					
						
							|  |  |  | 	sshFileXferAttrACmodTime   = 0x00000008 | 
					
						
							|  |  |  | 	sshFileXferAttrExtented    = 0x80000000 | 
					
						
							| 
									
										
										
										
											2019-12-27 17:56:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-31 07:36:04 +08:00
										 |  |  | 	sshFileXferAttrAll = sshFileXferAttrSize | sshFileXferAttrUIDGID | sshFileXferAttrPermissions | | 
					
						
							|  |  |  | 		sshFileXferAttrACmodTime | sshFileXferAttrExtented | 
					
						
							| 
									
										
										
										
											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 { | 
					
						
							| 
									
										
										
										
											2014-09-27 05:56:26 +08:00
										 |  |  | 	name  string | 
					
						
							|  |  |  | 	size  int64 | 
					
						
							|  |  |  | 	mode  os.FileMode | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | 	mtime time.Time | 
					
						
							| 
									
										
										
										
											2014-09-27 05:56:26 +08:00
										 |  |  | 	sys   interface{} | 
					
						
							| 
									
										
										
										
											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.
 | 
					
						
							| 
									
										
										
										
											2014-06-23 18:55:00 +08:00
										 |  |  | func (fi *fileInfo) Size() int64 { return fi.size } | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Mode returns file mode bits.
 | 
					
						
							| 
									
										
										
										
											2014-06-23 18:55:00 +08:00
										 |  |  | func (fi *fileInfo) Mode() os.FileMode { return fi.mode } | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // ModTime returns the last modification time of the file.
 | 
					
						
							| 
									
										
										
										
											2014-06-23 18:55:00 +08:00
										 |  |  | func (fi *fileInfo) ModTime() time.Time { return fi.mtime } | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-23 18:55:00 +08:00
										 |  |  | func (fi *fileInfo) Sys() interface{} { return fi.sys } | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func fileInfoFromStat(st *FileStat, name string) os.FileInfo { | 
					
						
							|  |  |  | 	fs := &fileInfo{ | 
					
						
							| 
									
										
										
										
											2014-09-27 05:56:26 +08:00
										 |  |  | 		name:  name, | 
					
						
							|  |  |  | 		size:  int64(st.Size), | 
					
						
							|  |  |  | 		mode:  toFileMode(st.Mode), | 
					
						
							| 
									
										
										
										
											2014-06-23 11:11:28 +08:00
										 |  |  | 		mtime: time.Unix(int64(st.Mtime), 0), | 
					
						
							| 
									
										
										
										
											2014-09-27 05:56:26 +08:00
										 |  |  | 		sys:   st, | 
					
						
							| 
									
										
										
										
											2014-06-23 11:11:28 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return fs | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-20 10:09:03 +08:00
										 |  |  | func fileStatFromInfo(fi os.FileInfo) (uint32, FileStat) { | 
					
						
							|  |  |  | 	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
										 |  |  | 
 | 
					
						
							|  |  |  | 	fileStat := FileStat{ | 
					
						
							|  |  |  | 		Size:  uint64(fi.Size()), | 
					
						
							|  |  |  | 		Mode:  fromFileMode(fi.Mode()), | 
					
						
							|  |  |  | 		Mtime: uint32(mtime), | 
					
						
							|  |  |  | 		Atime: uint32(atime), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// os specific file stat decoding
 | 
					
						
							|  |  |  | 	fileStatFromInfoOs(fi, &flags, &fileStat) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return flags, fileStat | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-23 11:11:28 +08:00
										 |  |  | func unmarshalAttrs(b []byte) (*FileStat, []byte) { | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | 	flags, b := unmarshalUint32(b) | 
					
						
							| 
									
										
										
										
											2018-01-10 07:29:55 +08:00
										 |  |  | 	return getFileStat(flags, b) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func getFileStat(flags uint32, b []byte) (*FileStat, []byte) { | 
					
						
							| 
									
										
										
										
											2014-06-23 18:55:00 +08:00
										 |  |  | 	var fs FileStat | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  | 	if flags&sshFileXferAttrSize == sshFileXferAttrSize { | 
					
						
							| 
									
										
										
										
											2019-12-24 16:37:32 +08:00
										 |  |  | 		fs.Size, b, _ = unmarshalUint64Safe(b) | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  | 	if flags&sshFileXferAttrUIDGID == sshFileXferAttrUIDGID { | 
					
						
							| 
									
										
										
										
											2019-12-24 16:37:32 +08:00
										 |  |  | 		fs.UID, b, _ = unmarshalUint32Safe(b) | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  | 	if flags&sshFileXferAttrUIDGID == sshFileXferAttrUIDGID { | 
					
						
							| 
									
										
										
										
											2019-12-24 16:37:32 +08:00
										 |  |  | 		fs.GID, b, _ = unmarshalUint32Safe(b) | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  | 	if flags&sshFileXferAttrPermissions == sshFileXferAttrPermissions { | 
					
						
							| 
									
										
										
										
											2019-12-24 16:37:32 +08:00
										 |  |  | 		fs.Mode, b, _ = unmarshalUint32Safe(b) | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  | 	if flags&sshFileXferAttrACmodTime == sshFileXferAttrACmodTime { | 
					
						
							| 
									
										
										
										
											2019-12-24 16:37:32 +08:00
										 |  |  | 		fs.Atime, b, _ = unmarshalUint32Safe(b) | 
					
						
							|  |  |  | 		fs.Mtime, b, _ = unmarshalUint32Safe(b) | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  | 	if flags&sshFileXferAttrExtented == sshFileXferAttrExtented { | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | 		var count uint32 | 
					
						
							| 
									
										
										
										
											2019-12-24 16:37:32 +08:00
										 |  |  | 		count, b, _ = unmarshalUint32Safe(b) | 
					
						
							| 
									
										
										
										
											2018-02-16 03:17:19 +08:00
										 |  |  | 		ext := make([]StatExtended, count) | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | 		for i := uint32(0); i < count; i++ { | 
					
						
							| 
									
										
										
										
											2014-06-23 11:11:28 +08:00
										 |  |  | 			var typ string | 
					
						
							|  |  |  | 			var data string | 
					
						
							| 
									
										
										
										
											2019-12-24 16:37:32 +08:00
										 |  |  | 			typ, b, _ = unmarshalStringSafe(b) | 
					
						
							|  |  |  | 			data, b, _ = unmarshalStringSafe(b) | 
					
						
							| 
									
										
										
										
											2014-09-27 05:56:26 +08:00
										 |  |  | 			ext[i] = StatExtended{typ, data} | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-06-23 18:55:00 +08:00
										 |  |  | 		fs.Extended = ext | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-06-23 18:55:00 +08:00
										 |  |  | 	return &fs, b | 
					
						
							| 
									
										
										
										
											2013-11-05 13:28:45 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-11-05 14:21:30 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | func marshalFileInfo(b []byte, fi os.FileInfo) []byte { | 
					
						
							|  |  |  | 	// attributes variable struct, and also variable per protocol version
 | 
					
						
							|  |  |  | 	// spec version 3 attributes:
 | 
					
						
							|  |  |  | 	// uint32   flags
 | 
					
						
							|  |  |  | 	// uint64   size           present only if flag SSH_FILEXFER_ATTR_SIZE
 | 
					
						
							|  |  |  | 	// uint32   uid            present only if flag SSH_FILEXFER_ATTR_UIDGID
 | 
					
						
							|  |  |  | 	// uint32   gid            present only if flag SSH_FILEXFER_ATTR_UIDGID
 | 
					
						
							|  |  |  | 	// uint32   permissions    present only if flag SSH_FILEXFER_ATTR_PERMISSIONS
 | 
					
						
							|  |  |  | 	// uint32   atime          present only if flag SSH_FILEXFER_ACMODTIME
 | 
					
						
							|  |  |  | 	// uint32   mtime          present only if flag SSH_FILEXFER_ACMODTIME
 | 
					
						
							|  |  |  | 	// uint32   extended_count present only if flag SSH_FILEXFER_ATTR_EXTENDED
 | 
					
						
							|  |  |  | 	// string   extended_type
 | 
					
						
							|  |  |  | 	// string   extended_data
 | 
					
						
							|  |  |  | 	// ...      more extended data (extended_type - extended_data pairs),
 | 
					
						
							|  |  |  | 	// 	   so that number of pairs equals extended_count
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-20 10:09:03 +08:00
										 |  |  | 	flags, fileStat := fileStatFromInfo(fi) | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-20 10:09:03 +08:00
										 |  |  | 	b = marshalUint32(b, flags) | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  | 	if flags&sshFileXferAttrSize != 0 { | 
					
						
							| 
									
										
										
										
											2015-09-20 10:09:03 +08:00
										 |  |  | 		b = marshalUint64(b, fileStat.Size) | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  | 	if flags&sshFileXferAttrUIDGID != 0 { | 
					
						
							| 
									
										
										
										
											2016-01-05 05:15:21 +08:00
										 |  |  | 		b = marshalUint32(b, fileStat.UID) | 
					
						
							|  |  |  | 		b = marshalUint32(b, fileStat.GID) | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  | 	if flags&sshFileXferAttrPermissions != 0 { | 
					
						
							| 
									
										
										
										
											2015-09-20 10:09:03 +08:00
										 |  |  | 		b = marshalUint32(b, fileStat.Mode) | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2019-08-30 23:04:37 +08:00
										 |  |  | 	if flags&sshFileXferAttrACmodTime != 0 { | 
					
						
							| 
									
										
										
										
											2015-09-20 10:09:03 +08:00
										 |  |  | 		b = marshalUint32(b, fileStat.Atime) | 
					
						
							|  |  |  | 		b = marshalUint32(b, fileStat.Mtime) | 
					
						
							| 
									
										
										
										
											2015-07-25 16:19:29 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return b | 
					
						
							|  |  |  | } |