Unix环境编程-文件和目录

一、打开/关闭文件

1

名称:

open

目标:

打开一个文件。

头文件:

#include <sys/types.h>

#include <sys/stat.h>

#include < fcntl.h>

函数原形:

int open(const char * pathname,int flags);

int open(const char * pathname,int flags,mode_t mode);

参数:

pathname    文件名

    

flags          打开模式

返回值:

-1     遇到错误

    

int    打开成功,返回文件描述符。

 

要打开一个文件必须指定文件名和打开模式种打开模式只读只写可读可写分别对应于O_RDONLY,O_WRONLY,O_RDWR,这在头文件/usr/include/fcntl.h中有定义。

       打开文件是内核提供的服务,如果在打开过程中内核检测到任何错误,这个系统调用就会返回-1。错误的类型是各种各样的,如:要打开的文件不存在。即使文件存在可能因为权限不够而无法打开,在open的联机帮助中列出了各种可能的错误,大家可以看看。

       UNIX允许一个文件被多个进程访问,也就是说当一个文件被一个进程打开后,这个文件还可以被其它进程打开。

      如果文件被顺利打开, 内核会返回一个正整数的值,这个数值就叫文件描述符,文件描述符是是一个简单的整数,用以标明每一个被进程所打开的文件,描述符0代表标准输出,对应的宏是STDOUT_FILENO, 描述符1代表标准输入,对应的宏为STDIN_FILENO,描述符2代表标准错误输出,对应的宏为STDERR_FILENO, 系统给进程分配描述符都是从3开始的,如果同时打开好几个文件,它们所对应的的文件描述符是不同的,如果一个文件打开多次,对应的文件描述符也不相同。必须通过文件描述符对文件操作。下面的程序可以证明这一点。

 

Open 函数的第二个功能是创建一个新文件并把它打开,其中有几个宏定义对于着flags参数:

       O_CREAT      如果打开文件不存在open就创建一个文件。

       O_TRUNC   如果打开的文件已经存在open就把原文件清空,长度置为0

所有我们利用openpathname, O_WRONLY| O_CREAT| O_TRUNC,0777;

       下面是一个例子

/*1_2.c*/

#include <unistd.h>

#include <sys/stat.h>

#include <sys/fcntl.h>

#include <stdio.h>

 

char buf[]=”abcdefg”;

int main(int argc,char *argv[ ])

{

    int  fd;

    if((fd=open(argv[1],O_RDWR|O_CREAT|O_TRUNC,0777))==-1)

        perror (“error”);

if(write(fd,buf,7)!=7)

    perror(“error”);

if(read(fd,buf,sizeof(buf))<0)

    perror (“error”);

printf(“%s\n”,buf);:

}

 

2

名称:

close

目标:

关闭一个文件。

头文件:

#include < unistd.h>

函数原形:

int close(int fd)

参数:

fd    文件描述符

返回值:

-1     遇到错误

    

int    关闭成功,返回文件描述符。

       Close这个系统调用会关闭进程和文件fd之间的连接,如果关闭过程中出现错误,close返回-1,如:fd所指的文件并不存在。关闭成功则返回文件描述符。

 

3.

名称:

creat

目标:

创建/重写一个文件

头文件:

#include <sys/types.h>

#include <stat.h>

#include < fcntl.h>

函数原形:

int creat(const char *pathname,mode_t mode)

参数:

pathname   文件名

 

mode      访问模式

返回值:

-1         遇到错误

    \

fd         创建成功,返回文件描述符

      

       creat告诉内核创建一个名为filename的文件,如果这个文件不存在,就创建它,如果已经存在,就把它的内容清空,把文件的长度设为0    

       如果内核成功地创建了文件那么文件的许可位permission bits被设置为由第二个参数mode所指定的值.

fd=creat(“addressbook”,0644);

       创建一个名为addressbook的文件如果文件不存在那么文件的许可位被设为 rw-r-r—.

如果文件已存在它的内容会被清空。任一情况下,fd都会是指向addressbook的文件描述符。

 

二、文件的读取和写入

4

名称:

read

目标:

