sql server 启用xp_cmdshell 重启pcanywhere

windows2003服务器使用pcanywhere进行远程管理,但有时pcanywhere会出问题而服务关闭,因为服务器在电信机房,以前这种问题只能请机房工作人员直接reset服务器,但这不是个好办法,直接reset断电,对数据而言,是很不安全的,不出问题则已,出问题就严重了。所以最好还是通过软件启动。
但问题是,windows无法登录,于是悖论了...
考虑到该服务器上装有ms sql server,而且启用了远程sa用户登录,于是想到了借用xp_cmdshell重新启动pcanywhere服务awhost32。
默认状态下xp_cmdshell是关闭状态的,需要通过sa帐号登录mssql,启用xp_cmdshell,以命令行形式开启awhost32服务,再关闭xp_cmdshell.
如下:

开启xp_cmdshell

EXEC sp_configure 'show advanced options', 1
RECONFIGURE WITH OVERRIDE
EXEC sp_configure 'xp_cmdshell', 1
RECONFIGURE WITH OVERRIDE
EXEC sp_configure 'show advanced options', 0

开启awhost32服务

xp_cmdshell 'net start awhost32'

关闭xp_cmdshell

EXEC sp_configure 'show advanced options', 1
RECONFIGURE WITH OVERRIDE
EXEC sp_configure 'xp_cmdshell', 0
RECONFIGURE WITH OVERRIDE
EXEC sp_configure 'show advanced options', 0

完成!

应对51yes统计bug:firefox 浏览器彻底屏蔽51yes弹出保存文件窗口方法

由于51yes统计的恶劣的bug,导致部分firefox浏览器打开包含有51yes统计的页面都会弹出是否下载文件确认的窗口,非常影响使用。

致51yes的一封信:该死的51yes统计能不能做得兼容性好一点!!!!

这个弹窗并非在所有的firefox里都出现,至于原因,不太清楚(据有些网友说是http返回头里文档类型字段不符合标准导致),但这个问题对于我们这些最终用户来说,是一个很影响情绪、更影响效率的问题,因此一定要解决,也希望51yes的技术人员能尽快解决这一问题

为了让我们正常的使用firefox上网,一定要解决这个令人咬牙切齿的问题,本人使用这个方法解决,非常简单,不用借助任何第三方工具/插件等,方法很简单:把下面的代码加到操作系统的的host文件中,即可以解决这一问题.

如果你是Linux使用者,提到hosts文件,就不用我在这里多说了

windows的hosts文件位置为:C:\WINDOWS\system32\drivers\etc\hosts

该文件是纯文本文件,使用任何文本编辑器都可以,如windows自带的傻傻的"记事本"就可以.

原理:强制对51yes的统计服务器的作错误的域名解析,如解析到本机127.0.0.1,51yes统计代码就无法正常工作,从而达到目的;51yes统计服务器好像有很多,这里从1到50,全部强制作错误解析;如果在实际上网中发现还有其它统计服务器,把它的域名也一并加进去,格式很简单,见下,一看就懂。

知道hosts文件的作用就非常好理解。

------------从下一行开始-------------

127.0.0.1       localhost
127.0.0.1       51yes.com
127.0.0.1       count1.51yes.com
127.0.0.1       count2.51yes.com
127.0.0.1       count3.51yes.com
127.0.0.1       count4.51yes.com
127.0.0.1       count5.51yes.com
127.0.0.1       count6.51yes.com
127.0.0.1       count7.51yes.com
127.0.0.1       count8.51yes.com
127.0.0.1       count9.51yes.com
127.0.0.1       count10.51yes.com
127.0.0.1       count11.51yes.com
127.0.0.1       count12.51yes.com
127.0.0.1       count13.51yes.com
127.0.0.1       count14.51yes.com
127.0.0.1       count15.51yes.com
127.0.0.1       count16.51yes.com
127.0.0.1       count17.51yes.com
127.0.0.1       count18.51yes.com
127.0.0.1       count19.51yes.com
127.0.0.1       count20.51yes.com
127.0.0.1       count21.51yes.com
127.0.0.1       count22.51yes.com
127.0.0.1       count23.51yes.com
127.0.0.1       count24.51yes.com
127.0.0.1       count25.51yes.com
127.0.0.1       count26.51yes.com
127.0.0.1       count27.51yes.com
127.0.0.1       count28.51yes.com
127.0.0.1       count29.51yes.com
127.0.0.1       count30.51yes.com
127.0.0.1       count31.51yes.com
127.0.0.1       count32.51yes.com
127.0.0.1       count33.51yes.com
127.0.0.1       count34.51yes.com
127.0.0.1       count35.51yes.com
127.0.0.1       count36.51yes.com
127.0.0.1       count37.51yes.com
127.0.0.1       count38.51yes.com
127.0.0.1       count39.51yes.com
127.0.0.1       count40.51yes.com
127.0.0.1       count41.51yes.com
127.0.0.1       count42.51yes.com
127.0.0.1       count43.51yes.com
127.0.0.1       count44.51yes.com
127.0.0.1       count45.51yes.com
127.0.0.1       count46.51yes.com
127.0.0.1       count47.51yes.com
127.0.0.1       count48.51yes.com
127.0.0.1       count49.51yes.com
127.0.0.1       count50.51yes.com

------------到这一行结束-------------

邮箱域名的spf记录添加方法

