pwd指令的简单实现

来源:互联网 发布:网络摄像头哪种好 编辑:程序博客网 时间:2024/06/03 16:25


pwd指令的简单实现

2015-08-23

pwd以绝对路径打印当前的工作目录。因为整个系统的文件组织是树形的,所以,可以从当前目录逐层向根目录进行查找,当找到根目录,即可得到完全路径。

1.如何逐层查找?

系统通过inode节点来管理文件,所以每个文件会有一个inode号。目录是比较特殊的文件,通过<inode, name>的列表组织目录下的文件。每个目录下有两个特殊的文件名".", "..",分别表示当前目录和父目录。

当前目录             父目录

通过查找父目录,知道当前目录的名字是sub_dir



intget_name_from_inode( char *cpDir, ino_t inoInput, char *cpName ){    DIR *fpDir;    struct dirent *stpEntry;    if( ( fpDir = opendir( cpDir ) ) == NULL )    {        fprintf( stderr, "[%s:%d]opendir() error: %s\n", _FL_, strerror( errno ) );        return -1;    }    while( ( stpEntry = readdir( fpDir ) ) != NULL )    {        if( strcmp( stpEntry->d_name, "dev" ) == 0 )            printf( "dev ino: %d\n", stpEntry->d_ino );        if( stpEntry->d_ino == inoInput )        {            printf( "d_name: %s\n", stpEntry->d_name );            strcpy( cpName, stpEntry->d_name );            break;        }    }    closedir( fpDir );    return stpEntry != NULL ? 0 : -1;}

2.如何知道到了根目录?

到达根目录说明没有父目录了,但是".", ".."还是存在于根目录,只是其inode号是相同的。


intdo_pwd( const char *ccpPath, char *cpCurr ){    ino_t inoCurr;    ino_t inoParent;    char  caName[ NAMELEN ];    if( get_inode_from_name( ccpPath, &inoCurr ) == -1 ||            get_inode_from_name( "..", &inoParent ) == -1 )    {        return -1;    }    /* haven't reached the root of the file system */    if( inoCurr != inoParent )    {        chdir( ".." );        if( get_name_from_inode( ".", inoCurr, caName ) != 0 )        {            fprintf( stderr, "[%s:%d]get_name_from_inode() error: %s\n", _FL_, strerror( errno ) );            return -1;        }        do_pwd( ".", cpCurr );        strcat( cpCurr, caName );    }    strcat( cpCurr, "/" );    return 0;}

其执行结果如下:

运行结果和系统的工具比较,不太让人满意。因为每个文件系统是一棵完整的树,而我的代码目录所处的文件系统被挂载在/home目录下,所以到达jliu这级目录时,已经到达了文件系统的根,其".",".."inode号是相同的。

3.如何打破文件系统的限制,形成完整的绝对路径?

思路一:

查看系统所有的挂载路径,将所有挂载路径和上面求得的路径拼接起来,如果是合法路径且inode号与最初目录的inode号相同,即是想要的最终的路径。

intdo_pwd_fix( const char *ccpPath, char *cpCurr ){    char caFullPath[ 2 * NAMELEN ];    char caMounted[ NAMELEN ];    char caLine[ LINELEN ];    ino_t inoCurr;    int  iRet;    struct stat stBuf;    FILE *fp = NULL;    if( get_inode_from_name( ccpPath, &inoCurr ) == -1 )    {        fprintf( stderr, "[%s:%d]get_inode_from_name() error: %s\n", _FL_, strerror( errno ) );        return -1;    }    /* get the current directory in a file system */    if( do_pwd( ccpPath, cpCurr ) != 0 )    {        fprintf( stderr, "[%s:%d]do_pwd() error: %s\n", _FL_, strerror( errno ) );        return -1;    }    /* the file system is mounted at root */    if( ( iRet = stat( cpCurr, &stBuf ) == 0 ) && stBuf.st_ino == inoCurr )        return 0;    /*    ** find the mouned point of the file system,    ** which not mounted at the root    */    if( ( fp = fopen( "/etc/mtab", "r" ) ) == NULL )    {        fprintf( stderr, "[%s:%d]fopen() error: %s\n", _FL_, strerror( errno ) );        return -1;    }    while( fgets( caLine, LINELEN, fp ) != NULL )    {        memset( caMounted, 0, sizeof( caMounted ) );        memset( caFullPath, 0, sizeof( caFullPath ) );        sscanf( caLine, "%*s%s", caMounted );        /*        ** the items mounted at root have been handled        */        if( strcmp( caMounted, "/" ) == 0 )            continue;        strcpy( caFullPath, caMounted );        strcat( caFullPath, cpCurr );        /*        ** check whether the path is legal        */        if( ( iRet = stat( caFullPath, &stBuf ) != 0 )                && ( errno == ENOENT || errno == EACCES ) )        {            continue;        }        else if( iRet == 0 && stBuf.st_ino != inoCurr )        {            continue;        }        else if( iRet == 0 && stBuf.st_ino == inoCurr )        {            strcpy( cpCurr, caFullPath );            break;        }        else        {            fprintf( stderr, "[%s:%d]stat() error: %s\n", _FL_, strerror( errno ) );            return -1;        }    }    fclose( fp );    return strcmp( cpCurr, caFullPath );}

