UNIX系统编程(2)

标签: unix 系统 编程 | 发表时间:2013-02-12 21:41 | 作者:DLUTBruceZhang
出处:http://blog.csdn.net


注:本文来自“网易”博主

第三章:文件系统 

这回我们来说一下UNIX的文件系统。由于一般情况下UNIX机的硬盘会很大,所以一般你可以给它分成几个区,而每个分区又都可以有独立的文件系统。如果你是UNIX系统,你有可能看见 
/dev/sd/c0t0d0s0

/dev/sd/c0t0d0s1

这样的文件。 
如果你是linux你有可能看见 
/dev/hda0

/dev/hda1

等等。这些文件,每一个就可以看成是一个分区。当计算机启动时,系统先找到/(根目录),然后系统就像挖土豆子一样找到一个带出来一串似的,顺着根目录一带就带出来挂载在根目录下的所有目录(详细的请查一下/etc/fstab这个文件)。在UNIX下叫目录(directory)的感念,就像是windows下的文件夹(folder),但与windows最大的区别在于UNIX没有A盘,C盘这样的概念。它所有的文件都要挂载到根目录下的某个子目录底下,另外UNIX把所有设备都看成是文件。比如A盘就有可能是/dev/fd0这个文件。那比如我们想使用软盘怎么办呢,以为软盘是个临时文件,所以在开机时一般不会设为自动挂载。所以我们要手动挂载它在这个某一个目录下。有可能我说得大家有点糊涂,不要紧我们举个例子。文件系统就像一棵大树,树干只有一个那就是根目,树干往上是树杈就是一个一个的子目录,树杈往上有可能还是树杈,那就是这个子目录的子目录,也有可能是树叶,树叶就是文件。现在你手里有一根树枝上面有几个叶子,可你拿手攥着它,它是不会得到来自这颗大树的养分的,除非你把它嫁接在大树的某一个树杈上。就是这个道理。 
回到刚才的话,具体怎么能使用软盘呢。 
$mount /dev/fd0 /mnt/floppy

这样你就把这个小树杈,嫁接到了/mnt/floppy上。等你用完了软盘输入 
$umount /mnt/floppy

就等于把这个树枝又掰折了。 
说了这么多,换换口味看一个程序,让我们来调查一下分区的剩余空间有多少 
#include <stdio.h>

#include <sys/types.h>

#include <sys/statvfs.h>

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

{

        struct statvfs buf[1];

        sync();

        if( statvfs(argv[1],buf)!=0 )

        {

                fprintf(stderr , "Cannot read super block !\n");

                exit(1);

        }

        fprintf(stderr , "%4.1f %% free\n",

                (float)buf[0].f_bfree / buf[0].f_blocks*100 );

        return 0;

}
编译执行: 
$./a.out

36.7 % free

这里用到了statvfs()这个系统调用。它是用来得到文件系统总体信息的系统调用。得到的信息它会放在一个叫做statvfs的结构体里。这时候结构体里的f_bfree表示的就是空闲的block数,f_block表示的就是所有block数。他们相除就得到了使用比,是不是很简单呢。这里注意,statvfs系统调用返回的是一个叫做statvfs的结构体,名字相同别弄混了。下面把statvfs()的格式写一下。 
#include<sys/types.h> 
#include<sys/statvfs.h>

int statvfs( char *path , struct statvfs *buf );



返回值:        成功时:0失败时:-1

结构体statvfs里还有好多关于这个分区的信息,感觉就像windows下查看C盘属性的功能差不多,但还要强大,大家可以自己上机man一下。我就不一一说了。 
上面另一个系统调用sync(),是用来将内存上的硬盘信息回写到硬盘上而用的。这时因为UNIX系统为了能快速查找硬盘信息,而将super block(下面要讲)信息放在内存里。它是一个没有参数也没有返回值的系统调用。 
另外还有一个命令也叫sync,作用和sync()是一样的。 

上面说到了一个概念叫super block,下面我们就说说它。 
一般,一个分区包含有这么几个部分:boot block,super block,i node block,data block。我们一个一个来说说。 
boot block : 
它总是在每个分区的最前面,用来存放开机引导程序。大小是512或1024字节。LINUX下我们常用的LILO等就放在这里。 
super block : 
super block用来存放这个分区全体的管理信息。我说说关于i-node的信息,别的大家可以查查任何一本关于UNIX文件系统的书,都会有的。super block里有一个存放空i-node号的数组。如果我们建立新文件时,系统就可以知道现在哪些i-node号是可用的。上面我们说了,super block的信息是常驻内存的,这样系统建立新文件时就不用去读盘,而直接从内存里调出来就可以了,提高了系统运行速度。 
i node block : 
i node block就是存放i-node的部分。i-node即index node是简称。里面装的关于每一个文件的属性,就好像windows里选文件点右键,查看属性里显示的东西。比如,文件的所有者,权限,大小,修改日期,硬盘上的位置等等。 
data block : 
这里存放就是货真价实的数据了。没什么好说的了 

