Perché rmdir e scollegano due chiamate di sistema separate?


10

Ecco qualcosa che mi ha fatto riflettere per un po ':

[15:40:50][/tmp]$ mkdir a
[15:40:52][/tmp]$ strace rmdir a
execve("/usr/bin/rmdir", ["rmdir", "a"], [/* 78 vars */]) = 0
brk(0)                                  = 0x11bb000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff3772c3000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=245801, ...}) = 0
mmap(NULL, 245801, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7ff377286000
close(3)                                = 0
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0p\36\3428<\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2100672, ...}) = 0
mmap(0x3c38e00000, 3924576, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x3c38e00000
mprotect(0x3c38fb4000, 2097152, PROT_NONE) = 0
mmap(0x3c391b4000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b4000) = 0x3c391b4000
mmap(0x3c391ba000, 16992, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x3c391ba000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff377285000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7ff377283000
arch_prctl(ARCH_SET_FS, 0x7ff377283740) = 0
mprotect(0x609000, 4096, PROT_READ)     = 0
mprotect(0x3c391b4000, 16384, PROT_READ) = 0
mprotect(0x3c38c1f000, 4096, PROT_READ) = 0
munmap(0x7ff377286000, 245801)          = 0
brk(0)                                  = 0x11bb000
brk(0x11dc000)                          = 0x11dc000
brk(0)                                  = 0x11dc000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=106070960, ...}) = 0
mmap(NULL, 106070960, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7ff370d5a000
close(3)                                = 0
rmdir("a")                              = 0
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++
[15:40:55][/tmp]$ touch a
[15:41:16][/tmp]$ strace rm a
execve("/usr/bin/rm", ["rm", "a"], [/* 78 vars */]) = 0
brk(0)                                  = 0xfa8000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3b2388a000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=245801, ...}) = 0
mmap(NULL, 245801, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f3b2384d000
close(3)                                = 0
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0p\36\3428<\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2100672, ...}) = 0
mmap(0x3c38e00000, 3924576, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x3c38e00000
mprotect(0x3c38fb4000, 2097152, PROT_NONE) = 0
mmap(0x3c391b4000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b4000) = 0x3c391b4000
mmap(0x3c391ba000, 16992, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x3c391ba000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3b2384c000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f3b2384a000
arch_prctl(ARCH_SET_FS, 0x7f3b2384a740) = 0
mprotect(0x60d000, 4096, PROT_READ)     = 0
mprotect(0x3c391b4000, 16384, PROT_READ) = 0
mprotect(0x3c38c1f000, 4096, PROT_READ) = 0
munmap(0x7f3b2384d000, 245801)          = 0
brk(0)                                  = 0xfa8000
brk(0xfc9000)                           = 0xfc9000
brk(0)                                  = 0xfc9000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=106070960, ...}) = 0
mmap(NULL, 106070960, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f3b1d321000
close(3)                                = 0
ioctl(0, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...}) = 0
newfstatat(AT_FDCWD, "a", {st_mode=S_IFREG|0664, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
geteuid()                               = 1000
newfstatat(AT_FDCWD, "a", {st_mode=S_IFREG|0664, st_size=0, ...}, AT_SYMLINK_NOFOLLOW) = 0
faccessat(AT_FDCWD, "a", W_OK)          = 0
unlinkat(AT_FDCWD, "a", 0)              = 0
lseek(0, 0, SEEK_CUR)                   = -1 ESPIPE (Illegal seek)
close(0)                                = 0
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

Perché ci sono chiamate di sistema separate per la rimozione di una directory e dei file? Perché queste due operazioni dovrebbero essere semanticamente distinte?


Risposte:


9

Le directory sono speciali nel senso che all'interno di una directory è possibile avere riferimenti a più file e directory, quindi, se si rimuove la directory principale, tutti quei file perdono il punto di riferimento da cui è possibile accedere, lo stesso con il processo. In questi casi, rmdir()hanno diversi controlli, che sono diversi da unlink():

  • Se la directory non è vuota. Se una directory non è vuota, non può rimuoverla fino a quando il contenuto non viene unlinkrimosso.

       ENOTEMPTY
          pathname contains entries other than . and .. ; or, pathname has
          ..  as its final component.  POSIX.1-2001 also allows EEXIST for
          this condition.
    
  • Se la directory è in uso. Se un processo perde la loro directory corrente, potrebbe causare problemi e comportamenti indefiniti. È meglio prevenirli.

       EBUSY  pathname  is currently in use by the system or some process that
          prevents its removal.  On Linux this means pathname is currently
          used  as  a  mount point or is the root directory of the calling
          process.
    

Nel caso di unlink()questi controlli non esiste. In effetti, è possibile eliminare il nome di un file con unlink()e il processo che sta ancora utilizzando / facendo riferimento ad esso, può modificarlo senza problemi. Il file esiste fino a quando non esiste il descrittore di file, inaccessibile al nuovo processo (a meno che non si sappia dove cercare). Questo fa parte della magia delle mani dai colori dell'arcobaleno dei file system * NIX.

Ora, c'è quello unlinkat()che si comporta come entrambi, unlink()o rmdir(2)dipende dal percorso che è quello che ti aspetti.


rm -rf "$PWD"Funziona bene e rimuove la directory corrente. Penso che il motivo per cui c'è rmdir()probabilmente è storico (inizialmente, le directory erano unlinked () e rmdir (il comando) stava scollegando dir /., Dir / .. e dir, e quando questo veniva spostato nel kernel, doveva essere un nuovo syscall che fa tutti e 3 almeno per un periodo di transizione o qualcosa del genere)
Stéphane Chazelas,

@ StéphaneChazelas sono d'accordo, ecco perché ho aggiunto unlinkat.
Braiam,

Se ho letto correttamente la tua risposta, stai dicendo rmdir(dir)che non funziona se dirè in uso. Questo non è vero almeno su Linux, dove rmdir(getcwd())funziona bene (a condizione che la directory corrente sia vuota).
Stéphane Chazelas,

@ StéphaneChazelas corretto, utilizzato da un processo o come punto di montaggio: EBUSY percorso è attualmente in uso dal sistema o da un processo che ne impedisce la rimozione . Su Linux questo significa che percorso è attualmente utilizzato come punto di montaggio o è la directory principale del processo di chiamata.
Braiam,

Non sono sicuro di cosa significhino o sia la directory principale del processo di chiamata . mkdir test; sudo strace -e chroot,rmdir perl -e 'chroot("test"); rmdir("test")'mostra sia chroot che rmdir riescono.
Stéphane Chazelas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.