《APUE》Chapter 4 Files and directories (学习笔记加上自己的代码)

时间:2022-09-21 22:50:04

Files and directories

整个第四章都是围绕着三个stat函数展开的

#include <sys/stat.h>
int stat(const char *restrict pathname, struct stat *restrict buf);
int fstat(int filedes, struct stat *buf);
int lstat(const char *restrict pathname, struct stat *restrict buf);


个人感觉三个函数的作用都是近似的,只是parameter有点不一样而已
对于给定的pathname,stat函数将返回关于文件的stat结构体的信息

而fstat函数和lstat有点不一样。

首先是参数:

fstat的结构体指针是struct stat * buf  而lstat的是struct stat * restrict buf

You see it。 restrict 这个关键字是C99新增加的。


In the C programming language, as of the C99 standardrestrict is a keyword that can be used in pointer declarations. The restrict keyword is a declaration of intent given by the programmer to the compiler. It says that for the lifetime of the pointer, only it or a value directly derived from it (such as pointer + 1) will be used to access the object to which it points. This limits the effects of pointer aliasing, aiding optimizations.

--wikipedia


restrict是C99新增的关键字,作用于指针,几乎是用于编译器的优化作用,其实我觉得没什么大的作用吧。。。C已经很快了

In the above code, the pointers ptrAptrB, and val might refer to the same memory location, so the compiler may generate less optimal code :

load R1 ← *val ; Load the value of val pointer
load R2 ← *ptrA ; Load the value of ptrA pointer
add R2 += R1 ; Perform Addition
set R2 → *ptrA ; Update the value of ptrA pointer
; Similarly for ptrB, note that val is loaded twice,
; because ptrA may be equal to val.
load R1 ← *val
load R2 ← *ptrB
add R2 += R1
set R2 → *ptrB

However if the restrict keyword is used and the above function is declared as :

void updatePtrs(size_t *restrict ptrA, size_t *restrict ptrB, size_t *restrict val);

then the compiler is allowed to assume that ptrAptrB, and val point to different locations and updating one pointer will not affect the other pointers. The programmer, not the compiler, is responsible for ensuring that the pointers do not point to identical locations.

Now the compiler can generate better code as follows:

load R1 ← *val
load R2 ← *ptrA
add R2 += R1
set R2 → *ptrA
; Note that val is not reloaded,
; because the compiler knows it is unchanged
load R2 ← *ptrB
add R2 += R1
set R2 → *ptrB
这样防止reload有点多此一举。C很快了。。。


fstat的第一个参数是file descriptor而lstat的参数是一个指向路径的const指针


此外,fstat和lstat的不同之初还在于,fstat函数获得关于filedes的信息,而如果pathname指向一个symbol link,那么就返回关于这个symbol link的信息,而不是symbol link指向的文件。


fstat test code:

#include "apue.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdio.h"

int main()
{
	struct stat buf;
 
	int file_descriptor = 0;

	if((file_descriptor = open("./test.txt",O_RDWR)) < 0)
	{
		printf("open error\n");
	}
	
	if(fstat(file_descriptor,&buf) < 0)
	{
		printf("fstat error\n");
	}
	
	printf("The file mode     is : %ld\n",buf.st_mode);
	printf("The i-node number is : %ld\n",buf.st_ino);
	printf("The device number is : %ld\n",buf.st_dev);
	printf("The device number for special files is : %d\n",buf.st_rdev);
	printf("The number of links   is : %ld\n",buf.st_nlink);
	printf("The user ID of owner  is : %ld\n",buf.st_uid);
	printf("The group ID of owner is : %ld\n",buf.st_gid);
	printf("The size in bytes  for regular files is : %ld\n",buf.st_size);
	printf("The best I/O size is : %ld\n",buf.st_blksize);
	printf("The number of disk blocks allocated is : %ld\n",buf.st_blocks);
	
	return 0;
}

lstat test code:

/*********************************************************************
code writer : EOF
code date : 2014.03.21

	The lstat function is similar to stat, but when the named file
is a symbolic link, lstat returns information about the symbolic
link, not the file referenced by symbolic link.

***********************************************************************/
#include "apue.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdio.h"

int main()
{
	struct stat buf;
 
	if(lstat("./test.txt",&buf) < 0)
	{
		printf("lstat error\n");
	}
	
	printf("The file mode     is : %d\n",buf.st_mode);
	printf("The i-node number is : %ld\n",buf.st_ino);
	printf("The device number is : %ld\n",buf.st_dev);
	printf("The device number for special files is : %ld\n",buf.st_rdev);
	printf("The number of links   is : %ld\n",buf.st_nlink);
	printf("The user ID of owner  is : %d\n",buf.st_uid);
	printf("The group ID of owner is : %d\n",buf.st_gid);
	printf("The size in bytes  for regular files is : %ld\n",buf.st_size);
	printf("The best I/O size is : %ld\n",buf.st_blksize);
	printf("The number of disk blocks allocated is : %ld\n",buf.st_blocks);
	
	return 0;
}

