Os membros de findutils
sabem disso , são compatíveis com * BSD:
One of the reasons that we skip deletion of "." is for compatibility with *BSD, where this action originated.
O NEWS no código-fonte do findutils mostra que eles decidiram manter o comportamento:
#20802: If -delete fails, find's exit status will now be non-zero. However, find still skips trying to delete ".".
[UPDATE]
Como esta questão se torna um dos assuntos mais importantes, então eu mergulho no código fonte do FreeBSD e vejo uma razão mais convincente.
Vamos ver o código fonte do utilitário do FreeBSD :
int
f_delete(PLAN *plan __unused, FTSENT *entry)
{
/* ignore these from fts */
if (strcmp(entry->fts_accpath, ".") == 0 ||
strcmp(entry->fts_accpath, "..") == 0)
return 1;
...
/* rmdir directories, unlink everything else */
if (S_ISDIR(entry->fts_statp->st_mode)) {
if (rmdir(entry->fts_accpath) < 0 && errno != ENOTEMPTY)
warn("-delete: rmdir(%s)", entry->fts_path);
} else {
if (unlink(entry->fts_accpath) < 0)
warn("-delete: unlink(%s)", entry->fts_path);
}
...
Como você pode ver, se não filtrar ponto e ponto, ele alcançará a função rmdir()
C definida pelo unistd.h
do POSIX.
Faça um teste simples, rmdir com argumento dot / dot-dot retornará -1:
printf("%d\n", rmdir(".."));
Vamos dar uma olhada como o POSIX descreve o rmdir :
If the path argument refers to a path whose final component is either dot or dot-dot, rmdir() shall fail.
Nenhuma razão foi dada porque shall fail
.
Eu encontrei rename
explico alguns argumentos n:
Renaming dot or dot-dot is prohibited in order to prevent cyclical file system paths.
Caminhos do sistema de arquivos cíclicos ?
Eu olho A Linguagem de Programação C (2ª Edição) e procuro pelo tópico do diretório, surpreendentemente eu encontrei o código é semelhante :
if(strcmp(dp->name,".") == 0 || strcmp(dp->name,"..") == 0)
continue;
E o comentário!
Each directory always contains entries for itself, called ".", and its parent, ".."; these must be skipped, or the program will loop forever.
"loop para sempre" , é como rename
descreve como "caminhos do sistema de arquivos cíclicos" acima.
Eu modifico um pouco o código e o faço executar no Kali Linux com base em esta resposta :
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
void fsize(char *);
void dirwalk(char *, void (*fcn)(char *));
int
main(int argc, char **argv) {
if (argc == 1)
fsize(".");
else
while (--argc > 0) {
printf("start\n");
fsize(*++argv);
}
return 0;
}
void fsize(char *name) {
struct stat stbuf;
if (stat(name, &stbuf) == -1 ) {
fprintf(stderr, "fsize: can't access %s\n", name);
return;
}
if ((stbuf.st_mode & S_IFMT) == S_IFDIR)
dirwalk(name, fsize);
printf("%81d %s\n", stbuf.st_size, name);
}
#define MAX_PATH 1024
void dirwalk(char *dir, void (*fcn)(char *))
{
char name[MAX_PATH];
struct dirent *dp;
DIR *dfd;
if ((dfd = opendir(dir)) == NULL) {
fprintf(stderr, "dirwalk: can't open %s\n", dir);
return;
}
while ((dp = readdir(dfd)) != NULL) {
sleep(1);
printf("d_name: S%sG\n", dp->d_name);
if (strcmp(dp->d_name, ".") == 0
|| strcmp(dp->d_name, "..") == 0) {
printf("hole dot\n");
continue;
}
if (strlen(dir)+strlen(dp->d_name)+2 > sizeof(name)) {
printf("mocha\n");
fprintf(stderr, "dirwalk: name %s/%s too long\n",
dir, dp->d_name);
}
else {
printf("ice\n");
(*fcn)(dp->d_name);
}
}
closedir(dfd);
}
Vamos ver:
xb@dnxb:/test/dot$ ls -la
total 8
drwxr-xr-x 2 xiaobai xiaobai 4096 Nov 20 04:14 .
drwxr-xr-x 3 xiaobai xiaobai 4096 Nov 20 04:14 ..
xb@dnxb:/test/dot$
xb@dnxb:/test/dot$ cc /tmp/kr/fsize.c -o /tmp/kr/a.out
xb@dnxb:/test/dot$ /tmp/kr/a.out .
start
d_name: S..G
hole dot
d_name: S.G
hole dot
4096 .
xb@dnxb:/test/dot$
Funciona corretamente, agora, se eu comentar a instrução continue
:
xb@dnxb:/test/dot$ cc /tmp/kr/fsize.c -o /tmp/kr/a.out
xb@dnxb:/test/dot$ /tmp/kr/a.out .
start
d_name: S..G
hole dot
ice
d_name: S..G
hole dot
ice
d_name: S..G
hole dot
ice
^C
xb@dnxb:/test/dot$
Como você pode ver, eu tenho que usar Ctrl + C para matar este programa de loop infinitamente.
O diretório '..' lê sua primeira entrada '..' e faz um loop para sempre.
Conclusão:
-
O GNU
findutils
tenta ser compatível com o utilitáriofind
em * BSD . -
find
utility no * BSD usa internamentermdir
função C compatível com POSIX que ponto / ponto-ponto não é permitido. -
O motivo de
rmdir
não permitir que o ponto / ponto seja impedido de seguir caminhos cíclicos do sistema de arquivos. -
A linguagem de programação C escrita por K & R mostra o exemplo de como o ponto / ponto-ponto levará a um programa de loop contínuo.