什么是SPF
就是Sender Policy Framework。SPF可以防止别人伪造你来发邮件,是一个反伪造性邮件的解决方案。当你定义了你的domain name的SPF记录之后,接收邮件方会根据你的SPF记录来确定连接过来的IP地址是否被包含在SPF记录里面,如果在,则认为是一封正确的邮件,否则 则认为是一封伪造的邮件。关于更详细的信息请参考RFC4408(http://www.ietf.org/rfc/rfc4408.txt

如何增加SPF记录
非常简单,在DNS里面添加TXT记录即可。登陆http://www.openspf.org/在里面输入你的域名,点击Begin,然后会自动得到你域名的一些相关信息。
a 你域名的A记录,一般选择yes,因为他有可能发出邮件。
mx 一般也是yes,MX服务器会有退信等。
ptr 选择no,官方建议的。

a: 有没有其他的二级域名?比如:mail.abc.com和www不在一台server上,则填入mail.abc.com。否则清空。
mx: 一般不会再有其他的mx记录了。
ip4: 你还有没有其他的ip发信?可能你的smtp服务器是独立出来的,那么就填入你的IP地址或者网段。
include: 如果有可能通过一个isp来发信,这个有自己的SPF记录,则填入这个isp的域名,比如:hichina.com
~all: 意思是除了上面的,其他的都不认可。当然是yes了。

好了,点击Continue…..
自动生成了一条SPF记录,比如abc.com的是
v=spf1 a mx ~all
并且在下面告诉你如何在你的bind里面添加一条
abc.com. IN TXT “v=spf1 a mx ~all”

加入你的bind,然后ndc reload即可。
检查一下:
dig -t txt extmail.org

如果您的域名是由万网的dns服务器进行解析的,万网的网页上没有设置TXT记录的地方,但是如果你的DNS主server是在Hichina的,可以在diy.hichina.com上设置。设置完毕后您即可以通过使用spf策略进行垃圾邮件验证了。

SPF 的 TXT 记录

SPF 记录包含在一个 TXT 记录之中,格式如下:

  v=spf1 [[pre] type [ext] ] ... [mod]

每个参数的含义如下表所示:

参数 描述
v=spf1 SPF 的版本。如果使用 Sender ID 的话,这个字段就应该是 v=spf2
pre 定义匹配时的返回值。

可能的返回值包括:

返回值 描述
+ 缺省值。在测试完成的时候表示通过。
- 表示测试失败。这个值通常是 -all,表示没有其他任何匹配发生。
~ 表示软失败,通常表示测试没有完成。
? 表示不置可否。这个值也通常在测试没有完成的时候使用。
type 定义使用的确认测试的类型。

可能的值包括:

候选值 描述
include 包含一个给定的域名的测试
以 include:domain 的形式书写。

all 终止测试序列。
比如,如果选项是 -all,那么到达这条记录也就意味着测试失败了。但是如果无法确定,可以使用"?all"来表示,这样,测试将被接受。

ip4 使用 IPv4 进行验证。
这个可以以 ip4:ipv4 或 ip4:ipv4/cidr 的形式使用。建议使用这个参数,以减少域名服务器的负荷。

ip6 使用 IPv6 进行验证。

a 使用一个域名进行验证。
这将引起对域名服务器进行一次 A RR 查询。
可以按照 a:domain, a:domain/cidr 或 a/cidr 的形式来使用。

mx 使用 DNS MX RR 进行验证。
MX RR 定义了收信的 MTA,这可能和发信的 MTA 是不同的,这种情况基于 mx 的测试将会失败。
可以用 mx:domain, mx:domain/cidr 或 mx/cidr 这些形式进行 mx 验证。

ptr 使用域名服务器的 PTR RR 进行验证。
这时,SPF 使用 PTR RR 和反向图进行查询。如果返回的主机名位于同一个域名之内,就验证通过了。
这个参数的写法是 ptr:domain

exist 验证域名的存在性。
可以写成 exist:domain 的形式。

ext 定义对 type 的可选扩展。如果没有这个字段,那么仅使用单个记录进行问询。
mod 这是最后的类型指示,作为记录的一个修正值。

修正值 描述
redirect 重定向查询,使用给出的域名的 SPF 记录。
以 redirect=domain 的方式使用。

exp 这条记录必须是最后一条,允许给出一条定制的失败消息。

IN TXT "v=spf1 mx -all exp=getlost.example.com"

getlost IN TXT "You are not authorized to send mail for the domain"

致51yes的一封信:该死的51yes统计能不能做得兼容性好一点!!!!

最近上网,很多网站网页一打开,就要弹出一个对话框,就是否下载一个.aspx文件,直接取消,没有理会它。因为明显是网站程序没写好,让浏览器认为是有文件下载。

见得多了,发现这些提示都是来源于一个网站,51yes,原来是51yes的统计代码。

IE及基于IE的浏览器没有这个问题。但这不能说是是浏览器的问题,因为IE这种霸道的公司出的霸道的产品,几乎从来不理会“标准”这个东西,仗着“闻到死”的基础,为所欲为,无所不为,虽然没到到无恶不作的地步,但也有几分这种感觉。

——扯远了。

单说今天,又一连好些次被这个垃圾统计代码打扰,甚至想通过一些技术手段屏蔽51yes的域名。

实然想,看看51yes他们官方网站是什么样子。于是打开一下,照例使用firefox浏览器。

天哪,我实在是惊呆了,目瞪口呆,呆若木鸡;接说一种十万份的无比崇拜油然而生——

“为什么有这么强烈的反应?”

你看看吧,啪啪啪......连续弹出无数多个窗口,你会有什么样的感触?

垃圾的51yes统计

垃圾的51yes统计

弹出窗口很多,为了能数清,我把它拉开了,至少有这么多个(可能还会有一两个被覆盖到底下看不到的)。

于是写了封信,给51yes(“我要噎死”?很恶搞~~),附带上这张169,475字节的图片,然而却遭退信“附件太大”。

很不逊的一封信;我想肯定还有无数跟我一样愤怒的朋友,这么多的愤怒加起来,也是不可遏止的一股力量。

-----------------------------

致51yes的一封信:

看看你们出的什么垃圾统计!!!!!!!

http://www.imkevinyang.com/2010/05/%E5%BC%BA%E7%83%88%E9%84%99%E8%A7%8651yes.html

http://hi.baidu.com/whomi/blog/item/af23dd54c203e15ad1090634.html

http://www.google.com/search?q=51yes+firefox&btnG=Google+%E6%90%9C%E7%B4%A2&hl=zh-CN&newwindow=1&safe=active&biw=1437&bih=659&sa=2

打开你们首页,出现无数多个弹出窗口,就出现附件里图片的样子,TMD 操蛋的 IE-only 网站!!

垃圾的51yes统计

垃圾的51yes统计

---------------------------
后记:做产品的,就要把产品做得好一点,不一定要做得完美,但至少不要影响大家正常使用,否则,是没有市场的,长期以来是做不大的。
见网上的网友们的评价说,51yes统计自从2006年就是这个样子,大概2006年也就是它对外发布的时候。

这是很“恶毒”的一篇文章,希望51yes人员看到后,不要生气,真切的希望你们能做好一款真正优秀的产品,这对站长、对普通上网的朋友,都是莫大的一件好事

--------------------

再后记:附件过大,于是删除附件,重新发邮件,引用这篇博客里上面的图片发送给他们,但还是被退信,还是说附件过大,根本都没有附件啊!!实在无语~~~~ 把图片删除,只用纯文字发送邮件,看看是不是还“附件过大”

再再后记:果然,还是“附件过大”......

再再后记:太TMD TMD了,只有几行字,也提示附件过大

wordpress 3.x 自由定义导航菜单,把任意链接加入到导航菜单,并自由修改菜单项顺序

wordpress 3.x支持全面的自定义导航菜单功能,这在2.x时间是很多人梦寐以求的,本人当开始用wordpress时,认为作为一个成熟的博客系统,肯定有这样的功能,曾多方找这样的设置,当然是没有办法;当然可以修改wordpress代码或者主题,实现,不过没有这样作过。

控制板 - 外观 -菜单 里的设置,可以把任意链接放到菜单里;该功能还需要主题支持。步骤如下:

创建wordpress导航菜单

创建wordpress导航菜单,这里创建一名为“testmenu”的菜单

点加号添加新菜单。上面图片是,显示有一个名称为(“主菜单”是已经创建好的另一个菜单,这里不用理会它)

wordpress导航菜单加入自定义菜单项

wordpress导航菜单加入自定义菜单项,

有三种添加菜单项的方式,A “url地址+链接名称”的方式; B 选择wordpress“页面”作菜单项  C 选择文章分类作为菜单项。

wordpress导航菜单加入的自定义菜单项可以拖动调整顺序

wordpress导航菜单加入的自定义菜单项可以拖动调整顺序

选择使用自定义菜单

选择使用自定义菜单

首页已经显示自定义的菜单

前台页面已经显示为自定义的菜单

wordpress 3.x 自由定义导航菜单,把任意链接加入到导航菜单,并自由修改菜单项顺序

-----------------------------------------------------------------

如果想对wordpress导航菜单更深入了解,可能参看从 http://fairyfish.net/2010/07/09/wordpress-nav-menu/ 转来的这篇文章,如下:

WordPress 原来默认的导航菜单只能是页面,或者分类,或者两者,如果想自己加入一个自定义链接都需要修改主题,非常不方便,所以一个完全可定制化的自定义的 WordPress 导航菜单成了所有人的需求。

而 WordPress 3.0 的其中一个非常重要的功能是一个全新的菜单管理系统,这个系统可以让我们创建包含由日志,页面,分类,标签和其他链接组成的完全自定义菜单,并且还支持多级菜单,非常方便和强大,今天就谈谈如果使用 WordPress 3.0 这个全新的导航菜单。

WordPress 导航菜单系统的概述

首先我们简单解释下这个导航系统的几个概念:

  • 主题位置:就是定义导航菜单在当前主题位置的名称,比如你在导航位置定义了一个菜单,名字就叫做导航菜单,那么这里就显示“导航菜单”。你可以定义多个主题位置的名称,也就是说可以在主题多个地方使用菜单系统,比如侧边栏的 Widget 等。
  • 独立的菜单:上面定义了菜单在主题的位置,那么这里就是定义菜单的具体内容。
  • 添加菜单项:会提供一堆选择让你添加,比如分类,页面,标签,日志,其他日志分类,还有自定义链接等。
  • 菜单项:可以对具体的菜单项进行配置,比如设置是否新窗口打开,这个菜单项标题,描述,Class 等等。

使用 WordPress 的导航菜单
使用 WordPress 的导航菜单

如何激活 WordPress 自带的导航菜单

要使用 WordPress 导航菜单功能,首先要给当前的主题注册导航菜单,从上面我们知道,我们可以注册一个或者多个导航菜单的主题位置,我么可以使用下面两个函数:

register_nav_menu():注册一个主题位置。
register_nav_menus():注册多个主题位置(使用数组形式)。

这里我们只注册一个导航菜单的主题位置:

register_nav_menu( 'nav-menu', '导航菜单');

nav-menu 是这个导航菜单的名字,用来在函数中定义身份的,而“导航菜单”则是名称,在 WordPress 后台使用的时候可见。

添加和显示导航菜单

注册好之后,就可以到 WordPress 后台 > 外观 > 菜单 添加菜单,添加的菜单的顺序是这样的:

  1. 首先定义好一个单独的菜单。
  2. 然后吧这个菜单赋给一个主题位置。
  3. 接下来就是添加和配置菜单项。

然后我们到主题的显示菜单的位置通过以下 wp_nav_menu() 就能把刚才定义的菜单显示出来,当然 wp_nav_menu() 这个函数可以有非常详细的参数,但是这里只要简单使用就可以,在特殊的情况下才可能使用到。

样式化导航菜单

样式化导航菜单非常简单,你只需要对 current-menu-item 和 current-menu-parent 这两个 Class 进行定义即可。如:

#menu-nav li.current-menu-item, #menu-nav li.current-menu-parent, #menu-nav li:hover {
	background:#1BA6B2;
	text-decoration:none;
	position: relative;
}

