《Windows NT FileSystem Internals》学习笔记之IO_STACK_LOCATION的学习

学而时习之,不亦悦乎?

这次记下的时IO_STACK_LOACTION的东东,以前就知道用,一直很迷糊,现在终于搞通了,爽!

还发现一个秘密,微软的Win2K源代码真是好东西啊,可惜放在我硬盘上的宝贝被浪费这么长时间。

IO_STACK_LOCATION和它的名字一样,是一个类似于栈的结构,属于先进后出的结构,看下面的例子 :

 

如上面的图所示,I/O管理器想文件系统驱动发送一个读请求,I/O管理器在创建IRP时候就分配了4个IO_STACK_LOCATION单元,这些单元是反向使用的。

当I/O管理器在调用驱动时,它总是讲IRP的StackLocation指针指向下一个StackLocation;当被调用的驱动释放IRP时,Stack Location真正被指回到前一个Stack Location。因此当过滤驱动的派遣函数运行时,I/O管理器使用Stack Location #4,也就是分配的最后一个Stack Location。

NT I/O管理器将IRP头中的StackCount字段初始化为IRP中Stack Location的总数。IRP头中的CurrentLocation字段初始化为StackCount+1,每一次通过IoCallDriver()调用驱动的派遣函数时,这个值减1。

因此,图中的StackCount=4,CurrentLocation初始化为5,实际上这个值是一个无效的指针值。那为什么要将CurrentLocation初始化为5呢?这得从I/O管理器调用器层次化调用驱动的过程讲起:内核组件总是首先得到指向下一个Stack Location的指针,然后在该Stack Location中填写相关的参数,再进行IoCallDriver();

当I/O管理器将IRP发往驱动堆栈中的最上面的驱动时,它的下一个Stack Location值为CurrentStackLocation-1=4,这个值时正确的!

I/O管理器经常检查一些IO_STACK_LOCATION中的相关值,例如在IOCallDriver()中,I/O管理器首先将CurrentLocation减1,然后检查CurrentLocation的值是否小于等于0,如果该值小于等于0,表明IoCallDriver()调用的次数多于Stack Location,I/O管理器将执行BugCheck,错误代码为NO_MORE_IRP_STACK_LOCATIONS。

上面几点可以从Win2K的源代码中看出:

Win2K中IoCallDriver代码的调用顺序是这样的:

NTSTATUS
IoCallDriver(
    IN PDEVICE_OBJECT DeviceObject,
    IN OUT PIRP Irp
    )
{
    return IofCallDriver (DeviceObject, Irp);
}

NTSTATUS
FASTCALL
IofCallDriver(
    IN PDEVICE_OBJECT DeviceObject,
    IN OUT PIRP Irp
    )
{
    //
    // This routine will either jump immediately to IopfCallDriver, or rather
    // IovCallDriver.
    //
    return pIofCallDriver(DeviceObject, Irp);
}

 

NTSTATUS
FASTCALL
IopfCallDriver(
    IN PDEVICE_OBJECT DeviceObject,
    IN OUT PIRP Irp
    )

/*++

Routine Description:

    This routine is invoked to pass an I/O Request Packet (IRP) to another
    driver at its dispatch routine.

Arguments:

    DeviceObject - Pointer to device object to which the IRP should be passed.

    Irp - Pointer to IRP for request.

Return Value:

    Return status from driver's dispatch routine.

--*/

{
    PIO_STACK_LOCATION irpSp;
    PDRIVER_OBJECT driverObject;
    NTSTATUS status;

    //
    // Ensure that this is really an I/O Request Packet.
    //

    ASSERT( Irp->Type == IO_TYPE_IRP );

    //
    // Update the IRP stack to point to the next location.
    //
    Irp->CurrentLocation--;

    if (Irp->CurrentLocation <= 0) {
        KeBugCheckEx( NO_MORE_IRP_STACK_LOCATIONS, (ULONG_PTR) Irp, 0, 0, 0 );
    }

    irpSp = IoGetNextIrpStackLocation( Irp );
    Irp->Tail.Overlay.CurrentStackLocation = irpSp;

    //
    // Save a pointer to the device object for this request so that it can
    // be used later in completion.
    //

    irpSp->DeviceObject = DeviceObject;

    //
    // Invoke the driver at its dispatch routine entry point.
    //

    driverObject = DeviceObject->DriverObject;

    PERFINFO_DRIVER_MAJORFUNCTION_CALL(Irp, irpSp, driverObject);

    status = driverObject->MajorFunction[irpSp->MajorFunction]( DeviceObject,
                                                              Irp );

    PERFINFO_DRIVER_MAJORFUNCTION_RETURN(Irp, irpSp, driverObject);

    return status;
}