我们再看一个程序。它是用来将i-node号及文件名输出来。 
#include <stdio.h>

#include <dirent.h>

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

{

        DIR *fp;

        struct dirent *p;

        fp=opendir(argv[1]);

        while( (p=readdir(fp))!=NULL )

        {

                printf("%i %s\n", p->d_ino , p->d_name );

        }

        closedir(fp);

        return 0;

}

执行 
$./a.out /

96673 sbin

966721 dev

998945 root

11 lost+found

2 ..

2 .

.

.

等等

.

.

1031169 lib

好下面我们来说说上面的几个系统调用 
opendir() 
作用:打开一个目录

#include <dirent.h>

#include <sys/types.h>

DIR *opendir( char *dirname );

返回值     成功时返回DIR结构体的地址,失败返回NULL

  
readdir() 
作用:读取目录信息到DIR结构体。DIR结构体是什么大家也可以查一下man 3 readdir

#include <linux/types.h>

#include <linux/dirent.h>

struct dirent *readdir(DIR *dir);

返回值:成功是返回DIR的地址,失败返回NULL


closedir() 
作用:关闭目录

#include <sys/types.h>

#include <dirent.h>

int closedir(DIR *dir);

返回值:成功时为0,失败为1
书接上回,上次我们说到了UNIX文件系统的结构,知道了有哪几个block,各是干什么用的,这回我们说说怎样对文件进行操作。 
我们一般对文件进行操作时不是直接指定i-node号的,而是指定文件的路径的。然而,在内核对文件的操作却是通过i-node来进行的。那么问题就来了,系统又是如何将路径和i-node联系起来从而又找到硬盘上数据存放的具体位置的呢。 
我来做一下解释,比如你要访问/home/user1/test.c这个文件。系统从根目录开始查找,根目录的i-node号是2这个是确定的。系统就去i-node block里找2号i-node,看过上次贴的朋友应该知道,它会告诉系统根目录信息数据存放在硬盘上的具体位置,里面会有根目录下的文件与i-node的对应表,就像我们上次那个程序里看到的那样。系统从而得到了home目录的i-node号然,然后再去硬盘看home目录下的文件与i-node的对应关系,这样也就找到了test.c在硬盘上的具体位置。 
其实如果test.c这个文件很大那它在硬盘上也不是放在一起的。data block里其实是一个一个的小数据块,数据就放在这里。但这个块的大小是一定的有1024字节的也有2048,4096的这根据你的分区方法不同也不太一样。如果你的文件比较大那么一个数据块里就放不下它,这就需要更多的块。打个比方,你有130万RMB(好比一个文件),这么多钱可别被贼偷了去,要把它们放到保险柜(好比数据块)里,但保险柜太小一个只能放50万。那你需要几个保险柜呢。(好像是小学时候做的应用题)答案是3个,最后一个装了只装了30万。浪费了20万的空间。那我接着要问这时我正好有20万(好比另一个文件)也要放进保险柜,那我们一共要多少个保险柜呢。如果你说还是3个那你就错了。虽然你有一个保险箱浪费了20万的空间,但其他人的钱(其他文件)也是不能放进去的,否则谁也分不清里面哪些钱是你的哪些钱是我的了。所以我的20万也好即使是一块钱也需要一个新的保险柜。 

下面我们举个例子来看看如何用i-node里面的信息。这个程序是将我们指定的两个文件名中输出更新时间晚的一个 
#include <sys/types.h>

#include <sys/stat.h>

#include <stdio.h>

int main( int argc , char *argv )

{

        struct stat buf[2] , *p ;

        if( argc!=3 )

        {

                fprintf( stderr , "Usage : %s file1 file2\n" , argv[0] );

                exit(1);

        }

        p=buf;

        if( stat(argv[1],p)!=0 ) 

        {

                fprintf( stderr , "%s not found !\n" , argv[1] );

                exit(1);

        }

        p++;

        if( stat(argv[2],p)!=0 )    

        {

                fprintf( stderr , "%s not found !\n" , argv[2] );

                exit(1);

        }

        if( buf[0].st_mtime > buf[1].st_mtime )       //比较更新时间

                printf( "%s\n" , argv[1] );

        else

                printf( "%s\n" , argv[2] );

        return 0;

}

大家可以自己执行一下看看结果。 
我们来说说stat(),使用它可以得到一个叫stat的结构体,它包含了i-node里面的一部分信息。诸如,文件的权限,i-node号,链接数,所有者id,组id,文件大小等等。具体的大家可man stat查看一下。 
作用:得到一个stat结构体。 

