Chinaunix首页 | 论坛 | 博客
  • 博客访问: 652360
  • 博文数量: 99
  • 博客积分: 4335
  • 博客等级: 中校
  • 技术积分: 931
  • 用 户 组: 普通用户
  • 注册时间: 2009-07-26 14:11
文章分类

全部博文(99)

文章存档

2012年(14)

2011年(17)

2010年(14)

2009年(54)

分类: LINUX

2009-08-03 20:50:44

    今天我们讲到Linux系统编程,首先要知道系统调用的概念:所谓系统调用就是操作系统提供给用户程序的一组特殊的接口,用户程序可以通过这些接口来获得操作系统内核提供的服务。在linux中用户程序接口API遵循UNIX中最流行的应用编程界面标准--POSIX标准,这些API主要靠C库(libc)实现。libc详细信息及代码:
 
下面是文件I/O函数有open,write,read,lseek,select,fcnl。
具体的函数就不一一定义了,用在具体的练习中就知道了,下面是我在linuxC编程实战上看到的myls代码:希望有所帮助,慢慢写出自己的ls吧:
 
 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <linux/limits.h>
#include <dirent.h>
#include <grp.h>
#include <pwd.h>
#include <errno.h>

#define        PARAM_NONE    0    // 无参数

#define        PARAM_A        1    // -a: 显示所有文件

#define        PARAM_L        2    // -l:一行显示一个文件的详细信息


#define        MAXROWLEN    80    // 一行显示的最多字符数


int        g_leave_len = MAXROWLEN;    // 一行剩余长度,用于输出对齐

int        g_maxlen;            // 存放某目录下最长文件名的长度


/* 错误处理函数,打印出错误所在行的行数和错误信息 */
void my_err(const char *err_string, int line)
{
    fprintf(stderr, "line:%d ", line);
    perror(err_string);
    exit(1);
}

/* 获取文件属性并打印 */
void display_attribute(struct stat buf, char * name)
{
    char        buf_time[32];
    struct passwd    *psd;    //从该结构体中获取文件所有者的用户名

    struct group    *grp;    //从该结构体中获取文件所有者所属组的组名


    /*获取并打印文件类型*/
    if (S_ISLNK(buf.st_mode)) {
        printf("l");
    } else if (S_ISREG(buf.st_mode)) {
        printf("-");
    } else if (S_ISDIR(buf.st_mode)) {
        printf("d");
    } else if (S_ISCHR(buf.st_mode)) {
        printf("c");
    } else if (S_ISBLK(buf.st_mode)) {
        printf("b");
    } else if (S_ISFIFO(buf.st_mode)) {
        printf("f");
    } else if (S_ISSOCK(buf.st_mode)) {
        printf("s");
    }

    /*获取并打印文件所有者的权限*/
    if (buf.st_mode & S_IRUSR){
        printf("r");
    } else {
        printf("-");
    }
    if (buf.st_mode & S_IWUSR){
        printf("w");
    } else {
        printf("-");
    }
    if (buf.st_mode & S_IXUSR){
        printf("x");
    } else {
        printf("-");
    }

    /*获取并打印与文件所有者同组的用户对该文件的操作权限*/
    if (buf.st_mode & S_IRGRP){
        printf("r");
    } else {
        printf("-");
    }
    if (buf.st_mode & S_IWGRP){
        printf("w");
    } else {
        printf("-");
    }
    if (buf.st_mode & S_IXGRP){
        printf("x");
    } else {
        printf("-");
    }

    /*获取并打印其它用户的对该文件的操作权限*/
    if (buf.st_mode & S_IROTH){
        printf("r");
    } else {
        printf("-");
    }
    if (buf.st_mode & S_IWOTH){
        printf("w");
    } else {
        printf("-");
    }
    if (buf.st_mode & S_IXOTH){
        printf("x");
    } else {
        printf("-");
    }

    printf(" ");

    /*根据uid与gid获取文件所有者的用户名与组名*/
    psd = getpwuid(buf.st_uid);
    grp = getgrgid(buf.st_gid);
    printf("%4d ",buf.st_nlink); // 打印文件的链接数

    printf("%-8s", psd->pw_name);
    printf("%-8s", grp->gr_name);

    printf("%6d",buf.st_size); // 打印文件的大小

    strcpy(buf_time, ctime(&buf.st_mtime));
    buf_time[strlen(buf_time) - 1] = '\0';    // 去掉换行符

    printf(" %s", buf_time);                // 打印文件的时间信息

}

/* 在没有使用-l选项时,打印一个文件名,打印时上下行之间进行对齐 */
void display_single(char *name)
{
    int i, len;

    // 如果本行不足以打印一个文件名则换行

    if (g_leave_len < g_maxlen) {    
        printf("\n");
        g_leave_len = MAXROWLEN;
    }

    len = strlen(name);
    len = g_maxlen - len;
    printf("%-s", name);
    
    for (i=0; i<len; i++) {
        printf(" ");
    }
    printf(" ");
    //下面的2指示空两格

    g_leave_len -= (g_maxlen + 2);
}

/*
*    根据命令行参数和完整路径名显示目标文件
*    参数flag: 命令行参数
*    参数pathname: 包含了文件名的路径名
*/

