在Linux中, 用C语言简单实现chmod命令

在Linux中,我们知道chmod这个命令的功能是改变文件的权限。
现在, 用C语言实现这个改变文件权限的功能
要用C语言实现这个功能的核心就是
利用chmod()这个函数及对需要改变的权限的分析



chmod函数原型如下:
#include <sys/types.h>
#include <sys/stat.h>
int chmod(const char *path, mode_t mode)	//第一个形参是要修改权限的文件的文件名, 第二个形参是文件需要写入的权限


首先, chmod命令有2个格式
1)  chmod 777 test.c//数字格式
2) chmod a+x, u+rw test.c //字符格式
因为是2个格式, 所以我们用分别处理它们


首先是"数字格式"
"数字(即777)"是需要写入的权限
因为"数字"是中命令行获取的, 而从命令行获取的信息都是字符串的形式存在的, 所以我们需要将数字(字符串类型), 转换成整型
所以需要用到atoi()函数(atoi()函数功能: 将字符串转换成整型), 执行了mode = atoi("数字")后, mode现在是一个整型了

因为在文件的权限中有3中权限r,(可读) w(可写), x(可执行), 分别对应r = 4, w = 2, x = 1. 
即如果满权限的话就是r+w+x = 7, 无权限的话就是0, 因为文件有3个组, 文件所有者, 组所属, 其他人。 所以最大的权限为777, 最小为000.

因为atoi()函数返回的类型是一个整型数, 即一个十进制
而chmod(const char *path, mode_t mode)中mode需要的数是一个八进制的数

所以我们现在要将mode转换成一个八进制

mode_u = mode / 100;					//文件所有者权限
mode_g = (mode - (mode_u*100))/10;			//所属组权限
mode_o = mode - (mode_u*100) - (mode_g*10)		//其他人权限
mode = (mode_u * 8 * 8) + (mode_g * 8) + mode _o	//转换成八进制

**************************************

 chmod a+x, u+rw test.c//字符格式
首先, 在chmod命令中 +代表添加权限, -代表删除权限, =代表设置权限.
前2个权限很好理解, 但是第3个是什么意思呢, 是这样的
例如 我们有一个文件test.c 它的权限是 rwxrw-rw-
现在我们用chmod u=x test.c 后, 这个文件的权限就变成了--xrw-rw, u=x代表中文件所有者的这个组中, 除了x(可执行)其他权限都被覆盖


对字符格式的分析, 更多的是分析+,--,=这些操作

首先我们要先构造一个架构

即如果是+, 我们应该这么实现, 如果是-, 怎么实现等

case '+'
	{
		添加权限操作
	}
	break;
case '-'
	{
		删除权限操作
	}
	break;
case '='
	{
		设置权限操作
	}
	break;
default:
	出错
 	break;

接下来在填补架构

case '+'
{	
	//添加权限操作
	if(如果u需要被写入权限)
	{

	}
	if(如果g需要被写入权限)
	{

	}
	if(如果o需要被写入权限)
	{

	}
}
	break;
-, = 格式如上

继续填补架构

case '+'
{	
	//添加权限操作
	if(如果u需要被写入权限)
	{
		if(如果写入权限的权限是r)
			;
		if(如果写入权限的权限是w)
			;
		if(如果写入权限的权限是x)
	}
	if(如果g需要被写入权限)
	{
		同上;
	}
	if(如果o需要被写入权限)
	{
		同上;
	}
}
	break;
-, = 格式如上

最终架构就是上面那样的一个模型

首先在分析+,-, =的时候, 先说明一下宏

宏对应的八进制含义

S_IRWXU  00700 权限,代表该文件所有者具有可读、可写及可执行的权限。
S_IRUSR 或S_IREAD,      00400权限, 代表该文件所有者具有可读取的权限。
S_IWUSR 或S_IWRITE,   00200 权限, 代表该文件所有者具有可写入的权限。
S_IXUSR 或S_IEXEC,      00100 权限, 代表该文件所有者具有可执行的权限。
S_IRWXG 00070权限,代表该文件用户组具有可读、可写及可执行的权限。
S_IRGRP 00040 权限,代表该文件用户组具有可读的权限。
S_IWGRP 00020权限,代表该文件用户组具有可写入的权限。
S_IXGRP 00010 权限,代表该文件用户组具有可执行的权限。
S_IRWXO 00007权限,代表其他用户具有可读、可写及可执行的权限。
S_IROTH 00004 权限,代表其他用户具有可读的权限
S_IWOTH 00002权限,代表其他用户具有可写入的权限。
S_IXOTH 00001 权限,代表其他用户具有可执行的权限。


如果是'+'的话

