1
0
mirror of https://github.com/skeeto/w64devkit.git synced 2026-10-23 06:08:56 +03:00

New command: recycle

Send files and folders to the recycle bin without confirmation.
This commit is contained in:
Christopher Wellons
2026-03-26 18:59:09 -04:00
parent 6d6cd37cbe
commit 75ee252f2b
2 changed files with 148 additions and 0 deletions

View File

@@ -807,6 +807,10 @@ RUN printf "id ICON \"$PREFIX/src/w64devkit.ico\"" >w64devkit.rc \
-O2 -fno-asynchronous-unwind-tables -fno-builtin -Wl,--gc-sections \
-s -nostdlib -o $PREFIX/bin/peports.exe $PREFIX/src/peports.c \
-lkernel32 -lshell32 -lmemory \
&& $ARCH-gcc \
-Oz -fno-asynchronous-unwind-tables -fno-builtin -Wl,--gc-sections \
-s -nostdlib -o $PREFIX/bin/recycle.exe $PREFIX/src/recycle.c \
-lkernel32 -lshell32 -lmemory \
&& $ARCH-gcc -DEXE=pkg-config.exe -DCMD=pkg-config \
-Oz -fno-asynchronous-unwind-tables -Wl,--gc-sections -s -nostdlib \
-o $PREFIX/bin/$ARCH-pkg-config.exe $PREFIX/src/alias.c -lkernel32 \

144
src/recycle.c Normal file
View File

@@ -0,0 +1,144 @@
// recycle: send files and folders to the recycle bin without confirmation
// $ cc -nostartfiles -o recycle.exe recycle.c
// $ recycle [PATHS...]
// Tip: Enable storage sense to automatically clear old recycle bin items
// This is free and unencumbered software released into the public domain.
#include <stddef.h>
#include <stdint.h>
#include <uchar.h>
#define lenof(a) (ptrdiff_t)(sizeof(a) / sizeof(*(a)))
#define affirm(c) while (!(c)) __builtin_trap()
#define new(a, n, t) (t *)alloc(a, n, sizeof(t), _Alignof(t))
typedef struct {
uintptr_t wnd;
int32_t func;
char16_t *from;
char16_t *to;
int16_t flags;
int32_t abort_flags;
uintptr_t mappings;
uintptr_t title;
} FileOp;
enum : int32_t {
FO_DELETE = 0x0003,
};
enum : int16_t {
FOF_ALLOWUNDO = 0x0040,
FOF_NOCONFIRMATION = 0x0010,
FOF_NOERRORUI = 0x0400,
FOF_SILENT = 0x0004,
};
enum : int32_t {
FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100,
FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000,
FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200,
};
#define W32 [[gnu::dllimport, gnu::stdcall]]
W32 char16_t **CommandLineToArgvW(char16_t *, int32_t *);
W32 void ExitProcess(int32_t);
W32 int32_t FormatMessageW(int32_t,uintptr_t,int32_t,int32_t,char16_t**,int32_t,uintptr_t);
W32 char16_t *GetCommandLineW();
W32 uintptr_t GetStdHandle(int32_t);
W32 int32_t SHFileOperationW(FileOp *);
W32 int32_t WriteConsoleW(uintptr_t,char16_t*,int32_t,int32_t *,uintptr_t);
typedef struct {
char *beg;
char *end;
} Arena;
static size_t tousize(ptrdiff_t x)
{
affirm(x >= 0);
return (size_t)x;
}
static char *alloc(Arena *a, ptrdiff_t count, ptrdiff_t size, ptrdiff_t align)
{
ptrdiff_t pad = (ptrdiff_t)-(uintptr_t)a->beg & (align - 1);
affirm(count < (a->end - a->beg - pad)/size);
char *r = a->beg + pad;
a->beg += pad;
return __builtin_memset(r, 0, tousize(count*size));
}
static int32_t len16(char16_t *s)
{
int32_t len = 0;
for (; s[len]; len++) {}
return len;
}
static char16_t *termzz(Arena *a, char16_t *s)
{
ptrdiff_t len = len16(s);
char16_t *r = new(a, len+2, char16_t);
__builtin_memcpy(r, s, tousize(len)*2);
return r;
}
static char16_t *geterror(int32_t err)
{
int32_t flags =
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS;
char16_t *r = {};
FormatMessageW(flags, 0, err, 0, &r, 0, 0);
return r;
}
static void report(char16_t *path, int32_t code)
{
uintptr_t h = GetStdHandle(-12);
static char16_t pre[] = u"recycle: ";
WriteConsoleW(h, pre, lenof(pre)-1, &(int32_t){}, 0);
WriteConsoleW(h, path, len16(path), &(int32_t){}, 0);
static char16_t mid[] = u": ";
WriteConsoleW(h, mid, lenof(mid)-1, &(int32_t){}, 0);
char16_t *err = geterror(code);
WriteConsoleW(h, err, len16(err), &(int32_t){}, 0);
WriteConsoleW(h, u"\n", 1, &(int32_t){}, 0);
}
static int32_t recycle(int32_t argc, char16_t **argv, Arena scratch)
{
int32_t errors = 0;
for (int32_t i = 1; i < argc; i++) {
Arena a = scratch;
FileOp op = {};
op.func = FO_DELETE;
op.from = termzz(&a, argv[i]);
op.flags =
FOF_ALLOWUNDO |
FOF_NOCONFIRMATION |
FOF_NOERRORUI |
FOF_SILENT;
int32_t r = SHFileOperationW(&op);
if (r) {
report(argv[i], r);
errors++;
}
}
return errors > 0;
}
[[gnu::stdcall]]
void mainCRTStartup()
{
static char mem[1<<18];
char16_t *cmd = GetCommandLineW();
int32_t argc = {};
char16_t **argv = CommandLineToArgvW(cmd, &argc);
int32_t stat = recycle(argc, argv, (Arena){mem, mem+lenof(mem)});
ExitProcess(stat);
__builtin_unreachable();
}