Linux C 学习之文件操作(二)

接着上一篇博客的讲~

博客先简述一下dup(),dup2(),fcntl().的系统调用(ioctl()就不说了,网络编程后面会提到);

dup()跟dup2()的函数功能差不多,在这里一并介绍了

包含的头文件 : #include<unistd.h>
函数原型 : int dup(int fd);int dup2(int fd1,int fd2);
这两个函数都是为了复制文件描述符,文件描述符是什么意思呢? 在我看来,就是系统自己给文件一个数字编号,通过这个数字,可以找到这个文件,可以理解成门牌号...
dup()函数主要是将一个文件的描述符复制下来,而dup2()是给一个文件增加一个文件描述符。比方说dup(1,2);1这个数字指的是一个文件a.c,调用了dup2()这个函数之后,2这个数字也可以调用a.c这个文件。
下面介绍一下fcntl()函数。
头文件 : #include <sys/types.h>#include <unistd.h> #include <fcntl.h>
函数原型 :1 int fcntl(int fd, int cmd); 
2 int fcntl(int fd, int cmd, long arg); 

3 int fcntl(int fd, int cmd, struct flock *lock);
fcntl()函数有5种作用:
  1. 复制一个已有的文件描述符(cmd = F_DUPFD 或 F_DUPDF_CLOEXEC)
  2. 获取/设置文件描述符标志(cmd = F_GETFD 或 F_SETFD)
  3. 获取/设置文件状态标志(cmd = F_GETFL 或 F_SETFL)
  4. 获取/设置异步I/O所有权(cmd = F_GETOWN 或 F_SET_OWN )
  5. 获取/设置记录锁(cmd = F_GETLK 或 F_SETLK 或 F_SETLKW)
贴一个例子:
<span style="font-size:18px;color:#ff0000;"><strong>#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

void my_err( const char * err_string , int line )
{
	fprintf(stderr, "line : %d ",line );
	perror(err_string);
	exit(1);
}

int main(int argc, char *argv[])
{
	int ret;
	int access_mode;
	int fd;

	if((fd = open( "example" , O_CREAT|O_TRUNC|O_RDWR , S_IRWXU)) == -1 )  {
		my_err("open",__LINE__);
	}

	if((ret = fcntl(fd,F_SETFL , O_APPEND)) < 0 )  {
		my_err("fcntl",__LINE__);
	}

	if((ret = fcntl( fd , F_GETFL , 0))  < 0 )  {
		my_err("fcntl",__LINE__);
	}

	access_mode = ret & O_ACCMODE;
	printf("%d\t",F_GETFL);
	printf("%d\t",F_SETFL);
	printf("%d\t",ret);
	printf("%d\t",access_mode);
	if( access_mode == O_RDONLY ) {
		printf("example access mode : read only~\n");
	}

	if( access_mode == O_WRONLY )  {
		printf("example access mode : write only!\n");
	}

	if( access_mode == O_RDWR )   {
		printf("example access mode : read + write!\n");
	}	

	if( ret & O_APPEND )  {
		printf(" ,append");
	}

	if( ret & O_NONBLOCK )  {
		printf(" ,nonbclock");
	}
		printf("\n%d \t ",O_NONBLOCK);

	if( ret & O_SYNC )  {
		printf("\n%d ",O_SYNC);


	}
		printf("\n%d ",O_SYNC);

	printf("\n");


	return 0;
}</strong></span>

上面的程序中,我们能看到有许多的宏定义,上篇博客博客有提到,大家还可以去/usr/include目录中查看unistd.h文件中查看这些宏定义的值。我们在程序中还能看到有ret&O_ACCMODE,这里O_ACCMODE值为3,ret跟它取“&”操作后,可以取得ret的值的后两位(只能是0 1 2 3 ),刚好O_RDONLY = 0 ,O_WRONLY = 1, O_RDWR = 2.因此就可以得出文件的打开方式到底是什么。
往下看,有if语句中的条件是(ret & O_APPEND),同理,我们得到这些值,进行与运算后,比较得到的值跟O_APPEND进行比较,可以发现,与运算后刚好是模式的值。