就是添加权限, 例如, 权限是rw-rw-rw-, 现在chmod u+x后, 权限就变成了rwxrw-rw-  文件所有者组多了可执行权限
还有一种情况就是如果是rwxrw-rw-, 现在执行chmod u+x后, 权限还是rwxrw-rw-, 并没有改变。
很明显, 这个添加的权限操作就是如果有这个权限的话, 我们就添加它, 没有的话就不添加它
所以, 这里用一个或运算就可以实现这个效果 原理是0|1 = 1, 1|1 = 1
即mode |= 要写入的权限

‘+’最终框架
		case '+':
			if(u)
			{
				if(r)
					*mode |= S_IRUSR;
				if(w)
					*mode |= S_IWUSR;
				if(x)
					*mode |= S_IXUSR;
			}

			if(g)
			{
				if(r)
					*mode |= S_IRGRP;
				if(w)
					*mode |= S_IWGRP;
				if(x)
					*mode |= S_IXGRP;
			}

			if(o)
			{
				if(r)
					*mode |= S_IROTH;
				if(w)
					*mode |= S_IWOTH;
				if(x)
					*mode |= S_IXOTH;	
			}
			break;

接下来分析'-'.
 '-'是删除权限, 即如果权限是r-xrwxrwx的话, 那么chmod u-x后, 权限就是r--rwxrwx
这里就是屏蔽要删除的权限, 在这里我们可以用与运算+反码实现这种操作
原理是0&任何数=0
这里的思路, 例如现在我要删除u的r权限, 而u的r权限的宏S_IXUSR的八进制是00100, 现在将它取反就变成了677 (不管前2个代表什么), 
在没有chmod u-x之前 权限是r-xrwxrwx 即577
现在我们用577&677

101 111 111
& 110 111 111
____________________
100 111 111  = 477

权限477 翻译后, 权限为r--rwxrwx 很明显u的x权限屏蔽了

‘-’最终框架
		case '-':
			if(u)
			{
				if(r)
					*mode &= ~S_IRUSR;
				if(w)
					*mode &= ~S_IWUSR;
				if(x)
					*mode &= ~S_IXUSR;
			}

			if(g)
			{
				if(r)
					*mode &= ~S_IRGRP;
				if(w)
					*mode &= ~S_IWGRP;
				if(x)
					*mode &= ~S_IXGRP;
			}

			if(o)
			{
				if(r)
					*mode &= ~S_IROTH;
				if(w)
					*mode &= ~S_IWOTH;
				if(x)
					*mode &= ~S_IXOTH;	
			}
			break;

最后分析'='
= 的操作时一个屏蔽权限的过程, 
例如文件test.c的权限是rwxrwxrwx, 执行chmod r=x后, 权限就变成了--xrwxrwx, 即在所有者


的组中rw权限被屏蔽, 而组所属组和其他人组没有发生什么变化
所以这里我们可以将需要覆盖权限的组的rwx全部置0, 其他组不变, 然后在加上需要加入的权



例如在上面的例子中, 我们可以这样做

*mode &= (S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);	//将所有者组中的权限置0

然后加上需要加上的权限, 我们可以用或运算 

*mode |= S_IXUSR;

所以这里的思路就是先将要设置权限的组的所有权限置0, 然后在添加上要设置的权限

