Comment les applications Mac peuvent-elles suivre l'emplacement d'un fichier?

18

J'observe un comportement comme celui-ci sur mon Mac:

  • Ouvrez un PDF avec PDF Expert, apportez des modifications au fichier, déplacez le fichier dans le Finder, enregistrez-le dans PDF Expert et il sera correctement enregistré au nouvel emplacement.
  • Ouvrez un shell dans un répertoire comme ~/foo, jetez le répertoire avec une autre application et le pwd du shell sort correctement ~/.Trash/foo.

Que se passe-t-il sous le capot? Ces cas semblent indiquer que les applications ne tiennent pas seulement un chemin absolu du fichier comme emacs (ai-je raison?), Ou est-ce un mécanisme totalement différent?

nichijou
la source

Réponses:

21

macos a un /.vol/système spécial mappé sur le répertoire et les fichiers réels. Les fichiers et répertoires sont accessibles via /.vol/<device_id>/<inode_number>, indépendamment de l'emplacement des fichiers sur le système de fichiers.

C'est un joli petit système.

Ainsi, les programmes peuvent par exemple obtenir le numéro d'inode de /Users/jdoe/someFile.txtpuis l'ouvrir via /.vol/12345/6789(dans ce cas, l'ID de périphérique est 12345 et le numéro d'inode 6789). Vous vous déplacez ensuite /Users/jdoe/someFile.txtoù vous voulez (sur le même volume) et tout fonctionne. Vous pouvez même écrire un script shell qui prend en charge cela magic.

ls -di <file> pour obtenir le numéro d'inode.

$ ls -di /User/jdoe/someFile.txt
6789 /User/jdoe/someFile.txt

ÉDITER:

Vous utilisez statpour obtenir l'id du volume et le numéro d'inode, selon la réponse liée comme souligné par IMSoP.

GetFileInfo /.vol/12345/6789retournerait l'emplacement actuel du fichier précédemment localisé dans /Users/jdoe/someFile.txt.

Voir /programming/11951328/is-there-any-function-to-retrieve-the-path-associated-with-an-inode pour plus d'informations.

la carpe
la source
1
Selon les réponses liées, statest une commande plus utile ici que ls -di, car elle vous indique l'ID de volume / périphérique ainsi que l'ID de fichier / numéro d'inode.
IMSoP
4
Dans Debian, je n'en ai pas /.vol/et cela se produit toujours (bien que j'aie besoin pwd -P, alors seulement la sortie de plain pwdest mise à jour). Je suppose que les programmes n'ont pas à ouvrir de fichiers via un chemin spécial car en général ils obtiennent (et conservent) des descripteurs de fichiers qui sont de toute façon mappés à des inodes par le noyau. Je soupçonne que sur Mac /.vol/n'est pas essentiel aussi.
Kamil Maciorowski
Donc, si vous déplacez un fichier vers un autre disque, ce schéma se casse.
Joel Coehoorn
1
@JoelCoehoorn Oui, mais techniquement, vous ne pouvez pas déplacer un fichier vers un autre disque. Vous pouvez le copier sur l'autre disque, puis le supprimer, et il existe des raccourcis pour le faire en "une seule étape", mais c'est toujours un copier-supprimer, pas un déplacement, donc techniquement un fichier différent.
ibrewster
1
De nombreux éditeurs de texte lisent un fichier donné, le ferment, travaillent avec sa copie et l'enregistrent sur le même chemin, afin de recréer le fichier à son ancien emplacement. Mais ils peuvent garder le fichier ouvert tout le temps et y écrire à la toute fin. Mon bashsur Debian fait cela. Je cours exec 3<>foo, puis je me déplace foodans le même système de fichiers, echo whatever >&3puis je vérifie foole nouvel emplacement - et cela a changé. Bien qu'ils bashne puissent pas rechercher dans le fichier, d'autres programmes en général le peuvent. Mon point n'est /.vol/pas essentiel, les programmes peuvent facilement fonctionner comme ça sans lui. Ou je ne comprends pas la différence.
Kamil Maciorowski
1

La réponse ci-dessous est fausse (voir commentaires). Merci d'ignorer


En plus de la bonne réponse thecarpy a donné, il est probable que vos programmes tiennent simplement un fichier poignée , qui est indépendant de l'emplacement des fichiers dans l'arborescence des répertoires (et sur les systèmes Unix persiste même la suppression de fichiers, au moins jusqu'à ce que vous fermiez ).

Un descripteur de fichier est essentiellement l'accès direct au fichier, indépendamment de l'endroit ou de la fréquence (dans le cas des liens physiques) où il existe dans la structure du répertoire.

À M
la source
Non, vous ne l'avez pas compris non plus, je pense ... voir mon commentaire à @KamilMaciorowski. Le descripteur de fichier ne change pas, lorsque vous enregistrez ensuite le fichier, un nouveau fichier est créé à l'emplacement d'origine .... pas le cas sur macos!
carpe du
1
Vous avez raison, c'est très inattendu et très différent d'Unix. :(
Tom
D'accord et surévalué!
thecarpy
0

Bien que je ne sache pas pourquoi macos utilise cela au lieu de la fonctionnalité C standard, en supposant que ce que j'ai lu il y a des années dans "Mac OS X Unleashed" est correct, il s'avère que j'ai encore appris quelque chose de nouveau.

Veuillez regarder le programme C simple suivant:

#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
    struct timespec ts;
        ts.tv_sec = 10;
        ts.tv_nsec = 0;
    FILE * fp;

    fp = fopen("file.txt", "a");
    int f = fileno(fp);

    if (fp == NULL)
    {
        printf("Error opening file!\n");
        exit(1);
    }

    struct stat file_stat;
    int ret;
    ret = fstat (f, &file_stat);
    printf("inode number is %d\n", file_stat.st_ino);
    nanosleep(&ts, NULL);

    printf("Finished sleep, writing to file.\n");

/* print some text */
    const char *text = "Write this to the file";
    dprintf(f, "Some text: %s\n", text);

/* print integers and floats */
    int i = 1;
    float py = 3.1415927;
    dprintf(f, "Integer: %d, float: %f\n", i, py);

/* printing single characters */
    char c = 'A';
    dprintf(f, "A character: %c\n", c);

    close(f);
}

Compilez le programme, exécutez-le en arrière-plan et rapidement mv file.txt file2.txtAVANT que le programme imprime "sommeil terminé, écriture dans un fichier". (vous avez 10 secondes)

Notez que file2.txtla sortie de votre programme a bien été déplacée avant que le texte ne soit imprimé dans le fichier (via le descripteur de fichier).

$ gcc myfile.c
$ ./a.out &
[1] 21416
$ inode number is 83956
$ ./mv file.txt file2.txt
$ Finished sleep, writing to file.
[1]+  Done                    ./a.out
$ cat file2.txt
Some text: Write this to the file
Integer: 1, float: 3.141593
A character: A

AVIS DE NON-RESPONSABILITÉ: Je n'ai pas élagué la liste "inclure", cela a été rapidement piraté ensemble pour prouver un point.

la carpe
la source