4.14

编写创建整个 demodir 目录树的 Unix 命令

#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>


int main()
{
    if(mkdir("demodir", 0755) == 0)
        printf("mkdir demodir success.\n");
    else
        perror("demodir: ");

    if (chdir("demodir") == 0)
        printf("change work directory to demodir success.\n");
    else
        perror("chdir demodir");

    if (mkdir("b", 0755) == 0)
        printf("mkdir b success.\n");
    else
        perror("mkdir b ");

    if (mkdir("cops", 0755) == 0)
        printf("mkdir cops success.\n");
    else
        perror("mkdir cops");

    if (rename("b", "c") == 0)
        printf("rename b to c success.\n");
    else
        perror("rename b to c ");
    if (rmdir("cops") == 0)
        printf("rmdir cops success.\n");
    else
        perror("rmdir cops: ");
    if (chdir("c") == 0)
        printf("chdir to c success.\n");
    else
        perror("chdir to c: ");
    if (mkdir("d1", 0755) == 0)
        printf("mkdir d1 success.\n");
    else
        perror("mkdir d1: ");
    if (mkdir("d2", 0755) == 0)
        printf("mkdir d2 success.\n");
    else
        perror("mkdir d2: ");
    if (chdir("../..") == 0)
        printf("chdir ../.. success.\n");
    else
        perror("chdir ../..\n");
    if (mkdir("demodir/a", 0755) == 0)
        printf("mkdir demodir/a success.\n");
    else
        perror("mkdir demodir/a: ");
    return 0;
}

4.15

编写一种支持 -p 选项的 mkdir 命令版本

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>

/* #define DEBUG */

static size_t dir_count = 0;
char **get_each_dir(char *);

    int
main( int argc, char **argv )
{
    if (argc == 1){
        fprintf(stderr, "Usage: %s [option] dir.\n", argv[0]);
    }
    if (argc == 2){
        if (mkdir(argv[1], 0755) == 0){
            return 0;
        }else{
            perror(argv[1]);
            return -1;
        }
    }else if (argc == 3 && strcmp(argv[1], "-p") == 0){
        char **dirs = get_each_dir(argv[2]);
        size_t i = 0;
        for (i = 0; i < dir_count; i++){
#ifdef DEBUG
            printf("%ld:%s\n", i, *dirs);
#endif
            if(mkdir(*dirs, 0755) != 0){
                perror(*dirs);
                return -1;
            }else{
                if (i != dir_count - 1){
                    if (chdir(*dirs) != 0){
                        perror(*dirs);
                        return -2;
                    }
                }
            }
            dirs++;
        }
    }
    return 0;
}

char **get_each_dir(char * path)
{
    char *buf[BUFSIZ];
    char tmp[BUFSIZ];
    int tmp_i = 0;
    unsigned long i;

    for(i = 0; i <= strlen(path); i++){
        if ((i != 0 && path[i] == '/') || i == (strlen(path))){
            tmp[tmp_i] = '\0';
            tmp_i = 0;
            buf[dir_count] = strdup(tmp); // 防止引用同一个地址
#ifdef DEBUG
            printf("%ld: %s : %s : %s\n", dir_count, tmp, buf[dir_count], buf[dir_count > 0?dir_count-1:0]);
#endif
            dir_count++;
        }else{
            tmp[tmp_i] = path[i];
            tmp_i++;
        }
    }
    return buf;
}

4.16

便捷一种接受两个参数的mv版本, 第一个参数必须是文件名, 第二个参数是文件名或目录 名. 如果是目录名, 则将文件移动到那个目录, 否则, 如果可能的话, mv将重命名这个文 件

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>

/* #define DEBUG */

char *get_filename(char *);
int endswith(char *, char *);

    int
main( int argc, char **argv )
{
    char *src = argv[1], *dist = argv[2];
    struct stat finfo;
    
    if (argc == 3){
        if (stat(dist, &finfo) == 0){
            if (S_ISDIR(finfo.st_mode)){
                if (!endswith(dist, "/"))
                    strcat(dist, "/");
                strcat(dist, get_filename(src));
#ifdef DEBUG
                printf("%s\n", dist);
#endif
            }

        }
        if (rename(src, dist) != 0){
            perror(argv[0]);
            return -1;
        }

    }else{
        fprintf(stderr, "Usage: %s file1 file2", argv[0]);
        return -1;
    }
    return 0;
}

int endswith(char *orig, char *sub)
{
    long i, j = strlen(sub) - 1;
    for (i = strlen(orig); i >= 0; i--){
        if (orig[i] != sub[j]){
            return 0;
        }
        j--;
        if (j < 0){
            return 1;
        }
    }
    return 1;
}


char *get_filename(char *path)
{
    char filename[BUFSIZ];
    int fi = 0;
    unsigned long i;

    for (i = 0; i < strlen(path) && path[i] != '\0'; i++){
        if (path[i] == '/'){
            fi = 0;
        }else{
            filename[fi] = path[i];
            fi++;
        }
    }
    filename[fi]='\0';
#ifdef DEBUG
    printf("get_filename: %s\n", filename);
#endif
    return filename;
}