Remove CRs. Oops :-/
[u/mdw/putty] / unix / uxsftp.c
CommitLineData
876eefd4 1/*
2 * uxsftp.c: the Unix-specific parts of PSFTP and PSCP.
3 */
4
5#include <sys/time.h>
6#include <sys/types.h>
7#include <sys/stat.h>
8#include <fcntl.h>
9#include <dirent.h>
10#include <unistd.h>
11#include <utime.h>
12#include <errno.h>
13#include <assert.h>
14
15#include "putty.h"
16#include "psftp.h"
17
18/*
19 * In PSFTP our selects are synchronous, so these functions are
20 * empty stubs.
21 */
22int uxsel_input_add(int fd, int rwx) { return 0; }
23void uxsel_input_remove(int id) { }
24
25char *x_get_default(const char *key)
26{
27 return NULL; /* this is a stub */
28}
29
30void platform_get_x11_auth(char *display, int *protocol,
31 unsigned char *data, int *datalen)
32{
33 /* Do nothing, therefore no auth. */
34}
35
36/*
37 * Default settings that are specific to PSFTP.
38 */
39char *platform_default_s(const char *name)
40{
41 return NULL;
42}
43
44int platform_default_i(const char *name, int def)
45{
46 return def;
47}
48
49FontSpec platform_default_fontspec(const char *name)
50{
51 FontSpec ret;
52 *ret.name = '\0';
53 return ret;
54}
55
56Filename platform_default_filename(const char *name)
57{
58 Filename ret;
59 if (!strcmp(name, "LogFileName"))
60 strcpy(ret.path, "putty.log");
61 else
62 *ret.path = '\0';
63 return ret;
64}
65
66/*
67 * Stubs for the GUI feedback mechanism in Windows PSCP.
68 */
69void gui_update_stats(char *name, unsigned long size,
70 int percentage, unsigned long elapsed,
71 unsigned long done, unsigned long eta,
72 unsigned long ratebs) {}
73void gui_send_errcount(int list, int errs) {}
74void gui_send_char(int is_stderr, int c) {}
75void gui_enable(char *arg) {}
76
77
78/*
79 * Set local current directory. Returns NULL on success, or else an
80 * error message which must be freed after printing.
81 */
82char *psftp_lcd(char *dir)
83{
84 if (chdir(dir) < 0)
85 return dupprintf("%s: chdir: %s", dir, strerror(errno));
86 else
87 return NULL;
88}
89
90/*
91 * Get local current directory. Returns a string which must be
92 * freed.
93 */
94char *psftp_getcwd(void)
95{
96 char *buffer, *ret;
97 int size = 256;
98
99 buffer = snewn(size, char);
100 while (1) {
101 ret = getcwd(buffer, size);
102 if (ret != NULL)
103 return ret;
104 if (errno != ERANGE) {
105 sfree(buffer);
106 return dupprintf("[cwd unavailable: %s]", strerror(errno));
107 }
108 /*
109 * Otherwise, ERANGE was returned, meaning the buffer
110 * wasn't big enough.
111 */
112 size = size * 3 / 2;
113 buffer = sresize(buffer, size, char);
114 }
115}
116
117struct RFile {
118 int fd;
119};
120
121RFile *open_existing_file(char *name, unsigned long *size,
122 unsigned long *mtime, unsigned long *atime)
123{
124 int fd;
125 RFile *ret;
126
127 fd = open(name, O_RDONLY);
128 if (fd < 0)
129 return NULL;
130
131 ret = snew(RFile);
132 ret->fd = fd;
133
134 if (size || mtime || atime) {
135 struct stat statbuf;
136 if (fstat(fd, &statbuf) < 0) {
137 fprintf(stderr, "%s: stat: %s\n", name, strerror(errno));
138 memset(&statbuf, 0, sizeof(statbuf));
139 }
140
141 if (size)
142 *size = statbuf.st_size;
143
144 if (mtime)
145 *mtime = statbuf.st_mtime;
146
147 if (atime)
148 *atime = statbuf.st_atime;
149 }
150
151 return ret;
152}
153
154int read_from_file(RFile *f, void *buffer, int length)
155{
156 return read(f->fd, buffer, length);
157}
158
159void close_rfile(RFile *f)
160{
161 close(f->fd);
162 sfree(f);
163}
164
165struct WFile {
166 int fd;
167 char *name;
168};
169
170WFile *open_new_file(char *name)
171{
172 int fd;
173 WFile *ret;
174
175 fd = open(name, O_CREAT | O_TRUNC | O_WRONLY, 0666);
176 if (fd < 0)
177 return NULL;
178
179 ret = snew(WFile);
180 ret->fd = fd;
181 ret->name = dupstr(name);
182
183 return ret;
184}
185
186int write_to_file(WFile *f, void *buffer, int length)
187{
188 char *p = (char *)buffer;
189 int so_far = 0;
190
191 /* Keep trying until we've really written as much as we can. */
192 while (length > 0) {
193 int ret = write(f->fd, p, length);
194
195 if (ret < 0)
196 return ret;
197
198 if (ret == 0)
199 break;
200
201 p += ret;
202 length -= ret;
203 so_far += ret;
204 }
205
206 return so_far;
207}
208
209void set_file_times(WFile *f, unsigned long mtime, unsigned long atime)
210{
211 struct utimbuf ut;
212
213 ut.actime = atime;
214 ut.modtime = mtime;
215
216 utime(f->name, &ut);
217}
218
219/* Closes and frees the WFile */
220void close_wfile(WFile *f)
221{
222 close(f->fd);
223 sfree(f->name);
224 sfree(f);
225}
226
227int file_type(char *name)
228{
229 struct stat statbuf;
230
231 if (stat(name, &statbuf) < 0) {
232 if (errno != ENOENT)
233 fprintf(stderr, "%s: stat: %s\n", name, strerror(errno));
234 return FILE_TYPE_NONEXISTENT;
235 }
236
237 if (S_ISREG(statbuf.st_mode))
238 return FILE_TYPE_FILE;
239
240 if (S_ISDIR(statbuf.st_mode))
241 return FILE_TYPE_DIRECTORY;
242
243 return FILE_TYPE_WEIRD;
244}
245
246struct DirHandle {
247 DIR *dir;
248};
249
250DirHandle *open_directory(char *name)
251{
252 DIR *dir;
253 DirHandle *ret;
254
255 dir = opendir(name);
256 if (!dir)
257 return NULL;
258
259 ret = snew(DirHandle);
260 ret->dir = dir;
261 return ret;
262}
263
264char *read_filename(DirHandle *dir)
265{
266 struct dirent *de;
267
268 do {
269 de = readdir(dir->dir);
270 if (de == NULL)
271 return NULL;
272 } while ((de->d_name[0] == '.' &&
273 (de->d_name[1] == '\0' ||
274 (de->d_name[1] == '.' && de->d_name[2] == '\0'))));
275
276 return dupstr(de->d_name);
277}
278
279void close_directory(DirHandle *dir)
280{
281 closedir(dir->dir);
282 sfree(dir);
283}
284
285int test_wildcard(char *name, int cmdline)
286{
287 /*
288 * On Unix, we currently don't support local wildcards at all.
289 * We will have to do so (FIXME) once PSFTP starts implementing
290 * mput, but until then we can assume `cmdline' is always set.
291 */
292 struct stat statbuf;
293
294 assert(cmdline);
295 if (stat(name, &statbuf) < 0)
296 return WCTYPE_NONEXISTENT;
297 else
298 return WCTYPE_FILENAME;
299}
300
301/*
302 * Actually return matching file names for a local wildcard. FIXME:
303 * we currently don't support this at all.
304 */
305struct WildcardMatcher {
306 int x;
307};
308WildcardMatcher *begin_wildcard_matching(char *name) { return NULL; }
309char *wildcard_get_filename(WildcardMatcher *dir) { return NULL; }
310void finish_wildcard_matching(WildcardMatcher *dir) {}
311
312int create_directory(char *name)
313{
314 return mkdir(name, 0777) == 0;
315}
316
317char *dir_file_cat(char *dir, char *file)
318{
319 return dupcat(dir, "/", file, NULL);
320}
321
322/*
323 * Wait for some network data and process it.
324 */
325int ssh_sftp_loop_iteration(void)
326{
327 fd_set rset, wset, xset;
328 int i, fdcount, fdsize, *fdlist;
329 int fd, fdstate, rwx, ret, maxfd;
330
331 fdlist = NULL;
332 fdcount = fdsize = 0;
333
334 /* Count the currently active fds. */
335 i = 0;
336 for (fd = first_fd(&fdstate, &rwx); fd >= 0;
337 fd = next_fd(&fdstate, &rwx)) i++;
338
339 if (i < 1)
340 return -1; /* doom */
341
342 /* Expand the fdlist buffer if necessary. */
343 if (i > fdsize) {
344 fdsize = i + 16;
345 fdlist = sresize(fdlist, fdsize, int);
346 }
347
348 FD_ZERO(&rset);
349 FD_ZERO(&wset);
350 FD_ZERO(&xset);
351 maxfd = 0;
352
353 /*
354 * Add all currently open fds to the select sets, and store
355 * them in fdlist as well.
356 */
357 fdcount = 0;
358 for (fd = first_fd(&fdstate, &rwx); fd >= 0;
359 fd = next_fd(&fdstate, &rwx)) {
360 fdlist[fdcount++] = fd;
361 if (rwx & 1)
362 FD_SET_MAX(fd, maxfd, rset);
363 if (rwx & 2)
364 FD_SET_MAX(fd, maxfd, wset);
365 if (rwx & 4)
366 FD_SET_MAX(fd, maxfd, xset);
367 }
368
369 do {
370 ret = select(maxfd, &rset, &wset, &xset, NULL);
371 } while (ret < 0 && errno == EINTR);
372
373 if (ret < 0) {
374 perror("select");
375 exit(1);
376 }
377
378 for (i = 0; i < fdcount; i++) {
379 fd = fdlist[i];
380 /*
381 * We must process exceptional notifications before
382 * ordinary readability ones, or we may go straight
383 * past the urgent marker.
384 */
385 if (FD_ISSET(fd, &xset))
386 select_result(fd, 4);
387 if (FD_ISSET(fd, &rset))
388 select_result(fd, 1);
389 if (FD_ISSET(fd, &wset))
390 select_result(fd, 2);
391 }
392
393 sfree(fdlist);
394
395 return 0;
396}
397
398/*
399 * Main program: do platform-specific initialisation and then call
400 * psftp_main().
401 */
402int main(int argc, char *argv[])
403{
404 uxsel_init();
405 return psftp_main(argc, argv);
406}