免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: naker
打印 上一主题 下一主题

UNIX系统编程(10月11号更新 1楼,2楼,11楼,20楼,53楼,54楼) [复制链接]

论坛徽章:
0
51 [报告]
发表于 2006-11-10 19:37 |只看该作者
不顶,说不过去

论坛徽章:
0
52 [报告]
发表于 2006-11-10 20:57 |只看该作者
hao

论坛徽章:
0
53 [报告]
发表于 2006-11-11 00:20 |只看该作者
第三章:文件系统
这回我们来说一下UNIX的文件系统。由于一般情况下UNIX机的硬盘会很大,所以一般你可以给它分成几个区,而每个分区又都可以有独立的文件系统。如果你是UNIX系统,你有可能看见
  1. /dev/sd/c0t0d0s0
  2. /dev/sd/c0t0d0s1
复制代码

这样的文件。
如果你是linux你有可能看见
  1. /dev/hda0
  2. /dev/hda1
复制代码

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

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

就等于把这个树枝又掰折了。
说了这么多,换换口味看一个程序,让我们来调查一下分区的剩余空间有多少
  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/statvfs.h>
  4. int main(int argc , char *argv[])
  5. {
  6.         struct statvfs buf[1];
  7.         sync();
  8.         if( statvfs(argv[1],buf)!=0 )
  9.         {
  10.                 fprintf(stderr , "Cannot read super block !\n");
  11.                 exit(1);
  12.         }
  13.         fprintf(stderr , "%4.1f %% free\n",
  14.                 (float)buf[0].f_bfree / buf[0].f_blocks*100 );
  15.         return 0;
  16. }
复制代码
编译执行:
  1. $./a.out
  2. 36.7 % free
复制代码

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

  3. 返回值:        成功时: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号及文件名输出来。
  1. #include <stdio.h>
  2. #include <dirent.h>
  3. int main( int argc , char *argv[] )
  4. {
  5.         DIR *fp;
  6.         struct dirent *p;
  7.         fp=opendir(argv[1]);
  8.         while( (p=readdir(fp))!=NULL )
  9.         {
  10.                 printf("%i %s\n", p->d_ino , p->d_name );
  11.         }
  12.         closedir(fp);
  13.         return 0;
  14. }
复制代码

执行
  1. $./a.out /
  2. 96673 sbin
  3. 966721 dev
  4. 998945 root
  5. 11 lost+found
  6. 2 ..
  7. 2 .
  8. .
  9. .
  10. 等等
  11. .
  12. .
  13. 1031169 lib
复制代码

好下面我们来说说上面的几个系统调用
opendir()
  1. 作用:打开一个目录
  2. #include <dirent.h>
  3. #include <sys/types.h>
  4. DIR *opendir( char *dirname );
  5. 返回值     成功时返回DIR结构体的地址,失败返回NULL
复制代码

readdir()
  1. 作用:读取目录信息到DIR结构体。DIR结构体是什么大家也可以查一下man 3 readdir
  2. #include <linux/types.h>
  3. #include <linux/dirent.h>
  4. struct dirent *readdir(DIR *dir);
  5. 返回值:成功是返回DIR的地址,失败返回NULL
复制代码


closedir()
  1. 作用:关闭目录
  2. #include <sys/types.h>
  3. #include <dirent.h>
  4. int closedir(DIR *dir);
  5. 返回值:成功时为0,失败为1
复制代码


今天就先说这么多,明天我看再来看看如何对文件进行操作。

论坛徽章:
0
54 [报告]
发表于 2006-11-11 18:57 |只看该作者
书接上回,上次我们说到了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里面的信息。这个程序是将我们指定的两个文件名中输出更新时间晚的一个
  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <stdio.h>
  4. int main( int argc , char *argv )
  5. {
  6.         struct stat buf[2] , *p ;
  7.         if( argc!=3 )
  8.         {
  9.                 fprintf( stderr , "Usage : %s file1 file2\n" , argv[0] );
  10.                 exit(1);
  11.         }
  12.         p=buf;
  13.         if( stat(argv[1],p)!=0 )
  14.         {
  15.                 fprintf( stderr , "%s not found !\n" , argv[1] );
  16.                 exit(1);
  17.         }
  18.         p++;
  19.         if( stat(argv[2],p)!=0 )   
  20.         {
  21.                 fprintf( stderr , "%s not found !\n" , argv[2] );
  22.                 exit(1);
  23.         }
  24.         if( buf[0].st_mtime > buf[1].st_mtime )       //比较更新时间
  25.                 printf( "%s\n" , argv[1] );
  26.         else
  27.                 printf( "%s\n" , argv[2] );
  28.         return 0;
  29. }
复制代码

大家可以自己执行一下看看结果。
我们来说说stat(),使用它可以得到一个叫stat的结构体,它包含了i-node里面的一部分信息。诸如,文件的权限,i-node号,链接数,所有者id,组id,文件大小等等。具体的大家可man stat查看一下。
  1. 作用:得到一个stat结构体。
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. int stat( char *path , struct stat *buf );
  5. 返回值:        成功时:0 失败时:-1