再来看看fcntl()函数的另一个功能——加锁功能。
struct flock
{
short int l_type;
short int l_whence;
off_t l_start;
off_t l_len;
pid_t l_pid;
};
l_type 有三种状态:
F_RDLCK 建立一个供读取用的锁定
F_WRLCK 建立一个供写入用的锁定
F_UNLCK 删除之前建立的锁定
l_whence 也有三种方式(跟lseek中的用法一样):
SEEK_SET    以文件开头为锁定的起始位置。
SEEK_CUR 以目前文件读写位置为锁定的起始位置
SEEK_END 以文件结尾为锁定的起始位置。
l_start 表示相对l_whence位置的偏移量,两者一起确定锁定区域的开始位置。
l_len表示锁定区域的长度,若果为0表示从起点(由l_whence和 l_start决定的开始位置)开始直到最大可能偏移量为止。即不管在后面增加多少数据都在锁的范围内。
贴一段代码:
<strong>#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

void my_err(const char * err_string , int line )
{
	fprintf(stderr, "line:%d  " , line) ;
	perror(err_string);
	exit(1);
}

int lock_set( int fd , struct flock * lock )
{
	if( fcntl(fd,F_SETLK,lock) == 0 )  {
		if(lock->l_type == F_RDLCK )  {
			printf("set read lock,pid:%d\n",getpid());
		}
		else if ( lock->l_type == F_WRLCK )  {
			printf("set write lock,pid:%d\n",getpid());
		}
		else if(lock->l_type == F_UNLCK )  {
			printf("release lock,pid:%d\n",getpid());
		}
		else  {
			perror("lock operation fail\n");
			return -1;
		}

		return 0;
	}
}

int lock_test( int fd, struct flock * lock )
{
	if(fcntl( fd , F_GETLK , lock ) == 0 )  {
		if( lock->l_type == F_UNLCK )   {
			printf("lock can be set in fd\n");
			return 0;
		}
		else {
			if( lock->l_type == F_RDLCK )  {
				printf("can't set lock ,read lock has been set by:%d\n",lock->l_pid );
			}
			else if( lock->l_type == F_WRLCK )  {
				printf("can't set lock ,write lock has been set by:%d\n",lock->l_pid );
			}
			return -2;
		}
	}
	else  {
		perror("get incompatible locks fail");
		return -1;
	}
}


int main(int argc, char *argv[])
{
	int fd;
	int ret;
	struct flock lock;
	char read_buf[32];

	if((fd = open("example.c" , O_CREAT | O_TRUNC | O_RDWR , S_IRWXU )) == -1 )  {
		my_err("open",__LINE__);
	}
	if(write(fd,"test lock",10) != 10 )  {
		my_err("write",__LINE__);
	}

	memset (&lock , 0, sizeof(struct flock));
	lock.l_start = SEEK_SET;
	lock.l_whence = 0;
	lock.l_len = 0;

	lock.l_type = F_RDLCK;
	if(lock_test(fd,&lock) == 0)  {
		lock.l_type = F_RDLCK;
		lock_set(fd,&lock);
	}

	lseek( fd, 0 , SEEK_SET );
	if((ret = read(fd, read_buf , 10)) < 0 )  {
		my_err("read",__LINE__) ;
	}

	read_buf[ret] = '\0';
	printf("%s\n",read_buf);

	getchar();

	lock.l_type = F_WRLCK;
	if(lock_test(fd,&lock) == 0 )  {
		lock.l_type = F_WRLCK;
		lock_set(fd,&lock);
	}

	lock.l_type = F_UNLCK;
	if( lock_test(fd,&lock)  == 0 )  {
		lock.l_type = F_UNLCK;
		lock_set(fd,&lock);
	}
	return 0;
}</strong>

