* gas/config/tc-avr.c: Change ISA for devices with USB support to
[external/binutils.git] / gdb / gdbserver / hostio.c
index 712deb4..df94d31 100644 (file)
@@ -1,5 +1,5 @@
 /* Host file transfer support for gdbserver.
-   Copyright (C) 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 2007-2013 Free Software Foundation, Inc.
 
    Contributed by CodeSourcery.
 
@@ -7,7 +7,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -16,9 +16,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "server.h"
 #include "gdb/fileio.h"
@@ -116,7 +114,7 @@ require_data (char *p, int p_len, char **data, int *data_len)
 {
   int input_index, output_index, escaped;
 
-  *data = malloc (p_len);
+  *data = xmalloc (p_len);
 
   output_index = 0;
   escaped = 0;
@@ -136,7 +134,10 @@ require_data (char *p, int p_len, char **data, int *data_len)
     }
 
   if (escaped)
-    return -1;
+    {
+      free (*data);
+      return -1;
+    }
 
   *data_len = output_index;
   return 0;
@@ -295,7 +296,7 @@ handle_open (char *own_buf)
     }
 
   /* Record the new file descriptor.  */
-  new_fd = malloc (sizeof (struct fd_list));
+  new_fd = xmalloc (sizeof (struct fd_list));
   new_fd->fd = fd;
   new_fd->next = open_fds;
   open_fds = new_fd;
@@ -323,14 +324,19 @@ handle_pread (char *own_buf, int *new_packet_len)
       return;
     }
 
-  data = malloc (len);
+  data = xmalloc (len);
 #ifdef HAVE_PREAD
   ret = pread (fd, data, len, offset);
 #else
-  ret = lseek (fd, offset, SEEK_SET);
-  if (ret != -1)
-    ret = read (fd, data, len);
+  ret = -1;
 #endif
+  /* If we have no pread or it failed for this file, use lseek/read.  */
+  if (ret == -1)
+    {
+      ret = lseek (fd, offset, SEEK_SET);
+      if (ret != -1)
+       ret = read (fd, data, len);
+    }
 
   if (ret == -1)
     {
@@ -375,10 +381,15 @@ handle_pwrite (char *own_buf, int packet_len)
 #ifdef HAVE_PWRITE
   ret = pwrite (fd, data, len, offset);
 #else
-  ret = lseek (fd, offset, SEEK_SET);
-  if (ret != -1)
-    ret = write (fd, data, len);
+  ret = -1;
 #endif
+  /* If we have no pwrite or it failed for this file, use lseek/write.  */
+  if (ret == -1)
+    {
+      ret = lseek (fd, offset, SEEK_SET);
+      if (ret != -1)
+       ret = write (fd, data, len);
+    }
 
   if (ret == -1)
     {
@@ -417,7 +428,8 @@ handle_close (char *own_buf)
     }
 
   open_fd_p = &open_fds;
-  while (*open_fd_p && (*open_fd_p)->fd != fd)
+  /* We know that fd is in the list, thanks to require_valid_fd.  */
+  while ((*open_fd_p)->fd != fd)
     open_fd_p = &(*open_fd_p)->next;
 
   old_fd = *open_fd_p;
@@ -454,6 +466,41 @@ handle_unlink (char *own_buf)
   hostio_reply (own_buf, ret);
 }
 
+static void
+handle_readlink (char *own_buf, int *new_packet_len)
+{
+#if defined (HAVE_READLINK)
+  char filename[PATH_MAX], linkname[PATH_MAX];
+  char *p;
+  int ret, bytes_sent;
+
+  p = own_buf + strlen ("vFile:readlink:");
+
+  if (require_filename (&p, filename)
+      || require_end (p))
+    {
+      hostio_packet_error (own_buf);
+      return;
+    }
+
+  ret = readlink (filename, linkname, sizeof (linkname) - 1);
+  if (ret == -1)
+    {
+      hostio_error (own_buf);
+      return;
+    }
+
+  bytes_sent = hostio_reply_with_data (own_buf, linkname, ret, new_packet_len);
+
+  /* If the response does not fit into a single packet, do not attempt
+     to return a partial response, but simply fail.  */
+  if (bytes_sent < ret)
+    sprintf (own_buf, "F-1,%x", FILEIO_ENAMETOOLONG);
+#else /* ! HAVE_READLINK */
+    sprintf (own_buf, "F-1,%x", FILEIO_ENOSYS);
+#endif
+}
+
 /* Handle all the 'F' file transfer packets.  */
 
 int
@@ -469,6 +516,8 @@ handle_vFile (char *own_buf, int packet_len, int *new_packet_len)
     handle_close (own_buf);
   else if (strncmp (own_buf, "vFile:unlink:", 13) == 0)
     handle_unlink (own_buf);
+  else if (strncmp (own_buf, "vFile:readlink:", 15) == 0)
+    handle_readlink (own_buf, new_packet_len);
   else
     return 0;