New Project: SD Cloner for PicoCalc (C + GTK3)

Hello everyone,

I’m new to the community and recently received my PicoCalc about a week ago. After finally getting some time to explore it, I accidentally erased the original SD card during experimentation. It took several hours of work to restore the system I developed SD Cloner on Pop!_OS 22.04 LTS (Wayland) using a native C compiler to ensure full compatibility and performance on modern Linux systems. The application allows reliable duplication of PicoCalc SD cards, performing direct SD-to-SD cloning while intelligently analyzing storage requirements. For example, if the source card is 128 GB and the target card is 32 GB, SD Cloner calculates the data footprint and, if it fits, automatically resizes and writes the image to the smaller card. It’s a safe, Linux-native cloning utility capable of both bit-for-bit imaging and filesystem-aware size optimization. Photo shows image burning to SD - that’s way no source is selected.

I’ve open-sourced the project on GitHub. Anyone interested in testing, refining, or contributing improvements is very welcome to collaborate!

:backhand_index_pointing_right: GitHub Repository: drericflores/sdcloner

2 Likes

Hello Dr. Flores and welcome.

I developed SD Cloner on Pop!_OS 22.04 LTS (Wayland) using a native C compiler to ensure full compatibility and performance on modern Linux systems.

Thank you, but this is a strange point when this is the expectation for a block device cloning tool. There’s a semi-popular Electron (read: web browser) program out there but its being non-native is why it is slow and not recommended on any basis other than its ease-of-use. I mention this because you bring up the fact that your program runs natively repeatedly throughout your post.

You say you developed this program using a native C compiler as well; are there any reasons you would use a non-native C compiler to develop for Linux? I wasn’t aware that was practical on any platform and had thought even on differing systems cross-compilation was the norm.

I know “burning” is reasonable terminology for writing a block device as it is literal when using optical media but I must admit seeing it in the context of SD cards makes me uneasy as they do on occasion halt and catch fire.

My following notes are regarding the GitHub project.

Your README.md lists the target for your program as the PicoCalc rather than Linux. Is this correct?

Your project’s directory layout in the README.txt lists some non-existent files and no correct paths. It also seems to lead into some malformed MarkDown syntax describing installation.

A part that concerns me is this:

**Safety and Reliability Model**

Source is never modified — all mounts are read-only. Block devices only — GUI validates with `stat()` and `lsblk`. Unmount-before-write safeguard on destination. Comprehensive logging for every shell invocation. Explicit failure modes to prevent silent corruption.

**Test Summary**

Absolutely — here’s a **block-style Markdown table** that looks clean and professional on GitHub. This layout keeps borders visible and content aligned, giving it a structured, report-like appearance:

The safety mechanisms described are standard practice, and the conversational tone of the test output implies it was formatted by a LLM. I find this extremely worrying because that lack of deliberate proofreading of your prose is in the description of a program which is juggling filesystems, a task in which even experts make catastrophic mistakes.

Later the README says:

Partition map mirroring (multi-partition shrink) Real-time byte-progress parsing (libparted integration) Hidden non-removable disks Optional write verification via checksum Dark theme + i18n (GTK theming & gettext)

I skimmed the #includes but I couldn’t find libparted. Where are you using this?

Your C code in general seems underdocumented given its context. For example, this function from sdcloner_engine.c:

// List partitions for a disk (e.g. /dev/sdd -> /dev/sdd1, /dev/sdd2).
// Returns a malloc'd array of strings; caller frees each and the array.
static char** list_partitions(const char* disk, int* out_count) {
    char cmd[512];
    snprintf(cmd, sizeof(cmd),
        "lsblk -rno PATH,TYPE '%s' | awk '$2==\"part\"{print $1}'", disk);
    char* out = run_cmd_capture(cmd);
    if (!out) { *out_count = 0; return NULL; }
    int cap = 8, n = 0;
    char** arr = malloc(sizeof(char*) * cap);
    char* save = NULL;
    for (char* line = strtok_r(out, "\n", &save); line; line = strtok_r(NULL, "\n", &save)) {
        if (!*line) continue;
        if (n == cap) { cap *= 2; arr = realloc(arr, sizeof(char*) * cap); }
        arr[n++] = strdup(line);
    }
    free(out);
    *out_count = n;
    return arr;
}