把数据读到缓冲区。

头文件:

#include < unistd.h>

函数原形:

ssize_t read(int fd, void *buf, size_t count)

参数:

fd       文件描述符

 

buf      用来存放数据的目的缓冲区

 

count     要读取的字节数

返回值:

-1       遇到错误

    

numread  成功关闭,返回所读取的字节数目。

 

read这个系统调用请求内核从fd所指定的文件中读取qty字节的数据,存放到buf所指定的内存空间中,内核如果成功地读取了数据,就返回所读取的字节数目。否则返回-1

当文件的字节数没有你想要的那么多时,read就会判断下一个数值是不是’\0’,如果是就停止读取,然后退出。numread返回的是’\0’之前的字节数,也就是是原文件的字节数而不是你想读的字节数。

 

5.

名称:

write

目标:

将内存中的数据写入文件。

头文件:

#include < unistd.h>

函数原形:

size_t write(int fd, const void *buf, size_t count)

参数:

fd       文件描述符

 

buf      内存数据

 

count    要写的字节数

返回值:

-1       遇到错误

    

Num written  成功写入,返回写入的字节数目。

 

在实际的写入过程中,可能会出现写入的字节数少于所要求的。这可能有两个原因,第一是有的系统对文件的最大尺寸有限制,第二是磁盘空间接近满了。在上述两种情况下内核都会尽力把数据往文件中写,并将实际写入的字节数返回,所以调用write后都必须检查返回值是否与要写入的相同,如果不同就要采取相应的措施。

       学完上面几个系统调用,我们就可以自己编写的cp命令了。它的基本思路是从原文件读取数据写入缓冲,再将缓冲的数据写入目标文件。

/*1_3.c*/

#include <stdio.h>

#include <unistd.h>

#include <fcntl.h>

#include <stdlib.h>

 

#define BUFFERSIZE 4096

#define COPYMODE 0644 

 

void oops(char *s1,char *s2);

 

main(int argc,char *argv[])

{

       int in_fd,out_fd,n_chars;

       char buf[BUFFERSIZE];

 

       if(argc!=3)

       {

              fprintf(stderr,”usage:%s source destination\n”,*argv);

              exit(1);

       }

       if((in_fd=open(argv[1],O_RDONLY))==-1)

              oops(“Cannot open”,argv[1]);

       if((out_fd=creat(argv[2], COPYMODE))==-1)

              oops(“Cannot creat”,argv[2]);

       while((n_chars=read(in_fd,buf,BUFFERSIZE))>0)

       {

              if(write(out_fd,buf,n_chars)!=n_chars)

                     oops(“Write error to”,argv[2]);

       }

       if(n_chars==-1)

              opps(“Read error form”,argv[1]);

       if(close(in_fd)==-1||close(out_fd)==-1)

              oops(“Error clising files”);

}

 

void oops(char *s1,char *s2)

{

       fprintf(stderr,”Error:%s”,s1);

       perror(s2);

       exit(1);

}

 

三、文件描述符操作函数

6

名称:

lseek

目标:

使指针指向文件中的指定位置。

头文件:

#include <sys/types.h>

#include <unistd.h>

函数原形:

off_t  lseek(int fildes,off_t offset,int whence)

参数:

fildes    文件描述符

offset    移动的距离

wence   SEEK_SET=>文件的开始

        SEEK_CUR=>当前位子

        SEEK_END=>文件结束

返回值:

-1      遇到错误

Ildpos   指针变化前的位子

      

lseek改变文件描述符所关联的指针的位置,新的位置由offsetwence来指定,wence是基准位置,基准位子可以是文件的开始(0)、当前位子(1)或文件的结束(2)。 offset是从基准位子开始的偏移量。若wenceSEEK_SET,该文件的偏移设置为距文件开始处offset个字节数。若wenceSEEK_CUR,该文件的偏移设置为其当前值加offset, offset可为正或负。若wenceSEEK_END,该文件的偏移设置为文件长度加offset, offset可为正或负。

       lseek(fd,0,SEEK_END);

       文件位偏移量可以大于文件的当前长度,在这种情况下,对该文件的下一次写将延长该文件,并在文件中构成一个空洞,这一点是允许的。位于文件中没有写过的字节都被读为0

