1
1
Этот коммит содержится в:
Patrick Winnertz 2009-01-26 16:56:24 +01:00
родитель e3a82ba1d8 1fd3aa61d6
Коммит 7abcb66aba
5 изменённых файлов: 248 добавлений и 58 удалений

Просмотреть файл

@ -4,6 +4,11 @@
* src/main.c, src/panel.h, src/screen.c, src/setup.c: * src/main.c, src/panel.h, src/screen.c, src/setup.c:
- Add support for showing executables at first in the panel view - Add support for showing executables at first in the panel view
2009-01-25 Patrick Winnertz <winnie@debian.org> & Sergei Trofimovich <slyfox@inbox.ru>
* mhl/string.h, vfs/fish.c, vfs/utilvfs.c, vfs/utilvfs.h: Reworked fish code
so that symlinks and files which special characters works now
2009-01-25 Enrico Weigelt <weigelt@metux.de> 2009-01-25 Enrico Weigelt <weigelt@metux.de>
* edit/editcmd.c, src/cmd.c, src/ext.c, src/history.h: * edit/editcmd.c, src/cmd.c, src/ext.c, src/history.h:

Просмотреть файл

@ -9,6 +9,11 @@
#define mhl_str_ndup(str,len) ((str ? strndup(str,len) : strdup(""))) #define mhl_str_ndup(str,len) ((str ? strndup(str,len) : strdup("")))
#define mhl_str_len(str) ((str ? strlen(str) : 0)) #define mhl_str_len(str) ((str ? strlen(str) : 0))
static inline char * mhl_str_dup_range(const char * s_start, const char * s_bound)
{
return mhl_str_ndup(s_start, s_bound - s_start);
}
static inline char* mhl_str_trim(char* str) static inline char* mhl_str_trim(char* str)
{ {
if (!str) return NULL; // NULL string ?! bail out. if (!str) return NULL; // NULL string ?! bail out.
@ -121,4 +126,4 @@ static inline char* mhl_str_reverse(char* ptr)
return ptr; return ptr;
} }
#endif #endif /* __MHL_STRING_H */

Просмотреть файл

