diff lib/local.c @ 1:8b1883341c6f

Initial revision
author masneyb
date Mon, 05 Aug 2002 19:46:57 +0000
parents
children 5551ab2301fe
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/local.c	Mon Aug 05 19:46:57 2002 +0000
@@ -0,0 +1,750 @@
+/*****************************************************************************/
+/*  local.c - functions that will use the local system                       */
+/*  Copyright (C) 1998-2002 Brian Masney <masneyb@gftp.org>                  */
+/*                                                                           */
+/*  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        */
+/*  (at your option) any later version.                                      */
+/*                                                                           */
+/*  This program is distributed in the hope that it will be useful,          */
+/*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
+/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
+/*  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., 59 Temple Place - Suite 330, Boston, MA 02111 USA      */
+/*****************************************************************************/
+
+#include "gftp.h"
+
+static void local_destroy 			( gftp_request * request );
+static void local_remove_key 			( gpointer key, 
+						  gpointer value, 
+						  gpointer user_data );
+static int local_connect 			( gftp_request * request );
+static void local_disconnect 			( gftp_request * request );
+static long local_get_file 			( gftp_request * request, 
+						  const char *filename,
+						  FILE * fd,
+						  off_t startsize );
+static int local_put_file 			( gftp_request * request, 
+						  const char *filename,
+						  FILE * fd,
+						  off_t startsize,
+						  off_t totalsize );
+static int local_end_transfer 			( gftp_request * request );
+static int local_get_next_file 			( gftp_request * request, 
+						  gftp_file * fle, 
+						  FILE * fd );
+static int local_list_files 			( gftp_request * request );
+static off_t local_get_file_size 		( gftp_request * request,
+						  const char *filename );
+static int local_chdir 				( gftp_request * request, 
+						  const char *directory );
+static int local_rmdir 				( gftp_request * request, 
+						  const char *directory );
+static int local_rmfile 			( gftp_request * request, 
+						  const char *file );
+static int local_mkdir 				( gftp_request * request, 
+						  const char *directory );
+static int local_rename 			( gftp_request * request, 
+						  const char *oldname,
+						  const char *newname );
+static int local_chmod 				( gftp_request * request, 
+						  const char *file, 
+						  int mode );
+static int local_set_file_time 			( gftp_request * request, 
+						  const char *file,
+						  time_t datetime );
+static char *make_text_mode			( gftp_file * fle,
+						  mode_t mode );
+static gint hash_compare 			( gconstpointer path1, 
+						  gconstpointer path2 );
+static guint hash_function 			( gconstpointer key );
+
+typedef struct local_protocol_data_tag
+{
+  DIR *dir;
+  GHashTable *userhash, *grouphash;
+} local_protocol_data;
+
+
+void
+local_init (gftp_request * request)
+{
+  local_protocol_data *lpd;
+
+  g_return_if_fail (request != NULL);
+
+  request->protonum = GFTP_LOCAL_NUM;
+  request->init = local_init;
+  request->destroy = local_destroy;
+  request->connect = local_connect;
+  request->disconnect = local_disconnect;
+  request->get_file = local_get_file;
+  request->put_file = local_put_file;
+  request->transfer_file = NULL;
+  request->get_next_file_chunk = NULL;
+  request->put_next_file_chunk = NULL;
+  request->end_transfer = local_end_transfer;
+  request->list_files = local_list_files;
+  request->get_next_file = local_get_next_file;
+  request->set_data_type = NULL;
+  request->get_file_size = local_get_file_size;
+  request->chdir = local_chdir;
+  request->rmdir = local_rmdir;
+  request->rmfile = local_rmfile;
+  request->mkdir = local_mkdir;
+  request->rename = local_rename;
+  request->chmod = local_chmod;
+  request->set_file_time = local_set_file_time;
+  request->site = NULL;
+  request->parse_url = NULL;
+  request->url_prefix = "file";
+  request->protocol_name = "Local";
+  request->need_hostport = 0;
+  request->need_userpass = 0;
+  request->use_cache = 0;
+  request->use_threads = 0;
+  request->always_connected = 1;
+  gftp_set_config_options (request);
+
+  lpd = g_malloc0 (sizeof (*lpd));
+  request->protocol_data = lpd;
+  lpd->userhash = g_hash_table_new (hash_function, hash_compare);
+  lpd->grouphash = g_hash_table_new (hash_function, hash_compare);
+}
+
+
+static void
+local_destroy (gftp_request * request)
+{
+  local_protocol_data * lpd;
+
+  g_return_if_fail (request != NULL);
+  g_return_if_fail (request->protonum == GFTP_LOCAL_NUM);
+
+  lpd = request->protocol_data;
+  g_hash_table_foreach (lpd->userhash, local_remove_key, NULL);
+  g_hash_table_destroy (lpd->userhash);
+  g_hash_table_foreach (lpd->grouphash, local_remove_key, NULL);
+  g_hash_table_destroy (lpd->grouphash);
+  lpd->userhash = lpd->grouphash = NULL;
+}
+
+
+static void
+local_remove_key (gpointer key, gpointer value, gpointer user_data)
+{
+  g_free (value);
+}
+
+
+static int
+local_connect (gftp_request * request)
+{
+  char tempstr[PATH_MAX];
+
+  g_return_val_if_fail (request != NULL, -2);
+  g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
+
+  request->sockfd = (void *) 1;
+
+  if (request->directory)
+    {
+      if (chdir (request->directory) != 0)
+        {
+          request->logging_function (gftp_logging_error, request->user_data,
+                             _("Could not change local directory to %s: %s\n"),
+                             request->directory, g_strerror (errno));
+        }
+      g_free (request->directory);
+      request->directory = NULL;
+    }
+
+  if (getcwd (tempstr, sizeof (tempstr)) != NULL)
+    {
+      tempstr[sizeof (tempstr) - 1] = '\0';
+      request->directory = g_malloc (strlen (tempstr) + 1);
+      strcpy (request->directory, tempstr);
+    }
+  else
+    request->logging_function (gftp_logging_error, request->user_data,
+                             _("Could not get current working directory: %s\n"),
+                             g_strerror (errno));
+
+  return (0);
+}
+
+
+static void
+local_disconnect (gftp_request * request)
+{
+  g_return_if_fail (request != NULL);
+  g_return_if_fail (request->protonum == GFTP_LOCAL_NUM);
+
+  if (request->datafd != NULL)
+    {
+      if (fclose (request->datafd) < 0)
+        request->logging_function (gftp_logging_error, request->user_data,
+                                   _("Error closing file descriptor: %s\n"),
+                                   g_strerror (errno));
+      request->datafd = NULL;
+    }
+  request->sockfd = NULL;
+}
+
+
+static long 
+local_get_file (gftp_request * request, const char *filename, FILE * fd,
+                off_t startsize)
+{
+  size_t size;
+
+  g_return_val_if_fail (request != NULL, -2);
+  g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
+  g_return_val_if_fail (filename != NULL, -2);
+
+  if (fd == NULL)
+    {
+      if ((request->datafd = fopen (filename, "rb")) == NULL)
+        {
+          request->logging_function (gftp_logging_error, request->user_data,
+                                   _("Error: Cannot open local file %s: %s\n"),
+                                   filename, g_strerror (errno));
+          return (-2);
+        }
+    }
+  else
+    request->datafd = fd;
+
+  if (lseek (fileno (request->datafd), 0, SEEK_END) == -1)
+    {
+      request->logging_function (gftp_logging_error, request->user_data,
+                                 _("Error: Cannot seek on file %s: %s\n"),
+                                 filename, g_strerror (errno));
+      fclose (request->datafd);
+      request->datafd = NULL;
+    }
+
+  if ((size = ftell (request->datafd)) == -1)
+    {
+      request->logging_function (gftp_logging_error, request->user_data,
+                                 _("Error: Cannot seek on file %s: %s\n"),
+                                 filename, g_strerror (errno));
+      fclose (request->datafd);
+      request->datafd = NULL;
+    }
+
+  if (lseek (fileno (request->datafd), startsize, SEEK_SET) == -1)
+    {
+      request->logging_function (gftp_logging_error, request->user_data,
+                                 _("Error: Cannot seek on file %s: %s\n"),
+                                 filename, g_strerror (errno));
+      fclose (request->datafd);
+      request->datafd = NULL;
+    }
+
+  return (size);
+}
+
+
+static int
+local_put_file (gftp_request * request, const char *filename, FILE * fd,
+                off_t startsize, off_t totalsize)
+{
+  int sock;
+
+  g_return_val_if_fail (request != NULL, -2);
+  g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
+  g_return_val_if_fail (filename != NULL, -2);
+
+  if (fd == NULL)
+    {
+      if ((sock = open (filename, 
+          startsize > 0 ? O_WRONLY | O_APPEND | O_CREAT: O_WRONLY | O_CREAT, 
+          S_IRUSR | S_IWUSR)) < 0)
+        {
+          request->logging_function (gftp_logging_error, request->user_data,
+                                   _("Error: Cannot open local file %s: %s\n"),
+                                   filename, g_strerror (errno));
+          return (-2);
+        }
+
+      if ((request->datafd = fdopen (sock, "ab")) == NULL)
+        {
+          request->logging_function (gftp_logging_error, request->user_data,
+                                     _("Cannot fdopen() socket for %s: %s\n"),
+                                     filename, g_strerror (errno));
+          close (sock);
+          return (-2);
+        }
+    }
+  else
+    request->datafd = fd;
+
+  if (ftruncate (fileno (request->datafd), startsize) == -1)
+    {
+      request->logging_function (gftp_logging_error, request->user_data,
+                               _("Error: Cannot truncate local file %s: %s\n"),
+                               filename, g_strerror (errno));
+      fclose (request->datafd);
+      request->datafd = NULL;
+      return (-2);
+    }
+    
+  if (fseek (request->datafd, startsize, SEEK_SET) == -1)
+    {
+      request->logging_function (gftp_logging_error, request->user_data,
+                                 _("Error: Cannot seek on file %s: %s\n"),
+                                 filename, g_strerror (errno));
+      fclose (request->datafd);
+      request->datafd = NULL;
+      return (-2);
+    }
+  return (0);
+}
+
+
+static int
+local_end_transfer (gftp_request * request)
+{
+  local_protocol_data * lpd;
+
+  lpd = request->protocol_data;
+  if (lpd->dir)
+    {
+      closedir (lpd->dir);
+      lpd->dir = NULL;
+    }
+
+  if (request->datafd != NULL)
+    {
+      if (fclose (request->datafd) < 0)
+        request->logging_function (gftp_logging_error, request->user_data,
+                                   _("Error closing file descriptor: %s\n"),
+                                   g_strerror (errno));
+
+      request->datafd = NULL;
+    }
+
+  return (0);
+}
+
+
+static int
+local_get_next_file (gftp_request * request, gftp_file * fle, FILE * fd)
+{
+  local_protocol_data * lpd;
+  struct dirent *dirp;
+  char *user, *group;
+  struct passwd *pw;
+  struct group *gr;
+  struct stat st;
+
+  /* the struct passwd and struct group are not thread safe. But,
+     we're ok here because I have threading turned off for the local
+     protocol (see use_threads in local_init above) */
+  g_return_val_if_fail (request != NULL, -2);
+  g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
+  g_return_val_if_fail (fle != NULL, -2);
+
+  lpd = request->protocol_data;
+  memset (fle, 0, sizeof (*fle));
+
+  if ((dirp = readdir (lpd->dir)) == NULL)
+    {
+      closedir (lpd->dir);
+      lpd->dir = NULL;
+      return (-2);
+    }
+
+  fle->file = g_malloc (strlen (dirp->d_name) + 1);
+  strcpy (fle->file, dirp->d_name);
+  if (lstat (fle->file, &st) != 0)
+    {
+      closedir (lpd->dir);
+      lpd->dir = NULL;
+      return (-2);
+    }
+
+  if ((user = g_hash_table_lookup (lpd->userhash, 
+                                   GUINT_TO_POINTER(st.st_uid))) != NULL)
+    {
+      fle->user = g_malloc (strlen (user) + 1);
+      strcpy (fle->user, user);
+    }
+  else
+    {
+      if ((pw = getpwuid (st.st_uid)) == NULL)
+        fle->user = g_strdup_printf ("%u", st.st_uid); 
+      else
+        {
+          fle->user = g_malloc (strlen (pw->pw_name) + 1);
+          strcpy (fle->user, pw->pw_name);
+        }
+
+      user = g_malloc (strlen (fle->user) + 1);
+      strcpy (user, fle->user);
+      g_hash_table_insert (lpd->userhash, GUINT_TO_POINTER (st.st_uid), user);
+    }
+
+  if ((group = g_hash_table_lookup (lpd->grouphash, 
+                                    GUINT_TO_POINTER(st.st_gid))) != NULL)
+    {
+      fle->group = g_malloc (strlen (group) + 1);
+      strcpy (fle->group, group);
+    }
+  else
+    {
+      if ((gr = getgrgid (st.st_gid)) == NULL)
+        fle->group = g_strdup_printf ("%u", st.st_gid); 
+      else
+        {
+          fle->group = g_malloc (strlen (gr->gr_name) + 1);
+          strcpy (fle->group, gr->gr_name);
+        }
+
+      group = g_malloc (strlen (fle->group) + 1);
+      strcpy (group, fle->group);
+      g_hash_table_insert (lpd->grouphash, GUINT_TO_POINTER (st.st_gid), group);
+    }
+
+  fle->size = st.st_size;
+  fle->datetime = st.st_mtime;
+  fle->attribs = make_text_mode (fle, st.st_mode);
+
+  if (*fle->attribs == 'd')
+    fle->isdir = 1;
+  if (*fle->attribs == 'l')
+    fle->islink = 1;
+  if (strchr (fle->attribs, 'x') != NULL && !fle->isdir && !fle->islink)
+    fle->isexe = 1;
+  if (*fle->attribs == 'b')
+    fle->isblock = 1;
+  if (*fle->attribs == 'c')
+    fle->ischar = 1;
+  if (*fle->attribs == 's')
+    fle->issocket = 1;
+  if (*fle->attribs == 'p')
+    fle->isfifo = 1;
+  return (1);
+}
+
+
+static int
+local_list_files (gftp_request * request)
+{
+  local_protocol_data *lpd;
+  char *tempstr;
+
+  g_return_val_if_fail (request != NULL, -2);
+  g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
+  lpd = request->protocol_data;
+
+  tempstr = g_strconcat (request->directory, "/", NULL);
+
+  if ((lpd->dir = opendir (tempstr)) == NULL)
+    {
+      request->logging_function (gftp_logging_error, request->user_data,
+                           _("Could not get local directory listing %s: %s\n"),
+                           tempstr, g_strerror (errno));
+      g_free (tempstr);
+      return (-1);
+    }
+
+  g_free (tempstr);
+  return (0);
+}
+
+
+static off_t 
+local_get_file_size (gftp_request * request, const char *filename)
+{
+  struct stat st;
+
+  if (stat (filename, &st) == -1)
+    return (-1);
+  return (st.st_size);
+}
+
+
+static int
+local_chdir (gftp_request * request, const char *directory)
+{
+  char tempstr[255];
+
+  g_return_val_if_fail (request != NULL, -2);
+  g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
+  g_return_val_if_fail (directory != NULL, -2);
+
+  if (chdir (directory) == 0)
+    {
+      request->logging_function (gftp_logging_error, request->user_data,
+                          _("Successfully changed local directory to %s\n"),
+                          directory);
+      if (request->directory != directory)
+        {
+          if (getcwd (tempstr, sizeof (tempstr)) == NULL)
+	    {
+              request->logging_function (gftp_logging_error, request->user_data,
+                            _("Could not get current working directory: %s\n"),
+                            g_strerror (errno));
+	      return (-1);
+	    }
+          if (request->directory)
+	    g_free (request->directory);
+          request->directory = g_malloc (strlen (tempstr) + 1);
+          strcpy (request->directory, tempstr);
+        }
+      return (0);
+    }
+  request->logging_function (gftp_logging_error, request->user_data,
+                             _("Could not change local directory to %s: %s\n"),
+                             directory, g_strerror (errno));
+  return (-1);
+}
+
+
+static int
+local_rmdir (gftp_request * request, const char *directory)
+{
+  g_return_val_if_fail (request != NULL, -2);
+  g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
+  g_return_val_if_fail (directory != NULL, -2);
+
+  if (rmdir (directory) == 0)
+    {
+      request->logging_function (gftp_logging_error, request->user_data,
+                                 _("Successfully removed %s\n"), directory);
+      return (0);
+    }
+  else
+    {
+      request->logging_function (gftp_logging_error, request->user_data,
+                              _("Error: Could not remove directory %s: %s\n"),
+                              directory, g_strerror (errno));
+      return (-1);
+    }
+}
+
+
+static int
+local_rmfile (gftp_request * request, const char *file)
+{
+  g_return_val_if_fail (request != NULL, -2);
+  g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
+  g_return_val_if_fail (file != NULL, -2);
+
+  if (unlink (file) == 0)
+    {
+      request->logging_function (gftp_logging_error, request->user_data,
+                                 _("Successfully removed %s\n"), file);
+      return (0);
+    }
+  else
+    {
+      request->logging_function (gftp_logging_error, request->user_data,
+                                 _("Error: Could not remove file %s: %s\n"),
+                                 file, g_strerror (errno));
+      return (-1);
+    }
+}
+
+
+static int
+local_mkdir (gftp_request * request, const char *directory)
+{
+  g_return_val_if_fail (request != NULL, -2);
+  g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
+  g_return_val_if_fail (directory != NULL, -2);
+
+  if (mkdir (directory, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0)
+    {
+      request->logging_function (gftp_logging_error, request->user_data,
+                                 _("Successfully made directory %s\n"),
+                                 directory);
+      return (0);
+    }
+  else
+    {
+      request->logging_function (gftp_logging_error, request->user_data,
+                                 _("Error: Could not make directory %s: %s\n"),
+                                 directory, g_strerror (errno));
+      return (-1);
+    }
+}
+
+
+static int
+local_rename (gftp_request * request, const char *oldname,
+	      const char *newname)
+{
+  g_return_val_if_fail (request != NULL, -2);
+  g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
+  g_return_val_if_fail (oldname != NULL, -2);
+  g_return_val_if_fail (newname != NULL, -2);
+
+  if (rename (oldname, newname) == 0)
+    {
+      request->logging_function (gftp_logging_error, request->user_data,
+                                 _("Successfully renamed %s to %s\n"),
+                                 oldname, newname);
+      return (0);
+    }
+  else
+    {
+      request->logging_function (gftp_logging_error, request->user_data,
+                                 _("Error: Could not rename %s to %s: %s\n"),
+                                 oldname, newname, g_strerror (errno));
+      return (-1);
+    }
+}
+
+
+static int
+local_chmod (gftp_request * request, const char *file, int mode)
+{
+  char buf[10];
+  int newmode;
+
+  g_return_val_if_fail (request != NULL, -2);
+  g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
+  g_return_val_if_fail (file != NULL, -2);
+
+  g_snprintf (buf, sizeof (buf), "%d", mode);
+  newmode = strtol (buf, NULL, 8);
+
+  if (chmod (file, newmode) == 0) 
+    {
+      request->logging_function (gftp_logging_error, request->user_data, 
+                                 _("Successfully changed mode of %s to %d\n"),
+                                 file, mode);
+      return (0);
+    }
+  else 
+    {
+      request->logging_function (gftp_logging_error, request->user_data, 
+                          _("Error: Could not change mode of %s to %d: %s\n"),
+                          file, mode, g_strerror (errno));
+      return (-1);
+    }
+}
+
+
+static int
+local_set_file_time (gftp_request * request, const char *file,
+		     time_t datetime)
+{
+  struct utimbuf time_buf;
+
+  g_return_val_if_fail (request != NULL, -2);
+  g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
+  g_return_val_if_fail (file != NULL, -2);
+
+  time_buf.modtime = time_buf.actime = datetime;
+  return (utime (file, &time_buf));
+}
+
+
+static char *
+make_text_mode (gftp_file * fle, mode_t mode)
+{
+  char *str;
+
+  str = g_malloc0 (11);
+  
+  str[0] = '?';
+  if (S_ISREG (mode))
+    str[0] = '-';
+
+  if (S_ISLNK (mode))
+    {
+      fle->islink = 1; 
+      str[0] = 'l';
+    }
+
+  if (S_ISBLK (mode))
+     {
+       fle->isblock = 1;
+       str[0] = 'b';
+     }
+
+  if (S_ISCHR (mode))
+     {
+       fle->ischar = 1;
+       str[0] = 'c';
+    }
+
+  if (S_ISFIFO (mode))
+    {
+      fle->isfifo = 1;
+      str[0] = 'p';
+    }
+
+  if (S_ISSOCK (mode))
+    {
+      fle->issocket = 1;
+      str[0] = 's';
+    }
+
+  if (S_ISDIR (mode))
+    {
+      fle->isdir = 1;
+      str[0] = 'd';
+    }
+
+  str[1] = mode & S_IRUSR ? 'r' : '-';
+  str[2] = mode & S_IWUSR ? 'w' : '-';
+
+  if ((mode & S_ISUID) && (mode & S_IXUSR))
+    str[3] = 's';
+  else if (mode & S_ISUID)
+    str[3] = 'S';
+  else if (mode & S_IXUSR)
+    str[3] = 'x';
+  else
+    str[3] = '-';
+    
+  str[4] = mode & S_IRGRP ? 'r' : '-';
+  str[5] = mode & S_IWGRP ? 'w' : '-';
+
+  if ((mode & S_ISGID) && (mode & S_IXGRP))
+    str[6] = 's';
+  else if (mode & S_ISGID)
+    str[6] = 'S';
+  else if (mode & S_IXGRP)
+    str[6] = 'x';
+  else
+    str[6] = '-';
+
+  str[7] = mode & S_IROTH ? 'r' : '-';
+  str[8] = mode & S_IWOTH ? 'w' : '-';
+
+  if ((mode & S_ISVTX) && (mode & S_IXOTH))
+    str[9] = 't';
+  else if (mode & S_ISVTX)
+    str[9] = 'T';
+  else if (mode & S_IXOTH)
+    str[9] = 'x';
+  else
+    str[9] = '-';
+  return (str);
+}
+
+
+static gint
+hash_compare (gconstpointer path1, gconstpointer path2)
+{
+  return (GPOINTER_TO_UINT (path1) == GPOINTER_TO_UINT (path2));
+}
+
+
+static guint
+hash_function (gconstpointer key)
+{
+  return (GPOINTER_TO_UINT (key));
+}
+