LinuxCプログラミング-lsの実装(-R,-a,-l)

42673 ワード

Linuxでのシステムプログラミングとは、プログラマがシステム呼び出しやC言語自体が持つライブラリ関数を使用して特定のプログラムを設計し、作成することを意味します.
lsは日常的に使用される比較的一般的なコマンドの一つであり、lsコマンドをどのように実現するかは、まずlsがパラメータの役割を明確にする必要がある.
ls-aはディレクトリ内のすべてのファイル(.で始まるファイルを含む)を表示することができる
ls-lは、ファイルの属性や権限などのデータを含むファイル内のすべての情報をリストします.
ls-Rはディレクトリ内のサブディレクトリ内のファイルと再帰的に表示され、非表示ファイルを表示する場合は-aパラメータを追加する
lsを実装する前に、次の情報ユーザ権限に対応するテーブルを理解する必要があります.
文字の長さ
文字定数に対応する8進数
意味
S_IRUSR(S_IREAD)
00400
ファイル所有者に読み取り可能な権限がある
S_IWUSR(S_IWRITE)
00200
ファイル所有者に書き込み可能な権限があります
S_IXUSR(S_IEXEC)
00100
ファイルの所有者に実行可能な権限があります
S_IRGRP
00040
ユーザー・グループに読み取り可能な権限があります
S_IWGRP
00020
ユーザー・グループに書き込み可能な権限があります
S_IXGRP
00010
ユーザー・グループに実行可能な権限があります
S_IROTH
00004
他のユーザーには読み取り可能な権限があります
S_IWOTH
00002
他のユーザーには書き込み可能な権限があります
S_ISUID
04000
ファイルの(set user-id)ビット
S_ISGID
02000
ファイルのビット
S_ISVTX
01000
ファイルのstickyビット
lsの出力過程では,端末の幅を大まかに計算する必要があるが,ここではisattyとioctl関数を紹介する
isatty関数は、現在出力されているデバイスが端末デバイスであるか否かを判断するために使用される
ioctlは端末のデバイス情報を取得することができ、いくつかの特殊なデバイスファイルはこれを利用して取得することができる.
具体的な使い方は次のとおりです.(この使い方ではterminalWidthをグローバル変数として使用します.
void getWidth(){
    struct winsize wbuf;
    terminalWidth = 80;
    if( isatty(STDOUT_FILENO) ){
       if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &wbuf) == -1 || wbuf.ws_col == 0){
        return ;  
        }
        else
            terminalWidth = wbuf.ws_col;
    }

}