‘=’最终框架
		case '=':
			if(u)
			{
				*mode &= (S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
				if(r)
					*mode |= S_IRUSR;
				if(w)
					*mode |= S_IWUSR;
				if(x)
					*mode |= S_IXUSR;
			}

			if(g)
			{
				*mode &= (S_IRUSR|S_IWUSR|S_IXUSR|S_IROTH|S_IWOTH|S_IXOTH);
 				if(r)
					*mode |= S_IRGRP;
				if(w)
					*mode |= S_IWGRP;
				if(x)
					*mode |= S_IXGRP;
			}
			if(o)
			{
				*mode &= (S_IRGRP|S_IWGRP|S_IXGRP|S_IRUSR|S_IWUSR|S_IXUSR);
				if(r)
					*mode |= S_IROTH;
				if(w)
					*mode |= S_IWOTH;
				if(x)
					*mode |= S_IXOTH;
			}
			break;

C语言简单实现chmod的具体代码

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

void get_mode(int u, int g, int o, int r, int w, int x,
		int sign, mode_t *mode)
{
	switch(sign)
	{
		case '+':
			if(u)
			{
				if(r)
					*mode |= S_IRUSR;
				if(w)
					*mode |= S_IWUSR;
				if(x)
					*mode |= S_IXUSR;
			}

			if(g)
			{
				if(r)
					*mode |= S_IRGRP;
				if(w)
					*mode |= S_IWGRP;
				if(x)
					*mode |= S_IXGRP;
			}

			if(o)
			{
				if(r)
					*mode |= S_IROTH;
				if(w)
					*mode |= S_IWOTH;
				if(x)
					*mode |= S_IXOTH;
			}
			break;

    case '-':
            if(u)
			{
				if(r)
					*mode &= ~S_IRUSR;
				if(w)
					*mode &= ~S_IWUSR;
				if(x)
					*mode &= ~S_IXUSR;
			}

			if(g)
			{
				if(r)
					*mode &= ~S_IRGRP;
				if(w)
					*mode &= ~S_IWGRP;
				if(x)
					*mode &= ~S_IXGRP;
			}

			if(o)
			{
				if(r)
					*mode &= ~S_IROTH;
				if(w)
					*mode &= ~S_IWOTH;
				if(x)
					*mode &= ~S_IXOTH;
			}
			break;

		case '=':
			if(u)
			{
				*mode &= (S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
				if(r)
					*mode |= S_IRUSR;
				if(w)
					*mode |= S_IWUSR;
				if(x)
					*mode |= S_IXUSR;
			}

			if(g)
			{
				*mode &= (S_IRUSR|S_IWUSR|S_IXUSR|S_IROTH|S_IWOTH|S_IXOTH);
				if(r)
					*mode |= S_IRGRP;
				if(w)
					*mode |= S_IWGRP;
				if(x)
					*mode |= S_IXGRP;
			}

			if(o)
			{
				*mode &= (S_IRGRP|S_IWGRP|S_IXGRP|S_IRUSR|S_IWUSR|S_IXUSR);

				if(r)
					*mode |= S_IROTH;
				if(w)
					*mode |= S_IWOTH;
				if(x)
					*mode |= S_IXOTH;
			}
			break;

		default:
			printf("sign error\n");
			break;
	}
}
int main(int argc, char *argv[])
{
	int i;
	int k;
	mode_t mode;		//总权限
	int mode_u;		//所有者权限
	int mode_g;		//组所属权限
	int mode_o;		//其他人权限
	int flag_u;		//标记所有者是否需要设置
	int flag_g;		//标记组所属是否需要设置
	int flag_o;		//标记其他人是否需要设置
	int r;
	int w;
	int x;
	int sign;		//标记+, -, =
	struct stat buf;	//lstat();

	//检查命令行是否输入错误
	if(argc < 3)
	{
		printf("%s <mode> <target file>\n", argv[0]);
		exit(0);
	}

	//有可能是多文件一起使用chmod, 所以用循环执行
	for(k = 2; k < argc; k++)
	{
		//区分出是数字格式, 还是字符串格式
		if(argv[1][0] >= '0' && argv[1][0] <= '7')		//数字格式
		{
			mode = (unsigned)atoi(argv[1]);			//字符串转换成无符号整型, mode_t是无符号类型
			if(mode > 777 || mode < 0)			//设置权限出错的话
			{
				printf("mode num error!\n");
				exit(0);
			}

			//转换成八进制
			mode_u = mode / 100;
			mode_g = (mode - (mode_u*100)) / 10;
			mode_o = mode - (mode_u*100) - mode_g*10;
			mode = mode_u*8*8 + mode_g*8 + mode_o;
		}
		else
        {
            i = 0;
            //获取文件本身的权限
            if(lstat(argv[k], &buf) == -1)
            {
                fprintf(stderr, "line %d ", __LINE__);
                perror("lstat");
                exit(1);
            }
            mode = buf.st_mode;
            while(argv[1][i] != '\0')
            {
                r = w = x = 0;
                flag_u = flag_g = flag_o = 0;
                while(argv[1][i] != ',' && argv[1][i] != '\0')
                {
                    if(argv[1][i] == 'u')
                        flag_u = 1;
                    else if(argv[1][i] == 'g')
                        flag_g = 1;
                    else if(argv[1][i] == 'o')
                        flag_o = 1;
                    else if(argv[1][i] == 'a')
                        flag_u = flag_g = flag_o = 1;
                    else if(argv[1][i] == '+')
                        sign = '+';
                    else if(argv[1][i] == '-')
                        sign = '-';
                    else if(argv[1][i] == '=')
                        sign = '=';
                    else if(argv[1][i] == 'r')
                        r = 'r';
                    else if(argv[1][i] == 'w')
                        w = 'w';
                    else if(argv[1][i] == 'x')
                        x = 'x';
                    i++;
                }
                    get_mode(flag_u, flag_g, flag_o, r, w, x, sign, &mode);
                if(argv[1][i] == ',')
                    i++;
            }
		}

		if( chmod(argv[k], mode) == -1)
		{
			perror("chmod error");
			exit(1);
		}

	}
	return 0;
}


代码实现的效果





不是我不想排好版啊, 只是CSDN的排版太烂了


  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值