@ -50,6 +50,9 @@
#include "tcputil.h" #include "tcputil.h"
#include "../src/unixcompat.h" #include "../src/unixcompat.h"
#include "fish.h" #include "fish.h"
#include "../mhl/memory.h"
#include "../mhl/string.h"
#include "../mhl/escape.h"
int fish_directory_timeout = 900; int fish_directory_timeout = 900;
@ -358,33 +361,100 @@ fish_dir_load(struct vfs_class *me, struct vfs_s_inode *dir, char *remote_path)
char *quoted_path; char *quoted_path;
int reply_code; int reply_code;
#if 0
/*
* Simple FISH debug interface :]
*/
if (!(MEDATA->logfile))
{
MEDATA->logfile = fopen("/tmp/mc-FISH.sh", "w");
}
#endif // 0
logfile = MEDATA->logfile; logfile = MEDATA->logfile;
print_vfs_message(_("fish: Reading directory %s..."), remote_path); print_vfs_message(_("fish: Reading directory %s..."), remote_path);
gettimeofday(&dir->timestamp, NULL); gettimeofday(&dir->timestamp, NULL);
dir->timestamp.tv_sec += fish_directory_timeout; dir->timestamp.tv_sec += fish_directory_timeout;
quoted_path = name_quote (remote_path, 0); quoted_path = mhl_shell_escape_dup (remote_path);
fish_command (me, super, NONE, fish_command (me, super, NONE,
"#LIST /%s\n" "#LIST /%s\n"
"if ls -1 /%s >/dev/null 2>&1 ;\n" "if `perl -v > /dev/null 2>&1` ; then\n"
"then\n" "perl -e '\n"
"ls -lLan /%s 2>/dev/null | grep '^[^cbt]' | (\n" "use strict;\n"
"while read p l u g s m d y n; do\n" "use POSIX;\n"
"echo \"P$p $u.$g\nS$s\nd$m $d $y\n:$n\n\"\n" "use Fcntl;\n"
"done\n" "use POSIX \":fcntl_h\"; #S_ISLNK was here until 5.6\n"
")\n" "import Fcntl \":mode\" unless defined &S_ISLNK; #and is now here\n"
"ls -lan /%s 2>/dev/null | grep '^[cb]' | (\n" "my $dirname = $ARGV[0];\n"
"while read p l u g a i m d y n; do\n" "if (opendir ( DIR, $dirname )) {\n"
"echo \"P$p $u.$g\nE$a$i\nd$m $d $y\n:$n\n\"\n" "while( (my $filename = readdir(DIR))){\n"
"done\n" "my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks) = lstat(\"$dirname/$filename\");\n"
")\n" "my $mloctime= scalar localtime $mtime;\n"
"echo '### 200'\n" "my $shell_escape_regex= s/([;<>\\*\\|`&\\$!#\\(\\)\\[\\]\\{\\}:'\\''\"\\ \\\\])/\\\\$1/g;\n"
"else\n" "my $e_filename = $filename;\n"
"echo '### 500'\n" "$e_filename =~ $shell_escape_regex;\n"
"fi\n", "if (S_ISLNK($mode) ) {\n"
remote_path, quoted_path, quoted_path, quoted_path); "my $linkname = readlink (\"$dirname/$filename\");\n"
g_free (quoted_path); "$linkname =~ $shell_escape_regex;\n"
"\n"
"printf(\"R%%o %%o $uid.$gid\\n"
"S$size\\n"
"d$mloctime\\n"
":\\\"$e_filename\\\" -> \\\"$linkname\\\"\\n"
"\\n\", S_IMODE($mode), S_IFMT($mode));\n"
"} else {\n"
"printf(\"R%%o %%o $uid.$gid\\n"
"S$size\\n"
"d$mloctime\\n"
":\\\"$e_filename\\\"\\n"
"\\n\", S_IMODE($mode), S_IFMT($mode));\n"
"}}\n"
"printf(\"### 200\\n\");\n"
"closedir(DIR);\n"
"} else {\n"
"printf(\"### 500\\n\");\n"
"}\n"
"exit 0\n"
"' /%s ||\n" /* ARGV[0] - path to browse */
" echo '### 500'\n" /* do not hang if perl is to eval it */
"elif `ls -1 /%s >/dev/null 2>&1` ; then\n"
"if `ls -Q /%s >/dev/null 2>&1`; then\n"
"LSOPT=\"-Qlan\";\n"
"ADD=0;\n"
"else\n"
"LSOPT=\"-lan\";\n"
"ADD=1;\n"
"fi\n"
"ls $LSOPT \"/%s\" 2>/dev/null | grep '^[^cbt]' | (\n"
"while read p l u g s m d y n; do\n"
"if [ $ADD = 0 ]; then\n"
"echo \"P$p $u.$g\nS$s\nd$m $d $y\n:$n\n\"\n"
"elif `sed --version >/dev/null 2>&1` ; then\n"
"file=`echo $n | sed -e 's#^\\(.*\\) -> \\(.*\\)#\\1\" -> \"\\2#'`\n"
"echo \"P$p $u $g\nS$s\nd$m $d $y\n:\"$file\"\n\"\n"
"else\n"
"echo \"P$p $u $g\nS$s\nd$m $d $y\n:\"$n\"\n\"\n"
"fi\n"
"done )\n"
"ls $LSOPT /%s 2>/dev/null | grep '^[cb]' | (\n"
"while read p l u g a i m d y n; do\n"
"if [ $ADD = 0 ]; then\n"
"echo \"P$p $u.$g\nE$a$i\nd$m $d $y\n:$n\n\"\n"
"elif `sed --version >/dev/null 2>&1` ; then\n"
"file=`echo $n | sed -e 's#^\\(.*\\) -> \\(.*\\)#\\1\" -> \"\\2#'`\n"
"echo \"P$p $u $g\nS$s\nd$m $d $y\n:\"$file\"\n\"\n"
"else\n"
"echo \"P$p $u $g\nS$s\nd$m $d $y\n:\"$n\"\n\"\n"
"fi\n"
"done)\n"
"echo '### 200'\n"
"else\n"
"echo '### 500'\n"
"fi\n",
quoted_path, quoted_path, quoted_path, quoted_path, quoted_path, quoted_path);
mhl_mem_free (quoted_path);
ent = vfs_s_generate_entry(me, NULL, dir, 0); ent = vfs_s_generate_entry(me, NULL, dir, 0);
while (1) { while (1) {
int res = vfs_s_get_line_interruptible (me, buffer, sizeof (buffer), SUP.sockr); int res = vfs_s_get_line_interruptible (me, buffer, sizeof (buffer), SUP.sockr);
@ -412,11 +482,61 @@ fish_dir_load(struct vfs_class *me, struct vfs_s_inode *dir, char *remote_path)
switch(buffer[0]) { switch(buffer[0]) {
case ':': { case ':': {
if (!strcmp(buffer+1, ".") || !strcmp(buffer+1, "..")) char *data_start = buffer+1;
break; /* We'll do . and .. ourself */ char *filename = data_start;
ent->name = g_strdup(buffer+1); char *linkname = data_start;
break; char *filename_bound = filename + strlen(filename);
} char *linkname_bound = filename_bound;
if (!strcmp(data_start, "\".\"") || !strcmp(data_start, "\"..\""))
break; /* We'll do "." and ".." ourselves */
if (S_ISLNK(ST.st_mode)) {
// we expect: "escaped-name" -> "escaped-name"
// -> cannot occur in filenames,
// because it will be escaped to -\>
if (*filename == '"')
++filename;
linkname = strstr(filename, "\" -> \"");
if (!linkname)
{
/* broken client, or smth goes wrong */
linkname = filename_bound;
if (filename_bound > filename
&& *(filename_bound - 1) == '"')
--filename_bound; // skip trailing "
}
else
{
filename_bound = linkname;
linkname += 6; // strlen ("\" -> \"")
if (*(linkname_bound - 1) == '"')
--linkname_bound; // skip trailing "
}
ent->name = mhl_str_dup_range(filename, filename_bound);
mhl_shell_unescape_buf(ent->name);
ent->ino->linkname = mhl_str_dup_range(linkname, linkname_bound);
mhl_shell_unescape_buf(ent->ino->linkname);
} else {
// we expect: "escaped-name"
if (filename_bound - filename > 2)
{
// there is at least 2 "
// and we skip them
if (*filename == '"')
++filename;
if (*(filename_bound - 1) == '"')
--filename_bound;
}
ent->name = mhl_str_dup_range(filename, filename_bound);
mhl_shell_unescape_buf(ent->name);
}
break;
}
case 'S': case 'S':
#ifdef HAVE_ATOLL #ifdef HAVE_ATOLL
ST.st_size = (off_t) atoll (buffer+1); ST.st_size = (off_t) atoll (buffer+1);
@ -426,11 +546,14 @@ fish_dir_load(struct vfs_class *me, struct vfs_s_inode *dir, char *remote_path)
break; break;
case 'P': { case 'P': {
size_t skipped; size_t skipped;
vfs_parse_filemode (buffer + 1, &skipped, &ST.st_mode);
if (vfs_parse_filemode (buffer + 1, &skipped, &ST.st_mode)) { break;
if (S_ISLNK(ST.st_mode)) }
ST.st_mode = 0; case 'R': {
} // raw filemode:
// we expect: Roctal-filemode octal-filetype uid.gid
size_t skipped;
vfs_parse_raw_filemode (buffer + 1, &skipped, &ST.st_mode);
break; break;
} }
case 'd': { case 'd': {
@ -456,8 +579,6 @@ fish_dir_load(struct vfs_class *me, struct vfs_s_inode *dir, char *remote_path)
ST.st_rdev = makedev (maj, min); ST.st_rdev = makedev (maj, min);
#endif #endif
} }
case 'L': ent->ino->linkname = g_strdup(buffer+1);
break;
} }
} }
@ -528,8 +649,8 @@ fish_file_store(struct vfs_class *me, struct vfs_s_fh *fh, char *name, char *loc
* algorithm for file appending case, therefore just "dd" is used for it. * algorithm for file appending case, therefore just "dd" is used for it.
*/ */
print_vfs_message(_("fish: store %s: sending command..."), name ); quoted_name = mhl_shell_escape_dup(name);
quoted_name = name_quote (name, 0); print_vfs_message(_("fish: store %s: sending command..."), quoted_name );
/* FIXME: File size is limited to ULONG_MAX */ /* FIXME: File size is limited to ULONG_MAX */
if (!fh->u.fish.append) if (!fh->u.fish.append)
@ -541,7 +662,7 @@ fish_file_store(struct vfs_class *me, struct vfs_s_fh *fh, char *name, char *loc
"(\n" "(\n"
"head -c %lu -q - || echo DD >&3\n" "head -c %lu -q - || echo DD >&3\n"
") 2>/dev/null | (\n" ") 2>/dev/null | (\n"
"cat > \"$file\"\n" "cat > $file\n"
"cat > /dev/null\n" "cat > /dev/null\n"
")`; [ \"$res\" = DD ] && {\n" ")`; [ \"$res\" = DD ] && {\n"
"> \"$file\"\n" "> \"$file\"\n"
@ -553,7 +674,7 @@ fish_file_store(struct vfs_class *me, struct vfs_s_fh *fh, char *name, char *loc
" rest=`expr $rest - $n`\n" " rest=`expr $rest - $n`\n"
"done\n" "done\n"
"}; echo '### 200'\n", "}; echo '### 200'\n",
(unsigned long) s.st_size, name, (unsigned long) s.st_size, quoted_name,
quoted_name, (unsigned long) s.st_size, quoted_name, (unsigned long) s.st_size,
(unsigned long) s.st_size); (unsigned long) s.st_size);
else else
@ -566,14 +687,13 @@ fish_file_store(struct vfs_class *me, struct vfs_s_fh *fh, char *name, char *loc
"while [ $rest -gt 0 ]\n" "while [ $rest -gt 0 ]\n"
"do\n" "do\n"
" cnt=`expr \\( $rest + 255 \\) / 256`\n" " cnt=`expr \\( $rest + 255 \\) / 256`\n"
" n=`dd bs=256 count=$cnt | tee -a \"$file\" | wc -c`\n" " n=`dd bs=256 count=$cnt | tee -a $file | wc -c`\n"
" rest=`expr $rest - $n`\n" " rest=`expr $rest - $n`\n"
"done\n" "done\n"
"}; echo '### 200'\n", "}; echo '### 200'\n",
(unsigned long) s.st_size, name, (unsigned long) s.st_size, quoted_name,
quoted_name, (unsigned long) s.st_size); quoted_name, (unsigned long) s.st_size);
g_free (quoted_name);
if (n != PRELIM) { if (n != PRELIM) {
close (h); close (h);
ERRNOR(E_REMOTE, -1); ERRNOR(E_REMOTE, -1);
@ -606,12 +726,14 @@ fish_file_store(struct vfs_class *me, struct vfs_s_fh *fh, char *name, char *loc
(unsigned long) s.st_size); (unsigned long) s.st_size);
} }
close(h); close(h);
mhl_mem_free(quoted_name);
if ((fish_get_reply (me, SUP.sockr, NULL, 0) != COMPLETE) || was_error) if ((fish_get_reply (me, SUP.sockr, NULL, 0) != COMPLETE) || was_error)
ERRNOR (E_REMOTE, -1); ERRNOR (E_REMOTE, -1);
return 0; return 0;
error_return: error_return:
close(h); close(h);
fish_get_reply(me, SUP.sockr, NULL, 0); fish_get_reply(me, SUP.sockr, NULL, 0);
mhl_mem_free(quoted_name);
return -1; return -1;
} }
@ -625,9 +747,7 @@ fish_linear_start (struct vfs_class *me, struct vfs_s_fh *fh, off_t offset)
name = vfs_s_fullpath (me, fh->ino); name = vfs_s_fullpath (me, fh->ino);
if (!name) if (!name)
return 0; return 0;
quoted_name = name_quote (name, 0); quoted_name = mhl_shell_escape_dup(name);
g_free (name);
name = quoted_name;
fh->u.fish.append = 0; fh->u.fish.append = 0;
/* /*
@ -642,16 +762,16 @@ fish_linear_start (struct vfs_class *me, struct vfs_s_fh *fh, off_t offset)
"then\n" "then\n"
"ls -ln /%s 2>/dev/null | (\n" "ls -ln /%s 2>/dev/null | (\n"
"read p l u g s r\n" "read p l u g s r\n"
"echo \"$s\"\n" "echo $s\n"
")\n" ")\n"
"echo '### 100'\n" "echo '### 100'\n"
"cat /%s\n" "cat /%s\n"
"echo '### 200'\n" "echo '### 200'\n"
"else\n" "else\n"
"echo '### 500'\n" "echo '### 500'\n"
"fi\n", "fi\n",
name, name, name, name ); quoted_name, quoted_name, quoted_name, quoted_name );
g_free (name); g_free (quoted_name);
if (offset != PRELIM) ERRNOR (E_REMOTE, 0); if (offset != PRELIM) ERRNOR (E_REMOTE, 0);
fh->linear = LS_LINEAR_OPEN; fh->linear = LS_LINEAR_OPEN;
fh->u.fish.got = 0; fh->u.fish.got = 0;
@ -766,7 +886,7 @@ fish_send_command(struct vfs_class *me, struct vfs_s_super *super, const char *c
g_free (mpath); \ g_free (mpath); \
return -1; \ return -1; \
} \ } \
rpath = name_quote (crpath, 0); \ rpath = mhl_shell_escape_dup(crpath); \
g_free (mpath); g_free (mpath);
#define POSTFIX(flags) \ #define POSTFIX(flags) \
@ -778,7 +898,7 @@ fish_chmod (struct vfs_class *me, const char *path, int mode)
{ {
PREFIX PREFIX
g_snprintf(buf, sizeof(buf), "#CHMOD %4.4o /%s\n" g_snprintf(buf, sizeof(buf), "#CHMOD %4.4o /%s\n"
"chmod %4.4o \"/%s\" 2>/dev/null\n" "chmod %4.4o /%s 2>/dev/null\n"
"echo '### 000'\n", "echo '### 000'\n",
mode & 07777, rpath, mode & 07777, rpath,
mode & 07777, rpath); mode & 07777, rpath);
@ -801,13 +921,13 @@ static int fish_##name (struct vfs_class *me, const char *path1, const char *pat
g_free (mpath2); \ g_free (mpath2); \
return -1; \ return -1; \
} \ } \
rpath1 = name_quote (crpath1, 0); \ rpath1 = mhl_shell_escape_dup (crpath1); \
g_free (mpath1); \ g_free (mpath1); \
rpath2 = name_quote (crpath2, 0); \ rpath2 = mhl_shell_escape_dup (crpath2); \
g_free (mpath2); \ g_free (mpath2); \
g_snprintf(buf, sizeof(buf), string "\n", rpath1, rpath2, rpath1, rpath2); \ g_snprintf(buf, sizeof(buf), string "\n", rpath1, rpath2, rpath1, rpath2); \
g_free (rpath1); \ mhl_mem_free (rpath1); \
g_free (rpath2); \ mhl_mem_free (rpath2); \
return fish_send_command(me, super2, buf, OPT_FLUSH); \ return fish_send_command(me, super2, buf, OPT_FLUSH); \
} }
@ -822,13 +942,13 @@ static int fish_symlink (struct vfs_class *me, const char *setto, const char *pa
{ {
char *qsetto; char *qsetto;
PREFIX PREFIX
qsetto = name_quote (setto, 0); qsetto = mhl_shell_escape_dup (setto);
g_snprintf(buf, sizeof(buf), g_snprintf(buf, sizeof(buf),
"#SYMLINK %s /%s\n" "#SYMLINK %s /%s\n"
"ln -s %s /%s 2>/dev/null\n" "ln -s %s /%s 2>/dev/null\n"
"echo '### 000'\n", "echo '### 000'\n",
qsetto, rpath, qsetto, rpath); qsetto, rpath, qsetto, rpath);
g_free (qsetto); mhl_mem_free (qsetto);
POSTFIX(OPT_FLUSH); POSTFIX(OPT_FLUSH);
} }
@ -850,7 +970,7 @@ fish_chown (struct vfs_class *me, const char *path, int owner, int group)
{ {
PREFIX PREFIX
g_snprintf (buf, sizeof(buf), g_snprintf (buf, sizeof(buf),
"#CHOWN /%s /%s\n" "#CHOWN %s /%s\n"
"chown %s /%s 2>/dev/null\n" "chown %s /%s 2>/dev/null\n"
"echo '### 000'\n", "echo '### 000'\n",
sowner, rpath, sowner, rpath,
@ -858,8 +978,8 @@ fish_chown (struct vfs_class *me, const char *path, int owner, int group)
fish_send_command (me, super, buf, OPT_FLUSH); fish_send_command (me, super, buf, OPT_FLUSH);
/* FIXME: what should we report if chgrp succeeds but chown fails? */ /* FIXME: what should we report if chgrp succeeds but chown fails? */
g_snprintf (buf, sizeof(buf), g_snprintf (buf, sizeof(buf),
"#CHGRP /%s /%s\n" "#CHGRP /%s \"/%s\"\n"
"chgrp %s /%s 2>/dev/null\n" "chgrp %s \"/%s\" 2>/dev/null\n"
"echo '### 000'\n", "echo '### 000'\n",
sgroup, rpath, sgroup, rpath,
sgroup, rpath); sgroup, rpath);

