Task 139: .DIRED File Format

Task 139: .DIRED File Format

File Format Specifications for .DIRED

Upon thorough research using web searches and page browsing, no standard binary or structured file format named ".DIRED" was identified. However, the term is closely associated with Emacs' Dired mode, where ".dired" (case-insensitive in most contexts) refers to text files used for two primary purposes: (1) saved directory listings in Virtual Dired mode, resembling ls -l output, and (2) per-directory configuration files containing Emacs local variables. These are plain text files without a formal binary specification. The Virtual Dired variant is more akin to a "file format" for storing directory snapshots, so the following analysis assumes that interpretation. If this does not match the intended ".DIRED" format, additional details would be required to refine the search.

List of Properties Intrinsic to the File Format

The ".dired" file format for Virtual Dired is a text-based representation of directory listings, parsed by Emacs to enable Dired operations. It mirrors the structure of UNIX ls -l output, with each line representing a file or directory entry. The properties are derived from file system attributes and include:

  • File type (e.g., 'd' for directory, '-' for regular file, 'l' for symbolic link).
  • Permissions (9-character string representing user/group/other read/write/execute rights, e.g., 'rwxr-xr-x').
  • Number of hard links (integer).
  • Owner (username or UID).
  • Group (group name or GID).
  • Size (in bytes, integer).
  • Modification timestamp (month, day, time or year, e.g., 'Sep 13 14:30' or 'Sep 13 2025').
  • File name (string).
  • Symlink target (if applicable, following ' -> ').

Directory headers appear as lines like '/path/to/directory:', followed by entry lines. The format is human-readable and machine-parsable but lacks a strict header or footer; properties are position-based within each line.

Two Direct Download Links for .DIRED Files

No direct download links for files with the ".DIRED" or ".dired" extension were found in the searched sources, including GitHub raw files and general web results. Such files are typically generated locally in Emacs and not commonly shared publicly. For illustration, a simple example ".dired" file content (a saved listing) could be:

/example/directory:
total 8
drwxr-xr-x  2 user group 4096 Sep 13 2025 .
drwxr-xr-x  3 user group 4096 Sep 13 2025 ..
-rw-r--r--  1 user group  123 Sep 13 2025 file.txt
lrwxr-xr-x  1 user group    8 Sep 13 2025 symlink -> target

To create one in Emacs: Use M-x dired-virtual on an ls -l output and save the buffer as ".dired".

Ghost Blog Embedded HTML JavaScript for Drag-and-Drop .DIRED File Dump

The following is a self-contained HTML page with embedded JavaScript that can be embedded in a Ghost blog post (or any HTML context). It allows dragging and dropping a ".dired" file, parses it, and dumps the properties to the screen.

.DIRED File Dumper
Drag and drop a .DIRED file here

Python Class for .DIRED File Handling

import re

class DiredFileHandler:
    def __init__(self, filepath):
        self.filepath = filepath
        self.entries = []

    def decode_and_read(self):
        with open(self.filepath, 'r') as f:
            content = f.read()
        lines = content.split('\n')
        current_dir = ''
        for line in lines:
            line = line.strip()
            if line.endswith(':'):
                current_dir = line[:-1]
            elif line and not line.startswith('total'):
                parts = re.split(r'\s+', line)
                if len(parts) >= 9:
                    entry = {
                        'directory': current_dir,
                        'file_type': parts[0][0],
                        'permissions': parts[0][1:],
                        'hard_links': int(parts[1]),
                        'owner': parts[2],
                        'group': parts[3],
                        'size': int(parts[4]),
                        'month': parts[5],
                        'day': parts[6],
                        'time_or_year': parts[7],
                        'file_name': ' '.join(parts[8:]).split(' -> ')[0],
                        'symlink_target': line.split(' -> ')[1] if ' -> ' in line else None
                    }
                    self.entries.append(entry)

    def print_properties(self):
        for entry in self.entries:
            print(entry)

    def write(self, new_filepath=None):
        filepath = new_filepath or self.filepath
        with open(filepath, 'w') as f:
            current_dir = ''
            for entry in self.entries:
                if entry['directory'] != current_dir:
                    current_dir = entry['directory']
                    f.write(f"{current_dir}:\n")
                    f.write("total 0\n")  # Placeholder; adjust as needed
                symlink = f" -> {entry['symlink_target']}" if entry['symlink_target'] else ''
                line = f"{entry['file_type']}{entry['permissions']} {entry['hard_links']} {entry['owner']} {entry['group']} {entry['size']} {entry['month']} {entry['day']} {entry['time_or_year']} {entry['file_name']}{symlink}\n"
                f.write(line)