然后定义各级菜单的显示和层次效果即可。

关于 WordPress 导航菜单就介绍到这里。

硬盘分区表的详细结构及自动备份和恢复

本篇题目的发起帖子来自于两个论坛,原帖链接分别如下: http://www.51ct.net/bbs/read.php?tid=500&fpage=1:推荐访问 http://www.cn-dos.net/dosbbs/dispbbs.asp?boardid=9&id=15000

需要参考的两篇资料文章的原链接及内容如下:

===================================================================== 1、硬盘分区结构及windows文件系统结构 =====================================================================

===================================================================== 2、扩展int13h调用详解(点击访问原文)

扩展int13h调用详解 作者:不详·发布日期:2002-12-17·阅读次数:18301

--------------------------------------------------------------------------------

转载自:BBS 水木清华站 (Sat Nov 20 16:12:06 1999)

第一部分 简 介

1,1

一. 硬盘结构简介

1. 硬盘参数释疑

到目前为止, 人们常说的硬盘参数还是古老的 CHS (Cylinder/ Head/Sector)参数. 那么为什么要使用这些参数, 它们的意义是什么? 它们的取值范围是什么? 很久以前, 硬盘的容量还非常小的时候, 人们采用与软盘类似的结 构生产硬盘. 也就是硬盘盘片的每一条磁道都具有相同的扇区数. 由此 产生了所谓的3D参数 (Disk Geometry). 既磁头数(Heads), 柱面数 (Cylinders), 扇区数(Sectors),以及相应的寻址方式.