Просмотреть файл

@ -539,6 +539,64 @@ vfs_parse_filemode (const char *s, size_t *ret_skipped,
return TRUE; return TRUE;
} }
gboolean
vfs_parse_raw_filemode (const char *s, size_t *ret_skipped,
mode_t *ret_mode)
{
const char *p;
mode_t remote_type = 0, local_type, perms = 0;
p = s;
// isoctal
while(*p >= '0' && *p <= '7')
{
perms *= 010;
perms += (*p - '0');
++p;
}
if (*p++ != ' ')
return FALSE;
while(*p >= '0' && *p <= '7')
{
remote_type *= 010;
remote_type += (*p - '0');
++p;
}
if (*p++ != ' ')
return FALSE;
/* generated with:
$ perl -e 'use Fcntl ":mode";
my @modes = (S_IFDIR, S_IFBLK, S_IFCHR, S_IFLNK, S_IFREG);
foreach $t (@modes) { printf ("%o\n", $t); };'
TODO: S_IFDOOR, S_IFIFO, S_IFSOCK (if supported by os)
(see vfs_parse_filetype)
*/
switch (remote_type)
{
case 020000:
local_type = S_IFCHR; break;
case 040000:
local_type = S_IFDIR; break;
case 060000:
local_type = S_IFBLK; break;
case 0120000:
local_type = S_IFLNK; break;
case 0100000:
default:// don't know what is it
local_type = S_IFREG; break;
}
*ret_skipped = p - s;
*ret_mode = local_type | perms;
return TRUE;
}
/* This function parses from idx in the columns[] array */ /* This function parses from idx in the columns[] array */
int int
vfs_parse_filedate (int idx, time_t *t) vfs_parse_filedate (int idx, time_t *t)

Просмотреть файл

@ -24,6 +24,8 @@ gboolean vfs_parse_fileperms (const char *s, size_t *ret_skipped,
mode_t *ret_perms); mode_t *ret_perms);
gboolean vfs_parse_filemode (const char *s, size_t *ret_skipped, gboolean vfs_parse_filemode (const char *s, size_t *ret_skipped,
mode_t *ret_mode); mode_t *ret_mode);
gboolean vfs_parse_raw_filemode (const char *s, size_t *ret_skipped,
mode_t *ret_mode);
int vfs_parse_ls_lga (const char *p, struct stat *s, char **filename, int vfs_parse_ls_lga (const char *p, struct stat *s, char **filename,
char **linkname); char **linkname);