#include <sys/types.h>

#include <sys/stat.h>

int stat( char *path , struct stat *buf );

返回值:        成功时:0 失败时:-1

为了简洁,我们的程序里没有考虑到更新时间相同的文件。大家可以自己补上。 

下面我们做一个改变文件权限的程序。 
#include <sys/types.h>

#include <sys/stat.h>

#include <stdio.h>

#define MASK 0555 //设置掩码

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

{

        struct stat buf[1];

        mode_t mode;

        if( argc!=2 )

        {

                fprintf( stderr , "Usage : %s file\n" , argv[0] );

                exit(1);

        }

        if( stat(argv[1],buf)!=0 )

        {

                fprintf( stderr , "Cannot read i-node\n" );

                exit(1);

        }

        mode = ( buf[0].st_mode & MASK );     

        if ( chmod(argv[1],mode)!=0 )         //改变文件的权限

        {

                fprintf( stderr , "Cannot change mode\n" );

        }

        return 0;

}


怎么样这个程序不能我直接说里面的系统调用 

chomd() 
作用:改变文件的权限(关于权限下面要说)

#include <sys/types.h>

#include <sys/stat.h>

int chmod( char *path , mode_t mode );

返回值:        成功时:0 失败时:-1

那什么是文件的权限呢?你可以用 
$ls –l /

命令来查看根目录下所有子目录的权限。你会看见类似下面这样的 
drwxr-xr-x  2 root root  4096 11-04 22:43 bin

drwxr-xr-x  4 root root  1024 09-27 02:15 boot

drwxr-xr-x 10 root root  3640 11-11 15:08 dev

drwxr-xr-x 88 root root 12288 11-11 15:08 etc

drwxr-xr-x  3 root root  4096 09-27 02:40 home

drwxr-xr-x 11 root root  4096 10-31 21:49 lib

drwx------  2 root root 16384 09-27 10:51 lost+found

drwxr-xr-x  2 root root  4096 09-27 20:27 media

drwxr-xr-x  2 root root  4096 2006-02-11 misc

drwxr-xr-x  2 root root  4096 2006-02-12 mnt

drwxr-xr-x  2 root root     0 11-11 15:08 net

drwxr-xr-x  2 root root  4096 2006-02-12 opt

我们看见的每行最前面的那一串字符就是表示权限的。其中第一位表示文件的类型(d:目录,-:一般文件,l:链接,c:字符设备,b:块设备,最后在/dev目录中很常见,是表示设备的)。其后有九位,三位一组,第一组(2-4位)是说明文件所有者的权限的,第二组(5-7)位是说明与文件所有者同group其他用户对这个文件的权限,第三组(8-10)是所有人对这个文件的权限。每组的第一位是r表示读,第二位是w表示写,第三位是x表示可执行,如果某一位上是-说明就没有该位的相应权限。比如说/bin与root同group的人就没有写的权限因为它的是r-x,中间本应是w的那一位是-。 
我们说的在详细点比如一个文件有这样的一个权限 
rwxr-xr--

我们把它先分组 
 
 rwx        r-x         r--

所有者    同group者   其他人

这样我们就可以清楚地看见谁有什么样的权限了。接着我们把有权限的为写成1,-位写成0的话会变成 
111     101    100

这种形式,我们把它们化成十进数就变成了 
7       5      4

所以我们也可以说这个文件的权限是754了。这回你应该明白为什么有时候说某个文件的权限是777,444,654等等了吧。下回看见了别再说它是777老虎机了。 
作者:DLUTBruceZhang 发表于2013-2-12 21:41:28 原文链接
阅读:99 评论:0 查看评论

相关 [unix 系统 编程] 推荐:

UNIX系统编程(2)

- - CSDN博客架构设计推荐文章
这回我们来说一下UNIX的文件系统. 由于一般情况下UNIX机的硬盘会很大,所以一般你可以给它分成几个区,而每个分区又都可以有独立的文件系统. 如果你是UNIX系统,你有可能看见 . 如果你是linux你有可能看见 . 这些文件,每一个就可以看成是一个分区. 当计算机启动时,系统先找到/(根目录),然后系统就像挖土豆子一样找到一个带出来一串似的,顺着根目录一带就带出来挂载在根目录下的所有目录(详细的请查一下/etc/fstab这个文件).

UNIX系统编程(1)