# Example usage:
# handler = DiredFileHandler('example.dired')
# handler.decode_and_read()
# handler.print_properties()
# handler.write('new.dired')

Java Class for .DIRED File Handling

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

public class DiredFileHandler {
    private String filepath;
    private List<DiredEntry> entries = new ArrayList<>();

    public DiredFileHandler(String filepath) {
        this.filepath = filepath;
    }

    public void decodeAndRead() throws IOException {
        try (BufferedReader reader = new BufferedReader(new FileReader(filepath))) {
            String line;
            String currentDir = "";
            while ((line = reader.readLine()) != null) {
                line = line.trim();
                if (line.endsWith(":")) {
                    currentDir = line.substring(0, line.length() - 1);
                } else if (!line.isEmpty() && !line.startsWith("total")) {
                    String[] parts = Pattern.compile("\\s+").split(line);
                    if (parts.length >= 9) {
                        DiredEntry entry = new DiredEntry();
                        entry.directory = currentDir;
                        entry.fileType = parts[0].charAt(0);
                        entry.permissions = parts[0].substring(1);
                        entry.hardLinks = Integer.parseInt(parts[1]);
                        entry.owner = parts[2];
                        entry.group = parts[3];
                        entry.size = Integer.parseInt(parts[4]);
                        entry.month = parts[5];
                        entry.day = parts[6];
                        entry.timeOrYear = parts[7];
                        String fullName = String.join(" ", java.util.Arrays.copyOfRange(parts, 8, parts.length));
                        String[] nameParts = fullName.split(" -> ");
                        entry.fileName = nameParts[0];
                        entry.symlinkTarget = (nameParts.length > 1) ? nameParts[1] : null;
                        entries.add(entry);
                    }
                }
            }
        }
    }

    public void printProperties() {
        for (DiredEntry entry : entries) {
            System.out.println(entry);
        }
    }

    public void write(String newFilepath) throws IOException {
        String targetPath = (newFilepath != null) ? newFilepath : filepath;
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(targetPath))) {
            String currentDir = "";
            for (DiredEntry entry : entries) {
                if (!entry.directory.equals(currentDir)) {
                    currentDir = entry.directory;
                    writer.write(currentDir + ":\n");
                    writer.write("total 0\n");  // Placeholder
                }
                String symlink = (entry.symlinkTarget != null) ? " -> " + entry.symlinkTarget : "";
                String line = entry.fileType + entry.permissions + " " + entry.hardLinks + " " + entry.owner + " " + entry.group + " " + entry.size + " " + entry.month + " " + entry.day + " " + entry.timeOrYear + " " + entry.fileName + symlink + "\n";
                writer.write(line);
            }
        }
    }

    static class DiredEntry {
        String directory, permissions, owner, group, month, day, timeOrYear, fileName, symlinkTarget;
        char fileType;
        int hardLinks, size;

        @Override
        public String toString() {
            return "DiredEntry{" +
                   "directory='" + directory + "', " +
                   "fileType=" + fileType + ", " +
                   "permissions='" + permissions + "', " +
                   "hardLinks=" + hardLinks + ", " +
                   "owner='" + owner + "', " +
                   "group='" + group + "', " +
                   "size=" + size + ", " +
                   "month='" + month + "', " +
                   "day='" + day + "', " +
                   "timeOrYear='" + timeOrYear + "', " +
                   "fileName='" + fileName + "', " +
                   "symlinkTarget='" + symlinkTarget + "'}";
        }
    }

    // Example usage:
    // public static void main(String[] args) throws IOException {
    //     DiredFileHandler handler = new DiredFileHandler("example.dired");
    //     handler.decodeAndRead();
    //     handler.printProperties();
    //     handler.write("new.dired");
    // }
}

