Changing file size "just on disk"

Hello everyone.

I’ve tried searching on this list about file size changes and read the article “Filtering File Systems - Then Things You Should Know”. I’ve noticed that it is a major issue trying to change file sizes because you need to mask it to every app. So, I’ve thought that, well, it’s ok, I won’t change the file size that the apps can see, but could I do this?:

  1. Let’s say I create one file with 500bytes. When IRP_MJ_WRITE is called, on pre-write, I’ll change the buffer size and write on disk 500bytes+200bytes of xml header. So it would look like […Originalfile].

  2. If IRP_MJ_READ is called, on pre-read, I change the buffer size to read 500bytes+200 bytes and on post-read I’ll parse that xml header and return only the 500bytes to the application.

So, on disk, the file size is 700 bytes, but every application will see the file with 500 bytes. So, my questions are:

Q1. Is this approach possible or I can’t change the buffers size like that?
Q2. If it is possible, should I catch some other major IRP function to make it work?

Thanks everyone.

Why you want to change on disk file size…
what exactly you want to achieve???

Be specific then only experts will answer your question… :slight_smile:

Well, I think I’ve been very specific, but to sum up:

I’m developing an encryption/decryption minifilter. I want not to only encrypt the files, but also add an xml header onto the file, so when the decryption occurs, it reads first the xml header and decrypt with parameters that are on that header.

It is possible but not the best approach, it can’t be implemented correctly for many file system drivers and filters. The better approach is through a file system isolation filter http://www.osronline.com/article.cfm?article=560 and http://www.osronline.com/article.cfm?article=571

At least IRP_MJ_READ, IRP_MJ_WRITE, IRP_MJ_QUERY_INFORMATION, IRP_MJ_SET_INFORMATION, IRP_MJ_FILE_SYSTEM_CONTROL ( FSCTL_MOVE_FILE ), IRP_MJ_LOCK_CONTROL this also includes all FastIo versions for these requests.

Thanks for your reply.

So, if I change my design and I remove that header, so the only size change of the file is related to encryption (AES), do I still need to implement that isolation filter? Or how do you manage that file size change on disk?

I ask that, because after reading both articles (thanks for them), I feel like I shouldn’t change the size of the file at any cost. But an encryption driver must do it, so I’m a bit lost right now on how to proceed.

Is so hard to manage size changes in isolation filters?

Yes. The isolation filter is the best approach to any data modification.

It is very easy to manage file size changes in an isolation filter when you have an isolation filter. The isolation filter implementation is itself a very difficult task. The approach you tried with I/O modification is faster to implement but it has significant limitations.

Hi jorge,
I am working on the exact task as you.
I’m not a driver professional, but I am sharing my experience with you. for any technical question you should ask other professionals here.

  1. Let’s say I create one file with 500bytes. When IRP_MJ_WRITE is called, on
    pre-write, I’ll change the buffer size and write on disk 500bytes+200bytes of
    xml header. So it would look like […Originalfile].
  1. If IRP_MJ_READ is called, on pre-read, I change the buffer size to read
    500bytes+200 bytes and on post-read I’ll parse that xml header and return only
    the 500bytes to the application.

So, on disk, the file size is 700 bytes, but every application will see the file
with 500 bytes. So, my questions are:

your specific question is managing file size but since you addressed the encryption\decryption filter people are giving you the correct solution for the whole problem and not answering your specific question.

for your question about file size. I exactly implemented the approach you described just recently.
It works. and the decrypted file is usable by common applications I tested against (MS word, Adobe acrobat, image viewers, notepad, etc).

But there is some issues:

  1. you can Alter the offset for read write, hiding the xml header but you can’t change the file size with this approach. the decrypted file had zero bytes at the end of it with the exact size of the header in my case. however the zero bytes did not break the applications I mentioned above, but I think in some cases this may cause problem with some applications.

Is so hard to manage size changes in isolation filters?

As I said before Isolation filter is a suggested design (some people here stated it as the only correct design) to implement enc\dec minifilter. However, implementing that approach will probably remove the need to fake the file size, since you provide 2 different views(virtual files) one encrypted and one plain to the consumers in that design.

So, if I change my design and I remove that header, so the only size change of
the file is related to encryption (AES), do I still need to implement that
isolation filter? Or how do you manage that file size change on disk?

This is not a windows kernel development concept, But if you use a stream cipher algorithm or Mode of encryption you can keep the file size un-touched. however in my experience with this filter so far you will need that header and have to keep it.

Thanks for your detailed answer, Ehsan.

I think I didn’t understand clearly your implementation. You said first that you implemented the same approach, but you are saying later that you don’t change the file size and you fill the end of file with 0’s.

Can you describe what are you doing then? I’m not sure of how you are hiding the header with the buffer offsets. Is it something like this?

  1. On create, change the file size to be 700 bytes instead of 500.
  2. On pre-write, fill the empty 200 bytes with the xml header.
  3. On pre-read, read the 700 bytes (since it is the real size now). On post-read, parse the xml header and return the 500bytes+200 0’s to fill the 700 bytes.

Thanks in advance.

Thanks again Slava for your answer.

Since I don’t think I have enough time to change my plan and start developing an isolation filter, could you summarize what are those limitations? Let’s say I always use the minifilter with NTFS, so I won’t handle different file systems.

Thanks.

In this light you can continue with I/O modification approach and tailor the minifilter to a particular file system driver implementation but bear in mind that it can be broken by some third party filter/minifilter or OS update.

Ok, thanks again then. I’ll try to make it work.

Last question is, have I to manage all the operations that you’ve said on your first answer (At least IRP_MJ_READ, IRP_MJ_WRITE, IRP_MJ_QUERY_INFORMATION,
IRP_MJ_SET_INFORMATION, IRP_MJ_FILE_SYSTEM_CONTROL ( FSCTL_MOVE_FILE ),
IRP_MJ_LOCK_CONTROL this also includes all FastIo versions for these requests) or was that related to the isolation filter solution?

What I implemented(It was just an experiment not a final design) is:

  1. I have files encrypted in the FS using a user mode utility and they got their header(which was a simple signature for encrypted files)
  2. in post create I detect if the file is encrypted or a regular file (by reading file content and examining the signature)
  3. in read and write I skip the header by adding to the offset I received. (for example the request is sent to read from offset 0 I add 200 to it to skip header)

but you are saying later that you don’t change the file size and you fill the end of file with 0’s.

I do not add any zeroes. but since I have shifted the data back by header size while the file size still includes header size the zeroes are read by the applications that try to read the file to its end.

Ok, thanks for clarifying your experiment. I’ll start my work on it, thanks for everything

If your filter modifies file size or/and data block offsets you should process the above mentioned requests. This was a minimal subset that came into my mind regarding I/O modification. If your filter modifies only data and keeps file size and block offsets intact you can restrict the implementation to IRP_MJ_READ, IRP_MJ_WRITE and respective Fast IO read/write requests.

The isolation filter implements all operations ( IRP, FastIO, Cache Mgr callbacks) as it is effectively a full-fledged file system driver implementation.

Ok, I supposed that Slava. Thanks again.

By the way, Ehsan, do you have that experiment in github or something like that? Or is that something private?

What you basically want here is two separate views, based on accessing application instance, into a single file. That means you need to “isolate” these two views. Hence the need for an Isolation Filter.

We have a LOT of experience in this space… and it’s very true. It’s taken us several engineering years of effort to get a proper Isolation Filter working. Seriously.

We (OSR) actually have a Solution Framework Kit that handles the hard parts of this… it’ s NOT open source, it’s a proprietary product, and it’s not cheap… But it’s FAR less expensive than trying to get the code right yourself. And because we don’t discuss/sell/promote commercial product in these forums, that’s all I’m going to say about this. Feel free to contact me offline for more info.

Peter
OSR
@OSRDrivers

>By the way, Ehsan, do you have that experiment in github or something like that?

Or is that something private?

It is not public.