2010-02-24 26 views
6

J'écris un outil d'archivage (un) et la façon dont il est conçu crée d'abord un fichier régulier à partir de l'archive avant d'examiner les attributs spéciaux et peut décider que ce item est un lien symbolique, en fait.Comment transformer un fichier normal en un lien symbolique sous Linux

Note: Avant que plus de gens ne me comprennent mal pour vouloir faire un lien symbolique de un fichier. Non, j'écris les données du lien symbolique, ie son chemin, dans le fichier, puis je veux dire au système de fichiers qu'il s'agit d'un lien symbolique

Je l'ai développé sur OS X, où il est possible de tourner un fichier régulier dans un lien symbolique en définissant simplement ses codes Type et Creator en conséquence.

Maintenant, j'aime aussi que ce code fonctionne sur Linux. Donc, j'aime trouver une manière similaire là-bas. Je suis conscient que la façon normale de créer un lien symbolique est d'appeler la fonction symlink(), mais je me demande s'il existe aussi un moyen de changer un fichier normal en lien symbolique, comme c'est possible dans le système BSD d'OSX , pour que je n'aie pas à refactoriser mon code de travail?

Il existe lstat(), qui renvoie le type de fichier dans les bits les plus élevés de st_mode. Maintenant, je me demande s'il existe aussi une fonction de réglage analogue pour ce champ de mode.

+0

Vérification si je comprends bien: vous voulez transformer un fichier normal en un lien symbolique qui pointe vers ce que contient le fichier? –

Répondre

4

Je ne crois pas qu'il existe un moyen pour Linux de faire ce que vous décrivez. IIRC, le système de fichiers stocke les informations de lien symbolique dans la table d'inode et non dans un fichier régulier, donc il n'y a pas de moyen direct de transformer un fichier en un lien.

Si le chemin du lien symbolique est stocké dans le fichier, pourquoi ne pas lire le chemin, supprimer le fichier et créer un lien symbolique à sa place?

+0

J'accepte cette réponse non pas pour sa suggestion de work-around plutôt évidente, mais pour l'explication de pourquoi il n'y a pas un moyen de faire ce que je voulais faire. J'espère que votre explication est correcte :) –

1

Non, vous ne pouvez pas transformer l'un dans l'autre. Vous devez dissocier pour tuer le fichier, puis le lien symbolique pour créer un lien symbolique en remplacement.

+1

Il serait préférable de créer un lien symbolique avec un nom différent, puis le renommer sur le fichier d'origine. Ceci est un remplacement atomique, et il n'y aura pas de trou où le nom de fichier est manquant (comme cela se produit après votre unlink). – ephemient

3

Démontrer que j'ai écrit comme commentaire à la réponse de bmarguiles,

#include <fcntl.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/stat.h> 
#include <sys/types.h> 
#include <unistd.h> 
int main(int argc, char **argv) { 
    char *buffer = 0, *name = 0; 
    int i; 
    for (i = 1; i < argc; i++) { 
     struct stat st; 
     int fd = open(argv[i], O_RDONLY); 
     fstat(fd, &st); 
     buffer = realloc(buffer, st.st_size + 1); 
     read(fd, buffer, st.st_size); 
     close(fd); 
     buffer[st.st_size] = '\0'; 
     name = realloc(name, strlen(argv[i]) + 2); 
     sprintf(name, "%s~", argv[i]); 
     symlink(buffer, name); 
     rename(name, argv[i]); 
    } 
    free(buffer); 
    free(name); 
    return 0; 
} 
 
$ vi f2s.c 
... 
$ cc -o f2s f2s.c 
$ echo -n/> test 
$ ./f2s test 
$ ls -l test 
lrwxrwxrwx 1 me me 1 Feb 24 23:17 test ->/
$ echo -n/> test2 
$ strace ./f2s test2 
open("test2", O_RDONLY)     = 3 
fstat(3, {st_mode=S_IFREG|0644, st_size=1, ...}) = 0 
read(3, "/", 1)       = 1 
close(3)        = 0 
symlink("/", "test2~")     = 0 
rename("test2~", "test2")    = 0 

Ceci est juste une démonstration; il faut vraiment plus de gestion des erreurs et peut-être un meilleur nom de fichier temporaire.

+0

Je suis curieux de savoir pourquoi l'utilisation de 'realloc()' sur 'malloc()'? – SiegeX

+0

Principalement parce que je suis paresseux et que je me sentais juste comme taper un seul «libre» à la fin. Ce n'est pas un code de qualité de production. – ephemient

+0

Vous n'êtes pas aussi paresseux que vous le pensez, vous avez déjà 'free()' s =) – SiegeX