last messages updated..
[midnight-commander.git] / vfs / shared_ftp_fish.c
blob3258f83da13eecbc8a871b36fcadb619baba65aa
1 /*
2 * Shared code between the fish.c and the ftp.c file systems
4 * $Id$
6 * Actually, this code is not being used by fish.c any more :-).
8 * Namespace pollution: X_hint_reread, X_flushdir.
9 */
10 static int store_file (struct direntry *fe);
11 static int retrieve_file (struct direntry *fe);
12 static int remove_temp_file (char *file_name);
13 static struct dir *retrieve_dir (struct connection *bucket,
14 char *remote_path,
15 int resolve_symlinks);
16 static void my_forget (char *path);
18 static int linear_start (struct direntry *fe, int from);
19 static int linear_read (struct direntry *fe, void *buf, int len);
20 static void linear_close (struct direntry *fe);
22 static int
23 select_on_two (int fd1, int fd2)
25 fd_set set;
26 struct timeval timeout;
27 int v;
28 int maxfd = (fd1 > fd2 ? fd1 : fd2) + 1;
30 timeout.tv_sec = 1;
31 timeout.tv_usec = 0;
32 FD_ZERO(&set);
33 FD_SET(fd1, &set);
34 FD_SET(fd2, &set);
35 v = select (maxfd, &set, 0, 0, &timeout);
36 if (v <= 0)
37 return v;
38 if (FD_ISSET (fd1, &set))
39 return 1;
40 if (FD_ISSET (fd2, &set))
41 return 2;
42 return -1;
45 static int
46 get_line (int sock, char *buf, int buf_len, char term)
48 int i, status;
49 char c;
51 for (i = 0; i < buf_len - 1; i++, buf++) {
52 if (read(sock, buf, sizeof(char)) <= 0)
53 return 0;
54 if (logfile){
55 fwrite (buf, 1, 1, logfile);
56 fflush (logfile);
58 if (*buf == term) {
59 *buf = 0;
60 return 1;
63 *buf = 0;
64 while ((status = read(sock, &c, sizeof(c))) > 0){
65 if (logfile){
66 fwrite (&c, 1, 1, logfile);
67 fflush (logfile);
69 if (c == '\n')
70 return 1;
72 return 0;
75 static void
76 direntry_destructor (void *data)
78 struct direntry *fe = data;
80 fe->count--;
82 if (fe->count > 0)
83 return;
84 g_free(fe->name);
85 if (fe->linkname)
86 g_free(fe->linkname);
87 if (fe->local_filename) {
88 if (fe->local_is_temp) {
89 if (!fe->local_stat.st_mtime)
90 unlink(fe->local_filename);
91 else {
92 struct stat sb;
94 if (stat (fe->local_filename, &sb) >=0 &&
95 fe->local_stat.st_mtime == sb.st_mtime)
96 unlink (fe->local_filename); /* Delete only if it hasn't changed */
99 g_free(fe->local_filename);
100 fe->local_filename = NULL;
102 if (fe->remote_filename)
103 g_free(fe->remote_filename);
104 if (fe->l_stat)
105 g_free(fe->l_stat);
106 g_free(fe);
109 static void
110 dir_destructor(void *data)
112 struct dir *fd = data;
114 fd->count--;
115 if (fd->count > 0)
116 return;
117 g_free(fd->remote_path);
118 linklist_destroy(fd->file_list, direntry_destructor);
119 g_free(fd);
122 static int
123 get_line_interruptible (char *buffer, int size, int fd)
125 int n;
126 int i = 0;
128 for (i = 0; i < size-1; i++) {
129 n = read (fd, buffer+i, 1);
130 if (n == -1 && errno == EINTR){
131 buffer [i] = 0;
132 return EINTR;
134 if (n == 0){
135 buffer [i] = 0;
136 return 0;
138 if (buffer [i] == '\n'){
139 buffer [i] = 0;
140 return 1;
143 buffer [size-1] = 0;
144 return 0;
147 static void
148 free_bucket (void *data)
150 struct connection *bucket = data;
152 g_free(qhost(bucket));
153 g_free(quser(bucket));
154 if (qcdir(bucket))
155 g_free(qcdir(bucket));
156 if (qhome(bucket))
157 g_free(qhome(bucket));
158 if (qupdir(bucket))
159 g_free(qupdir(bucket));
160 if (bucket->password)
161 wipe_password (bucket->password);
162 linklist_destroy(qdcache(bucket), dir_destructor);
163 g_free(bucket);
167 static void
168 connection_destructor(void *data)
170 connection_close (data);
171 free_bucket (data);
174 static void
175 flush_all_directory(struct connection *bucket)
177 linklist_delete_all(qdcache(bucket), dir_destructor);
180 static void X_fill_names (vfs *me, void (*func)(char *))
182 struct linklist *lptr;
183 char *path_name;
184 struct connection *bucket;
186 if (!connections_list)
187 return;
188 lptr = connections_list;
189 do {
190 if ((bucket = lptr->data) != 0){
192 path_name = g_strconcat ( X_myname, quser (bucket),
193 "@", qhost (bucket),
194 qcdir(bucket), NULL);
195 (*func)(path_name);
196 g_free (path_name);
198 lptr = lptr->next;
199 } while (lptr != connections_list);
202 /* get_path:
203 * makes BUCKET point to the connection bucket descriptor for PATH
204 * returns a malloced string with the pathname relative to BUCKET.
206 * path must _not_ contain initial /bla/#ftp:
208 static char*
209 s_get_path (struct connection **bucket, char *path, char *name)
211 char *user, *host, *remote_path, *pass;
212 int port;
214 #ifndef BROKEN_PATHS
215 if (strncmp (path, name, strlen (name)))
216 return NULL; /* Normal: consider cd /bla/#ftp */
217 #else
218 if (!(path = strstr (path, name)))
219 return NULL;
220 #endif
221 path += strlen (name);
223 if (!(remote_path = my_get_host_and_username (path, &host, &user, &port, &pass)))
224 my_errno = ENOENT;
225 else {
226 if ((*bucket = open_link (host, user, port, pass)) == NULL) {
227 g_free (remote_path);
228 remote_path = NULL;
231 if (host)
232 g_free (host);
233 if (user)
234 g_free (user);
235 if (pass)
236 wipe_password (pass);
238 if (!remote_path)
239 return NULL;
241 /* NOTE: Usage of tildes is deprecated, consider:
242 * cd /#ftp:pavel@hobit
243 * cd ~
244 * And now: what do I want to do? Do I want to go to /home/pavel or to
245 * /#ftp:hobit/home/pavel? I think first has better sense...
248 int f = !strcmp( remote_path, "/~" );
249 if (f || !strncmp( remote_path, "/~/", 3 )) {
250 char *s;
251 s = concat_dir_and_file( qhome (*bucket), remote_path +3-f );
252 g_free (remote_path);
253 remote_path = s;
256 return remote_path;
259 void
260 ftpfs_flushdir (void)
262 force_expiration = 1;
266 static int
267 s_setctl (vfs *me, char *path, int ctlop, char *arg)
269 switch (ctlop) {
270 case MCCTL_REMOVELOCALCOPY:
271 return remove_temp_file (path);
272 return 0;
273 case MCCTL_FORGET_ABOUT:
274 my_forget(path);
275 return 0;
277 return 0;
280 static struct direntry *
281 _get_file_entry(struct connection *bucket, char *file_name,
282 int op, int flags)
284 char *p, q;
285 struct direntry *ent;
286 struct linklist *file_list, *lptr;
287 struct dir *dcache;
288 struct stat sb;
290 p = strrchr(file_name, '/');
291 q = *p;
292 *p = '\0';
293 dcache = retrieve_dir(bucket, *file_name ? file_name : "/", op & DO_RESOLVE_SYMLINK);
294 if (dcache == NULL)
295 return NULL;
296 file_list = dcache->file_list;
297 *p++ = q;
298 if (!*p)
299 p = ".";
300 for (lptr = file_list->next; lptr != file_list; lptr = lptr->next) {
301 ent = lptr->data;
302 if (strcmp(p, ent->name) == 0) {
303 if (S_ISLNK(ent->s.st_mode) && (op & DO_RESOLVE_SYMLINK)) {
304 if (ent->l_stat == NULL) ERRNOR (ENOENT, NULL);
305 if (S_ISLNK(ent->l_stat->st_mode)) ERRNOR (ELOOP, NULL);
307 if (ent && (op & DO_OPEN)) {
308 mode_t fmode;
310 fmode = S_ISLNK(ent->s.st_mode)
311 ? ent->l_stat->st_mode
312 : ent->s.st_mode;
313 if (S_ISDIR(fmode))
314 ERRNOR (EISDIR, NULL);
315 if (!S_ISREG(fmode))
316 ERRNOR (EPERM, NULL);
317 if ((flags & O_EXCL) && (flags & O_CREAT))
318 ERRNOR (EEXIST, NULL);
319 if (ent->remote_filename == NULL)
320 if (!(ent->remote_filename = g_strdup(file_name)))
321 ERRNOR (ENOMEM, NULL);
322 if (ent->local_filename == NULL ||
323 !ent->local_stat.st_mtime ||
324 stat (ent->local_filename, &sb) < 0 ||
325 sb.st_mtime != ent->local_stat.st_mtime) {
326 int handle;
328 if (ent->local_filename){
329 g_free (ent->local_filename);
330 ent->local_filename = NULL;
332 if (flags & O_TRUNC) {
333 ent->local_filename = tempnam (NULL, X "fs");
334 if (ent->local_filename == NULL) ERRNOR (ENOMEM, NULL);
335 handle = open(ent->local_filename, O_CREAT | O_TRUNC | O_RDWR | O_EXCL, 0600);
336 if (handle < 0) ERRNOR (EIO, NULL);
337 close(handle);
338 if (stat (ent->local_filename, &ent->local_stat) < 0)
339 ent->local_stat.st_mtime = 0;
341 else {
342 if (IS_LINEAR(flags)) {
343 ent->local_is_temp = 0;
344 ent->local_filename = NULL;
345 ent->linear_state = LS_LINEAR_CLOSED;
346 return ent;
348 if (!retrieve_file(ent))
349 return NULL;
352 else if (flags & O_TRUNC) {
353 truncate(ent->local_filename, 0);
356 return ent;
359 if ((op & DO_OPEN) && (flags & O_CREAT)) {
360 int handle;
362 ent = g_new (struct direntry, 1);
363 if (ent == NULL) ERRNOR (ENOMEM, NULL);
364 ent->freshly_created = 0;
365 ent->count = 1;
366 ent->linkname = NULL;
367 ent->l_stat = NULL;
368 ent->bucket = bucket;
369 ent->name = g_strdup(p);
370 ent->remote_filename = g_strdup(file_name);
371 ent->local_filename = tempnam (NULL, X "fs");
372 if (!ent->name || !ent->remote_filename || !ent->local_filename) {
373 direntry_destructor(ent);
374 ERRNOR (ENOMEM, NULL);
376 handle = open (ent->local_filename, O_CREAT | O_EXCL | O_RDWR | O_TRUNC, 0700);
377 if (handle == -1) {
378 my_errno = EIO;
379 goto error;
381 fstat(handle, &ent->s);
382 close(handle);
383 #if 0
384 /* This is very wrong - like this a zero length file will be always created
385 and usually preclude uploading anything more desirable */
386 #if defined(UPLOAD_ZERO_LENGTH_FILE)
387 if (!store_file(ent)) goto error;
388 #endif
389 #endif
390 if (!linklist_insert(file_list, ent)) {
391 my_errno = ENOMEM;
392 goto error;
394 ent->freshly_created = 1;
395 return ent;
397 else ERRNOR (ENOENT, NULL);
398 error:
399 direntry_destructor(ent);
400 return NULL;
404 /* this just free's the local temp file. I don't know if the
405 remote file can be used after this without crashing - paul
406 psheer@obsidian.co.za psheer@icon.co.za */
407 static int
408 remove_temp_file (char *file_name)
410 char *p, q;
411 struct connection *bucket;
412 struct direntry *ent;
413 struct linklist *file_list, *lptr;
414 struct dir *dcache;
416 if (!(file_name = get_path (&bucket, file_name)))
417 return -1;
418 p = strrchr (file_name, '/');
419 q = *p;
420 *p = '\0';
421 dcache = retrieve_dir (bucket, *file_name ? file_name : "/", 0);
422 if (dcache == NULL)
423 return -1;
424 file_list = dcache->file_list;
425 *p++ = q;
426 if (!*p)
427 p = ".";
428 for (lptr = file_list->next; lptr != file_list; lptr = lptr->next) {
429 ent = lptr->data;
430 if (strcmp (p, ent->name) == 0) {
431 if (ent->local_filename) {
432 unlink (ent->local_filename);
433 g_free (ent->local_filename);
434 ent->local_filename = NULL;
435 return 0;
439 return -1;
442 static struct direntry *
443 get_file_entry(char *path, int op, int flags)
445 struct connection *bucket;
446 struct direntry *fe;
447 char *remote_path;
449 if (!(remote_path = get_path (&bucket, path)))
450 return NULL;
451 fe = _get_file_entry(bucket, remote_path, op,
452 flags);
453 g_free(remote_path);
454 #if 0
455 if (op & DO_FREE_RESOURCE)
456 vfs_add_noncurrent_stamps (&vfs_X_ops, (vfsid) bucket, NULL);
457 #endif
458 return fe;
461 #define OPT_FLUSH 1
462 #define OPT_IGNORE_ERROR 2
464 static int normal_flush = 1;
466 void X_hint_reread(int reread)
468 if (reread)
469 normal_flush++;
470 else
471 normal_flush--;
475 /* The callbacks */
477 struct filp {
478 unsigned int has_changed:1;
479 struct direntry *fe;
480 int local_handle;
483 static void *s_open (vfs *me, char *file, int flags, int mode)
485 struct filp *fp;
486 struct direntry *fe;
488 fp = g_new (struct filp, 1);
489 if (fp == NULL) ERRNOR (ENOMEM, NULL);
490 fe = get_file_entry(file, DO_OPEN | DO_RESOLVE_SYMLINK, flags);
491 if (!fe) {
492 g_free(fp);
493 return NULL;
495 fe->linear_state = IS_LINEAR(flags);
496 if (!fe->linear_state) {
497 fp->local_handle = open(fe->local_filename, flags, mode);
498 if (fp->local_handle < 0) {
499 g_free(fp);
500 ERRNOR (errno, NULL);
502 } else fp->local_handle = -1;
503 #ifdef UPLOAD_ZERO_LENGTH_FILE
504 fp->has_changed = fe->freshly_created;
505 #else
506 fp->has_changed = 0;
507 #endif
508 fp->fe = fe;
509 qlock(fe->bucket)++;
510 fe->count++;
511 return fp;
514 static int s_read (void *data, char *buffer, int count)
516 struct filp *fp;
517 int n;
519 fp = data;
520 if (fp->fe->linear_state == LS_LINEAR_CLOSED) {
521 print_vfs_message (_("Starting linear transfer..."));
522 if (!linear_start (fp->fe, 0))
523 return -1;
526 if (fp->fe->linear_state == LS_LINEAR_CLOSED)
527 vfs_die ("linear_start() did not set linear_state!");
529 if (fp->fe->linear_state == LS_LINEAR_OPEN)
530 return linear_read (fp->fe, buffer, count);
532 n = read (fp->local_handle, buffer, count);
533 if (n < 0)
534 my_errno = errno;
535 return n;
538 static int s_write (void *data, char *buf, int nbyte)
540 struct filp *fp = data;
541 int n;
543 if (fp->fe->linear_state)
544 vfs_die ("You may not write to linear file");
545 n = write (fp->local_handle, buf, nbyte);
546 if (n < 0)
547 my_errno = errno;
548 fp->has_changed = 1;
549 return n;
552 static int s_close (void *data)
554 struct filp *fp = data;
555 int result = 0;
557 if (fp->has_changed) {
558 if (!store_file(fp->fe))
559 result = -1;
560 if (normal_flush)
561 flush_all_directory(fp->fe->bucket);
563 if (fp->fe->linear_state == LS_LINEAR_OPEN)
564 linear_close(fp->fe);
565 if (fp->local_handle >= 0)
566 close(fp->local_handle);
567 qlock(fp->fe->bucket)--;
568 direntry_destructor(fp->fe);
569 g_free(fp);
570 return result;
573 static int s_errno (vfs *me)
575 return my_errno;
579 /* Explanation:
580 * On some operating systems (Slowaris 2 for example)
581 * the d_name member is just a char long (nice trick that break everything),
582 * so we need to set up some space for the filename.
584 struct my_dirent {
585 struct dirent dent;
586 #ifdef NEED_EXTRA_DIRENT_BUFFER
587 char extra_buffer [MC_MAXPATHLEN];
588 #endif
589 struct linklist *pos;
590 struct dir *dcache;
593 /* Possible FIXME: what happens if one directory is opened twice ? */
595 static void *s_opendir (vfs *me, char *dirname)
597 struct connection *bucket;
598 char *remote_path;
599 struct my_dirent *dirp;
601 if (!(remote_path = get_path (&bucket, dirname)))
602 return NULL;
603 dirp = g_new (struct my_dirent, 1);
604 if (dirp == NULL) {
605 my_errno = ENOMEM;
606 goto error_return;
608 dirp->dcache = retrieve_dir(bucket, remote_path, 1);
609 if (dirp->dcache == NULL)
610 goto error_return;
611 dirp->pos = dirp->dcache->file_list->next;
612 g_free(remote_path);
613 dirp->dcache->count++;
614 return (void *)dirp;
615 error_return:
616 vfs_add_noncurrent_stamps (&vfs_X_ops, (vfsid) bucket, NULL);
617 g_free(remote_path);
618 g_free(dirp);
619 return NULL;
622 static void *s_readdir (void *data)
624 struct direntry *fe;
625 struct my_dirent *dirp = data;
627 if (dirp->pos == dirp->dcache->file_list)
628 return NULL;
629 fe = dirp->pos->data;
630 strcpy (&(dirp->dent.d_name [0]), fe->name);
631 #ifndef DIRENT_LENGTH_COMPUTED
632 dirp->d_namlen = strlen (dirp->d_name);
633 #endif
634 dirp->pos = dirp->pos->next;
635 return (void *) &dirp->dent;
638 static int s_telldir (void *data)
640 struct my_dirent *dirp = data;
641 struct linklist *pos;
642 int i = 0;
644 pos = dirp->dcache->file_list->next;
645 while( pos!=dirp->dcache->file_list) {
646 if (pos == dirp->pos)
647 return i;
648 pos = pos->next;
649 i++;
651 return -1;
654 static void s_seekdir (void *data, int pos)
656 struct my_dirent *dirp = data;
657 int i;
659 dirp->pos = dirp->dcache->file_list->next;
660 for (i=0; i<pos; i++)
661 s_readdir(data);
664 static int s_closedir (void *info)
666 struct my_dirent *dirp = info;
667 dir_destructor(dirp->dcache);
668 g_free(dirp);
669 return 0;
672 static int s_lstat (vfs *me, char *path, struct stat *buf)
674 struct direntry *fe;
676 fe = get_file_entry(path, DO_FREE_RESOURCE, 0);
677 if (fe) {
678 *buf = fe->s;
679 return 0;
681 else
682 return -1;
685 static int s_stat (vfs *me, char *path, struct stat *buf)
687 struct direntry *fe;
689 fe = get_file_entry(path, DO_RESOLVE_SYMLINK | DO_FREE_RESOURCE, 0);
690 if (fe) {
691 if (!S_ISLNK(fe->s.st_mode))
692 *buf = fe->s;
693 else
694 *buf = *fe->l_stat;
695 return 0;
697 else
698 return -1;
701 static int s_fstat (void *data, struct stat *buf)
703 struct filp *fp = data;
705 if (!S_ISLNK(fp->fe->s.st_mode))
706 *buf = fp->fe->s;
707 else
708 *buf = *fp->fe->l_stat;
709 return 0;
712 static int s_readlink (vfs *me, char *path, char *buf, int size)
714 struct direntry *fe;
716 fe = get_file_entry(path, DO_FREE_RESOURCE, 0);
717 if (!fe)
718 return -1;
719 if (!S_ISLNK(fe->s.st_mode)) ERRNOR (EINVAL, -1);
720 if (fe->linkname == NULL) ERRNOR (EACCES, -1);
721 if (strlen(fe->linkname) >= size) ERRNOR (ERANGE, -1);
722 strncpy(buf, fe->linkname, size);
723 return strlen(fe->linkname);
726 static int s_chdir (vfs *me, char *path)
728 char *remote_path;
729 struct connection *bucket;
731 if (!(remote_path = get_path(&bucket, path)))
732 return -1;
733 if (qcdir(bucket))
734 g_free(qcdir(bucket));
735 qcdir(bucket) = remote_path;
736 bucket->cwd_defered = 1;
738 vfs_add_noncurrent_stamps (&vfs_X_ops, (vfsid) bucket, NULL);
739 return 0;
742 static int s_lseek (void *data, off_t offset, int whence)
744 struct filp *fp = data;
746 if (fp->fe->linear_state == LS_LINEAR_OPEN)
747 vfs_die ("You promissed not to seek!");
748 if (fp->fe->linear_state == LS_LINEAR_CLOSED) {
749 print_vfs_message (_("Preparing reget..."));
750 if (whence != SEEK_SET)
751 vfs_die ("You may not do such seek on linear file");
752 if (!linear_start (fp->fe, offset))
753 return -1;
754 return offset;
756 return lseek(fp->local_handle, offset, whence);
759 static vfsid s_getid (vfs *me, char *p, struct vfs_stamping **parent)
761 struct connection *bucket;
762 char *remote_path;
764 *parent = NULL; /* We are not enclosed in any other fs */
766 if (!(remote_path = get_path (&bucket, p)))
767 return (vfsid) -1;
768 else {
769 g_free(remote_path);
770 return (vfsid) bucket;
774 static int s_nothingisopen (vfsid id)
776 return qlock((struct connection *)id) == 0;
779 static void s_free (vfsid id)
781 struct connection *bucket = (struct connection *) id;
783 connection_destructor(bucket);
784 linklist_delete(connections_list, bucket);
787 static char *s_getlocalcopy (vfs *me, char *path)
789 struct filp *fp = (struct filp *) s_open (me, path, O_RDONLY, 0);
790 char *p;
792 if (fp == NULL)
793 return NULL;
794 if (fp->fe->local_filename == NULL) {
795 s_close ((void *) fp);
796 return NULL;
798 p = g_strdup (fp->fe->local_filename);
799 qlock(fp->fe->bucket)++;
800 fp->fe->count++;
801 s_close ((void *) fp);
802 return p;
805 static int s_ungetlocalcopy (vfs *me, char *path, char *local, int has_changed)
807 struct filp *fp = (struct filp *) s_open (me, path, O_WRONLY, 0);
809 if (fp == NULL)
810 return 0;
811 if (!strcmp (fp->fe->local_filename, local)) {
812 fp->has_changed = has_changed;
813 qlock(fp->fe->bucket)--;
814 direntry_destructor(fp->fe);
815 s_close ((void *) fp);
816 } else {
817 /* Should not happen */
818 s_close ((void *) fp);
819 mc_def_ungetlocalcopy (me, path, local, has_changed);
821 return 0;
824 static void
825 X_done(vfs *me)
827 linklist_destroy(connections_list, connection_destructor);
828 connections_list = NULL;
829 if (logfile)
830 fclose (logfile);
831 logfile = NULL;
834 static int retrieve_file(struct direntry *fe)
836 /* If you want reget, you'll have to open file with O_LINEAR */
837 int total = 0;
838 char buffer[8192];
839 int local_handle, n;
840 int stat_size = fe->s.st_size;
842 if (fe->local_filename)
843 return 1;
844 if (!(fe->local_filename = tempnam (NULL, X))) ERRNOR (ENOMEM, 0);
845 fe->local_is_temp = 1;
847 local_handle = open(fe->local_filename, O_RDWR | O_CREAT | O_TRUNC | O_EXCL, 0600);
848 if (local_handle == -1) {
849 my_errno = EIO;
850 goto error_4;
853 if (!linear_start (fe, 0))
854 goto error_3;
856 /* Clear the interrupt status */
857 enable_interrupt_key ();
859 while (1) {
860 if ((n = linear_read(fe, buffer, sizeof(buffer))) < 0)
861 goto error_1;
862 if (!n)
863 break;
865 total += n;
866 vfs_print_stats (X, _("Getting file"), fe->remote_filename, total, stat_size);
868 while (write(local_handle, buffer, n) < 0) {
869 if (errno == EINTR) {
870 if (got_interrupt()) {
871 my_errno = EINTR;
872 goto error_2;
874 else
875 continue;
877 my_errno = errno;
878 goto error_1;
881 linear_close(fe);
882 disable_interrupt_key();
883 close(local_handle);
885 if (stat (fe->local_filename, &fe->local_stat) < 0)
886 fe->local_stat.st_mtime = 0;
888 return 1;
889 error_1:
890 error_2:
891 linear_close(fe);
892 error_3:
893 disable_interrupt_key();
894 close(local_handle);
895 unlink(fe->local_filename);
896 error_4:
897 g_free(fe->local_filename);
898 fe->local_filename = NULL;
899 return 0;