Conversione di un file in directory


14

Come sappiamo "Tutto in Linux" è un file e inoltre la directory è solo un file contenente altri file.

Quindi, non so se questa "idea folle" sia possibile, ma dovrebbe essere in qualche modo secondo il principio di cui sopra.

In parole semplici, come potrei cambiare un file vuoto esistente in una directory. È possibile?

Come un po 'di tempesta di cervello, ho pensato a una modifica dei metadati del file e renderlo come i metadati della directory dovrebbero farlo !!

Qualsiasi informazione è apprezzata


AGGIORNAMENTO: Sicuramente non voglio cancellare un file e creare invece la directory! Sto solo cercando di sapere quanto la filosofia sopra è applicabile se puoi giocare con alcuni metadati di file.


1
Quale può essere una ragione per farlo?
Pilota 6

1
L'unico modo corretto è eliminare il file e creare una directory. In caso contrario, il file system potrebbe essere danneggiato. Puoi farlo a basso livello ma dipende dal file system. In ext4 l'inode dovrebbe essere modificato, penso.
Pilota 6

2
Il concetto di "file" non riguarda questo. I dispositivi vengono anche trattati come file, ma ciò non significa che è possibile convertire un file in un dispositivo. :))
Pilot6,

5
debugfs ha un comando edit_inode che consente di modificare direttamente un inode che consente di impostare il flag del file su una directory. Ha anche un comando mkdir <inode>. Non ho fatto nulla di tutto ciò e non sto per provare.
tallus,

4
Questo presupposto "Come sappiamo" Tutto in Linux "è un file" è sbagliato, quindi l'intera domanda cade a pezzi. Come sappiamo "Tutto in Linux è un DESCRITTORE di file". Fa un mondo di differenza.
Rinzwind,

Risposte:


21

Raggiungere la conversione

Creazione di un filesystem di prova

Al fine di preservare il nostro filesystem principale da ogni possibile danno dopo aver eseguito questo esperimento, creeremo un piccolo filesystem all'interno di un file normale a scopo di test.

  1. Crea un file a riempimento zero chiamato testcon una dimensione di 10 megabyte:

    dd if=/dev/zero of=~/test bs=10M count=1
    
  2. Crea un filesystem Ext4 all'interno del file, come se fosse una partizione:

    mkfs.ext4 ~/test
    

Creazione di alcuni file e directory

Ora abbiamo un filesystem completamente funzionale all'interno del testfile, quindi creeremo alcuni file e directory al suo interno.

  1. Montare il filesystem appena creato all'interno /mnt:

    sudo mount ~/test /mnt
    
  2. Crea un file e una directory:

    sudo mkdir /mnt/folder
    echo "contents" | sudo tee /mnt/file
    
  3. Controlla il contenuto del filesystem:

    ls -l /mnt
    

    L'output dovrebbe essere qualcosa del genere:

    total 2
    -rw-r--r-- 1 root root     0 may 21 18:53 file
    drw-r--r-- 2 root root  1024 may 21 18:55 folder
    
  4. Smonta il filesystem di prova:

    sudo umount /mnt
    

Scambiare il file e la cartella

  1. Esegui debugfscontro il testfile con autorizzazione di scrittura ( -wflag):

    debugfs -w ~/test
    
  2. Converti filein una cartella:

    • Al debugfsprompt, digitare questo:

      modify_inode file
      
    • Apparirà un messaggio che ti chiede una modalità; digita questo:

      040644
      
    • Continuare a premere returnper lasciare i dati rimanenti così come sono finché non viene di nuovo visualizzato il messaggio.

  3. Converti folderin un file:

    • Al debugfsprompt, digitare questo:

      modify_inode folder
      
    • Apparirà un messaggio che ti chiede una modalità; digita questo:

      0100644
      
    • Continuare a premere returnper lasciare i dati rimanenti così come sono finché non viene di nuovo visualizzato il messaggio.

  4. Per uscire dal debugfsprompt, premi semplicemente qe poireturn

Verifica del successo dell'operazione

  1. Montare nuovamente il filesystem di prova:

    sudo mount ~/test /mnt
    
  2. Controlla il contenuto del filesystem:

    ls -l /mnt
    

    Ora, dovrebbe mostrare il file come se fosse una directory e viceversa :

    total 2
    drw-r--r-- 1 root root     0 may 21 18:53 file
    -rw-r--r-- 2 root root  1024 may 21 18:55 folder
    

Script per calcolare le modalità di inode

#!/bin/bash

#### See https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout#Inode_Table

## Terminal measures:
x="$(( $(tput cols) / 2 ))"   # Width of the terminal
y="$(( $(tput lines) /  2 ))" # Height of the terminal

