Skip to content

Commit 5c00b58

Browse files
committed
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]
1 parent f14953d commit 5c00b58

File tree

7 files changed

+81
-31
lines changed

7 files changed

+81
-31
lines changed

pscp.c

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -830,21 +830,26 @@ int scp_send_filetimes(unsigned long mtime, unsigned long atime)
830830
}
831831
}
832832

833-
int scp_send_filename(char *name, uint64 size, int modes)
833+
int scp_send_filename(char *name, uint64 size, int permissions)
834834
{
835835
if (using_sftp) {
836836
char *fullname;
837837
struct sftp_packet *pktin;
838838
struct sftp_request *req, *rreq;
839+
struct fxp_attrs attrs;
839840

840841
if (scp_sftp_targetisdir) {
841842
fullname = dupcat(scp_sftp_remotepath, "/", name, NULL);
842843
} else {
843844
fullname = dupstr(scp_sftp_remotepath);
844845
}
845846

847+
attrs.flags = 0;
848+
PUT_PERMISSIONS(attrs, permissions);
849+
846850
sftp_register(req = fxp_open_send(fullname, SSH_FXF_WRITE |
847-
SSH_FXF_CREAT | SSH_FXF_TRUNC));
851+
SSH_FXF_CREAT | SSH_FXF_TRUNC,
852+
&attrs));
848853
rreq = sftp_find_request(pktin = sftp_recv());
849854
assert(rreq == req);
850855
scp_sftp_filehandle = fxp_open_recv(pktin, rreq);
@@ -864,7 +869,9 @@ int scp_send_filename(char *name, uint64 size, int modes)
864869
char buf[40];
865870
char sizestr[40];
866871
uint64_decimal(size, sizestr);
867-
sprintf(buf, "C%04o %s ", modes, sizestr);
872+
if (permissions < 0)
873+
permissions = 0644;
874+
sprintf(buf, "C%04o %s ", (int)(permissions & 07777), sizestr);
868875
back->send(backhandle, buf, strlen(buf));
869876
back->send(backhandle, name, strlen(name));
870877
back->send(backhandle, "\n", 1);
@@ -1144,7 +1151,7 @@ struct scp_sink_action {
11441151
int action; /* FILE, DIR, ENDDIR */
11451152
char *buf; /* will need freeing after use */
11461153
char *name; /* filename or dirname (not ENDDIR) */
1147-
int mode; /* access mode (not ENDDIR) */
1154+
long permissions; /* access permissions (not ENDDIR) */
11481155
uint64 size; /* file size (not ENDDIR) */
11491156
int settime; /* 1 if atime and mtime are filled */
11501157
unsigned long atime, mtime; /* access times for the file */
@@ -1370,7 +1377,7 @@ int scp_get_sink_action(struct scp_sink_action *act)
13701377
act->buf = dupstr(stripslashes(fname, 0));
13711378
act->name = act->buf;
13721379
act->size = uint64_make(0,0); /* duhh, it's a directory */
1373-
act->mode = 07777 & attrs.permissions;
1380+
act->permissions = 07777 & attrs.permissions;
13741381
if (scp_sftp_preserve &&
13751382
(attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) {
13761383
act->atime = attrs.atime;
@@ -1392,7 +1399,7 @@ int scp_get_sink_action(struct scp_sink_action *act)
13921399
act->size = attrs.size;
13931400
} else
13941401
act->size = uint64_make(ULONG_MAX,ULONG_MAX); /* no idea */
1395-
act->mode = 07777 & attrs.permissions;
1402+
act->permissions = 07777 & attrs.permissions;
13961403
if (scp_sftp_preserve &&
13971404
(attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) {
13981405
act->atime = attrs.atime;
@@ -1474,7 +1481,8 @@ int scp_get_sink_action(struct scp_sink_action *act)
14741481
{
14751482
char sizestr[40];
14761483

1477-
if (sscanf(act->buf, "%o %s %n", &act->mode, sizestr, &i) != 2)
1484+
if (sscanf(act->buf, "%lo %s %n", &act->permissions,
1485+
sizestr, &i) != 2)
14781486
bump("Protocol error: Illegal file descriptor format");
14791487
act->size = uint64_from_decimal(sizestr);
14801488
act->name = act->buf + i;
@@ -1489,7 +1497,8 @@ int scp_accept_filexfer(void)
14891497
struct sftp_packet *pktin;
14901498
struct sftp_request *req, *rreq;
14911499

1492-
sftp_register(req = fxp_open_send(scp_sftp_currentname, SSH_FXF_READ));
1500+
sftp_register(req = fxp_open_send(scp_sftp_currentname, SSH_FXF_READ,
1501+
NULL));
14931502
rreq = sftp_find_request(pktin = sftp_recv());
14941503
assert(rreq == req);
14951504
scp_sftp_filehandle = fxp_open_recv(pktin, rreq);
@@ -1609,6 +1618,7 @@ static void source(char *src)
16091618
{
16101619
uint64 size;
16111620
unsigned long mtime, atime;
1621+
long permissions;
16121622
char *last;
16131623
RFile *f;
16141624
int attr;
@@ -1656,7 +1666,7 @@ static void source(char *src)
16561666
if (last == src && strchr(src, ':') != NULL)
16571667
last = strchr(src, ':') + 1;
16581668

1659-
f = open_existing_file(src, &size, &mtime, &atime);
1669+
f = open_existing_file(src, &size, &mtime, &atime, &permissions);
16601670
if (f == NULL) {
16611671
run_err("%s: Cannot open file", src);
16621672
return;
@@ -1671,7 +1681,7 @@ static void source(char *src)
16711681
uint64_decimal(size, sizestr);
16721682
tell_user(stderr, "Sending file %s, size=%s", last, sizestr);
16731683
}
1674-
if (scp_send_filename(last, size, 0644))
1684+
if (scp_send_filename(last, size, permissions))
16751685
return;
16761686

16771687
stat_bytes = uint64_make(0,0);
@@ -1888,7 +1898,7 @@ static void sink(char *targ, char *src)
18881898
continue;
18891899
}
18901900

1891-
f = open_new_file(destfname);
1901+
f = open_new_file(destfname, act.permissions);
18921902
if (f == NULL) {
18931903
run_err("%s: Cannot create file", destfname);
18941904
continue;

psftp.c

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -212,14 +212,14 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
212212
uint64 offset;
213213
WFile *file;
214214
int ret, shown_err = FALSE;
215+
struct fxp_attrs attrs;
215216

216217
/*
217218
* In recursive mode, see if we're dealing with a directory.
218219
* (If we're not in recursive mode, we need not even check: the
219220
* subsequent FXP_OPEN will return a usable error message.)
220221
*/
221222
if (recurse) {
222-
struct fxp_attrs attrs;
223223
int result;
224224

225225
sftp_register(req = fxp_stat_send(fname));
@@ -383,7 +383,13 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
383383
}
384384
}
385385

386-
sftp_register(req = fxp_open_send(fname, SSH_FXF_READ));
386+
sftp_register(req = fxp_stat_send(fname));
387+
rreq = sftp_find_request(pktin = sftp_recv());
388+
assert(rreq == req);
389+
if (!fxp_stat_recv(pktin, rreq, &attrs))
390+
attrs.flags = 0;
391+
392+
sftp_register(req = fxp_open_send(fname, SSH_FXF_READ, NULL));
387393
rreq = sftp_find_request(pktin = sftp_recv());
388394
assert(rreq == req);
389395
fh = fxp_open_recv(pktin, rreq);
@@ -396,7 +402,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
396402
if (restart) {
397403
file = open_existing_wfile(outfname, NULL);
398404
} else {
399-
file = open_new_file(outfname);
405+
file = open_new_file(outfname, GET_PERMISSIONS(attrs));
400406
}
401407

402408
if (!file) {
@@ -500,14 +506,15 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
500506
uint64 offset;
501507
RFile *file;
502508
int ret, err, eof;
509+
struct fxp_attrs attrs;
510+
long permissions;
503511

504512
/*
505513
* In recursive mode, see if we're dealing with a directory.
506514
* (If we're not in recursive mode, we need not even check: the
507515
* subsequent fopen will return an error message.)
508516
*/
509517
if (recurse && file_type(fname) == FILE_TYPE_DIRECTORY) {
510-
struct fxp_attrs attrs;
511518
int result;
512519
int nnames, namesize;
513520
char *name, **ournames;
@@ -630,16 +637,19 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
630637
return 1;
631638
}
632639

633-
file = open_existing_file(fname, NULL, NULL, NULL);
640+
file = open_existing_file(fname, NULL, NULL, NULL, &permissions);
634641
if (!file) {
635642
printf("local: unable to open %s\n", fname);
636643
return 0;
637644
}
645+
attrs.flags = 0;
646+
PUT_PERMISSIONS(attrs, permissions);
638647
if (restart) {
639-
sftp_register(req = fxp_open_send(outfname, SSH_FXF_WRITE));
648+
sftp_register(req = fxp_open_send(outfname, SSH_FXF_WRITE, &attrs));
640649
} else {
641650
sftp_register(req = fxp_open_send(outfname, SSH_FXF_WRITE |
642-
SSH_FXF_CREAT | SSH_FXF_TRUNC));
651+
SSH_FXF_CREAT | SSH_FXF_TRUNC,
652+
&attrs));
643653
}
644654
rreq = sftp_find_request(pktin = sftp_recv());
645655
assert(rreq == req);

psftp.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,17 @@ void gui_enable(char *arg);
8585
*/
8686
typedef struct RFile RFile;
8787
typedef struct WFile WFile;
88-
/* Output params size, mtime and atime can all be NULL if desired */
88+
/* Output params size, perms, mtime and atime can all be NULL if
89+
* desired. perms will be -1 if the OS does not support POSIX permissions. */
8990
RFile *open_existing_file(char *name, uint64 *size,
90-
unsigned long *mtime, unsigned long *atime);
91+
unsigned long *mtime, unsigned long *atime,
92+
long *perms);
9193
WFile *open_existing_wfile(char *name, uint64 *size);
9294
/* Returns <0 on error, 0 on eof, or number of bytes read, as usual */
9395
int read_from_file(RFile *f, void *buffer, int length);
9496
/* Closes and frees the RFile */
9597
void close_rfile(RFile *f);
96-
WFile *open_new_file(char *name);
98+
WFile *open_new_file(char *name, long perms);
9799
/* Returns <0 on error, 0 on eof, or number of bytes written, as usual */
98100
int write_to_file(WFile *f, void *buffer, int length);
99101
void set_file_times(WFile *f, unsigned long mtime, unsigned long atime);

sftp.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,8 @@ char *fxp_realpath_recv(struct sftp_packet *pktin, struct sftp_request *req)
548548
/*
549549
* Open a file.
550550
*/
551-
struct sftp_request *fxp_open_send(char *path, int type)
551+
struct sftp_request *fxp_open_send(char *path, int type,
552+
struct fxp_attrs *attrs)
552553
{
553554
struct sftp_request *req = sftp_alloc_request();
554555
struct sftp_packet *pktout;
@@ -557,7 +558,10 @@ struct sftp_request *fxp_open_send(char *path, int type)
557558
sftp_pkt_adduint32(pktout, req->id);
558559
sftp_pkt_addstring(pktout, path);
559560
sftp_pkt_adduint32(pktout, type);
560-
sftp_pkt_adduint32(pktout, 0); /* (FIXME) empty ATTRS structure */
561+
if (attrs)
562+
sftp_pkt_addattrs(pktout, *attrs);
563+
else
564+
sftp_pkt_adduint32(pktout, 0); /* empty ATTRS structure */
561565
sftp_send(pktout);
562566

563567
return req;

sftp.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,19 @@ struct fxp_attrs {
8282
unsigned long mtime;
8383
};
8484

85+
/*
86+
* Copy between the possibly-unused permissions field in an fxp_attrs
87+
* and a possibly-negative integer containing the same permissions.
88+
*/
89+
#define PUT_PERMISSIONS(attrs, perms) \
90+
((perms) >= 0 ? \
91+
((attrs).flags |= SSH_FILEXFER_ATTR_PERMISSIONS, \
92+
(attrs).permissions = (perms)) : \
93+
((attrs).flags &= ~SSH_FILEXFER_ATTR_PERMISSIONS))
94+
#define GET_PERMISSIONS(attrs) \
95+
((attrs).flags & SSH_FILEXFER_ATTR_PERMISSIONS ? \
96+
(attrs).permissions : -1)
97+
8598
struct fxp_handle {
8699
char *hstring;
87100
int hlen;
@@ -116,9 +129,11 @@ struct sftp_request *fxp_realpath_send(char *path);
116129
char *fxp_realpath_recv(struct sftp_packet *pktin, struct sftp_request *req);
117130

118131
/*
119-
* Open a file.
132+
* Open a file. 'attrs' contains attributes to be applied to the file
133+
* if it's being created.
120134
*/
121-
struct sftp_request *fxp_open_send(char *path, int type);
135+
struct sftp_request *fxp_open_send(char *path, int type,
136+
struct fxp_attrs *attrs);
122137
struct fxp_handle *fxp_open_recv(struct sftp_packet *pktin,
123138
struct sftp_request *req);
124139

unix/uxsftp.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ struct RFile {
125125
};
126126

127127
RFile *open_existing_file(char *name, uint64 *size,
128-
unsigned long *mtime, unsigned long *atime)
128+
unsigned long *mtime, unsigned long *atime,
129+
long *perms)
129130
{
130131
int fd;
131132
RFile *ret;
@@ -137,7 +138,7 @@ RFile *open_existing_file(char *name, uint64 *size,
137138
ret = snew(RFile);
138139
ret->fd = fd;
139140

140-
if (size || mtime || atime) {
141+
if (size || mtime || atime || perms) {
141142
struct stat statbuf;
142143
if (fstat(fd, &statbuf) < 0) {
143144
fprintf(stderr, "%s: stat: %s\n", name, strerror(errno));
@@ -153,6 +154,9 @@ RFile *open_existing_file(char *name, uint64 *size,
153154

154155
if (atime)
155156
*atime = statbuf.st_atime;
157+
158+
if (perms)
159+
*perms = statbuf.st_mode;
156160
}
157161

158162
return ret;
@@ -174,12 +178,13 @@ struct WFile {
174178
char *name;
175179
};
176180

177-
WFile *open_new_file(char *name)
181+
WFile *open_new_file(char *name, long perms)
178182
{
179183
int fd;
180184
WFile *ret;
181185

182-
fd = open(name, O_CREAT | O_TRUNC | O_WRONLY, 0666);
186+
fd = open(name, O_CREAT | O_TRUNC | O_WRONLY,
187+
(mode_t)(perms ? perms : 0666));
183188
if (fd < 0)
184189
return NULL;
185190

windows/winsftp.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ struct RFile {
8888
};
8989

9090
RFile *open_existing_file(char *name, uint64 *size,
91-
unsigned long *mtime, unsigned long *atime)
91+
unsigned long *mtime, unsigned long *atime,
92+
long *perms)
9293
{
9394
HANDLE h;
9495
RFile *ret;
@@ -113,6 +114,9 @@ RFile *open_existing_file(char *name, uint64 *size,
113114
TIME_WIN_TO_POSIX(wrtime, *mtime);
114115
}
115116

117+
if (perms)
118+
*perms = -1;
119+
116120
return ret;
117121
}
118122

@@ -137,7 +141,7 @@ struct WFile {
137141
HANDLE h;
138142
};
139143

140-
WFile *open_new_file(char *name)
144+
WFile *open_new_file(char *name, long perms)
141145
{
142146
HANDLE h;
143147
WFile *ret;

0 commit comments

Comments
 (0)