下面是一个例子:

/*1_4.c*/

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

#include <stdlib.h>

 

char buf1[]=”abcdefg”;

char buf2[]=”ABCDEFG”;

 

int main(void)

{

int fd;

if((fd=creat(“file.hole”,0644))==-1)

    printf(“creat error”);

if(write(fd,buf1,7)!=7)

    printf (“buf1 write error”);

if(lseek(fd,40,SEEK_SET)==-1)

    printf (“lseek error”);

if(write(fd,buf2,7)!=7)

printf (“buf2 write error”);

exit(0);

}

 

 

7.

名称:

dup/dup2

目标:

复制一个现存的文件描述符.

头文件:

#include <unistd.h>

函数原形:

int dup(int oldfd)

int dup2(int oldfd,int newfd)

参数:

oldfd    原有文件描述符

newfd   新的文件描述符

返回值:

-1      遇到错误

int      新文件描述符

  

系统调用dup是用来复制一个文件描述符,也就是将进程u区的文件描述符表中的一项复制一份,使得这两项同时指向系统稳健表的同一表项。

  系统调用dup复制由参数oldfd指定的文件描述到进程文件描述符表的第一个空表项处。而系统调用dup2复制由参数oldfd指定的文件描述到参数newfd指定的文件描述符表项处。老的文件描述符和新复制的文件描述符可以互换使用。它们共享锁、文件指针和文件状态。例如,对其中一个文件描述符使用系统调用lseek修改文件指针的位置,对另一文件描述符来说文件指针也改变了,其实我们了解了内核的工作原理,这一点很容易理解。因为我们知道,文件指针是放在系统文件表中的。但这两个文件描述符具有不同的close-on-exec标志,因为该标志是存放在文件描述符表中的。

  该调用成功时,返回值为新的描述符;错误时,返回-1,并设置相应的错误代码errno

  • EBADF:参数oldfd不是一个已经打开的文件描述符;或者参数newfd超出允许的文件描述符的取值范围。
  • EMFILE:进程打开的文件描述符数量已经到达最大值,但仍然企图打开新的文件描述符。

  下面我们来看一个简单的例子。在这个例子中,我们将标准输出(文件描述符为1)关闭,并将一个打开了普通文件output”的文件描述符复制到标准输出上,因为刚关闭了文件描述符1,所以,文件描述符表的第一个空表项是1。所以,程序以后的printf等向标准输出写的内容都写到了文件中。

利用这个功能我们可以把输出/输入重定向到文件中。下面是一个例子。

/*1_5.c*/

#include <stdio.h>

#include <unistd.h>

#include <systypes.h>

#include <sys/stat.h>

#include <string.h>

#include <errno.h>

#include <fcntl.h>

 

main(int argc,char *argv[])
{
int fd;
if ((fd=open(argv[1],O_CREAT|O_RDWR,0644))==-1)
printf("cannot open output file ");


close(1); /* 关闭标准输出 */
if(dup(fd)==-1); /* 复制fd到文件描述符1
*/
    perror(
error);

close(fd); /* 即时关闭不用的文件描述符是一个好习惯 */
printf("This line will write to file ");

}

  该程序执行过程的屏幕拷贝:

[wap@wapgw /tmp]$ gcc -o 1_5 1_5.c
[wap@wapgw /tmp]$ ./1_5 test1
[wap@wapgw /tmp]$ more test1
This line will write to file

 

dup2的功能和dup基本相同,只不过是dup2复制oldfdnewfd上。下面是用dup2实现同样的例子。

/*1_6.c*/

#include <stdio.h>

#include <unistd.h>

#include <systypes.h>

#include <sys/stat.h>

#include <string.h>

#include <errno.h>

#include <fcntl.h>

 

main(int argc,char *argv[])

{

int fd;

if((fd=open(argv[1],O_WRONLY|O_CREAT,0644))==-1)

    perror(“error”);

close(1);

if(dup2(fd,1)==-1)

    perror(“error”);

close(fd);

printf(“This line will write to file \n”);

close(fd);

}

 