微软的代码写的就是清楚,值得学习,呵呵

下一讲将讲述IoCompleteRequest()的学习笔记,结合Win2K源代码学习,呵呵

 
<think>嗯,用户想知道如何使用boost::filesystem::last_write_time来获取文件的最后修改时间。首先,我需要回忆一下Boost.Filesystem库的相关函数。记得last_write_time有两个重载版本:一个用于获取时间,另一个用于设置时间。用户需要的是获取功能,所以应该用那个接受路径参数的版本。 接下来,函数返回的是一个std::time_t类型的时间戳。不过用户可能需要将其转换为可读的格式,比如本地时间。这时候需要用std::localtime函数转换,但要注意这个函数不是线程安全的。可能需要提醒用户这一点,或者建议使用其他方法,比如Boost.DateTime库中的功能。 然后,用户可能需要示例代码。我应该构造一个简单的例子,包含必要的头文件,比如boost/filesystem.hpp,以及处理异常的try-catch块。因为文件操作可能会抛出异常,特别是当路径不存在时,所以异常处理很重要。引用中的例子也提到了filesystem_error,所以需要捕获这个异常并处理。 另外,用户提供的引用里提到使用boost::filesystem::last_write_time,并且有一个参考链接,可能涉及到时区的问题。比如,返回的时间戳是否是本地时间还是UTC,是否需要调整时区。比如,在引用4中,用户提到时间可能少一个小时,这可能和时区转换有关。所以在示例代码中,可能需要指出如何正确转换时间,或者提醒用户注意时区的问题。 然后,关于代码部分,要确保路径正确,使用绝对路径或者相对路径。可能需要建议用户先检查文件是否存在,或者使用其他函数如is_regular_file来验证路径指向的是常规文件,避免对目录或符号链接进行操作。但根据用户的问题,可能只需要关注如何获取时间,所以示例可以简单一些。 最后,注意事项部分需要包括异常处理、时区问题、路径有效性检查,以及是否需要权限等。这些都是用户在实际使用中可能会遇到的问题,提前说明可以帮助他们避免错误。</think>以下是如何使用`boost::filesystem::last_write_time`获取文件最后修改时间的详细说明: --- ### 核心步骤 1. **包含头文件**:需包含`<boost/filesystem.hpp>` 2. **获取时间戳**:调用`boost::filesystem::last_write_time(path)`返回`std::time_t`类型的时间戳 3. **转换为可读格式**:通过`std::localtime`函数转换为本地时间结构`tm` ### 代码示例 ```cpp #include <iostream> #include <ctime> #include <boost/filesystem.hpp> int main() { boost::filesystem::path file_path = "test.txt"; // 替换为实际路径 try { if (boost::filesystem::exists(file_path)) { std::time_t t = boost::filesystem::last_write_time(file_path); std::tm* local_time = std::localtime(&t); std::cout << "最后修改时间: " << 1900 + local_time->tm_year << "-" << 1 + local_time->tm_mon << "-" << local_time->tm_mday << " " << local_time->tm_hour << ":" << local_time->tm_min << ":" << local_time->tm_sec << std::endl; } else { std::cout << "文件不存在" << std::endl; } } catch (const boost::filesystem::filesystem_error& e) { std::cerr << "文件操作异常: " << e.what() << std::endl; // 引用[2] } return 0; } ``` --- ### 关键注意事项 1. **异常处理**:必须捕获`filesystem_error`异常,例如路径非法或权限不足时会抛出[^2] 2. **时区问题**:`last_write_time`返回的是UTC时间戳,转换为本地时间可能涉及时区偏移(参考[^4]) 3. **路径有效性**:建议先用`boost::filesystem::exists`检查文件是否存在[^1] 4. **时间精度**:该函数返回的时间精度取决于文件系统实现(通常为秒级) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值