In pseudocode, I might describe this as:

  • Run $ xargs lsblk -rno PATH,TYPE | awk '$2==\"part\"{print $1}' with a standard input of disk
  • If the command failed, return an error status.
  • Allocate enough memory to keep track of 8 strings; store a reference to an allocated copy of each line from the command output. If the number of strings exceeds the allocation, double it.
  • Return that array.

Except, because the cmd is 512B, the function will error out in unpredictable ways if disk is longer than a certain length. This is a very reasonable limit as Linux paths can’t be longer than a few hundred bytes anyway, assuming this program will only ever be used on Linux systems where paths can’t be longer than a few hundred bytes, but this limitation or assumption isn’t documented. In fact, this function is so dense yet so long it took me a moment to understand it myself and longer to piece together (with prior knowledge) that it isn’t a segfault hazard at least on Linux.

A better function might be this:

/* List partitions for the given block devices (e.g. /dev/hd0). Returns a
 * malloc(3)d double-nul-terminated array of strings.
 * Calls cut(1p), grep(1p), and lsblk(1) (util-linux). */
static char *
list_partitions(const char *disk, int *size) {
        static char *cmd = "lsblk -rno PATH,TYPE '%s'" /* list subdevices */
                " | grep 'part$'"                      /* filter partitions */
                " | cut -d ' ' -f 1";                  /* print paths only */
        static char *line = NULL;
        int line_l; /* without NUL */
        char *retval;

        *size = 0;

        /* write command line */
        line_l = snprintf(NULL, 0, cmd, disk); /* gets length */
        if ((line = realloc(line, line_l + 1)) == NULL) { return NULL; }
        (void)snprintf(line, line_l + 1, cmd, disk);

        /* run, clean, serve */
        if (!(retval = run_cmd_capture(cmd))) { return NULL; } /* cmd fail */
        for (size_t i = 0; retval[i] != '\0'; ++i) /* replace '\n' with '\0' */
                { if (retval[i] == '\n') { ++*size; retval[i] = '\0'; } }

        return retval;
}

It works differently (granting a double-nul-terminated string rather than an array of addresses) but can be adapted. It’s in theory significantly more efficient, safer due to documented assumptions, doesn’t use magic numbers, and is commented enough that understanding this single function doesn’t require understanding the rest of the codebase, but I haven’t tested it so it might have a wrinkle.

1 Like

I’m sorry for being harsh, but this whole thing is just horrible. It feels like it was written by someone who wants the challenge of writing something in C but then bungles it up and takes a bunch of [very unsafe] shortcuts. How much of it was done by an LLM? Why doesn’t it have the advertised features?

This provides less value than a simple bash script…

I’m more confused by this one: GitHub - harshu3008/picocalc-sd-formatter: A GUI tool for formatting SD cards for use with the PicoCalc device. This tool creates the correct partition layout required by the PicoCalc operating system. This project was developed with the assistance of Cursor IDE's AI capabilities.
It’s definitely AI generated garbage, but the really odd thing is that the repo is constantly updated with just changes made to the readme. I’m asuming it’s on an automated loop, though it makes no sense to me why someone would do that. Maybe people are trying to farm github activity now, so they can sell their account to someone who wants to look like they’ve been using it for a long time and have “experience”?

All I know is it always shows up at the top of the list when I do a search on github for “picocalc” and sort by most recent activity. (I do this every once in a while since it’s a great way to find hidden projects that haven’t been posted to the forums here.) I get tired of seeing that garbage project every time though.

1 Like

I also think that AI was involved in his Project sdprep ( GitHub - drericflores/sdprep: A picocalc sd card formatter ), as the version available on GitHub cannot even be built without making some corrections. I wouldn’t upload anything to git that I can’t build.