JavaScript Class for .DIRED File Handling

class DiredFileHandler {
    constructor(filepath) {
        this.filepath = filepath;
        this.entries = [];
    }

    async decodeAndRead() {
        // Assuming Node.js for file I/O
        const fs = require('fs');
        const content = fs.readFileSync(this.filepath, 'utf8');
        const lines = content.split('\n');
        let currentDir = '';
        lines.forEach(line => {
            line = line.trim();
            if (line.endsWith(':')) {
                currentDir = line.slice(0, -1);
            } else if (line && !line.startsWith('total')) {
                const parts = line.split(/\s+/);
                if (parts.length >= 9) {
                    const fullName = parts.slice(8).join(' ');
                    const nameParts = fullName.split(' -> ');
                    const entry = {
                        directory: currentDir,
                        fileType: parts[0][0],
                        permissions: parts[0].slice(1),
                        hardLinks: parseInt(parts[1]),
                        owner: parts[2],
                        group: parts[3],
                        size: parseInt(parts[4]),
                        month: parts[5],
                        day: parts[6],
                        timeOrYear: parts[7],
                        fileName: nameParts[0],
                        symlinkTarget: nameParts[1] || null
                    };
                    this.entries.push(entry);
                }
            }
        });
    }

    printProperties() {
        console.log(this.entries);
    }

    write(newFilepath = this.filepath) {
        const fs = require('fs');
        let output = '';
        let currentDir = '';
        this.entries.forEach(entry => {
            if (entry.directory !== currentDir) {
                currentDir = entry.directory;
                output += `${currentDir}:\n`;
                output += 'total 0\n';  // Placeholder
            }
            const symlink = entry.symlinkTarget ? ` -> ${entry.symlinkTarget}` : '';
            const line = `${entry.fileType}${entry.permissions} ${entry.hardLinks} ${entry.owner} ${entry.group} ${entry.size} ${entry.month} ${entry.day} ${entry.timeOrYear} ${entry.fileName}${symlink}\n`;
            output += line;
        });
        fs.writeFileSync(newFilepath, output);
    }
}

// Example usage (Node.js):
// const handler = new DiredFileHandler('example.dired');
// await handler.decodeAndRead();
// handler.printProperties();
// handler.write('new.dired');

C Implementation for .DIRED File Handling (Using Struct Instead of Class)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

typedef struct {
    char *directory;
    char fileType;
    char *permissions;
    int hardLinks;
    char *owner;
    char *group;
    int size;
    char *month;
    char *day;
    char *timeOrYear;
    char *fileName;
    char *symlinkTarget;
} DiredEntry;

typedef struct {
    char *filepath;
    DiredEntry *entries;
    int count;
} DiredFileHandler;

DiredFileHandler* createHandler(const char *filepath) {
    DiredFileHandler *handler = malloc(sizeof(DiredFileHandler));
    handler->filepath = strdup(filepath);
    handler->entries = NULL;
    handler->count = 0;
    return handler;
}

