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
- pwd指令的简单实现
- pwd命令的简单实现
- Linux命令简单实现 -- pwd
- pwd的实现
- Linux操作系统的简单指令(pwd、ls、cd、su、whoami、init、which、cat、clear等)
- more指令的简单实现
- cp指令的简单实现
- ac指令的简单实现
- uptime指令的简单实现
- od指令的简单实现
- 简单的ori指令实现
- Linux指令--cd,pwd
- linux指令 -- pwd
- Linux命令的实现 -- ls pwd cd
- pwd和clear 基本功能的实现
- Linux:实现自己的pwd命令
- 【angularjs指令】简单的搜索框实现
- 一个简单的linux命令——pwd
- Android Binder机制分析
- php匿名函数的用法
- 四层和七层负载均衡的区别
- iOS 一个很简单的使用类的代码,和.net很像,很好理解
- 2015年8月学习英语总结-坚持一段时间将成为习惯
- pwd指令的简单实现
- 带头结点的单链表的基本操作
- iOS 一个很简单的使用类的代码,和.net很像,很好理解
- setOnTouchListener与setOnKeyListener
- Redis字符串类型操作
- 不带头结点的单链表的基本操作
- 自定义UISearchBar背景、边框、左侧图标、删除图标、取消按钮
- 96.Unique Binary Search Trees
- Android ActionBar 自定义布局