percorsi di file lunghi (o bizzarri)

2

So che (su Linux almeno, con i file system nativi come Ext3) i percorsi dei file possono in teoria essere piuttosto lunghi, e PATH_MAX è spesso (ma non sempre) grande come 4096 (vedi questo ; e questo spiega che potrebbe essere più lungo o definito in fase di esecuzione!).

Tuttavia, i percorsi dei file sono spesso costruiti al volo e non è insolito in C codificare qualcosa come

#define MY_PATH_MAX 256
char pathbuf[MY_PATH_MAX];
snprintf (pathbuf, sizeof(pathbuf), "%s/%s", getenv("HOME"), somevar);
FILE *f = fopen(pathbuf, "r");
//// etc, avoiding error checks for simplicity

Ora, credo che avere MY_PATH_MAX non sia troppo grande (in particolare per evitare di consumare molto spazio sul frame dello stack di chiamate) sia praticamente importante e ragionevole. Quindi, nell'esempio precedente fare #define MY_PATH_MAX PATH_MAX sarebbe sciocco (non è necessario spendere 4Kbyte nel mio frame di chiamata).

Sto codificando dal 1974 e non ho mai incontrato un caso in cui il percorso di un file fosse più grande di una larghezza dello schermo, ad es. 80 caratteri o così. Tutti i file system di cui ho sentito parlare non hanno una gerarchia di directory molto profonda (un file con 8 directory sopra è molto insolito).

Quindi, la mia intuizione è corretta? Il software reale si preoccupa di percorsi di file così lunghi o bizzarri? Allo stesso modo, non ho mai incontrato nessun nome di file che contenga una nuova riga (e raccomando vivamente contro gli spazi nei nomi di file!).

IIUC, non sarai in grado di creare un software GNU come GCC in una directory il cui nome contiene spazi o newlines ... molto probabilmente gli script relativi a autoconf ne risentirebbero ... Inoltre, non c'è semplicemente modo di dare al tuo /etc/passwd a $HOME contenente newline o anche a due punti : -come passwd(5) non lo supporta.

Il mio limite pratico di 256 byte in un percorso file è un buon limite?

Per i commenti, l'ho appena aggiornato a 384 ...

Hai un esempio pratico in cui i nomi dei percorsi di file lunghi sono rilevanti? Sono principalmente interessato ai sistemi POSIX o Linux!

    
posta Basile Starynkevitch 11.07.2015 - 16:43
fonte

3 risposte

5

Does real software care about such long or bizarre file paths?

Non esiste un percorso file lungo o bizzarro. Esistono solo percorsi di file validi e non validi e software reale - il software correct - considera quelli validi come stringhe di byte e non si preoccupa dei contenuti.

Is my practical limit of 256 bytes in a file path a good limit?

Assolutamente no. Né il tuo limite modificato di 384.

Il limite pratico su qualsiasi sistema che definisce PATH_MAX è PATH_MAX se il valore attuale dietro è 5, 50, 500 o 5.000. (256 è il minimo richiesto da POSIX.)

PATH_MAX è il modo del sistema di dirti esattamente quanti caratteri aspettarsi in un percorso valido. L'utilizzo di buffer che sono più piccoli limita il programma a essere in grado di gestire un sottoinsieme dei percorsi validi sul sistema. Ciò servirà ad aggravare gli utenti del tuo programma che si scontreranno con questa limitazione e renderà più lavoro per te quando ti chiederanno di rispettare lo standard stabilito.

A meno che non sia possibile descrivere uno specifico problema reale risolto utilizzando buffer troncati, non c'è motivo di utilizzare altro che PATH_MAX . Gli anni '70 erano più di 35 anni fa e PATH_MAX byte per un percorso sulla maggior parte degli stack non è un problema. Se ti trovi in un ambiente con stack limitato, le probabilità sono buone, probabilmente non aprirai molti file, e se lo sei, PATH_MAX di quell'ambiente sarà abbastanza piccolo per sistemarlo.

    
risposta data 11.07.2015 - 19:58
fonte
6

Sono molto contrario alla creazione di restrizioni inutili nel nostro software, a meno che non ci troviamo davvero in un ambiente con molte risorse (ad es. sistemi embedded). Ogni volta che pensiamo che "nessuno avrà mai bisogno di questo", qualcuno si imbatterà in queste restrizioni arbitrarie.

Una lunghezza massima del percorso è fondamentalmente in disaccordo con il modello gerarchico, ad albero e ricorsivo dei moderni file system. Un percorso si rivolge a un nodo in questo albero e non ci dovrebbero essere differenze fondamentali nell'indirizzamento tra un albero e il suo sottoalbero. Tuttavia, l'imposizione di un limite di lunghezza sul percorso generale significa che in casi estremi possiamo indirizzare un file da una sottodirectory che non può essere indirizzata da una directory padre. Per esempio. se le lunghezze del percorso erano limitate a dieci byte, per indirizzare il file /a/b/c/d.txt (12 byte + terminatore), potremmo chdir in /a/b e quindi indirizzare il file come c/d.txt . Dovendo chdir solo per aprire un file davvero fa schifo.