现在介绍锁的功能,锁是为了避免多个进程对同一个文件的操作使得文件出错。这个程序测试时候需要打开不同的终端对一个文件操作,这时锁的功能就体现出来了。代码中有memset(&lock,0,sizeof(struct flock));这个是对锁进行初始化操作。要是想锁文件,还有flock函数。以后写程序时候就要先写锁,这样才能避免文件出错。

现在简述一下文件属性的操作,这里面就包含了stat() / fstat() / lstat() , chown() / fchown() / lchown() , truncate() / ftruncate() , utime() , umask() , rename() , unlink() / remove()等函数。

1、获取文件属性:
stat() / fstat() / lstat() 
相关函数:fstat, lstat, chmod, chown, readlink, utime
头文件:#include <sys/stat.h>   #include <unistd.h>
定义函数:int stat(const char * file_name, struct stat *buf);
函数说明:stat()用来将参数file_name 所指的文件状态, 复制到参数buf 所指的结构中。
下面是struct stat 内各参数的说明:
struct stat
{
dev_t   st_dev; //device 文件的设备编号
ino_t   st_ino; //inode 文件的i-node
mode_tst_mode; //protection 文件的类型和存取的权限
nlink_tst_nlink; //number of hard links 连到该文件的硬连接数目, 刚建立的文件值为1.
uid_t st_uid; //user ID of owner 文件所有者的用户识别码
gid_t st_gid; //group ID of owner 文件所有者的组识别码
dev_t st_rdev; //device type 若此文件为装置设备文件, 则为其设备编号
off_tst_size; //total size, in bytes 文件大小, 以字节计算
unsigned longst_blksize; //blocksize for filesystem I/O 文件系统的I/O 缓冲区大小.
unsigned longst_blocks; //number of blocks allocated 占用文件区块的个数, 每一区块大小为512 个字节.
time_t st_atime; //time of lastaccess 文件最近一次被存取或被执行的时间, 一般只有在用mknod、utime、read、write 与tructate 时改变.
time_t st_mtime; //time of last modification 文件最后一次被修改的时间, 一般只有在用mknod、utime 和write 时才会改变
time_t st_ctime; //time of last change i-node 最近一次被更改的时间, 此参数会在文件所有者、组、权限被更改时更新
};

先前所描述的st_mode 则定义了下列数种情况:
1、S_IFMT 0170000 文件类型的位遮罩
2、S_IFSOCK 0140000 scoket
3、S_IFLNK 0120000 符号连接
4、S_IFREG 0100000 一般文件
5、S_IFBLK 0060000 区块装置
6、S_IFDIR 0040000 目录
7、S_IFCHR 0020000 字符装置
8、S_IFIFO 0010000 先进先出
9、S_ISUID 04000 文件的 (set user-id on execution)位
10、S_ISGID 02000 文件的 (set group-id on execution)位
11、S_ISVTX 01000 文件的sticky 位
12、S_IRUSR (S_IREAD) 00400 文件所有者具可读取权限
13、S_IWUSR (S_IWRITE)00200 文件所有者具可写入权限
14、S_IXUSR (S_IEXEC) 00100 文件所有者具可执行权限
15、S_IRGRP 00040 用户组具可读取权限
16、S_IWGRP 00020 用户组具可写入权限
17、S_IXGRP 00010 用户组具可执行权限
18、S_IROTH 00004 其他用户具可读取权限
19、S_IWOTH 00002 其他用户具可写入权限
20、S_IXOTH 00001 其他用户具可执行权限上述的文件类型在 POSIX 中定义了检查这些类型的宏定义
21、S_ISLNK (st_mode) 判断是否为符号连接
22、S_ISREG (st_mode) 是否为一般文件
23、S_ISDIR (st_mode) 是否为目录
24、S_ISCHR (st_mode) 是否为字符装置文件
25、S_ISBLK (s3e) 是否为先进先出
26、S_ISSOCK (st_mode) 是否为socket 若一目录具有sticky 位 (S_ISVTX), 则表示在此目录下的文件只能被该文件所有者、此目录所有者或root 来删除或改名.


