xref: /netbsd-src/external/gpl3/gdb/dist/gdbserver/hostio.cc (revision f1c2b495c8d0ed769f039187bdd4f963026e012b)
18dffb485Schristos /* Host file transfer support for gdbserver.
2*f1c2b495Schristos    Copyright (C) 2007-2024 Free Software Foundation, Inc.
38dffb485Schristos 
48dffb485Schristos    Contributed by CodeSourcery.
58dffb485Schristos 
68dffb485Schristos    This file is part of GDB.
78dffb485Schristos 
88dffb485Schristos    This program is free software; you can redistribute it and/or modify
98dffb485Schristos    it under the terms of the GNU General Public License as published by
108dffb485Schristos    the Free Software Foundation; either version 3 of the License, or
118dffb485Schristos    (at your option) any later version.
128dffb485Schristos 
138dffb485Schristos    This program is distributed in the hope that it will be useful,
148dffb485Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
158dffb485Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
168dffb485Schristos    GNU General Public License for more details.
178dffb485Schristos 
188dffb485Schristos    You should have received a copy of the GNU General Public License
198dffb485Schristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
208dffb485Schristos 
214b169a6bSchristos #include "gdbsupport/fileio.h"
228dffb485Schristos #include "hostio.h"
238dffb485Schristos 
248dffb485Schristos #include <fcntl.h>
258dffb485Schristos #include <limits.h>
268dffb485Schristos #include <unistd.h>
278dffb485Schristos #include <sys/types.h>
288dffb485Schristos #include <sys/stat.h>
298dffb485Schristos #include "gdbsupport/fileio.h"
308dffb485Schristos 
318dffb485Schristos struct fd_list
328dffb485Schristos {
338dffb485Schristos   int fd;
348dffb485Schristos   struct fd_list *next;
358dffb485Schristos };
368dffb485Schristos 
378dffb485Schristos static struct fd_list *open_fds;
388dffb485Schristos 
398dffb485Schristos static int
408dffb485Schristos safe_fromhex (char a, int *nibble)
418dffb485Schristos {
428dffb485Schristos   if (a >= '0' && a <= '9')
438dffb485Schristos     *nibble = a - '0';
448dffb485Schristos   else if (a >= 'a' && a <= 'f')
458dffb485Schristos     *nibble = a - 'a' + 10;
468dffb485Schristos   else if (a >= 'A' && a <= 'F')
478dffb485Schristos     *nibble = a - 'A' + 10;
488dffb485Schristos   else
498dffb485Schristos     return -1;
508dffb485Schristos 
518dffb485Schristos   return 0;
528dffb485Schristos }
538dffb485Schristos 
548dffb485Schristos /* Filenames are hex encoded, so the maximum we can handle is half the
558dffb485Schristos    packet buffer size.  Cap to PATH_MAX, if it is shorter.  */
568dffb485Schristos #if !defined (PATH_MAX) || (PATH_MAX > (PBUFSIZ / 2 + 1))
578dffb485Schristos #  define HOSTIO_PATH_MAX (PBUFSIZ / 2 + 1)
588dffb485Schristos #else
598dffb485Schristos #  define HOSTIO_PATH_MAX PATH_MAX
608dffb485Schristos #endif
618dffb485Schristos 
628dffb485Schristos static int
638dffb485Schristos require_filename (char **pp, char *filename)
648dffb485Schristos {
658dffb485Schristos   int count;
668dffb485Schristos   char *p;
678dffb485Schristos 
688dffb485Schristos   p = *pp;
698dffb485Schristos   count = 0;
708dffb485Schristos 
718dffb485Schristos   while (*p && *p != ',')
728dffb485Schristos     {
738dffb485Schristos       int nib1, nib2;
748dffb485Schristos 
758dffb485Schristos       /* Don't allow overflow.  */
768dffb485Schristos       if (count >= HOSTIO_PATH_MAX - 1)
778dffb485Schristos 	return -1;
788dffb485Schristos 
798dffb485Schristos       if (safe_fromhex (p[0], &nib1)
808dffb485Schristos 	  || safe_fromhex (p[1], &nib2))
818dffb485Schristos 	return -1;
828dffb485Schristos 
838dffb485Schristos       filename[count++] = nib1 * 16 + nib2;
848dffb485Schristos       p += 2;
858dffb485Schristos     }
868dffb485Schristos 
878dffb485Schristos   filename[count] = '\0';
888dffb485Schristos   *pp = p;
898dffb485Schristos   return 0;
908dffb485Schristos }
918dffb485Schristos 
928dffb485Schristos static int
938dffb485Schristos require_int (char **pp, int *value)
948dffb485Schristos {
958dffb485Schristos   char *p;
968dffb485Schristos   int count, firstdigit;
978dffb485Schristos 
988dffb485Schristos   p = *pp;
998dffb485Schristos   *value = 0;
1008dffb485Schristos   count = 0;
1018dffb485Schristos   firstdigit = -1;
1028dffb485Schristos 
1038dffb485Schristos   while (*p && *p != ',')
1048dffb485Schristos     {
1058dffb485Schristos       int nib;
1068dffb485Schristos 
1078dffb485Schristos       if (safe_fromhex (p[0], &nib))
1088dffb485Schristos 	return -1;
1098dffb485Schristos 
1108dffb485Schristos       if (firstdigit == -1)
1118dffb485Schristos 	firstdigit = nib;
1128dffb485Schristos 
1138dffb485Schristos       /* Don't allow overflow.  */
1148dffb485Schristos       if (count >= 8 || (count == 7 && firstdigit >= 0x8))
1158dffb485Schristos 	return -1;
1168dffb485Schristos 
1178dffb485Schristos       *value = *value * 16 + nib;
1188dffb485Schristos       p++;
1198dffb485Schristos       count++;
1208dffb485Schristos     }
1218dffb485Schristos 
1228dffb485Schristos   *pp = p;
1238dffb485Schristos   return 0;
1248dffb485Schristos }
1258dffb485Schristos 
1268dffb485Schristos static int
1278dffb485Schristos require_data (char *p, int p_len, char **data, int *data_len)
1288dffb485Schristos {
1298dffb485Schristos   int input_index, output_index, escaped;
1308dffb485Schristos 
1318dffb485Schristos   *data = (char *) xmalloc (p_len);
1328dffb485Schristos 
1338dffb485Schristos   output_index = 0;
1348dffb485Schristos   escaped = 0;
1358dffb485Schristos   for (input_index = 0; input_index < p_len; input_index++)
1368dffb485Schristos     {
1378dffb485Schristos       char b = p[input_index];
1388dffb485Schristos 
1398dffb485Schristos       if (escaped)
1408dffb485Schristos 	{
1418dffb485Schristos 	  (*data)[output_index++] = b ^ 0x20;
1428dffb485Schristos 	  escaped = 0;
1438dffb485Schristos 	}
1448dffb485Schristos       else if (b == '}')
1458dffb485Schristos 	escaped = 1;
1468dffb485Schristos       else
1478dffb485Schristos 	(*data)[output_index++] = b;
1488dffb485Schristos     }
1498dffb485Schristos 
1508dffb485Schristos   if (escaped)
1518dffb485Schristos     {
1528dffb485Schristos       free (*data);
1538dffb485Schristos       return -1;
1548dffb485Schristos     }
1558dffb485Schristos 
1568dffb485Schristos   *data_len = output_index;
1578dffb485Schristos   return 0;
1588dffb485Schristos }
1598dffb485Schristos 
1608dffb485Schristos static int
1618dffb485Schristos require_comma (char **pp)
1628dffb485Schristos {
1638dffb485Schristos   if (**pp == ',')
1648dffb485Schristos     {
1658dffb485Schristos       (*pp)++;
1668dffb485Schristos       return 0;
1678dffb485Schristos     }
1688dffb485Schristos   else
1698dffb485Schristos     return -1;
1708dffb485Schristos }
1718dffb485Schristos 
1728dffb485Schristos static int
1738dffb485Schristos require_end (char *p)
1748dffb485Schristos {
1758dffb485Schristos   if (*p == '\0')
1768dffb485Schristos     return 0;
1778dffb485Schristos   else
1788dffb485Schristos     return -1;
1798dffb485Schristos }
1808dffb485Schristos 
1818dffb485Schristos static int
1828dffb485Schristos require_valid_fd (int fd)
1838dffb485Schristos {
1848dffb485Schristos   struct fd_list *fd_ptr;
1858dffb485Schristos 
1868dffb485Schristos   for (fd_ptr = open_fds; fd_ptr != NULL; fd_ptr = fd_ptr->next)
1878dffb485Schristos     if (fd_ptr->fd == fd)
1888dffb485Schristos       return 0;
1898dffb485Schristos 
1908dffb485Schristos   return -1;
1918dffb485Schristos }
1928dffb485Schristos 
1934b169a6bSchristos /* Fill BUF with an hostio error packet representing the last hostio
1944b169a6bSchristos    error, from errno.  */
1954b169a6bSchristos 
1968dffb485Schristos static void
1978dffb485Schristos hostio_error (char *own_buf)
1988dffb485Schristos {
1994b169a6bSchristos   int fileio_error = host_to_fileio_error (errno);
2004b169a6bSchristos   sprintf (own_buf, "F-1,%x", fileio_error);
2018dffb485Schristos }
2028dffb485Schristos 
2038dffb485Schristos static void
2048dffb485Schristos hostio_packet_error (char *own_buf)
2058dffb485Schristos {
2068dffb485Schristos   sprintf (own_buf, "F-1,%x", FILEIO_EINVAL);
2078dffb485Schristos }
2088dffb485Schristos 
2098dffb485Schristos static void
2108dffb485Schristos hostio_reply (char *own_buf, int result)
2118dffb485Schristos {
2128dffb485Schristos   sprintf (own_buf, "F%x", result);
2138dffb485Schristos }
2148dffb485Schristos 
2158dffb485Schristos static int
2168dffb485Schristos hostio_reply_with_data (char *own_buf, char *buffer, int len,
2178dffb485Schristos 			int *new_packet_len)
2188dffb485Schristos {
2198dffb485Schristos   int input_index, output_index, out_maxlen;
2208dffb485Schristos 
2218dffb485Schristos   sprintf (own_buf, "F%x;", len);
2228dffb485Schristos   output_index = strlen (own_buf);
2238dffb485Schristos 
2248dffb485Schristos   out_maxlen = PBUFSIZ;
2258dffb485Schristos 
2268dffb485Schristos   for (input_index = 0; input_index < len; input_index++)
2278dffb485Schristos     {
2288dffb485Schristos       char b = buffer[input_index];
2298dffb485Schristos 
2308dffb485Schristos       if (b == '$' || b == '#' || b == '}' || b == '*')
2318dffb485Schristos 	{
2328dffb485Schristos 	  /* These must be escaped.  */
2338dffb485Schristos 	  if (output_index + 2 > out_maxlen)
2348dffb485Schristos 	    break;
2358dffb485Schristos 	  own_buf[output_index++] = '}';
2368dffb485Schristos 	  own_buf[output_index++] = b ^ 0x20;
2378dffb485Schristos 	}
2388dffb485Schristos       else
2398dffb485Schristos 	{
2408dffb485Schristos 	  if (output_index + 1 > out_maxlen)
2418dffb485Schristos 	    break;
2428dffb485Schristos 	  own_buf[output_index++] = b;
2438dffb485Schristos 	}
2448dffb485Schristos     }
2458dffb485Schristos 
2468dffb485Schristos   *new_packet_len = output_index;
2478dffb485Schristos   return input_index;
2488dffb485Schristos }
2498dffb485Schristos 
2508dffb485Schristos /* Process ID of inferior whose filesystem hostio functions
2518dffb485Schristos    that take FILENAME arguments will use.  Zero means to use
2528dffb485Schristos    our own filesystem.  */
2538dffb485Schristos 
2548dffb485Schristos static int hostio_fs_pid;
2558dffb485Schristos 
2568dffb485Schristos /* See hostio.h.  */
2578dffb485Schristos 
2588dffb485Schristos void
2598dffb485Schristos hostio_handle_new_gdb_connection (void)
2608dffb485Schristos {
2618dffb485Schristos   hostio_fs_pid = 0;
2628dffb485Schristos }
2638dffb485Schristos 
2648dffb485Schristos /* Handle a "vFile:setfs:" packet.  */
2658dffb485Schristos 
2668dffb485Schristos static void
2678dffb485Schristos handle_setfs (char *own_buf)
2688dffb485Schristos {
2698dffb485Schristos   char *p;
2708dffb485Schristos   int pid;
2718dffb485Schristos 
2728dffb485Schristos   /* If the target doesn't have any of the in-filesystem-of methods
2738dffb485Schristos      then there's no point in GDB sending "vFile:setfs:" packets.  We
2748dffb485Schristos      reply with an empty packet (i.e. we pretend we don't understand
2758dffb485Schristos      "vFile:setfs:") and that should stop GDB sending any more.  */
2768dffb485Schristos   if (!the_target->supports_multifs ())
2778dffb485Schristos     {
2788dffb485Schristos       own_buf[0] = '\0';
2798dffb485Schristos       return;
2808dffb485Schristos     }
2818dffb485Schristos 
2828dffb485Schristos   p = own_buf + strlen ("vFile:setfs:");
2838dffb485Schristos 
2848dffb485Schristos   if (require_int (&p, &pid)
2858dffb485Schristos       || pid < 0
2868dffb485Schristos       || require_end (p))
2878dffb485Schristos     {
2888dffb485Schristos       hostio_packet_error (own_buf);
2898dffb485Schristos       return;
2908dffb485Schristos     }
2918dffb485Schristos 
2928dffb485Schristos   hostio_fs_pid = pid;
2938dffb485Schristos 
2948dffb485Schristos   hostio_reply (own_buf, 0);
2958dffb485Schristos }
2968dffb485Schristos 
2978dffb485Schristos static void
2988dffb485Schristos handle_open (char *own_buf)
2998dffb485Schristos {
3008dffb485Schristos   char filename[HOSTIO_PATH_MAX];
3018dffb485Schristos   char *p;
3028dffb485Schristos   int fileio_flags, fileio_mode, flags, fd;
3038dffb485Schristos   mode_t mode;
3048dffb485Schristos   struct fd_list *new_fd;
3058dffb485Schristos 
3068dffb485Schristos   p = own_buf + strlen ("vFile:open:");
3078dffb485Schristos 
3088dffb485Schristos   if (require_filename (&p, filename)
3098dffb485Schristos       || require_comma (&p)
3108dffb485Schristos       || require_int (&p, &fileio_flags)
3118dffb485Schristos       || require_comma (&p)
3128dffb485Schristos       || require_int (&p, &fileio_mode)
3138dffb485Schristos       || require_end (p)
3148dffb485Schristos       || fileio_to_host_openflags (fileio_flags, &flags)
3158dffb485Schristos       || fileio_to_host_mode (fileio_mode, &mode))
3168dffb485Schristos     {
3178dffb485Schristos       hostio_packet_error (own_buf);
3188dffb485Schristos       return;
3198dffb485Schristos     }
3208dffb485Schristos 
3218dffb485Schristos   /* We do not need to convert MODE, since the fileio protocol
3228dffb485Schristos      uses the standard values.  */
3238dffb485Schristos   if (hostio_fs_pid != 0)
3248dffb485Schristos     fd = the_target->multifs_open (hostio_fs_pid, filename, flags, mode);
3258dffb485Schristos   else
3268dffb485Schristos     fd = open (filename, flags, mode);
3278dffb485Schristos 
3288dffb485Schristos   if (fd == -1)
3298dffb485Schristos     {
3308dffb485Schristos       hostio_error (own_buf);
3318dffb485Schristos       return;
3328dffb485Schristos     }
3338dffb485Schristos 
3348dffb485Schristos   /* Record the new file descriptor.  */
3358dffb485Schristos   new_fd = XNEW (struct fd_list);
3368dffb485Schristos   new_fd->fd = fd;
3378dffb485Schristos   new_fd->next = open_fds;
3388dffb485Schristos   open_fds = new_fd;
3398dffb485Schristos 
3408dffb485Schristos   hostio_reply (own_buf, fd);
3418dffb485Schristos }
3428dffb485Schristos 
3438dffb485Schristos static void
3448dffb485Schristos handle_pread (char *own_buf, int *new_packet_len)
3458dffb485Schristos {
3468dffb485Schristos   int fd, ret, len, offset, bytes_sent;
3478dffb485Schristos   char *p, *data;
3488dffb485Schristos   static int max_reply_size = -1;
3498dffb485Schristos 
3508dffb485Schristos   p = own_buf + strlen ("vFile:pread:");
3518dffb485Schristos 
3528dffb485Schristos   if (require_int (&p, &fd)
3538dffb485Schristos       || require_comma (&p)
3548dffb485Schristos       || require_valid_fd (fd)
3558dffb485Schristos       || require_int (&p, &len)
3568dffb485Schristos       || require_comma (&p)
3578dffb485Schristos       || require_int (&p, &offset)
3588dffb485Schristos       || require_end (p))
3598dffb485Schristos     {
3608dffb485Schristos       hostio_packet_error (own_buf);
3618dffb485Schristos       return;
3628dffb485Schristos     }
3638dffb485Schristos 
3648dffb485Schristos   /* Do not attempt to read more than the maximum number of bytes
3658dffb485Schristos      hostio_reply_with_data can fit in a packet.  We may still read
3668dffb485Schristos      too much because of escaping, but this is handled below.  */
3678dffb485Schristos   if (max_reply_size == -1)
3688dffb485Schristos     {
3698dffb485Schristos       sprintf (own_buf, "F%x;", PBUFSIZ);
3708dffb485Schristos       max_reply_size = PBUFSIZ - strlen (own_buf);
3718dffb485Schristos     }
3728dffb485Schristos   if (len > max_reply_size)
3738dffb485Schristos     len = max_reply_size;
3748dffb485Schristos 
3758dffb485Schristos   data = (char *) xmalloc (len);
3768dffb485Schristos #ifdef HAVE_PREAD
3778dffb485Schristos   ret = pread (fd, data, len, offset);
3788dffb485Schristos #else
3798dffb485Schristos   ret = -1;
3808dffb485Schristos #endif
3818dffb485Schristos   /* If we have no pread or it failed for this file, use lseek/read.  */
3828dffb485Schristos   if (ret == -1)
3838dffb485Schristos     {
3848dffb485Schristos       ret = lseek (fd, offset, SEEK_SET);
3858dffb485Schristos       if (ret != -1)
3868dffb485Schristos 	ret = read (fd, data, len);
3878dffb485Schristos     }
3888dffb485Schristos 
3898dffb485Schristos   if (ret == -1)
3908dffb485Schristos     {
3918dffb485Schristos       hostio_error (own_buf);
3928dffb485Schristos       free (data);
3938dffb485Schristos       return;
3948dffb485Schristos     }
3958dffb485Schristos 
3968dffb485Schristos   bytes_sent = hostio_reply_with_data (own_buf, data, ret, new_packet_len);
3978dffb485Schristos 
3988dffb485Schristos   /* If we were using read, and the data did not all fit in the reply,
3998dffb485Schristos      we would have to back up using lseek here.  With pread it does
4008dffb485Schristos      not matter.  But we still have a problem; the return value in the
4018dffb485Schristos      packet might be wrong, so we must fix it.  This time it will
4028dffb485Schristos      definitely fit.  */
4038dffb485Schristos   if (bytes_sent < ret)
4048dffb485Schristos     bytes_sent = hostio_reply_with_data (own_buf, data, bytes_sent,
4058dffb485Schristos 					 new_packet_len);
4068dffb485Schristos 
4078dffb485Schristos   free (data);
4088dffb485Schristos }
4098dffb485Schristos 
4108dffb485Schristos static void
4118dffb485Schristos handle_pwrite (char *own_buf, int packet_len)
4128dffb485Schristos {
4138dffb485Schristos   int fd, ret, len, offset;
4148dffb485Schristos   char *p, *data;
4158dffb485Schristos 
4168dffb485Schristos   p = own_buf + strlen ("vFile:pwrite:");
4178dffb485Schristos 
4188dffb485Schristos   if (require_int (&p, &fd)
4198dffb485Schristos       || require_comma (&p)
4208dffb485Schristos       || require_valid_fd (fd)
4218dffb485Schristos       || require_int (&p, &offset)
4228dffb485Schristos       || require_comma (&p)
4238dffb485Schristos       || require_data (p, packet_len - (p - own_buf), &data, &len))
4248dffb485Schristos     {
4258dffb485Schristos       hostio_packet_error (own_buf);
4268dffb485Schristos       return;
4278dffb485Schristos     }
4288dffb485Schristos 
4298dffb485Schristos #ifdef HAVE_PWRITE
4308dffb485Schristos   ret = pwrite (fd, data, len, offset);
4318dffb485Schristos #else
4328dffb485Schristos   ret = -1;
4338dffb485Schristos #endif
4348dffb485Schristos   /* If we have no pwrite or it failed for this file, use lseek/write.  */
4358dffb485Schristos   if (ret == -1)
4368dffb485Schristos     {
4378dffb485Schristos       ret = lseek (fd, offset, SEEK_SET);
4388dffb485Schristos       if (ret != -1)
4398dffb485Schristos 	ret = write (fd, data, len);
4408dffb485Schristos     }
4418dffb485Schristos 
4428dffb485Schristos   if (ret == -1)
4438dffb485Schristos     {
4448dffb485Schristos       hostio_error (own_buf);
4458dffb485Schristos       free (data);
4468dffb485Schristos       return;
4478dffb485Schristos     }
4488dffb485Schristos 
4498dffb485Schristos   hostio_reply (own_buf, ret);
4508dffb485Schristos   free (data);
4518dffb485Schristos }
4528dffb485Schristos 
4538dffb485Schristos static void
4548dffb485Schristos handle_fstat (char *own_buf, int *new_packet_len)
4558dffb485Schristos {
4568dffb485Schristos   int fd, bytes_sent;
4578dffb485Schristos   char *p;
4588dffb485Schristos   struct stat st;
4598dffb485Schristos   struct fio_stat fst;
4608dffb485Schristos 
4618dffb485Schristos   p = own_buf + strlen ("vFile:fstat:");
4628dffb485Schristos 
4638dffb485Schristos   if (require_int (&p, &fd)
4648dffb485Schristos       || require_valid_fd (fd)
4658dffb485Schristos       || require_end (p))
4668dffb485Schristos     {
4678dffb485Schristos       hostio_packet_error (own_buf);
4688dffb485Schristos       return;
4698dffb485Schristos     }
4708dffb485Schristos 
4718dffb485Schristos   if (fstat (fd, &st) == -1)
4728dffb485Schristos     {
4738dffb485Schristos       hostio_error (own_buf);
4748dffb485Schristos       return;
4758dffb485Schristos     }
4768dffb485Schristos 
4778dffb485Schristos   host_to_fileio_stat (&st, &fst);
4788dffb485Schristos 
4798dffb485Schristos   bytes_sent = hostio_reply_with_data (own_buf,
4808dffb485Schristos 				       (char *) &fst, sizeof (fst),
4818dffb485Schristos 				       new_packet_len);
4828dffb485Schristos 
4838dffb485Schristos   /* If the response does not fit into a single packet, do not attempt
4848dffb485Schristos      to return a partial response, but simply fail.  */
4858dffb485Schristos   if (bytes_sent < sizeof (fst))
4868dffb485Schristos     write_enn (own_buf);
4878dffb485Schristos }
4888dffb485Schristos 
4898dffb485Schristos static void
4908dffb485Schristos handle_close (char *own_buf)
4918dffb485Schristos {
4928dffb485Schristos   int fd, ret;
4938dffb485Schristos   char *p;
4948dffb485Schristos   struct fd_list **open_fd_p, *old_fd;
4958dffb485Schristos 
4968dffb485Schristos   p = own_buf + strlen ("vFile:close:");
4978dffb485Schristos 
4988dffb485Schristos   if (require_int (&p, &fd)
4998dffb485Schristos       || require_valid_fd (fd)
5008dffb485Schristos       || require_end (p))
5018dffb485Schristos     {
5028dffb485Schristos       hostio_packet_error (own_buf);
5038dffb485Schristos       return;
5048dffb485Schristos     }
5058dffb485Schristos 
5068dffb485Schristos   ret = close (fd);
5078dffb485Schristos 
5088dffb485Schristos   if (ret == -1)
5098dffb485Schristos     {
5108dffb485Schristos       hostio_error (own_buf);
5118dffb485Schristos       return;
5128dffb485Schristos     }
5138dffb485Schristos 
5148dffb485Schristos   open_fd_p = &open_fds;
5158dffb485Schristos   /* We know that fd is in the list, thanks to require_valid_fd.  */
5168dffb485Schristos   while ((*open_fd_p)->fd != fd)
5178dffb485Schristos     open_fd_p = &(*open_fd_p)->next;
5188dffb485Schristos 
5198dffb485Schristos   old_fd = *open_fd_p;
5208dffb485Schristos   *open_fd_p = (*open_fd_p)->next;
5218dffb485Schristos   free (old_fd);
5228dffb485Schristos 
5238dffb485Schristos   hostio_reply (own_buf, ret);
5248dffb485Schristos }
5258dffb485Schristos 
5268dffb485Schristos static void
5278dffb485Schristos handle_unlink (char *own_buf)
5288dffb485Schristos {
5298dffb485Schristos   char filename[HOSTIO_PATH_MAX];
5308dffb485Schristos   char *p;
5318dffb485Schristos   int ret;
5328dffb485Schristos 
5338dffb485Schristos   p = own_buf + strlen ("vFile:unlink:");
5348dffb485Schristos 
5358dffb485Schristos   if (require_filename (&p, filename)
5368dffb485Schristos       || require_end (p))
5378dffb485Schristos     {
5388dffb485Schristos       hostio_packet_error (own_buf);
5398dffb485Schristos       return;
5408dffb485Schristos     }
5418dffb485Schristos 
5428dffb485Schristos   if (hostio_fs_pid != 0)
5438dffb485Schristos     ret = the_target->multifs_unlink (hostio_fs_pid, filename);
5448dffb485Schristos   else
5458dffb485Schristos     ret = unlink (filename);
5468dffb485Schristos 
5478dffb485Schristos   if (ret == -1)
5488dffb485Schristos     {
5498dffb485Schristos       hostio_error (own_buf);
5508dffb485Schristos       return;
5518dffb485Schristos     }
5528dffb485Schristos 
5538dffb485Schristos   hostio_reply (own_buf, ret);
5548dffb485Schristos }
5558dffb485Schristos 
5568dffb485Schristos static void
5578dffb485Schristos handle_readlink (char *own_buf, int *new_packet_len)
5588dffb485Schristos {
5598dffb485Schristos   char filename[HOSTIO_PATH_MAX], linkname[HOSTIO_PATH_MAX];
5608dffb485Schristos   char *p;
5618dffb485Schristos   int ret, bytes_sent;
5628dffb485Schristos 
5638dffb485Schristos   p = own_buf + strlen ("vFile:readlink:");
5648dffb485Schristos 
5658dffb485Schristos   if (require_filename (&p, filename)
5668dffb485Schristos       || require_end (p))
5678dffb485Schristos     {
5688dffb485Schristos       hostio_packet_error (own_buf);
5698dffb485Schristos       return;
5708dffb485Schristos     }
5718dffb485Schristos 
5728dffb485Schristos   if (hostio_fs_pid != 0)
5738dffb485Schristos     ret = the_target->multifs_readlink (hostio_fs_pid, filename,
5748dffb485Schristos 					linkname,
5758dffb485Schristos 					sizeof (linkname) - 1);
5768dffb485Schristos   else
5778dffb485Schristos     ret = readlink (filename, linkname, sizeof (linkname) - 1);
5788dffb485Schristos 
5798dffb485Schristos   if (ret == -1)
5808dffb485Schristos     {
5818dffb485Schristos       hostio_error (own_buf);
5828dffb485Schristos       return;
5838dffb485Schristos     }
5848dffb485Schristos 
5858dffb485Schristos   bytes_sent = hostio_reply_with_data (own_buf, linkname, ret, new_packet_len);
5868dffb485Schristos 
5878dffb485Schristos   /* If the response does not fit into a single packet, do not attempt
5888dffb485Schristos      to return a partial response, but simply fail.  */
5898dffb485Schristos   if (bytes_sent < ret)
5908dffb485Schristos     sprintf (own_buf, "F-1,%x", FILEIO_ENAMETOOLONG);
5918dffb485Schristos }
5928dffb485Schristos 
5938dffb485Schristos /* Handle all the 'F' file transfer packets.  */
5948dffb485Schristos 
5958dffb485Schristos int
5968dffb485Schristos handle_vFile (char *own_buf, int packet_len, int *new_packet_len)
5978dffb485Schristos {
5988dffb485Schristos   if (startswith (own_buf, "vFile:open:"))
5998dffb485Schristos     handle_open (own_buf);
6008dffb485Schristos   else if (startswith (own_buf, "vFile:pread:"))
6018dffb485Schristos     handle_pread (own_buf, new_packet_len);
6028dffb485Schristos   else if (startswith (own_buf, "vFile:pwrite:"))
6038dffb485Schristos     handle_pwrite (own_buf, packet_len);
6048dffb485Schristos   else if (startswith (own_buf, "vFile:fstat:"))
6058dffb485Schristos     handle_fstat (own_buf, new_packet_len);
6068dffb485Schristos   else if (startswith (own_buf, "vFile:close:"))
6078dffb485Schristos     handle_close (own_buf);
6088dffb485Schristos   else if (startswith (own_buf, "vFile:unlink:"))
6098dffb485Schristos     handle_unlink (own_buf);
6108dffb485Schristos   else if (startswith (own_buf, "vFile:readlink:"))
6118dffb485Schristos     handle_readlink (own_buf, new_packet_len);
6128dffb485Schristos   else if (startswith (own_buf, "vFile:setfs:"))
6138dffb485Schristos     handle_setfs (own_buf);
6148dffb485Schristos   else
6158dffb485Schristos     return 0;
6168dffb485Schristos 
6178dffb485Schristos   return 1;
6188dffb485Schristos }
619