In pratica, i nomi di percorsi lunghi possono verificarsi a causa di vari motivi:

  • I file system sono un database. Alcuni programmi usano gli hash come chiave in questo database, ad es. Git o Firefox. mentre entrambi sono molto addomesticati poichè usano solo percorsi abbastanza brevi come ./.git/objects/07/5f3cb2c7deb3abb3ce6b7e6eb8b83ff34c883c (percorso relativo, 56 byte + terminatore) o ~/.cache/mozilla/firefox/********.default/cache2/entries/1101BEDA093DDE5562CCC4FE6CF1C4538D36022E (percorso relativo, 97 byte + terminatore), non c'è motivo per cui qualcuno non debba avere più hash in un percorso.
  • Molti strumenti di programmazione utilizzano percorsi lunghi. Ad esempio, Java ha una convenzione in cui un nome di pacchetto come com.example.product.awesome.backend.dataaccesslayer.util può portare a un percorso ./src/com/example/product/awesometool/backend/dataaccesslayer/util/SecondaryProductInformationVisitorManagerFactory.java (esempio faceto, percorso relativo, 120 byte + terminatore). Ho eseguito una query sul mio file system per trovare il percorso più lungo e ho trovato un file in un pacchetto NodeJS chiamato /usr/local/lib/node_modules/phonegap/node_modules/cordova/node_modules/cordova-lib/node_modules/cordova-js/node_modules/browserify/node_modules/insert-module-globals/node_modules/combine-source-map/node_modules/inline-source-map/node_modules/source-map/lib/source-map/indexed-source-map-consumer.js (esempio reale, nessun link simbolico, 298 byte + terminatore). Anche se devo ammettere, questo sembra essere un orribile layout di progetto.
  • I collegamenti simbolici sono divertenti. Soprattutto quando sono alla fine di un lungo percorso e puntano a una directory. Naturalmente, i collegamenti simbolici hanno usi reali, ad es. per la gestione della configurazione.

Consiglio vivamente di allontanarmi da una mentalità a dimensione fissa. Scala in base alle esigenze, dal momento che una dimensione non si adatta a tutti. Se non si desidera allocare un buffer 4KB nello stack, non farlo. Il tuo esempio nella domanda è particolarmente negativo perché puoi facilmente scoprire quanto spazio hai bisogno, e semplicemente malloc così tanto - o usare matrici di lunghezza variabile, se il tuo compilatore lo consente. Se si scopre che qualcuno ti ha passato megabyte di dati, puoi fallire in modo esplicito con questo motivo, ma provare ad accedere a un nome di file a metà copia è anche peggio. Penso che Steele e Sussman l'abbiano messo meglio di me nel loro design " del 1979 di processori basati su LISP o, SCHEME: LISP dielettrico o Memoria finita di ricordi considerati o, LAMBDA: The Ultimate Opcode " :

As far as the LISP programmer is concerned, new data objects are available in endless supply. They can be conveniently called forth to serve some immediate purpose and discarded when they are no longer in use. […]

The immense freedom this gives the programmer may be seen by an example taken from current experience. A sort of error message familiar to most programmers is “too many nested DO loops”, or “more than 200 declared arrays” or “symbol table overflow”. Such messages typically arise within compilers or assemblers which were written in languages requiring data tables to be pre-allocated [at compile time] to some fixed length. The author of a compiler, for example, might well guess, “No one will even use more than, say, ten nested DO loops; I'll double that for good measure, and make the nested-DO-loop-table 20 long.” Inevitably, someone eventually finds some reason to write 21 nested DO loops, and finds the compiler overflows its fixed table and issues an error message (or worse yet, doesn't issue an error message). On the other hand, had the compiler writer made the table 100 long or 1000 long, most of the time most of the memory space devoted to that table would be wasted.

Ovviamente, stanno parlando dell'inizio di Fortran e della sua avversione per la gestione dinamica della memoria. L'ironia qui è che C supporta assolutamente l'allocazione dinamica della memoria, anche se è certamente ingombrante. Se hai bisogno di aiuto per tenere traccia di tutta quella memoria, puoi sempre usare C ++ ...

    
risposta data 11.07.2015 - 19:13
fonte
5

Non farti odiare dagli utenti: concedi ciò che è probabile che il sistema sottostante permetta.

Ricordo di aver incontrato problemi con il percorso dei file in un'azienda ragionevolmente grande in cui le risorse (di diversi tipi, per prodotti che contenevano componenti suddivisi in contenuti) erano archiviate in una struttura di cartelle simile a:

  • Nome del dipartimento
  • Nome del team
  • Famiglia di prodotti
  • Nome prodotto
  • Nome del rilascio
  • Componente
  • Sotto-componente
  • Tipo di risorsa

Ecco otto livelli che non includono un identificatore per l'unità di rete e il nome file. Praticamente nessuno di questi sarebbe vicino a otto caratteri. Il nome del rilascio potrebbe includere una data; i nomi dei prodotti sarebbero spesso dell'ordine del "Manuale cliente Inspirational Product Title Mark 3 (tedesco svizzero)".

E questo è ottimistico: molto spesso un altro livello o due di gerarchia si insinuano.

    
risposta data 11.07.2015 - 19:07
fonte

Leggi altre domande sui tag