返回值:执行成功则返回0,失败返回-1,错误代码存于errno。


错误代码:
1、ENOENT 参数file_name 指定的文件不存在
2、ENOTDIR 路径中的目录存在但却非真正的目录
3、ELOOP 欲打开的文件有过多符号连接问题, 上限为16 符号连接
4、EFAULT 参数buf 为无效指针, 指向无法存在的内存空间
5、EACCESS 存取文件时被拒绝
6、ENOMEM 核心内存不足
7、ENAMETOOLONG 参数file_name 的路径名称太长
fstat() / lstat()跟stat()类似,函数原型如下:
 int lstat(const char *path, struct stat *buf) ; int fstat(int fildes,struct stat *buf);

2、设置文件属性 :
chown() / fchown() / lchown()
包含头文件:
#include <unistd.h> 
函数原型:
int chown (const char *filename, uid t owner, gid t group);
int fchown(int filedes,uid_t owner,gid_t growp);
int lchown(const char* pathname,uid_t owner,gid_t group); 
chown会将参数指定的文件所有者id变更为owner代表的用户组id,而将该文件所有者的组id变更为参数group组id。fchown跟chown类似,不同是以文件描述符作为参数。lchown在某个文件是符号连接文件的情况下,更改链接本身所有者id,而不是该符号链接所指向的文件。
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

int main(int argc, char *argv[])
{
	struct stat buf;
	if( argc != 2 )  {
		printf("usage : my_stat <filename>\n");
		exit(0);
	}
	if( stat(argv[1],&buf)  == -1)  {
		perror("stat:");
		exit(1);
	}

	chown(argv[1],1000,1000);

	return 0;
}

3、用于改变文件的大小:
truncate() / ftruncate() 
表头文件:#include <unistd.h>
函数原型 :int truncate(const char *path, off_t length); 
int ftruncate(int fd,off_t length);
path:指定的文件  length:改变的文件大小

4、用于改变任何文件的st_mtime域和st_ctime域
utime() 
头文件:
#include<sys/types.h>
#include<utime.h>
函数原型:
int utime(const char * filename,struct utimbuf * buf);
filename是指定的文件 ,将指定文件存取时间改为第二个参数buf的actime域。
第二个参数的定义:
struct utimbuf{
time_t actime;
time_t modtime;
};


5、用于设置文件创建时使用的屏蔽字
umask() 
头文件: #include <sys/stat.h>
函数原型: mode_t umask(mode_t cmask);

     函数用来修改进程的umask,参数umask可以取值,也可以取open系统调用的第三个参数mode的宏;
    
     贴一段代码:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{
umask(0);
if(creat("example2",S_IRWXU | S_IRWXG |S_IRWXO) < 0 ) {
perror("creat");
exit(0);
}

umask(S_IRWXO);
if(creat("example1",S_IRWXU | S_IRWXG | S_IRWXO) < 0) {
perror("creat:");
exit(1);
}

return 0;
}

第一个umask函数没有屏避任何的权限,第二个umask屏蔽了S_IRWXO这个其他用户的读,写,执行权限。


6、修改文件名或者文件的位置
      rename()
头文件: #include <stdio.h>
函数 原型 :int rename(const char *oldname, const char *newname);

     rename会将参数oldname所指定的文件名改为newname所指定的文件名,若newname所指定的文件存在,则原文件会被删除。

      贴一段代码:

    
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
if( argc < 3 ) {
printf("my_mv <old file> <new file>");
exit(0);
}

if ( rename(argv[1],argv[2]) < 0 ) {
perror("rename");
exit(1);
}