其中:

磁头数(Heads) 表示硬盘总共有几个磁头,也就是有几面盘片, 最大 为 255 (用 8 个二进制位存储); 柱面数(Cylinders) 表示硬盘每一面盘片上有几条磁道, 最大为 1023 (用 10 个二进制位存储); 扇区数(Sectors) 表示每一条磁道上有几个扇区, 最大为 63 (用 6 个二进制位存储). 每个扇区一般是 512个字节, 理论上讲这不是必须的, 但好象没有取 别的值的.

所以磁盘最大容量为:

255 * 1023 * 63 * 512 / 1048576 = 8024 GB ( 1M = 1048576 Bytes ) 或硬盘厂商常用的单位: 255 * 1023 * 63 * 512 / 1000000 = 8414 GB ( 1M = 1000000 Bytes )

在 CHS 寻址方式中, 磁头, 柱面, 扇区的取值范围分别为 0 到 Heads - 1, 0 到 Cylinders - 1, 1 到 Sectors (注意是从 1 开始).

2. 基本 Int 13H 调用简介

BIOS Int 13H 调用是 BIOS 提供的磁盘基本输入输出中断调用, 它可以 完成磁盘(包括硬盘和软盘)的复位, 读写, 校验, 定位, 诊断, 格式化等功能. 它使用的就是 CHS 寻址方式, 因此最大识能访问 8 GB 左右的硬盘 ( 本文中 如不作特殊说明, 均以 1M = 1048576 字节为单位).

3. 现代硬盘结构简介

在老式硬盘中, 由于每个磁道的扇区数相等, 所以外道的记录密度要远低 于内道, 因此会浪费很多磁盘空间 (与软盘一样). 为了解决这一问题, 进一 步提高硬盘容量, 人们改用等密度结构生产硬盘. 也就是说, 外圈磁道的扇区 比内圈磁道多. 采用这种结构后, 硬盘不再具有实际的3D参数, 寻址方式也改 为线性寻址, 即以扇区为单位进行寻址. 为了与使用3D寻址的老软件兼容 (如使用BIOS Int13H接口的软件), 在硬 盘控制器内部安装了一个地址翻译器, 由它负责将老式3D参数翻译成新的线性 参数. 这也是为什么现在硬盘的3D参数可以有多种选择的原因 (不同的工作模 式, 对应不同的3D参数, 如 LBA, LARGE, NORMAL).

4. 扩展 Int 13H 简介

虽然现代硬盘都已经采用了线性寻址, 但是由于基本 Int 13H 的制约, 使 用 BIOS Int 13H 接口的程序, 如 DOS 等还只能访问 8 G 以内的硬盘空间. 为了打破这一限制, Microsoft 等几家公司制定了扩展 Int 13H 标准 (Extended Int13H), 采用线性寻址方式存取硬盘, 所以突破了 8 G 的限制, 而且还加入了对可拆卸介质 (如活动硬盘) 的支持.

二. Boot Sector 结构简介

1. Boot Sector 的组成

Boot Sector 也就是硬盘的第一个扇区, 它由 MBR (Master Boot Record), DPT (Disk Partition Table) 和 Boot Record ID 三部分组成.

MBR 又称作主引导记录占用 Boot Sector 的前 446 个字节 ( 0 to 0x1BD ), 存放系统主引导程序 (它负责从活动分区中装载并运行系统引导程序). DPT 即主分区表占用 64 个字节 (0x1BE to 0x1FD), 记录了磁盘的基本分区 信息. 主分区表分为四个分区项, 每项 16 字节, 分别记录了每个主分区的信息 (因此最多可以有四个主分区). Boot Record ID 即引导区标记占用两个字节 (0x1FE and 0x1FF), 对于合法 引导区, 它等于 0xAA55, 这是判别引导区是否合法的标志. Boot Sector 的具体结构如下图所示 (参见 NightOwl 大侠的文章):

0000 |------------------------------------------------| | | | | | Master Boot Record | | | | | | 主引导记录(446字节) | | | | | | | 01BD | | 01BE |------------------------------------------------| | | 01CD | 分区信息 1(16字节) | 01CE |------------------------------------------------| | | 01DD | 分区信息 2(16字节) | 01DE |------------------------------------------------| | | 01ED | 分区信息 3(16字节) | 01EE |------------------------------------------------| | | 01FD | 分区信息 4(16字节) | |------------------------------------------------| | 01FE | 01FF | | 55 | AA | |------------------------------------------------|

2. 分区表结构简介

分区表由四个分区项构成, 每一项的结构如下:

BYTE State : 分区状态, 0 = 未激活, 0x80 = 激活 (注意此项) BYTE StartHead : 分区起始磁头号 WORD StartSC : 分区起始扇区和柱面号, 底字节的低6位为扇区号, 高2位为柱面号的第 9,10 位, 高字节为柱面号的低 8 位 BYTE Type : 分区类型, 如 0x0B = FAT32, 0x83 = Linux 等, 00 表示此项未用 BYTE EndHead : 分区结束磁头号 WORD EndSC : 分区结束扇区和柱面号, 定义同前 DWORD Relative : 在线性寻址方式下的分区相对扇区地址 (对于基本分区即为绝对地址) DWORD Sectors : 分区大小 (总扇区数)

注意: 在 DOS / Windows 系统下, 基本分区必须以柱面为单位划分 ( Sectors * Heads 个扇区), 如对于 CHS 为 764/255/63 的硬盘, 分区的 最小尺寸为 255 * 63 * 512 / 1048576 = 7.844 MB.

3. 扩展分区简介

