1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-10 01:48:00 +00:00

Remove CRs. Oops :-/

[originally from svn r3435]
This commit is contained in:
Simon Tatham 2003-09-02 09:00:35 +00:00
parent f68c785aa4
commit b104be3b00
2 changed files with 556 additions and 556 deletions

300
psftp.h
View File

@ -1,150 +1,150 @@
/* /*
* psftp.h: interface between psftp.c / scp.c and each * psftp.h: interface between psftp.c / scp.c and each
* platform-specific SFTP module. * platform-specific SFTP module.
*/ */
#ifndef PUTTY_PSFTP_H #ifndef PUTTY_PSFTP_H
#define PUTTY_PSFTP_H #define PUTTY_PSFTP_H
/* /*
* psftp_getcwd returns the local current directory. The returned * psftp_getcwd returns the local current directory. The returned
* string must be freed by the caller. * string must be freed by the caller.
*/ */
char *psftp_getcwd(void); char *psftp_getcwd(void);
/* /*
* psftp_lcd changes the local current directory. The return value * psftp_lcd changes the local current directory. The return value
* is NULL on success, or else an error message which must be freed * is NULL on success, or else an error message which must be freed
* by the caller. * by the caller.
*/ */
char *psftp_lcd(char *newdir); char *psftp_lcd(char *newdir);
/* /*
* Retrieve file times on a local file. Must return two unsigned * Retrieve file times on a local file. Must return two unsigned
* longs in POSIX time_t format. * longs in POSIX time_t format.
*/ */
void get_file_times(char *filename, unsigned long *mtime, void get_file_times(char *filename, unsigned long *mtime,
unsigned long *atime); unsigned long *atime);
/* /*
* One iteration of the PSFTP event loop: wait for network data and * One iteration of the PSFTP event loop: wait for network data and
* process it, once. * process it, once.
*/ */
int ssh_sftp_loop_iteration(void); int ssh_sftp_loop_iteration(void);
/* /*
* The main program in psftp.c. Called from main() in the platform- * The main program in psftp.c. Called from main() in the platform-
* specific code, after doing any platform-specific initialisation. * specific code, after doing any platform-specific initialisation.
*/ */
int psftp_main(int argc, char *argv[]); int psftp_main(int argc, char *argv[]);
/* /*
* These functions are used by PSCP to transmit progress updates * These functions are used by PSCP to transmit progress updates
* and error information to a GUI window managing it. This will * and error information to a GUI window managing it. This will
* probably only ever be supported on Windows, so these functions * probably only ever be supported on Windows, so these functions
* can safely be stubs on all other platforms. * can safely be stubs on all other platforms.
*/ */
void gui_update_stats(char *name, unsigned long size, void gui_update_stats(char *name, unsigned long size,
int percentage, unsigned long elapsed, int percentage, unsigned long elapsed,
unsigned long done, unsigned long eta, unsigned long done, unsigned long eta,
unsigned long ratebs); unsigned long ratebs);
void gui_send_errcount(int list, int errs); void gui_send_errcount(int list, int errs);
void gui_send_char(int is_stderr, int c); void gui_send_char(int is_stderr, int c);
void gui_enable(char *arg); void gui_enable(char *arg);
/* /*
* It's likely that a given platform's implementation of file * It's likely that a given platform's implementation of file
* transfer utilities is going to want to do things with them that * transfer utilities is going to want to do things with them that
* aren't present in stdio. Hence we supply an alternative * aren't present in stdio. Hence we supply an alternative
* abstraction for file access functions. * abstraction for file access functions.
* *
* This abstraction tells you the size and access times when you * This abstraction tells you the size and access times when you
* open an existing file (platforms may choose the meaning of the * open an existing file (platforms may choose the meaning of the
* file times if it's not clear; whatever they choose will be what * file times if it's not clear; whatever they choose will be what
* PSCP sends to the server as mtime and atime), and lets you set * PSCP sends to the server as mtime and atime), and lets you set
* the times when saving a new file. * the times when saving a new file.
* *
* On the other hand, the abstraction is pretty simple: it supports * On the other hand, the abstraction is pretty simple: it supports
* only opening a file and reading it, or creating a file and * only opening a file and reading it, or creating a file and
* writing it. (FIXME: to use this in PSFTP it will also need to * writing it. (FIXME: to use this in PSFTP it will also need to
* support seeking to a starting point for restarted transfers.) * support seeking to a starting point for restarted transfers.)
* None of this read-and-write, seeking-back-and-forth stuff. * None of this read-and-write, seeking-back-and-forth stuff.
*/ */
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, mtime and atime can all be NULL if desired */
RFile *open_existing_file(char *name, unsigned long *size, RFile *open_existing_file(char *name, unsigned long *size,
unsigned long *mtime, unsigned long *atime); unsigned long *mtime, unsigned long *atime);
/* 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);
/* 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);
/* Closes and frees the WFile */ /* Closes and frees the WFile */
void close_wfile(WFile *f); void close_wfile(WFile *f);
/* /*
* Determine the type of a file: nonexistent, file, directory or * Determine the type of a file: nonexistent, file, directory or
* weird. `weird' covers anything else - named pipes, Unix sockets, * weird. `weird' covers anything else - named pipes, Unix sockets,
* device files, fish, badgers, you name it. Things marked `weird' * device files, fish, badgers, you name it. Things marked `weird'
* will be skipped over in recursive file transfers, so the only * will be skipped over in recursive file transfers, so the only
* real reason for not lumping them in with `nonexistent' is that * real reason for not lumping them in with `nonexistent' is that
* it allows a slightly more sane error message. * it allows a slightly more sane error message.
*/ */
enum { enum {
FILE_TYPE_NONEXISTENT, FILE_TYPE_FILE, FILE_TYPE_DIRECTORY, FILE_TYPE_WEIRD FILE_TYPE_NONEXISTENT, FILE_TYPE_FILE, FILE_TYPE_DIRECTORY, FILE_TYPE_WEIRD
}; };
int file_type(char *name); int file_type(char *name);
/* /*
* Read all the file names out of a directory. * Read all the file names out of a directory.
*/ */
typedef struct DirHandle DirHandle; typedef struct DirHandle DirHandle;
DirHandle *open_directory(char *name); DirHandle *open_directory(char *name);
/* The string returned from this will need freeing if not NULL */ /* The string returned from this will need freeing if not NULL */
char *read_filename(DirHandle *dir); char *read_filename(DirHandle *dir);
void close_directory(DirHandle *dir); void close_directory(DirHandle *dir);
/* /*
* Test a filespec to see whether it's a local wildcard or not. * Test a filespec to see whether it's a local wildcard or not.
* Return values: * Return values:
* *
* - WCTYPE_WILDCARD (this is a wildcard). * - WCTYPE_WILDCARD (this is a wildcard).
* - WCTYPE_FILENAME (this is a single file name). * - WCTYPE_FILENAME (this is a single file name).
* - WCTYPE_NONEXISTENT (whichever it was, nothing of that name exists). * - WCTYPE_NONEXISTENT (whichever it was, nothing of that name exists).
* *
* Some platforms may choose not to support local wildcards when * Some platforms may choose not to support local wildcards when
* they come from the command line; in this case they simply never * they come from the command line; in this case they simply never
* return WCTYPE_WILDCARD, but still test the file's existence. * return WCTYPE_WILDCARD, but still test the file's existence.
* (However, all platforms will probably want to support wildcards * (However, all platforms will probably want to support wildcards
* inside the PSFTP CLI.) * inside the PSFTP CLI.)
*/ */
enum { enum {
WCTYPE_NONEXISTENT, WCTYPE_FILENAME, WCTYPE_WILDCARD WCTYPE_NONEXISTENT, WCTYPE_FILENAME, WCTYPE_WILDCARD
}; };
int test_wildcard(char *name, int cmdline); int test_wildcard(char *name, int cmdline);
/* /*
* Actually return matching file names for a local wildcard. * Actually return matching file names for a local wildcard.
*/ */
typedef struct WildcardMatcher WildcardMatcher; typedef struct WildcardMatcher WildcardMatcher;
WildcardMatcher *begin_wildcard_matching(char *name); WildcardMatcher *begin_wildcard_matching(char *name);
/* The string returned from this will need freeing if not NULL */ /* The string returned from this will need freeing if not NULL */
char *wildcard_get_filename(WildcardMatcher *dir); char *wildcard_get_filename(WildcardMatcher *dir);
void finish_wildcard_matching(WildcardMatcher *dir); void finish_wildcard_matching(WildcardMatcher *dir);
/* /*
* Create a directory. Returns 0 on error, !=0 on success. * Create a directory. Returns 0 on error, !=0 on success.
*/ */
int create_directory(char *name); int create_directory(char *name);
/* /*
* Concatenate a directory name and a file name. The way this is * Concatenate a directory name and a file name. The way this is
* done will depend on the OS. * done will depend on the OS.
*/ */
char *dir_file_cat(char *dir, char *file); char *dir_file_cat(char *dir, char *file);
#endif /* PUTTY_PSFTP_H */ #endif /* PUTTY_PSFTP_H */

