Updata:8/10
关于文件复制时的权限问题,更完整和详细的解答见实现cp命令(8)。 此文可能有不正确或者不完整的解释,但是希望你继续阅读,找出问题。
Update:8/09
上次给大家将了my_cp之后,一些同学提出关于文件权限的问题,比如不同用户组之间的文件拷贝涉及到的权限问题。之前对my_cp的测试以及整体设计我都只是针对文件所有者而言,因此这个问题还有待于完善。针对权限问题,我觉得可能还有不少BUG,所以今天就反复测试,结果就发现了如下问题。
我们在进行拷贝文件时,当目的文件不存在时会新建这个目的文件,并进行内容拷贝。目的文件的权限为默认的644。参考下面:
gues@huangwei-desktop:~/code/shell_command$ ls -l test.c -rw-rw-r-- 1 gues gues 5327 2010-08-09 10:31 test.c gues@huangwei-desktop:~/code/shell_command$ cp test.c newtest.c gues@huangwei-desktop:~/code/shell_command$ ls -l test.c newtest.c -rw-r--r-- 1 gues gues 5327 2010-08-09 10:45 newtest.c -rw-rw-r-- 1 gues gues 5327 2010-08-09 10:31 test.c
目的文件已经存在时,也会如同上述结果:只拷贝权限,不影响目的文件权限,即保持原目的文件的属性。
那么如何才能拷贝权限?此时就得加入-p选项。目前的my_cp并没有注意到这个问题,只要涉及到拷贝文件,都会将内容和属性一起拷贝。因此我们接下来修改代码:修复my_cp存在的上述漏洞,并且加入-p选项。同时,我们应该稍微修改代码的逻辑判断,为其他选项留条后路。好了,开始吧!
首先在主函数中,我们增加一个对选项-p的判断,注意同时要在声明相应的变量param_p和index_p数组,功能和-r选项相同,具体可参见前文。并且,如果日后要添加其他选项那么直接添加即可。注意,我还增加了一个param全局变量(如果选项不合法,也不碍事),只有命令中含有任何选项,那么它就为真(下面就将用到)。
//check the legality of the options,only -r or -R for(i=1;i<\argc;i++) { if(argv[i][0]=='-') { param=1;//have a option if((!strcmp(argv[i],"-r")||!strcmp(argv[i],"-R"))) { param_r+=1; index_r[i]=i; } else if(!strcmp(argv[i],"-p")) { param_p+=1; index_p[i]=i; } /* *if the command include another option,you can add the similar code in here. *You must also add the variable param_? and index_?[] */ else { printf("my_cp:无效选项: %s\n",argv[i]); exit(1); } } }
对于获得文件操作数个数和源文件个数的代码也要修改。注意这里的param_r或param_p并不一定为1,当存在相应选项时。因为输入多个相同选项,其效果和一个选项是一样的。
//get the number of src file if(param) { num=argc-1;//because of "./my_cp" if(param_r) { num-=param_r; } if(param_p) { num-=param_p; } /*if the command include another option,you can add the similar code in here*/ src_num=num-1;//because of "dest file" } else { //the command doesn't include any option num=argc-1; src_num=num-1; }
另外,当文件数目不合法时,我也对其判断做了优化,具体参见代码。
if(num<2) { if(num==0) { printf("my_cp:缺少了文件操作数\n"); exit(1); } if(num==1) { printf("my_cp:缺少了要操作的目标文件\n"); exit(1); } }
另外在获取目的文件和源文件的时候,也应该相应添加对-p选项的判断。以上修改使得我们增加其他选型的时候会变得更容易,代码可读性更高。
接下来就是修补上述my_cp的bug了。根据上述举例,只有加入了-p选项时,才会将源文件的属性复制给目的文件,因此我们只要将上述文字翻译成代码即可。
//set the dset file's access right when the “-p” existed if(param_p) { if(fchmod(fdwt,buf.st_mode)==-1) { perror("fchmod"); exit(1); } //set file's user id and group id if(fchown(fdwt,buf.st_uid,buf.st_gid)==-1) { perror("fchown"); exit(1); } }
这里还没有完,还记得我们上面讨论分目的文件存在和目的文件不存在两种情况吗?我们还必须修改打开目的文件时open函数的参数。这些参数的的功能:当目的文件不存在时,新建这个文件,文件属性由opne函数第三个参数决定(644);否则,只是清空目的文件中的内容。这些参数刚好满足我们一开始举例后描述的情况。
//open the dest file if((fdwt=open(dest_path,O_CREAT|O_TRUNC|O_RDWR,S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH))==-1) { perror("open"); exit(1); }
OK,这下就可以解决上述漏洞了。