由于主分区表中只能分四个分区, 无法满足需求, 因此设计了一种扩展 分区格式. 基本上说, 扩展分区的信息是以链表形式存放的, 但也有一些特 别的地方. 首先, 主分区表中要有一个基本扩展分区项, 所有扩展分区都隶属于它, 也就是说其他所有扩展分区的空间都必须包括在这个基本扩展分区中. 对于 DOS / Windows 来说, 扩展分区的类型为 0x05. 除基本扩展分区以外的其他所有扩展分区则以链表的形式级联存放, 后 一个扩展分区的数据项记录在前一个扩展分区的分区表中, 但两个扩展分区 的空间并不重叠. 扩展分区类似于一个完整的硬盘, 必须进一步分区才能使用. 但每个扩 展分区中只能存在一个其他分区. 此分区在 DOS/Windows 环境中即为逻辑盘. 因此每一个扩展分区的分区表 (同样存储在扩展分区的第一个扇区中)中最多 只能有两个分区数据项(包括下一个扩展分区的数据项). 扩展分区和逻辑盘的示意图如下:

|-----------------------| -------- | 主扩展分区(/dev/hda2) | ^ |-----------------------| | | 扩 展 | 分区项 1 |--\ | | |------------| | | | 分区表 | 分区项 2 |--+--\ | |-----------------------| | | | | | | | | | 逻辑盘 1 (/dev/hda5) |<-/ | | | | | | |-----------------------| | 主 | 扩展分区 2 |<----/ |-----------------------| 扩 | 扩 展 | 分区项 1 |--\ | |------------| | 展 | 分区表 | 分区项 2 |--+--\ |-----------------------| | | 分 | | | | | 逻辑盘 2 (/dev/hda6) |<-/ | 区 | | | | |-----------------------| | | | 扩展分区 3 |<----/ | |-----------------------| | | 扩 展 | 分区项 1 |--\ | | |------------| | | | 分区表 | 分区项 2 | | | |-----------------------| | | | | | | | 逻辑盘 3 (/dev/hda7) |<-/ | | | |

|-----------------------| ---------

三. 系统启动过程简介

系统启动过程主要由一下几步组成(以硬盘启动为例):

1. 开机 :-) 2. BIOS 加电自检 ( Power On Self Test -- POST ) 内存地址为 0ffff:0000 3. 将硬盘第一个扇区 (0头0道1扇区, 也就是Boot Sector) 读入内存地址 0000:7c00 处. 4. 检查 (WORD) 0000:7dfe 是否等于 0xaa55, 若不等于 则转去尝试其他启动介质, 如果没有其他启动介质则显示 "No ROM BASIC" 然后死机. 5. 跳转到 0000:7c00 处执行 MBR 中的程序. 6. MBR 首先将自己复制到 0000:0600 处, 然后继续执行. 7. 在主分区表中搜索标志为活动的分区. 如果发现没有活动 分区或有不止一个活动分区, 则转停止. 8. 将活动分区的第一个扇区读入内存地址 0000:7c00 处. 9. 检查 (WORD) 0000:7dfe 是否等于 0xaa55, 若不等于则

显示 "Missing Operating System" 然后停止, 或尝试 软盘启动. 10. 跳转到 0000:7c00 处继续执行特定系统的启动程序. 11. 启动系统 ...

以上步骤中 2,3,4,5 步是由 BIOS 的引导程序完成. 6,7,8,9,10 步由MBR中的引导程序完成.

一般多系统引导程序 (如 SmartFDISK, BootStar, PQBoot 等) 都是将标准主引导记录替换成自己的引导程序, 在运行系统启动程序 之前让用户选择要启动的分区. 而某些系统自带的多系统引导程序 (如 lilo, NT Loader 等) 则可以将自己的引导程序放在系统所处分区的第一个扇区中, 在 Linux 中即为 SuperBlock (其实 SuperBlock 是两个扇区).

注: 以上各步骤中使用的是标准 MBR, 其他多系统引导程序的引导 过程与此不同.

第二部分 技术资料

第一章 扩展 Int13H 技术资料

一. 简介 设计扩展 Int13H 接口的目的是为了扩展 BIOS 的功能, 使其支持 多于1024柱面的硬盘, 以及可移动介质的琐定, 解锁及弹出等功能.

二. 数据结构

1. 数据类型约定 BYTE 1 字节整型 ( 8 位 ) WORD 2 字节整型 ( 16 位 ) DWORD 4 字节整型 ( 32 位 ) QWORD 8 字节整型 ( 64 位 )

2. 磁盘地址数据包 Disk Address Packet (DAP) DAP 是基于绝对扇区地址的, 因此利用 DAP, Int13H 可以轻松地逾 越 1024 柱面的限制, 因为它根本就不需要 CHS 的概念. DAP 的结构如下:

struct DiskAddressPacket { BYTE PacketSize; // 数据包尺寸(16字节) BYTE Reserved; // ==0 WORD BlockCount; // 要传输的数据块个数(以扇区为单位) DWORD BufferAddr; // 传输缓冲地址(segment:offset) QWORD BlockNum; // 磁盘起始绝对块地址 };

PacketSize 保存了 DAP 结构的尺寸, 以便将来对其进行扩充. 在 目前使用的扩展 Int13H 版本中 PacketSize 恒等于 16. 如果它小于 16, 扩展 Int13H 将返回错误码( AH=01, CF=1 ). BlockCount 对于输入来说是需要传输的数据块总数, 对于输出来说 是实际传输的数据块个数. BlockCount = 0 表示不传输任何数据块. BufferAddr 是传输数据缓冲区的 32 位地址 (段地址:偏移量). 数据 缓冲区必须位于常规内存以内(1M). BlockNum 表示的是从磁盘开始算起的绝对块地址(以扇区为单位), 与分区无关. 第一个块地址为 0. 一般来说, BlockNum 与 CHS 地址的关系 是: BlockNum = cylinder * NumberOfHeads + head * SectorsPerTrack + sector - 1;

其中 cylinder, head, sector 是 CHS 地址, NumberOfHeads 是磁盘 的磁头数, SectorsPerTrack 是磁盘每磁道的扇区数. 也就是说 BlockNum 是沿着 扇区->磁道->柱面 的顺序记数的. 这一顺 序是由磁盘控制器虚拟的, 磁盘表面数据块的实际排列顺序可能与此不同 (如为了提高磁盘速度而设置的间隔因子将会打乱扇区的排列顺序).

3. 驱动器参数数据包 Drive Parameters Packet 驱动器参数数据包是在扩展 Int13H 的取得驱动器参数子功能调用中 使用的数据包. 格式如下: struct DriveParametersPacket { WORD InfoSize; // 数据包尺寸 (26 字节) WORD Flags; // 信息标志 DWORD Cylinders; // 磁盘柱面数 DWORD Heads; // 磁盘磁头数 DWORD SectorsPerTrack; // 每磁道扇区数 QWORD Sectors; // 磁盘总扇区数 WORD SectorSize; // 扇区尺寸 (以字节为单位) }; 信息标志用于返回磁盘的附加信息, 每一位的定义如下:

0 位: 0 = 可能发生 DMA 边界错误 1 = DMA 边界错误将被透明处理 如果这位置 1, 表示 BIOS 将自动处理 DMA 边界错误, 也就是说 错误代码 09H 永远也不会出现.

1 位: 0 = 未提供 CHS 信息 1 = CHS 信息合法 如果块设备的传统 CHS 几何信息不适当的话, 该位将置 0.

2 位: 0 = 驱动器不可移动 1 = 驱动器可移动

3 位: 表示该驱动器是否支持写入时校验.

4 位: 0 = 驱动器不具备介质更换检测线 1 = 驱动器具备介质更换检测线

5 位: 0 = 驱动器不可锁定 1 = 驱动器可以锁定 要存取驱动器号大于 0x80 的可移动驱动器, 该位必须置 1 (某些驱动器号为 0 到 0x7F 的设备也需要置位)

6 位: 0 = CHS 值是当前存储介质的值 (仅对于可移动介质), 如果 驱动器中有存储介质, CHS 值将被返回. 1 = CHS 值是驱动器支持的最大值 (此时驱动器中没有介质).

7 - 15 位: 保留, 必须置 0.

三. 接口规范

1. 寄存器约定 在扩展 Int13H 调用中一般使用如下寄存器约定:

ds:di ==> 磁盘地址数据包( disk address packet ) dl ==> 驱动器号 ah ==> 功能代码 / 返回码

在基本 Int13H 调用中, 0 - 0x7F 之间的驱动器号代表可移动驱动器 0x80 - 0xFF 之间的驱动器号代表固定驱动器. 但在扩展 Int13H 调用中 0x80 - 0xFF 之间还包括一些新出现的可移动驱动器, 比如活动硬盘等. 这些驱动器支持先进的锁定,解锁等功能. ah 返回的错误码除了标准 Int13H 调用规定的基本错误码以外,又增加 了以下错误码:

B0h 驱动器中的介质未被锁定

B1h 驱动器中的介质已经锁定

B2h 介质是可移动的

B3h 介质正在被使用

B4h 锁定记数溢出

B5h 合法的弹出请求失败

2. API 子集介绍 1.x 版的扩展 Int13H 调用中规定了两个主要的 API 子集.

第一个子集提供了访问大硬盘所必须的功能, 包括 检查扩展 In13H 是否存在( 41h ), 扩展读( 42h ), 扩展写( 43h ), 校验扇区( 44h ), 扩展定位( 47h ) 和 取得驱动器参数( 48h ). 第二个子集提供了对软件控制驱动器锁定和弹出的支持, 包括 检查扩展 Int13H 是否存在( 41h ), 锁定/解锁驱动器( 45h ), 弹出驱动器( 46h ), 取得驱动器参数( 48h ), 取得扩展驱动器改变状态( 49h ), int 15h. 如果使用了调用规范中不支持的功能, BIOS 将返回错误码 ah = 01h, CF = 1.

3. API 详解

1) 检验扩展功能是否存在 入口: AH = 41h BX = 55AAh DL = 驱动器号

返回: CF = 0 AH = 扩展功能的主版本号 AL = 内部使用 BX = AA55h CX = API 子集支持位图 CF = 1 AH = 错误码 01h, 无效命令

这个调用检验对特定的驱动器是否存在扩展功能. 如果进位标志置 1 则此驱动器不支持扩展功能. 如果进位标志为 0, 同时 BX = AA55h, 则 存在扩展功能. 此时 CX 的 0 位表示是否支持第一个子集, 1位表示是否 支持第二个子集. 对于 1.x 版的扩展 Int13H 来说, 主版本号 AH = 1. AL 是副版本号, 但这仅限于 BIOS 内部使用, 任何软件不得检查 AL 的值.

2) 扩展读 入口: AH = 42h DL = 驱动器号 DS:DI = 磁盘地址数据包(Disk Address Packet)

返回: CF = 0, AH = 0 成功 CF = 1, AH = 错误码

这个调用将磁盘上的数据读入内存. 如果出现错误, DAP 的 BlockCount 项中则记录了出错前实际读取的数据块个数.

3) 扩展写 入口: AH = 43h AL 0 位 = 0 关闭写校验 1 打开写校验 1 - 7 位保留, 置 0 DL = 驱动器号 DS:DI = 磁盘地址数据包(DAP) 返回: CF = 0, AH = 0 成功 CF = 1, AH = 错误码

这个调用将内存中的数据写入磁盘. 如果打开了写校验选项, 但 BIOS 不支持, 则会返回错误码 AH = 01h, CF = 1. 功能 48h 可以检测BIOS是否 支持写校验. 如果出现错误, DAP 的 BlockCount 项中则记录了出错前实际写入的数 据块个数.

4) 校验扇区 入口: AH = 44h DL = 驱动器号 DS:DI = 磁盘地址数据包(Disk Address Packet)

返回: CF = 0, AH = 0 成功 CF = 1, AH = 错误码

这个调用校验磁盘数据, 但并不将数据读入内存.如果出现错误, DAP 的 BlockCount 项中则记录了出错前实际校验的数据块个数.

5) 锁定/解锁驱动器 入口: AH = 45h AL = 0 锁定驱动器 = 1 驱动器解锁 = 02 返回锁定/解锁状态 = 03h-FFh - 保留 DL = 驱动器号

返回: CF = 0, AH = 0 成功 CF = 1, AH = 错误码

这个调用用来缩定指定驱动器中的介质. 所有标号大于等于 0x80 的可移动驱动器必须支持这个功能. 如果 在支持可移动驱动器控制功能子集的固定驱动器上使用这个功能调用, 将 会成功返回. 驱动器必须支持最大255次锁定, 在所有锁定被解锁之前, 不能在物理上 将驱动器解锁. 解锁一个未锁定的驱动器,将返回错误码 AH= B0h. 如果锁定一 个已锁定了255次的驱动器, 将返回错误码 AH = B4h. 锁定一个没有介质的驱动器是合法的.

