And just to prove that psftp.c really is now platform-independent
[u/mdw/putty] / unix / uxsftp.c
1 /*
2 * uxsftp.c: the Unix-specific parts of PSFTP.
3 */
4
5 #include <sys/time.h>
6 #include <sys/types.h>
7 #include <unistd.h>
8 #include <errno.h>
9 #include <pwd.h>
10
11 #include "putty.h"
12 #include "psftp.h"
13
14 /*
15 * In PSFTP our selects are synchronous, so these functions are
16 * empty stubs.
17 */
18 int uxsel_input_add(int fd, int rwx) { return 0; }
19 void uxsel_input_remove(int id) { }
20
21 char *x_get_default(const char *key)
22 {
23 return NULL; /* this is a stub */
24 }
25
26 void platform_get_x11_auth(char *display, int *protocol,
27 unsigned char *data, int *datalen)
28 {
29 /* Do nothing, therefore no auth. */
30 }
31
32 /*
33 * Default settings that are specific to PSFTP.
34 */
35 char *platform_default_s(const char *name)
36 {
37 if (!strcmp(name, "UserName")) {
38 /*
39 * Remote login username will default to the local username.
40 */
41 struct passwd *p;
42 uid_t uid = getuid();
43 char *user, *ret = NULL;
44
45 /*
46 * First, find who we think we are using getlogin. If this
47 * agrees with our uid, we'll go along with it. This should
48 * allow sharing of uids between several login names whilst
49 * coping correctly with people who have su'ed.
50 */
51 user = getlogin();
52 setpwent();
53 if (user)
54 p = getpwnam(user);
55 else
56 p = NULL;
57 if (p && p->pw_uid == uid) {
58 /*
59 * The result of getlogin() really does correspond to
60 * our uid. Fine.
61 */
62 ret = user;
63 } else {
64 /*
65 * If that didn't work, for whatever reason, we'll do
66 * the simpler version: look up our uid in the password
67 * file and map it straight to a name.
68 */
69 p = getpwuid(uid);
70 ret = p->pw_name;
71 }
72 endpwent();
73
74 return ret;
75 }
76 return NULL;
77 }
78
79 int platform_default_i(const char *name, int def)
80 {
81 return def;
82 }
83
84 FontSpec platform_default_fontspec(const char *name)
85 {
86 FontSpec ret;
87 *ret.name = '\0';
88 return ret;
89 }
90
91 Filename platform_default_filename(const char *name)
92 {
93 Filename ret;
94 if (!strcmp(name, "LogFileName"))
95 strcpy(ret.path, "putty.log");
96 else
97 *ret.path = '\0';
98 return ret;
99 }
100
101 /*
102 * Set local current directory. Returns NULL on success, or else an
103 * error message which must be freed after printing.
104 */
105 char *psftp_lcd(char *dir)
106 {
107 if (chdir(dir) < 0)
108 return dupprintf("%s: chdir: %s", dir, strerror(errno));
109 else
110 return NULL;
111 }
112
113 /*
114 * Get local current directory. Returns a string which must be
115 * freed.
116 */
117 char *psftp_getcwd(void)
118 {
119 char *buffer, *ret;
120 int size = 256;
121
122 buffer = snewn(size, char);
123 while (1) {
124 ret = getcwd(buffer, size);
125 if (ret != NULL)
126 return ret;
127 if (errno != ERANGE) {
128 sfree(buffer);
129 return dupprintf("[cwd unavailable: %s]", strerror(errno));
130 }
131 /*
132 * Otherwise, ERANGE was returned, meaning the buffer
133 * wasn't big enough.
134 */
135 size = size * 3 / 2;
136 buffer = sresize(buffer, size, char);
137 }
138 }
139
140 /*
141 * Wait for some network data and process it.
142 */
143 int ssh_sftp_loop_iteration(void)
144 {
145 fd_set rset, wset, xset;
146 int i, fdcount, fdsize, *fdlist;
147 int fd, fdstate, rwx, ret, maxfd;
148
149 fdlist = NULL;
150 fdcount = fdsize = 0;
151
152 /* Count the currently active fds. */
153 i = 0;
154 for (fd = first_fd(&fdstate, &rwx); fd >= 0;
155 fd = next_fd(&fdstate, &rwx)) i++;
156
157 if (i < 1)
158 return -1; /* doom */
159
160 /* Expand the fdlist buffer if necessary. */
161 if (i > fdsize) {
162 fdsize = i + 16;
163 fdlist = sresize(fdlist, fdsize, int);
164 }
165
166 FD_ZERO(&rset);
167 FD_ZERO(&wset);
168 FD_ZERO(&xset);
169 maxfd = 0;
170
171 /*
172 * Add all currently open fds to the select sets, and store
173 * them in fdlist as well.
174 */
175 fdcount = 0;
176 for (fd = first_fd(&fdstate, &rwx); fd >= 0;
177 fd = next_fd(&fdstate, &rwx)) {
178 fdlist[fdcount++] = fd;
179 if (rwx & 1)
180 FD_SET_MAX(fd, maxfd, rset);
181 if (rwx & 2)
182 FD_SET_MAX(fd, maxfd, wset);
183 if (rwx & 4)
184 FD_SET_MAX(fd, maxfd, xset);
185 }
186
187 do {
188 ret = select(maxfd, &rset, &wset, &xset, NULL);
189 } while (ret < 0 && errno == EINTR);
190
191 if (ret < 0) {
192 perror("select");
193 exit(1);
194 }
195
196 for (i = 0; i < fdcount; i++) {
197 fd = fdlist[i];
198 /*
199 * We must process exceptional notifications before
200 * ordinary readability ones, or we may go straight
201 * past the urgent marker.
202 */
203 if (FD_ISSET(fd, &xset))
204 select_result(fd, 4);
205 if (FD_ISSET(fd, &rset))
206 select_result(fd, 1);
207 if (FD_ISSET(fd, &wset))
208 select_result(fd, 2);
209 }
210
211 sfree(fdlist);
212
213 return 0;
214 }
215
216 /*
217 * Main program: do platform-specific initialisation and then call
218 * psftp_main().
219 */
220 int main(int argc, char *argv[])
221 {
222 uxsel_init();
223 return psftp_main(argc, argv);
224 }