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.
git-svn-id: svn://svn.tartarus.org/sgt/putty@9260
cda61777-01e9-0310-a592-
d414129be87e
-int scp_send_filename(char *name, uint64 size, int modes)
+int scp_send_filename(char *name, uint64 size, int permissions)
{
if (using_sftp) {
char *fullname;
struct sftp_packet *pktin;
struct sftp_request *req, *rreq;
{
if (using_sftp) {
char *fullname;
struct sftp_packet *pktin;
struct sftp_request *req, *rreq;
+ struct fxp_attrs attrs;
if (scp_sftp_targetisdir) {
fullname = dupcat(scp_sftp_remotepath, "/", name, NULL);
if (scp_sftp_targetisdir) {
fullname = dupcat(scp_sftp_remotepath, "/", name, NULL);
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());
assert(rreq == req);
scp_sftp_filehandle = fxp_open_recv(pktin, rreq);
rreq = sftp_find_request(pktin = sftp_recv());
assert(rreq == req);
scp_sftp_filehandle = fxp_open_recv(pktin, rreq);
char buf[40];
char sizestr[40];
uint64_decimal(size, sizestr);
char buf[40];
char sizestr[40];
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, name, strlen(name));
back->send(backhandle, "\n", 1);
back->send(backhandle, buf, strlen(buf));
back->send(backhandle, name, strlen(name));
back->send(backhandle, "\n", 1);
int action; /* FILE, DIR, ENDDIR */
char *buf; /* will need freeing after use */
char *name; /* filename or dirname (not ENDDIR) */
int action; /* FILE, DIR, ENDDIR */
char *buf; /* will need freeing after use */
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) */
int settime; /* 1 if atime and mtime are filled */
unsigned long atime, mtime; /* access times for the file */
uint64 size; /* file size (not ENDDIR) */
int settime; /* 1 if atime and mtime are filled */
unsigned long atime, mtime; /* access times for the file */
act->buf = dupstr(stripslashes(fname, 0));
act->name = act->buf;
act->size = uint64_make(0,0); /* duhh, it's a directory */
act->buf = dupstr(stripslashes(fname, 0));
act->name = act->buf;
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 &&
(attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) {
act->atime = attrs.atime;
if (scp_sftp_preserve &&
(attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) {
act->atime = attrs.atime;
act->size = attrs.size;
} else
act->size = uint64_make(ULONG_MAX,ULONG_MAX); /* no idea */
act->size = attrs.size;
} else
act->size = uint64_make(ULONG_MAX,ULONG_MAX); /* no idea */
- act->mode = 07777 & attrs.permissions;
+ act->permissions = 07777 & attrs.permissions;
if (scp_sftp_preserve &&
(attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) {
act->atime = attrs.atime;
if (scp_sftp_preserve &&
(attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) {
act->atime = attrs.atime;
- 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");
act->size = uint64_from_decimal(sizestr);
act->name = act->buf + i;
bump("Protocol error: Illegal file descriptor format");
act->size = uint64_from_decimal(sizestr);
act->name = act->buf + i;
struct sftp_packet *pktin;
struct sftp_request *req, *rreq;
struct sftp_packet *pktin;
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());
assert(rreq == req);
scp_sftp_filehandle = fxp_open_recv(pktin, rreq);
rreq = sftp_find_request(pktin = sftp_recv());
assert(rreq == req);
scp_sftp_filehandle = fxp_open_recv(pktin, rreq);
{
uint64 size;
unsigned long mtime, atime;
{
uint64 size;
unsigned long mtime, atime;
char *last;
RFile *f;
int attr;
char *last;
RFile *f;
int attr;
if (last == src && strchr(src, ':') != NULL)
last = strchr(src, ':') + 1;
if (last == src && strchr(src, ':') != NULL)
last = strchr(src, ':') + 1;
- f = open_existing_file(src, &size, &mtime, &atime);
+ f = open_existing_file(src, &size, &mtime, &atime, &permissions);
if (f == NULL) {
run_err("%s: Cannot open file", src);
return;
if (f == NULL) {
run_err("%s: Cannot open file", src);
return;
uint64_decimal(size, sizestr);
tell_user(stderr, "Sending file %s, size=%s", last, sizestr);
}
uint64_decimal(size, 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;
stat_bytes = uint64_make(0,0);
return;
stat_bytes = uint64_make(0,0);
- f = open_new_file(destfname);
+ f = open_new_file(destfname, act.permissions);
if (f == NULL) {
run_err("%s: Cannot create file", destfname);
continue;
if (f == NULL) {
run_err("%s: Cannot create file", destfname);
continue;
uint64 offset;
WFile *file;
int ret, shown_err = FALSE;
uint64 offset;
WFile *file;
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.
* subsequent FXP_OPEN will return a usable error message.)
*/
if (recurse) {
* subsequent FXP_OPEN will return a usable error message.)
*/
if (recurse) {
- struct fxp_attrs attrs;
int result;
sftp_register(req = fxp_stat_send(fname));
int result;
sftp_register(req = fxp_stat_send(fname));
- 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());
assert(rreq == req);
fh = fxp_open_recv(pktin, rreq);
rreq = sftp_find_request(pktin = sftp_recv());
assert(rreq == req);
fh = fxp_open_recv(pktin, rreq);
if (restart) {
file = open_existing_wfile(outfname, NULL);
} else {
if (restart) {
file = open_existing_wfile(outfname, NULL);
} else {
- file = open_new_file(outfname);
+ file = open_new_file(outfname, GET_PERMISSIONS(attrs));
uint64 offset;
RFile *file;
int ret, err, eof;
uint64 offset;
RFile *file;
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.
* subsequent fopen will return an error message.)
*/
if (recurse && file_type(fname) == FILE_TYPE_DIRECTORY) {
* subsequent fopen will return an error message.)
*/
if (recurse && file_type(fname) == FILE_TYPE_DIRECTORY) {
- struct fxp_attrs attrs;
int result;
int nnames, namesize;
char *name, **ournames;
int result;
int nnames, namesize;
char *name, **ournames;
- file = open_existing_file(fname, NULL, NULL, NULL);
+ file = open_existing_file(fname, NULL, NULL, NULL, &permissions);
if (!file) {
printf("local: unable to open %s\n", fname);
return 0;
}
if (!file) {
printf("local: unable to open %s\n", fname);
return 0;
}
+ attrs.flags = 0;
+ PUT_PERMISSIONS(attrs, permissions);
- sftp_register(req = fxp_open_send(outfname, SSH_FXF_WRITE));
+ sftp_register(req = fxp_open_send(outfname, SSH_FXF_WRITE, &attrs));
} else {
sftp_register(req = fxp_open_send(outfname, SSH_FXF_WRITE |
} else {
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());
assert(rreq == req);
}
rreq = sftp_find_request(pktin = sftp_recv());
assert(rreq == req);
*/
typedef struct RFile RFile;
typedef struct WFile WFile;
*/
typedef struct RFile RFile;
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);
/* Returns <0 on error, 0 on eof, or number of bytes read, as usual */
int read_from_file(RFile *f, void *buffer, int length);
/* Closes and frees the RFile */
void close_rfile(RFile *f);
WFile *open_existing_wfile(char *name, uint64 *size);
/* Returns <0 on error, 0 on eof, or number of bytes read, as usual */
int read_from_file(RFile *f, void *buffer, int length);
/* Closes and frees the RFile */
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 */
int write_to_file(WFile *f, void *buffer, int length);
void set_file_times(WFile *f, unsigned long mtime, unsigned long atime);
/* Returns <0 on error, 0 on eof, or number of bytes written, as usual */
int write_to_file(WFile *f, void *buffer, int length);
void set_file_times(WFile *f, unsigned long mtime, unsigned long atime);
-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_packet *pktout;
{
struct sftp_request *req = sftp_alloc_request();
struct sftp_packet *pktout;
sftp_pkt_adduint32(pktout, req->id);
sftp_pkt_addstring(pktout, path);
sftp_pkt_adduint32(pktout, type);
sftp_pkt_adduint32(pktout, req->id);
sftp_pkt_addstring(pktout, path);
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);
return req;
sftp_send(pktout);
return req;
+/*
+ * 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 {
char *hstring;
int hlen;
struct fxp_handle {
char *hstring;
int hlen;
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. '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 sftp_request *req);
struct fxp_handle *fxp_open_recv(struct sftp_packet *pktin,
struct sftp_request *req);
};
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)
ret = snew(RFile);
ret->fd = fd;
ret = snew(RFile);
ret->fd = fd;
- if (size || mtime || atime) {
+ if (size || mtime || atime || perms) {
struct stat statbuf;
if (fstat(fd, &statbuf) < 0) {
fprintf(stderr, "%s: stat: %s\n", name, strerror(errno));
struct stat statbuf;
if (fstat(fd, &statbuf) < 0) {
fprintf(stderr, "%s: stat: %s\n", name, strerror(errno));
if (atime)
*atime = statbuf.st_atime;
if (atime)
*atime = statbuf.st_atime;
+
+ if (perms)
+ *perms = statbuf.st_mode;
-WFile *open_new_file(char *name)
+WFile *open_new_file(char *name, long perms)
- fd = open(name, O_CREAT | O_TRUNC | O_WRONLY, 0666);
+ fd = open(name, O_CREAT | O_TRUNC | O_WRONLY,
+ (mode_t)(perms ? perms : 0666));
};
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)
TIME_WIN_TO_POSIX(wrtime, *mtime);
}
TIME_WIN_TO_POSIX(wrtime, *mtime);
}
+ if (perms)
+ *perms = -1;
+
-WFile *open_new_file(char *name)
+WFile *open_new_file(char *name, long perms)