Ticket #10: fish-fix.patch
File fish-fix.patch, 16.3 KB (added by Patrick Winnertz, 16 years ago) |
---|
-
ChangeLog
ChangeLog | 5 + mhl/string.h | 7 ++- vfs/fish.c | 240 +++++++++++++++++++++++++++++++++++++++++++-------------- vfs/utilvfs.c | 58 ++++++++++++++ vfs/utilvfs.h | 2 + 5 files changed, 254 insertions(+), 58 deletions(-) diff --git a/ChangeLog b/ChangeLog index e71071b..f1dbe82 100644
a b 1 2009-01-25 Patrick Winnertz <winnie@debian.org> & Sergei Trofimovich <slyfox@inbox.ru> 2 3 * mhl/string.h, vfs/fish.c, vfs/utilvfs.c, vfs/utilvfs.h: Reworked fish code 4 so that symlinks and files which special characters works now 5 1 6 2009-01-25 Enrico Weigelt <weigelt@metux.de> 2 7 3 8 * edit/editcmd.c, src/cmd.c, src/ext.c, src/history.h: -
mhl/string.h
diff --git a/mhl/string.h b/mhl/string.h index fde86a7..28f6198 100644
a b 9 9 #define mhl_str_ndup(str,len) ((str ? strndup(str,len) : strdup(""))) 10 10 #define mhl_str_len(str) ((str ? strlen(str) : 0)) 11 11 12 static inline char * mhl_str_dup_range(const char * s_start, const char * s_bound) 13 { 14 return mhl_str_ndup(s_start, s_bound - s_start); 15 } 16 12 17 static inline char* mhl_str_trim(char* str) 13 18 { 14 19 if (!str) return NULL; // NULL string ?! bail out. … … static inline char* mhl_str_reverse(char* ptr) 121 126 return ptr; 122 127 } 123 128 124 #endif 129 #endif /* __MHL_STRING_H */ -
vfs/fish.c
diff --git a/vfs/fish.c b/vfs/fish.c index 2a2deb6..c639498 100644
a b 50 50 #include "tcputil.h" 51 51 #include "../src/unixcompat.h" 52 52 #include "fish.h" 53 #include "../mhl/memory.h" 54 #include "../mhl/string.h" 55 #include "../mhl/escape.h" 53 56 54 57 int fish_directory_timeout = 900; 55 58 … … fish_dir_load(struct vfs_class *me, struct vfs_s_inode *dir, char *remote_path) 358 361 char *quoted_path; 359 362 int reply_code; 360 363 364 #if 0 365 /* 366 * Simple FISH debug interface :] 367 */ 368 if (!(MEDATA->logfile)) 369 { 370 MEDATA->logfile = fopen("/tmp/mc-FISH.sh", "w"); 371 } 372 #endif // 0 373 361 374 logfile = MEDATA->logfile; 362 375 363 376 print_vfs_message(_("fish: Reading directory %s..."), remote_path); 364 377 365 378 gettimeofday(&dir->timestamp, NULL); 366 379 dir->timestamp.tv_sec += fish_directory_timeout; 367 quoted_path = name_quote (remote_path, 0);380 quoted_path = mhl_shell_escape_dup (remote_path); 368 381 fish_command (me, super, NONE, 369 "#LIST /%s\n" 370 "if ls -1 /%s >/dev/null 2>&1 ;\n" 371 "then\n" 372 "ls -lLan /%s 2>/dev/null | grep '^[^cbt]' | (\n" 373 "while read p l u g s m d y n; do\n" 374 "echo \"P$p $u.$g\nS$s\nd$m $d $y\n:$n\n\"\n" 375 "done\n" 376 ")\n" 377 "ls -lan /%s 2>/dev/null | grep '^[cb]' | (\n" 378 "while read p l u g a i m d y n; do\n" 379 "echo \"P$p $u.$g\nE$a$i\nd$m $d $y\n:$n\n\"\n" 380 "done\n" 381 ")\n" 382 "echo '### 200'\n" 383 "else\n" 384 "echo '### 500'\n" 385 "fi\n", 386 remote_path, quoted_path, quoted_path, quoted_path); 387 g_free (quoted_path); 382 "#LIST /%s\n" 383 "if `perl -v > /dev/null 2>&1` ; then\n" 384 "perl -e '\n" 385 "use strict;\n" 386 "use POSIX;\n" 387 "use Fcntl;\n" 388 "use POSIX \":fcntl_h\"; #S_ISLNK was here until 5.6\n" 389 "import Fcntl \":mode\" unless defined &S_ISLNK; #and is now here\n" 390 "my $dirname = $ARGV[0];\n" 391 "if (opendir ( DIR, $dirname )) {\n" 392 "while( (my $filename = readdir(DIR))){\n" 393 "my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = lstat(\"$dirname/$filename\");\n" 394 "my $mloctime= scalar localtime $mtime;\n" 395 "\n" 396 "# shell escs are taken from here: http://www.slac.stanford.edu/slac/www/resource/how-to-use/cgi-rexx/cgi-esc.html\n" 397 " sub esc_shell_chars {\n" 398 " my $s = $_[0];\n" 399 " $s =~ s/([;<>\\*\\|`&\\$!#\\(\\)\\[\\]\\{\\}:'\\''\"\\ \\\\])/\\\\$1/g;\n" 400 " return $s;\n" 401 " }\n" 402 "\n" 403 "my $e_filename = esc_shell_chars($filename);\n" 404 "if (S_ISLNK($mode) ) {\n" 405 "my $linkname = readlink (\"$dirname/$filename\");\n" 406 "my $e_linkname = esc_shell_chars($linkname);\n" 407 "\n" 408 "printf(\"R%%o %%o $uid.$gid\\n" 409 "S$size\\n" 410 "d$mloctime\\n" 411 ":\\\"$e_filename\\\" -> \\\"$e_linkname\\\"\\n" 412 "\\n\", S_IMODE($mode), S_IFMT($mode));\n" 413 "} else {\n" 414 "printf(\"R%%o %%o $uid.$gid\\n" 415 "S$size\\n" 416 "d$mloctime\\n" 417 ":\\\"$e_filename\\\"\\n" 418 "\\n\", S_IMODE($mode), S_IFMT($mode));\n" 419 "}}\n" 420 "printf(\"### 200\\n\");\n" 421 "closedir(DIR);\n" 422 "} else {\n" 423 "printf(\"### 500\\n\");\n" 424 "}\n" 425 "exit 0\n" 426 "' /%s ||\n" /* ARGV[0] - path to browse */ 427 " echo '### 500'\n" /* do not hang if perl is to eval it */ 428 "elif `ls -1 /%s >/dev/null 2>&1` ; then\n" 429 "if `ls -Q /%s >/dev/null 2>&1`; then\n" 430 "LSOPT=\"-Qlan\";\n" 431 "ADD=0;\n" 432 "else\n" 433 "LSOPT=\"-lan\";\n" 434 "ADD=1;\n" 435 "fi\n" 436 "ls $LSOPT \"/%s\" 2>/dev/null | grep '^[^cbt]' | (\n" 437 "while read p l u g s m d y n; do\n" 438 "if [ $ADD = 0 ]; then\n" 439 "echo \"P$p $u.$g\nS$s\nd$m $d $y\n:$n\n\"\n" 440 "elif `sed --version >/dev/null 2>&1` ; then\n" 441 "file=`echo $n | sed -e 's#^\\(.*\\) -> \\(.*\\)#\\1\" -> \"\\2#'`\n" 442 "echo \"P$p $u $g\nS$s\nd$m $d $y\n:\"$file\"\n\"\n" 443 "else\n" 444 "echo \"P$p $u $g\nS$s\nd$m $d $y\n:\"$n\"\n\"\n" 445 "fi\n" 446 "done )\n" 447 "ls $LSOPT /%s 2>/dev/null | grep '^[cb]' | (\n" 448 "while read p l u g a i m d y n; do\n" 449 "if [ $ADD = 0 ]; then\n" 450 "echo \"P$p $u.$g\nE$a$i\nd$m $d $y\n:$n\n\"\n" 451 "elif `sed --version >/dev/null 2>&1` ; then\n" 452 "file=`echo $n | sed -e 's#^\\(.*\\) -> \\(.*\\)#\\1\" -> \"\\2#'`\n" 453 "echo \"P$p $u $g\nS$s\nd$m $d $y\n:\"$file\"\n\"\n" 454 "else\n" 455 "echo \"P$p $u $g\nS$s\nd$m $d $y\n:\"$n\"\n\"\n" 456 "fi\n" 457 "done)\n" 458 "echo '### 200'\n" 459 "else\n" 460 "echo '### 500'\n" 461 "fi\n", 462 quoted_path, quoted_path, quoted_path, quoted_path, quoted_path, quoted_path); 463 mhl_mem_free (quoted_path); 388 464 ent = vfs_s_generate_entry(me, NULL, dir, 0); 389 465 while (1) { 390 466 int res = vfs_s_get_line_interruptible (me, buffer, sizeof (buffer), SUP.sockr); … … fish_dir_load(struct vfs_class *me, struct vfs_s_inode *dir, char *remote_path) 412 488 413 489 switch(buffer[0]) { 414 490 case ':': { 415 if (!strcmp(buffer+1, ".") || !strcmp(buffer+1, "..")) 416 break; /* We'll do . and .. ourself */ 417 ent->name = g_strdup(buffer+1); 418 break; 419 } 491 char *data_start = buffer+1; 492 char *filename = data_start; 493 char *linkname = data_start; 494 char *filename_bound = filename + strlen(filename); 495 char *linkname_bound = filename_bound; 496 if (!strcmp(data_start, "\".\"") || !strcmp(data_start, "\"..\"")) 497 break; /* We'll do "." and ".." ourselves */ 498 499 if (S_ISLNK(ST.st_mode)) { 500 // we expect: "escaped-name" -> "escaped-name" 501 // -> cannot occur in filenames, 502 // because it will be escaped to -\> 503 504 if (*filename == '"') 505 ++filename; 506 507 linkname = strstr(filename, "\" -> \""); 508 if (!linkname) 509 { 510 /* broken client, or smth goes wrong */ 511 linkname = filename_bound; 512 if (filename_bound > filename 513 && *(filename_bound - 1) == '"') 514 --filename_bound; // skip trailing " 515 } 516 else 517 { 518 filename_bound = linkname; 519 linkname += 6; // strlen ("\" -> \"") 520 if (*(linkname_bound - 1) == '"') 521 --linkname_bound; // skip trailing " 522 } 523 524 ent->name = mhl_str_dup_range(filename, filename_bound); 525 mhl_shell_unescape_buf(ent->name); 526 527 ent->ino->linkname = mhl_str_dup_range(linkname, linkname_bound); 528 mhl_shell_unescape_buf(ent->ino->linkname); 529 } else { 530 // we expect: "escaped-name" 531 if (filename_bound - filename > 2) 532 { 533 // there is at least 2 " 534 // and we skip them 535 if (*filename == '"') 536 ++filename; 537 if (*(filename_bound - 1) == '"') 538 --filename_bound; 539 } 540 541 ent->name = mhl_str_dup_range(filename, filename_bound); 542 mhl_shell_unescape_buf(ent->name); 543 } 544 break; 545 } 420 546 case 'S': 421 547 #ifdef HAVE_ATOLL 422 548 ST.st_size = (off_t) atoll (buffer+1); … … fish_dir_load(struct vfs_class *me, struct vfs_s_inode *dir, char *remote_path) 426 552 break; 427 553 case 'P': { 428 554 size_t skipped; 429 430 if (vfs_parse_filemode (buffer + 1, &skipped, &ST.st_mode)) { 431 if (S_ISLNK(ST.st_mode)) 432 ST.st_mode = 0; 433 } 555 vfs_parse_filemode (buffer + 1, &skipped, &ST.st_mode); 556 break; 557 } 558 case 'R': { 559 // raw filemode: 560 // we expect: Roctal-filemode octal-filetype uid.gid 561 size_t skipped; 562 vfs_parse_raw_filemode (buffer + 1, &skipped, &ST.st_mode); 434 563 break; 435 564 } 436 565 case 'd': { … … fish_dir_load(struct vfs_class *me, struct vfs_s_inode *dir, char *remote_path) 456 585 ST.st_rdev = makedev (maj, min); 457 586 #endif 458 587 } 459 case 'L': ent->ino->linkname = g_strdup(buffer+1);460 break;461 588 } 462 589 } 463 590 … … fish_file_store(struct vfs_class *me, struct vfs_s_fh *fh, char *name, char *loc 528 655 * algorithm for file appending case, therefore just "dd" is used for it. 529 656 */ 530 657 531 print_vfs_message(_("fish: store %s: sending command..."), name);532 quoted_name = name_quote (name, 0);658 quoted_name = mhl_shell_escape_dup(name); 659 print_vfs_message(_("fish: store %s: sending command..."), quoted_name ); 533 660 534 661 /* FIXME: File size is limited to ULONG_MAX */ 535 662 if (!fh->u.fish.append) … … fish_file_store(struct vfs_class *me, struct vfs_s_fh *fh, char *name, char *loc 541 668 "(\n" 542 669 "head -c %lu -q - || echo DD >&3\n" 543 670 ") 2>/dev/null | (\n" 544 "cat > \"$file\"\n"671 "cat > $file\n" 545 672 "cat > /dev/null\n" 546 673 ")`; [ \"$res\" = DD ] && {\n" 547 674 "> \"$file\"\n" … … fish_file_store(struct vfs_class *me, struct vfs_s_fh *fh, char *name, char *loc 553 680 " rest=`expr $rest - $n`\n" 554 681 "done\n" 555 682 "}; echo '### 200'\n", 556 (unsigned long) s.st_size, name,683 (unsigned long) s.st_size, quoted_name, 557 684 quoted_name, (unsigned long) s.st_size, 558 685 (unsigned long) s.st_size); 559 686 else … … fish_file_store(struct vfs_class *me, struct vfs_s_fh *fh, char *name, char *loc 566 693 "while [ $rest -gt 0 ]\n" 567 694 "do\n" 568 695 " cnt=`expr \\( $rest + 255 \\) / 256`\n" 569 " n=`dd bs=256 count=$cnt | tee -a \"$file\"| wc -c`\n"696 " n=`dd bs=256 count=$cnt | tee -a $file | wc -c`\n" 570 697 " rest=`expr $rest - $n`\n" 571 698 "done\n" 572 699 "}; echo '### 200'\n", 573 (unsigned long) s.st_size, name,700 (unsigned long) s.st_size, quoted_name, 574 701 quoted_name, (unsigned long) s.st_size); 575 702 576 g_free (quoted_name);577 703 if (n != PRELIM) { 578 704 close (h); 579 705 ERRNOR(E_REMOTE, -1); … … fish_file_store(struct vfs_class *me, struct vfs_s_fh *fh, char *name, char *loc 606 732 (unsigned long) s.st_size); 607 733 } 608 734 close(h); 735 mhl_mem_free(quoted_name); 609 736 if ((fish_get_reply (me, SUP.sockr, NULL, 0) != COMPLETE) || was_error) 610 737 ERRNOR (E_REMOTE, -1); 611 738 return 0; 612 739 error_return: 613 740 close(h); 614 741 fish_get_reply(me, SUP.sockr, NULL, 0); 742 mhl_mem_free(quoted_name); 615 743 return -1; 616 744 } 617 745 … … fish_linear_start (struct vfs_class *me, struct vfs_s_fh *fh, off_t offset) 625 753 name = vfs_s_fullpath (me, fh->ino); 626 754 if (!name) 627 755 return 0; 628 quoted_name = name_quote (name, 0); 629 g_free (name); 630 name = quoted_name; 756 quoted_name = mhl_shell_escape_dup(name); 631 757 fh->u.fish.append = 0; 632 758 633 759 /* … … fish_linear_start (struct vfs_class *me, struct vfs_s_fh *fh, off_t offset) 642 768 "then\n" 643 769 "ls -ln /%s 2>/dev/null | (\n" 644 770 "read p l u g s r\n" 645 "echo \"$s\"\n"771 "echo $s\n" 646 772 ")\n" 647 773 "echo '### 100'\n" 648 774 "cat /%s\n" 649 775 "echo '### 200'\n" 650 776 "else\n" 651 "echo '### 500'\n" 777 "echo '### 500'\n" 652 778 "fi\n", 653 name, name, name,name );654 g_free ( name);779 quoted_name, quoted_name, quoted_name, quoted_name ); 780 g_free (quoted_name); 655 781 if (offset != PRELIM) ERRNOR (E_REMOTE, 0); 656 782 fh->linear = LS_LINEAR_OPEN; 657 783 fh->u.fish.got = 0; … … fish_send_command(struct vfs_class *me, struct vfs_s_super *super, const char *c 766 892 g_free (mpath); \ 767 893 return -1; \ 768 894 } \ 769 rpath = name_quote (crpath, 0); \895 rpath = mhl_shell_escape_dup(crpath); \ 770 896 g_free (mpath); 771 897 772 898 #define POSTFIX(flags) \ … … fish_chmod (struct vfs_class *me, const char *path, int mode) 778 904 { 779 905 PREFIX 780 906 g_snprintf(buf, sizeof(buf), "#CHMOD %4.4o /%s\n" 781 "chmod %4.4o \"/%s\"2>/dev/null\n"907 "chmod %4.4o /%s 2>/dev/null\n" 782 908 "echo '### 000'\n", 783 909 mode & 07777, rpath, 784 910 mode & 07777, rpath); … … static int fish_##name (struct vfs_class *me, const char *path1, const char *pat 801 927 g_free (mpath2); \ 802 928 return -1; \ 803 929 } \ 804 rpath1 = name_quote (crpath1, 0); \930 rpath1 = mhl_shell_escape_dup (crpath1); \ 805 931 g_free (mpath1); \ 806 rpath2 = name_quote (crpath2, 0); \932 rpath2 = mhl_shell_escape_dup (crpath2); \ 807 933 g_free (mpath2); \ 808 934 g_snprintf(buf, sizeof(buf), string "\n", rpath1, rpath2, rpath1, rpath2); \ 809 g_free (rpath1); \810 g_free (rpath2); \935 mhl_mem_free (rpath1); \ 936 mhl_mem_free (rpath2); \ 811 937 return fish_send_command(me, super2, buf, OPT_FLUSH); \ 812 938 } 813 939 … … static int fish_symlink (struct vfs_class *me, const char *setto, const char *pa 822 948 { 823 949 char *qsetto; 824 950 PREFIX 825 qsetto = name_quote (setto, 0);951 qsetto = mhl_shell_escape_dup (setto); 826 952 g_snprintf(buf, sizeof(buf), 827 953 "#SYMLINK %s /%s\n" 828 954 "ln -s %s /%s 2>/dev/null\n" 829 955 "echo '### 000'\n", 830 956 qsetto, rpath, qsetto, rpath); 831 g_free (qsetto);957 mhl_mem_free (qsetto); 832 958 POSTFIX(OPT_FLUSH); 833 959 } 834 960 … … fish_chown (struct vfs_class *me, const char *path, int owner, int group) 850 976 { 851 977 PREFIX 852 978 g_snprintf (buf, sizeof(buf), 853 "#CHOWN /%s /%s\n"979 "#CHOWN %s /%s\n" 854 980 "chown %s /%s 2>/dev/null\n" 855 981 "echo '### 000'\n", 856 982 sowner, rpath, … … fish_chown (struct vfs_class *me, const char *path, int owner, int group) 858 984 fish_send_command (me, super, buf, OPT_FLUSH); 859 985 /* FIXME: what should we report if chgrp succeeds but chown fails? */ 860 986 g_snprintf (buf, sizeof(buf), 861 "#CHGRP /%s /%s\n"862 "chgrp %s /%s2>/dev/null\n"987 "#CHGRP /%s \"/%s\"\n" 988 "chgrp %s \"/%s\" 2>/dev/null\n" 863 989 "echo '### 000'\n", 864 990 sgroup, rpath, 865 991 sgroup, rpath); -
vfs/utilvfs.c
diff --git a/vfs/utilvfs.c b/vfs/utilvfs.c index 8284c8a..a2000a7 100644
a b vfs_parse_filemode (const char *s, size_t *ret_skipped, 539 539 return TRUE; 540 540 } 541 541 542 gboolean 543 vfs_parse_raw_filemode (const char *s, size_t *ret_skipped, 544 mode_t *ret_mode) 545 { 546 const char *p; 547 mode_t remote_type = 0, local_type, perms = 0; 548 549 p = s; 550 551 // isoctal 552 while(*p >= '0' && *p <= '7') 553 { 554 perms *= 010; 555 perms += (*p - '0'); 556 ++p; 557 } 558 559 if (*p++ != ' ') 560 return FALSE; 561 562 while(*p >= '0' && *p <= '7') 563 { 564 remote_type *= 010; 565 remote_type += (*p - '0'); 566 ++p; 567 } 568 569 if (*p++ != ' ') 570 return FALSE; 571 572 /* generated with: 573 $ perl -e 'use Fcntl ":mode"; 574 my @modes = (S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFREG); 575 foreach $t (@modes) { printf ("%o\n", $t); };' 576 TODO: S_IFDOOR, S_IFIFO, S_IFSOCK (if supported by os) 577 (see vfs_parse_filetype) 578 */ 579 580 switch (remote_type) 581 { 582 case 020000: 583 local_type = S_IFCHR; break; 584 case 040000: 585 local_type = S_IFDIR; break; 586 case 060000: 587 local_type = S_IFBLK; break; 588 case 0120000: 589 local_type = S_IFLNK; break; 590 case 0100000: 591 default:// don't know what is it 592 local_type = S_IFREG; break; 593 } 594 595 *ret_skipped = p - s; 596 *ret_mode = local_type | perms; 597 return TRUE; 598 } 599 542 600 /* This function parses from idx in the columns[] array */ 543 601 int 544 602 vfs_parse_filedate (int idx, time_t *t) -
vfs/utilvfs.h
diff --git a/vfs/utilvfs.h b/vfs/utilvfs.h index c920610..d025503 100644
a b gboolean vfs_parse_fileperms (const char *s, size_t *ret_skipped, 24 24 mode_t *ret_perms); 25 25 gboolean vfs_parse_filemode (const char *s, size_t *ret_skipped, 26 26 mode_t *ret_mode); 27 gboolean vfs_parse_raw_filemode (const char *s, size_t *ret_skipped, 28 mode_t *ret_mode); 27 29 28 30 int vfs_parse_ls_lga (const char *p, struct stat *s, char **filename, 29 31 char **linkname);