利用这两个函数我们可以实现管道的功能,有关管道的内容将在后面介绍。

 

8

名称:

fcntl

目标:

改变已经打开文件的性质。

头文件:

#include <unistd.h>

#include <sys/types.h>

#include <fcntl.h>

函数原形:

int fcntl(int fd,int cmd);

int fcntl(int fd,int cmd,long arg);

int fcntl(int fd,int cmd,struct flock *lock);

参数:

fd       文件描述符

cmd     功能描述位

返回值:

-1      遇到错误

V-node

int      依赖于cmd

 

 

fcntl函数有5种功能:

1    复制一个现存的文件描述符(cmd=F_DUPFD

2         获得/设置文件描述符标记(cmd=F_GETFDF_SETFD

3         获得/设置文件状态标志(cmd=F_GETFLF_SETFL

4         获得/设置异步I/O所有权(cmd=F_GETOWN F_SETOWN

5         获得/设置记录锁(cmd=F_GRTLK,F_SETLK或F_SETLKW

 

fcntl的功能之一是重复文件描述字。

fcntl (FileDescriptor, F_DUPFD, 0)等价于Dup(FileDescriptor)

close (New); fcntl(Old, F_DUPFD, New)等价于dup2 (Old,New)

 

fcntl的功能之二获得/设置文件描述符标记。

获得文件描述标记fcntl (FileDescriptor, F_GETFD)

设置文件描述标记fcntl(FileDescriptor, F_SETFD, flags)

 

fcntl的功能之三获得/设置文件状态标签,文件状态标签分为3类它们是文件访问方式、打开时标志和I/O操作方式。

 

 

一、目录的打开和关闭

 

1.

名称:

opendir

目标:

打开一个目录。

头文件:

#include <sys/types.h>

#include < dirent.h>

函数原形:

DIR *opendir(const char *name)

参数:

name      目录名

返回值:

NULL     遇到错误

    

DIR *     打开成功

opendir用于打开一个目录,其功能和open相似。只不过open用于打开一个文件,而opendir用于打开一个目录。如果opendir可以成功打开一个目录,它就返回一个指向目录的指针,我们可以通过opendir的联机帮助知道这些内容。

首先在命令提示符后面键入[root@LINUX root]#man –k opendir来查找和opendir相关的联机帮助。我们可以得到以下内容:

opendir            (3)         -open a directory

这正是我们想要的。

然后我们可以键入[root@LINUX root]#man 3 opendir 来查看opendir[3]的联机帮助。

在帮助文档中我们可以看到这样一段话:

The opendir() function opens a directory stream correspondig to the directory name,and returns a pointer to the directory stream. The stream is positioned at the first entry in the directory.

The opendir() function rerurns a poin to the directory stream or NULL if an error occurred.

这些正是我们要找的信息. 除了这些信息我们还可以从帮助中获取诸如函数头文件,函数功能,函数原形,返回值,出错处理,相关函数等信息。大家试着用同样的方法来学习这些相关函数,达到举一返三的目的。

 

2

名称:

closedir

目标:

关闭一个目录.

头文件:

#include <sys/types.h>

#include < dirent.h>

函数原形:

int closedir(DIR *dir)

参数:

dir       指向目录的指针

返回值:

-1        遇到错误

    

0         打开成功,返回指向目录的指针。

 

二、目录的读取

3

名称:

readdir

目标:

读取目录内容。

头文件:

#include <unistd.h>

#include <lixux/dirent.h>

#include < linux/unistd.h>

函数原形:

int readdir(unsigned int fd ,struct dirent *dirp,unsigned int count)

参数:

fd        文件描述符

dirp       用于存放读入数据的数组

count      

返回值:

-1    遇到错误

    

0     打开成功

 

同样readdir的功能也和read相似,用于读取目录中内容。其实用open,read,close等函数也可以对目录目录操作的,但不是一个好的办法,因为Linux支持多种的目录类型,如AppleHFSISO9600VFAYNFS,如果用read来读,需要了解这些不同类型目录各自的结构细节。

利用这些函数我们可以编写不加参数的ls 命令,下面是代码。

/*2_1.c*/

 

#include < dirent.h>

#include <stdio.h>

#include <sys/types.h>

 

void show_dir(char dirname[]);

 

main(int ac,char *av[])

{

if(ac==1)

    show_dir(“.”);    / *读当前目录*/

else

    while(--ac)      

{

          printf(“%s:\n”,*++av);

          show_dir(*av);    /*读指定目录*/

     }

}

 

void show_dir(char dirname[])

{

DIR *dir_ptr;     /*定义目录类型的指针*/                 

struct dirent *direntp;       /*定义用于读目录的缓冲区*/

 

if((dir_ptr=opendir(dirname))==NULL)

    printf(“Can’t open!”);

else

{

    while((direntp=readdir(dir_ptr))!=NULL)

    printf(“%s\n”,direntp->d_name);

    closedir(dir_ptr);

}

}

 

 

三、目录的创建和删除

4

名称:

mkdir

目标:

创建目录

头文件:

#include < sys/stat.h>

#include <sys/types.h>

函数原形:

int result=mkdir(char *pathname,mode_t mode)

参数:

pathname   新建目录名

mode      权限位的掩码

返回值:

-1        遇到错误

    

0         成功创建

 

 

 

 

 

 

 

 

 

  

 

/*2_2.c*/

 

#include <unistd.h>

#include <sys/types.h>

 

main(int argc,char *argv[])

{

int result;

if(argc!=2)

    printf(“please input a direction.”);

if((result=mkdir(argv[1]))==-1)

    perror(“error”);

}

 

5

名称:

rmdir

目标:

删除一个目录,此目录必须为空

头文件:

#include <unistd.h>

函数原形:

int result=rmdir(const char *path);

参数:

path      目录名

返回值:

-1        遇到错误

    

0         成功删除

 

 

 

 

 

 

 

 

 

四、文件的链接

6

名称:

link

目标:

创建一个文件的新链接

头文件:

#include < unistd.h>

函数原形:

int link(const char *oldpath,const char *newpath);

参数:

oldpath    原始链接名称

newpath   新建链接名称

返回值:

-1        遇到错误

    

0         成功创建

 

 

 

 

 

 

 

 

 

 

 

实例:

/*2_3.c*/

 

#include <unistd.h>

main(int argc,char *argv[])

{

int result;

if(argc!=3)

    printf(“please input two file!”);

if((result=link(argv[1],argv[2]))==-1)

    perror(“error”);

}

 

7

名称:

unlink

目标:

删除一个链接

头文件:

#include <unistd.h>

函数原形:

int unlink(const char *pathname);

参数:

pathname    目录名

返回值:

-1          遇到错误

    

0           成功删除

 

 

 

 

 

 

 

 

 

8

名称:

rename

目标:

重命名或删除一个链接

头文件:

#include < stdio.h>

函数原形:

int rename(const char* foldoath, const char* newpath);

参数:

oldpath    原始连接名称

newpath    新建连接名称

返回值:

-1      遇到错误

    

0       成功返回

 

 

 

 

 

 

 

 

 

 

 

/*2_5.c*/

 

#include <stdio.h>

#include <unistd.h>

 

main(int argc,char *argv[])

{

int result;

 

if(argc!=3)

    printf(“please input two link!”);

if((result=tename(argv[1].argv[2]))==-1)

    perror(“error”);

}

 

9

名称:

symlink

目标:

创建符号连接文件

头文件:

#include <unistd.h>

函数原形:

int symlink(const char *oldpath,const char *newpath);

参数:

oldpath  原文件名

newpath 新连接名

返回值:

-1       遇到错误

    

0        成功返回

下面是例子:

#include <unistd.h>

 

main(int argc,char *argv[])

{

if(symlink(argv[1],argv[2])<0)

    perror(“error”);

}

 

 

10

名称:

chdir/fchdir

目标:

改变所调用进程的当前目录

头文件:

#include < unistd.h>

函数原形:

int chdir(const char *path);

int fchdir(int fd);

参数:

path      要达到的目录

fd        文件描述符

返回值:

-1        遇到错误

    

0         成功改变

 

 

 

 

 

 

 

 

 

 

 

六、文件的属性

11

名称:

stat/fstat/lstat

目标:

得到文件的属性。

头文件:

#include <sys/types.h>

#include <sys/stat.h>

#include <unistd.h>

函数原形:

int stat(const char *file_name,struct stat *buf)

int fstat(int filedes, struct stat *buf)

int lstat(const char *file_name,struct stat *buf)

参数:

file_name    文件名

filedes       文件描述符     

buf         指向buffer的指针

返回值:

-1          遇到错误

    

0          成功返回

 

Stat把文件fname 的信息复制到指针bufp所指的结构中。Stat包括的信息有

st_mode           文件类型和许可权限

st_uid         用户所有者ID

st_gid         所属组ID

st_size        所占字节数

st_nlink       文件链接数

st_mtime      文件最后修改时间

st_atime       文件最后访问时间

st_actime      文件属性最后改变时间

 

下面的程序得到这些属性,并显示它们。

/*2_7.c*/

 

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

 

int main(int ac, char *av[ ])

{

struct stat info;

 

if(ac>1)

    if(stat(av[1],&info)=-1)

    {

        show_stat_info(av[1],&info);

        return 0;

    }

else

    perror(av[1]);

return 1;

}

 

show stat_info(char *fname,struct stat *buf)

{

      printf(“mode : %o\n”,buf->st_mode);     /*显示文件模式字段*/

      printf(“links : %d\n”,buf->st_nlink);      /*显示链接数*/

printf(“user : %d\n”,buf->st_uid);        /*显示用户名ID*/

printf(“group : %d\n”,buf->st_gid);       /*显示组ID*/

printf(“size : %d\n”,buf->st_size);        /*显示文件大小*/

printf(“modtime : %d\n”,buf->st_mtime);  /*显示文件的最后修改时间*/

printf(“name:%s\n”,fname);        /*显示文件名*/

}

 

 

fstat函数类似于stat,但是当命名的文件是一个符号连接时,lstat返回该符号连接的有关信息,而不是由该符号连接引用的文件的信息。

 

编译并运行fileinfo.c

[root@LINUX root]#cc –o fileinfo fileinfo.c

[root@LINUX root]#./fileinfo fileinfo.c

mode:100664

links: 1

user:500

group:120

size:1106

modtime:965158604

name:fileinfo.c

 

这个程序就是ls –l 命令实现代码的一部分,但是会和ls –l的输出有些不同,比如说时间的表示,用户和组ID的表示,文件权限的表示。涉及到了Linux编码的问题,这里不作介绍,大家可以查阅相关质料。

 

七、文件的存取性和权限

12

名称:

access

目标:

确定文件的可存取性

头文件:

#include < unistd.h>

函数原形:

int access(const char *pathname ,int mode);

参数:

pathname  文件名

mode     新的所有权和特殊属性。

返回值:

-1       遇到错误

    

0        成功返回

 

其中,mode是表4-5中所列常数的逐位或运算。

access函数的mode常数有:

R_OK            测试读许可权

W_OK           测试写许可权

X_OK            测试执行许可权

  F_OK           测试文件是否存在

当用open函数打开一个文件时,内核以进程的有效用户ID和有效组ID为基础执行其存取许可权测试。有时,进程也希望按区实际用户ID和实际组ID来测试其存取能力。例如当一个进程使用设置用户ID,或设置组ID特征作为另一个用户(或组)运行时,就可能需要。

access函数是按实际用户ID和实际组ID进行存取许可权测试的。下面是程序例子。

/*2_8.c*/

#include <stdio.h>

#include <fcntl.h>

#include <sys/types.h>

#include <unistd.h>

 

int main(int argc,char *argv[])

{

if(access(argv[1],R_OK)<0)

    printf(“access error for %s\n”,argv[1];

else

    printf(“read access OK\n”);

if(open(argv[1],O_RDONLY)<0)

    printf(“open for reading OK\n”);

else

    printf(“open for reading OK\n”);

 

}

 

 

 

13

名称:

umask

目标:

为进程文件方式创建屏蔽字

头文件:

#include < sys/types.h>

#include <sys/stat.h>

函数原形:

mode_t umask(mode_t cmask);

参数:

cmask

返回值:

以前的文件方式创建屏蔽字

 

umask函数为进程设置文件方式创建屏蔽字,并返回以前的值。其中,参数cmask由下面9个常数逐为与构成。

       S_IRUSR              用户-

       S_IWUSR             用户-

       S_IXUSR              用户-执行

       S_IRGRP              -

       S_IWGRP             -

       S_IXGRP              -执行

       S_IROTH              其他-

       S_IWOTH             其他-

       S_IXOTH              其他-执行

在进程创建一个新文件或新目录时,就一定会使用文件方式创建屏蔽字。

下面是一个例子程序2_9.c创建两个文件,创建第一个时,umask值为0,创建第二个时,umask值禁止所有组和其他存取许可权。若运行此程序可得如下结果,从中可见存取许可权是如何设置的。

/*2_9.c*/

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

 

int main(int argc,char *argv[])

{

umask(0);

if(creat(argv[1],S_IRUST|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)<0)

    perror(“ERROR”);

umask(S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);

if(creat(argv[2],S_IRUST|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)<0)

    perror(“ERROR”);

exit(0);

}

下面是执行:

#gcc –o 2_9 2_9.c

#./2_9 test1 test2

#ls –l test1 test2

-rw-rw-rw-    1 root    root          0  sep 24 22:26 test1

-rw-------     1 root    root           0  sep 24 22:26 test2

我们可以看到第二个文件的组成员和其他人的读写权限被屏蔽了。

 

14

名称:

chmod/fchmod

目标:

修改文件的所有权限和特殊属性。

头文件:

#include < sys/types.h>

#include <sys/stat.h>

函数原形:

int chmod(const char *path,mode_t  mode);

int fchmod(in fildes,mode_t mode);

参数:

path     文件名

mode    新的所有权和特殊属性。

fildes    文件描述符

返回值:

-1       遇到错误

    

0        成功返回

      

chmod函数在指定的文件上进行操作,而fchmod函数则对已打开的文件进行操作。

为了改变一个文件的许可权位,进程的有效用户ID必须等于文件的所有者,或者该进程必须具有超级用户许可权。

程序可以通过系统调用chmod来改变文件的所有权和特殊属性,如:

chmod(“/tmp/myfie”,04764);

chmod(“/tmp/myfie”,S_ISUID|S_IRWXU|S_IRGRP|S_IWGRP|S_IROTH);

上述两条指令的作用相同,第一条是八进制来表示,第二条是用<sys/stat.h>中定义的符号来表示。后者有明显的优点,当系统定义的许可位的值改变时,无需修改程序。

Chmod函数的mode常数如下:

宏表示                  八进制表示           含义

S_ISUID                      04000            执行时设置用户id

S_ISGID                      02000            执行时设置组id

S_ISVTX                     01000            保存正文

 

S_IRWXU                    00700            用户(所有者)读、写和执行

       S_IRUSR              00400            用户(所有者)读

       S_IWUSR             00200            用户(所有者)写

       S_IXUSR              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            其他执行

 

八、文件所有者和组

15

名称:

chown/fchown/lchown

目标:

修改文件所有者和组

头文件:

#include <sys/types.h>

#include < unistd.h>

函数原形:

int chown(const char *path,uid_t owner,gid_t group);

int fchown(int fd,uid_t owner,gid_t group);

int lchown(const char *path,uid_t owner,gid_t group);

参数:

path     文件名

fp       文件描述符

owner    新的文件所有者ID

group    新的组ID

返回值:

-1       遇到错误

    

0        成功返回

chown通过修改文件属性来修改文件所有者和组的ID。例如:

chown(“file1“,20040)

将文件file1的用户ID改为200,组ID改为40

 

 

你可能感兴趣的:(unix)