## File descriptors:
declare -A types       # Declare an associative array with file descriptors
types[f]='0x8000'      # File
types[l]='0xA000'      # Link
types[s]='0xC000'      # Socket
types[d]='0x4000'      # Directory
types[p]='0x1000'      # Named pipe
types[b]='0x6000'      # Block device
types[c]='0x2000'      # Character device

## Permissions:
declare -A permission  # Declare an associative array with permissions
permission[user_S]='0x800'  # UID
permission[user_s]='0x840'  # UID and user can execute
permission[user_r]='0x100'  # User can read
permission[user_w]='0x80'   # User can write
permission[user_x]='0x40'   # User can execute
permission[group_S]='0x400' # GID
permission[group_s]='0x408' # GID and group can execute
permission[group_r]='0x20'  # Group can read
permission[group_w]='0x10'  # Group can write
permission[group_x]='0x8'   # Group can execute
permission[other_T]='0x200' # Sticky bit
permission[other_t]='0x201' # Sticky bit and other can execute
permission[other_r]='0x4'   # Other can read
permission[other_w]='0x2'   # Other can write
permission[other_x]='0x1'   # Other can execute

## Cleanup function:
function cleanup() {
    tput cvvis        # Make the cursor visible
    tput rmcup        # Restore saved terminal contents
    stty sane         # Fix problems caused by read -s
    exit 0            # Exit gracefully
}

## Function to print at a specified position:
function pprint() {
    tput cup $1 $2
    printf "${@:3}"
}

## Function to clear the notification area:
function reset() {
    pprint $((y+2)) $((x-40)) ' %.0s' {1..25} # Print 25 spaces
}

## Function to notify something to the user:
function notify() {
    reset                          # Clear the notification area
    pprint $((y+2)) $((x-40)) "$@" # Print the notification text
}

## If the terminal is smaller than 100x8, exit gracefully (self-explainatory):
if [ $x -lt 50 ] || [ $y -lt 5 ]; then
    echo 'Error, I need a minimum of 100x10 lines to run'
    exit 0
fi

## Initialize the terminal:
trap cleanup EXIT SIGHUP SIGINT SIGTERM # Call cleanup function after receiving ^C
stty -echo  cbreak                      # Put terminal in silent mode
tput smcup                              # Save terminal contents
tput civis                              # Make the cursor inisible

## Draw the big box:
printf '\033[1;37m'                            # Color
pprint $((y-3)) $((x-48)) '\u2500%.0s' {1..97} # Upper line
pprint $((y+4)) $((x-48)) '\u2500%.0s' {1..97} # Lower line
for ((i=4;i>-4;i--)); do                       # Sides:
    pprint $((y+i)) $((x-49)) '\u2502'             # Left line
    pprint $((y+i)) $((x+49)) '\u2502'             # Right line
done                                           # End sides
pprint $((y-3)) $((x-49)) '\u256D'             # Upper-left corner
pprint $((y+4)) $((x-49)) '\u2570'             # Lower-left corner
pprint $((y-3)) $((x+49)) '\u256E'             # Upper-right corner
pprint $((y+4)) $((x+49)) '\u256F'             # Lower-right corner

## Draw the small box:
printf '\033[1;35m'                             # Color
pprint $((y+1)) $((x-10)) '\u2501%.0s' {1..10}  # Upper line
pprint $((y+3)) $((x-10)) '\u2501%.0s' {1..10}  # Lower line
pprint $((y+2)) $((x-11)) '\u2503'              # Left line
pprint $((y+2)) $((x+00)) '\u2503'              # Right line
pprint $((y+1)) $((x-11)) '\u250F'              # Upper-left corner
pprint $((y+3)) $((x-11)) '\u2517'              # Lower-left corner
pprint $((y+1)) $((x+00)) '\u2513'              # Upper-right corner
pprint $((y+3)) $((x+00)) '\u251B'              # Lower-right corner

## Print type help:
pprint $((y-2)) $((x-44)) '\033[0;37mInode type: \033[1;37mf\033[0;37mile, \033[1;37md\033[0;37mirectory, \033[1;37ml\033[0;37mink, named \033[1;37mp\033[0;37mipe, \033[1;37ms\033[0;37mocket, \033[1;37mc\033[0;37mharacter device or \033[1;37mb\033[0;37mlock device.'

