La risposta è che non puoi, a meno che il tuo filesystem non abbia un bug. Ecco perché:
C'è una chiamata di sistema per rinominare il tuo file definito in fs/namei.c
chiamato renameat
:
SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,
int, newdfd, const char __user *, newname)
Quando la chiamata di sistema viene invocata, esegue una ricerca del percorso ( do_path_lookup
) sul nome. Continua a rintracciarlo e arriviamo a quello link_path_walk
che ha questo:
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;
...
Questo codice si applica a qualsiasi file system. Cosa significa questo? Significa che se provi a passare un parametro con un '/'
carattere reale come nome del file usando i mezzi tradizionali, non farà quello che vuoi. Non c'è modo di sfuggire al personaggio. Se un filesystem "supporta" questo, è perché:
- Usa un carattere Unicode o qualcosa che assomigli a una barra ma non lo è.
- Hanno un bug.
Inoltre, se si ha fatto entrare e modificare i byte per aggiungere un carattere barra in un nome di file, le cose cattive sarebbe accaduto. Questo perché non potresti mai fare riferimento a questo file per nome :( poiché ogni volta che lo fai, Linux presume che ti riferisci a una directory inesistente. Anche l'uso della tecnica 'rm *' non funzionerebbe, poiché bash lo espande semplicemente al nome del file. Nemmeno rm -rf
funzionerebbe, dal momento che una semplice stringa rivela come vanno le cose sotto il cofano (abbreviato):
$ 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
...
Si noti che queste chiamate a unlinkat
fallirebbero perché devono fare riferimento ai file per nome.