また、ファイルのプロパティの取得方法についても説明します.
#include < sys/types.h> #include < sys/stat.h> #include < unistd.h> int stat(const char *pathname, struct stat *statbuf); int fstat(int fd, struct stat *statbuf); int lstat(const char pathname, struct stat *statbuf);*
多くの仲間たちは、どの関数を使うべきか迷っているに違いない.この3つの関数の違いは、statがパラメータfile nameで指定されたファイル名情報を取得するために使用され、struct stat*bufに保存され、fstatとstatの違いfstatはファイル記述子によってファイルが作成され、lstatとstatの違いは、シンボルリンクファイルについて、lstatはシンボルリンク自体を返し、statはファイル状態情報を指す
2.そこでここでお勧めするのは、lstatという関数ですが、リンクファイルをどのように読み取るかについては、readlinkという関数を使用してファイル内のリンクを取得することができます.私はここでいくつかのエラーに遭遇しました.まず、readlinkという関数がshellのコマンドであることを説明します.またオペレーティングシステムが提供するインタフェースはmanマニュアルを参照することで
#include < unistd.h> ssize_t readlink(const char *pathname, char *buf, size_t bufsiz); #include < fcntl.h>/* Definition of AT_* constants */ #include < unistd.h> ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz);
まず、その戻り値はssize_です.tタイプ、32ビットのマシンではintタイプと一致し、64ビットのマシンではlong intタイプと一致しています.ディレクトリの内容を読み取ることができますが、ファイル制御記号で終わる'0'、つまり'0'を追加しなければなりません.readlinkを実装する過程で次のようなエラーに遭遇しました.
1.'0'を追加しないと、自分が読み取ったリンクを出力するたびに、アクセスすべきでないメモリにアクセスするというセグメントエラーが発生する.私はダイナミック配列を採用しています.ダイナミック配列はスタックの中で申請されていますが、カーネルは効率を高めるために、申請されたダイナミック配列には内容があるので、使用中にダイナミック配列を初期化しなければなりません.そうしないと、他の多くの関連のない内容が読み出されます.
struct stat*bufではファイル情報を保存する構造体です
struct stat {dev_t st_dev;//ファイルのデバイス番号ino_t st_ino;//ファイルのi-node番号mode_t st_mode_t//ファイルのタイプとアクセス権限nlink_t st_nink;//ファイルのハードリンク数uid_t st_uid;//ファイル所有者のid gid_t st_gid//ファイルのすべてのグループのid dev_t_st_rdev;//ファイルがデバイスファイルであれば、そのデバイス番号off_t_st_size//ファイルのサイズblksize_t st_blksize//ファイルシステムのバッファblkcnt_t st_blocks//ファイルを占有するブロックの個数time_t st_atime//ファイルが最近アクセスされた時刻time_t st_mtime//ファイルが最後に変更された時間time_t st_ctime//ファイルが最近変更された時間
st_modeに含まれるファイル情報
S_ISLNKシンボルリンクS_ISREG一般ファイルS_ISDIRディレクトリファイルS_ISCHRは、文字デバイスファイルS_であるISBLKブロックデバイスファイルS_ISFIFOは、FIFO Sであるか否かを判断するISSOCKはソケットかどうかを判断する
ディレクトリ情報の取得方法については、ディレクトリに対する読み取り権限があれば、ディレクトリ情報を取得できます.
1.opendir DIR opendir(const char name)は、パラメータで指定するディレクトリを取得し、ファイル操作中のファイル記述子と同様にDIR*のディレクトリフローを返します.次に、ディレクトリの読み取りと検索にこの戻り値を使用し、成功するとDIR*のディレクトリフローを返します.readdirは、チェーンテーブルのループ入力が完了した後にNULLd_を出力するように、DIRから中ディレクトリ項目情報を読み出すために使用されます.name 3.closedirがdirを閉じるディレクトリの使い方は、次のようになります.include #include< dirent.h> #include < stdio.h> int readir(const char * path) { DIR * dir; struct dirent * prt; if((dir = opendir(path)==NULL) perror(“opendir”); while((ptr=readdir(dir)!=NULL) { printf(“%d” ptr->d_name); } closedir(dir); return 0; }
再帰を実現する過程でrewinddir関数を採用することは非常に重要です.ここでは、以下のrewindirの関数の役割と、再帰の過程で非常に重要なヘッダファイルの理由を説明します.
#include < sys/types.h> #include < dirent.h>
定義された関数:
void rewinddir(DIR *dir);
公式に示す説明は、rewinddir()がパラメータdirディレクトリストリームの現在の読取位置を元の先頭の読取位置に設定ために用いる.上位ディレクトリを印刷するときに現在のディレクトリの最後に入っており、rewinddirを使用すると最初のファイルに戻ることができます.ls-Rを実現する上で私が直面した問題は自分の解決方法です.
1.セグメントエラーに遭遇する可能性のある原因:スタックオーバーフロー-Rの再帰は巨大なファイル量を発生し、通常の静的配列を使用するとこのような需要を満たすことができず、範囲が大きくてもできない.ここでは動的配列またはチェーンテーブルを使用してこの機能を実現すべきである./proc/ディレクトリを巡回中にエラーが発生することがあります.ほとんどの場合、ファイルの読み取りに失敗した解決方法、lstatはファイル情報を取得します.取得に失敗した場合、上位/proc/は仮想ファイルシステムに戻ります.プロセスを保存し、定期的にクリアします.読み取りと同時に、このファイルを削除する可能性があります.つまり、読み取りに失敗します.
ls-Rを実現する時必ず自分の構想を明確にしなければならない私の構想は、まず第1層のディレクトリを出力して、それからrewinddirを通じてファイルストリームに戻って、それからそれがディレクトリであるかどうかを判断して、もしディレクトリならば入って、1層がディレクトリがない時、returnは上層の世代のコードに戻って奉上します
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include
#include
int terminalWidth ;
char filenames[256][PATH_MAX];
char filenames1[256][100];
int alfag=0,lflag=0;//    , -l -a,-r,-R    
int cnt=0;
void Quicksort(int cnt1,char filenames2[][PATH_MAX],int start);
void recursion(char * path,int alfag);
int ls_prepare(char *path,int lflag);
int ls_prepare(char *pathname,int lflag);
int _ls(char *path,int lflag,int alfag);
int colormode,foreground,background;    
void getcolor( char *filename ){
    struct stat info;    //            
    foreground=0;
   lstat( filename,&info );//          info
//    foreground = 37;
    switch ( (info.st_mode & S_IFMT) ){
        case S_IFREG:               /*regular      ,  */
            {
                foreground = 37;
                    if((info.st_mode&S_IXOTH)||(info.st_mode&S_IXGRP)||(info.st_mode&S_IXUSR))
      {
            foreground = 32;
        }
            break;
            }
        case S_IFLNK:               /*symbolic link      ,    */
            foreground = 36;
            break;
        case S_IFSOCK:              /*   */
            foreground = 35;
            break;
        case S_IFDIR:               /*directory      ,   */
        foreground = 34;
            break;
        case S_IFBLK:               /*block special       ,   */
            foreground = 33;
            break;
        case S_IFCHR:               /*character special        ,   */
            foreground = 33;
            break;
    }
}
struct filename
{
    char filename[PATH_MAX];
    struct filename * next;
};
void Quicksort1(struct filename * pHead,struct filename * tail)
{
    if(pHead->next==tail)
        return ;
    if(pHead->next->next==tail)
    {
            return ;
    }
    struct filename * mid = pHead->next;
    struct filename * p = pHead;
    struct filename * q =mid;
    struct filename * t = mid->next;
    char name[MAXNAMLEN];
    strcpy(name,mid->filename);
    while(t!=tail)
    {
        if(strcmp(t->filename,name)<0)
            p=p->next=t;
        else
            q=q->next=t;
        t=t->next;
    }
    p->next= mid;
    q->next =tail;
    Quicksort1( pHead ,mid );
    Quicksort1( mid  , tail);
}
void list_R(const char * dirname,int lflag)
{
        DIR     *dir_ptr;       
        struct dirent   *direntp;       
        char        *fullpath;
        struct stat info;
//        int i;
        struct filename * pHead,*p1;
        pHead=p1=(struct filename *)malloc(sizeof(struct filename));
        pHead->next=p1->next=NULL;
        printf("%s:
"
,dirname); if ( ( dir_ptr = opendir( dirname ) ) == NULL ){ fprintf(stderr,"list_R: cannot open %s
"
, dirname); return; } // printf("%s:
",dirname);
// i=0; fullpath = (char *)malloc(strlen(dirname) + 1 + MAXNAMLEN + 1); while ( ( direntp = readdir( dir_ptr ) ) != NULL ) { struct filename *new1=(struct filename *)malloc(sizeof(struct filename)); if(alfag==0) { if(direntp->d_name[0]=='.') { continue; } } sprintf(fullpath,"%s/%s",dirname,direntp->d_name); if(lflag==3) _ls(fullpath,lflag,alfag); else { strcpy(new1->filename,direntp->d_name); p1->next=new1; p1=new1; new1->next=NULL; } } Quicksort1(pHead,NULL); struct filename * pTemp=pHead->next; struct filename * q=pHead; if(pHead->next!=NULL) { while(pTemp!=NULL) { getcolor(pTemp->filename); printf("\033[%dm%s\033[0m
"
,foreground,pTemp->filename); free(q); q=pTemp; pTemp=pTemp->next; } } if ( lflag ){ rewinddir(dir_ptr); while ( ( direntp = readdir( dir_ptr ) ) != NULL ) { if(alfag==0) { if(direntp->d_name[0]=='.') { continue; } } sprintf(fullpath,"%s/%s",dirname,direntp->d_name); // printf("%s",direntp->d_name); // puts(""); lstat(fullpath,&info); // _ls(fullpath,lflag,alfag); if(alfag==0) { if(S_ISDIR(info.st_mode)) { putchar('
'
); list_R( fullpath, lflag ); } } else { if ( S_ISDIR(info.st_mode)&& direntp->d_name[0]!='.') // { putchar('
'
); list_R( fullpath, lflag ); } } } } closedir(dir_ptr); free(fullpath); } void Quicksort(int cnt1,char filenames2[][PATH_MAX],int start) { int i,j; char *name; char *name1; name=(char *)malloc(MAXNAMLEN); name1=(char *)malloc(MAXNAMLEN); memset(name,0,MAXNAMLEN); memset(name,0,MAXNAMLEN); if(start >cnt1) return ; strcpy(name,filenames2[start]); i=start; j=cnt1; while(i!=j) { while(strcmp(filenames2[j],name)<=0 && iwhile(strcmp(filenames2[i],name)>=0 && iif(istrcpy(name1,filenames2[i]); strcpy(filenames2[i],filenames2[j]); strcpy(filenames2[j],name1); } } strcpy(filenames2[start],filenames2[i]); strcpy(filenames2[i],name); Quicksort(i-1,filenames2,start); Quicksort(cnt1,filenames2,i+1); return ; free(name); free(name1); } void getWidth(){ struct winsize wbuf; terminalWidth = 80; if( isatty(STDOUT_FILENO) ){ if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &wbuf) == -1 || wbuf.ws_col == 0){ } else terminalWidth = wbuf.ws_col; } return ; } int getlen_str(char * str) { int res=0,i; while(*str!='\0') { if(*str > 0) { res++; str++; } else { for(i=7;i>=0;i--) { if(!((*str>>7)&1)) break; res+=2; str+=7-i; // if((*str>>7)&1) // break; } } } return res; } void display_single(int cnt,int alfag) { int i,k,n=0,m=0,j=0,n1; n=cnt,n1=cnt; i=0; Quicksort(cnt,filenames,0); while(n>=0) { n--; strcpy(filenames1[i],filenames[i]); for(m=0;mint)strlen(filenames[i]));m++) { if((filenames[i][m]=='.'&&filenames[i][m-1]=='/')) { break ; } if(filenames[i][m]=='/') { k=m; } } for(j=0;j<=k;j++) { filenames[i][j]=' '; } if(alfag==0) { if(filenames[i][k+1]=='.') { strcpy(filenames[i]," "); } } i++; } Quicksort(cnt,filenames,0); int wordColNUM=20; cnt=cnt// while(cnt>0) { int wordLenMax[4000]={0};// int wordRowNum=0;// j=0; int sum=0; int length[4000]; for(j=0;j1);// if((cnt-1)*wordRowNum>=terminalWidth) cnt-- ; for(j=0;jint f=j*wordRowNum; for(i=0;i// { if(f>n1) break; if(getlen_str(filenames[f])>wordLenMax[j]) wordLenMax[j]=(getlen_str(filenames[f])); f++; } if(j!=cnt-1) sum+=wordLenMax[j]+2; } if(sum// cnt--; int t=wordRowNum - cnt * wordRowNum +n1; for(int p=0;pfor(int o=0;o1;o++) { getcolor(filenames1[p+o*wordRowNum]); printf("\033[%dm%s\033[0m",foreground,filenames[p+o*wordRowNum]); for(int y=0;yprintf(" "); for( int g=0;g<2;g++) printf(" "); // printf("
");
} if(t) { getcolor(filenames1[p+(cnt-1 )*wordRowNum]); printf("\033[%dm%s\033[0m",foreground,filenames[p+(cnt-1)*wordRowNum]); t--; } printf("
"
); } break; } // wordLenMax +=2; // ; // wordRowNum = terminalWidth/wordLenMax; // cnt--; if(!cnt) { cnt=1; for(int x=0;xprintf("\033[%dm%s\033[0m
"
,foreground,filenames[x]); } } } return ; } int _ls(char *path,int lflag,int alfag) { int i,n,k; int temp; struct stat buf; char *out=NULL; // char out[PATH_MAX]; struct passwd *pw=NULL; struct group *gr=NULL; char *t=NULL; char *name=NULL; char *name1=NULL; name = (char *)malloc(strlen(path) + 1 + MAXNAMLEN + 1); name1 =(char *)malloc(strlen(path)+1 +MAXNAMLEN +1); out=(char *)malloc(PATH_MAX); memset(out,0,PATH_MAX); // j=strlen(out); strcpy(name,path); strcpy(name1,path); for(i=0;iint)strlen(name));i++) { if((name[i]=='.'&&name[i-1]=='/')&&alfag==0) { // cnt--; return 0; } if(name[i]=='/') k=i; } for(i=0;i<=k;i++) { name[i]=' '; } if(lflag==2) return 0; // lstat(path,&buf); if(lstat(path,&buf)<0) { // fprintf(stderr,"stat error:%s
",strerror(errno));
return 0 ; } // : -、 d、 c、 b、 // p、 l、 s //st.mode switch(buf.st_mode & S_IFMT) //S_IFMT { case S_IFREG: { printf("-"); } break; case S_IFDIR: { printf("d"); } break; case S_IFCHR: { printf("c"); } break; case S_IFBLK: { printf("b"); } break; case S_IFIFO: { printf("p"); } break; case S_IFLNK: { printf("l"); } break; case S_IFSOCK: { printf("s"); } break; } // : r、 w、 x、 - for(n=8;n>=0;n--) { if(buf.st_mode&(1<switch(n%3) { case 2: printf("r"); break; case 1: printf("w"); break; case 0: { printf("x"); } break; default: break; } } else { printf("-"); } } // , , ( ) , // 1, 2, ( , ) printf(" %4d ",(int)buf.st_nlink); pw = getpwuid(buf.st_uid); // // // struct passswd * getpwuid printf(" %s ",pw->pw_name); gr = getgrgid(buf.st_gid); // printf(" %6s ",gr->gr_name); printf(" %8ld ",buf.st_size); // t = ctime(&buf.st_atime); // printf(" %10.12s ",4+t); getcolor(path); printf("\033[%dm%4s\033[0m",foreground,name); // , if(S_ISLNK(buf.st_mode)) { printf(" -> "); if((temp=readlink(name1,out,PATH_MAX)==-1))// { // printf("readlink error"); } strcat(out,"\0"); printf("%4s",out); } printf("
"
); free(name); free(name1); free(out); return 0; } // ls int ls_prepare(char *path,int lflag) { struct stat buf; //man lstat DIR *dir; //opendir dir struct dirent *ptr; int count = 0; //man readdir // / buf, lstat , // w , , lstat(path,&buf); /* if(lstat(path,&buf)<0) { fprintf(stderr,"stat error:%s
",strerror(errno)); return -1; }*/
dir=opendir(path); while((ptr= readdir(dir))!=NULL) { count++; } closedir(dir); int i,len=strlen(path); dir=opendir(path); for(i=0;iif(ptr==NULL) { perror("readdir"); } strcpy(filenames[i],path); filenames[i][len]='\0'; strcat(filenames[i],ptr->d_name); filenames[i][len+strlen(ptr->d_name)]='\0'; } cnt=i; //S_IRUSR ,S_IWUSR Quicksort(cnt-1,filenames,0); if(lflag==0) { display_single(cnt,alfag); return 0; } for(i=0;ireturn 0; } int main(int argc,char ** argv) { getWidth(); char param[32];// , -l -al -a char path[81]; struct stat buf; int i,j,k,num=0; // j=0; for(i=1;iif(argv[i][0]=='-') { for(k=1;kint)strlen(argv[i]);k++,j++) { param[j] = argv[i][k]; } num++; } } for(i=0;iif(param[i]=='a') { alfag=1; continue; } if(param[i]=='l') { lflag+=1; continue; } if(param[i]=='R') { lflag=lflag+2; continue; } } param[j]='\0'; // , if((num+1)==argc) { strcpy(path,"./"); path[2]='\0'; ls_prepare(path,lflag); return 0; } i=1; do { if(argv[i][0]=='-') { i++; continue; } else { strcpy(path,argv[i]); if(stat(path,&buf)==-1) { perror("stat"); } if(S_ISDIR(buf.st_mode))//argv[i] // , '/', { if(path[strlen(argv[i])-1]!='/') { path[strlen(argv[i])]='/'; path[strlen(argv[i])+1]='\0';// } else path[strlen(argv[i])]='\0'; if(lflag>=2) { list_R(path,lflag); return 0; } ls_prepare(path,lflag); i++; } else{ display_single(cnt,alfag); i++; } } }while(ireturn 0; }