View File

@ -1,406 +1,406 @@
/* /*
* uxsftp.c: the Unix-specific parts of PSFTP and PSCP. * uxsftp.c: the Unix-specific parts of PSFTP and PSCP.
*/ */
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h> #include <fcntl.h>
#include <dirent.h> #include <dirent.h>
#include <unistd.h> #include <unistd.h>
#include <utime.h> #include <utime.h>
#include <errno.h> #include <errno.h>
#include <assert.h> #include <assert.h>
#include "putty.h" #include "putty.h"
#include "psftp.h" #include "psftp.h"
/* /*
* In PSFTP our selects are synchronous, so these functions are * In PSFTP our selects are synchronous, so these functions are
* empty stubs. * empty stubs.
*/ */
int uxsel_input_add(int fd, int rwx) { return 0; } int uxsel_input_add(int fd, int rwx) { return 0; }
void uxsel_input_remove(int id) { } void uxsel_input_remove(int id) { }
char *x_get_default(const char *key) char *x_get_default(const char *key)
{ {
return NULL; /* this is a stub */ return NULL; /* this is a stub */
} }
void platform_get_x11_auth(char *display, int *protocol, void platform_get_x11_auth(char *display, int *protocol,
unsigned char *data, int *datalen) unsigned char *data, int *datalen)
{ {
/* Do nothing, therefore no auth. */ /* Do nothing, therefore no auth. */
} }
/* /*
* Default settings that are specific to PSFTP. * Default settings that are specific to PSFTP.
*/ */
char *platform_default_s(const char *name) char *platform_default_s(const char *name)
{ {
return NULL; return NULL;
} }
int platform_default_i(const char *name, int def) int platform_default_i(const char *name, int def)
{ {
return def; return def;
} }
FontSpec platform_default_fontspec(const char *name) FontSpec platform_default_fontspec(const char *name)
{ {
FontSpec ret; FontSpec ret;
*ret.name = '\0'; *ret.name = '\0';
return ret; return ret;
} }
Filename platform_default_filename(const char *name) Filename platform_default_filename(const char *name)
{ {
Filename ret; Filename ret;
if (!strcmp(name, "LogFileName")) if (!strcmp(name, "LogFileName"))
strcpy(ret.path, "putty.log"); strcpy(ret.path, "putty.log");
else else
*ret.path = '\0'; *ret.path = '\0';
return ret; return ret;
} }
/* /*
* Stubs for the GUI feedback mechanism in Windows PSCP. * Stubs for the GUI feedback mechanism in Windows PSCP.
*/ */
void gui_update_stats(char *name, unsigned long size, void gui_update_stats(char *name, unsigned long size,
int percentage, unsigned long elapsed, int percentage, unsigned long elapsed,
unsigned long done, unsigned long eta, unsigned long done, unsigned long eta,
unsigned long ratebs) {} unsigned long ratebs) {}
void gui_send_errcount(int list, int errs) {} void gui_send_errcount(int list, int errs) {}
void gui_send_char(int is_stderr, int c) {} void gui_send_char(int is_stderr, int c) {}
void gui_enable(char *arg) {} void gui_enable(char *arg) {}
/* /*
* Set local current directory. Returns NULL on success, or else an * Set local current directory. Returns NULL on success, or else an
* error message which must be freed after printing. * error message which must be freed after printing.
*/ */
char *psftp_lcd(char *dir) char *psftp_lcd(char *dir)
{ {
if (chdir(dir) < 0) if (chdir(dir) < 0)
return dupprintf("%s: chdir: %s", dir, strerror(errno)); return dupprintf("%s: chdir: %s", dir, strerror(errno));
else else
return NULL; return NULL;
} }
/* /*
* Get local current directory. Returns a string which must be * Get local current directory. Returns a string which must be
* freed. * freed.
*/ */
char *psftp_getcwd(void) char *psftp_getcwd(void)
{ {
char *buffer, *ret; char *buffer, *ret;
int size = 256; int size = 256;
buffer = snewn(size, char); buffer = snewn(size, char);
while (1) { while (1) {
ret = getcwd(buffer, size); ret = getcwd(buffer, size);
if (ret != NULL) if (ret != NULL)
return ret; return ret;
if (errno != ERANGE) { if (errno != ERANGE) {
sfree(buffer); sfree(buffer);
return dupprintf("[cwd unavailable: %s]", strerror(errno)); return dupprintf("[cwd unavailable: %s]", strerror(errno));
} }
/* /*
* Otherwise, ERANGE was returned, meaning the buffer * Otherwise, ERANGE was returned, meaning the buffer
* wasn't big enough. * wasn't big enough.
*/ */
size = size * 3 / 2; size = size * 3 / 2;
buffer = sresize(buffer, size, char); buffer = sresize(buffer, size, char);
} }
} }
struct RFile { struct RFile {
int fd; int fd;
}; };
RFile *open_existing_file(char *name, unsigned long *size, RFile *open_existing_file(char *name, unsigned long *size,
unsigned long *mtime, unsigned long *atime) unsigned long *mtime, unsigned long *atime)
{ {
int fd; int fd;
RFile *ret; RFile *ret;
fd = open(name, O_RDONLY); fd = open(name, O_RDONLY);
if (fd < 0) if (fd < 0)
return NULL; return NULL;
ret = snew(RFile); ret = snew(RFile);
ret->fd = fd; ret->fd = fd;
if (size || mtime || atime) { if (size || mtime || atime) {
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));
memset(&statbuf, 0, sizeof(statbuf)); memset(&statbuf, 0, sizeof(statbuf));
} }
if (size) if (size)
*size = statbuf.st_size; *size = statbuf.st_size;
if (mtime) if (mtime)
*mtime = statbuf.st_mtime; *mtime = statbuf.st_mtime;
if (atime) if (atime)
*atime = statbuf.st_atime; *atime = statbuf.st_atime;
} }
return ret; return ret;
} }
int read_from_file(RFile *f, void *buffer, int length) int read_from_file(RFile *f, void *buffer, int length)
{ {
return read(f->fd, buffer, length); return read(f->fd, buffer, length);
} }
void close_rfile(RFile *f) void close_rfile(RFile *f)
{ {
close(f->fd); close(f->fd);
sfree(f); sfree(f);
} }
struct WFile { struct WFile {
int fd; int fd;
char *name; char *name;
}; };
WFile *open_new_file(char *name) WFile *open_new_file(char *name)
{ {
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, 0666);
if (fd < 0) if (fd < 0)
return NULL; return NULL;
ret = snew(WFile); ret = snew(WFile);
ret->fd = fd; ret->fd = fd;
ret->name = dupstr(name); ret->name = dupstr(name);
return ret; return ret;
} }
int write_to_file(WFile *f, void *buffer, int length) int write_to_file(WFile *f, void *buffer, int length)
{ {
char *p = (char *)buffer; char *p = (char *)buffer;
int so_far = 0; int so_far = 0;
/* Keep trying until we've really written as much as we can. */ /* Keep trying until we've really written as much as we can. */
while (length > 0) { while (length > 0) {
int ret = write(f->fd, p, length); int ret = write(f->fd, p, length);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (ret == 0) if (ret == 0)
break; break;
p += ret; p += ret;
length -= ret; length -= ret;
so_far += ret; so_far += ret;
} }
return so_far; return so_far;
} }
void set_file_times(WFile *f, unsigned long mtime, unsigned long atime) void set_file_times(WFile *f, unsigned long mtime, unsigned long atime)
{ {
struct utimbuf ut; struct utimbuf ut;
ut.actime = atime; ut.actime = atime;
ut.modtime = mtime; ut.modtime = mtime;
utime(f->name, &ut); utime(f->name, &ut);
} }
/* Closes and frees the WFile */ /* Closes and frees the WFile */
void close_wfile(WFile *f) void close_wfile(WFile *f)
{ {
close(f->fd); close(f->fd);
sfree(f->name); sfree(f->name);
sfree(f); sfree(f);
} }
int file_type(char *name) int file_type(char *name)
{ {
struct stat statbuf; struct stat statbuf;
if (stat(name, &statbuf) < 0) { if (stat(name, &statbuf) < 0) {
if (errno != ENOENT) if (errno != ENOENT)
fprintf(stderr, "%s: stat: %s\n", name, strerror(errno)); fprintf(stderr, "%s: stat: %s\n", name, strerror(errno));
return FILE_TYPE_NONEXISTENT; return FILE_TYPE_NONEXISTENT;
} }
if (S_ISREG(statbuf.st_mode)) if (S_ISREG(statbuf.st_mode))
return FILE_TYPE_FILE; return FILE_TYPE_FILE;
if (S_ISDIR(statbuf.st_mode)) if (S_ISDIR(statbuf.st_mode))
return FILE_TYPE_DIRECTORY; return FILE_TYPE_DIRECTORY;
return FILE_TYPE_WEIRD; return FILE_TYPE_WEIRD;
} }
struct DirHandle { struct DirHandle {
DIR *dir; DIR *dir;
}; };
DirHandle *open_directory(char *name) DirHandle *open_directory(char *name)
{ {
DIR *dir; DIR *dir;
DirHandle *ret; DirHandle *ret;
dir = opendir(name); dir = opendir(name);
if (!dir) if (!dir)
return NULL; return NULL;
ret = snew(DirHandle); ret = snew(DirHandle);
ret->dir = dir; ret->dir = dir;
return ret; return ret;
} }
char *read_filename(DirHandle *dir) char *read_filename(DirHandle *dir)
{ {
struct dirent *de; struct dirent *de;
do { do {
de = readdir(dir->dir); de = readdir(dir->dir);
if (de == NULL) if (de == NULL)
return NULL; return NULL;
} while ((de->d_name[0] == '.' && } while ((de->d_name[0] == '.' &&
(de->d_name[1] == '\0' || (de->d_name[1] == '\0' ||
(de->d_name[1] == '.' && de->d_name[2] == '\0')))); (de->d_name[1] == '.' && de->d_name[2] == '\0'))));
return dupstr(de->d_name); return dupstr(de->d_name);
} }
void close_directory(DirHandle *dir) void close_directory(DirHandle *dir)
{ {
closedir(dir->dir); closedir(dir->dir);
sfree(dir); sfree(dir);
} }
int test_wildcard(char *name, int cmdline) int test_wildcard(char *name, int cmdline)
{ {
/* /*
* On Unix, we currently don't support local wildcards at all. * On Unix, we currently don't support local wildcards at all.
* We will have to do so (FIXME) once PSFTP starts implementing * We will have to do so (FIXME) once PSFTP starts implementing
* mput, but until then we can assume `cmdline' is always set. * mput, but until then we can assume `cmdline' is always set.
*/ */
struct stat statbuf; struct stat statbuf;
assert(cmdline); assert(cmdline);
if (stat(name, &statbuf) < 0) if (stat(name, &statbuf) < 0)
return WCTYPE_NONEXISTENT; return WCTYPE_NONEXISTENT;
else else
return WCTYPE_FILENAME; return WCTYPE_FILENAME;
} }
/* /*
* Actually return matching file names for a local wildcard. FIXME: * Actually return matching file names for a local wildcard. FIXME:
* we currently don't support this at all. * we currently don't support this at all.
*/ */
struct WildcardMatcher { struct WildcardMatcher {
int x; int x;
}; };
WildcardMatcher *begin_wildcard_matching(char *name) { return NULL; } WildcardMatcher *begin_wildcard_matching(char *name) { return NULL; }
char *wildcard_get_filename(WildcardMatcher *dir) { return NULL; } char *wildcard_get_filename(WildcardMatcher *dir) { return NULL; }
void finish_wildcard_matching(WildcardMatcher *dir) {} void finish_wildcard_matching(WildcardMatcher *dir) {}
int create_directory(char *name) int create_directory(char *name)
{ {
return mkdir(name, 0777) == 0; return mkdir(name, 0777) == 0;
} }
char *dir_file_cat(char *dir, char *file) char *dir_file_cat(char *dir, char *file)
{ {
return dupcat(dir, "/", file, NULL); return dupcat(dir, "/", file, NULL);
} }
/* /*
* Wait for some network data and process it. * Wait for some network data and process it.
*/ */
int ssh_sftp_loop_iteration(void) int ssh_sftp_loop_iteration(void)
{ {
fd_set rset, wset, xset; fd_set rset, wset, xset;
int i, fdcount, fdsize, *fdlist; int i, fdcount, fdsize, *fdlist;
int fd, fdstate, rwx, ret, maxfd; int fd, fdstate, rwx, ret, maxfd;
fdlist = NULL; fdlist = NULL;
fdcount = fdsize = 0; fdcount = fdsize = 0;
/* Count the currently active fds. */ /* Count the currently active fds. */
i = 0; i = 0;
for (fd = first_fd(&fdstate, &rwx); fd >= 0; for (fd = first_fd(&fdstate, &rwx); fd >= 0;
fd = next_fd(&fdstate, &rwx)) i++; fd = next_fd(&fdstate, &rwx)) i++;
if (i < 1) if (i < 1)
return -1; /* doom */ return -1; /* doom */
/* Expand the fdlist buffer if necessary. */ /* Expand the fdlist buffer if necessary. */
if (i > fdsize) { if (i > fdsize) {
fdsize = i + 16; fdsize = i + 16;
fdlist = sresize(fdlist, fdsize, int); fdlist = sresize(fdlist, fdsize, int);
} }
FD_ZERO(&rset); FD_ZERO(&rset);
FD_ZERO(&wset); FD_ZERO(&wset);
FD_ZERO(&xset); FD_ZERO(&xset);
maxfd = 0; maxfd = 0;
/* /*
* Add all currently open fds to the select sets, and store * Add all currently open fds to the select sets, and store
* them in fdlist as well. * them in fdlist as well.
*/ */
fdcount = 0; fdcount = 0;
for (fd = first_fd(&fdstate, &rwx); fd >= 0; for (fd = first_fd(&fdstate, &rwx); fd >= 0;
fd = next_fd(&fdstate, &rwx)) { fd = next_fd(&fdstate, &rwx)) {
fdlist[fdcount++] = fd; fdlist[fdcount++] = fd;
if (rwx & 1) if (rwx & 1)
FD_SET_MAX(fd, maxfd, rset); FD_SET_MAX(fd, maxfd, rset);
if (rwx & 2) if (rwx & 2)
FD_SET_MAX(fd, maxfd, wset); FD_SET_MAX(fd, maxfd, wset);
if (rwx & 4) if (rwx & 4)
FD_SET_MAX(fd, maxfd, xset); FD_SET_MAX(fd, maxfd, xset);
} }
do { do {
ret = select(maxfd, &rset, &wset, &xset, NULL); ret = select(maxfd, &rset, &wset, &xset, NULL);
} while (ret < 0 && errno == EINTR); } while (ret < 0 && errno == EINTR);
if (ret < 0) { if (ret < 0) {
perror("select"); perror("select");
exit(1); exit(1);
} }
for (i = 0; i < fdcount; i++) { for (i = 0; i < fdcount; i++) {
fd = fdlist[i]; fd = fdlist[i];
/* /*
* We must process exceptional notifications before * We must process exceptional notifications before
* ordinary readability ones, or we may go straight * ordinary readability ones, or we may go straight
* past the urgent marker. * past the urgent marker.
*/ */
if (FD_ISSET(fd, &xset)) if (FD_ISSET(fd, &xset))
select_result(fd, 4); select_result(fd, 4);
if (FD_ISSET(fd, &rset)) if (FD_ISSET(fd, &rset))
select_result(fd, 1); select_result(fd, 1);
if (FD_ISSET(fd, &wset)) if (FD_ISSET(fd, &wset))
select_result(fd, 2); select_result(fd, 2);
} }
sfree(fdlist); sfree(fdlist);
return 0; return 0;
} }
/* /*
* Main program: do platform-specific initialisation and then call * Main program: do platform-specific initialisation and then call
* psftp_main(). * psftp_main().
*/ */
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
uxsel_init(); uxsel_init();
return psftp_main(argc, argv); return psftp_main(argc, argv);
} }