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