Have top level symlink behavior match for local and remote drops

This commit is contained in:
Kovid Goyal
2026-04-30 09:38:17 +05:30
parent 79bf7ef1a4
commit ee84e68ca4
3 changed files with 17 additions and 25 deletions

View File

@@ -171,15 +171,12 @@ MIME type is not present in the drop, the terminal must reply with
If the client requests an entry that is not a supported URI type the
terminal must reply with ``EUNKNOWN``.
Terminals must ONLY send data for regular files or directories. Symbolic links must be
resolved and the corresponding file or directory read. Only if the symbolic
link cannot be resolved must it be transmitted as a symbolic link (in which
case ``X=1`` and the payload is the base64 encoded target of the symlink. See
below for more details about sending symlinks.
Terminals must ONLY send data for regular files, symbolic links and directories.
See below for more details about sending symlinks.
If the terminal does not have permission to read the file it must reply with
``EPERM``. Terminals must respond with ``EINVAL`` if the file is not a regular
file after resolving symlinks and ``ENOENT`` if the file does not exist. If an
file or symlink or directory and ``ENOENT`` if the file does not exist. If an
I/O error occurs the terminal must send ``EIO``.
For security reasons, terminals must reply with ``EPERM`` if the drag

View File

@@ -947,12 +947,14 @@ drop_send_dir_listing(Window *w, const char *path) {
}
static void
drop_send_symlink(Window *w, const char *target, size_t sz) {
drop_send_symlink(Window *w, const char *path) {
char target[PATH_MAX]; ssize_t tgtsz;
if ((tgtsz = readlink(path, target, sizeof(target)-1)) < 0) { drop_send_error(w, EIO); return; }
char hdr[128];
int hdr_sz = snprintf(hdr, sizeof(hdr), "\x1b]%d;t=r", DND_CODE);
hdr_sz += drop_append_request_keys(w, hdr + hdr_sz, sizeof(hdr) - hdr_sz);
hdr_sz += snprintf(hdr + hdr_sz, sizeof(hdr) - hdr_sz, ":X=1");
queue_payload_to_child(w->id, w->drop.client_id, &w->drop.pending, hdr, hdr_sz, target, sz, true);
queue_payload_to_child(w->id, w->drop.client_id, &w->drop.pending, hdr, hdr_sz, target, tgtsz, true);
queue_payload_to_child(w->id, w->drop.client_id, &w->drop.pending, hdr, hdr_sz, NULL, 0, true);
}
@@ -985,31 +987,24 @@ do_drop_request_uri_data(Window *w, int32_t mime_idx, int32_t file_idx) {
}
struct stat st;
if (stat(path, &st) < 0) {
if (lstat(path, &st) < 0) {
switch (errno) {
case ENOENT: case ENOTDIR: drop_send_error(w, ENOENT); break;
case EACCES: case EPERM: drop_send_error(w, EPERM); break;
default: drop_send_error(w, EIO); break;
}
return true;
if (lstat(path, &st) < 0) {
switch (errno) {
case ENOENT: case ENOTDIR: drop_send_error(w, ENOENT); break;
case EACCES: case EPERM: drop_send_error(w, EPERM); break;
default: drop_send_error(w, EIO); break;
}
// We have a broken symlink
char target[PATH_MAX]; ssize_t tgtsz;
if ((tgtsz = readlink(path, target, sizeof(target)-1)) < 0) drop_send_error(w, ENOENT);
drop_send_symlink(w, target, tgtsz);
return true;
}
bool sync;
bool sync = true;
if (S_ISDIR(st.st_mode)) {
drop_send_dir_listing(w, path);
sync = true;
} else if (S_ISREG(st.st_mode)) {
sync = drop_send_file_data(w, path);
} else if (S_ISLNK(st.st_mode)) {
drop_send_symlink(w, path);
} else {
drop_send_error(w, EINVAL);
sync = true;
}
return sync;
}

View File

@@ -37,7 +37,7 @@ class Capture(WriteCapture):
self.pty.write_to_child(data)
def create_fs(base, include_toplevel_working_symlink=False):
def create_fs(base, include_toplevel_working_symlink=True):
join = partial(os.path.join, base)
def w(sz, *path):
if sz == 0:
@@ -232,7 +232,7 @@ class TestDnDKitten(BaseTest):
self.assertEqual('text/uri-list\x00image/png', self.probe_state('drop_mimes').rstrip('\x00'))
self.wait_for_state('drop_data_requests', ((1,0,0), (4,0,0)))
self.assertEqual('text/uri-list', self.probe_state('drop_getting_data_for_mime'))
create_fs(self.src_data_dir, include_toplevel_working_symlink=not remote_client)
create_fs(self.src_data_dir)
uri_list, path_list = [], []
for x in sorted(os.listdir(self.src_data_dir)):
uri_list.append(as_file_url(self.src_data_dir, x))