stat test code:

/*******************************************************************************
code writer:liuzijian

date : 2014.01.01

e-mail: jasonleaster@gmail.com
just test what is in the structure -- stat

There would be some warnings during the code is complied,but it doesn't matter.

Just ran the program that you complied is OK!
********************************************************************************/
#include<apue.h>
#include<stdio.h>
int main(int argc,char* argv[])
{
	struct stat buf;
	
	printf("please enter two parameter!\n");
	
	if(argc != 2)
	{
		printf("parameter is wrong!\nplease enter two parameter!\n");
		return 0;
	}
	else
	{
		if(lstat(argv[1],&buf) < 0 )
		{
			printf("lstat is wrong!\n");
		}
		else
		{
			printf("The file mode     is : %ld\n",buf.st_mode);
			printf("The i-node number is : %ld\n",buf.st_ino);
			printf("The device number is : %ld\n",buf.st_dev);
			printf("The device number for special files is : %d\n",buf.st_rdev);
			printf("The number of links   is : %ld\n",buf.st_nlink);
			printf("The user ID of owner  is : %ld\n",buf.st_uid);
			printf("The group ID of owner is : %ld\n",buf.st_gid);
			printf("The size in bytes  for regular files is : %ld\n",buf.st_size);
			printf("The best I/O size is : %ld\n",buf.st_blksize);
			printf("The number of disk blocks allocated is : %ld\n",buf.st_blocks);
		}
	}

	return 0;
}


文件类型:

1.regular file 普通文件。对于Unix来说,没有所谓的data 或者file的区别。

2.Directory file 文件夹。嗯。文件夹也是个文件,这个特殊的文件包含了其他文件的信息。

3.Block special file 块文件。用于缓冲I/O的设备文件。

4.Character special file 字符文件。用于非缓冲I/O的设备文件 

        5.FIFO. 队列。用于进程间的通信

6.Socket. 用于网络进程通信的文件类型。

7.Symbolic link。链接。=_= A type of file that points to another file.


stat 结构体里面储存了很多关于文件的信息。

    struct stat {
      mode_t    st_mode;      /* file type & mode (permissions) */
      ino_t     st_ino;       /* i-node number (serial number) */
      dev_t     st_dev;       /* device number (file system) */
      dev_t     st_rdev;      /* device number for special files */
      nlink_t   st_nlink;     /* number of links */
      uid_t     st_uid;       /* user ID of owner */
      gid_t     st_gid;       /* group ID of owner */
      off_t     st_size;      /* size in bytes, for regular files */
      time_t    st_atime;     /* time of last access */
      time_t    st_mtime;     /* time of last modification */
      time_t    st_ctime;     /* time of last file status change */
      blksize_t st_blksize;   /* best I/O block size */
      blkcnt_t  st_blocks;    /* number of disk blocks allocated */
  };

其中st_mode  这个变量可以用文件类型宏来确认文件类型。

Macro                Type of file
S_ISREG()          regular file
S_ISDIR()            directory file
S_ISCHR()          character special file
S_ISBLK()           block special file
S_ISFIFO()          pipe or FIFO
S_ISLNK()           symbolic link
S_ISSOCK()        socket

test code:

#include"apue.h"
#include"myerr.h"
#include"stdio.h"
int main(int argc,char* argv[])
{
	int i =0;
	struct stat buf;
	char * ptr = NULL;
	for(i = 1;i < argc;i++)
	{
		printf("%s ",argv[i]);
		if(lstat(argv[i],&buf) < 0 )
		{
			err_ret("lstat error");
			continue;
		}
		
		if(S_ISREG(buf.st_mode))
		{
			ptr = "regular";
		}
		else if(S_ISDIR(buf.st_mode))
		{
			ptr = "directory";
		}
		else if(S_ISCHR(buf.st_mode))
		{
			ptr = "character special";
		}
		else if(S_ISBLK(buf.st_mode))
		{
			ptr = "block special";
		}
		else if(S_ISFIFO(buf.st_mode))
		{
			ptr = "fifo";
		}
		else if(S_ISLNK(buf.st_mode))
		{
			ptr = "symbolic link";
		}
		else if(S_ISSOCK(buf.st_mode))
		{
			ptr = "socket";
		}
		else 
		{
			ptr = "** unknown mode **";
		}
		
		printf("%s\n",ptr);			
	}
	return 0;	
}
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ./b.out ./test.txt
./test.txt regular

类Unix里面大多是regular file,其次是directory,其余的百分比不足2.68。。。。



include <sys/stat.h>

这个stat.h 文件我找了半天都没找到。。。用 whereis 命令也没用

其实在这里 

/usr/include/x86_64-linux-gnu/sys/stat.h


文件access权限

