Cleanup previous PR

This commit is contained in:
Kovid Goyal
2026-04-01 19:52:40 +05:30
parent 05f4c324f1
commit 78f1607bf5
3 changed files with 24 additions and 38 deletions

View File

@@ -3716,28 +3716,3 @@ class Boss:
def copy_or_noop(self) -> None: def copy_or_noop(self) -> None:
if w := self.active_window: if w := self.active_window:
w.copy_or_noop() w.copy_or_noop()
def nth_decoded_file_url(self, n: int, text_uri_list: bytes) -> tuple[bool, str]:
' Return the abspath of the nth url in text_uri_list if it is a valid file:// URL. Appropriate error code returned otherwise '
from urllib.parse import unquote, urlparse
for line in text_uri_list.decode().splitlines():
if line.startswith('#'):
continue
if n <= 0:
break
n -= 1
else:
return False, 'ENOENT'
try:
purl = urlparse(line.strip())
if purl.scheme != 'file':
return False, 'EUNKNOWN'
if not purl.path:
return False, 'EINVAL'
path = unquote(purl.path)
if not os.path.isabs(path):
return False, 'EINVAL'
path = os.path.abspath(os.path.realpath(path))
return True, path
except Exception:
return False, 'EINVAL'

View File

@@ -8,6 +8,7 @@
#include "dnd.h" #include "dnd.h"
#include "base64.h" #include "base64.h"
#include "control-codes.h" #include "control-codes.h"
#include "safe-wrappers.h"
#include "iqsort.h" #include "iqsort.h"
#include <dirent.h> #include <dirent.h>
#include <fcntl.h> #include <fcntl.h>
@@ -516,7 +517,7 @@ drop_send_file_data(Window *w, const char *path) {
} }
if (!S_ISREG(st.st_mode)) { drop_send_error(w, EINVAL); return; } if (!S_ISREG(st.st_mode)) { drop_send_error(w, EINVAL); return; }
int fd = open(path, O_RDONLY | O_CLOEXEC); int fd = safe_open(path, O_RDONLY | O_CLOEXEC, 0);
if (fd < 0) { if (fd < 0) {
switch (errno) { switch (errno) {
case ENOENT: case ENOTDIR: drop_send_error(w, ENOENT); break; case ENOENT: case ENOTDIR: drop_send_error(w, ENOENT); break;
@@ -530,20 +531,20 @@ drop_send_file_data(Window *w, const char *path) {
char *data = NULL; char *data = NULL;
if (data_sz) { if (data_sz) {
data = malloc(data_sz); data = malloc(data_sz);
if (!data) { close(fd); drop_send_error(w, EIO); return; } if (!data) { safe_close(fd, __FILE__, __LINE__); drop_send_error(w, EIO); return; }
size_t done = 0; size_t done = 0;
while (done < data_sz) { while (done < data_sz) {
ssize_t n = read(fd, data + done, data_sz - done); ssize_t n = read(fd, data + done, data_sz - done);
if (n < 0) { if (n < 0) {
if (errno == EINTR) continue; if (errno == EINTR) continue;
free(data); close(fd); drop_send_error(w, EIO); return; free(data); safe_close(fd, __FILE__, __LINE__); drop_send_error(w, EIO); return;
} }
if (n == 0) break; if (n == 0) break;
done += (size_t)n; done += (size_t)n;
} }
data_sz = done; data_sz = done;
} }
close(fd); safe_close(fd, __FILE__, __LINE__);
char hdr[128]; char hdr[128];
int hdr_sz = snprintf(hdr, sizeof(hdr), "\x1b]%d;t=r", DND_CODE); int hdr_sz = snprintf(hdr, sizeof(hdr), "\x1b]%d;t=r", DND_CODE);

View File

@@ -514,7 +514,8 @@ class TestDnDProtocol(BaseTest):
def test_uri_file_transfer_basic(self) -> None: def test_uri_file_transfer_basic(self) -> None:
"""t=s request sends the content of a regular file as t=r chunks.""" """t=s request sends the content of a regular file as t=r chunks."""
import os, tempfile import os
import tempfile
content = b'Hello, remote DnD world!\n' * 100 content = b'Hello, remote DnD world!\n' * 100
with tempfile.NamedTemporaryFile(delete=False) as f: with tempfile.NamedTemporaryFile(delete=False) as f:
f.write(content) f.write(content)
@@ -537,7 +538,8 @@ class TestDnDProtocol(BaseTest):
def test_uri_file_transfer_integrity(self) -> None: def test_uri_file_transfer_integrity(self) -> None:
"""File content is transferred byte-for-byte (binary integrity).""" """File content is transferred byte-for-byte (binary integrity)."""
import os, tempfile import os
import tempfile
# Use binary content with all byte values to check integrity # Use binary content with all byte values to check integrity
content = bytes(range(256)) * 512 # 128 KiB content = bytes(range(256)) * 512 # 128 KiB
with tempfile.NamedTemporaryFile(delete=False) as f: with tempfile.NamedTemporaryFile(delete=False) as f:
@@ -571,7 +573,8 @@ class TestDnDProtocol(BaseTest):
def test_uri_file_transfer_out_of_bounds(self) -> None: def test_uri_file_transfer_out_of_bounds(self) -> None:
"""t=s with an index beyond the URI list returns ENOENT.""" """t=s with an index beyond the URI list returns ENOENT."""
import os, tempfile import os
import tempfile
with tempfile.NamedTemporaryFile(delete=False) as f: with tempfile.NamedTemporaryFile(delete=False) as f:
fpath = f.name fpath = f.name
try: try:
@@ -588,7 +591,8 @@ class TestDnDProtocol(BaseTest):
def test_uri_request_without_uri_list_returns_einval(self) -> None: def test_uri_request_without_uri_list_returns_einval(self) -> None:
"""t=s without prior text/uri-list request returns EINVAL.""" """t=s without prior text/uri-list request returns EINVAL."""
import os, tempfile import os
import tempfile
with tempfile.NamedTemporaryFile(delete=False) as f: with tempfile.NamedTemporaryFile(delete=False) as f:
fpath = f.name fpath = f.name
try: try:
@@ -619,7 +623,9 @@ class TestDnDProtocol(BaseTest):
def test_uri_directory_transfer_tree(self) -> None: def test_uri_directory_transfer_tree(self) -> None:
"""Full directory tree transfer: listing, sub-dirs, file integrity.""" """Full directory tree transfer: listing, sub-dirs, file integrity."""
import os, tempfile, hashlib import hashlib
import os
import tempfile
# Build a tree: root/ a.txt b/ b/c.txt b/d/ b/d/e.txt # Build a tree: root/ a.txt b/ b/c.txt b/d/ b/d/e.txt
with tempfile.TemporaryDirectory() as root: with tempfile.TemporaryDirectory() as root:
@@ -739,7 +745,8 @@ class TestDnDProtocol(BaseTest):
def test_dir_handle_close_and_reuse(self) -> None: def test_dir_handle_close_and_reuse(self) -> None:
"""Closing a directory handle invalidates it; subsequent requests return EINVAL.""" """Closing a directory handle invalidates it; subsequent requests return EINVAL."""
import os, tempfile import os
import tempfile
with tempfile.TemporaryDirectory() as root: with tempfile.TemporaryDirectory() as root:
open(os.path.join(root, 'f.txt'), 'w').close() open(os.path.join(root, 'f.txt'), 'w').close()
uri_list = f'file://{root}\r\n'.encode() uri_list = f'file://{root}\r\n'.encode()
@@ -765,7 +772,8 @@ class TestDnDProtocol(BaseTest):
def test_dir_entry_out_of_bounds_returns_enoent(self) -> None: def test_dir_entry_out_of_bounds_returns_enoent(self) -> None:
"""Reading a directory entry with an out-of-range index returns ENOENT.""" """Reading a directory entry with an out-of-range index returns ENOENT."""
import os, tempfile import os
import tempfile
with tempfile.TemporaryDirectory() as root: with tempfile.TemporaryDirectory() as root:
open(os.path.join(root, 'only.txt'), 'w').close() open(os.path.join(root, 'only.txt'), 'w').close()
uri_list = f'file://{root}\r\n'.encode() uri_list = f'file://{root}\r\n'.encode()
@@ -786,7 +794,8 @@ class TestDnDProtocol(BaseTest):
def test_dir_unique_identifier_prevents_loops(self) -> None: def test_dir_unique_identifier_prevents_loops(self) -> None:
"""Each directory listing starts with a unique id (dev:inode format).""" """Each directory listing starts with a unique id (dev:inode format)."""
import os, tempfile import os
import tempfile
with tempfile.TemporaryDirectory() as root: with tempfile.TemporaryDirectory() as root:
sub = os.path.join(root, 'sub') sub = os.path.join(root, 'sub')
os.mkdir(sub) os.mkdir(sub)
@@ -822,7 +831,8 @@ class TestDnDProtocol(BaseTest):
def test_window_close_during_transfer_no_leak(self) -> None: def test_window_close_during_transfer_no_leak(self) -> None:
"""Closing the window while dir handles are open frees all resources (no crash).""" """Closing the window while dir handles are open frees all resources (no crash)."""
import os, tempfile import os
import tempfile
with tempfile.TemporaryDirectory() as root: with tempfile.TemporaryDirectory() as root:
open(os.path.join(root, 'f.txt'), 'w').close() open(os.path.join(root, 'f.txt'), 'w').close()
uri_list = f'file://{root}\r\n'.encode() uri_list = f'file://{root}\r\n'.encode()