ls.c
上传用户:lukesailor
上传日期:2007-01-04
资源大小:27k
文件大小:15k
源码类别:

Ftp客户端

开发平台:

Unix_Linux

  1. /* $Id: ls.c,v 1.10 1999/02/13 15:23:42 agulbra Exp $ */
  2. #include <time.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <unistd.h>
  6. #include <ctype.h>
  7. #include <sys/time.h>
  8. #include <setjmp.h>
  9. #include <errno.h>
  10. #include <string.h>
  11. #include <syslog.h>
  12. #include <sys/types.h>
  13. #include <sys/socket.h>
  14. #include <netinet/in.h>
  15. #include <sys/stat.h>
  16. #include <fcntl.h>
  17. #include <sys/mman.h>
  18. #include <sys/param.h>
  19. #include <pwd.h>
  20. #include <grp.h>
  21. #include <arpa/inet.h>
  22. #include <netdb.h>
  23. #ifndef _GNU_SOURCE
  24. #define _GNU_SOURCE /* for GLOB_ABEND in newer glibcs */
  25. #endif
  26. #include <glob.h> /* linux rules! */
  27. #include <dirent.h>
  28. #include <sys/resource.h>
  29. #include <sys/vfs.h>
  30. #include <signal.h>
  31. #include "ftpd.h"
  32. #if defined(GLOB_ABORTED) && !defined(GLOB_ABEND)
  33. #define GLOB_ABEND GLOB_ABORTED
  34. #endif
  35. static char *getname( const uid_t uid );
  36. static char **sreaddir( const char *dirname );
  37. static void addfile( const char *, const char * );
  38. static void outputfiles( int );
  39. static int listfile( const char *name );
  40. static void listdir( int f, const char *name );
  41. char *users = NULL;
  42. char *groups = NULL;
  43. static int matches;
  44. static char outbuf[1024];
  45. static int outptr = 0;
  46. static void wrstr( int f, const char * s )
  47. {
  48.     int l;
  49.     if ( !s ) {
  50. if ( outptr )
  51.     write( f, outbuf, outptr );
  52. outptr = 0;
  53. return;
  54.     }
  55.     l = strlen( s );
  56.     if ( l + outptr > 1024 ) {
  57. if ( outptr )
  58.     write( f, outbuf, outptr );
  59. outptr = 0;
  60.     }
  61.     if ( l > 1024 ) {
  62. write( f, s, l );
  63.     } else {
  64. memcpy( outbuf+outptr, s, l );
  65. outptr += l;
  66.     }
  67. }
  68. void getnames( void )
  69. {
  70.     int f;
  71.     /* uid_t can have 65536 values on linux */
  72.     f = open( "/var/adm/ftp/users", O_RDONLY );
  73.     if ( f >= 0 ) {
  74. users = mmap( 0, (size_t) 9 * 65536,
  75.       PROT_READ, MAP_FILE | MAP_SHARED, f, 0 );
  76. if ( users == (void *) -1 ) {
  77.     users = NULL;
  78.     close( f );
  79. }
  80.     }
  81.     f = open( "/var/adm/ftp/groups", O_RDONLY );
  82.     if ( f >= 0 ) {
  83. groups = mmap( 0, ( size_t ) 9 * 65536,
  84.        PROT_READ, MAP_FILE | MAP_SHARED, f, 0 );
  85. if ( groups == (void *)-1 ) {
  86.     groups = NULL;
  87.     close( f );
  88. }
  89.     }
  90. }
  91. char *getname( const uid_t uid )
  92. {
  93.     static char number[9];
  94.     if ( users && users[9 * uid] ) {
  95. return ( users + ( 9 * uid ) );
  96.     } else {
  97. sprintf( number, "%-8d", uid );
  98. return ( number );
  99.     }
  100. }
  101. char *getgroup( const gid_t gid )
  102. {
  103.     static char number[9];
  104.     if ( groups && groups[9 * gid] ) {
  105. return ( groups + ( 9 * gid ) );
  106.     } else {
  107. sprintf( number, "%-8d", gid );
  108. return ( number );
  109.     }
  110. }
  111. /* ls options */
  112. int opt_a,
  113.   opt_C,
  114.   opt_d,
  115.   opt_F,
  116.   opt_l,
  117.   opt_R,
  118.   opt_r,
  119.   opt_t,
  120.   opt_S;
  121. /* listfile returns non-zero if the file is a directory */
  122. int listfile( const char *name )
  123. {
  124.     int rval = 0;
  125.     char m[1024];
  126.     struct stat st;
  127.     char months[12][4] =
  128.     {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  129.      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
  130.     struct tm *t;
  131.     char suffix[2];
  132.     if ( lstat( name, &st ) == 0 ) {
  133. t = localtime( (time_t * ) & st.st_mtime );
  134. if ( !t ) {
  135.     printf( "421 Bailing out, localtime() is insanern" );
  136.     fflush( stdout );
  137.     exit( 2 );
  138. }
  139. suffix[0] = suffix[1] = '';
  140. if ( opt_F ) {
  141.     if ( S_ISLNK( st.st_mode ) )
  142. suffix[0] = '@';
  143.     else if ( S_ISDIR( st.st_mode ) ) {
  144. suffix[0] = '/';
  145. rval = 1;
  146.     } else if ( st.st_mode & 010101 )
  147. suffix[0] = '*';
  148. }
  149. if ( opt_l ) {
  150.     strcpy( m, " ---------" );
  151.     switch ( st.st_mode & S_IFMT ) {
  152. case S_IFREG:
  153. m[0] = '-';
  154. break;
  155. case S_IFLNK:
  156. m[0] = 'l';
  157. break; /* readlink() here? */
  158. case S_IFDIR:
  159. m[0] = 'd';
  160. rval = 1;
  161. break;
  162.     }
  163.     if ( m[0] != ' ' ) {
  164. char nameline[PATH_MAX + PATH_MAX + 128];
  165. char timeline[6];
  166. if ( st.st_mode & 256 )
  167.     m[1] = 'r';
  168. if ( st.st_mode & 128 )
  169.     m[2] = 'w';
  170. if ( st.st_mode & 64 )
  171.     m[3] = 'x';
  172. if ( st.st_mode & 32 )
  173.     m[4] = 'r';
  174. if ( st.st_mode & 16 )
  175.     m[5] = 'w';
  176. if ( st.st_mode & 8 )
  177.     m[6] = 'x';
  178. if ( st.st_mode & 4 )
  179.     m[7] = 'r';
  180. if ( st.st_mode & 2 )
  181.     m[8] = 'w';
  182. if ( st.st_mode & 1 )
  183.     m[9] = 'x';
  184. if ( time( NULL ) - st.st_mtime > 180 * 24 * 60 * 60 )
  185.     sprintf( timeline, "%5d", t->tm_year + 1900 );
  186. else
  187.     sprintf( timeline, "%02d:%02d", t->tm_hour, t->tm_min );
  188. sprintf( nameline, "%s %3d %s %s %7d %s %2d %s %s", m,
  189.     st.st_nlink, getname( st.st_uid ), getgroup( st.st_gid ),
  190. ( unsigned int ) st.st_size, months[t->tm_mon],
  191. t->tm_mday, timeline, name );
  192. if ( S_ISLNK( st.st_mode ) ) {
  193.     char *p = nameline + strlen( nameline );
  194.     m[readlink( name, m, 1023 )] = '';
  195.     suffix[0] = '';
  196.     if ( opt_F && stat( name, &st ) == 0 ) {
  197. if ( S_ISLNK( st.st_mode ) )
  198.     suffix[0] = '@';
  199. else if ( S_ISDIR( st.st_mode ) )
  200.     suffix[0] = '/';
  201. else if ( st.st_mode & 010101 )
  202.     suffix[0] = '*';
  203.     }
  204.     sprintf( p, " -> %s", m );
  205. }
  206. addfile( nameline, suffix );
  207.     } /* hide non-downloadable files */
  208. } else {
  209.     if ( S_ISREG( st.st_mode ) ||
  210. S_ISDIR( st.st_mode ) ||
  211. S_ISLNK( st.st_mode ) ) {
  212. addfile( name, suffix );
  213.     }
  214. }
  215.     }
  216.     return rval;
  217. }
  218. int colwidth = 0;
  219. int filenames = 0;
  220. struct filename {
  221.     struct filename *down;
  222.     struct filename *right;
  223.     int top;
  224.     char line[1];
  225. };
  226. struct filename *head = NULL;
  227. struct filename *tail = NULL;
  228. void addfile( const char *name, const char *suffix )
  229. {
  230.     struct filename *p;
  231.     int l;
  232.     if ( !name || !suffix )
  233. return;
  234.     matches++;
  235.     l = strlen( name ) + strlen( suffix );
  236.     if ( l > colwidth )
  237. colwidth = l;
  238.     p = ( struct filename * ) malloc( sizeof( struct filename ) + l );
  239.     if ( !p ) {
  240. printf( "421 Out of memoryrn" );
  241. fflush( stdout );
  242. exit( 7 );
  243.     }
  244.     sprintf( p->line, "%s%s", name, suffix );
  245.     if ( tail )
  246. tail->down = p;
  247.     else
  248. head = p;
  249.     tail = p;
  250.     filenames++;
  251. }
  252. void outputfiles( int f )
  253. {
  254.     int n;
  255.     struct filename *p;
  256.     struct filename *q;
  257.     if ( !head )
  258. return;
  259.     tail->down = NULL;
  260.     tail = NULL;
  261.     colwidth = ( colwidth | 7 ) + 1;
  262.     if ( opt_l || !opt_C )
  263. colwidth = 75;
  264.     /* set up first column */
  265.     p = head;
  266.     p->top = 1;
  267.     n = (filenames + (75 / colwidth)-1) / (75 / colwidth);
  268.     while ( n && p ) {
  269. p = p->down;
  270. if ( p )
  271.     p->top = 0;
  272. n--;
  273.     }
  274.     /* while there's a neighbour to the right, point at it */
  275.     q = head;
  276.     while ( p ) {
  277. p->top = q->top;
  278. q->right = p;
  279. q = q->down;
  280. p = p->down;
  281.     }
  282.     /* some are at the right end */
  283.     while ( q ) {
  284. q->right = NULL;
  285. q = q->down;
  286.     }
  287.     /* don't want wraparound, do we? */
  288.     p = head;
  289.     while ( p && p->down && !p->down->top )
  290. p = p->down;
  291.     if ( p && p->down )
  292. p->down = NULL;
  293.     /* print each line, which consists of each column */
  294.     p = head;
  295.     while ( p ) {
  296. q = p;
  297. p = p->down;
  298. while ( q ) {
  299.     char pad[6];
  300.     char *tmp = ( char * ) q;
  301.     if ( q->right ) {
  302. strcpy( pad, "ttttt" );
  303. pad[( colwidth + 7 - strlen( q->line ) ) / 8] = '';
  304.     } else {
  305. strcpy( pad, "rn" );
  306.     }
  307.     wrstr( f, q->line );
  308.     wrstr( f, pad );
  309.     q = q->right;
  310.     free( tmp );
  311. }
  312.     }
  313.     /* reset variables for next time */
  314.     head = tail = NULL;
  315.     colwidth = 0;
  316.     filenames = 0;
  317. }
  318. char **sreaddir( const char *dirname )
  319. {
  320.     DIR *d;
  321.     struct dirent *de;
  322.     struct stat st;
  323.     int i;
  324.     char **p;
  325.     int s;
  326.     int dsize;
  327.     static int cmp( const void *a, const void *b );
  328.     /* functions to to sort for qsort() */
  329.     static int cmp( const void *a, const void *b ) {
  330. return strcmp( *( const char ** ) a, *( const char ** ) b );
  331.     }
  332.     static int cmp_r ( const void *a, const void *b ) {
  333. return strcmp( *( const char ** ) b, *( const char ** ) a );
  334.     }
  335.     static int cmp_t ( const void *a, const void *b ) {
  336.         return *(*(const int **)a -2) - *(*(const int **)b -2);
  337.     }
  338.     static int cmp_rt ( const void *a, const void *b ) {
  339.         return *(*(const int **)b -2) - *(*(const int **)a -2);
  340.     }
  341.     static int cmp_S ( const void *a, const void *b ) {
  342.         return *(*(const int **)b -1) - *(*(const int **)a -1);
  343.     }
  344.     static int cmp_rS ( const void *a, const void *b ) {
  345.         return *(*(const int **)a -1) - *(*(const int **)b -1);
  346.     }
  347.     if ( stat( dirname, &st ) < 0 )
  348. return NULL;
  349.     if ( !S_ISDIR( st.st_mode ) ) {
  350. errno = ENOTDIR;
  351. return NULL;
  352.     }
  353.     if ( (d = opendir( dirname ) ) == NULL )
  354. return NULL;
  355.     /* st_size is enough for any sane fs, but procfs is insane */
  356.     dsize = st.st_size + 100; /* okay okay, a little margin is cool */
  357.  berkeley:
  358.     dsize = dsize * 2;
  359.     p = (char **)malloc( dsize );
  360.     if ( !p ) {
  361. closedir( d );
  362. errno = ENOMEM;
  363. return NULL;
  364.     }
  365.     s = dsize;
  366.     i = 0;
  367.     while ( (de = readdir( d ) ) != NULL ) {
  368. struct stat st;
  369. if ( s < i*sizeof(int) + 3*sizeof(int) + strlen( de->d_name ) + 1 ) {
  370.     /* should leak some memory too, make it perfect : ) */
  371.     free( p );
  372.     rewinddir( d );
  373.     goto berkeley;
  374. }
  375. s -= strlen( de->d_name ) + 1;
  376. strcpy( ((char *)p)+s, de->d_name );
  377. p[i++] = ((char *)p)+s;
  378. if (!lstat(de->d_name,&st)) {
  379.     s -= sizeof(int);
  380.     *((int *)(((char *)p) + s))=st.st_size;
  381.     s -= sizeof(int);
  382.     *((int *)(((char *)p) + s))=st.st_size;
  383. } else {
  384.     s -= sizeof(int);
  385.     *((int *)(((char *)p) + s))=0;
  386.     s -= sizeof(int);
  387.     *((int *)(((char *)p) + s))=0;
  388. }
  389.     }
  390.     closedir( d );
  391.     p[i] = NULL;
  392.     if (opt_t)
  393. if (opt_r)
  394.     qsort( p, i, sizeof( char * ), cmp_rt );
  395. else
  396.     qsort( p, i, sizeof( char * ), cmp_t );
  397.     else if (opt_S)
  398. if (opt_r)
  399.     qsort( p, i, sizeof( char * ), cmp_rS );
  400. else
  401.     qsort( p, i, sizeof( char * ), cmp_S );
  402.     else
  403. if (opt_r)
  404.     qsort( p, i, sizeof( char * ), cmp_r );
  405. else
  406.     qsort( p, i, sizeof( char * ), cmp );
  407.     return p;
  408. }
  409. /* have to change to the directory first ( speed hack for -R ) */
  410. void listdir( int f, const char *name )
  411. {
  412.     char **dir;
  413.     dir = sreaddir( "." );
  414.     if ( dir ) {
  415. char **s;
  416. char **r;
  417. int d;
  418. wrstr( f, "total 1rn" ); /* so what is total anyway */
  419. s = dir;
  420. while ( *s ) {
  421.     if ( **s != '.' ) {
  422. d = listfile( *s );
  423.     } else if ( opt_a ) {
  424. d = listfile( *s );
  425. if ( ( (*s)[1] == '' ) ||
  426.      ( ( (*s)[1] == '.' ) &&
  427.        ( (*s)[2] == '' ) ) )
  428.     d = 0;
  429.     } else {
  430. d = 0;
  431.     }
  432.     if ( !d )
  433. *s = NULL;
  434.     s++;
  435. }
  436. outputfiles( f );
  437. r = dir;
  438. while ( opt_R && r != s ) {
  439.     if ( *r && !chdir( *r ) ) {
  440. char subdir[MAXPATHLEN];
  441. sprintf( subdir, "%s/%s", name, *r );
  442. wrstr( f, "rn" );
  443. wrstr( f, subdir );
  444. wrstr( f, ":rn" );
  445. listdir( f, subdir );
  446. if ( chdir( ".." ) ) { /* defensive in the extreme... */
  447.     chdir( wd );
  448.     if ( chdir( name ) ) { /* someone rmdir()'d it? */
  449. printf( "421 Unrecoverable file system error: %srn",
  450. strerror( errno ) );
  451. fflush( stdout );
  452. exit( 13 );
  453.     }
  454. }
  455.     }
  456.     r++;
  457. }
  458. free( dir );
  459.     } else {
  460. addreply( 226, "Out of memory during reading of %s", name );
  461.     }
  462. }
  463. void donlist( char *arg )
  464. {
  465.     int c;
  466.     matches = 0;
  467.     opt_a = opt_C = opt_d = opt_F = opt_R = opt_r = opt_t = opt_S = 0;
  468.     while ( isspace( *arg ) )
  469. arg++;
  470.     while ( arg && *arg == '-' ) {
  471. while ( arg++ && isalnum( *arg ) ) {
  472.     switch ( *arg ) {
  473.     case 'a':
  474. opt_a = 1;
  475. break;
  476.     case 'l':
  477. opt_l = 1;
  478. opt_C = 0;
  479. break;
  480.     case '1':
  481. opt_l = opt_C = 0;
  482. break;
  483.     case 'C':
  484. opt_l = 0;
  485. opt_C = 1;
  486. break;
  487.     case 'F':
  488. opt_F = 1;
  489. break;
  490.     case 'R':
  491. opt_R = 1;
  492. break;
  493.     case 'd':
  494. opt_d = 1;
  495. break;
  496.     case 'r':
  497. opt_r = 1;
  498. break;
  499.     case 't':
  500. opt_t = 1;
  501. opt_S = 0;
  502. break;
  503.     case 'S':
  504. opt_S = 1;
  505. opt_t = 0;
  506. break;
  507.     default:
  508.     }
  509. }
  510. while ( isspace( *arg ) )
  511.     arg++;
  512.     }
  513.     c = opendata();
  514.     if ( !c )
  515. return;
  516.     doreply();
  517.     if ( type == 2 )
  518. addreply( 0, "Binary mode requested, but A (ASCII) used." );
  519.     if ( arg && *arg ) {
  520. int justone;
  521. char * doshack;
  522. justone = 1; /* just one argument, so don't print dir name */
  523. while ( arg ) {
  524.     glob_t g;
  525.     int a;
  526.     char buffer[PATH_MAX];
  527.     char *endarg = strchr( arg, ' ' );
  528.     if ( endarg ) {
  529. *endarg++ = '';
  530. justone = 0;
  531.     }
  532.     if ( debug )
  533. addreply( 226, "Glob argument: %s", arg );
  534.     if ( loggedin && !guest && *arg == '~' ) {
  535. struct passwd *pw;
  536. int i;
  537. const char *p;
  538. i = 0;
  539. p = arg;
  540. p++;
  541. while ( *p && *p != '/' )
  542.     buffer[i++] = *p++;
  543. buffer[i] = '';
  544. if ( (pw = getpwnam( i ? buffer : account ) ) )
  545.     sprintf( buffer, "%s%s", pw->pw_dir, p );
  546. else
  547.     *buffer = '';
  548.     } else {
  549. *buffer = '';
  550.     }
  551.     /* try to defend against wildcard denial-of-service attack */
  552.     doshack = strstr( arg, "/../" );
  553.     if ( doshack ) {
  554. /* first eliminate those at the start */
  555. if ( doshack == arg ) {
  556.     while( strncmp( arg, "/../", 4 ) == 0 )
  557. strcpy( arg, arg+4 );
  558.     doshack = strstr( arg, "/../" );
  559. }
  560. /* next, eliminate /../ in the middle of the string */
  561. while( doshack ) {
  562.     char * nextcomponent = doshack + 4;
  563.     if ( doshack != arg && *doshack == '/' )
  564. doshack--;
  565.     while( doshack != arg && *doshack != '/' )
  566. doshack--;
  567.     if ( *doshack == '/' )
  568. doshack++;
  569.     strcpy( doshack, nextcomponent );
  570.     doshack = strstr( arg, "/../" );
  571. }
  572. addreply( 0, "Simplified wildcard expression to %s", arg );
  573.     }
  574.     a = glob( *buffer ? buffer:arg, opt_a ? GLOB_PERIOD : 0,
  575.       NULL, &g );
  576.     if ( !a ) {
  577. char **path;
  578. path = g.gl_pathv;
  579. if ( path && path[0] && path[1] )
  580.     justone = 0;
  581. while ( path && *path ) {
  582.     struct stat st;
  583.     if ( lstat( *path, &st ) == 0 ) {
  584. if ( opt_d || !( S_ISDIR( st.st_mode ) ) ) {
  585.     listfile( *path );
  586.     **path = '';
  587. }
  588.     } else {
  589. **path = '';
  590.     }
  591.     path++;
  592. }
  593. outputfiles( c ); /* in case of opt_C */
  594. path = g.gl_pathv;
  595. while ( path && *path ) {
  596.     if ( **path ) {
  597. if ( !justone ) {
  598.     wrstr( c, "rr" );
  599.     wrstr( c, *path );
  600.     wrstr( c, ":rn" );
  601. }
  602. if ( !chdir( *path ) ) {
  603.     listdir( c, *path );
  604.     chdir( wd );
  605. }
  606.     }
  607.     path++;
  608. }
  609.     } else {
  610. if ( a == GLOB_NOSPACE ) {
  611.     addreply( 226,
  612.       "Out of memory during globbing of %s", arg );
  613.     addreply( 0,
  614.       "(This probably means "Permission denied")" );
  615. } else if ( a == GLOB_ABEND ) {
  616.     addreply( 226,
  617.       "Read error during globbing of %s", arg );
  618. } else if ( a != GLOB_NOMATCH ) {
  619.     addreply( 226,
  620.       "Unknown error during globbing of %s", arg );
  621. }
  622.     }
  623.     globfree( &g );
  624.     arg = endarg;
  625. }
  626.     } else {
  627. if ( opt_d )
  628.     listfile( "." );
  629. else
  630.     listdir( c, "." );
  631. outputfiles( c );
  632.     }
  633.     wrstr( c, NULL );
  634.     close( c );
  635.     if ( opt_a || opt_C || opt_d || opt_F || opt_l || opt_r || opt_R ||
  636.  opt_t || opt_S )
  637. addreply( 0, "Options: %s%s%s%s%s%s%s%s%s",
  638.   opt_a ? "-a " : "",
  639.   opt_C ? "-C " : "",
  640.   opt_d ? "-d " : "",
  641.   opt_F ? "-F " : "",
  642.   opt_l ? "-l " : "",
  643.   opt_r ? "-r " : "",
  644.   opt_R ? "-R " : "",
  645.   opt_S ? "-S " : "",
  646.   opt_t ? "-t" : "" );
  647.     addreply( 226, "%d matches total", matches );
  648. }