st_mode mask  Meaning
S_IRUSR user-read
S_IWUSR user-write
S_IXUSR user-execute
S_IRGRP group-read
S_IWGRP group-write
S_IXGRP group-execute
S_IROTH other-read
S_IWOTH other-write
S_IXOTH other-execute


Note  that  read  permission  for  a  directory  and  execute  permission  for  a  directory
mean different things. Read permission lets us read the directory,obtaining a list of
all the filenames in  the directory .Execute  permission  lets  us  pass  through  the
directory  when  it  is  a  component  of  a  pathname  that  we  aretrying  to  access. (We
need to search the directory to look for a specific filename.)


特别要注意到,对于文件夹的权限问题。文件夹的可读和可执行完全是两码事。

对某个文件夹具有可执行的权限(x),表示可以进入这个这个这个文件夹

而对某个文件夹具有可读的权限,表示可以读取这个文件夹里所有文件的名字


•The  read  permission  for  a  file  determines  whether  we  can  open  an  existing  file  for
re ading: the O_RDONLY and O_RDWR flags for theopen function.

•The write permission for a file determines whether we can open an existing file for
writing: theO_WRONLY and O_RDWR flags for theopen function.

•We must  have  write  permission  for  a  file  to  specify  the O_TRUNC flag  in  the open
function.// 打开O_TRUNC这个家伙如果原先文件里面有文件内容会被擦出。。。 

•We cannot  create  a  new  file  in  a  directory  unless  we  have  write  permission  and
execute permission in the directory.

•To delete  an  existing  file,  we  need  write  permission  and  execute  permission  in  the
directory  containing  the  file. We  do not  need  read  permission  or  write  permission
for the file itself.

•Execute permission for a file must be on if we want to execute the file using any of
the  seven exec functions. The file also has to be a regular file.


access function:

	#include <unistd.h>
	int access(const char * pathname ,int mode);
	int faccessat(int fd ,const char *pathname ,int mode,int flag); //这个是第三版的APUE加上去的。。。


Both return: 0 if OK, −1 on error


mode Description
R_OK test for read permission
W_OK test for write permission
X_OK test for execute permission


#include<apue.h>
#include<fcntl.h>
#include<myerr.h>
int main(int argc ,char* argv[])
{
        int file_descriptor = 0;

        if(argc != 2)
        {
                err_quit("usage : a.out <pathname>");
        }

        if(access(argv[1],R_OK) < 0)
        {
                err_ret("access error for %s",argv[1]);
        }
        else
        {
                printf("read access OK\n");
        }

        if(file_descriptor = open(argv[1],O_RDONLY) < 0)
        {
                err_ret("open error for %s",argv[1]);
        }
        else
        {
                printf("open for reading OK\n");
        }

        close(file_descriptor);

        return 0;
}


root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ./c.out ./test.txt
read access OK
open for reading OK


之初创建Ad_Pro_in_Unix这个文件夹的时候就用的root权限,所以之后也一直没改,写的时候就用的root了,坏习惯,大家表和我一样。。。等APUE完了俺再也不轻易用root了。。。TT。保持良好的习惯


umask  function:

#include <sys/stat.h>
mode_t umask(mode_t cmask );
 
Returns: previous file mode creation mask

返回值就这些种:

文件access权限,这里st_mode 是mode_t 类型的变量

st_mode mask  Meaning
S_IRUSR  user-read
S_IWUSR  user-write
S_IXUSR  user-execute
S_IRGRP   group-read
S_IWGRP  group-write
S_IXGRP  group-execute
S_IROTH  other-read
S_IWOTH other-write
S_IXOTH  other-execute


#include"apue.h"
#include"stdio.h"
#include"myerr.h"
#include"fcntl.h"

#define RWRWRW (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)

int main()
{
	umask(0);
	if(creat("foo",RWRWRW) < 0)
	{
		err_sys("creat error for foo");
	}	
	umask(~(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH));
	if(creat("bar",RWRWRW) < 0)
	{
		err_sys("creat error for bar");
	}
	exit(0);
}

If we want to ensure that anyone can read a file, we should set the umask to  0.

Otherwise,  the umask value  that  is  in  effect  when  our  process  is

running can cause permission bits to be turned off.


root@ubuntu:/Ad_Pro_in_Unix/chapter_4# umask
0022
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ./a.out
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ls -l ./bar ./foo
----rw-rw- 1 root root 0  3月 23 01:07 ./bar
-rw-rw-rw- 1 root root 0  3月 23 01:07 ./foo
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# umask
0022

This  shows  us that  changing  the  file  mode  creation  mask  of  a  process  doesn’t  affect  the  mask  of  its
parent (often a shell). 


bash  下面有个chmod 命令

NAME
       chmod - change file mode bits


SYNOPSIS
       chmod [OPTION]... MODE[,MODE]... FILE...
       chmod [OPTION]... OCTAL-MODE FILE...
       chmod [OPTION]... --reference=RFILE FILE...