## Print permission help:
pprint $((y-1)) $((x-40)) '\033[0;36mPermission (\033[1;32mu\033[0;32mser\033[0;36m, \033[1;33mg\033[0;33mroup\033[0;36m or \033[1;31mo\033[0;31mther\033[0;36m): \033[1;36mr\033[0;36mead, \033[1;36mw\033[0;36mrite, e\033[1;36mx\033[0;36mecute, \033[1;36mhyphen\033[0;36m or \033[1;36mspace\033[0;36m to skip.'
pprint $((y+0)) $((x+8)) 's\033[1;36mt\033[0;36micky bit and executable, '
pprint $((y+1)) $((x+8)) 's\033[1;36mT\033[0;36micky bit not executable, '
pprint $((y+2)) $((x+8)) '\033[1;36ms\033[0;36metuid/setgid and executable, '
pprint $((y+3)) $((x+8)) '\033[1;36mS\033[0;36metuid/setgid not executable. '

## Endless loop:
while :; do

    ## Clear the input area:
    pprint $((y+2)) $((x-10)) '% *s\n' 10         # Print 16 spaces

    ## Print mask in the input area:
    printf '\033[1;37m'                           # Color for the type
    pprint $((y+2)) $((x-10)) '\u2588'            # Block for the type
    printf '\033[1;36m'                           # Color for the permision
    pprint $((y+2)) $((x- 9)) '\u2588%.0s' {1..9} # Blocks for the permission

    ## Loop through all variables to make a proper input:
    for var in type {user,group,other}_{r,w,x}; do

        ## Assign colors and regex to fields:
        case "$var" in
            (type)    color='\033[1;37m';     regex='^[fdlpscb]$'    ;;

            (other_x)                         regex='^[-xtT]$'       ;;&
            (user_x|group_x)                  regex='^[-xsS]$'       ;;&
            (user_[rw]|group_[rw]|other_[rw]) regex="^[-${var: -1}]$";;&

            (user*)   color='\033[1;32m'                             ;;
            (group*)  color='\033[1;33m'                             ;;
            (other*)  color='\033[1;31m'                             ;;
        esac

        ## Change the pointer position:
        pprint $((y+3)) $(((x-10)+pointer)) "${color}\u2501"           # Print the pointer on its new position
        if (( pointer > 0 )); then                                     # If the pointer is not in the first position:
            pprint $((y+3)) $(((x-10)+(pointer-1))) '\033[1;35m\u2501'     # Clear the old pointer         
        fi

        ## Infinite loop until there is a valid input for the current character:
        while :; do
            printf "$color"                       # Set the character color
            IFS= read -rn 1 $var                  # Read a character (even if it's a space)

            declare $var="${!var// /-}"           # Convert spaces to hyphens.
            if [[ "$var" == "type" ]]; then       # If the current variable is type:
                declare $var="${!var//-/f}"           # Convert "-" to "f"
            fi

            if [[ "${!var}"  =~ $regex ]]; then   # If there is a valid input:
                reset                                 # Clear error notification if any
                break                                 # Exit from this loop
            else                                  # Else:
                notify "\033[1;31mWrong input!"       # Print the error message
            fi
        done

        ## Print the entered value:
        pprint $((y+2)) $(((x-10)+pointer)) "${!var}"

        ## Sum the current permission:
        ((mode+=permission[${var%_*}_${!var}]))

        ## Increment the pointer:
        ((pointer++))
    done

    ## Post-read:
    unset pointer                                 # Reset the pointer
    pprint $((y+3)) $((x-1)) "\033[1;35m\u2501"   # Clear the pointer
    read -n 1                                     # Wait for Return or another character

    ## Sum file descriptor type:
    ((mode+=${types[$type]}))

    ## Final commands:
    mode=$(printf "%o" $mode)                      # Convert mode to octal (before this was decimal)
    notify "\033[1;32mOctal mode:\033[1;34m $mode" # Print the octal mode
    unset mode                                     # Reset the mode
done

Visualizza lo script su GitHub

handicap

  • La cartella non si apre. Non è possibile aprirlo a meno che non vengano inseriti i "dati della cartella non elaborati" che lo contenevano in origine.

Ulteriori letture

https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout#Inode_Table


Grazie a @tallus . Mi ha dato un grande suggerimento:

debugfs ha un comando edit_inode che consente di modificare direttamente un inode che consente di impostare il flag del file su una directory.


2
+1 Bella risposta, ma solo le note 0100755devono essere 0100644per non modificare le autorizzazioni di un file poiché 755 darà l'esecuzione per il file convertito ...
Maythux,

Inoltre, la directory appena convertita non si aprirà. Mostra il file diventare cartella ma la cartella non può essere aperta. Hai qualche soluzione per questo?
Maythux,

Lo terrò aperto per un po ', altrimenti se non c'è un'altra grande risposta
segnerò la

3
Accidenti è bello @helio: D
Rinzwind

1
Che risposta geniale! Va bene, alla fine è inutile, ma comunque molto impressionante, quindi +1 da parte mia.
Carl H,
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.