source: filezilla/trunk/fuentes/src/putty/unix/uxsftp.c @ 130

Last change on this file since 130 was 130, checked in by jrpelegrina, 4 years ago

First release to xenial

File size: 11.9 KB
Line 
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 <stdlib.h>
9#include <fcntl.h>
10#include <dirent.h>
11#include <unistd.h>
12#include <utime.h>
13#include <errno.h>
14#include <assert.h>
15#include <glob.h>
16#ifndef HAVE_NO_SYS_SELECT_H
17#include <sys/select.h>
18#endif
19
20#include "putty.h"
21#include "ssh.h"
22#include "psftp.h"
23#include "int64.h"
24
25/*
26 * In PSFTP our selects are synchronous, so these functions are
27 * empty stubs.
28 */
29uxsel_id *uxsel_input_add(int fd, int rwx) { return NULL; }
30void uxsel_input_remove(uxsel_id *id) { }
31
32char *x_get_default(const char *key)
33{
34    return NULL;                       /* this is a stub */
35}
36
37void platform_get_x11_auth(struct X11Display *display, Conf *conf)
38{
39    /* Do nothing, therefore no auth. */
40}
41const int platform_uses_x11_unix_by_default = TRUE;
42
43/*
44 * Default settings that are specific to PSFTP.
45 */
46char *platform_default_s(const char *name)
47{
48    return NULL;
49}
50
51int platform_default_i(const char *name, int def)
52{
53    return def;
54}
55
56FontSpec *platform_default_fontspec(const char *name)
57{
58    return fontspec_new("");
59}
60
61Filename *platform_default_filename(const char *name)
62{
63    if (!strcmp(name, "LogFileName"))
64        return filename_from_str("putty.log");
65    else
66        return filename_from_str("");
67}
68
69char *get_ttymode(void *frontend, const char *mode) { return NULL; }
70
71int get_userpass_input(prompts_t *p, const unsigned char *in, int inlen)
72{
73    int ret;
74    ret = cmdline_get_passwd_input(p, in, inlen);
75    if (ret == -1)
76        ret = console_get_userpass_input(p, in, inlen);
77    return ret;
78}
79
80/*
81 * Set local current directory. Returns NULL on success, or else an
82 * error message which must be freed after printing.
83 */
84char *psftp_lcd(char *dir)
85{
86    if (chdir(dir) < 0)
87        return dupprintf("%s: chdir: %s", dir, strerror(errno));
88    else
89        return NULL;
90}
91
92/*
93 * Get local current directory. Returns a string which must be
94 * freed.
95 */
96char *psftp_getcwd(void)
97{
98    char *buffer, *ret;
99    int size = 256;
100
101    buffer = snewn(size, char);
102    while (1) {
103        ret = getcwd(buffer, size);
104        if (ret != NULL)
105            return ret;
106        if (errno != ERANGE) {
107            sfree(buffer);
108            return dupprintf("[cwd unavailable: %s]", strerror(errno));
109        }
110        /*
111         * Otherwise, ERANGE was returned, meaning the buffer
112         * wasn't big enough.
113         */
114        size = size * 3 / 2;
115        buffer = sresize(buffer, size, char);
116    }
117}
118
119struct RFile {
120    int fd;
121};
122
123RFile *open_existing_file(const char *name, uint64 *size,
124                          unsigned long *mtime, unsigned long *atime,
125                          long *perms)
126{
127    int fd;
128    RFile *ret;
129
130    fd = open(name, O_RDONLY);
131    if (fd < 0)
132    {
133        fzprintf(sftpStatus, "%s: open: %s", name, strerror(errno));
134        return NULL;
135    }
136
137    ret = snew(RFile);
138    ret->fd = fd;
139
140    if (size || mtime || atime || perms) {
141        struct stat statbuf;
142        if (fstat(fd, &statbuf) < 0) {
143            fzprintf(sftpStatus, "%s: stat: %s", name, strerror(errno));
144            memset(&statbuf, 0, sizeof(statbuf));
145        }
146
147        if (size)
148            *size = uint64_make((statbuf.st_size >> 16) >> 16,
149                                statbuf.st_size);
150               
151        if (mtime)
152            *mtime = statbuf.st_mtime;
153
154        if (atime)
155            *atime = statbuf.st_atime;
156
157        if (perms)
158            *perms = statbuf.st_mode;
159    }
160
161    return ret;
162}
163
164int read_from_file(RFile *f, void *buffer, int length)
165{
166    return read(f->fd, buffer, length);
167}
168
169void close_rfile(RFile *f)
170{
171    close(f->fd);
172    sfree(f);
173}
174
175struct WFile {
176    int fd;
177    char *name;
178};
179
180WFile *open_new_file(const char *name, long perms)
181{
182    int fd;
183    WFile *ret;
184
185    fd = open(name, O_CREAT | O_TRUNC | O_WRONLY,
186              (mode_t)(perms ? perms : 0666));
187    if (fd < 0)
188        return NULL;
189
190    ret = snew(WFile);
191    ret->fd = fd;
192    ret->name = dupstr(name);
193
194    return ret;
195}
196
197
198WFile *open_existing_wfile(const char *name, uint64 *size)
199{
200    int fd;
201    WFile *ret;
202
203    fd = open(name, O_APPEND | O_WRONLY);
204    if (fd < 0)
205        return NULL;
206
207    ret = snew(WFile);
208    ret->fd = fd;
209    ret->name = dupstr(name);
210
211    if (size) {
212        struct stat statbuf;
213        if (fstat(fd, &statbuf) < 0) {
214            fprintf(stderr, "%s: stat: %s\n", name, strerror(errno));
215            memset(&statbuf, 0, sizeof(statbuf));
216        }
217
218        *size = uint64_make((statbuf.st_size >> 16) >> 16,
219                            statbuf.st_size);
220    }
221
222    return ret;
223}
224
225int write_to_file(WFile *f, void *buffer, int length)
226{
227    char *p = (char *)buffer;
228    int so_far = 0;
229
230    /* Keep trying until we've really written as much as we can. */
231    while (length > 0) {
232        int ret = write(f->fd, p, length);
233
234        if (ret < 0)
235            return ret;
236
237        if (ret == 0)
238            break;
239
240        p += ret;
241        length -= ret;
242        so_far += ret;
243    }
244
245    return so_far;
246}
247
248void set_file_times(WFile *f, unsigned long mtime, unsigned long atime)
249{
250    struct utimbuf ut;
251
252    ut.actime = atime;
253    ut.modtime = mtime;
254
255    utime(f->name, &ut);
256}
257
258/* Closes and frees the WFile */
259void close_wfile(WFile *f)
260{
261    close(f->fd);
262    sfree(f->name);
263    sfree(f);
264}
265
266/* Seek offset bytes through file, from whence, where whence is
267   FROM_START, FROM_CURRENT, or FROM_END */
268int seek_file(WFile *f, uint64 offset, int whence)
269{
270    off_t fileofft;
271    int lseek_whence;
272   
273    fileofft = (((off_t) offset.hi << 16) << 16) + offset.lo;
274
275    switch (whence) {
276    case FROM_START:
277        lseek_whence = SEEK_SET;
278        break;
279    case FROM_CURRENT:
280        lseek_whence = SEEK_CUR;
281        break;
282    case FROM_END:
283        lseek_whence = SEEK_END;
284        break;
285    default:
286        return -1;
287    }
288
289    return lseek(f->fd, fileofft, lseek_whence) >= 0 ? 0 : -1;
290}
291
292uint64 get_file_posn(WFile *f)
293{
294    off_t fileofft;
295    uint64 ret;
296
297    fileofft = lseek(f->fd, (off_t) 0, SEEK_CUR);
298
299    ret = uint64_make((fileofft >> 16) >> 16, fileofft);
300
301    return ret;
302}
303
304int file_type(const char *name)
305{
306    struct stat statbuf;
307
308    if (stat(name, &statbuf) < 0) {
309        if (errno != ENOENT)
310            fprintf(stderr, "%s: stat: %s\n", name, strerror(errno));
311        return FILE_TYPE_NONEXISTENT;
312    }
313
314    if (S_ISREG(statbuf.st_mode))
315        return FILE_TYPE_FILE;
316
317    if (S_ISDIR(statbuf.st_mode))
318        return FILE_TYPE_DIRECTORY;
319
320    return FILE_TYPE_WEIRD;
321}
322
323struct DirHandle {
324    DIR *dir;
325};
326
327DirHandle *open_directory(const char *name)
328{
329    DIR *dir;
330    DirHandle *ret;
331
332    dir = opendir(name);
333    if (!dir)
334        return NULL;
335
336    ret = snew(DirHandle);
337    ret->dir = dir;
338    return ret;
339}
340
341char *read_filename(DirHandle *dir)
342{
343    struct dirent *de;
344
345    do {
346        de = readdir(dir->dir);
347        if (de == NULL)
348            return NULL;
349    } while ((de->d_name[0] == '.' &&
350              (de->d_name[1] == '\0' ||
351               (de->d_name[1] == '.' && de->d_name[2] == '\0'))));
352
353    return dupstr(de->d_name);
354}
355
356void close_directory(DirHandle *dir)
357{
358    closedir(dir->dir);
359    sfree(dir);
360}
361
362int test_wildcard(const char *name, int cmdline)
363{
364    struct stat statbuf;
365
366    if (stat(name, &statbuf) == 0) {
367        return WCTYPE_FILENAME;
368    } else if (cmdline) {
369        /*
370         * On Unix, we never need to parse wildcards coming from
371         * the command line, because the shell will have expanded
372         * them into a filename list already.
373         */
374        return WCTYPE_NONEXISTENT;
375    } else {
376        glob_t globbed;
377        int ret = WCTYPE_NONEXISTENT;
378
379        if (glob(name, GLOB_ERR, NULL, &globbed) == 0) {
380            if (globbed.gl_pathc > 0)
381                ret = WCTYPE_WILDCARD;
382            globfree(&globbed);
383        }
384
385        return ret;
386    }
387}
388
389/*
390 * Actually return matching file names for a local wildcard.
391 */
392struct WildcardMatcher {
393    glob_t globbed;
394    int i;
395};
396WildcardMatcher *begin_wildcard_matching(const char *name) {
397    WildcardMatcher *ret = snew(WildcardMatcher);
398
399    if (glob(name, 0, NULL, &ret->globbed) < 0) {
400        sfree(ret);
401        return NULL;
402    }
403
404    ret->i = 0;
405
406    return ret;
407}
408char *wildcard_get_filename(WildcardMatcher *dir) {
409    if (dir->i < dir->globbed.gl_pathc) {
410        return dupstr(dir->globbed.gl_pathv[dir->i++]);
411    } else
412        return NULL;
413}
414void finish_wildcard_matching(WildcardMatcher *dir) {
415    globfree(&dir->globbed);
416    sfree(dir);
417}
418
419char *stripslashes(const char *str, int local)
420{
421    char *p;
422
423    /*
424     * On Unix, we do the same thing regardless of the 'local'
425     * parameter.
426     */
427    p = strrchr(str, '/');
428    if (p) str = p+1;
429
430    return (char *)str;
431}
432
433int vet_filename(const char *name)
434{
435    if (strchr(name, '/'))
436        return FALSE;
437
438    if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
439        return FALSE;
440
441    return TRUE;
442}
443
444int create_directory(const char *name)
445{
446    return mkdir(name, 0777) == 0;
447}
448
449char *dir_file_cat(const char *dir, const char *file)
450{
451    return dupcat(dir, "/", file, NULL);
452}
453
454/*
455 * Do a select() between all currently active network fds and
456 * optionally stdin.
457 */
458static int ssh_sftp_do_select(int include_stdin, int no_fds_ok)
459{
460    fd_set rset, wset, xset;
461    int i, fdcount, fdsize, *fdlist;
462    int fd, fdstate, rwx, ret, maxfd;
463    unsigned long now = GETTICKCOUNT();
464    unsigned long next;
465
466    fdlist = NULL;
467    fdcount = fdsize = 0;
468
469    if (include_stdin && has_input_pushback())
470        return 0;
471
472    do {
473
474        /* Count the currently active fds. */
475        i = 0;
476        for (fd = first_fd(&fdstate, &rwx); fd >= 0;
477             fd = next_fd(&fdstate, &rwx)) i++;
478
479        if (i < 1 && !no_fds_ok)
480            return -1;                 /* doom */
481
482        /* Expand the fdlist buffer if necessary. */
483        if (i > fdsize) {
484            fdsize = i + 16;
485            fdlist = sresize(fdlist, fdsize, int);
486        }
487
488        FD_ZERO(&rset);
489        FD_ZERO(&wset);
490        FD_ZERO(&xset);
491        maxfd = 0;
492
493        /*
494         * Add all currently open fds to the select sets, and store
495         * them in fdlist as well.
496         */
497        fdcount = 0;
498        for (fd = first_fd(&fdstate, &rwx); fd >= 0;
499             fd = next_fd(&fdstate, &rwx)) {
500            fdlist[fdcount++] = fd;
501            if (rwx & 1)
502                FD_SET_MAX(fd, maxfd, rset);
503            if (rwx & 2)
504                FD_SET_MAX(fd, maxfd, wset);
505            if (rwx & 4)
506                FD_SET_MAX(fd, maxfd, xset);
507        }
508
509        if (include_stdin)
510            FD_SET_MAX(0, maxfd, rset);
511
512        if (toplevel_callback_pending()) {
513            struct timeval tv;
514            tv.tv_sec = 0;
515            tv.tv_usec = 0;
516            ret = select(maxfd, &rset, &wset, &xset, &tv);
517            if (ret == 0)
518                run_toplevel_callbacks();
519        } else if (run_timers(now, &next)) {
520            do {
521                unsigned long then;
522                long ticks;
523                struct timeval tv;
524
525                then = now;
526                now = GETTICKCOUNT();
527                if (now - then > next - then)
528                    ticks = 0;
529                else
530                    ticks = next - now;
531                tv.tv_sec = ticks / 1000;
532                tv.tv_usec = ticks % 1000 * 1000;
533                ret = select(maxfd, &rset, &wset, &xset, &tv);
534                if (ret == 0)
535                    now = next;
536                else
537                    now = GETTICKCOUNT();
538            } while (ret < 0 && errno == EINTR);
539        } else {
540            ret = select(maxfd, &rset, &wset, &xset, NULL);
541        }
542    } while (ret == 0);
543
544    if (ret < 0) {
545        perror("select");
546        exit(1);
547    }
548
549    for (i = 0; i < fdcount; i++) {
550        fd = fdlist[i];
551        /*
552         * We must process exceptional notifications before
553         * ordinary readability ones, or we may go straight
554         * past the urgent marker.
555         */
556        if (FD_ISSET(fd, &xset))
557            select_result(fd, 4);
558        if (FD_ISSET(fd, &rset))
559            select_result(fd, 1);
560        if (FD_ISSET(fd, &wset))
561            select_result(fd, 2);
562    }
563
564    sfree(fdlist);
565
566    run_toplevel_callbacks();
567
568    return FD_ISSET(0, &rset) ? 1 : 0;
569}
570
571/*
572 * Wait for some network data and process it.
573 */
574int ssh_sftp_loop_iteration(void)
575{
576    return ssh_sftp_do_select(FALSE, FALSE);
577}
578
579/*
580 * Read a PSFTP command line from stdin.
581 */
582char *ssh_sftp_get_cmdline(const char *prompt, int no_fds_ok)
583{
584    int ret;
585
586    char* line = get_input_pushback();
587    if (line != 0)
588        return line;
589
590
591    while (1) {
592        ret = ssh_sftp_do_select(TRUE, no_fds_ok);
593        if (ret < 0) {
594            printf("connection died\n");
595            sfree(line);
596            return NULL;               /* woop woop */
597        }
598        if (ret > 0) {
599            int error = 0;
600            line = read_input_line(0, &error);
601            if (error)
602                return NULL;
603
604            if (line == NULL)
605                continue;
606
607            if (line[0] == '-')
608            {
609                ProcessQuotaCmd(line);
610                sfree(line);
611            }
612            else
613                return line;
614        }
615    }
616}
617
618void frontend_net_error_pending(void) {}
619
620/*
621 * Main program: do platform-specific initialisation and then call
622 * psftp_main().
623 */
624int main(int argc, char *argv[])
625{
626    uxsel_init();
627    return psftp_main(argc, argv);
628}
Note: See TracBrowser for help on using the repository browser.