我正在开发一个Java项目,我需要监视某个目录中的文件,并在其中一个文件发生更改时收到通知,这可以使用WatchService
来实现。此外,我想知道做了哪些更改,例如:“删除了字符10到15”,“添加了索引13个字符'abcd'”......我愿意甚至基于c语言采取任何解决方案监视文件系统。
我还想避免diff解决方案以避免存储相同的文件2次,并且对于算法的复杂性,大文件需要花费很多时间。
谢谢你的帮助。 :)
答案 0 :(得分:2)
如果您使用的是Linux,则以下代码将检测文件长度的变化,您可以轻松扩展此更新以更新修改。
因为您不想保留两个文件,如果文件长度减少(无法找到丢失的字符)或文件在中间某处被更改,则无法确定哪些字符被更改< / p>
#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调用,以便在内存中保留我们即将溢出的文件部分。
这应该是获得所需内容的良好起点,我做了以下简化,因为这只是一个例子:
[EDIT2]
忘了提到这个函数所在的位置,它位于内核树中的fs/read_write.c
下
[EDIT3]
还有另一种可能的解决方案,让您知道要监视哪个程序,并且没有静态链接的libc是使用LD_PRELOAD来覆盖write
函数并将其用作您的钩子并记录变化。我没有试过这个,但是没有理由不这样做