mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-26 12:53:13 +00:00
Make fish avoid iterating through user list when completing file part of directory starting with tilde. Also add a timeout to the directory iteration, to protect against humongously large user databases.
darcs-hash:20090202224645-ac50b-353047a73e4d6f494f470fe2ea6c4a34b486d302.gz
This commit is contained in:
parent
05341b055b
commit
72025a6a38
4 changed files with 133 additions and 137 deletions
15
common.c
15
common.c
|
@ -1805,3 +1805,18 @@ void sb_format_size( string_buffer_t *sb,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
double timef()
|
||||
{
|
||||
int time_res;
|
||||
struct timeval tv;
|
||||
|
||||
time_res = gettimeofday(&tv, 0);
|
||||
|
||||
if( time_res )
|
||||
{
|
||||
return NAN;
|
||||
}
|
||||
|
||||
return (double)tv.tv_sec + 0.000001*tv.tv_usec;
|
||||
}
|
||||
|
|
10
common.h
10
common.h
|
@ -447,5 +447,15 @@ void bugreport();
|
|||
void sb_format_size( string_buffer_t *sb,
|
||||
long long sz );
|
||||
|
||||
/**
|
||||
Return the number of seconds from the UNIX epoch, with subsecond
|
||||
precision. This function uses the gettimeofday function, and will
|
||||
have the same precision as that function.
|
||||
|
||||
If an error occurs, NAN is returned.
|
||||
*/
|
||||
double timef();
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
237
complete.c
237
complete.c
|
@ -1,6 +1,6 @@
|
|||
/** \file complete.c Functions related to tab-completion.
|
||||
|
||||
These functions are used for storing and retrieving tab-completion data, as well as for performing tab-completion.
|
||||
These functions are used for storing and retrieving tab-completion data, as well as for performing tab-completion.
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
|
@ -107,6 +107,14 @@ These functions are used for storing and retrieving tab-completion data, as well
|
|||
#endif
|
||||
|
||||
|
||||
/**
|
||||
The maximum amount of time that we're willing to spend doing
|
||||
username tilde completion. This special limit has been coded in
|
||||
because user lookup can be extremely slow in cases of a humongous
|
||||
LDAP database. (Google, I'm looking at you)
|
||||
*/
|
||||
#define MAX_USER_LOOKUP_TIME 0.2
|
||||
|
||||
/**
|
||||
Struct describing a completion option entry.
|
||||
|
||||
|
@ -180,9 +188,9 @@ static void complete_free_entry( complete_entry_t *c );
|
|||
|
||||
*/
|
||||
void completion_allocate( array_list_t *context,
|
||||
const wchar_t *comp,
|
||||
const wchar_t *desc,
|
||||
int flags )
|
||||
const wchar_t *comp,
|
||||
const wchar_t *desc,
|
||||
int flags )
|
||||
{
|
||||
completion_t *res = halloc( context, sizeof( completion_t) );
|
||||
res->completion = halloc_wcsdup( context, comp );
|
||||
|
@ -378,8 +386,8 @@ static complete_entry_t *complete_get_exact_entry( const wchar_t *cmd,
|
|||
|
||||
|
||||
void complete_set_authoritative( const wchar_t *cmd,
|
||||
int cmd_type,
|
||||
int authoritative )
|
||||
int cmd_type,
|
||||
int authoritative )
|
||||
{
|
||||
complete_entry_t *c;
|
||||
|
||||
|
@ -473,9 +481,9 @@ static complete_entry_t *complete_remove_entry( complete_entry_t *e,
|
|||
{
|
||||
wchar_t *pos;
|
||||
/* fwprintf( stderr,
|
||||
L"remove option -%lc --%ls\n",
|
||||
o->short_opt?o->short_opt:L' ',
|
||||
o->long_opt );
|
||||
L"remove option -%lc --%ls\n",
|
||||
o->short_opt?o->short_opt:L' ',
|
||||
o->long_opt );
|
||||
*/
|
||||
if( o->short_opt )
|
||||
{
|
||||
|
@ -1067,10 +1075,10 @@ static const wchar_t *complete_function_desc( const wchar_t *fn )
|
|||
\param comp the list to add all completions to
|
||||
*/
|
||||
static void complete_cmd( const wchar_t *cmd,
|
||||
array_list_t *comp,
|
||||
int use_function,
|
||||
int use_builtin,
|
||||
int use_command )
|
||||
array_list_t *comp,
|
||||
int use_function,
|
||||
int use_builtin,
|
||||
int use_command )
|
||||
{
|
||||
wchar_t *path;
|
||||
wchar_t *path_cpy;
|
||||
|
@ -1124,18 +1132,18 @@ static void complete_cmd( const wchar_t *cmd,
|
|||
|
||||
add_slash = nxt_path[path_len-1]!=L'/';
|
||||
nxt_completion = wcsdupcat( nxt_path,
|
||||
add_slash?L"/":L"",
|
||||
cmd );
|
||||
add_slash?L"/":L"",
|
||||
cmd );
|
||||
if( ! nxt_completion )
|
||||
continue;
|
||||
|
||||
prev_count = al_get_count( comp );
|
||||
|
||||
if( expand_string( 0,
|
||||
nxt_completion,
|
||||
comp,
|
||||
ACCEPT_INCOMPLETE |
|
||||
EXECUTABLES_ONLY ) != EXPAND_ERROR )
|
||||
nxt_completion,
|
||||
comp,
|
||||
ACCEPT_INCOMPLETE |
|
||||
EXECUTABLES_ONLY ) != EXPAND_ERROR )
|
||||
{
|
||||
for( i=prev_count; i<al_get_count( comp ); i++ )
|
||||
{
|
||||
|
@ -1188,8 +1196,8 @@ static void complete_cmd( const wchar_t *cmd,
|
|||
{
|
||||
wchar_t *nxt_completion=
|
||||
wcsdupcat( nxt_path,
|
||||
(nxt_path[wcslen(nxt_path)-1]==L'/'?L"":L"/"),
|
||||
cmd );
|
||||
(nxt_path[wcslen(nxt_path)-1]==L'/'?L"":L"/"),
|
||||
cmd );
|
||||
if( ! nxt_completion )
|
||||
{
|
||||
continue;
|
||||
|
@ -1613,8 +1621,8 @@ static void complete_param_expand( wchar_t *str,
|
|||
Complete the specified string as an environment variable
|
||||
*/
|
||||
static int complete_variable( const wchar_t *whole_var,
|
||||
int start_offset,
|
||||
array_list_t *comp_list )
|
||||
int start_offset,
|
||||
array_list_t *comp_list )
|
||||
{
|
||||
int i;
|
||||
const wchar_t *var = &whole_var[start_offset];
|
||||
|
@ -1671,9 +1679,9 @@ static int complete_variable( const wchar_t *whole_var,
|
|||
sb_printf( &desc, COMPLETE_VAR_DESC_VAL, value );
|
||||
|
||||
completion_allocate( comp_list,
|
||||
(wchar_t *)comp.buff,
|
||||
(wchar_t *)desc.buff,
|
||||
flags );
|
||||
(wchar_t *)comp.buff,
|
||||
(wchar_t *)desc.buff,
|
||||
flags );
|
||||
res =1;
|
||||
|
||||
free( value );
|
||||
|
@ -1724,127 +1732,86 @@ static int try_complete_variable( const wchar_t *cmd,
|
|||
static int try_complete_user( const wchar_t *cmd,
|
||||
array_list_t *comp )
|
||||
{
|
||||
const wchar_t *first_char=0;
|
||||
const wchar_t *p;
|
||||
int mode = 0;
|
||||
int res = 0;
|
||||
const wchar_t *first_char=cmd;
|
||||
int res=0;
|
||||
double start_time = timef();
|
||||
|
||||
for( p=cmd; *p; p++ )
|
||||
if( *first_char ==L'~' && !wcschr(first_char, L'/'))
|
||||
{
|
||||
switch( mode )
|
||||
const wchar_t *user_name = first_char+1;
|
||||
wchar_t *name_end = wcschr( user_name, L'~' );
|
||||
if( name_end == 0 )
|
||||
{
|
||||
/*Between parameters*/
|
||||
case 0:
|
||||
switch( *p )
|
||||
{
|
||||
case L'\"':
|
||||
mode=2;
|
||||
p++;
|
||||
first_char = p;
|
||||
break;
|
||||
case L' ':
|
||||
case L'\t':
|
||||
case L'\n':
|
||||
case L'\r':
|
||||
break;
|
||||
default:
|
||||
mode=1;
|
||||
first_char = p;
|
||||
}
|
||||
break;
|
||||
/*Inside non-quoted parameter*/
|
||||
case 1:
|
||||
switch( *p )
|
||||
{
|
||||
case L' ':
|
||||
case L'\t':
|
||||
case L'\n':
|
||||
case L'\r':
|
||||
mode = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
switch( *p )
|
||||
{
|
||||
case L'\"':
|
||||
if( *(p-1) != L'\\' )
|
||||
mode =0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
struct passwd *pw;
|
||||
int name_len = wcslen( user_name );
|
||||
|
||||
if( mode != 0 )
|
||||
{
|
||||
if( *first_char ==L'~' )
|
||||
{
|
||||
const wchar_t *user_name = first_char+1;
|
||||
wchar_t *name_end = wcschr( user_name, L'~' );
|
||||
if( name_end == 0 )
|
||||
setpwent();
|
||||
|
||||
while((pw=getpwent()) != 0)
|
||||
{
|
||||
struct passwd *pw;
|
||||
int name_len = wcslen( user_name );
|
||||
double current_time = timef();
|
||||
wchar_t *pw_name;
|
||||
|
||||
setpwent();
|
||||
|
||||
while((pw=getpwent()) != 0)
|
||||
if( current_time - start_time > 0.2 )
|
||||
{
|
||||
wchar_t *pw_name = str2wcs( pw->pw_name );
|
||||
if( pw_name )
|
||||
{
|
||||
if( wcsncmp( user_name, pw_name, name_len )==0 )
|
||||
{
|
||||
string_buffer_t desc;
|
||||
|
||||
sb_init( &desc );
|
||||
sb_printf( &desc,
|
||||
COMPLETE_USER_DESC,
|
||||
pw_name );
|
||||
|
||||
completion_allocate( comp,
|
||||
&pw_name[name_len],
|
||||
(wchar_t *)desc.buff,
|
||||
COMPLETE_NO_SPACE );
|
||||
|
||||
res=1;
|
||||
|
||||
sb_destroy( &desc );
|
||||
}
|
||||
else if( wcsncasecmp( user_name, pw_name, name_len )==0 )
|
||||
{
|
||||
string_buffer_t name;
|
||||
string_buffer_t desc;
|
||||
|
||||
sb_init( &name );
|
||||
sb_init( &desc );
|
||||
sb_printf( &name,
|
||||
L"~%ls",
|
||||
pw_name );
|
||||
sb_printf( &desc,
|
||||
COMPLETE_USER_DESC,
|
||||
pw_name );
|
||||
|
||||
completion_allocate( comp,
|
||||
(wchar_t *)name.buff,
|
||||
(wchar_t *)desc.buff,
|
||||
COMPLETE_NO_CASE | COMPLETE_DONT_ESCAPE | COMPLETE_NO_SPACE );
|
||||
res=1;
|
||||
|
||||
sb_destroy( &desc );
|
||||
sb_destroy( &name );
|
||||
|
||||
}
|
||||
free( pw_name );
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
pw_name = str2wcs( pw->pw_name );
|
||||
|
||||
if( pw_name )
|
||||
{
|
||||
if( wcsncmp( user_name, pw_name, name_len )==0 )
|
||||
{
|
||||
string_buffer_t desc;
|
||||
|
||||
sb_init( &desc );
|
||||
sb_printf( &desc,
|
||||
COMPLETE_USER_DESC,
|
||||
pw_name );
|
||||
|
||||
completion_allocate( comp,
|
||||
&pw_name[name_len],
|
||||
(wchar_t *)desc.buff,
|
||||
COMPLETE_NO_SPACE );
|
||||
|
||||
res=1;
|
||||
|
||||
sb_destroy( &desc );
|
||||
}
|
||||
else if( wcsncasecmp( user_name, pw_name, name_len )==0 )
|
||||
{
|
||||
string_buffer_t name;
|
||||
string_buffer_t desc;
|
||||
|
||||
sb_init( &name );
|
||||
sb_init( &desc );
|
||||
sb_printf( &name,
|
||||
L"~%ls",
|
||||
pw_name );
|
||||
sb_printf( &desc,
|
||||
COMPLETE_USER_DESC,
|
||||
pw_name );
|
||||
|
||||
completion_allocate( comp,
|
||||
(wchar_t *)name.buff,
|
||||
(wchar_t *)desc.buff,
|
||||
COMPLETE_NO_CASE | COMPLETE_DONT_ESCAPE | COMPLETE_NO_SPACE );
|
||||
res=1;
|
||||
|
||||
sb_destroy( &desc );
|
||||
sb_destroy( &name );
|
||||
|
||||
}
|
||||
free( pw_name );
|
||||
}
|
||||
endpwent();
|
||||
}
|
||||
endpwent();
|
||||
}
|
||||
}
|
||||
|
||||
return res;}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -469,4 +469,8 @@ long sysconf(int name);
|
|||
|
||||
#endif
|
||||
|
||||
#ifndef NAN
|
||||
#define NAN (0.0/0.0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue