我正在开发一个 Java 项目,我需要监视某个目录中的文件,并在对其中一个文件进行更改时收到通知,这可以使用WatchService
. 此外,我想知道进行了哪些更改,例如:“删除的字符 10 到 15”、“在索引 13 处添加了字符 'abcd'”......即使基于 c 语言,我也愿意采取任何解决方案监控文件系统。我还想避免 diff 解决方案以避免存储相同的文件 2 次,并且由于算法的复杂性,大文件需要很多时间。谢谢你的帮助。:)
问问题
144 次
1 回答
2
如果您使用的是 Linux,那么以下代码将检测文件长度的变化,您可以轻松地扩展它以更新修改。
因为您不想保留两个文件,所以如果文件长度减少(找不到丢失的字符)或文件在中间某处被更改,则无法判断哪些字符被更改
#include <stdio.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char** argv)
{
int fd = open("test", O_RDONLY);
int length = lseek(fd, 0, SEEK_END);
while (1)
{
int new_length;
close(fd);
open("test", O_RDONLY);
sleep(1);
new_length = lseek(fd, 0, SEEK_END);
printf("new_length = %d\n", new_length);
if (new_length != length)
printf ("Length changed! %d->%d\n", length, new_length);
length=new_length;
}
}
[编辑]
由于作者接受了对该任务的内核更改,因此对 vfs_write 的以下更改应该可以解决问题:
#define MAX_DIFF_LENGTH 128
ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
{
char old_content[MAX_DIFF_LENGTH+1];
char new_content[MAX_DIFF_LENGTH+1];
ssize_t ret;
if (!(file->f_mode & FMODE_WRITE))
return -EBADF;
if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write))
return -EINVAL;
if (unlikely(!access_ok(VERIFY_READ, buf, count)))
return -EFAULT;
ret = rw_verify_area(WRITE, file, pos, count);
if (___ishay < 20)
{
int i;
int length = count > MAX_DIFF_LENGTH ? MAX_DIFF_LENGTH : count;
___ishay++;
vfs_read(file, old_content, length, pos);
old_content[length] = 0;
new_content[length] = 0;
memcpy(new_content, buf, length);
printk(KERN_ERR"[___ISHAY___]Write request for file named: %s count: %d pos: %lld:\n",
file->f_path.dentry->d_name.name,
count,
*pos);
printk(KERN_ERR"[___ISHAY___]New content (replacement) <%d>:\n", length);
for (i=0;i<length;i++)
{
printk("[0x%02x] (%c)", new_content[i], (new_content[i] > 32 && new_content[i] < 127) ?
new_content[i] : 46);
if (length+1 % 10 == 0)
printk("\n");
}
printk(KERN_ERR"[___ISHAY___]Old content (on file now):\n");
for (i=0;i<length;i++)
{
printk("[0x%02x] (%c)", old_content[i], (old_content[i] > 32 && old_content[i] < 127) ?
old_content[i] : 46);
if (length+1 % 10 == 0)
printk("\n");
}
}
if (ret >= 0) {
count = ret;
if (file->f_op->write)
ret = file->f_op->write(file, buf, count, pos);
else
ret = do_sync_write(file, buf, count, pos);
if (ret > 0) {
fsnotify_modify(file);
add_wchar(current, ret);
}
inc_syscw(current);
}
return ret;
}
说明:
vfs_write 是处理文件写入请求的函数,因此这是我们在文件修改请求发生之前捕获文件修改请求的最佳中央挂钩。
vfs_write 接受写入操作的文件、文件位置、缓冲区和长度,因此我们知道文件的哪些部分将被此写入替换,以及哪些数据将替换它。
因为我们知道文件的哪一部分会被改变,所以我在实际写入之前添加了 vfs_read 调用,以将我们即将溢出的文件部分保存在内存中。
这应该是获得所需内容的一个很好的起点,我做了以下简化,因为这只是一个示例:
- 缓冲区以最大 128 字节静态分配(应动态分配并保护内存分配不会在大量写入请求上浪费太多内存)
- 应检查文件长度,读取缓冲区应参考此检查,即使写入溢出到超出文件结尾的长度,当前代码也会打印读取缓冲区
- 当前输出到 dmesg。更好的实现是在 debugfs 中保持可访问的循环缓冲区,可能使用 poll 选项
- 当前代码捕获写入所有文件,我敢肯定这不是你想要的......
[EDIT2]
忘了说这个函数在哪里,它fs/read_write.c
在内核树下
[EDIT3] 还有另一种可能的解决方案,前提是您知道要监视哪个程序,并且它没有静态链接 libc 是使用LD_PRELOAD覆盖该write
函数并将其用作您的挂钩并记录更改。我没有尝试过,但没有理由不应该工作
于 2015-03-30T08:47:35.550 回答