6) 弹出可移动驱动器中的介质 入口: AH = 46h AL = 0 保留 DL = 驱动器号

返回: CF = 0, AH = 0 成功 CF = 1, AH = 错误码

这个调用用来弹出指定的可移动驱动器中的介质. 所有标号大于等于 0x80 的可移动驱动器必须支持这个功能. 如果 在支持可移动驱动器控制功能子集的固定驱动器上使用这个功能调用, 将 会返回错误码 AH = B2h (介质不可移动). 如果试图弹出一个被锁定的介质 将返回错误码 AH = B1h (介质被锁定). 如果试图弹出一个没有介质的驱动器, 则返回错误码 Ah = 31h (驱动器 中没有介质). 如果试图弹出一个未锁定的可移动驱动器中的介质, Int13h会调用 Int15h (AH = 52h) 来检查弹出请求能否执行. 如果弹出请求被拒绝则返回错误码(同 Int15h). 如果弹出请求被接受,但出现了其他错误, 则返回错误码 AH = B5h.

7) 扩展定位 入口: AH = 47h DL = 驱动器号 DS:DI = 磁盘地址数据包(Disk Address Packet)

返回: CF = 0, AH = 0 成功 CF = 1, AH = 错误码

这个调用将磁头定位到指定扇区.

8) 取得驱动器参数 入口: AH = 48h DL = 驱动器号 DS:DI = 返回数据缓冲区地址

返回: CF = 0, AH = 0 成功 DS:DI 驱动器参数数据包地址, (参见前面的文章) CF = 1, AH = 错误码

这个调用返回指定驱动器的参数.

9) 取得扩展驱动器介质更换检测线状态 入口: AH = 49h DL = 驱动器号

返回: CF = 0, AH = 0 介质未更换 CF = 1, AH = 06h 介质可能已更换

这个调用返回指定驱动器的介质更换状态. 这个调用与 Int13h AH = 16h 子功能调用相同, 只是允许任何驱动器 标号. 如果对一台支持可移动介质功能子集的固定驱动器使用此功能,则永远 返回 CF = 0, AH = 0. 简单地将可移动介质锁定再解锁就可以激活检测线, 而无须真正更换介质.

10) Int 15h 可移动介质弹出支持 入口: AH = 52h DL = 驱动器号 返回: CF = 0, AH = 0 弹出请求可能可以执行 CF = 1, AH = 错误码 B1h 或 B3h 弹出请求不能执行

这个调用是由 Int13h AH=46h 弹出介质功能调用内部使用的.

=================================

crshen网友提供的第一个版本的自动备份和恢复硬盘分区表的C源程序:

[code] #include <stdio.h> #include <bios.h>

#define READ 2 #define WRITE 3

void ShowHelp() { printf("\nHD SECTOR BACKUP & RESTORE TOOLS by CRSHEN\n\n\ Usage: hdsect.exe drive head track sector filename parameter\n\ drive: 1=first HD 2=second HD and so on\n\ head track sector MUST be integer\n\ parameter: /b means backup /r means restore, *case sensitive*\n"); }

void main(int argc,char *argv[]) { int drive=0x80,head=0,track=0,sector=1,nsects=1; unsigned char buf[512]; FILE *fp;

drive=0x80+atoi(argv[1])-1; head=atoi(argv[2]); track=atoi(argv[3]); sector=atoi(argv[4]);

if (argc!=7) { ShowHelp(); exit(2); } if (strcmp(argv[6],"/b")==0) { if (biosdisk(READ,drive,head,track,sector,nsects,buf)) { printf("Failed to read from sector !\n"); exit(1); } if ((fp=fopen(argv[5],"wb"))!=NULL) { fwrite(buf,512,1,fp); fclose(fp); printf("Backup sector to file %s done !\n",argv[5]); exit(0); } else { printf("Open File %s Failed !\n",argv[5]); exit(1); } } if (strcmp(argv[6],"/r")==0) { if ((fp=fopen(argv[5],"rb"))!=NULL) { fread(buf,512,1,fp); fclose(fp); } else { printf("Open File %s Failed !\n",argv[5]); exit(1); } if (biosdisk(WRITE,drive,head,track,sector,nsects,buf)) { printf("Failed to write to sector !\n"); exit(1); } else { printf("Restore sector from file %s done !",argv[5]); exit(0); } } } [/code]

=================================================

crshen网友提供的第二个版本的自动备份和恢复硬盘分区表的C源程序:
以下内容为程序代码:

#include <stdio.h>
#include <bios.h>
#include <dos.h> 

#define READ 2
#define WRITE 3
#define READ_EXT 0x42
#define WRITE_EXT 0x43
#define HD1st 0x80

void ShowHelp();
/*显示帮助信息*/

short _diskop (unsigned char drv, unsigned char cmd,unsigned char verify,unsigned char * buffer, unsigned long startlow, unsigned short copyblks);
/*采用扩展int 13读写扇区*/

short _OldINT13(unsigned char cmd,unsigned char * buffer,unsigned char drv,unsigned char head,unsigned char sector,unsigned char cylinder);
/*老的int 13中断读写扇区,兼容旧机子*/

long cal_add(FILE *fp, int ignore);
/*累加法校验文件*/

