- 前言
- 为什么要开发适用早期LTO磁带驱动器的LTFS?
- 什么是LTO?
- LTO历代容量变化
- 获取磁带驱动器信息
- CreateFile打开设备
- 使用GetTapeStatus
- 使用GetTapeParameters
- 如何使用GetTapePosition获得磁带所在地址?
- 磁带驱动器的操作
- PrepareTape执行基本操作
- 使用EraseTape擦除部分或全部磁带的数据
- CreateTapePartition函数重新格式化磁带
- SetTapeParameters函数使用
- 使用SetTapePosition将磁带移到指定位置
- 读写磁带操作
- WriteFile/BackupWrite函数
- ReadFile/BackupRead函数
- 真正设计LTFS!
- 创建环境
- 窗口设计
- 代码部分
- 测试
- 程序、源码下载地址
作者B站这里
为什么要开发适用早期LTO磁带驱动器的LTFS?存储媒体的种类十分丰富,有我们常见的硬盘、逐渐淘汰的软盘和光盘、和企业服务器备份用的磁带。磁带的类型有很多:主流的LTO磁带、DAT320/160磁带、DSS、DLT、SDLT等类型。市面上也有针对家用的磁带驱动器,逐渐淘汰了较老的SCSI接口。但是,由于预算的不足,资金不够,以及平台不同,我们很难buy到最新的磁带驱动器,只能使用较老型号、容量较小的驱动器。但是只有专业的备份软件才能够对磁带进行读写,非常麻烦。LTFS解决了这个问题,它可以把磁带变得像U盘、硬盘一样访问,十分方便。但也有许多缺点,其中最致命的是LTFS最低只支持LTO5代驱动器,这意味着LTO4代及以前版本无法使用LTFS,即便是二手的LTO5代及以上驱动器价格也十分昂贵,对于学生来说,消费不起,只能使用较老型号、容量较小的驱动器。为了方便读写和更多人的方便,因此,作者开发了这么一款软件。
什么是LTO?LTO(Linear Tape Open,线性磁带开放协议)是一种结合了线性多通道双向磁带格式的磁带存储技术,其优点主要是将服务系统、硬件数据压缩、优化磁道面、高效纠错技术和提高磁带容量性能等结合于一体。LTO是一种开放格式技术,用户可拥有多项产品和多规格存储介质,还可提高产品的兼容性和延续性。
—资料来源于这里!
LTO历代容量变化| LTO代数 | 容量 | 压缩比 |
|---|---|---|
| LTO1 | 100GB:200GB | 2:1 |
| LTO2 | 200GB:400GB | 2:1 |
| LTO3 | 400GB:800GB | 2:1 |
| LTO4 | 800GB:1.6TB | 2:1 |
| LTO5 | 1.5TB:3TB | 2:1 |
| LTO6 | 2.5TB:6.25TB | 2.5:1 |
| LTO7 | 6TB:15TB | 2.5:1 |
| LTO8 | 12TB:30TB | 2.5:1 |
| LTO9 | 18TB:45:TB | 2.5:1 |
让我们来看看CreateFile函数的定义! fileapi.h:
HANDLE CreateFileW( [in] LPCWSTR lpFileName, [in] DWORD dwDesiredAccess, [in] DWORD dwShareMode, [in, optional] LPSECURITY_ATTRIBUTES lpSecurityAttributes, [in] DWORD dwCreationDisposition, [in] DWORD dwFlagsAndAttributes, [in, optional] HANDLE hTemplateFile );
参数
[in] lpFileName
要创建或打开的文件或设备的名称。您可以在此名称中使用正斜杠 (/) 或反斜杠 (“”)。
在此函数的 ANSI 版本中,名称仅限于MAX_PATH字符。要将此限制扩展到 32,767 个宽字符,请使用此 Unicode 版本的函数并在路径前添加“\?”。有关详细信息,请参阅命名文件、路径和命名空间。
有关特殊设备名称的信息,请参阅 定义 MS-DOS 设备名称。
要创建文件流,请指定文件名、冒号,然后是流的名称。有关详细信息,请参阅文件流。
对文件或设备的请求访问,可以概括为读、写、两者或都不为零)。
最常用的值是GENERIC_READ、 GENERIC_WRITE或两者兼有 ( GENERIC_READ | GENERIC_WRITE)。有关详细信息,请参阅 通用访问权限、 文件安全和访问权限、 文件访问权限常量和 ACCESS_MASK。
如果此参数为零,则应用程序可以查询某些元数据,例如文件、目录或设备属性,而无需访问该文件或设备,即使GENERIC_READ访问已被拒绝。
您不能请求与 已具有打开句柄的打开请求中的dwShareMode参数指定的共享模式冲突的访问模式。
| 设备 | 用来打开设备的函数 |
|---|---|
| 文件 | CreateFile(lpFileName为路径名或UNC路径名) |
| 目录 | CreateFile(lpFileName为路径名或UNC路径名) 如果在调用CreateFile的时候指定FILE_FLAG_BACKUP_SEMANTICS标识,那么Windows允许我们打开一个目录,打开目录使我们能够改变路径的属性 |
| 逻辑磁盘驱动器 | CreateFile(lpFileName为"\.x:“。如果指定的字串符是”\.x:"的形式,那么Windows允许我们打开一个逻辑磁盘驱动器,其中的x是驱动器的盘符。打开驱动器使我们能够格式化驱动器或检测驱动器媒介的大小。 |
| 物理磁盘驱动器 | CCreateFile(lpFileName为"\.PHYSICALDRIVEx"。如果我们指定"\.PHYSICALDRIVEx"的形式,那么Windows允许我们打开一个物理磁盘驱动器。注意,打开物理磁盘驱动器使我们能直接访问硬盘的分区表,有潜在的危险,错误的写入设备可能会导致操作系统的文件系统无法访问磁盘的内容!!! |
| 串口 | CreateFile(lpFileName为"COMx") |
| 并口 | CreateFIle(lpFileName为"LPTx") |
| … | 上网查找详细资料 |
[in] dwShareMode
文件或设备请求的共享模式,可以是read、write、both、delete、all these或none(参考下表)。对属性或扩展属性的访问请求不受此标志的影响。
如果此参数为零且CreateFile成功,则无法共享文件或设备,并且在关闭文件或设备的句柄之前无法再次打开。有关详细信息,请参阅备注部分。
您不能请求与具有打开句柄的现有请求中指定的访问模式冲突的共享模式。CreateFile将失败,GetLastError函数将返回 ERROR_SHARING_VIOLATION。
要使一个进程能够在另一个进程打开文件或设备时共享文件或设备,请使用以下一个或多个值的兼容组合。有关此参数与dwDesiredAccess参数的有效组合的更多信息,请参阅 创建和打开文件。
注意 每个打开的句柄的共享选项在该句柄关闭之前一直有效,无论进程上下文如何。
如果未指定此标志,但已打开文件或设备以进行写访问或具有具有写访问权限的文件映射,则该函数将失败。
[in, optional] lpSecurityAttributes
一个指向SECURITY_ATTRIBUTES 结构的指针,该结构包含两个独立但相关的数据成员:一个可选的安全描述符和一个布尔值,用于确定返回的句柄是否可以被子进程继承。
此参数可以为NULL。
如果此参数为NULL ,则CreateFile返回的句柄 不能被应用程序可能创建的任何子进程继承,并且与返回的句柄关联的文件或设备将获得默认的安全描述符。
结构的lpSecurityDescriptor成员为文件或设备指定 SECURITY_DESCRIPTOR。如果此成员为NULL,则为与返回句柄关联的文件或设备分配一个默认安全描述符。
CreateFile在打开现有文件或设备时忽略 lpSecurityDescriptor成员,但继续使用bInheritHandle成员。
结构的bInheritHandle成员指定返回的句柄是否可以被继承。
有关详细信息,请参阅备注部分。
[in] dwCreationDisposition
对存在或不存在的文件或设备执行的操作。
对于文件以外的设备,此参数通常设置为OPEN_EXISTING。
调用进程必须打开文件,并将GENERIC_WRITE位设置为dwDesiredAccess参数的一部分。
[in] dwFlagsAndAttributes
文件或设备属性和标志,FILE_ATTRIBUTE_NORMAL是文件最常见的默认值。
此参数可以包括可用文件属性 ( FILE_ATTRIBUTE_* ) 的任意组合。所有其他文件属性覆盖 FILE_ATTRIBUTE_NORMAL。
此参数还可以包含标志组合(FILE_FLAG_) 用于控制文件或设备缓存行为、访问模式和其他特殊用途的标志。这些与任何 FILE_ATTRIBUTE_值结合。
通过指定SECURITY_SQOS_PRESENT标志,此参数还可以包含安全服务质量 (SQOS) 信息 。其他与 SQOS 相关的标志信息显示在属性和标志表之后的表格中。
注意 当CreateFile打开一个现有文件时,它通常将文件标志与现有文件的文件属性结合起来,并忽略作为dwFlagsAndAttributes一部分提供的任何文件属性。特殊情况在 创建和打开文件中有详细说明。
以下某些文件属性和标志可能仅适用于文件,不一定适用于CreateFile可以打开的所有其他类型的设备。有关其他信息,请参阅本主题的备注部分和 创建和打开文件。
有关对文件属性的更高级访问,请参阅 SetFileAttributes。有关所有文件属性及其值和描述的完整列表,请参阅 文件属性常量。
[in, optional] hTemplateFile
具有GENERIC_READ访问权限的模板文件的有效句柄。模板文件为正在创建的文件提供文件属性和扩展属性。
此参数可以为NULL。
打开现有文件时,CreateFile 会忽略此参数。
当打开一个新的加密文件时,该文件从其父目录继承自由访问控制列表。有关其他信息,请参阅 文件加密。
—材料摘自这里!
其中,第一个参数传入设备的名称,因此传入"\\.\TAPE0",其中TAPE0代表此电脑的第一个磁带驱动器,有需求的话可以改变此参数。
第二个参数传入文件或设备请求的共享模式,因为我们需要对磁带进行读写,所以我们传入GENERIC_READ | GENERIC_WRITE
打开磁带设备的方法,如果要打开的设备为TAPE0时:
HANDLE hTape=CreateFile(TEXT("\\.\TAPE0"),GENERIC_READ | GENERIC_WRITE,0,0,OPEN_EXISTING,0,NULL);
如果函数成功,则返回值是指定文件、设备、命名管道或邮槽的打开句柄。
如果函数失败,则返回值为INVALID_HANDLE_VALUE。要获取扩展的错误信息,请调用GetLastError。
GetTapeStatus 函数确定磁带设备是否准备好处理磁带命令。
句法:
DWORD GetTapeStatus( [in] HANDLE hDevice );
[in] hDevice
要获取其设备状态的设备的句柄。此句柄是使用 CreateFile函数创建的。
此函数的参数非常简单,把磁带驱动器的设备句柄传入即可。
返回值如下:
如果磁带设备准备好接受适当的磁带访问命令而不返回错误,则返回值为 NO_ERROR。
| 错误代码 | 描述 |
|---|---|
| ERROR_BEGINNING_OF_MEDIA | 在媒体开始标记之前访问数据的尝试失败。 |
| ERROR_BUS_RESET | 在总线上检测到复位条件。 |
| ERROR_DEVICE_NOT_PARTITIONED | 加载磁带时找不到分区信息。 |
| ERROR_DEVICE_REQUIRES_CLEANING | 磁带机能够报告它需要清洁,并报告它确实需要清洁。 |
| ERROR_END_OF_MEDIA | 在手术过程中到达磁带末端标记。 |
| ERROR_FILEMARK_DETECTED | 操作期间到达文件标记。 |
| ERROR_INVALID_BLOCK_LENGTH | 多卷分区中的新磁带上的块大小不正确。 |
| ERROR_MEDIA_CHANGED | 驱动器中的磁带已被更换或移除。 |
| ERROR_NO_DATA_DETECTED | 在操作期间到达数据结束标记。 |
| ERROR_NO_MEDIA_IN_DRIVE | 驱动器中没有媒体。 |
| ERROR_NOT_SUPPORTED | 磁带驱动程序不支持请求的功能。 |
| ERROR_PARTITION_FAILURE | 无法对磁带进行分区。 |
| ERROR_SETMARK_DETECTED | 在操作期间达到了设定标记。 |
| ERROR_UNABLE_TO_LOCK_MEDIA | 尝试锁定弹出机制失败。 |
| ERROR_UNABLE_TO_UNLOAD_MEDIA | 卸载磁带的尝试失败。 |
| ERROR_WRITE_PROTECT | 媒体是写保护的。 |
GetTapeParameters函数检索描述磁带或磁带驱动器的信息。
句法:
DWORD GetTapeParameters( [in] HANDLE hDevice, [in] DWORD dwOperation, [out] LPDWORD lpdwSize, [out] LPVOID lpTapeInformation );
[in] hDevice
处理寻求有关其信息的设备。此句柄是使用 CreateFile函数创建的。
[in] dwOperation
请求的信息类型。此参数必须是以下值之一。
[out] lpdwSize
指向一个变量的指针,该变量接收由lpTapeInformation参数指定的缓冲区大小(以字节为单位)。如果缓冲区太小,则此参数接收所需的大小。
[out] lpTapeInformation
指向包含所请求信息的结构的指针。如果dwOperation参数是GET_TAPE_MEDIA_INFORMATION,lpTapeInformation指向一个 TAPE_GET_MEDIA_PARAMETERS结构。
如果dwOperation是GET_TAPE_DRIVE_INFORMATION,lpTapeInformation指向一个 TAPE_GET_DRIVE_PARAMETERS结构。
| 价值 | 意义 |
|---|---|
| GET_TAPE_DRIVE_INFORMATION | 检索有关磁带设备的信息。 |
| GET_TAPE_MEDIA_INFORMATION | 检索有关磁带设备中磁带的信息。 |
返回值:
如果函数成功,则返回值为NO_ERROR。
如果函数失败,它可以返回以下错误代码之一。
| 错误代码 | 描述 |
|---|---|
| ERROR_BEGINNING_OF_MEDIA | 在媒体开始标记之前访问数据的尝试失败。 |
| ERROR_BUS_RESET | 在总线上检测到复位条件。 |
| ERROR_DEVICE_NOT_PARTITIONED | 加载磁带时找不到分区信息。 |
| ERROR_DEVICE_REQUIRES_CLEANING | 磁带机能够报告它需要清洁,并报告它确实需要清洁。 |
| ERROR_END_OF_MEDIA | 在手术过程中到达磁带末端标记。 |
| ERROR_FILEMARK_DETECTED | 操作期间到达文件标记。 |
| ERROR_INVALID_BLOCK_LENGTH | 多卷分区中的新磁带上的块大小不正确。 |
| ERROR_MEDIA_CHANGED | 驱动器中的磁带已被更换或移除。 |
| ERROR_NO_DATA_DETECTED | 在操作期间到达数据结束标记。 |
| ERROR_NO_MEDIA_IN_DRIVE | 驱动器中没有媒体。 |
| ERROR_NOT_SUPPORTED | 磁带驱动程序不支持请求的功能。 |
| ERROR_PARTITION_FAILURE | 无法对磁带进行分区。 |
| ERROR_SETMARK_DETECTED | 在操作期间达到了设定标记。 |
| ERROR_UNABLE_TO_LOCK_MEDIA | 尝试锁定弹出机制失败。 |
| ERROR_UNABLE_TO_UNLOAD_MEDIA | 卸载磁带的尝试失败。 |
| ERROR_WRITE_PROTECT | 媒体是写保护的。 |
GetTapePosition函数以逻辑或绝对块的 形式检索磁带的当前地址。
句法:
DWORD GetTapePosition( [in] HANDLE hDevice, [in] DWORD dwPositionType, [out] LPDWORD lpdwPartition, [out] LPDWORD lpdwOffsetLow, [out] LPDWORD lpdwOffsetHigh );
[in] hDevice
处理获取磁带位置的设备。此句柄是使用 CreateFile 创建的。
[in] dwPositionType
要获取的地址类型。此参数可以是以下值之一。
| 价值 | 意义 |
|---|---|
| TAPE_ABSOLUTE_POSITION | lpdwOffsetLow和lpdwOffsetHigh参数接收设备特定的块地址。dwPartition参数接收零。 |
| TAPE_LOGICAL_POSITION | lpdwOffsetLow和lpdwOffsetHigh参数接收逻辑块地址。dwPartition参数接收逻辑磁带分区。 |
[out] lpdwPartition
指向接收当前磁带分区号的变量的指针。分区在逻辑上从 1 到 n 编号,其中 1 是磁带上的第一个分区,n 是最后一个分区。当检索到特定于设备的块地址时,或者如果设备仅支持一个分区,则此参数接收零。
[out] lpdwOffsetLow
指向一个变量的指针,该变量接收当前磁带位置的低位。
[out] lpdwOffsetHigh
指向一个变量的指针,该变量接收当前磁带位置的高位。如果不需要高位,则此参数可以为NULL 。
返回值:
如果函数成功,则返回值为 NO_ERROR。
如果函数失败,它可以返回以下错误代码之一。
| 错误代码 | 描述 |
|---|---|
| ERROR_BEGINNING_OF_MEDIA | 在媒体开始标记之前访问数据的尝试失败。 |
| ERROR_BUS_RESET | 在总线上检测到复位条件。 |
| ERROR_DEVICE_NOT_PARTITIONED | 加载磁带时找不到分区信息。 |
| ERROR_DEVICE_REQUIRES_CLEANING | 磁带机能够报告它需要清洁,并报告它确实需要清洁。 |
| ERROR_END_OF_MEDIA | 在手术过程中到达磁带末端标记。 |
| ERROR_FILEMARK_DETECTED | 操作期间到达文件标记。 |
| ERROR_INVALID_BLOCK_LENGTH | 多卷分区中的新磁带上的块大小不正确。 |
| ERROR_MEDIA_CHANGED | 驱动器中的磁带已被更换或移除。 |
| ERROR_NO_DATA_DETECTED | 在操作期间到达数据结束标记。 |
| ERROR_NO_MEDIA_IN_DRIVE | 驱动器中没有媒体。 |
| ERROR_NOT_SUPPORTED | 磁带驱动程序不支持请求的功能。 |
| ERROR_PARTITION_FAILURE | 无法对磁带进行分区。 |
| ERROR_SETMARK_DETECTED | 在操作期间达到了设定标记。 |
| ERROR_UNABLE_TO_LOCK_MEDIA | 尝试锁定弹出机制失败。 |
| ERROR_UNABLE_TO_UNLOAD_MEDIA | 卸载磁带的尝试失败。 |
| ERROR_WRITE_PROTECT | 媒体是写保护的。 |
PrepareTape函数准备要访问或删除的磁带。
句法:
DWORD PrepareTape( [in] HANDLE hDevice, [in] DWORD dwOperation, [in] BOOL bImmediate );
[in] hDevice
处理准备磁带的设备。此句柄是使用 CreateFile函数创建的。
[in] dwOperation
磁带设备准备。此参数可以是以下值之一。
| 价值 | 意义 |
|---|---|
| TAPE_FORMAT | 执行磁带的低级格式化。目前,只有 QIC117 器件支持此功能。 |
| TAPE_LOAD | 加载磁带并将磁带移动到开头。 |
| TAPE_LOCK | 锁定磁带弹出机构,使磁带不会意外弹出。 |
| TAPE_TENSION | 通过将磁带移动到磁带的末端并回到开头来调整张力。并非所有设备都支持此选项。如果不支持,则忽略此值。 |
| TAPE_UNLOAD | 将磁带移到开头以便从设备中移除。成功卸载操作后,设备会向尝试访问磁带的应用程序返回错误,直到再次加载磁带。 |
| TAPE_UNLOCK | 解锁磁带弹出机制。 |
[in] bImmediate
如果此参数为TRUE,则函数立即返回。如果为FALSE,则该函数在操作完成之前不会返回。
返回值:
如果函数成功,则返回值为 NO_ERROR。
如果函数失败,它可以返回以下错误代码之一。
| 错误代码 | 描述 |
|---|---|
| ERROR_BEGINNING_OF_MEDIA | 在媒体开始标记之前访问数据的尝试失败。 |
| ERROR_BUS_RESET | 在总线上检测到复位条件。 |
| ERROR_DEVICE_NOT_PARTITIONED | 加载磁带时找不到分区信息。 |
| ERROR_DEVICE_REQUIRES_CLEANING | 磁带机能够报告它需要清洁,并报告它确实需要清洁。 |
| ERROR_END_OF_MEDIA | 在手术过程中到达磁带末端标记。 |
| ERROR_FILEMARK_DETECTED | 操作期间到达文件标记。 |
| ERROR_INVALID_BLOCK_LENGTH | 多卷分区中的新磁带上的块大小不正确。 |
| ERROR_MEDIA_CHANGED | 驱动器中的磁带已被更换或移除。 |
| ERROR_NO_DATA_DETECTED | 在操作期间到达数据结束标记。 |
| ERROR_NO_MEDIA_IN_DRIVE | 驱动器中没有媒体。 |
| ERROR_NOT_SUPPORTED | 磁带驱动程序不支持请求的功能。 |
| ERROR_PARTITION_FAILURE | 无法对磁带进行分区。 |
| ERROR_SETMARK_DETECTED | 在操作期间达到了设定标记。 |
| ERROR_UNABLE_TO_LOCK_MEDIA | 尝试锁定弹出机制失败。 |
| ERROR_UNABLE_TO_UNLOAD_MEDIA | 卸载磁带的尝试失败。 |
| ERROR_WRITE_PROTECT | 媒体是写保护的。 |
EraseTape功能擦除磁带的 全部或部分内容。
句法:
DWORD EraseTape( [in] HANDLE hDevice, [in] DWORD dwEraseType, [in] BOOL bImmediate );
[in] hDevice
处理要擦除磁带的设备。此句柄是使用 CreateFile函数创建的。
[in] dwEraseType
擦除技术。此参数可以是以下值之一。
| 价值 | 意义 |
|---|---|
| TAPE_ERASE_LONG | 将磁带从当前位置擦除到当前分区的末尾。 |
| TAPE_ERASE_SHORT | 在当前位置写入擦除间隙或数据结束标记。 |
[in] bImmediate
如果此参数为TRUE,则函数立即返回;如果为FALSE,则函数在擦除操作完成之前不会返回。
返回值:
如果函数成功,则返回值为 NO_ERROR。
如果函数失败,它可以返回以下错误代码之一。
| 错误代码 | 描述 |
|---|---|
| ERROR_BEGINNING_OF_MEDIA | 在媒体开始标记之前访问数据的尝试失败。 |
| ERROR_BUS_RESET | 在总线上检测到复位条件。 |
| ERROR_DEVICE_NOT_PARTITIONED | 加载磁带时找不到分区信息。 |
| ERROR_DEVICE_REQUIRES_CLEANING | 磁带机能够报告它需要清洁,并报告它确实需要清洁。 |
| ERROR_END_OF_MEDIA | 在手术过程中到达磁带末端标记。 |
| ERROR_FILEMARK_DETECTED | 操作期间到达文件标记。 |
| ERROR_INVALID_BLOCK_LENGTH | 多卷分区中的新磁带上的块大小不正确。 |
| ERROR_MEDIA_CHANGED | 驱动器中的磁带已被更换或移除。 |
| ERROR_NO_DATA_DETECTED | 在操作期间到达数据结束标记。 |
| ERROR_NO_MEDIA_IN_DRIVE | 驱动器中没有媒体。 |
| ERROR_NOT_SUPPORTED | 磁带驱动程序不支持请求的功能。 |
| ERROR_PARTITION_FAILURE | 无法对磁带进行分区。 |
| ERROR_SETMARK_DETECTED | 在操作期间达到了设定标记。 |
| ERROR_UNABLE_TO_LOCK_MEDIA | 尝试锁定弹出机制失败。 |
| ERROR_UNABLE_TO_UNLOAD_MEDIA | 卸载磁带的尝试失败。 |
| ERROR_WRITE_PROTECT | 媒体是写保护的。 |
CreateTapePartition函数重新格式化磁带。
句法:
DWORD CreateTapePartition( [in] HANDLE hDevice, [in] DWORD dwPartitionMethod, [in] DWORD dwCount, [in] DWORD dwSize );
[in] hDevice
处理要创建新分区的设备。此句柄是使用 CreateFile函数创建的。
[in] dwPartitionMethod
要创建的分区类型。要确定您的设备支持的分区类型,请参阅硬件文档。此参数可以具有以下值之一。
| 价值 | 意义 |
|---|---|
| TAPE_FIXED_PARTITIONS | 根据设备的默认分区定义对磁带进行分区。dwCount和dwSize参数被忽略 。 |
| TAPE_INITIATOR_PARTITIONS | 将磁带分区为分别由dwCount和dwSize指定的分区数量和大小,最后一个分区除外。最后一个分区的大小是磁带的剩余部分。 |
| TAPE_SELECT_PARTITIONS | 将磁带分区为dwCount指定的分区数。dwSize参数被忽略。分区的大小由设备的默认分区大小决定。有关更具体的信息,请参阅磁带设备的文档。 |
[in] dwCount
要创建的分区数。GetTapeParameters函数提供磁带可以支持的最大分区数。
[in] dwSize
每个分区的大小,以兆字节为单位。如果dwPartitionMethod参数为TAPE_SELECT_PARTITIONS ,则忽略此值。
返回值:
如果函数成功,则返回值为 NO_ERROR。
如果函数失败,它可以返回以下错误代码之一。
| 错误代码 | 描述 |
|---|---|
| ERROR_BEGINNING_OF_MEDIA | 在媒体开始标记之前访问数据的尝试失败。 |
| ERROR_BUS_RESET | 在总线上检测到复位条件。 |
| ERROR_DEVICE_NOT_PARTITIONED | 加载磁带时找不到分区信息。 |
| ERROR_DEVICE_REQUIRES_CLEANING | 磁带机能够报告它需要清洁,并报告它确实需要清洁。 |
| ERROR_END_OF_MEDIA | 在手术过程中到达磁带末端标记。 |
| ERROR_FILEMARK_DETECTED | 操作期间到达文件标记。 |
| ERROR_INVALID_BLOCK_LENGTH | 多卷分区中的新磁带上的块大小不正确。 |
| ERROR_MEDIA_CHANGED | 驱动器中的磁带已被更换或移除。 |
| ERROR_NO_DATA_DETECTED | 在操作期间到达数据结束标记。 |
| ERROR_NO_MEDIA_IN_DRIVE | 驱动器中没有媒体。 |
| ERROR_NOT_SUPPORTED | 磁带驱动程序不支持请求的功能。 |
| ERROR_PARTITION_FAILURE | 无法对磁带进行分区。 |
| ERROR_SETMARK_DETECTED | 在操作期间达到了设定标记。 |
| ERROR_UNABLE_TO_LOCK_MEDIA | 尝试锁定弹出机制失败。 |
| ERROR_UNABLE_TO_UNLOAD_MEDIA | 卸载磁带的尝试失败。 |
| ERROR_WRITE_PROTECT | 媒体是写保护的。 |
SetTapeParameters 函数要么指定磁带的块大小,要么配置磁带设备。
句法:
DWORD SetTapeParameters( [in] HANDLE hDevice, [in] DWORD dwOperation, [in] LPVOID lpTapeInformation );
[in] hDevice
要为其设置配置信息的设备的句柄。此句柄是使用 CreateFile函数创建的。
[in] dwOperation
要设置的信息类型。此参数必须是以下值之一。
| 价值 | 意义 |
|---|---|
| SET_TAPE_DRIVE_INFORMATION | 设置由lpTapeInformation 指定的设备特定信息。 |
| SET_TAPE_MEDIA_INFORMATION | 设置由lpTapeInformation参数 指定的磁带特定信息。 |
[in] lpTapeInformation
指向包含要设置的信息的结构的指针。如果dwOperation参数是 SET_TAPE_MEDIA_INFORMATION,lpTapeInformation指向一个 TAPE_SET_MEDIA_PARAMETERS结构。
如果dwOperation是 SET_TAPE_DRIVE_INFORMATION,lpTapeInformation指向一个 TAPE_SET_DRIVE_PARAMETERS结构。
返回值:
如果函数成功,则返回值为 NO_ERROR。
如果函数失败,它可以返回以下错误代码之一。
| 错误代码 | 描述 |
|---|---|
| ERROR_BEGINNING_OF_MEDIA | 在媒体开始标记之前访问数据的尝试失败。 |
| ERROR_BUS_RESET | 在总线上检测到复位条件。 |
| ERROR_DEVICE_NOT_PARTITIONED | 加载磁带时找不到分区信息。 |
| ERROR_DEVICE_REQUIRES_CLEANING | 磁带机能够报告它需要清洁,并报告它确实需要清洁。 |
| ERROR_END_OF_MEDIA | 在手术过程中到达磁带末端标记。 |
| ERROR_FILEMARK_DETECTED | 操作期间到达文件标记。 |
| ERROR_INVALID_BLOCK_LENGTH | 多卷分区中的新磁带上的块大小不正确。 |
| ERROR_MEDIA_CHANGED | 驱动器中的磁带已被更换或移除。 |
| ERROR_NO_DATA_DETECTED | 在操作期间到达数据结束标记。 |
| ERROR_NO_MEDIA_IN_DRIVE | 驱动器中没有媒体。 |
| ERROR_NOT_SUPPORTED | 磁带驱动程序不支持请求的功能。 |
| ERROR_PARTITION_FAILURE | 无法对磁带进行分区。 |
| ERROR_SETMARK_DETECTED | 在操作期间达到了设定标记。 |
| ERROR_UNABLE_TO_LOCK_MEDIA | 尝试锁定弹出机制失败。 |
| ERROR_UNABLE_TO_UNLOAD_MEDIA | 卸载磁带的尝试失败。 |
| ERROR_WRITE_PROTECT | 媒体是写保护的。 |
SetTapePosition 函数设置指定设备上的磁带位置。
句法:
DWORD SetTapePosition( [in] HANDLE hDevice, [in] DWORD dwPositionMethod, [in] DWORD dwPartition, [in] DWORD dwOffsetLow, [in] DWORD dwOffsetHigh, [in] BOOL bImmediate );
[in] hDevice
设置磁带位置的设备的句柄。此句柄是使用 CreateFile函数创建的。
[in] dwPositionMethod
要执行的定位类型。此参数必须是以下值之一。
| 价值 | 意义 |
|---|---|
| TAPE_ABSOLUTE_BLOCK | 将磁带移动到由dwOffsetLow和dwOffsetHigh参数 指定的设备特定块地址。dwPartition参数被忽略 。 |
| TAPE_LOGICAL_BLOCK | 将磁带移动到由 dwPartition 指定的分区中由dwOffsetLow和dwOffsetHigh指定的块地址。 |
| TAPE_REWIND | 将磁带移动到当前分区的开头。dwPartition 、dwOffsetLow和dwOffsetHigh参数被忽略 。 |
| TAPE_SPACE_END_OF_DATA | 将磁带移动到dwPartition指定的分区上的数据末尾。 |
| TAPE_SPACE_FILEMARKS | 将磁带向前(或向后)移动当前分区中由dwOffsetLow和dwOffsetHigh指定的文件标记数。dwPartition参数被忽略 。 |
| TAPE_SPACE_RELATIVE_BLOCKS | 在当前分区 中将磁带向前(或向后)移动dwOffsetLow和dwOffsetHigh指定的块数。dwPartition参数被忽略 。 |
| TAPE_SPACE_SEQUENTIAL_FMKS | 将磁带向前(或向后)移动到当前分区中第一次出现 n 个文件标记,其中 n 是dwOffsetLow和dwOffsetHigh指定的数字。dwPartition参数被忽略 。 |
| TAPE_SPACE_SEQUENTIAL_SMKS | 将磁带向前(或向后)移动到当前分区中第一次出现 n 个设置标记,其中 n 是dwOffsetLow和dwOffsetHigh指定的数字。dwPartition参数被忽略 。 |
| TAPE_SPACE_SETMARKS | 在当前分区 中将磁带向前(或向后)移动dwOffsetLow和dwOffsetHigh指定的设置标记数。dwPartition参数被忽略 。 |
[in] dwPartition
分区到里面的位置。如果dwPartition为零,则使用当前分区。分区在逻辑上从 1 到 n 编号,其中 1 是磁带上的第一个分区,n 是最后一个分区。
[in] dwOffsetLow
dwPositionMethod参数指定的位置操作的块地址或计数的低位。
[in] dwOffsetHigh
dwPositionMethod参数指定的位置操作的块地址或计数的高位。如果不需要高位,则该参数应为零。
[in] bImmediate
指示是否在移动操作开始后立即返回。如果此参数为TRUE,则函数立即返回;如果为FALSE,则函数在移动操作完成之前不会返回。
返回值:
如果函数成功,则返回值为 NO_ERROR。
如果函数失败,它可以返回以下错误代码之一。
| 错误代码 | 描述 |
|---|---|
| ERROR_BEGINNING_OF_MEDIA | 在媒体开始标记之前访问数据的尝试失败。 |
| ERROR_BUS_RESET | 在总线上检测到复位条件。 |
| ERROR_DEVICE_NOT_PARTITIONED | 加载磁带时找不到分区信息。 |
| ERROR_DEVICE_REQUIRES_CLEANING | 磁带机能够报告它需要清洁,并报告它确实需要清洁。 |
| ERROR_END_OF_MEDIA | 在手术过程中到达磁带末端标记。 |
| ERROR_FILEMARK_DETECTED | 操作期间到达文件标记。 |
| ERROR_INVALID_BLOCK_LENGTH | 多卷分区中的新磁带上的块大小不正确。 |
| ERROR_MEDIA_CHANGED | 驱动器中的磁带已被更换或移除。 |
| ERROR_NO_DATA_DETECTED | 在操作期间到达数据结束标记。 |
| ERROR_NO_MEDIA_IN_DRIVE | 驱动器中没有媒体。 |
| ERROR_NOT_SUPPORTED | 磁带驱动程序不支持请求的功能。 |
| ERROR_PARTITION_FAILURE | 无法对磁带进行分区。 |
| ERROR_SETMARK_DETECTED | 在操作期间达到了设定标记。 |
| ERROR_UNABLE_TO_LOCK_MEDIA | 尝试锁定弹出机制失败。 |
| ERROR_UNABLE_TO_UNLOAD_MEDIA | 卸载磁带的尝试失败。 |
| ERROR_WRITE_PROTECT | 媒体是写保护的。 |
让我们先来看看WriteFile函数的定义吧!
将数据写入指定的文件或输入/输出 (I/O) 设备。
句法:
BOOL WriteFile( [in] HANDLE hFile, [in] LPCVOID lpBuffer, [in] DWORD nNumberOfBytesToWrite, [out, optional] LPDWORD lpNumberOfBytesWritten, [in, out, optional] LPOVERLAPPED lpOverlapped );
[in] hFile
文件或 I/O 设备的句柄(例如,文件、文件流、物理磁盘、卷、控制台缓冲区、磁带驱动器、套接字、通信资源、邮槽或管道)。
hFile参数必须已创建具有写访问权限。有关详细信息,请参阅 通用访问权限和 文件安全和访问权限。
对于异步写入操作,hFile可以是 使用FILE_FLAG_OVERLAPPED标志 的CreateFile函数 打开的任何句柄,也可以是套接字或 接受函数返回的套接字句柄。
[in] lpBuffer
指向包含要写入文件或设备的数据的缓冲区的指针。
该缓冲区必须在写操作期间保持有效。在写入操作完成之前,调用者不得使用此缓冲区。
[in] nNumberOfBytesToWrite
要写入文件或设备的字节数。
零值指定空写操作。空写操作的行为取决于底层文件系统或通信技术。
Windows Server 2003 和 Windows XP: 跨网络的管道写入操作在每次写入的大小上受到限制。金额因平台而异。对于 x86 平台,它是 63.97 MB。对于 x64 平台,它是 31.97 MB。对于 Itanium,它是 63.95 MB。有关管道的更多信息,请参阅备注部分。
[out, optional] lpNumberOfBytesWritten
指向变量的指针,该变量接收使用同步 hFile参数时写入的字节数。在进行任何工作或错误检查之前,WriteFile将此值设置为零。如果这是异步操作,请为此参数使用NULL以避免潜在的错误结果。
仅当lpOverlapped 参数不为NULL时,此参数才能为NULL。
Windows 7: 此参数不能为NULL。
有关详细信息,请参阅备注部分。
[in, out, optional] lpOverlapped
如果使用FILE_FLAG_OVERLAPPED打开hFile参数, 则需要指向OVERLAPPED结构的指针,否则此参数可以为 NULL。
对于支持字节偏移的hFile,如果使用此参数,则必须指定开始写入文件或设备的字节偏移。通过设置 OVERLAPPED结构的Offset和OffsetHigh成员 来指定此偏移量。对于 不支持字节偏移的hFile , Offset和 OffsetHigh将被忽略。
要写入文件末尾,请将OVERLAPPED结构的Offset和 OffsetHigh成员 都指定为 0xFFFFFFFF。这在功能上等同于之前调用 CreateFile函数以使用FILE_APPEND_DATA访问打开 hFile 。
有关lpOverlapped和 FILE_FLAG_OVERLAPPED不同组合的更多信息,请参阅备注部分和 同步和文件位置部分。
接下来再让我们看看BackupWrite函数的定义吧!
BackupWrite函数可用于恢复使用BackupRead备份的文件或目录 。使用 ReadFile函数从备份介质中获取数据流,然后使用BackupWrite将数据写入指定的文件或目录。
句法:
BOOL BackupWrite( [in] HANDLE hFile, [in] LPBYTE lpBuffer, [in] DWORD nNumberOfBytesToWrite, [out] LPDWORD lpNumberOfBytesWritten, [in] BOOL bAbort, [in] BOOL bProcessSecurity, [out] LPVOID *lpContext );
[in] hFile
要恢复的文件或目录的句柄。要获取句柄,请调用CreateFile函数。除非使用ACCESS_SYSTEM_SECURITY访问权限创建文件句柄,否则不会恢复 SACL 。为确保正确恢复完整性 ACE,还必须使用WRITE_OWNER访问权限创建文件句柄。有关详细信息,请参阅文件安全和访问权限。
句柄必须是同步的(不重叠)。这意味着调用CreateFile时不得设置FILE_FLAG_OVERLAPPED标志。此函数不会验证它接收到的句柄是否同步,因此它不会为同步句柄返回错误代码,但使用异步(重叠)句柄调用它可能会导致难以调试的细微错误。
如果使用标志 FILE_FLAG_NO_BUFFERING调用CreateFile,BackupWrite函数可能会失败 。在这种情况下, GetLastError函数返回值 ERROR_INVALID_PARAMETER。
[in] lpBuffer
指向函数从中写入数据的缓冲区的指针。
[in] nNumberOfBytesToWrite
缓冲区的大小,以字节为单位。缓冲区大小必须大于 WIN32_STREAM_ID结构的大小。
[out] lpNumberOfBytesWritten
指向接收写入字节数的变量的指针。
[in] bAbort
指示您是否已完成对句柄的BackupWrite使用。在恢复文件时,将此参数指定为FALSE。使用完 BackupWrite后,您必须再调用一次 BackupWrite,为此参数 指定TRUE并传递适当的lpContext。当bAbort为TRUE时,必须传递 lpContext;所有其他参数都被忽略。
[in] bProcessSecurity
指定函数是否将恢复文件或目录的访问控制列表 (ACL) 数据。
如果bProcessSecurity为TRUE,您需要 在打开文件或目录句柄时指定WRITE_OWNER和WRITE_DAC访问权限。如果句柄没有这些访问权限,则操作系统拒绝访问 ACL 数据,ACL 数据将不会恢复。
[out] lpContext
指向一个变量的指针,该变量接收指向 BackupWrite用于在还原操作期间维护上下文信息的内部数据结构的指针。
在第一次调用指定文件或目录的BackupWrite之前,您必须将lpContext指向的变量设置为NULL 。该函数为数据结构分配内存,然后将变量设置为指向该结构。在对BackupWrite的调用之间, 您不得更改lpContext或其指向的变量。
要释放数据结构使用的内存,请在恢复操作完成时调用BackupWrite,并将 bAbort参数设置为TRUE 。
ReadFile/BackupRead函数 真正设计LTFS!从现在开始,我们运用之前学习的知识总结到这里,设计一个让用户更直观使用的程序——Win32 C++
创建环境 窗口设计 代码部分 测试 程序、源码下载地址