return EXIT_SUCCESS;
}


     7、文件删除
     unlink()
    
     头文件 : #include<stdio.h>
                      #include<unistd.h>
     函数原型:int unlink(const char * pathname);
                       
     unlink调用从文件系统中删除一个文件,如果文件的链接数为0且没有进程打开,则文件删除文件占用的磁盘空间被释放,但要是有进程打开这个文件,等进程结束后删除。如果pathname指向一个符号连接文件,则链接被删除。

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

void my_err( const char * err_string , int line )
{
fprintf(stderr , "line :%d" , __LINE__);
perror(err_string);
exit(0);
}


int main(int argc, char *argv[])
{
int fd;
char buf[32];
if((fd = open(argv[1] , O_CREAT | O_RDWR | O_TRUNC , S_IRWXU)) < 0 ) {
my_err("open",__LINE__);
}

if(unlink(argv[1]) < 0 ) {
my_err("unlink" , __LINE__);
}
printf("file unlinked\n");

if((lseek(fd,0,SEEK_SET)) == -1 ) {
my_err("lseek",__LINE__);
}

if(read(fd,buf,5) < 0 ) {
my_err("read",__LINE__);
}
printf("%s\n",buf);
return EXIT_SUCCESS;
}


下来是对目录的操作
    
1、目录的创建
    mkdir();

    头文件:#include<sys/star.h> 
                   #include<sys/types.h>
    函数原型:int mkdir(const char * pathname ,mode_t   mode)

     mkdir创建一个新的空目录,空目录会自动创建"."".."目录项。

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

int main(int argc, char *argv[])
{
if( argc < 2 ) {
printf("my_mkdir <directory name>\n");
exit(0);
}
mkdir( argv[1] , S_IRWXU | S_IRWXG | S_IRWXO );

return EXIT_SUCCESS;
}

2、目录的删除
     rmdir()

    头文件:#include<unistd.h>
    函数原型:int rmdir(const char * pathname)

    pathname是要删除的文件名。比较简单就不贴代码了。

  3、获取当前目录
   getcwd(),getwd().
    头文件 :#include <unistd.h>
    函数原型:char *getcwd(char *buf, size_t size);
                       char *getwd(char * buf);

    getcwd会将当前的工作目录的绝对路径复制到参数buf所指的内存空间,参数size为buf的空间大小,所以要求buf所指的空间要足够大。getwd用法类似,但是会报警告,因为有越界的可能。代码比较简单,就不贴出来了。

4、设置工作的目录
    chdir();
   
    头文件:#include<unistd.h>
    函数原型:int chdir(const char * path) ;    int fchdir(int fd);

    chdir用来将当前工作的目录改为由参数path指定的目录。而fchdir是改成由文件描述符指定的目录。贴一个代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <unistd.h>

void my_err(const char * err_string , int line )
{
fprintf(stderr,"line : %s\n", line );
perror(err_string);
exit(0);
}


int main(int argc, char *argv[])
{
char buf[PATH_MAX + 1] ;

if( argc < 2 ) {
printf("my_cd <target path>\n");
exit(1);
}

if(chdir( argv[1]) < 0 ) {
my_err("chdir",__LINE__);
}

system("touch 2");

if(getcwd(buf,512) < 0 ) {
my_err("getcwd",__LINE__);
}

printf("%s\n",buf);

return EXIT_SUCCESS;
}

5、获取目录信息
    opendir(),readdir(),closedir();
   
    头文件:#include <sys.types.h>
                   #include <dirent.h>
    函数原型:DIR *opendir(const char * name);
                       struct dirent *readdir(const char * name);
                       int closedir(DIR *dir);

     opendir是用来打开参数name所指定的目录,readdir是用来从参数dir所指向的目录中读出信息,返回一个struct dirent 结构的指针。
         