DESCRIPTION
       This  manual  page  documents the GNU version of chmod.  chmod changes the file mode bits of each given file according to mode, which can be either a symbolic representation of changes to make, or an octal number representing the bit pattern for the new mode bits.


 

类似的,有

chmod and fchmod function:

The chmod, fchmod,and fchmodat functions  allow  us to  change  the  file  access permissions for anexisting file.

#include <sys/stat.h>
int chmod(const char *pathname,mode_tmode);
int fchmod(int fd ,mode_tmode);
int fchmodat(int fd ,const char*pathname ,mode_tmode,int flag);//第三版加上去的...
								All three return: 0 if OK, −1 onerror 



mode                    Description
S_ISUID               set-user-ID onexecution
S_ISGID               set-group-ID onexecution
S_ISVTX              saved-text(sticky bit)
S_IRWXU        read, write, and execute byuser (owner)
S_IRUSR         read by user (owner)
S_IWUSR        write by user (owner)
S_IXUSR         execute by user (owner)

S_IRWXG        read, write, and execute bygroup
S_IRGRP        read by group
S_IWGRP        write by group
S_IXGRP         execute by group
S_IRWXO        read, write, and execute byother (world)
S_IROTH         read by other (world)
S_IWOTH        write by other (world)
S_IXOTH         execute by other (world)

 

#include "apue.h"
#include "myerr.h"
int main()
{
        struct stat statbuf;
 
        if(stat("foo",&statbuf))
        {
                err_sys("stat error forfoo\n");
        }
 
       if(chmod("foo",(statbuf.st_mode & ~S_IXGRP | S_ISGID))< 0)
        {
                err_sys("chmod error forfoo");
        }
 
        if(chmod("bar",S_IRUSR |S_IWUSR | S_IRGRP | S_IROTH) < 0)
        {
                err_sys("chmod error forbar");
        }
 
        return 0;
}


test:

root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ls -l ./bar ./foo
----rw-rw- 1 root root 0  3月 23 01:07 ./bar
-rw-rw-rw- 1 root root 0  3月 23 01:07 ./foo
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ./b.out
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ls -l ./bar ./foo
-rw-r--r-- 1 root root 0  3月 23 01:07 ./bar
-rw-rwSrw- 1 root root 0  3月 23 01:07 ./foo

 

Note that the ls command lists the group-execute permissionas S to signify that the set-group-ID bit is set without the group-executebit being set.

原来木有S的,现在有S了哇。。。(⊙0⊙)

 To  prevent malicious users  from setting  the  sticky  bit  and  adversely affecting  system  performance,
only the superuser can set the sticky bit of a regular file.

 

If the process does not have superuser privileges, then theset-group-ID bit is automatically turned
off.  This prevents a user from creating a set-group-ID file owned by agroup that the user doesn’t belong to

 

Sticky bit:sticky 位(以前的老技术,现在可以不用鸟,有virtual memory)

If it was  set  for  an executable program  file,  then  the  first  time  the program  was  executed,  a  copy  of  the
program’s  text  was  saved  in  the  swap area  when  the  process  terminated. (The text portion  of  a  program  is  the machine  instructions.)  The program  would  then load  into memory  more quickly  the  next time  it  was executed,  because  the  swap area  was handled  as  a  contiguous  file, as  compared  to  the  possibly  random location of  data blocks  in  a  normal  UNIX file  system. The  sticky  bit  was  often set  for  common application programs,  such  as the  text  editor  and  the  passes  of the  C  compiler.

如果一个可执行程序文件的这个位被“激活”,当这个程序第一次执行的时候,当程序结束时,程序的文本副本就会被拷贝到swap里面去。当程序再次被执行的时候,程序就能更快的被载入内存,因为swap是用来把被处理对象当作连续文件来处理的。sticky bit常常被类似于文本编辑器和C编译器之类的程序使用。

 

With today’s newer UNIX systems, most of which  have a  virtual  memory  system  and  a  faster file  system,  the  need  for this technique has disappeared.

 

chown functions:

#include <unistd.h>
int chown(const char *pathname,uid_t owner ,gid_t group);
int fchown(int fd ,uid_t owner,gid_t group);
int fchownat(int fd ,const char*pathname ,uid_t owner ,gid_t group,int flag);
int lchown(const char * pathname,uid_t owner ,gid_t group);
                                                       All four return: 0 if OK,−1 on error


These  four  functions operate  similarly  unless  the  referenced file  is  a  symbolic  link. In that  case,lchown and fchownat (with  the AT_SYMLINK_NOFOLLOW flag  set) change the owners of the symbolic link itself, not the file pointedto by the symbolic link.

书上没有demo,我自己写的时候发现一个问题,fchown的 owner是用户ID。。。我去where调用个函数,找到我想要的用户ID额。。。。God ..=_=| 待解决。。要找到所有存在用户的ID并返回自己想设置的用户的ID。。。

 

 