void display(int flag, char * pathname)
{
    int        i, j;
    struct stat    buf;
    char        name[NAME_MAX + 1];

    /*从路径中解析出文件名*/
    for (i=0, j=0; i<strlen(pathname); i++) {
        if (pathname[i] == '/') {
            j = 0;
            continue;
        }
        name[j++] = pathname[i];
    }
    name[j] = '\0';
    
    /*用lstat而不是stat以方便解析链接文件*/
    if ( lstat(pathname, &buf) == -1 ) {
        my_err("stat", __LINE__);
    }
    
    switch (flag) {
        case PARAM_NONE: // 没有-l和-a选项

            if (name[0] != '.') {
                display_single(name);
            }
            break;

        case PARAM_A:     // -a:显示包括隐藏文件在内的所有文件

            display_single(name);
            break;

        case PARAM_L:     // -l:每个文件单独占一行,显示文件的详细属性信息

            if (name[0] != '.') {
                display_attribute(buf, name);
                printf(" %-s\n", name);
            }
            break;

        case PARAM_A + PARAM_L:        // 同时有-a和-l选项的情况

            display_attribute(buf, name);
            printf(" %-s\n", name);
            break;

        default:
            break;
    }
}

void display_dir(int flag_param, char *path)
{
        DIR *dir;
        struct dirent *ptr;
        int count = 0;
        char filenames[256][PATH_MAX+1],temp[PATH_MAX+1];

        // 获取该目录下文件总数和最长的文件名

        dir = opendir(path);
        if (dir == NULL) {
                my_err("opendir", __LINE__);
        }
        while ((ptr = readdir(dir))!=NULL) {
                if (g_maxlen < strlen(ptr->d_name))
                         g_maxlen = strlen(ptr->d_name);
                count++;
        }
        closedir(dir);

        if(count>256)
                my_err("too many files under this dir",__LINE__);
        

        int i, j, len = strlen(path);
        // 获取该目录下所有的文件名

        dir = opendir(path);
        for(i = 0; i < count; i++){
                ptr = readdir(dir);
                if( ptr == NULL){
                        my_err("readdir",__LINE__);
                }
                strncpy(filenames[i],path,len);
                filenames[i][len] = '\0';
                strcat(filenames[i],ptr->d_name);
                filenames[i][len+strlen(ptr->d_name)] = '\0';
        }

        // 使用冒泡法对文件名进行排序,排序后文件名按字母顺序存储于filenames

        for(i = 0; i < count-1; i++)
                for(j = 0; j < count-1-i; j++) {
                        if( strcmp(filenames[j],filenames[j+1]) > 0 ) {
                                strcpy(temp,filenames[j+1]);
                                temp[strlen(filenames[j+1])] = '\0';
                                strcpy(filenames[j+1],filenames[j]);
                                filenames[j+1][strlen(filenames[j])] = '\0';
                                strcpy(filenames[j], temp);
                                filenames[j][strlen(temp)] = '\0';
                        }
                }
        for(i = 0; i < count; i++)
                display(flag_param, filenames[i]);

        closedir(dir);

        // 如果命令行中没有-l选项,打印一个换行符

        if( (flag_param & PARAM_L) == 0)
                printf("\n");}


int main(int argc, char ** argv)
{
    int        i, j, k, num;
    char        path[PATH_MAX+1];
    char        param[32];     // 保存命令行参数,目标文件名和目录名不在此列

    int        flag_param = PARAM_NONE; // 用来标志参数种类,即是否有-l和-a选项

    struct stat    buf;


    /*命令行参数的解析,分析-l、-a、-al、-la选项*/
    j = 0,
    num = 0;
    for (i=1; i<argc; i++) {
        if (argv[i][0] == '-') {
            for(k=1; k < strlen(argv[i]); k++,j++) {
                param[j] = argv[i][k];    // 获取-后面的参数保存到数组param中

            }
        num++; // 保存"-"的个数

        }
    }
    
    /*只支持参数a和l,如果含有其他选项就报错*/
    for(i=0; i<j; i++) {
        if (param[i] == 'a') {
            flag_param |= PARAM_A;
            continue;
        } else if (param[i] == 'l') {
            flag_param |= PARAM_L;
            continue;
        } else {
            printf("my_ls: invalid option -%c\n", param[i]);
            exit(1);
        }
    }
    param[j] = '\0';
    
    // 如果没有输入文件名或目录,就显示当前目录

    if ((num + 1) == argc) {    
        strcpy(path, "./");
        path[2] = '\0';
        display_dir(flag_param, path);
        return 0;
    }

    i=1;
    do {
        // 如果不是目标文件名或目录,解析下一个命令行参数

        if (argv[i][0] == '-') {
            i++;
            continue;    
        } else {
            strcpy(path, argv[i]);

            // 如果目标文件或目录不存在,报错并退出程序

            if ( stat(path, &buf) == -1 )
                my_err("stat", __LINE__);    

            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';

                display_dir(flag_param,path);
                i++;
            }
            else { //argv[i]是一个文件

                display(flag_param, path);
                i++;
            }
        }
    } while (i<argc);

    return 0;
}

阅读(4514) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

wkl71232014-03-27 14:13:52

感谢!

chinaunix网友2009-09-24 21:21:29

虽然没有复杂的数据结构来支持,可以看出楼主是对linux API和对c语言的基础比我扎实多了,多多向露珠学习