]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - unix/uxsftp.c
Remove CRs. Oops :-/
[PuTTY.git] / unix / uxsftp.c
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  */
22 int uxsel_input_add(int fd, int rwx) { return 0; }
23 void uxsel_input_remove(int id) { }
24
25 char *x_get_default(const char *key)
26 {
27     return NULL;                       /* this is a stub */
28 }
29
30 void 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  */
39 char *platform_default_s(const char *name)
40 {
41     return NULL;
42 }
43
44 int platform_default_i(const char *name, int def)
45 {
46     return def;
47 }
48
49 FontSpec platform_default_fontspec(const char *name)
50 {
51     FontSpec ret;
52     *ret.name = '\0';
53     return ret;
54 }
55
56 Filename 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  */
69 void 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) {}
73 void gui_send_errcount(int list, int errs) {}
74 void gui_send_char(int is_stderr, int c) {}
75 void 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  */
82 char *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  */
94 char *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
117 struct RFile {
118     int fd;
119 };
120
121 RFile *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
154 int read_from_file(RFile *f, void *buffer, int length)
155 {
156     return read(f->fd, buffer, length);
157 }
158
159 void close_rfile(RFile *f)
160 {
161     close(f->fd);
162     sfree(f);
163 }
164
165 struct WFile {
166     int fd;
167     char *name;
168 };
169
170 WFile *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
186 int 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
209 void 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 */
220 void close_wfile(WFile *f)
221 {
222     close(f->fd);
223     sfree(f->name);
224     sfree(f);
225 }
226
227 int 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
246 struct DirHandle {
247     DIR *dir;
248 };
249
250 DirHandle *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
264 char *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
279 void close_directory(DirHandle *dir)
280 {
281     closedir(dir->dir);
282     sfree(dir);
283 }
284
285 int 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  */
305 struct WildcardMatcher {
306     int x;
307 };
308 WildcardMatcher *begin_wildcard_matching(char *name) { return NULL; }
309 char *wildcard_get_filename(WildcardMatcher *dir) { return NULL; }
310 void finish_wildcard_matching(WildcardMatcher *dir) {}
311
312 int create_directory(char *name)
313 {
314     return mkdir(name, 0777) == 0;
315 }
316
317 char *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  */
325 int 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  */
402 int main(int argc, char *argv[])
403 {
404     uxsel_init();
405     return psftp_main(argc, argv);
406 }