File size:文件规格

For a regular file, a file size of 0 is allowed. We’ll get anend-of-file indication on the first read of the file.

For a directory ,t he file size is usually a multiple of a number, such as 16 or 512. (为什么是16 或者 512以后会讲)

For  a  symbolic  link,  the  file size  is  the  number  of  bytes  in the  filename. 

 

For example, in the following case, the file size of 7 is thelength of the pathname usr/lib:

          lrwxrwxrwx  1root  7 Sep 25 07:14 lib -> usr/lib


(Note that symbolic links do not contain the normal C null byte at the end ofthe name,
as the length is always specified by st_size.

 

File truncation:文件截断

Emptying  a  file,  which  we  can do  with  the O_TRUNC flag  to open, is a special case of truncation.

#include <unistd.h>
int truncate(const char *pathname,off_t length );
int ftruncate(int fd ,off_t length);
                        Bothreturn: 0 if OK, −1 on error

test code:

#include "apue.h"
#include "fcntl.h"
#include "stdio.h"
#include "unistd.h"
#define BUFFSIZE 1024
 
int main()
{
        int file_descriptor = 0;
        char buffer[BUFFSIZE];
 
        if((file_descriptor =open("./test.txt",O_RDWR)) < 0)
        {
                printf("openerror\n");
        }
 
        memset(buffer,0,BUFFSIZE*sizeof(char));
 
        printf("beforetruncation\n");
        while(read(file_descriptor,buffer,BUFFSIZE-1) > 0)
        {
               if(write(STDIN_FILENO,buffer,BUFFSIZE-1) <=0)
                {
                        printf("writeerror\n");
                }
        }
 
       ftruncate(file_descriptor,sizeof(char)*40);
 
        lseek(file_descriptor,0,SEEK_SET);
 
        memset(buffer,0,BUFFSIZE*sizeof(char));
 
        printf("after truncation\n");
        while(read(file_descriptor,buffer,BUFFSIZE-1) > 0)
        {
               if(write(STDIN_FILENO,buffer,BUFFSIZE-1) <=0)
                {
                        printf("writeerror\n");
                }
        }
 
        close(file_descriptor);
        return 0;
}


test.txt 里面是10行hello world。。。。

root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ./e.out
before truncation
1: hello world!
2: hello world!
3: hello world!
4: hello world!
5: hello world!
6: hello world!
7: hello world!
8: hello world!
9: hello world!
10:hello world!
after truncation
1: hello world!
2: hello world!

 

 unlink function:

 #include <unistd.h>
int unlink(const char * pathname );
int unlinkat(int fd ,const char *pathname ,int flag);
				Both return: 0 if OK, −1 on error


These  functions  remove  the  directory  entry  and  decrement  the  link  count  of  the  file
re ferenced  by pathname .Ifthereare  o ther  links  to  the  file,  the  data  in  the  file  is  still
accessible through the other links. The file is not changed if an error occurs.

test code:

#include "apue.h"
#include "stdio.h"
#include <fcntl.h>
#include "myerr.h"
 
int main()
{
        if(open("./test.txt",O_RDWR)< 0)
        {
                err_sys("openerror");
        }
        if(unlink("./test.txt") <0)
        {
                err_sys("unlinkerror");
        }
        printf("file unlinked");
        sleep(15);
        printf("done\n");
 
        return 0;
}

root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ls -l ./test.txt
-rw-rw-r-- 1 liuzjian liuzjian 40  3月 23 02:19 ./test.txt
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# df ./
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sda1       19478204 5621980  12860128  31% /
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ./b.out &
[1] 6646
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ls -l ./test.txt
ls: cannot access ./test.txt: No such file or directory
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# df ./
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sda1       19478204 5621956  12860152  31% /
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# file unlinkeddone
df ./
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sda1       19478204 5621952  12860156  31% /
[1]+  Done                   ./b.out
 


rename and renameat Functions:

A file or a directory is renamed with either the rename or renameat function.


#include <stdio.h>
int rename(const char * oldname,const char *newname );
int renameat(int oldfd,const char *oldname,int newfd,const char *newname );
				Both return: 0 if OK, −1 on error



test code:

#include "apue.h"
#include "stdio.h"
#include "unistd.h"

int main()
{
        if(rename("./test.txt","./hehe.txt") < 0)
        {
                printf("rename error\n");
        }

        return 0;
}




Symbolic Links:

A symbolic  link  is  an  indirect  pointer  to  a  file,  unlike  the  hard links  described  in  the previous  section,  which  pointed  directly  to  the  i-node  of  the  file. 


Creating and  Reading  Symbolic  Links
A symbolic link is created with either the symlink or symlinkat function.

<span style="font-size:14px;">#include <unistd.h>
int symlink(const char *actualpath,const char *sympath );
int symlinkat(const char *actualpath,int fd ,const char *sympath );
<span style="white-space:pre">				</span>Both return: 0 if OK, −1 on error</span>

test code:

#include "apue.h"
#include "stdio.h"
#include "unistd.h"

int main()
{
        if(symlink("./test.txt","./symbolink_to_test") < 0)
        {
                printf("symlink error\n");
        }

        return 0;
}


test result:

lrwxrwxrwx  1 root     root        10  3月 23 11:34 symbolink_to_test -> ./test.txt

A new  directory  entry, sympath , is created  that  points  to actualpath.

It is not  required that actualpath exist  when  the  symbolic  link  is  created.  (We saw  this  in  the  example  at
the  end  of  the  previous  section.) Also, actualpath and sympath need  not  reside  in  the same file system.

The symlinkat function  is  similar  to symlink,but  the sympath argument  is evaluated  relative  to  the  directory referenced  by  the  open  file  descriptor  for  that directory (specified by the fd argument).  If the sympath argument specifies an absolute pathname  or  if  the fd argument  has  the  special  value AT_FDCWD ,then symlinkat
behaves the same way assymlink.

Because the open function follows a symbolic link, we need a way to open the link itself and read the name in the link. The readlink and readlinkat functions do this.

#include <unistd.h>
ssize_t readlink(const char* restrict pathname ,char *restrict buf,size_t bufsize );
ssize_t readlinkat(int fd ,const char* restrict pathname ,char *restrict buf,size_tbufsize );
Both return: number of bytes read if OK, −1 on error


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

File time:文件时间(都在stat结构体里面的信息,用fstat函数读取即可)

Field  Description Example ls(1) option
st_atim last-access time of file data read  -u
st_mtim last-modification time of file data write default
st_ctim last-change time of i-node status chmod, chown -c


#include "apue.h"
#include "fcntl.h"
#include "myerr.h"
#include "unistd.h"
#include "sys/times.h"
#include "utime.h"

int main(int argc,char* argv[])
{
        int  i,fd;
        struct stat statbuf;
        struct utimbuf timebuf;

        for(i = 1;i<argc ;i++)
        {
                if(stat(argv[i],&statbuf) < 0)
                {
                        err_ret("%s stat error",argv[i]);
                        continue;
                }
                if((fd = open(argv[i],O_RDWR |O_TRUNC)) < 0)
                {
                        err_ret("%s open error");
                        continue;
                }

                close(fd);

                timebuf.actime  = statbuf.st_atime;
                timebuf.modtime = statbuf.st_mtime;

                if(utime(argv[i],&timebuf) < 0)
                {
                        err_ret("%s : utime error",argv[i]);
                        continue;
                }
        }
        return 0;
}




下面是linux里面的stat定义:

<span style="font-size:14px;">struct stat {
        unsigned long   st_dev;         /* Device.  */
        unsigned long   st_ino;         /* File serial number.  */
        unsigned int    st_mode;        /* File mode.  */
        unsigned int    st_nlink;       /* Link count.  */
        unsigned int    st_uid;         /* User ID of the file's owner.  */
        unsigned int    st_gid;         /* Group ID of the file's group. */
        unsigned long st_rdev;        /* Device number, if device.  */
        unsigned long  __pad1;
        long            	st_size;        /* Size of file, in bytes.  */
        int             	st_blksize;     /* Optimal block size for I/O.  */
        int             	__pad2;
        long            	st_blocks;      /* Number 512-byte blocks allocated. */
        long            	st_atime;       /* Time of last access.  */
        unsigned long  st_atime_nsec;
        long            	st_mtime;       /* Time of last modification.  */
        unsigned long  st_mtime_nsec;
        long            	st_ctime;       /* Time of last status change.  */
        unsigned long  st_ctime_nsec;
        unsigned int    __unused4;
        unsigned int    __unused5;
};</span>



mkdir and rmdir function:

Directories  are created  with  the mkdir and mkdirat functions, and deleted with  the rmdir function.

#include <sys/stat.h>
int mkdir(const char *pathname ,mode_tmode);
int mkdirat(intfd ,const char *pathname ,mode_tmode);
				Both return: 0 if OK, −1 on error



These  functions  create  a  new,empty  directory.The  entries  for  dot  and  dot-dot  are  created  automatically .

The  specified  file  access  permissions,mode,are  modified  by  the file mode creation mask of the process.



test code:

#include "apue.h"
#include "stdio.h"


int main()
{
        if(mkdir("./a_dir_made_from_mkdir",S_IRUSR|S_IWUSR|S_IXUSR) < 0)
        {
                printf("mkdir error\n");
        }


        return 0;
}


root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ls
a_dir_made_from_mkdir  c.out              fstat_test.c  lstat_test.c  pro_4_16.c  pro_4_3.c  rename_test.c  truncation_test.c
a.out                  exercise_4_6.c     hehe          mkdir_test.c  pro_4_21.c  pro_4_8.c  show_stat.c    xixi
b.out                  file_permission.c  link_test.c   pro_4_12.c    pro_4_22.c  pro_4_9.c  test.txt


这个时候可以看出,文件夹下面多出了一个a_dir_made_from_mkdir 的文件夹

A common  mistake  is  to  specify  the  same mode as  for  a  file:  read  and  write permissions only.

But for a directory, we normally want at least one of the execute bits enabled, to allow access to filenames within the

directory.

注意给文件夹权限的时候记得不仅仅要给RW还要给可执行(x)的权限


Reading directories: 读取文件信息

#include <dirent.h>
DIR *opendir(const char *pathname );
DIR *fdopendir(int fd );
	Both return: pointer if OK, NULL on error

struct dirent *readdir(DIR * dp);
	eturns: pointer if OK,NULL at end of directory or error

void rewinddir(DIR *dp);
int closedir(DIR * dp);
	Returns: 0 if OK,−1 on error

long telldir(DIR * dp);
Returns: current location in directory associated with dp

void seekdir(DIR * dp,long loc);


demo 来了。。。。:

#include"apue.h"
#include"dirent.h"
#include"limits.h"
#include"myerr.h"
#include "/Ad_Pro_in_Unix/chapter_2/path_alloc.c"


typedef int Myfunc(const char* ,const struct stat *,int);


static Myfunc myfunc;
static int    myftw(char*,Myfunc *);
static int    dopath(Myfunc *);


static long nreg ,ndir ,nblk,nchr,nfifo,nslink,nsock,ntot;


int main(int argc,char* argv[])
{
        int ret;
        if(argc != 2)
        {
                err_quit("usage: ftw <starting-pathname>");
        }


        ret = myftw(argv[1],myfunc);


        ntot = nreg+ndir+nblk+nchr+nfifo+nslink+nsock;
        if(ntot == 0)
        {
                ntot = 1;
        }


        printf("regular files  = %7ld, %5.2f %%\n",nreg,nreg*100.0/ntot);
        printf("directories    = %7ld, %5.2f %%\n",ndir,ndir*100.0/ntot);
        printf("block special  = %7ld, %5.2f %%\n",nblk,nblk*100.0/ntot);
        printf("cha special    = %7ld, %5.2f %%\n",nchr,nchr*100.0/ntot);
        printf("FIFOs          = %7ld, %5.2f %%\n",nfifo,nfifo*100.0/ntot);
        printf("symbolic links = %7ld, %5.2f %%\n",nslink,nslink*100.0/ntot);
        printf("sockets        = %7ld, %5.2f %%\n",nsock,nsock*100.0/ntot);
        exit(ret);
}

#define FTW_F   1
#define FTW_D   2
#define FTW_DNR 3
#define FTW_NS  4


static char *fullpath;
static size_t pathlen;


static int myftw(char *pathname,Myfunc* func)
{
        fullpath = path_alloc(&pathlen);


        if(pathlen <= strlen(pathname))
        {
                pathlen = strlen(pathname)*2;
                if((fullpath = realloc(fullpath,pathlen)) == NULL)
                {
                        err_sys("realloc failed");
                }
        }


        strcpy(fullpath,pathname);
        return(dopath(func));
}


static int dopath(Myfunc* func)
{
        struct stat statbuf;
        struct dirent *dirp;
        DIR *dp;
        char *ptr;
        int ret,n;


        if(lstat(fullpath,&statbuf) < 0)
        {
                return (func(fullpath,&statbuf,FTW_NS));
        }


        if(S_ISDIR(statbuf.st_mode) == 0)
        {
	        return (func(fullpath,&statbuf,FTW_NS));
        }


        if(S_ISDIR(statbuf.st_mode) == 0)
        {
                return (func(fullpath,&statbuf,FTW_F));
        }


        if((ret = func(fullpath,&statbuf,FTW_D)) != 0)
        {
                return (ret);
        }


        n = strlen(fullpath);
        if(n + NAME_MAX +2 >pathlen)
        {
                pathlen*=2;
                if((fullpath = realloc(fullpath,pathlen)) == NULL)
                {
                        err_sys("realloc failed");
                }
        }


        fullpath[n++] = '/';
        fullpath[n] = 0;


        if((dp = opendir(fullpath)) == NULL)
        {
                return(func(fullpath,&statbuf,FTW_DNR));
        }


        while((dirp = readdir(dp)) != NULL)
        {
                if(strcmp(dirp->d_name,".") == 0 || strcmp(dirp->d_name,"..") == 0)
                {
                        continue;
                }
                strcpy(&fullpath[n],dirp->d_name);
                if((ret = dopath(func)) != 0)
                {
                        break;
                }
        }
        fullpath[n-1] = 0;


        if(closedir(dp) < 0)
        {
                err_ret("can't close directory %s",fullpath);
        }
        return (ret);
}


static int myfunc(const char* pathname,const struct stat* statptr,int type)
{
        switch(type)
        {
                case FTW_F:
                {
                        switch(statptr->st_mode & S_IFMT)
                        {
                                case S_IFREG: nreg++; break;
                                case S_IFBLK: nblk++; break;
                                case S_IFCHR: nchr++; break;
                                case S_IFIFO: nfifo++; break;
                                case S_IFLNK: nslink++; break;
                                case S_IFSOCK: nsock++; break;
                                case S_IFDIR: err_dump("for S_IFDIR for %s",pathname);
                        }
                };
                break;
                case FTW_D:
                        ndir++;
                        break;

                case FTW_DNR:
                        err_ret("can't read directory %s",pathname);
                        break;


                case FTW_NS:
                        err_ret("stat error for %s",pathname);
                        break;
                default :
                        err_dump("unknown type %d for pathname %s",type,pathname);
        }
        return 0;
}



chdir fchdir function:

We  can  change  the  current  working  directory  of  the  calling  process  by  calling  the chdir or fchdir function.
#include <unistd.h>
int chdir(const char *pathname );
int fchdir(int fd );
<span style="white-space:pre">		</span>Both return: 0 if OK, −1 on error

demo:

#include "apue.h"
#include "unistd.h"
#include "myerr.h"

int main()
{
        if(chdir("/tmp") < 0)
        {
                err_sys("chdir failed\n");
        }

        printf("chdir to /tmp succeeded\n");

        return 0;
}                                                                                                                           


执行完程序,发现当前目录没有改变,还是程序运行前的目录。事情是这个样子的:

The  current  working  directory  for  the  shell  that  executed  the my cd program  didn’t change.  This is a side effect of the way that the shell executes programs.  Each program is  run  in  a  separate  process,  so  the  current working  directory  of  the  shell  is  unaffected by  the  call  to chdir in  the  program.  For this  reason,  the chdir function  has  to  be called directly from the shell, so the cd command is built into the shells.

 打印当前工作目录:

#include <unistd.h>
char *getcwd(char *buf,size_tsize );
<span style="white-space:pre">		</span>Returns: buf if OK, NULL on error


We  must  pass  to  this  function  the  address  of  a  buffer, buf,and  its size (in  bytes).


#include "apue.h"
#include "stdio.h"
#include "myerr.h"
#include "/Ad_Pro_in_Unix/chapter_2/path_alloc.c"

int main()
{
        char *ptr;
        int size;

        if(chdir("/usr/") < 0)
        {
                err_sys("chdir failed\n");
        }

        ptr = path_alloc(&size);

        if(getcwd(ptr,size) == NULL)
        {
                err_sys("getcwd failed\n");
        }

        printf("pwd = %s\n",ptr);

        return 0;
}


Device special file:设备文件

The major number identifies the  device  driver  and  sometimes  encodes  which  peripheral  board to communicate  with; the  minor  number  identifies  the  specific  subdevice.

Each file system on the same disk drive would usually have the same major number ,but a different minor number.


• The st_dev value  for  every  filename  on  a  system  is  the  device  number  of  the file system containing that filename and its corresponding i-node.
• Only character special files and block special files have an st_rdev value.  This value contains the device number for the actual device.


#include "apue.h"
#include "stdio.h"
#include "myerr.h"

#define _BSD_SOURCE

#include "sys/sysmacros.h"
#include "/usr/include/x86_64-linux-gnu/sys/types.h"

#ifdef SOLARIS
        #include <sys/mkdev.h>
#endif

int main(int argc,char* argv[])
{
        int i;
        struct stat buf;

        for(i = 0;i < argc;i++)
        {
                printf("%s\n",argv[i]);
                if(stat(argv[i],&buf) < 0)
                {
                        err_ret("stat error\n");
                        continue ;
                }

                printf("dev = %d/%d",major(buf.st_dev),minor(buf.st_dev));
                if(S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode))
                {
                        printf("(%s) rdev = %d/%d",(S_ISCHR(buf.st_mode)) ? "character":"block",major(buf.st_rdev),minor(buf.st_rdev));
                }

                printf("\n");
        }

        return 0;
}


root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ./c.out /dev/tty 
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# vim ./pro_4_25.c
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# gcc ./pro_4_25.c -o ./d.out
root@ubuntu:/Ad_Pro_in_Unix/chapter_4# ./d.out /dev/tty
./d.out
dev = 8/1
/dev/tty
dev = 0/5(character) rdev = 5/0

TT。。。。。。。。。。终于summary了。。。。。。第四章太尼玛长了。。。吐槽一下。。。

当然第二次看,总结了还是很舒服。。。

Summary of File  Access  Permission  Bits

《APUE》Chapter 4 Files and directories (学习笔记加上自己的代码)



《APUE》Chapter 4 Files and directories (学习笔记加上自己的代码)