1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-24 16:52:24 +00:00

Propagate file permissions in both directions in Unix pscp and psftp.

I think I have to consider this to be a separate but related change to
the wishlist item 'pscp-filemodes'; that was written before the Unix
port existed, and referred to the ability to configure the permissions
used for files copied from Windows to Unix - which is still not done.

[originally from svn r9260]
This commit is contained in:
Simon Tatham 2011-08-11 17:59:30 +00:00
parent f14953d9e9
commit 5c00b581c8
7 changed files with 81 additions and 31 deletions

32
pscp.c
View File

@ -830,12 +830,13 @@ int scp_send_filetimes(unsigned long mtime, unsigned long atime)
} }
} }
int scp_send_filename(char *name, uint64 size, int modes) int scp_send_filename(char *name, uint64 size, int permissions)
{ {
if (using_sftp) { if (using_sftp) {
char *fullname; char *fullname;
struct sftp_packet *pktin; struct sftp_packet *pktin;
struct sftp_request *req, *rreq; struct sftp_request *req, *rreq;
struct fxp_attrs attrs;
if (scp_sftp_targetisdir) { if (scp_sftp_targetisdir) {
fullname = dupcat(scp_sftp_remotepath, "/", name, NULL); fullname = dupcat(scp_sftp_remotepath, "/", name, NULL);
@ -843,8 +844,12 @@ int scp_send_filename(char *name, uint64 size, int modes)
fullname = dupstr(scp_sftp_remotepath); fullname = dupstr(scp_sftp_remotepath);
} }
attrs.flags = 0;
PUT_PERMISSIONS(attrs, permissions);
sftp_register(req = fxp_open_send(fullname, SSH_FXF_WRITE | sftp_register(req = fxp_open_send(fullname, SSH_FXF_WRITE |
SSH_FXF_CREAT | SSH_FXF_TRUNC)); SSH_FXF_CREAT | SSH_FXF_TRUNC,
&attrs));
rreq = sftp_find_request(pktin = sftp_recv()); rreq = sftp_find_request(pktin = sftp_recv());
assert(rreq == req); assert(rreq == req);
scp_sftp_filehandle = fxp_open_recv(pktin, rreq); scp_sftp_filehandle = fxp_open_recv(pktin, rreq);
@ -864,7 +869,9 @@ int scp_send_filename(char *name, uint64 size, int modes)
char buf[40]; char buf[40];
char sizestr[40]; char sizestr[40];
uint64_decimal(size, sizestr); uint64_decimal(size, sizestr);
sprintf(buf, "C%04o %s ", modes, sizestr); if (permissions < 0)
permissions = 0644;
sprintf(buf, "C%04o %s ", (int)(permissions & 07777), sizestr);
back->send(backhandle, buf, strlen(buf)); back->send(backhandle, buf, strlen(buf));
back->send(backhandle, name, strlen(name)); back->send(backhandle, name, strlen(name));
back->send(backhandle, "\n", 1); back->send(backhandle, "\n", 1);
@ -1144,7 +1151,7 @@ struct scp_sink_action {
int action; /* FILE, DIR, ENDDIR */ int action; /* FILE, DIR, ENDDIR */
char *buf; /* will need freeing after use */ char *buf; /* will need freeing after use */
char *name; /* filename or dirname (not ENDDIR) */ char *name; /* filename or dirname (not ENDDIR) */
int mode; /* access mode (not ENDDIR) */ long permissions; /* access permissions (not ENDDIR) */
uint64 size; /* file size (not ENDDIR) */ uint64 size; /* file size (not ENDDIR) */
int settime; /* 1 if atime and mtime are filled */ int settime; /* 1 if atime and mtime are filled */
unsigned long atime, mtime; /* access times for the file */ unsigned long atime, mtime; /* access times for the file */
@ -1370,7 +1377,7 @@ int scp_get_sink_action(struct scp_sink_action *act)
act->buf = dupstr(stripslashes(fname, 0)); act->buf = dupstr(stripslashes(fname, 0));
act->name = act->buf; act->name = act->buf;
act->size = uint64_make(0,0); /* duhh, it's a directory */ act->size = uint64_make(0,0); /* duhh, it's a directory */
act->mode = 07777 & attrs.permissions; act->permissions = 07777 & attrs.permissions;
if (scp_sftp_preserve && if (scp_sftp_preserve &&
(attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) { (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) {
act->atime = attrs.atime; act->atime = attrs.atime;
@ -1392,7 +1399,7 @@ int scp_get_sink_action(struct scp_sink_action *act)
act->size = attrs.size; act->size = attrs.size;
} else } else
act->size = uint64_make(ULONG_MAX,ULONG_MAX); /* no idea */ act->size = uint64_make(ULONG_MAX,ULONG_MAX); /* no idea */
act->mode = 07777 & attrs.permissions; act->permissions = 07777 & attrs.permissions;
if (scp_sftp_preserve && if (scp_sftp_preserve &&
(attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) { (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) {
act->atime = attrs.atime; act->atime = attrs.atime;
@ -1474,7 +1481,8 @@ int scp_get_sink_action(struct scp_sink_action *act)
{ {
char sizestr[40]; char sizestr[40];
if (sscanf(act->buf, "%o %s %n", &act->mode, sizestr, &i) != 2) if (sscanf(act->buf, "%lo %s %n", &act->permissions,
sizestr, &i) != 2)
bump("Protocol error: Illegal file descriptor format"); bump("Protocol error: Illegal file descriptor format");
act->size = uint64_from_decimal(sizestr); act->size = uint64_from_decimal(sizestr);
act->name = act->buf + i; act->name = act->buf + i;
@ -1489,7 +1497,8 @@ int scp_accept_filexfer(void)
struct sftp_packet *pktin; struct sftp_packet *pktin;
struct sftp_request *req, *rreq; struct sftp_request *req, *rreq;
sftp_register(req = fxp_open_send(scp_sftp_currentname, SSH_FXF_READ)); sftp_register(req = fxp_open_send(scp_sftp_currentname, SSH_FXF_READ,
NULL));
rreq = sftp_find_request(pktin = sftp_recv()); rreq = sftp_find_request(pktin = sftp_recv());
assert(rreq == req); assert(rreq == req);
scp_sftp_filehandle = fxp_open_recv(pktin, rreq); scp_sftp_filehandle = fxp_open_recv(pktin, rreq);
@ -1609,6 +1618,7 @@ static void source(char *src)
{ {
uint64 size; uint64 size;
unsigned long mtime, atime; unsigned long mtime, atime;
long permissions;
char *last; char *last;
RFile *f; RFile *f;
int attr; int attr;
@ -1656,7 +1666,7 @@ static void source(char *src)
if (last == src && strchr(src, ':') != NULL) if (last == src && strchr(src, ':') != NULL)
last = strchr(src, ':') + 1; last = strchr(src, ':') + 1;
f = open_existing_file(src, &size, &mtime, &atime); f = open_existing_file(src, &size, &mtime, &atime, &permissions);
if (f == NULL) { if (f == NULL) {
run_err("%s: Cannot open file", src); run_err("%s: Cannot open file", src);
return; return;
@ -1671,7 +1681,7 @@ static void source(char *src)
uint64_decimal(size, sizestr); uint64_decimal(size, sizestr);
tell_user(stderr, "Sending file %s, size=%s", last, sizestr); tell_user(stderr, "Sending file %s, size=%s", last, sizestr);
} }
if (scp_send_filename(last, size, 0644)) if (scp_send_filename(last, size, permissions))
return; return;
stat_bytes = uint64_make(0,0); stat_bytes = uint64_make(0,0);
@ -1888,7 +1898,7 @@ static void sink(char *targ, char *src)
continue; continue;
} }
f = open_new_file(destfname); f = open_new_file(destfname, act.permissions);
if (f == NULL) { if (f == NULL) {
run_err("%s: Cannot create file", destfname); run_err("%s: Cannot create file", destfname);
continue; continue;

24
psftp.c
View File

@ -212,6 +212,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
uint64 offset; uint64 offset;
WFile *file; WFile *file;
int ret, shown_err = FALSE; int ret, shown_err = FALSE;
struct fxp_attrs attrs;
/* /*
* In recursive mode, see if we're dealing with a directory. * In recursive mode, see if we're dealing with a directory.
@ -219,7 +220,6 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
* subsequent FXP_OPEN will return a usable error message.) * subsequent FXP_OPEN will return a usable error message.)
*/ */
if (recurse) { if (recurse) {
struct fxp_attrs attrs;
int result; int result;
sftp_register(req = fxp_stat_send(fname)); sftp_register(req = fxp_stat_send(fname));
@ -383,7 +383,13 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
} }
} }
sftp_register(req = fxp_open_send(fname, SSH_FXF_READ)); sftp_register(req = fxp_stat_send(fname));
rreq = sftp_find_request(pktin = sftp_recv());
assert(rreq == req);
if (!fxp_stat_recv(pktin, rreq, &attrs))
attrs.flags = 0;
sftp_register(req = fxp_open_send(fname, SSH_FXF_READ, NULL));
rreq = sftp_find_request(pktin = sftp_recv()); rreq = sftp_find_request(pktin = sftp_recv());
assert(rreq == req); assert(rreq == req);
fh = fxp_open_recv(pktin, rreq); fh = fxp_open_recv(pktin, rreq);
@ -396,7 +402,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
if (restart) { if (restart) {
file = open_existing_wfile(outfname, NULL); file = open_existing_wfile(outfname, NULL);
} else { } else {
file = open_new_file(outfname); file = open_new_file(outfname, GET_PERMISSIONS(attrs));
} }
if (!file) { if (!file) {
@ -500,6 +506,8 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
uint64 offset; uint64 offset;
RFile *file; RFile *file;
int ret, err, eof; int ret, err, eof;
struct fxp_attrs attrs;
long permissions;
/* /*
* In recursive mode, see if we're dealing with a directory. * In recursive mode, see if we're dealing with a directory.
@ -507,7 +515,6 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
* subsequent fopen will return an error message.) * subsequent fopen will return an error message.)
*/ */
if (recurse && file_type(fname) == FILE_TYPE_DIRECTORY) { if (recurse && file_type(fname) == FILE_TYPE_DIRECTORY) {
struct fxp_attrs attrs;
int result; int result;
int nnames, namesize; int nnames, namesize;
char *name, **ournames; char *name, **ournames;
@ -630,16 +637,19 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
return 1; return 1;
} }
file = open_existing_file(fname, NULL, NULL, NULL); file = open_existing_file(fname, NULL, NULL, NULL, &permissions);
if (!file) { if (!file) {
printf("local: unable to open %s\n", fname); printf("local: unable to open %s\n", fname);
return 0; return 0;
} }
attrs.flags = 0;
PUT_PERMISSIONS(attrs, permissions);
if (restart) { if (restart) {
sftp_register(req = fxp_open_send(outfname, SSH_FXF_WRITE)); sftp_register(req = fxp_open_send(outfname, SSH_FXF_WRITE, &attrs));
} else { } else {
sftp_register(req = fxp_open_send(outfname, SSH_FXF_WRITE | sftp_register(req = fxp_open_send(outfname, SSH_FXF_WRITE |
SSH_FXF_CREAT | SSH_FXF_TRUNC)); SSH_FXF_CREAT | SSH_FXF_TRUNC,
&attrs));
} }
rreq = sftp_find_request(pktin = sftp_recv()); rreq = sftp_find_request(pktin = sftp_recv());
assert(rreq == req); assert(rreq == req);

View File

@ -85,15 +85,17 @@ void gui_enable(char *arg);
*/ */
typedef struct RFile RFile; typedef struct RFile RFile;
typedef struct WFile WFile; typedef struct WFile WFile;
/* Output params size, mtime and atime can all be NULL if desired */ /* Output params size, perms, mtime and atime can all be NULL if
* desired. perms will be -1 if the OS does not support POSIX permissions. */
RFile *open_existing_file(char *name, uint64 *size, RFile *open_existing_file(char *name, uint64 *size,
unsigned long *mtime, unsigned long *atime); unsigned long *mtime, unsigned long *atime,
long *perms);
WFile *open_existing_wfile(char *name, uint64 *size); WFile *open_existing_wfile(char *name, uint64 *size);
/* Returns <0 on error, 0 on eof, or number of bytes read, as usual */ /* Returns <0 on error, 0 on eof, or number of bytes read, as usual */
int read_from_file(RFile *f, void *buffer, int length); int read_from_file(RFile *f, void *buffer, int length);
/* Closes and frees the RFile */ /* Closes and frees the RFile */
void close_rfile(RFile *f); void close_rfile(RFile *f);
WFile *open_new_file(char *name); WFile *open_new_file(char *name, long perms);
/* Returns <0 on error, 0 on eof, or number of bytes written, as usual */ /* Returns <0 on error, 0 on eof, or number of bytes written, as usual */
int write_to_file(WFile *f, void *buffer, int length); int write_to_file(WFile *f, void *buffer, int length);
void set_file_times(WFile *f, unsigned long mtime, unsigned long atime); void set_file_times(WFile *f, unsigned long mtime, unsigned long atime);

8
sftp.c
View File

@ -548,7 +548,8 @@ char *fxp_realpath_recv(struct sftp_packet *pktin, struct sftp_request *req)
/* /*
* Open a file. * Open a file.
*/ */
struct sftp_request *fxp_open_send(char *path, int type) struct sftp_request *fxp_open_send(char *path, int type,
struct fxp_attrs *attrs)
{ {
struct sftp_request *req = sftp_alloc_request(); struct sftp_request *req = sftp_alloc_request();
struct sftp_packet *pktout; struct sftp_packet *pktout;
@ -557,7 +558,10 @@ struct sftp_request *fxp_open_send(char *path, int type)
sftp_pkt_adduint32(pktout, req->id); sftp_pkt_adduint32(pktout, req->id);
sftp_pkt_addstring(pktout, path); sftp_pkt_addstring(pktout, path);
sftp_pkt_adduint32(pktout, type); sftp_pkt_adduint32(pktout, type);
sftp_pkt_adduint32(pktout, 0); /* (FIXME) empty ATTRS structure */ if (attrs)
sftp_pkt_addattrs(pktout, *attrs);
else
sftp_pkt_adduint32(pktout, 0); /* empty ATTRS structure */
sftp_send(pktout); sftp_send(pktout);
return req; return req;

19
sftp.h
View File

@ -82,6 +82,19 @@ struct fxp_attrs {
unsigned long mtime; unsigned long mtime;
}; };
/*
* Copy between the possibly-unused permissions field in an fxp_attrs
* and a possibly-negative integer containing the same permissions.
*/
#define PUT_PERMISSIONS(attrs, perms) \
((perms) >= 0 ? \
((attrs).flags |= SSH_FILEXFER_ATTR_PERMISSIONS, \
(attrs).permissions = (perms)) : \
((attrs).flags &= ~SSH_FILEXFER_ATTR_PERMISSIONS))
#define GET_PERMISSIONS(attrs) \
((attrs).flags & SSH_FILEXFER_ATTR_PERMISSIONS ? \
(attrs).permissions : -1)
struct fxp_handle { struct fxp_handle {
char *hstring; char *hstring;
int hlen; int hlen;
@ -116,9 +129,11 @@ struct sftp_request *fxp_realpath_send(char *path);
char *fxp_realpath_recv(struct sftp_packet *pktin, struct sftp_request *req); char *fxp_realpath_recv(struct sftp_packet *pktin, struct sftp_request *req);
/* /*
* Open a file. * Open a file. 'attrs' contains attributes to be applied to the file
* if it's being created.
*/ */
struct sftp_request *fxp_open_send(char *path, int type); struct sftp_request *fxp_open_send(char *path, int type,
struct fxp_attrs *attrs);
struct fxp_handle *fxp_open_recv(struct sftp_packet *pktin, struct fxp_handle *fxp_open_recv(struct sftp_packet *pktin,
struct sftp_request *req); struct sftp_request *req);

View File

@ -125,7 +125,8 @@ struct RFile {
}; };
RFile *open_existing_file(char *name, uint64 *size, RFile *open_existing_file(char *name, uint64 *size,
unsigned long *mtime, unsigned long *atime) unsigned long *mtime, unsigned long *atime,
long *perms)
{ {
int fd; int fd;
RFile *ret; RFile *ret;
@ -137,7 +138,7 @@ RFile *open_existing_file(char *name, uint64 *size,
ret = snew(RFile); ret = snew(RFile);
ret->fd = fd; ret->fd = fd;
if (size || mtime || atime) { if (size || mtime || atime || perms) {
struct stat statbuf; struct stat statbuf;
if (fstat(fd, &statbuf) < 0) { if (fstat(fd, &statbuf) < 0) {
fprintf(stderr, "%s: stat: %s\n", name, strerror(errno)); fprintf(stderr, "%s: stat: %s\n", name, strerror(errno));
@ -153,6 +154,9 @@ RFile *open_existing_file(char *name, uint64 *size,
if (atime) if (atime)
*atime = statbuf.st_atime; *atime = statbuf.st_atime;
if (perms)
*perms = statbuf.st_mode;
} }
return ret; return ret;
@ -174,12 +178,13 @@ struct WFile {
char *name; char *name;
}; };
WFile *open_new_file(char *name) WFile *open_new_file(char *name, long perms)
{ {
int fd; int fd;
WFile *ret; WFile *ret;
fd = open(name, O_CREAT | O_TRUNC | O_WRONLY, 0666); fd = open(name, O_CREAT | O_TRUNC | O_WRONLY,
(mode_t)(perms ? perms : 0666));
if (fd < 0) if (fd < 0)
return NULL; return NULL;

View File

@ -88,7 +88,8 @@ struct RFile {
}; };
RFile *open_existing_file(char *name, uint64 *size, RFile *open_existing_file(char *name, uint64 *size,
unsigned long *mtime, unsigned long *atime) unsigned long *mtime, unsigned long *atime,
long *perms)
{ {
HANDLE h; HANDLE h;
RFile *ret; RFile *ret;
@ -113,6 +114,9 @@ RFile *open_existing_file(char *name, uint64 *size,
TIME_WIN_TO_POSIX(wrtime, *mtime); TIME_WIN_TO_POSIX(wrtime, *mtime);
} }
if (perms)
*perms = -1;
return ret; return ret;
} }
@ -137,7 +141,7 @@ struct WFile {
HANDLE h; HANDLE h;
}; };
WFile *open_new_file(char *name) WFile *open_new_file(char *name, long perms)
{ {
HANDLE h; HANDLE h;
WFile *ret; WFile *ret;