void decodeAndRead(DiredFileHandler *handler) {
    FILE *file = fopen(handler->filepath, "r");
    if (!file) return;

    char line[1024];
    char *currentDir = NULL;
    while (fgets(line, sizeof(line), file)) {
        char *trimmed = strtok(line, "\n");
        if (!trimmed) continue;

        if (trimmed[strlen(trimmed) - 1] == ':') {
            free(currentDir);
            currentDir = strdup(trimmed);
            currentDir[strlen(currentDir) - 1] = '\0';
        } else if (strncmp(trimmed, "total", 5) != 0) {
            handler->entries = realloc(handler->entries, (handler->count + 1) * sizeof(DiredEntry));
            DiredEntry *entry = &handler->entries[handler->count++];

            entry->directory = strdup(currentDir);
            sscanf(trimmed, "%c%9s %d %s %s %d %s %s %s", &entry->fileType, entry->permissions = malloc(10),
                   &entry->hardLinks, entry->owner = malloc(32), entry->group = malloc(32),
                   &entry->size, entry->month = malloc(4), entry->day = malloc(3), entry->timeOrYear = malloc(5));

            // Parse file name and symlink
            char *nameStart = strstr(trimmed, entry->timeOrYear) + strlen(entry->timeOrYear) + 1;
            char *arrow = strstr(nameStart, " -> ");
            if (arrow) {
                entry->fileName = strndup(nameStart, arrow - nameStart);
                entry->symlinkTarget = strdup(arrow + 4);
            } else {
                entry->fileName = strdup(nameStart);
                entry->symlinkTarget = NULL;
            }
        }
    }
    free(currentDir);
    fclose(file);
}

void printProperties(DiredFileHandler *handler) {
    for (int i = 0; i < handler->count; i++) {
        DiredEntry *entry = &handler->entries[i];
        printf("Directory: %s\nFile Type: %c\nPermissions: %s\nHard Links: %d\nOwner: %s\nGroup: %s\nSize: %d\nMonth: %s\nDay: %s\nTime/Year: %s\nFile Name: %s\nSymlink Target: %s\n\n",
               entry->directory, entry->fileType, entry->permissions, entry->hardLinks, entry->owner, entry->group,
               entry->size, entry->month, entry->day, entry->timeOrYear, entry->fileName, entry->symlinkTarget ? entry->symlinkTarget : "None");
    }
}

void write(DiredFileHandler *handler, const char *newFilepath) {
    FILE *file = fopen(newFilepath ? newFilepath : handler->filepath, "w");
    if (!file) return;

    char *currentDir = NULL;
    for (int i = 0; i < handler->count; i++) {
        DiredEntry *entry = &handler->entries[i];
        if (!currentDir || strcmp(entry->directory, currentDir) != 0) {
            free(currentDir);
            currentDir = strdup(entry->directory);
            fprintf(file, "%s:\n", currentDir);
            fprintf(file, "total 0\n");  // Placeholder
        }
        char *symlink = entry->symlinkTarget ? malloc(strlen(entry->symlinkTarget) + 5) : "";
        if (entry->symlinkTarget) sprintf(symlink, " -> %s", entry->symlinkTarget);
        fprintf(file, "%c%s %d %s %s %d %s %s %s %s%s\n",
                entry->fileType, entry->permissions, entry->hardLinks, entry->owner, entry->group,
                entry->size, entry->month, entry->day, entry->timeOrYear, entry->fileName, symlink);
        free(symlink);
    }
    free(currentDir);
    fclose(file);
}

void destroyHandler(DiredFileHandler *handler) {
    for (int i = 0; i < handler->count; i++) {
        free(handler->entries[i].directory);
        free(handler->entries[i].permissions);
        free(handler->entries[i].owner);
        free(handler->entries[i].group);
        free(handler->entries[i].month);
        free(handler->entries[i].day);
        free(handler->entries[i].timeOrYear);
        free(handler->entries[i].fileName);
        free(handler->entries[i].symlinkTarget);
    }
    free(handler->entries);
    free(handler->filepath);
    free(handler);
}

// Example usage:
// int main() {
//     DiredFileHandler *handler = createHandler("example.dired");
//     decodeAndRead(handler);
//     printProperties(handler);
//     write(handler, "new.dired");
//     destroyHandler(handler);
//     return 0;
// }