void main(int argc,char *argv[])
{
  unsigned char buf[512],tempbuf[512];
  unsigned long StartSector;
  long add;
  int ch,mark,test;
  FILE *fp;

  if (argc!=3)
  {
    ShowHelp();
    exit(6);             /*返回6,帮助信息*/
  }
  /*下面为备份分区信息*/
  if (strcmp(argv[1],"/backup")==0)
  {
    if (biosdisk(READ,HD1st,0,0,1,1,buf))
    {
        printf("Failed to read from sector 0!\n");
        exit(3);           /*返回3,读0扇区出错*/
    }
    if ((fp=fopen(argv[2],"wb"))!=NULL)
        fwrite(buf,512,1,fp);
    else
    {
        printf("Failed to creat file:%s\n",argv[2]);
        exit(1);           /*返回1,磁盘写保护?*/
    }
    for (mark=450;buf[mark]!=0 && mark<512;mark+=16)
    {
        StartSector=buf[mark+7]*16777216L+buf[mark+6]*65536L+buf[mark+5]*256L+buf[mark+4];
        test=_diskop (HD1st, READ_EXT, 0, tempbuf, StartSector, 1);
        if (test!=0)
      {
          printf("READ_EXT ERROR Number: %d\n",test);       /*查看出错信息代码*/
          _OldINT13(READ,tempbuf,HD1st,buf[mark-3],buf[mark-2],buf[mark-1]); /*出错可能为主板不支持扩展int 13,改用老的int 13*/
      }
        fwrite(tempbuf,512,1,fp);
    }
    fclose(fp);

    fp=fopen(argv[2],"ab+");       /*在文件尾部写入校验信息*/
    add=cal_add(fp, 0);
    fseek(fp,0L,SEEK_END);
    ch=add&0xFF;
    fputc(ch,fp);
    add/=0x100;
    ch=add&0xFF;
    fputc(ch,fp);       /*校验信息为文件字节累积和的低4位*/
    fclose(fp);
    exit(0);       /*返回0,操作成功*/
  }
  /*下面为恢复分区信息*/
  if (strcmp(argv[1],"/restore")==0)
  {
    if ((fp=fopen(argv[2],"rb"))!=NULL)
    {
        add=cal_add(fp, 2);
        fseek(fp,-2L,SEEK_END);
        ch=add&0xFF;
        if (ch!=fgetc(fp))         /*首先校验文件正确性*/
      {
          printf("File %s may be wrong !\n",argv[2]);
          exit(5);     /*返回5,文件校验出错*/
      }
        add/=0x100;
        ch=add&0xFF;
        if (ch!=fgetc(fp))
      {
          printf("File %s may be wrong !\n",argv[2]);
          exit(5);
      }
        rewind(fp);
        fread(buf,512,1,fp);
    }
    else
    {
        printf("Failed to open file:%s\n",argv[2]);
        exit(2);     /*返回2,备份文件不存在*/
    }
    if (biosdisk(WRITE,HD1st,0,0,1,1,buf))
    {
        printf("Failed to write to sector 0!\n");
        exit(4);     /*返回4,写扇区0出错*/
    }
    for (mark=450;buf[mark]!=0 && mark<512;mark+=16)
    {
        fread(tempbuf,512,1,fp);
        StartSector=buf[mark+7]*16777216L+buf[mark+6]*65536L+buf[mark+5]*256L+buf[mark+4];
        /*printf("Write sector...\n");*/
        /**/
        test=_diskop (HD1st, WRITE_EXT, 1, tempbuf, StartSector, 1);
        if (test!=0)   /*写扇区出错*/
      {
          test=_diskop (HD1st, WRITE_EXT, 2, tempbuf, StartSector, 1);
          if (test==1)   /*校验与不校验下,两种写入方式均提示invalid function,考虑为主板不支持扩展int 13*/
            _OldINT13(WRITE,tempbuf,HD1st,buf[mark-3],buf[mark-2],buf[mark-1]);
      }
    }
    fclose(fp);
    exit(0);       /*返回0,操作成功*/
  }
  /*下面为重新设置文件校验值*/
  if (strcmp(argv[1],"/checksum")==0)
  if ((fp=fopen(argv[2],"rb+"))!=NULL)
  {
    add=cal_add(fp, 2);
    fseek(fp,-2L,SEEK_END);
    if (fgetc(fp)==0x55 && fgetc(fp)==0xAA)
        printf("Can not checksum of this file (end of 55AA)\n");
    else
    {
        fseek(fp,-2L,SEEK_END);
        ch=add&0xFF;
        fputc(ch,fp);
        add/=0x100;
        ch=add&0xFF;
        fputc(ch,fp);
        fclose(fp);
        printf("Re_Check file: %s done\n",argv[2]);
    }
  }
  else
  {
    printf("Failed to open file:%s\n",argv[2]);
    exit(2);
  }
}

short _OldINT13(unsigned char cmd,unsigned char * buffer,unsigned char drv,unsigned char head,unsigned char sector,unsigned char cylinder)
{
  asm push ds
    asm mov ah,cmd
    asm mov al,1h
    asm mov bx,buffer
    asm mov ch,cylinder
    asm mov cl,sector
    asm mov dh,head
    asm mov dl,drv
    asm int 13h
    asm pop ds
    asm jc error
    return (1);
  error:
    return (-1);
}

short _diskop (unsigned char drv, unsigned char cmd,unsigned char verify,unsigned char * buffer, unsigned long startlow, unsigned short copyblks)
{   /* 磁盘存取数据包结构 */
  struct disk_address_packet
  {
    unsigned char size_of_packet;
    unsigned char reserved;
    unsigned short number_of_blocks_to_transfer;
    unsigned short transfer_buffer_offset;
    unsigned short transfer_buffer_segment;
    unsigned long starting_absolute_block_low;
    unsigned long starting_absolute_block_high;
  };
  struct disk_address_packet dap;
  unsigned char av;
  unsigned char * pt = (unsigned char *) &dap;
  dap.size_of_packet = sizeof (dap);
  dap.reserved = 0;
  dap.number_of_blocks_to_transfer = copyblks;
  dap.transfer_buffer_offset = FP_OFF(buffer);
  dap.transfer_buffer_segment = FP_SEG(buffer);
  dap.starting_absolute_block_low = startlow;
  dap.starting_absolute_block_high = 0; /* 忽略高位 */

  asm push ds
    asm push si
    asm mov ah, cmd
    asm mov al,verify
    asm mov dl, drv
    asm lds si, DWORD PTR pt
    asm int 13h
    asm pop si
    asm pop ds
    asm mov av, ah
    asm jc error
  /*return (dap.number_of_blocks_to_transfer); 返回成功读写的扇区数目*/
    return(0);
  error:
  /*ErrorNum = av;出错信息代码*/
    return (av);
}

long cal_add(FILE *fp, int ignore)
{
  long filelength,add=0;
  fseek(fp,0L,SEEK_END);
  filelength=ftell(fp)-ignore;
  rewind(fp);
  while (filelength--!=0)
    add+=fgetc(fp);   /*文件字节累积求和*/
  return(add);
}

void ShowHelp()
{
  printf("\n=== PATITION TABLE BACKUP & RESTORE TOOLS by CRSHEN ===\n\n\
  Usage: patition.exe </backup|/restore|/checksum> filename\n");
}

----------------------

from http://nufans.net/dvbbs/dispbbs.asp?boardID=1&ID=544&page=3