Câu trả lời là bạn không thể, trừ khi hệ thống tệp của bạn có lỗi. Đây là lý do tại sao:
Có một lệnh gọi hệ thống để đổi tên tệp của bạn được xác định bằng fs/namei.c
tên renameat
:
SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
int, newdfd, const char __user *, newname)
Khi lệnh gọi hệ thống được gọi, nó thực hiện tra cứu đường dẫn ( do_path_lookup
) trên tên. Tiếp tục theo dõi điều này, và chúng tôi nhận được link_path_walk
điều này:
static int link_path_walk(const char *name, struct nameidata *nd)
{
struct path next;
int err;
unsigned int lookup_flags = nd->flags;
while (*name=='/')
name++;
if (!*name)
return 0;
...
Mã này áp dụng cho bất kỳ hệ thống tệp nào. Điều này có nghĩa là gì? Nó có nghĩa là nếu bạn cố gắng truyền một tham số với một '/'
ký tự thực tế là tên của tệp bằng cách sử dụng phương tiện truyền thống, nó sẽ không thực hiện những gì bạn muốn. Không có cách nào để thoát khỏi nhân vật. Nếu hệ thống tệp "hỗ trợ" điều này, đó là bởi vì chúng:
- Sử dụng một ký tự unicode hoặc một cái gì đó giống như một dấu gạch chéo nhưng không phải.
- Họ có một lỗi.
Hơn nữa, nếu bạn đã vào và chỉnh sửa các byte để thêm ký tự gạch chéo vào tên tệp, điều tồi tệ sẽ xảy ra. Đó là bởi vì bạn không bao giờ có thể tham chiếu đến tệp này bằng tên :( vì bất cứ lúc nào bạn làm vậy, Linux sẽ cho rằng bạn đang đề cập đến một thư mục không tồn tại. Sử dụng kỹ thuật 'rm *' cũng sẽ không hoạt động, vì bash chỉ cần mở rộng nó thành tên tệp. Thậm chí rm -rf
sẽ không hoạt động, vì một sơ suất đơn giản cho thấy mọi thứ diễn ra như thế nào (rút gọn):
$ ls testdir
myfile2 out
$ strace -vf rm -rf testdir
...
unlinkat(3, "myfile2", 0) = 0
unlinkat(3, "out", 0) = 0
fcntl(3, F_GETFD) = 0x1 (flags FD_CLOEXEC)
close(3) = 0
unlinkat(AT_FDCWD, "testdir", AT_REMOVEDIR) = 0
...
Lưu ý rằng các lệnh gọi unlinkat
này sẽ không thành công vì chúng cần tham chiếu đến các tệp theo tên.