运行结果如下:

初看起来没什么问题,但是将可执行文件放到/home/dev下去执行,结果如下:

1)问题一:/home目录下执行mypwd,打印出来的是/,显然不正确。

因为/home目录的inode号确实和/目录的inode号相同。

2)问题二:/dev目录下无法正常的工作,即使系统调用没有出错,但是好像代码逻辑有问题。

初步判断是因为stat()出来的st_inode和在父目录readdir()出来的d_ino不同。

 

思路二:

针对上面的两个问题,可以看出单纯使用父目录和当前目录的inode号作为判断依据貌似不太可靠。转换思路比较struct stat的内容,作为判断的依据,memcmp( &stBufCurr, &stBufParent, sizeof( struct stat ) );。这个时候,我放弃使用挂载路径拼接的方式求完整绝对路径的方式。而是让程序不停滴chdir,直到memcmp( &stBufCurr, &stBufParent, sizeof( struct stat ) ) ==0,说明已经到达最终的root

intdo_pwd_fix( const char *ccpPath, char *cpCurr ){    char        caFullPath[ 2 * NAMELEN ];    char        caMounted[ NAMELEN ];    item        *pLink;    struct stat stBufStd;    struct stat stBufCurr;    struct stat stBufParent;    if( stat( ccpPath, &stBufStd) != 0 )    {        fprintf( stderr, "[%s:%d]stat() error: %s\n", _FL_, strerror( errno ) );        return -1;    }    /*    ** get the current directory in a file system    */    if( do_pwd( ccpPath, cpCurr ) != 0 )    {        fprintf( stderr, "[%s:%d]do_pwd() error: %s\n", _FL_, strerror( errno ) );        return -1;    }    /*    ** whether reach the final root    */    if( stat( cpCurr, &stBufCurr ) == 0 && memcmp( &stBufCurr, &stBufStd, sizeof( struct stat ) ) == 0 )    {        /* reach the final root, so respond to me */        return 0;    }    /*    ** haven't reached the final root, go on changing direcotry    ** until memcmp( &stBufCurr, &stBufParent ) == 0    */    if( stat( ".", &stBufCurr ) != 0 )    {        fprintf( stderr, "[%s:%d]stat() error: %s\n", _FL_, strerror( errno ) );        return -1;    }    if( chdir( ".." ) != 0 && stat( ".", &stBufParent ) != 0 )    {        fprintf( stderr, "[%s:%d]chdir() or stat() error: %s\n", _FL_, strerror( errno ) );        return -1;    }    init_link( &pLink );    insert_link( &pLink , "." );    insert_link( &pLink , ".." );    while( memcmp( &stBufCurr, &stBufParent, sizeof( struct stat ) ) != 0 )    {        /* search the directory beyond the file system, stored in caMounted */        if( get_name_from_inode_ext( ".", &stBufStd, caMounted, pLink, cpCurr ) != 0 )        {            fprintf( stderr, "[%s:%d]get_name_from_inode() error: %s\n", _FL_, strerror( errno ) );            clear_link( pLink );            return -1;        }        strcpy( caFullPath, caMounted );        strcat( caFullPath, cpCurr );        strcpy( cpCurr, "/" );        strcat( cpCurr, caFullPath );        memcpy( &stBufCurr, &stBufParent, sizeof( struct stat ) );        if( chdir( ".." ) != 0 && stat( ".", &stBufParent) != 0 )        {            clear_link( pLink );            fprintf( stderr, "[%s:%d]chdir() or stat() error: %s\n", _FL_, strerror( errno ) );            return -1;        }    }    /* reach the final root */    clear_link( pLink );    return 0;}

运行结果如下:

 

4.但是又发现一个新的问题,进入一个符号连接的目录,执行mypwd,其结果如下:

打印出来的是从符号连接指向的实际目录的目录路径,而不是符号连接的目录路径。

暂时没有找到方法解决。

/* TODO */


5.源代码

http://download.csdn.net/detail/qq123386926/9039517


0 0
原创粉丝点击