/usr/lib/python2.7/dist-packages/paramiko/sftp_attr.py is in python-paramiko 1.16.0-1ubuntu0.2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | # Copyright (C) 2003-2006 Robey Pointer <robeypointer@gmail.com>
#
# This file is part of paramiko.
#
# Paramiko is free software; you can redistribute it and/or modify it under the
# terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 2.1 of the License, or (at your option)
# any later version.
#
# Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Paramiko; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
import stat
import time
from paramiko.common import x80000000, o700, o70, xffffffff
from paramiko.py3compat import long, b
class SFTPAttributes (object):
"""
Representation of the attributes of a file (or proxied file) for SFTP in
client or server mode. It attemps to mirror the object returned by
`os.stat` as closely as possible, so it may have the following fields,
with the same meanings as those returned by an `os.stat` object:
- ``st_size``
- ``st_uid``
- ``st_gid``
- ``st_mode``
- ``st_atime``
- ``st_mtime``
Because SFTP allows flags to have other arbitrary named attributes, these
are stored in a dict named ``attr``. Occasionally, the filename is also
stored, in ``filename``.
"""
FLAG_SIZE = 1
FLAG_UIDGID = 2
FLAG_PERMISSIONS = 4
FLAG_AMTIME = 8
FLAG_EXTENDED = x80000000
def __init__(self):
"""
Create a new (empty) SFTPAttributes object. All fields will be empty.
"""
self._flags = 0
self.st_size = None
self.st_uid = None
self.st_gid = None
self.st_mode = None
self.st_atime = None
self.st_mtime = None
self.attr = {}
@classmethod
def from_stat(cls, obj, filename=None):
"""
Create an `.SFTPAttributes` object from an existing ``stat`` object (an
object returned by `os.stat`).
:param object obj: an object returned by `os.stat` (or equivalent).
:param str filename: the filename associated with this file.
:return: new `.SFTPAttributes` object with the same attribute fields.
"""
attr = cls()
attr.st_size = obj.st_size
attr.st_uid = obj.st_uid
attr.st_gid = obj.st_gid
attr.st_mode = obj.st_mode
attr.st_atime = obj.st_atime
attr.st_mtime = obj.st_mtime
if filename is not None:
attr.filename = filename
return attr
def __repr__(self):
return '<SFTPAttributes: %s>' % self._debug_str()
### internals...
@classmethod
def _from_msg(cls, msg, filename=None, longname=None):
attr = cls()
attr._unpack(msg)
if filename is not None:
attr.filename = filename
if longname is not None:
attr.longname = longname
return attr
def _unpack(self, msg):
self._flags = msg.get_int()
if self._flags & self.FLAG_SIZE:
self.st_size = msg.get_int64()
if self._flags & self.FLAG_UIDGID:
self.st_uid = msg.get_int()
self.st_gid = msg.get_int()
if self._flags & self.FLAG_PERMISSIONS:
self.st_mode = msg.get_int()
if self._flags & self.FLAG_AMTIME:
self.st_atime = msg.get_int()
self.st_mtime = msg.get_int()
if self._flags & self.FLAG_EXTENDED:
count = msg.get_int()
for i in range(count):
self.attr[msg.get_string()] = msg.get_string()
def _pack(self, msg):
self._flags = 0
if self.st_size is not None:
self._flags |= self.FLAG_SIZE
if (self.st_uid is not None) and (self.st_gid is not None):
self._flags |= self.FLAG_UIDGID
if self.st_mode is not None:
self._flags |= self.FLAG_PERMISSIONS
if (self.st_atime is not None) and (self.st_mtime is not None):
self._flags |= self.FLAG_AMTIME
if len(self.attr) > 0:
self._flags |= self.FLAG_EXTENDED
msg.add_int(self._flags)
if self._flags & self.FLAG_SIZE:
msg.add_int64(self.st_size)
if self._flags & self.FLAG_UIDGID:
msg.add_int(self.st_uid)
msg.add_int(self.st_gid)
if self._flags & self.FLAG_PERMISSIONS:
msg.add_int(self.st_mode)
if self._flags & self.FLAG_AMTIME:
# throw away any fractional seconds
msg.add_int(long(self.st_atime))
msg.add_int(long(self.st_mtime))
if self._flags & self.FLAG_EXTENDED:
msg.add_int(len(self.attr))
for key, val in self.attr.items():
msg.add_string(key)
msg.add_string(val)
return
def _debug_str(self):
out = '[ '
if self.st_size is not None:
out += 'size=%d ' % self.st_size
if (self.st_uid is not None) and (self.st_gid is not None):
out += 'uid=%d gid=%d ' % (self.st_uid, self.st_gid)
if self.st_mode is not None:
out += 'mode=' + oct(self.st_mode) + ' '
if (self.st_atime is not None) and (self.st_mtime is not None):
out += 'atime=%d mtime=%d ' % (self.st_atime, self.st_mtime)
for k, v in self.attr.items():
out += '"%s"=%r ' % (str(k), v)
out += ']'
return out
@staticmethod
def _rwx(n, suid, sticky=False):
if suid:
suid = 2
out = '-r'[n >> 2] + '-w'[(n >> 1) & 1]
if sticky:
out += '-xTt'[suid + (n & 1)]
else:
out += '-xSs'[suid + (n & 1)]
return out
def __str__(self):
"""create a unix-style long description of the file (like ls -l)"""
if self.st_mode is not None:
kind = stat.S_IFMT(self.st_mode)
if kind == stat.S_IFIFO:
ks = 'p'
elif kind == stat.S_IFCHR:
ks = 'c'
elif kind == stat.S_IFDIR:
ks = 'd'
elif kind == stat.S_IFBLK:
ks = 'b'
elif kind == stat.S_IFREG:
ks = '-'
elif kind == stat.S_IFLNK:
ks = 'l'
elif kind == stat.S_IFSOCK:
ks = 's'
else:
ks = '?'
ks += self._rwx((self.st_mode & o700) >> 6, self.st_mode & stat.S_ISUID)
ks += self._rwx((self.st_mode & o70) >> 3, self.st_mode & stat.S_ISGID)
ks += self._rwx(self.st_mode & 7, self.st_mode & stat.S_ISVTX, True)
else:
ks = '?---------'
# compute display date
if (self.st_mtime is None) or (self.st_mtime == xffffffff):
# shouldn't really happen
datestr = '(unknown date)'
else:
if abs(time.time() - self.st_mtime) > 15552000:
# (15552000 = 6 months)
datestr = time.strftime('%d %b %Y', time.localtime(self.st_mtime))
else:
datestr = time.strftime('%d %b %H:%M', time.localtime(self.st_mtime))
filename = getattr(self, 'filename', '?')
# not all servers support uid/gid
uid = self.st_uid
gid = self.st_gid
size = self.st_size
if uid is None:
uid = 0
if gid is None:
gid = 0
if size is None:
size = 0
return '%s 1 %-8d %-8d %8d %-12s %s' % (ks, uid, gid, size, datestr, filename)
def asbytes(self):
return b(str(self))
|