- - CSDN博客架构设计推荐文章
注:本文来自“网易”博主,仅阅读,学习. 第一章:什么是系统编程 . UNIX系统编程,简单的说就是“C语言+系统调用(system call)”,学会了C语言再知道一些系统调用的方法,其实就可以进行UNIX系统编程了. 那什么又是系统调用呢,其实初学者就把它看当成是函数用就可以了. 这些“函数”是干什么用的呢,大家知道操作系统内核管理着我们的计算机资源,比如CPU,内存,硬盘等等.

如何选择服务器操作系统(Linux/Unix)

- - 标点符
Linux的发行版有上百种,如何选择也是一种难题. 一、Ubuntu Desktop 和 Ubuntu Server. 这个是最方便,也是最快捷的方式. 如果刚开始使用Ubuntu,且不太熟悉命令行的可以选用Ubuntu Desktop来学习. 继而转为Ubuntu Server. 对于初学者,Ubuntu可以更好地上手,并且提供了很好提供了apt软件管理方式(这个是目前最好的软件管理方式),使用起来非常方便,同事Ubuntu的社区也非常的活跃,使用的人数也较多.

工具推荐:HardeningONE(类Unix系统安全检查脚本)

- - FreeBuf.COM | 关注黑客与极客
hardeningone是一款类Unix系统安全检查bash shell脚本,适合信安审计人员或信安测试人员使用. 作者写这个检测脚本的初衷是为了做系统安全审计、网络安全配置和系统安全维护之用. 该脚本主要包括如下功能内容:. (4)运行情况监控与报告. (5)其他的一些还在调试的功能. hardeningone无需进行安装,仅仅只需你通过github下载到系统中,在文件目录里面运行即可(注意文件运行权限).

现代计算机操作系统 Unix、C 语言之父 Dennis Ritchie 逝世

- tossking - 爱范儿 · Beats of Bits
令人悲伤的消息不止一个,现代计算机操作系统 Unix 之父、C 语言之父 Dennis Ritchie 辞世,IT 产业连续失去了两名重要的人物. 根据 Ritchie 的前同事 Rob Pike 在 Google+ 透露的消息,Ritchie  10 月 9 日病逝,享年 70 岁. 1941 年,Ritchie 出生在纽约 Bronxville,后来到哈佛大学学习应用数学与物理学毕业,1967 年他进入贝尔实验室.

UNIX传奇

- dayu - 桃源
了解过去,我们才能知其然,更知所以然. 总结过去,我们才会知道我们明天该如何去规划,该如何去走. 在时间的滚轮中,许许多的东西就像流星一样一闪而逝,而有些东西却能经受着时间的考验散发着经久的魅力,让人津津乐道,流传至今. 要知道明天怎么去选择,怎么去做,不是盲目地跟从今天各种各样琳琅满目前沿技术,而应该是去 —— 认认真真地了解和回顾历史.

C语言之父和Unix系统共同研制者丹尼斯•里奇去世

- kof2002 - 译言-每日精品译文推荐
莱纳斯·托瓦尔兹曾经就Linux的发展说过,他“[他自己]早就被托在巨人的肩膀上. ”丹尼斯·里奇(亦称dmr)很可能是这些巨人中间最高大的. C程序设计语言的创始人和Unix操作系统的共同研制者里奇于10月8日去世,终年70岁,他的遗产投下很长很长的影子. 由于里奇在Unix神怪般的分时系统方面的成果,我开始从事技术工作.

Unix调试的瑞士军刀:lsof

- Ran - 黑客志
这是“你应该知道的Unix和Linux命令”系列的第三篇,在这篇文章中,我会介绍lsof这个工具,如果说netcat是进行网络诊断的瑞士军刀,那么lsof就是Unix调试的瑞士军刀. Lsof是遵从Unix哲学的典范,它只做一件事情,并且做的相当完美——它可以列出某个进程打开的所有文件信息. 打开的文件可能是普通的文件,目录,NFS文件,块文件,字符文件,共享库,常规管道,明明管道,符号链接,Socket流,网络Socket,UNIX域Socket,以及其它更多.

24 个很酷的 Linux/Unix 工具

- will - LinuxTOY
KKovacs 收集了 24 个 Linux/Unix 平台上的工具,既有熟悉的,也有鲜为人知的. 这些运行于终端的工具都很酷,很有用. iostat、vmstat、ifstat 等. 进程、内存、以及 io 监视. 通过 SSH 保持文件系统同步. 在分隔的窗口中查看你的日志. socket 输入、输出更容易.

Unix/Linux常用的一些命令

- 白开水易拉罐 - BlogJava-首页技术区
Unix/Linux 的常用命令:. 这是我在学完Unix后归纳的一些觉得有用的命令:. ps:查看进程,也可以观察当前shell. ps -ef:查看和终端有关的所有进程. df -k:查看当前文件系统使用情况. passwd-d  user:清除用户的口令. more   :查看文件内容   可以分屏显示.