复制代码

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

下面我们做一个改变文件权限的程序。
  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <stdio.h>
  4. #define MASK 0555 //设置掩码
  5. int main( int argc , char *argv[] )
  6. {
  7.         struct stat buf[1];
  8.         mode_t mode;
  9.         if( argc!=2 )
  10.         {
  11.                 fprintf( stderr , "Usage : %s file\n" , argv[0] );
  12.                 exit(1);
  13.         }
  14.         if( stat(argv[1],buf)!=0 )
  15.         {
  16.                 fprintf( stderr , "Cannot read i-node\n" );
  17.                 exit(1);
  18.         }
  19.         mode = ( buf[0].st_mode & MASK );     
  20.         if ( chmod(argv[1],mode)!=0 )         //改变文件的权限
  21.         {
  22.                 fprintf( stderr , "Cannot change mode\n" );
  23.         }
  24.         return 0;
  25. }
复制代码


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

chomd()
  1. 作用:改变文件的权限(关于权限下面要说)
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. int chmod( char *path , mode_t mode );
  5. 返回值:        成功时:0 失败时:-1
复制代码

那什么是文件的权限呢?你可以用
  1. $ls –l /
复制代码

命令来查看根目录下所有子目录的权限。你会看见类似下面这样的
  1. drwxr-xr-x  2 root root  4096 11-04 22:43 bin
  2. drwxr-xr-x  4 root root  1024 09-27 02:15 boot
  3. drwxr-xr-x 10 root root  3640 11-11 15:08 dev
  4. drwxr-xr-x 88 root root 12288 11-11 15:08 etc
  5. drwxr-xr-x  3 root root  4096 09-27 02:40 home
  6. drwxr-xr-x 11 root root  4096 10-31 21:49 lib
  7. drwx------  2 root root 16384 09-27 10:51 lost+found
  8. drwxr-xr-x  2 root root  4096 09-27 20:27 media
  9. drwxr-xr-x  2 root root  4096 2006-02-11 misc
  10. drwxr-xr-x  2 root root  4096 2006-02-12 mnt
  11. drwxr-xr-x  2 root root     0 11-11 15:08 net
  12. 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的那一位是-。
我们说的在详细点比如一个文件有这样的一个权限
  1. rwxr-xr--
复制代码

我们把它先分组
  1. rwx        r-x         r--
  2. 所有者    同group者   其他人
复制代码

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

这种形式,我们把它们化成十进数就变成了
  1. 7       5      4
复制代码

所以我们也可以说这个文件的权限是754了。这回你应该明白为什么有时候说某个文件的权限是777,444,654等等了吧。下回看见了别再说它是777老虎机了。

好,文件系统我们就讲到这。其实文件系统的知识很多也很杂,我这里只是介绍了一下文件系统的4个block,和它们的作用,而且只是皮毛的皮毛。所以关于文件系统的知识希望大家还是多多参看其他的一些资料。
下一章,我们说说标准输入输出以及管道,在那里还将补充说明一些关于文件描述符和读写文件的一些知识,希望大家继续支持我!

论坛徽章:
0
55 [报告]
发表于 2006-11-13 16:31 |只看该作者
温故知新
赞一个~

论坛徽章:
0
56 [报告]
发表于 2006-11-14 09:12 |只看该作者
接着来顶,呵呵。

论坛徽章:
0
57 [报告]
发表于 2006-11-16 00:21 |只看该作者
up

论坛徽章:
0
58 [报告]
发表于 2006-11-16 00:40 |只看该作者
安装Red Flat Linux 像蜗牛一样.

正好看LZ的教程....

不错..收藏了.

论坛徽章:
0
59 [报告]
发表于 2006-11-16 00:47 |只看该作者
我想问一下各位大哥大姐:

Windows 2000 下通过虚拟机(VM Ware )安装的Red flat linux 5.0

与非虚拟机安装的Linux有什么不同呢?


我想学习在linux下的C语言.....



先谢过了.LZ能否给答一下啊?

论坛徽章:
0
60 [报告]
发表于 2006-11-16 10:24 |只看该作者

  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <stdio.h>
  4. #define MASK 0555 //设置掩码
  5. int main( int argc , char *argv[] )
  6. {
  7.         struct stat buf[1];
  8.         mode_t mode;
  9.         if( argc!=2 )
  10.         {
  11.                 fprintf( stderr , "Usage : %s file\n" , argv[0] );
  12.                 exit(1);
  13.         }
  14.         if( stat(argv[1],buf)!=0 )
  15.         {
  16.                 fprintf( stderr , "Cannot read i-node\n" );
  17.                 exit(1);
  18.         }
  19.         mode = ( buf[0].st_mode & MASK );     
  20.         if ( chmod(argv[1],mode)!=0 )         //改变文件的权限
  21.         {
  22.                 fprintf( stderr , "Cannot change mode\n" );
  23.         }
  24.         return 0;
  25. }

复制代码


Segmentation fault
不知道为什么?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP