fish.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837
  1. /* Virtual File System: FISH implementation for transfering files over
  2. shell connections.
  3. Copyright (C) 1998 The Free Software Foundation
  4. Written by: 1998 Pavel Machek
  5. Derived from ftpfs.c.
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU Library General Public License
  8. as published by the Free Software Foundation; either version 2 of
  9. the License, or (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU Library General Public License for more details.
  14. You should have received a copy of the GNU Library General Public
  15. License along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
  17. /*
  18. * Read README.fish for protocol specification.
  19. *
  20. * Syntax of path is: /#sh:user@host[:Cr]/path
  21. * where C means you want compressed connection,
  22. * and r means you want to use rsh
  23. *
  24. * Namespace: fish_vfs_ops exported.
  25. */
  26. /* Define this if your ssh can take -I option */
  27. #define HAVE_HACKED_SSH
  28. #include "xdirentry.h"
  29. #include "../src/tty.h" /* enable/disable interrupt key */
  30. #include "../src/main.h"
  31. #include "../src/mem.h"
  32. #include "vfs.h"
  33. #include "tcputil.h"
  34. #include "container.h"
  35. #include "fish.h"
  36. #include <glib.h>
  37. /*
  38. * Reply codes.
  39. */
  40. #define PRELIM 1 /* positive preliminary */
  41. #define COMPLETE 2 /* positive completion */
  42. #define CONTINUE 3 /* positive intermediate */
  43. #define TRANSIENT 4 /* transient negative completion */
  44. #define ERROR 5 /* permanent negative completion */
  45. /* If true, the directory cache is forced to reload */
  46. static int force_expiration = 0;
  47. /* FIXME: prev two variables should be killed */
  48. /* command wait_flag: */
  49. #define NONE 0x00
  50. #define WAIT_REPLY 0x01
  51. #define WANT_STRING 0x02
  52. static char reply_str [80];
  53. static int decode_reply (char *s, int was_garbage)
  54. {
  55. int code;
  56. if (!sscanf(s, "%d", &code)) {
  57. code = 500;
  58. return 5;
  59. }
  60. if (code<100) return was_garbage ? ERROR : (!code ? COMPLETE : PRELIM);
  61. return code / 100;
  62. }
  63. /* Returns a reply code, check /usr/include/arpa/ftp.h for possible values */
  64. static int get_reply (vfs *me, int sock, char *string_buf, int string_len)
  65. {
  66. char answer[1024];
  67. int was_garbage = 0;
  68. for (;;) {
  69. if (!vfs_s_get_line(me, sock, answer, sizeof(answer), '\n')) {
  70. if (string_buf)
  71. *string_buf = 0;
  72. return 4;
  73. }
  74. if (strncmp(answer, "### ", 4)) {
  75. was_garbage = 1;
  76. if (string_buf) {
  77. strncpy(string_buf, answer, string_len - 1);
  78. *(string_buf + string_len - 1) = 0;
  79. }
  80. } else return decode_reply(answer+4, was_garbage);
  81. }
  82. }
  83. #define SUP super->u.fish
  84. static int command (vfs *me, vfs_s_super *super, int wait_reply, char *fmt, ...)
  85. {
  86. va_list ap;
  87. char *str;
  88. int n, status;
  89. FILE *logfile = MEDATA->logfile;
  90. va_start (ap, fmt);
  91. str = g_strdup_vprintf (fmt, ap);
  92. va_end (ap);
  93. if (logfile){
  94. fwrite (str, strlen (str), 1, logfile);
  95. fflush (logfile);
  96. }
  97. enable_interrupt_key();
  98. status = write(SUP.sockw, str, strlen(str));
  99. g_free (str);
  100. disable_interrupt_key();
  101. if (status < 0)
  102. return TRANSIENT;
  103. if (wait_reply)
  104. return get_reply (me, SUP.sockr, (wait_reply & WANT_STRING) ? reply_str : NULL, sizeof (reply_str)-1);
  105. return COMPLETE;
  106. }
  107. static void
  108. free_archive (vfs *me, vfs_s_super *super)
  109. {
  110. if ((SUP.sockw != -1) || (SUP.sockr != -1)){
  111. print_vfs_message ("fish: Disconnecting from %s", super->name);
  112. command(me, super, NONE, "#BYE\nlogout\n");
  113. close(SUP.sockw);
  114. close(SUP.sockr);
  115. SUP.sockw = SUP.sockr = -1;
  116. }
  117. ifree (SUP.host);
  118. ifree (SUP.home);
  119. ifree (SUP.user);
  120. ifree (SUP.cwdir);
  121. ifree (SUP.password);
  122. }
  123. static void
  124. pipeopen(vfs_s_super *super, char *path, char *argv[])
  125. {
  126. int fileset1[2], fileset2[2];
  127. int res;
  128. if ((pipe(fileset1)<0) || (pipe(fileset2)<0))
  129. vfs_die("Could not pipe(): %m.");
  130. if ((res = fork())) {
  131. if (res<0) vfs_die("Could not fork(): %m.");
  132. /* We are the parent */
  133. close(fileset1[0]);
  134. SUP.sockw = fileset1[1];
  135. close(fileset2[1]);
  136. SUP.sockr = fileset2[0];
  137. } else {
  138. close(0);
  139. dup(fileset1[0]);
  140. close(fileset1[0]); close(fileset1[1]);
  141. close(1); close(2);
  142. dup(fileset2[1]);
  143. dup(fileset2[1]);
  144. close(fileset2[0]); close(fileset2[1]);
  145. execvp(path, argv);
  146. vfs_die("Exec failed.");
  147. }
  148. }
  149. /* The returned directory should always contain a trailing slash */
  150. static char *fish_getcwd(vfs *me, vfs_s_super *super)
  151. {
  152. if (command(me, super, WANT_STRING, "#PWD\npwd; echo '### 200'\n") == COMPLETE)
  153. return copy_strings(reply_str, "/", NULL);
  154. ERRNOR (EIO, NULL);
  155. }
  156. static int
  157. open_archive_int (vfs *me, vfs_s_super *super)
  158. {
  159. char *argv[100];
  160. char *xsh = (SUP.flags == FISH_FLAG_RSH ? "rsh" : "ssh");
  161. int i = 0;
  162. argv[i++] = xsh;
  163. #ifdef HAVE_HACKED_SSH
  164. argv[i++] = "-I";
  165. #endif
  166. argv[i++] = "-l";
  167. argv[i++] = SUP.user;
  168. argv[i++] = SUP.host;
  169. if (SUP.flags == FISH_FLAG_COMPRESSED)
  170. argv[i++] = "-C";
  171. argv[i++] = "echo FISH:; /bin/sh";
  172. argv[i++] = NULL;
  173. /* Debugging hack */
  174. #warning Debugging hack, delete me
  175. if (!MEDATA->logfile)
  176. MEDATA->logfile = fopen( "/home/pavel/talk.fish", "w+" ); /* FIXME */
  177. pipeopen(super, xsh, argv );
  178. {
  179. char answer[2048];
  180. print_vfs_message( "fish: Waiting for initial line..." );
  181. if (!vfs_s_get_line(me, SUP.sockr, answer, sizeof(answer), ':'))
  182. ERRNOR (E_PROTO, -1);
  183. print_vfs_message( answer );
  184. if (strstr(answer, "assword")) {
  185. /* Currently, this does not work. ssh reads passwords from
  186. /dev/tty, not from stdin :-(. */
  187. #ifndef HAVE_HACKED_SSH
  188. message_1s (1, _(" Error "), _("Sorry, we can not do password authenticated connections for now."));
  189. ERRNOR (EPERM, -1);
  190. #endif
  191. if (!SUP.password){
  192. char *p, *op;
  193. p = copy_strings (" fish: Password required for ", SUP.user,
  194. " ", NULL);
  195. op = vfs_get_password (p);
  196. free (p);
  197. if (op == NULL)
  198. ERRNOR (EPERM, -1);
  199. SUP.password = strdup (op);
  200. wipe_password(op);
  201. }
  202. print_vfs_message( "fish: Sending password..." );
  203. write(SUP.sockw, SUP.password, strlen(SUP.password));
  204. write(SUP.sockw, "\n", 1);
  205. }
  206. }
  207. print_vfs_message( "FISH: Sending initial line..." );
  208. if (command (me, super, WAIT_REPLY, "#FISH\necho; start_fish_server; echo '### 200'\n") != COMPLETE)
  209. ERRNOR (E_PROTO, -1);
  210. print_vfs_message( "FISH: Handshaking version..." );
  211. if (command (me, super, WAIT_REPLY, "#VER 0.0.0\necho '### 000'\n") != COMPLETE)
  212. ERRNOR (E_PROTO, -1);
  213. print_vfs_message( "FISH: Setting up current directory..." );
  214. SUP.home = fish_getcwd (me, super);
  215. print_vfs_message( "FISH: Connected, home %s.", SUP.home );
  216. #if 0
  217. super->name = copy_strings( "/#sh:", SUP.user, "@", SUP.host, "/", NULL );
  218. #endif
  219. super->name = strdup( "/" );
  220. super->root = vfs_s_new_inode (me, super, vfs_s_default_stat(me, S_IFDIR | 0755));
  221. return 0;
  222. }
  223. int
  224. open_archive (vfs *me, vfs_s_super *super, char *archive_name, char *op)
  225. {
  226. char *host, *user, *password;
  227. int flags;
  228. vfs_split_url (strchr(op, ':')+1, &host, &user, &flags, &password, 0, URL_NOSLASH);
  229. SUP.host = strdup (host);
  230. SUP.user = strdup (user);
  231. SUP.flags = flags;
  232. if (!strncmp( op, "rsh:", 4 ))
  233. SUP.flags |= FISH_FLAG_RSH;
  234. SUP.home = NULL;
  235. if (password)
  236. SUP.password = strdup (password);
  237. return open_archive_int (me, super);
  238. }
  239. static int
  240. archive_same(vfs *me, vfs_s_super *super, char *archive_name, char *op, void *cookie)
  241. {
  242. char *host, *user, *dummy2;
  243. int flags;
  244. vfs_split_url (strchr(op, ':')+1, &host, &user, &flags, &dummy2, 0, URL_NOSLASH);
  245. return ((strcmp (host, SUP.host) == 0) &&
  246. (strcmp (user, SUP.user) == 0) &&
  247. (flags == SUP.flags));
  248. }
  249. int
  250. fish_which (vfs *me, char *path)
  251. {
  252. if (!strncmp (path, "/#sh:", 5))
  253. return 1;
  254. if (!strncmp (path, "/#ssh:", 6))
  255. return 1;
  256. if (!strncmp (path, "/#rsh:", 6))
  257. return 1;
  258. return 0;
  259. }
  260. int
  261. dir_uptodate(vfs *me, vfs_s_inode *ino)
  262. {
  263. struct timeval tim;
  264. return 1; /* Timeouting of directories does not work too well :-(. */
  265. gettimeofday(&tim, NULL);
  266. if (force_expiration) {
  267. force_expiration = 0;
  268. return 0;
  269. }
  270. if (tim.tv_sec < ino->u.fish.timestamp.tv_sec)
  271. return 1;
  272. return 0;
  273. }
  274. static int
  275. dir_load(vfs *me, vfs_s_inode *dir, char *remote_path)
  276. {
  277. vfs_s_super *super = dir->super;
  278. char buffer[8192];
  279. vfs_s_entry *ent = NULL;
  280. FILE *logfile;
  281. logfile = MEDATA->logfile;
  282. print_vfs_message("fish: Reading directory %s...", remote_path);
  283. gettimeofday(&dir->u.fish.timestamp, NULL);
  284. dir->u.fish.timestamp.tv_sec += 10; /* was 360: 10 is good for
  285. stressing direntry layer a bit */
  286. command(me, super, NONE,
  287. "#LIST /%s\nls -lLa /%s | grep '^[^cbt]' | ( while read p x u g s m d y n; do echo \"P$p $u.$g\n"
  288. "S$s\nd$m $d $y\n:$n\n\"; done )\n"
  289. "ls -lLa /%s | grep '^[cb]' | ( while read p x u g a i m d y n; do echo \"P$p $u.$g\n"
  290. "E$a$i\nd$m $d $y\n:$n\n\"; done ); echo '### 200'\n",
  291. remote_path, remote_path, remote_path);
  292. #define SIMPLE_ENTRY vfs_s_generate_entry(me, NULL, dir, 0)
  293. ent = SIMPLE_ENTRY;
  294. while (1) {
  295. int res = vfs_s_get_line_interruptible (me, buffer, sizeof (buffer), SUP.sockr);
  296. if ((!res) || (res == EINTR)) {
  297. vfs_s_free_entry(me, ent);
  298. me->verrno = ECONNRESET;
  299. goto error;
  300. }
  301. if (logfile){
  302. fputs (buffer, logfile);
  303. fputs ("\n", logfile);
  304. fflush (logfile);
  305. }
  306. if (!strncmp(buffer, "### ", 4))
  307. break;
  308. if ((!buffer[0])) {
  309. if (ent->name) {
  310. vfs_s_insert_entry(me, dir, ent);
  311. ent = SIMPLE_ENTRY;
  312. }
  313. continue;
  314. }
  315. #define ST ent->ino->st
  316. switch(buffer[0]) {
  317. case ':': {
  318. char *c;
  319. if (!strcmp(buffer+1, ".") || !strcmp(buffer+1, ".."))
  320. break; /* We'll do . and .. ourself */
  321. ent->name = strdup(buffer+1);
  322. if ((c=strchr(ent->name, ' ')))
  323. *c = 0; /* this is ugly, but we can not handle " " in name */
  324. break;
  325. }
  326. case 'S': ST.st_size = atoi(buffer+1); break;
  327. case 'P': {
  328. int i;
  329. if ((i = vfs_parse_filetype(buffer[1])) ==-1)
  330. break;
  331. ST.st_mode = i;
  332. if ((i = vfs_parse_filemode(buffer+2)) ==-1)
  333. break;
  334. ST.st_mode |= i;
  335. if (S_ISLNK(ST.st_mode))
  336. ST.st_mode = 0;
  337. }
  338. break;
  339. case 'd': {
  340. vfs_split_text(buffer+1);
  341. if (!vfs_parse_filedate(0, &ST.st_ctime))
  342. break;
  343. ST.st_atime = ST.st_mtime = ST.st_ctime;
  344. }
  345. break;
  346. case 'D': {
  347. struct tm tim;
  348. if (sscanf(buffer+1, "%d %d %d %d %d %d", &tim.tm_year, &tim.tm_mon,
  349. &tim.tm_mday, &tim.tm_hour, &tim.tm_min, &tim.tm_sec) != 6)
  350. break;
  351. ST.st_atime = ST.st_mtime = ST.st_ctime = mktime(&tim);
  352. }
  353. break;
  354. case 'E': {
  355. int maj, min;
  356. if (sscanf(buffer+1, "%d,%d", &maj, &min) != 2)
  357. break;
  358. #ifdef HAVE_ST_RDEV
  359. ST.st_rdev = (maj << 8) | min;
  360. #endif
  361. }
  362. case 'L': ent->ino->linkname = strdup(buffer+1);
  363. break;
  364. }
  365. }
  366. vfs_s_free_entry (me, ent);
  367. me->verrno = E_REMOTE;
  368. if (decode_reply(buffer+4, 0) != COMPLETE)
  369. goto error;
  370. print_vfs_message("fish: got listing");
  371. return 0;
  372. error:
  373. print_vfs_message("fish: failed");
  374. return 1;
  375. }
  376. static int
  377. file_store(vfs *me, vfs_s_super *super, char *name, char *localname)
  378. {
  379. int n, total;
  380. char buffer[8192];
  381. struct stat s;
  382. int was_error = 0;
  383. int h;
  384. h = open(localname, O_RDONLY);
  385. if (fstat(h, &s)<0)
  386. ERRNOR (EIO, -1);
  387. /* Use this as stor: ( dd block ; dd smallblock ) | ( cat > file; cat > /dev/null ) */
  388. print_vfs_message("FISH: store %s: sending command...", name );
  389. if (command (me, super, WAIT_REPLY,
  390. "#STOR %d /%s\n> /%s; echo '### 001'; ( dd bs=4096 count=%d; dd bs=%d count=1 ) 2>/dev/null | ( cat > /%s; cat > /dev/null ); echo '### 200'\n",
  391. s.st_size, name, name,
  392. s.st_size / 4096, s.st_size % 4096, name)
  393. != PRELIM)
  394. ERRNOR(E_REMOTE, -1);
  395. total = 0;
  396. while (1) {
  397. while ((n = read(h, buffer, sizeof(buffer))) < 0) {
  398. if ((errno == EINTR) && got_interrupt)
  399. continue;
  400. print_vfs_message("FISH: Local read failed, sending zeros" );
  401. close(h);
  402. h = open( "/dev/zero", O_RDONLY );
  403. }
  404. if (n == 0)
  405. break;
  406. while (write(SUP.sockw, buffer, n) < 0) {
  407. me->verrno = errno;
  408. goto error_return;
  409. }
  410. disable_interrupt_key();
  411. total += n;
  412. print_vfs_message("fish: storing %s %d (%d)",
  413. was_error ? "zeros" : "file", total, s.st_size);
  414. }
  415. if ((get_reply (me, SUP.sockr, NULL, 0) != COMPLETE) || was_error)
  416. ERRNOR (E_REMOTE, 0);
  417. close(h);
  418. return 0;
  419. error_return:
  420. close(h);
  421. get_reply(me, SUP.sockr, NULL, 0);
  422. return -1;
  423. }
  424. static int linear_start(vfs *me, vfs_s_fh *fh, int offset)
  425. {
  426. char *name;
  427. if (offset)
  428. ERRNOR (E_NOTSUPP, 0);
  429. /* fe->local_stat.st_mtime = 0; FIXME: what is this good for? */
  430. name = vfs_s_fullpath (me, fh->ino);
  431. if (!name)
  432. return 0;
  433. if (command(me, FH_SUPER, WANT_STRING,
  434. "#RETR /%s\nls -l /%s | ( read var1 var2 var3 var4 var5 var6; echo $var5 ); echo '### 100'; cat /%s; echo '### 200'\n",
  435. name, name, name )
  436. != PRELIM) ERRNOR (E_REMOTE, 0);
  437. fh->linear = LS_LINEAR_OPEN;
  438. fh->u.fish.got = 0;
  439. if (sscanf( reply_str, "%d", &fh->u.fish.total )!=1)
  440. ERRNOR (E_REMOTE, 0);
  441. return 1;
  442. }
  443. static void
  444. linear_abort (vfs *me, vfs_s_fh *fh)
  445. {
  446. vfs_s_super *super = FH_SUPER;
  447. char buffer[8192];
  448. int n;
  449. print_vfs_message( "Aborting transfer..." );
  450. do {
  451. n = VFS_MIN(8192, fh->u.fish.total - fh->u.fish.got);
  452. if (n)
  453. if ((n = read(SUP.sockr, buffer, n)) < 0)
  454. return;
  455. } while (n);
  456. if (get_reply (me, SUP.sockr, NULL, 0) != COMPLETE)
  457. print_vfs_message( "Error reported after abort." );
  458. else
  459. print_vfs_message( "Aborted transfer would be successfull." );
  460. }
  461. static int
  462. linear_read (vfs *me, vfs_s_fh *fh, void *buf, int len)
  463. {
  464. vfs_s_super *super = FH_SUPER;
  465. int n = 0;
  466. len = VFS_MIN( fh->u.fish.total - fh->u.fish.got, len );
  467. disable_interrupt_key();
  468. while (len && ((n = read (SUP.sockr, buf, len))<0)) {
  469. if ((errno == EINTR) && !got_interrupt())
  470. continue;
  471. break;
  472. }
  473. enable_interrupt_key();
  474. if (n>0) fh->u.fish.got += n;
  475. if (n<0) linear_abort(me, fh);
  476. if ((!n) && ((get_reply (me, SUP.sockr, NULL, 0) != COMPLETE)))
  477. ERRNOR (E_REMOTE, -1);
  478. ERRNOR (errno, n);
  479. }
  480. static void
  481. linear_close (vfs *me, vfs_s_fh *fh)
  482. {
  483. if (fh->u.fish.total != fh->u.fish.got)
  484. linear_abort(me, fh);
  485. }
  486. static int
  487. fish_ctl (void *fh, int ctlop, int arg)
  488. {
  489. return 0;
  490. switch (ctlop) {
  491. case MCCTL_IS_NOTREADY:
  492. {
  493. int v;
  494. if (!FH->linear)
  495. vfs_die ("You may not do this");
  496. if (FH->linear == LS_LINEAR_CLOSED)
  497. return 0;
  498. v = vfs_s_select_on_two (FH_SUPER->u.fish.sockr, 0);
  499. if (((v < 0) && (errno == EINTR)) || v == 0)
  500. return 1;
  501. return 0;
  502. }
  503. default:
  504. return 0;
  505. }
  506. }
  507. static int
  508. send_fish_command(vfs *me, vfs_s_super *super, char *cmd, int flags)
  509. {
  510. int r;
  511. r = command (me, super, WAIT_REPLY, cmd);
  512. vfs_add_noncurrent_stamps (&vfs_fish_ops, (vfsid) super, NULL);
  513. if (r != COMPLETE) ERRNOR (E_REMOTE, -1);
  514. if (flags & OPT_FLUSH)
  515. vfs_s_invalidate(me, super);
  516. return 0;
  517. }
  518. #define PREFIX \
  519. char buf[999]; \
  520. char *rpath; \
  521. vfs_s_super *super; \
  522. if (!(rpath = vfs_s_get_path_mangle(me, path, &super, 0))) \
  523. return -1;
  524. #define POSTFIX(flags) \
  525. return send_fish_command(me, super, buf, flags);
  526. static int
  527. fish_chmod (vfs *me, char *path, int mode)
  528. {
  529. PREFIX
  530. sprintf(buf, "#CHMOD %4.4o /%s\nchmod %4.4o /%s; echo '### 000'\n",
  531. mode & 07777, rpath,
  532. mode & 07777, rpath);
  533. POSTFIX(OPT_FLUSH);
  534. }
  535. #define FISH_OP(name, chk, string) \
  536. static int fish_##name (vfs *me, char *path1, char *path2) \
  537. { \
  538. char buf[1024]; \
  539. char *rpath1 = NULL, *rpath2 = NULL; \
  540. vfs_s_super *super1, *super2; \
  541. if (!(rpath1 = vfs_s_get_path_mangle(me, path1, &super1, 0))) \
  542. return -1; \
  543. if (!(rpath2 = vfs_s_get_path_mangle(me, path2, &super2, 0))) \
  544. return -1; \
  545. snprintf(buf, 1023, string "\n", rpath1, rpath2, rpath1, rpath2 ); \
  546. return send_fish_command(me, super2, buf, OPT_FLUSH); \
  547. }
  548. #define XTEST if (bucket1 != bucket2) { ERRNOR (EXDEV, -1); }
  549. FISH_OP(rename, XTEST, "#RENAME /%s /%s\nmv /%s /%s; echo '### 000'" );
  550. FISH_OP(link, XTEST, "#LINK /%s /%s\nln /%s /%s; echo '### 000'" );
  551. static int fish_symlink (vfs *me, char *setto, char *path)
  552. {
  553. PREFIX
  554. sprintf(buf, "#SYMLINK %s /%s\nln -s %s /%s; echo '### 000'\n", setto, rpath, setto, rpath);
  555. POSTFIX(OPT_FLUSH);
  556. }
  557. static int
  558. fish_chown (vfs *me, char *path, int owner, int group)
  559. {
  560. char *sowner, *sgroup;
  561. PREFIX
  562. sowner = getpwuid( owner )->pw_name;
  563. sgroup = getgrgid( group )->gr_name;
  564. sprintf(buf, "#CHOWN /%s /%s\nchown /%s /%s; echo '### 000'\n",
  565. sowner, rpath,
  566. sowner, rpath);
  567. send_fish_command(me, super, buf, OPT_FLUSH);
  568. /* FIXME: what should we report if chgrp succeeds but chown fails? */
  569. sprintf(buf, "#CHGRP /%s /%s\nchgrp /%s /%s; echo '### 000'\n",
  570. sgroup, rpath,
  571. sgroup, rpath);
  572. POSTFIX(OPT_FLUSH)
  573. }
  574. static int fish_unlink (vfs *me, char *path)
  575. {
  576. PREFIX
  577. sprintf(buf, "#DELE /%s\nrm -f /%s; echo '### 000'\n", rpath, rpath);
  578. POSTFIX(OPT_FLUSH);
  579. }
  580. static int fish_mkdir (vfs *me, char *path, mode_t mode)
  581. {
  582. PREFIX
  583. sprintf(buf, "#MKD /%s\nmkdir /%s; echo '### 000'\n", rpath, rpath);
  584. POSTFIX(OPT_FLUSH);
  585. }
  586. static int fish_rmdir (vfs *me, char *path)
  587. {
  588. PREFIX
  589. sprintf(buf, "#RMD /%s\nrmdir /%s; echo '### 000'\n", rpath, rpath);
  590. POSTFIX(OPT_FLUSH);
  591. }
  592. static int retrieve_file(vfs *me, struct vfs_s_inode *ino)
  593. {
  594. /* If you want reget, you'll have to open file with O_LINEAR */
  595. int total = 0;
  596. char buffer[8192];
  597. int handle, n;
  598. int stat_size = ino->st.st_size;
  599. struct vfs_s_fh fh;
  600. memset(&fh, 0, sizeof(fh));
  601. fh.ino = ino;
  602. if (!(ino->localname = tempnam (NULL, me->name))) ERRNOR (ENOMEM, 0);
  603. handle = open(ino->localname, O_RDWR | O_CREAT | O_TRUNC | O_EXCL, 0600);
  604. if (handle == -1) {
  605. me->verrno = errno;
  606. goto error_4;
  607. }
  608. if (!MEDATA->linear_start (me, &fh, 0))
  609. goto error_3;
  610. /* Clear the interrupt status */
  611. while (1) {
  612. n = linear_read(me, &fh, buffer, sizeof(buffer));
  613. if (n < 0)
  614. goto error_1;
  615. if (!n)
  616. break;
  617. total += n;
  618. vfs_print_stats (me->name, "Getting file", ino->ent->name, total, stat_size);
  619. if (write(handle, buffer, n) < 0) {
  620. me->verrno = errno;
  621. goto error_1;
  622. }
  623. }
  624. linear_close(me, &fh);
  625. close(handle);
  626. if (stat (ino->localname, &ino->u.fish.local_stat) < 0)
  627. ino->u.fish.local_stat.st_mtime = 0;
  628. return 0;
  629. error_1:
  630. linear_close(me, &fh);
  631. error_3:
  632. disable_interrupt_key();
  633. close(handle);
  634. unlink(ino->localname);
  635. error_4:
  636. free(ino->localname);
  637. ino->localname = NULL;
  638. return -1;
  639. }
  640. static int fish_fh_open (vfs *me, vfs_s_fh *fh, int flags, int mode)
  641. {
  642. if (IS_LINEAR(mode)) {
  643. message_1s(1, "Linear mode requested", "?!" );
  644. fh->linear = LS_LINEAR_CLOSED;
  645. return 0;
  646. }
  647. if (!fh->ino->localname)
  648. if (retrieve_file (me, fh->ino)==-1)
  649. return -1;
  650. if (!fh->ino->localname)
  651. vfs_die( "retrieve_file failed to fill in localname" );
  652. return 0;
  653. }
  654. static struct vfs_s_data fish_data = {
  655. NULL,
  656. 0,
  657. 0,
  658. NULL,
  659. NULL, /* init_inode */
  660. NULL, /* free_inode */
  661. NULL, /* init_entry */
  662. NULL, /* archive_check */
  663. archive_same,
  664. open_archive,
  665. free_archive,
  666. fish_fh_open, /* fh_open */
  667. NULL, /* fh_close */
  668. vfs_s_find_entry_linear,
  669. dir_load,
  670. dir_uptodate,
  671. file_store,
  672. linear_start,
  673. linear_read,
  674. linear_close
  675. };
  676. vfs vfs_fish_ops = {
  677. NULL, /* This is place of next pointer */
  678. "FIles tranferred over SHell",
  679. F_EXEC, /* flags */
  680. "sh:", /* prefix */
  681. &fish_data, /* data */
  682. 0, /* errno */
  683. NULL,
  684. NULL,
  685. vfs_s_fill_names,
  686. NULL,
  687. vfs_s_open,
  688. vfs_s_close,
  689. vfs_s_read,
  690. vfs_s_write,
  691. vfs_s_opendir,
  692. vfs_s_readdir,
  693. vfs_s_closedir,
  694. vfs_s_telldir,
  695. vfs_s_seekdir,
  696. vfs_s_stat,
  697. vfs_s_lstat,
  698. vfs_s_fstat,
  699. fish_chmod,
  700. fish_chown,
  701. NULL, /* utime */
  702. vfs_s_readlink,
  703. fish_symlink, /* symlink */
  704. fish_link, /* link */
  705. fish_unlink,
  706. fish_rename, /* rename */
  707. vfs_s_chdir,
  708. vfs_s_ferrno,
  709. vfs_s_lseek,
  710. NULL, /* mknod */
  711. vfs_s_getid,
  712. vfs_s_nothingisopen,
  713. vfs_s_free,
  714. NULL, /* vfs_s_getlocalcopy, */
  715. NULL, /* vfs_s_ungetlocalcopy, */
  716. fish_mkdir,
  717. fish_rmdir,
  718. fish_ctl,
  719. vfs_s_setctl
  720. MMAPNULL
  721. };