struct dirent
{
long d_ino; /* inode number 索引节点号 */
off_t d_off; /* offset to this dirent 在目录文件中的偏移 */
unsigned short d_reclen; /* length of this d_name 文件名长 */
unsigned char d_type; /* the type of d_name 文件类型 */
char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名,最长256字符 */
}

    closedir是用来关闭dir所指向的目录。


     用到这篇博客所写到的东西,可以简单实现一个ls命令,代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <dirent.h>
#include <time.h>
#include <errno.h>
#include <grp.h>
#include <pwd.h>
#include <unistd.h>

#define MAX_LINE 50

void my_err( const char * err_string , int line )
{
fprintf( stderr , "line :%d" , line );
perror("err_string");
exit(0);
}

void ls_a( char *argv )
{
DIR * dir;
struct dirent *ptr,*ptr1;
struct stat buf;
int sure_len = 0 , i , j , m, n, MAX_FILE_NAME = 0,LAST_LETTER,NUMBER_OF_FILE = 0;
//测试文件夹里面文件的个数,以及最长文件名字的长度
if(( dir = opendir(argv)) == NULL ) {
perror("opendir");
exit(0);
}
while((ptr1 = readdir(dir)) != NULL ) {
if( MAX_FILE_NAME < strlen(ptr1->d_name)) {
MAX_FILE_NAME = strlen(ptr1->d_name);
}
NUMBER_OF_FILE++;
}
closedir(dir);



char FILE_NAME[NUMBER_OF_FILE][MAX_FILE_NAME+1],FILE[MAX_FILE_NAME+1];//定义二维字符数组,写入所有文件的名字

//将文件名字写入数组中
if(( dir = opendir(argv)) == NULL ) {
perror("opendir");
exit(0);
}


i = 0;
while(( ptr = readdir(dir)) != NULL ) {
strcpy(FILE_NAME[i],ptr->d_name);
i++;
}
closedir(dir);

for( m = 0 ; m < NUMBER_OF_FILE ; m++ )
for( n = 0 ; n < NUMBER_OF_FILE-1 ; n++ )
if( strcmp(FILE_NAME[n] , FILE_NAME[n+1]) > 0 ) {
strcpy(FILE , FILE_NAME[n]);
strcpy(FILE_NAME[n],FILE_NAME[n+1]);
strcpy(FILE_NAME[n+1],FILE);
}
j = 0;
while( j < i ) {
m = 0;
sure_len += strlen(FILE_NAME[j]);
if( sure_len >= MAX_LINE ) {
printf("\n");
sure_len = 0;
}
printf("%s",FILE_NAME[j] );
while( m < (MAX_FILE_NAME - strlen(FILE_NAME[j])) ) {
printf(" ");
m++;
}
printf(" ");
j++;
}	
printf("\n\n\n");
}


void ls( char *argv )
{
DIR * dir;
struct dirent *ptr,*ptr1;
struct stat buf;
int sure_len = 0 , i , j , m, n, MAX_FILE_NAME = 0,LAST_LETTER,NUMBER_OF_FILE = 0;
//测试文件夹里面文件的个数,以及最长文件名字的长度
if(( dir = opendir(argv)) == NULL ) {
perror("opendir");
exit(0);
}
while((ptr1 = readdir(dir)) != NULL ) {
if( MAX_FILE_NAME < strlen(ptr1->d_name)) {
MAX_FILE_NAME = strlen(ptr1->d_name);
}
NUMBER_OF_FILE++;
}
closedir(dir);



char FILE_NAME[NUMBER_OF_FILE][MAX_FILE_NAME+1],FILE[MAX_FILE_NAME+1];//定义二维字符数组,写入所有文件的名字

//将文件名字写入数组中
if(( dir = opendir(argv)) == NULL ) {
perror("opendir");
exit(0);
}


i = 0;
while(( ptr = readdir(dir)) != NULL ) {
strcpy(FILE_NAME[i],ptr->d_name);
i++;
}
closedir(dir);

for( m = 0 ; m < NUMBER_OF_FILE ; m++ )
for( n = 0 ; n < NUMBER_OF_FILE-1 ; n++ )
if( strcmp(FILE_NAME[n] , FILE_NAME[n+1]) > 0 ) {
strcpy(FILE , FILE_NAME[n]);
strcpy(FILE_NAME[n],FILE_NAME[n+1]);
strcpy(FILE_NAME[n+1],FILE);
}
j = 0;
while( j < i ) {
m = 0;

if(FILE_NAME[j][0] == '.') {
j++;
continue;
}
sure_len += strlen(FILE_NAME[j]);
if( sure_len >= MAX_LINE ) {
printf("\n");
sure_len = 0;
}
printf("%s",FILE_NAME[j] );
while( m < (MAX_FILE_NAME - strlen(FILE_NAME[j])) ) {
printf(" ");
m++;
}
printf(" ");
j++;
}	

printf("\n");
}


