ru.po: Corrections from Evgeny Bulgakov <bgav@netvision.net.il>
[midnight-commander.git] / vfs / fish.c
blobd36095adb40ef909d2012038d323d989d51ee548
1 /* Virtual File System: FISH implementation for transfering files over
2 shell connections.
4 Copyright (C) 1998 The Free Software Foundation
6 Written by: 1998 Pavel Machek
8 Derived from ftpfs.c.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU Library General Public License
12 as published by the Free Software Foundation; either version 2 of
13 the License, or (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Library General Public License for more details.
20 You should have received a copy of the GNU Library General Public
21 License along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
25 * Read README.fish for protocol specification.
27 * Syntax of path is: /#sh:user@host[:Cr]/path
28 * where C means you want compressed connection,
29 * and r means you want to use rsh
31 * Namespace: fish_vfs_ops exported.
34 /* Define this if your ssh can take -I option */
36 #undef HAVE_HACKED_SSH
38 #include "utilvfs.h"
40 #include "xdirentry.h"
41 #include "vfs.h"
42 #include "tcputil.h"
43 #include "container.h"
44 #include "fish.h"
47 * Reply codes.
49 #define PRELIM 1 /* positive preliminary */
50 #define COMPLETE 2 /* positive completion */
51 #define CONTINUE 3 /* positive intermediate */
52 #define TRANSIENT 4 /* transient negative completion */
53 #define ERROR 5 /* permanent negative completion */
55 /* If true, the directory cache is forced to reload */
56 static int force_expiration = 0;
58 /* FIXME: prev two variables should be killed */
60 /* command wait_flag: */
61 #define NONE 0x00
62 #define WAIT_REPLY 0x01
63 #define WANT_STRING 0x02
64 static char reply_str [80];
66 static int decode_reply (char *s, int was_garbage)
68 int code;
69 if (!sscanf(s, "%d", &code)) {
70 code = 500;
71 return 5;
73 if (code<100) return was_garbage ? ERROR : (!code ? COMPLETE : PRELIM);
74 return code / 100;
77 /* Returns a reply code, check /usr/include/arpa/ftp.h for possible values */
78 static int get_reply (vfs *me, int sock, char *string_buf, int string_len)
80 char answer[1024];
81 int was_garbage = 0;
83 for (;;) {
84 if (!vfs_s_get_line(me, sock, answer, sizeof(answer), '\n')) {
85 if (string_buf)
86 *string_buf = 0;
87 return 4;
89 if (strncmp(answer, "### ", 4)) {
90 was_garbage = 1;
91 if (string_buf) {
92 strncpy(string_buf, answer, string_len - 1);
93 *(string_buf + string_len - 1) = 0;
95 } else return decode_reply(answer+4, was_garbage);
99 #define SUP super->u.fish
101 static int command (vfs *me, vfs_s_super *super, int wait_reply, char *fmt, ...)
103 va_list ap;
104 char *str;
105 int status;
106 FILE *logfile = MEDATA->logfile;
108 va_start (ap, fmt);
110 str = g_strdup_vprintf (fmt, ap);
111 va_end (ap);
113 if (logfile){
114 fwrite (str, strlen (str), 1, logfile);
115 fflush (logfile);
118 enable_interrupt_key();
120 status = write(SUP.sockw, str, strlen(str));
121 g_free (str);
123 disable_interrupt_key();
124 if (status < 0)
125 return TRANSIENT;
127 if (wait_reply)
128 return get_reply (me, SUP.sockr, (wait_reply & WANT_STRING) ? reply_str : NULL, sizeof (reply_str)-1);
129 return COMPLETE;
132 static void
133 free_archive (vfs *me, vfs_s_super *super)
135 if ((SUP.sockw != -1) || (SUP.sockr != -1)){
136 print_vfs_message (_("fish: Disconnecting from %s"), super->name?super->name:"???");
137 command(me, super, NONE, "#BYE\nlogout\n");
138 close(SUP.sockw);
139 close(SUP.sockr);
140 SUP.sockw = SUP.sockr = -1;
142 ifree (SUP.host);
143 ifree (SUP.home);
144 ifree (SUP.user);
145 ifree (SUP.cwdir);
146 ifree (SUP.password);
149 static void
150 pipeopen(vfs_s_super *super, char *path, char *argv[])
152 int fileset1[2], fileset2[2];
153 int res;
155 if ((pipe(fileset1)<0) || (pipe(fileset2)<0))
156 vfs_die("Could not pipe(): %m.");
158 if ((res = fork())) {
159 if (res<0) vfs_die("Could not fork(): %m.");
160 /* We are the parent */
161 close(fileset1[0]);
162 SUP.sockw = fileset1[1];
163 close(fileset2[1]);
164 SUP.sockr = fileset2[0];
165 } else {
166 close(0);
167 dup(fileset1[0]);
168 close(fileset1[0]); close(fileset1[1]);
169 close(1); close(2);
170 dup(fileset2[1]);
171 dup(fileset2[1]);
172 close(fileset2[0]); close(fileset2[1]);
173 execvp(path, argv);
174 vfs_die("Exec failed.");
178 /* The returned directory should always contain a trailing slash */
179 static char *fish_getcwd(vfs *me, vfs_s_super *super)
181 if (command(me, super, WANT_STRING, "#PWD\npwd; echo '### 200'\n") == COMPLETE)
182 return g_strconcat (reply_str, "/", NULL);
183 ERRNOR (EIO, NULL);
185 static int
186 open_archive_int (vfs *me, vfs_s_super *super)
188 char *argv[100];
189 char *xsh = (SUP.flags == FISH_FLAG_RSH ? "rsh" : "ssh");
190 int i = 0;
192 argv[i++] = xsh;
193 #ifdef HAVE_HACKED_SSH
194 argv[i++] = "-I";
195 #endif
196 argv[i++] = "-l";
197 argv[i++] = SUP.user;
198 argv[i++] = SUP.host;
199 if (SUP.flags == FISH_FLAG_COMPRESSED)
200 argv[i++] = "-C";
201 argv[i++] = "echo FISH:; /bin/sh";
202 argv[i++] = NULL;
204 #if 0
205 /* Debugging hack */
206 if (!MEDATA->logfile)
207 MEDATA->logfile = fopen( "/home/pavel/talk.fish", "w+" ); /* FIXME */
208 #endif
210 pipeopen(super, xsh, argv );
213 char answer[2048];
214 print_vfs_message( _("fish: Waiting for initial line...") );
215 if (!vfs_s_get_line(me, SUP.sockr, answer, sizeof(answer), ':'))
216 ERRNOR (E_PROTO, -1);
217 print_vfs_message( answer );
218 if (strstr(answer, "assword")) {
220 /* Currently, this does not work. ssh reads passwords from
221 /dev/tty, not from stdin :-(. */
223 #ifndef HAVE_HACKED_SSH
224 message_1s (1, _(" Error "), _("Sorry, we can not do password authenticated connections for now."));
225 ERRNOR (EPERM, -1);
226 #endif
227 if (!SUP.password){
228 char *p, *op;
229 p = g_strconcat (" fish: Password required for ", SUP.user,
230 " ", NULL);
231 op = vfs_get_password (p);
232 g_free (p);
233 if (op == NULL)
234 ERRNOR (EPERM, -1);
235 SUP.password = g_strdup (op);
236 wipe_password(op);
238 print_vfs_message( _("fish: Sending password...") );
239 write(SUP.sockw, SUP.password, strlen(SUP.password));
240 write(SUP.sockw, "\n", 1);
244 print_vfs_message( _("fish: Sending initial line...") );
245 if (command (me, super, WAIT_REPLY, "#FISH\necho; start_fish_server; echo '### 200'\n") != COMPLETE)
246 ERRNOR (E_PROTO, -1);
248 print_vfs_message( _("fish: Handshaking version...") );
249 if (command (me, super, WAIT_REPLY, "#VER 0.0.0\necho '### 000'\n") != COMPLETE)
250 ERRNOR (E_PROTO, -1);
252 print_vfs_message( _("fish: Setting up current directory...") );
253 SUP.home = fish_getcwd (me, super);
254 print_vfs_message( _("fish: Connected, home %s."), SUP.home );
255 #if 0
256 super->name = g_strconcat ( "/#sh:", SUP.user, "@", SUP.host, "/", NULL );
257 #endif
258 super->name = g_strdup(PATH_SEP_STR);
260 super->root = vfs_s_new_inode (me, super, vfs_s_default_stat(me, S_IFDIR | 0755));
261 return 0;
265 open_archive (vfs *me, vfs_s_super *super, char *archive_name, char *op)
267 char *host, *user, *password;
268 int flags;
270 vfs_split_url (strchr(op, ':')+1, &host, &user, &flags, &password, 0, URL_NOSLASH);
271 SUP.host = g_strdup (host);
272 SUP.user = g_strdup (user);
273 SUP.flags = flags;
274 if (!strncmp( op, "rsh:", 4 ))
275 SUP.flags |= FISH_FLAG_RSH;
276 SUP.home = NULL;
277 if (password)
278 SUP.password = g_strdup (password);
279 return open_archive_int (me, super);
282 static int
283 archive_same(vfs *me, vfs_s_super *super, char *archive_name, char *op, void *cookie)
285 char *host, *user, *dummy2;
286 int flags;
287 vfs_split_url (strchr(op, ':')+1, &host, &user, &flags, &dummy2, 0, URL_NOSLASH);
288 return ((strcmp (host, SUP.host) == 0) &&
289 (strcmp (user, SUP.user) == 0) &&
290 (flags == SUP.flags));
294 fish_which (vfs *me, char *path)
296 if (!strncmp (path, "/#sh:", 5))
297 return 1;
298 if (!strncmp (path, "/#ssh:", 6))
299 return 1;
300 if (!strncmp (path, "/#rsh:", 6))
301 return 1;
302 return 0;
306 dir_uptodate(vfs *me, vfs_s_inode *ino)
308 struct timeval tim;
310 return 1; /* Timeouting of directories does not work too well :-(. */
311 gettimeofday(&tim, NULL);
312 if (force_expiration) {
313 force_expiration = 0;
314 return 0;
316 if (tim.tv_sec < ino->u.fish.timestamp.tv_sec)
317 return 1;
318 return 0;
321 static int
322 dir_load(vfs *me, vfs_s_inode *dir, char *remote_path)
324 vfs_s_super *super = dir->super;
325 char buffer[8192];
326 vfs_s_entry *ent = NULL;
327 FILE *logfile;
329 logfile = MEDATA->logfile;
331 print_vfs_message(_("fish: Reading directory %s..."), remote_path);
333 gettimeofday(&dir->u.fish.timestamp, NULL);
334 dir->u.fish.timestamp.tv_sec += 10; /* was 360: 10 is good for
335 stressing direntry layer a bit */
337 command(me, super, NONE,
338 "#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"
339 "S$s\nd$m $d $y\n:$n\n\"; done )\n"
340 "ls -lLa /%s | grep '^[cb]' | ( while read p x u g a i m d y n; do echo \"P$p $u.$g\n"
341 "E$a$i\nd$m $d $y\n:$n\n\"; done ); echo '### 200'\n",
342 remote_path, remote_path, remote_path);
344 #define SIMPLE_ENTRY vfs_s_generate_entry(me, NULL, dir, 0)
345 ent = SIMPLE_ENTRY;
346 while (1) {
347 int res = vfs_s_get_line_interruptible (me, buffer, sizeof (buffer), SUP.sockr);
348 if ((!res) || (res == EINTR)) {
349 vfs_s_free_entry(me, ent);
350 me->verrno = ECONNRESET;
351 goto error;
353 if (logfile){
354 fputs (buffer, logfile);
355 fputs ("\n", logfile);
356 fflush (logfile);
358 if (!strncmp(buffer, "### ", 4))
359 break;
360 if ((!buffer[0])) {
361 if (ent->name) {
362 vfs_s_insert_entry(me, dir, ent);
363 ent = SIMPLE_ENTRY;
365 continue;
368 #define ST ent->ino->st
370 switch(buffer[0]) {
371 case ':': {
372 char *c;
373 if (!strcmp(buffer+1, ".") || !strcmp(buffer+1, ".."))
374 break; /* We'll do . and .. ourself */
375 ent->name = g_strdup(buffer+1);
376 if ((c=strchr(ent->name, ' ')))
377 *c = 0; /* this is ugly, but we can not handle " " in name */
378 break;
380 case 'S': ST.st_size = atoi(buffer+1); break;
381 case 'P': {
382 int i;
383 if ((i = vfs_parse_filetype(buffer[1])) ==-1)
384 break;
385 ST.st_mode = i;
386 if ((i = vfs_parse_filemode(buffer+2)) ==-1)
387 break;
388 ST.st_mode |= i;
389 if (S_ISLNK(ST.st_mode))
390 ST.st_mode = 0;
392 break;
393 case 'd': {
394 vfs_split_text(buffer+1);
395 if (!vfs_parse_filedate(0, &ST.st_ctime))
396 break;
397 ST.st_atime = ST.st_mtime = ST.st_ctime;
399 break;
400 case 'D': {
401 struct tm tim;
402 if (sscanf(buffer+1, "%d %d %d %d %d %d", &tim.tm_year, &tim.tm_mon,
403 &tim.tm_mday, &tim.tm_hour, &tim.tm_min, &tim.tm_sec) != 6)
404 break;
405 ST.st_atime = ST.st_mtime = ST.st_ctime = mktime(&tim);
407 break;
408 case 'E': {
409 int maj, min;
410 if (sscanf(buffer+1, "%d,%d", &maj, &min) != 2)
411 break;
412 #ifdef HAVE_ST_RDEV
413 ST.st_rdev = (maj << 8) | min;
414 #endif
416 case 'L': ent->ino->linkname = g_strdup(buffer+1);
417 break;
421 vfs_s_free_entry (me, ent);
422 me->verrno = E_REMOTE;
423 if (decode_reply(buffer+4, 0) != COMPLETE)
424 goto error;
426 print_vfs_message(_("fish: got listing"));
427 return 0;
429 error:
430 print_vfs_message(_("fish: failed"));
431 return 1;
434 static int
435 file_store(vfs *me, vfs_s_super *super, char *name, char *localname)
437 int n, total;
438 char buffer[8192];
439 struct stat s;
440 int was_error = 0;
441 int h;
443 h = open(localname, O_RDONLY);
445 if (fstat(h, &s)<0)
446 ERRNOR (EIO, -1);
448 /* Use this as stor: ( dd block ; dd smallblock ) | ( cat > file; cat > /dev/null ) */
450 print_vfs_message(_("fish: store %s: sending command..."), name );
451 if (command (me, super, WAIT_REPLY,
452 "#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",
453 s.st_size, name, name,
454 s.st_size / 4096, s.st_size % 4096, name)
455 != PRELIM)
456 ERRNOR(E_REMOTE, -1);
458 total = 0;
460 while (1) {
461 while ((n = read(h, buffer, sizeof(buffer))) < 0) {
462 if ((errno == EINTR) && got_interrupt)
463 continue;
464 print_vfs_message(_("fish: Local read failed, sending zeros") );
465 close(h);
466 h = open( "/dev/zero", O_RDONLY );
468 if (n == 0)
469 break;
470 while (write(SUP.sockw, buffer, n) < 0) {
471 me->verrno = errno;
472 goto error_return;
474 disable_interrupt_key();
475 total += n;
476 print_vfs_message(_("fish: storing %s %d (%d)"),
477 was_error ? "zeros" : "file", total, s.st_size);
479 if ((get_reply (me, SUP.sockr, NULL, 0) != COMPLETE) || was_error)
480 ERRNOR (E_REMOTE, 0);
481 close(h);
482 return 0;
483 error_return:
484 close(h);
485 get_reply(me, SUP.sockr, NULL, 0);
486 return -1;
489 static int linear_start(vfs *me, vfs_s_fh *fh, int offset)
491 char *name;
492 if (offset)
493 ERRNOR (E_NOTSUPP, 0);
494 /* fe->local_stat.st_mtime = 0; FIXME: what is this good for? */
495 name = vfs_s_fullpath (me, fh->ino);
496 if (!name)
497 return 0;
498 if (command(me, FH_SUPER, WANT_STRING,
499 "#RETR /%s\nls -l /%s | ( read var1 var2 var3 var4 var5 var6; echo $var5 ); echo '### 100'; cat /%s; echo '### 200'\n",
500 name, name, name )
501 != PRELIM) ERRNOR (E_REMOTE, 0);
502 fh->linear = LS_LINEAR_OPEN;
503 fh->u.fish.got = 0;
504 if (sscanf( reply_str, "%d", &fh->u.fish.total )!=1)
505 ERRNOR (E_REMOTE, 0);
506 return 1;
509 static void
510 linear_abort (vfs *me, vfs_s_fh *fh)
512 vfs_s_super *super = FH_SUPER;
513 char buffer[8192];
514 int n;
516 print_vfs_message( _("Aborting transfer...") );
517 do {
518 n = MIN(8192, fh->u.fish.total - fh->u.fish.got);
519 if (n)
520 if ((n = read(SUP.sockr, buffer, n)) < 0)
521 return;
522 } while (n);
524 if (get_reply (me, SUP.sockr, NULL, 0) != COMPLETE)
525 print_vfs_message( _("Error reported after abort.") );
526 else
527 print_vfs_message( _("Aborted transfer would be successful.") );
530 static int
531 linear_read (vfs *me, vfs_s_fh *fh, void *buf, int len)
533 vfs_s_super *super = FH_SUPER;
534 int n = 0;
535 len = MIN( fh->u.fish.total - fh->u.fish.got, len );
536 disable_interrupt_key();
537 while (len && ((n = read (SUP.sockr, buf, len))<0)) {
538 if ((errno == EINTR) && !got_interrupt())
539 continue;
540 break;
542 enable_interrupt_key();
544 if (n>0) fh->u.fish.got += n;
545 if (n<0) linear_abort(me, fh);
546 if ((!n) && ((get_reply (me, SUP.sockr, NULL, 0) != COMPLETE)))
547 ERRNOR (E_REMOTE, -1);
548 ERRNOR (errno, n);
551 static void
552 linear_close (vfs *me, vfs_s_fh *fh)
554 if (fh->u.fish.total != fh->u.fish.got)
555 linear_abort(me, fh);
558 static int
559 fish_ctl (void *fh, int ctlop, int arg)
561 return 0;
562 switch (ctlop) {
563 case MCCTL_IS_NOTREADY:
565 int v;
567 if (!FH->linear)
568 vfs_die ("You may not do this");
569 if (FH->linear == LS_LINEAR_CLOSED)
570 return 0;
572 v = vfs_s_select_on_two (FH_SUPER->u.fish.sockr, 0);
573 if (((v < 0) && (errno == EINTR)) || v == 0)
574 return 1;
575 return 0;
577 default:
578 return 0;
582 static int
583 send_fish_command(vfs *me, vfs_s_super *super, char *cmd, int flags)
585 int r;
587 r = command (me, super, WAIT_REPLY, cmd);
588 vfs_add_noncurrent_stamps (&vfs_fish_ops, (vfsid) super, NULL);
589 if (r != COMPLETE) ERRNOR (E_REMOTE, -1);
590 if (flags & OPT_FLUSH)
591 vfs_s_invalidate(me, super);
592 return 0;
595 #define PREFIX \
596 char buf[BUF_LARGE]; \
597 char *rpath; \
598 vfs_s_super *super; \
599 if (!(rpath = vfs_s_get_path_mangle(me, path, &super, 0))) \
600 return -1;
602 #define POSTFIX(flags) \
603 return send_fish_command(me, super, buf, flags);
605 static int
606 fish_chmod (vfs *me, char *path, int mode)
608 PREFIX
609 g_snprintf(buf, sizeof(buf), "#CHMOD %4.4o /%s\nchmod %4.4o /%s; echo '### 000'\n",
610 mode & 07777, rpath,
611 mode & 07777, rpath);
612 POSTFIX(OPT_FLUSH);
615 #define FISH_OP(name, chk, string) \
616 static int fish_##name (vfs *me, char *path1, char *path2) \
618 char buf[BUF_LARGE]; \
619 char *rpath1 = NULL, *rpath2 = NULL; \
620 vfs_s_super *super1, *super2; \
621 if (!(rpath1 = vfs_s_get_path_mangle(me, path1, &super1, 0))) \
622 return -1; \
623 if (!(rpath2 = vfs_s_get_path_mangle(me, path2, &super2, 0))) \
624 return -1; \
625 g_snprintf(buf, 1023, string "\n", rpath1, rpath2, rpath1, rpath2 ); \
626 return send_fish_command(me, super2, buf, OPT_FLUSH); \
629 #define XTEST if (bucket1 != bucket2) { ERRNOR (EXDEV, -1); }
630 FISH_OP(rename, XTEST, "#RENAME /%s /%s\nmv /%s /%s; echo '### 000'" );
631 FISH_OP(link, XTEST, "#LINK /%s /%s\nln /%s /%s; echo '### 000'" );
633 static int fish_symlink (vfs *me, char *setto, char *path)
635 PREFIX
636 g_snprintf(buf, sizeof(buf), "#SYMLINK %s /%s\nln -s %s /%s; echo '### 000'\n", setto, rpath, setto, rpath);
637 POSTFIX(OPT_FLUSH);
640 static int
641 fish_chown (vfs *me, char *path, int owner, int group)
643 char *sowner, *sgroup;
644 PREFIX
645 sowner = getpwuid( owner )->pw_name;
646 sgroup = getgrgid( group )->gr_name;
647 g_snprintf(buf, sizeof(buf), "#CHOWN /%s /%s\nchown /%s /%s; echo '### 000'\n",
648 sowner, rpath,
649 sowner, rpath);
650 send_fish_command(me, super, buf, OPT_FLUSH);
651 /* FIXME: what should we report if chgrp succeeds but chown fails? */
652 g_snprintf(buf, sizeof(buf), "#CHGRP /%s /%s\nchgrp /%s /%s; echo '### 000'\n",
653 sgroup, rpath,
654 sgroup, rpath);
655 POSTFIX(OPT_FLUSH)
658 static int fish_unlink (vfs *me, char *path)
660 PREFIX
661 g_snprintf(buf, sizeof(buf), "#DELE /%s\nrm -f /%s; echo '### 000'\n", rpath, rpath);
662 POSTFIX(OPT_FLUSH);
665 static int fish_mkdir (vfs *me, char *path, mode_t mode)
667 PREFIX
668 g_snprintf(buf, sizeof(buf), "#MKD /%s\nmkdir /%s; echo '### 000'\n", rpath, rpath);
669 POSTFIX(OPT_FLUSH);
672 static int fish_rmdir (vfs *me, char *path)
674 PREFIX
675 g_snprintf(buf, sizeof(buf), "#RMD /%s\nrmdir /%s; echo '### 000'\n", rpath, rpath);
676 POSTFIX(OPT_FLUSH);
679 static int retrieve_file(vfs *me, struct vfs_s_inode *ino)
681 /* If you want reget, you'll have to open file with O_LINEAR */
682 int total = 0;
683 char buffer[8192];
684 int handle, n;
685 int stat_size = ino->st.st_size;
686 struct vfs_s_fh fh;
688 memset(&fh, 0, sizeof(fh));
690 fh.ino = ino;
691 if (!(ino->localname = tempnam (NULL, me->name))) ERRNOR (ENOMEM, 0);
693 handle = open(ino->localname, O_RDWR | O_CREAT | O_TRUNC | O_EXCL, 0600);
694 if (handle == -1) {
695 me->verrno = errno;
696 goto error_4;
699 if (!MEDATA->linear_start (me, &fh, 0))
700 goto error_3;
702 /* Clear the interrupt status */
704 while (1) {
705 n = linear_read(me, &fh, buffer, sizeof(buffer));
706 if (n < 0)
707 goto error_1;
708 if (!n)
709 break;
711 total += n;
712 vfs_print_stats (me->name, "Getting file", ino->ent->name, total, stat_size);
714 if (write(handle, buffer, n) < 0) {
715 me->verrno = errno;
716 goto error_1;
719 linear_close(me, &fh);
720 close(handle);
722 if (stat (ino->localname, &ino->u.fish.local_stat) < 0)
723 ino->u.fish.local_stat.st_mtime = 0;
725 return 0;
726 error_1:
727 linear_close(me, &fh);
728 error_3:
729 disable_interrupt_key();
730 close(handle);
731 unlink(ino->localname);
732 error_4:
733 g_free(ino->localname);
734 ino->localname = NULL;
735 return -1;
738 static int fish_fh_open (vfs *me, vfs_s_fh *fh, int flags, int mode)
740 if (IS_LINEAR(mode)) {
741 message_1s(1, "Linear mode requested", "?!" );
742 fh->linear = LS_LINEAR_CLOSED;
743 return 0;
745 if (!fh->ino->localname)
746 if (retrieve_file (me, fh->ino)==-1)
747 return -1;
748 if (!fh->ino->localname)
749 vfs_die( "retrieve_file failed to fill in localname" );
750 return 0;
753 static struct vfs_s_data fish_data = {
754 NULL,
757 NULL,
759 NULL, /* init_inode */
760 NULL, /* free_inode */
761 NULL, /* init_entry */
763 NULL, /* archive_check */
764 archive_same,
765 open_archive,
766 free_archive,
768 fish_fh_open, /* fh_open */
769 NULL, /* fh_close */
771 vfs_s_find_entry_linear,
772 dir_load,
773 dir_uptodate,
774 file_store,
776 linear_start,
777 linear_read,
778 linear_close
781 vfs vfs_fish_ops = {
782 NULL, /* This is place of next pointer */
783 "FIles tranferred over SHell",
784 F_EXEC, /* flags */
785 "sh:", /* prefix */
786 &fish_data, /* data */
787 0, /* errno */
788 NULL,
789 NULL,
790 vfs_s_fill_names,
791 NULL,
793 vfs_s_open,
794 vfs_s_close,
795 vfs_s_read,
796 vfs_s_write,
798 vfs_s_opendir,
799 vfs_s_readdir,
800 vfs_s_closedir,
801 vfs_s_telldir,
802 vfs_s_seekdir,
804 vfs_s_stat,
805 vfs_s_lstat,
806 vfs_s_fstat,
808 fish_chmod,
809 fish_chown,
810 NULL, /* utime */
812 vfs_s_readlink,
813 fish_symlink, /* symlink */
814 fish_link, /* link */
815 fish_unlink,
817 fish_rename, /* rename */
818 vfs_s_chdir,
819 vfs_s_ferrno,
820 vfs_s_lseek,
821 NULL, /* mknod */
823 vfs_s_getid,
824 vfs_s_nothingisopen,
825 vfs_s_free,
827 NULL, /* vfs_s_getlocalcopy, */
828 NULL, /* vfs_s_ungetlocalcopy, */
830 fish_mkdir,
831 fish_rmdir,
832 fish_ctl,
833 vfs_s_setctl
835 MMAPNULL