blob: 386e6d01f60ef48fafa860313f7d910e7ade8dca [file] [log] [blame]
// Copyright (c) 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
'use strict';
nassh.sftp.packets = {};
/**
* Possible status code values.
*/
nassh.sftp.packets.StatusCodes = {
OK: 0,
EOF: 1,
NO_SUCH_FILE: 2,
PERMISSION_DENIED: 3,
FAILURE: 4,
BAD_MESSAGE: 5,
NO_CONNECTION: 6,
CONNECTION_LOST: 7,
OP_UNSUPPORTED: 8,
};
/**
* SFTP Status Packet containing the request id, status codes, status message
* and language.
*/
nassh.sftp.packets.StatusPacket = function(packet) {
this.requestId = packet.getUint32();
this.code = packet.getUint32();
this.message = packet.getString();
this.lang = packet.getString();
};
/**
* SFTP Data Packet containing the request id and associated data.
*/
nassh.sftp.packets.DataPacket = function(packet) {
this.requestId = packet.getUint32();
this.data = packet.getString();
};
/**
* SFTP Handle Packet containing the request id and a file handle.
*/
nassh.sftp.packets.HandlePacket = function(packet) {
this.requestId = packet.getUint32();
this.handle = packet.getString();
};
/**
* SFTP Name Packet containing the request id, file count and an array of file
* attributes.
*/
nassh.sftp.packets.NamePacket = function(packet) {
this.requestId = packet.getUint32();
this.fileCount = packet.getUint32();
this.files = [];
for(var i = 0; i < this.fileCount; i++) {
var fileName = packet.getString();
var longFileName = packet.getString();
var fileData = nassh.sftp.packets.getFileAttrs(packet);
fileData.filename = fileName;
fileData.long_filename = longFileName;
this.files.push(fileData);
}
};
/**
* SFTP Attrs Packet containing the request id and a file's attributes.
*/
nassh.sftp.packets.AttrsPacket = function(packet) {
this.requestId = packet.getUint32();
this.attrs = nassh.sftp.packets.getFileAttrs(packet);
};
/**
* Unknown Packet containing the request id (potentially garbage) and associated
* data (also potentially garbage).
*/
nassh.sftp.packets.UnknownPacket = function(packet) {
this.requestId = packet.getUint32();
this.data = packet.getData();
};
/**
* Possible SFTP File Transfer flags attributes (SSH_FILEXFER_ATTR_XXX).
*/
nassh.sftp.packets.FileXferAttrs = {
SIZE: 0x00000001,
UIDGID: 0x00000002,
PERMISSIONS: 0x00000004,
ACMODTIME: 0x00000008,
EXTENDED: 0x10000000,
};
/**
* Possible SFTP permission bits.
*
* Note: The RFC says:
* The `permissions' field contains a bit mask of file permissions as
* defined by posix.
* Except that POSIX only defines the bit values for permissions (ones that
* start with S_Ixxx). It does not define the bit values for file types
* (ones that start with S_IFxxx). We use "common" Linux ones for that.
*/
nassh.sftp.packets.PermissionBits = {
SMODE: 0o007777, // Mask for file mode bits.
ISVTX: 0o001000, // Sticky directory.
ISGID: 0o002000, // Setgid.
ISUID: 0o004000, // Setuid.
IFMT: 0o170000, // Mask for IFxxx fields below.
IFCHR: 0o020000, // Character special.
IFDIR: 0o040000, // Directory.
IFBLK: 0o060000, // Block special.
IFREG: 0o100000, // Regular file.
IFIFO: 0o010000, // FIFO special.
IFLNK: 0o120000, // Symbolic link.
IFSOCK: 0o140000, // Socket.
};
/**
* Convert permission bits into a standard UNIX summary.
*
* Typically used in conjunction with AttrsPacket and the permissions field.
*
* The output will look similar to `ls -l`. e.g. "drwxr-xr-x".
*
* @param {integer} bits The permission bits to convert.
* @return {string} The short `ls -l`-like summary.
*/
nassh.sftp.packets.bitsToUnixModeLine = function(bits) {
var ret = '';
// First handle the file type.
var ifmt = bits & nassh.sftp.packets.PermissionBits.IFMT;
var fmtMap = {
[nassh.sftp.packets.PermissionBits.IFCHR]: 'c',
[nassh.sftp.packets.PermissionBits.IFDIR]: 'd',
[nassh.sftp.packets.PermissionBits.IFBLK]: 'b',
[nassh.sftp.packets.PermissionBits.IFREG]: '-',
[nassh.sftp.packets.PermissionBits.IFIFO]: 'p',
[nassh.sftp.packets.PermissionBits.IFLNK]: 'l',
[nassh.sftp.packets.PermissionBits.IFSOCK]: 's',
};
if (fmtMap[ifmt] === null)
ret += '?';
else
ret += fmtMap[ifmt];
// Then handle user/group/other permissions.
function threebits(bits, sid, x, X) {
if (!sid)
x = 'x', X = '-';
return ((bits & 0o4) ? 'r' : '-') +
((bits & 0o2) ? 'w' : '-') +
((bits & 0o1) ? x : X);
}
ret += threebits(bits >> 6, (bits & nassh.sftp.packets.PermissionBits.ISUID),
's', 'S');
ret += threebits(bits >> 3, (bits & nassh.sftp.packets.PermissionBits.IGUID),
's', 'S');
ret += threebits(bits >> 0, (bits & nassh.sftp.packets.PermissionBits.ISVTX),
't', 'T');
return ret;
};
/**
* Given a packet (at the correct offset), will read one file's attributes.
*/
nassh.sftp.packets.getFileAttrs = function(packet) {
var attrs = {};
attrs.flags = packet.getUint32();
if (attrs.flags & nassh.sftp.packets.FileXferAttrs.SIZE) {
attrs.size = packet.getUint64();
}
if (attrs.flags & nassh.sftp.packets.FileXferAttrs.UIDGID) {
attrs.uid = packet.getUint32();
attrs.gid = packet.getUint32();
}
if (attrs.flags & nassh.sftp.packets.FileXferAttrs.PERMISSIONS) {
attrs.permissions = packet.getUint32();
}
if (attrs.flags & nassh.sftp.packets.FileXferAttrs.ACMODTIME) {
attrs.last_accessed = packet.getUint32();
attrs.last_modified = packet.getUint32();
}
if (attrs.flags & nassh.sftp.packets.FileXferAttrs.EXTENDED) {
var extendedCount = packet.getUint32();
attrs.extendedCount = extendedCount;
var extendedData = [];
for(var i = 0; i < extendedCount; i++) {
extendedData.push({
'type': packet.getString(),
'data': packet.getString()
});
}
attrs.extensions = extendedData;
}
return attrs;
};
/**
* Serialize an attribute object back into a packet.
*/
nassh.sftp.packets.setFileAttrs = function(packet, attrs) {
// We only add fields we know how to handle.
packet.setUint32(attrs.flags & (
nassh.sftp.packets.FileXferAttrs.SIZE |
nassh.sftp.packets.FileXferAttrs.UIDGID |
nassh.sftp.packets.FileXferAttrs.PERMISSIONS |
nassh.sftp.packets.FileXferAttrs.ACMODTIME
));
if (attrs.flags & nassh.sftp.packets.FileXferAttrs.SIZE) {
packet.setUint64(attrs.size);
}
if (attrs.flags & nassh.sftp.packets.FileXferAttrs.UIDGID) {
packet.setUint32(attrs.uid);
packet.setUint32(attrs.gid);
}
if (attrs.flags & nassh.sftp.packets.FileXferAttrs.PERMISSIONS) {
packet.setUint32(attrs.permissions);
}
if (attrs.flags & nassh.sftp.packets.FileXferAttrs.ACMODTIME) {
packet.setUint32(attrs.last_accessed);
packet.setUint32(attrs.last_modified);
}
};
/**
* Convert UTC epoch timestamps that we get from the server to local time.
*
* Typically used in conjunction with AttrsPacket and the last_accessed &
* last_modified fields. This is the same thing as "UNIX time".
*
* @param {integer} epoch The epoch time to convert.
* @return {Date} A standard Date object.
*/
nassh.sftp.packets.epochToLocal = function(epoch) {
var date = new Date(0);
date.setUTCSeconds(epoch);
return date;
};
/**
* Possible SFTP Request Packet types
*/
nassh.sftp.packets.RequestPackets = {
INIT: 1,
VERSION: 2,
OPEN: 3,
CLOSE: 4,
READ: 5,
WRITE: 6,
LSTAT: 7,
FSTAT: 8,
SETSTAT: 9,
FSETSTAT: 10,
OPENDIR: 11,
READDIR: 12,
REMOVE: 13,
MKDIR: 14,
RMDIR: 15,
REALPATH: 16,
STAT: 17,
RENAME: 18,
READLINK: 19,
SYMLINK: 20,
};
/**
* Possible SFTP Response Packet types
*/
nassh.sftp.packets.ResponsePackets = {
101: nassh.sftp.packets.StatusPacket,
102: nassh.sftp.packets.HandlePacket,
103: nassh.sftp.packets.DataPacket,
104: nassh.sftp.packets.NamePacket,
105: nassh.sftp.packets.AttrsPacket,
};
/**
* Possible bit flags with open packets.
*/
nassh.sftp.packets.OpenFlags = {
READ: 0x00000001,
WRITE: 0x00000002,
APPEND: 0x00000004,
CREAT: 0x00000008,
TRUNC: 0x00000010,
EXCL: 0x00000020,
};