void ls_l(char *argv)
{
DIR * dir;
struct dirent *ptr;
struct passwd * psd;
struct group * grp;
struct stat buf;
char buf_time[32];

if(((dir = opendir(argv)) == NULL) ) {
perror("opendir");
exit(0);
}

chdir(argv);
while((ptr = readdir(dir)) != NULL ) {
stat(ptr->d_name,&buf);
//打印文件类型
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_IWUSR ) {
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(" ");
psd = getpwuid(buf.st_uid);
grp = getgrgid(buf.st_gid);
printf("%-d ",buf.st_nlink);
printf("%-6s ",psd->pw_name);
printf("%-6s ",grp->gr_name);
printf("%-6ld ",buf.st_size);
strcpy(buf_time,ctime(&buf.st_mtime));
buf_time[strlen(buf_time) - 1] = '\0';
printf("%s ",buf_time);
printf("%s ",ptr->d_name);
printf("\n");

}
closedir(dir);


}

int ls_r(char * argv)
{
DIR * dir;
struct dirent *ptr, *ptr1;
struct stat buf;

ls(argv);
if((dir = opendir(argv)) == NULL ) {
perror("opendir");
exit(1);
}
chdir(argv);
while((ptr1 = readdir(dir)) != NULL ) {
lstat(ptr1->d_name,&buf);
if(S_ISDIR(buf.st_mode)) {
if( strcmp(ptr1->d_name,".") == 0 || strcmp(ptr1->d_name,"..") == 0) {
continue;
}
if(ptr1->d_name[0] != '.') {
printf("\n%s:\n",ptr1->d_name);
ls_r(ptr1->d_name);
printf("\n\n");
}
}
}
closedir(dir);
chdir("..");
return 0;
}

int main(int argc, char * argv[])
{
char add_directory[100];
int flag; //flag确定进入哪个函数 0:ls 1:ls -a 2:ls -l 3:ls -R
getcwd(add_directory,100);

if( argc == 1 ) {
flag = 0;

}
else if( 2 == argc ) {
if( argv[1][0] == '-') {
if( argv[1][1] == 'a' ) {
flag = 1;
}
else if( argv[1][1] == 'l' ) {
flag = 2;
}
else if( argv[1][1] == 'R' ) {
flag = 3;
}
else {
printf("my_ls <options> -a -l -R");
}
}
}
else if( 3 == argc ) {
if( argv[1][1] == 'a' ) {
flag = 4;
}
else if( argv[1][1] == 'l' ) {
flag = 5;
}
else if( argv[1][1] == 'R' ) {
flag = 6;
}
else {
printf("my_ls <options> -a -l -R <path>");
}
}
else {
printf("my_ls <options>");
}

switch(flag) {
case 0:ls(add_directory);break;
case 1:ls_a(add_directory);break;
case 2:ls_l(add_directory);break;
case 3:ls_r(add_directory);break;
case 4:ls_a(argv[2]);break;
case 5:ls_l(argv[2]);break;
case 6:ls_r(argv[2]);break;
};

return 0 ;
}

这个代码是自己完成的,看起来比较容易。











  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值