local.c
上传用户:tjfeida
上传日期:2013-03-10
资源大小:1917k
文件大小:19k
源码类别:

Ftp客户端

开发平台:

Visual C++

  1. /*****************************************************************************/
  2. /*  local.c - functions that will use the local system                       */
  3. /*  Copyright (C) 1998-2002 Brian Masney <masneyb@gftp.org>                  */
  4. /*                                                                           */
  5. /*  This program is free software; you can redistribute it and/or modify     */
  6. /*  it under the terms of the GNU General Public License as published by     */
  7. /*  the Free Software Foundation; either version 2 of the License, or        */
  8. /*  (at your option) any later version.                                      */
  9. /*                                                                           */
  10. /*  This program is distributed in the hope that it will be useful,          */
  11. /*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
  12. /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
  13. /*  GNU General Public License for more details.                             */
  14. /*                                                                           */
  15. /*  You should have received a copy of the GNU General Public License        */
  16. /*  along with this program; if not, write to the Free Software              */
  17. /*  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA      */
  18. /*****************************************************************************/
  19. #include "gftp.h"
  20. static const char cvsid[] = "$Id: local.c,v 1.13 2002/11/27 02:23:51 masneyb Exp $";
  21. typedef struct local_protocol_data_tag
  22. {
  23.   DIR *dir;
  24.   GHashTable *userhash, *grouphash;
  25. } local_protocol_data;
  26. static void
  27. local_remove_key (gpointer key, gpointer value, gpointer user_data)
  28. {
  29.   g_free (value);
  30. }
  31. static void
  32. local_destroy (gftp_request * request)
  33. {
  34.   local_protocol_data * lpd;
  35.   g_return_if_fail (request != NULL);
  36.   g_return_if_fail (request->protonum == GFTP_LOCAL_NUM);
  37.   lpd = request->protocol_data;
  38.   g_hash_table_foreach (lpd->userhash, local_remove_key, NULL);
  39.   g_hash_table_destroy (lpd->userhash);
  40.   g_hash_table_foreach (lpd->grouphash, local_remove_key, NULL);
  41.   g_hash_table_destroy (lpd->grouphash);
  42.   lpd->userhash = lpd->grouphash = NULL;
  43. }
  44. static int
  45. local_connect (gftp_request * request)
  46. {
  47.   char tempstr[PATH_MAX];
  48.   g_return_val_if_fail (request != NULL, -2);
  49.   g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
  50.   if (request->directory)
  51.     {
  52.       if (chdir (request->directory) != 0)
  53.         {
  54.           request->logging_function (gftp_logging_error, request->user_data,
  55.                              _("Could not change local directory to %s: %sn"),
  56.                              request->directory, g_strerror (errno));
  57.         }
  58.       g_free (request->directory);
  59.       request->directory = NULL;
  60.     }
  61.   if (getcwd (tempstr, sizeof (tempstr)) != NULL)
  62.     {
  63.       tempstr[sizeof (tempstr) - 1] = '';
  64.       request->directory = g_malloc (strlen (tempstr) + 1);
  65.       strcpy (request->directory, tempstr);
  66.     }
  67.   else
  68.     request->logging_function (gftp_logging_error, request->user_data,
  69.                              _("Could not get current working directory: %sn"),
  70.                              g_strerror (errno));
  71.   return (0);
  72. }
  73. static void
  74. local_disconnect (gftp_request * request)
  75. {
  76.   g_return_if_fail (request != NULL);
  77.   g_return_if_fail (request->protonum == GFTP_LOCAL_NUM);
  78.   if (request->datafd != -1)
  79.     {
  80.       if (close (request->datafd) < 0)
  81.         request->logging_function (gftp_logging_error, request->user_data,
  82.                                    _("Error closing file descriptor: %sn"),
  83.                                    g_strerror (errno));
  84.       request->datafd = -1;
  85.     }
  86. }
  87. static off_t
  88. local_get_file (gftp_request * request, const char *filename, int fd,
  89.                 off_t startsize)
  90. {
  91.   off_t size;
  92.   int flags;
  93.   g_return_val_if_fail (request != NULL, -2);
  94.   g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
  95.   g_return_val_if_fail (filename != NULL, -2);
  96.   if (fd <= 0)
  97.     {
  98.       flags = O_RDONLY;
  99. #if defined (_LARGEFILE_SOURCE)
  100.       flags |= O_LARGEFILE;
  101. #endif
  102.       if ((request->datafd = open (filename, flags)) < 0)
  103.         {
  104.           request->logging_function (gftp_logging_error, request->user_data,
  105.                                    _("Error: Cannot open local file %s: %sn"),
  106.                                    filename, g_strerror (errno));
  107.           return (-2);
  108.         }
  109.     }
  110.   else
  111.     request->datafd = fd;
  112.   if ((size = lseek (request->datafd, 0, SEEK_END)) == -1)
  113.     {
  114.       request->logging_function (gftp_logging_error, request->user_data,
  115.                                  _("Error: Cannot seek on file %s: %sn"),
  116.                                  filename, g_strerror (errno));
  117.       gftp_disconnect (request);
  118.       return (-1);
  119.     }
  120.   if (lseek (request->datafd, startsize, SEEK_SET) == -1)
  121.     {
  122.       request->logging_function (gftp_logging_error, request->user_data,
  123.                                  _("Error: Cannot seek on file %s: %sn"),
  124.                                  filename, g_strerror (errno));
  125.       gftp_disconnect (request);
  126.       return (-1);
  127.     }
  128.   return (size);
  129. }
  130. static int
  131. local_put_file (gftp_request * request, const char *filename, int fd,
  132.                 off_t startsize, off_t totalsize)
  133. {
  134.   int flags;
  135.   g_return_val_if_fail (request != NULL, -2);
  136.   g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
  137.   g_return_val_if_fail (filename != NULL, -2);
  138.   if (fd <= 0)
  139.     {
  140.       flags = O_WRONLY | O_CREAT;
  141.       if (startsize > 0)
  142.          flags |= O_APPEND;
  143. #if defined (_LARGEFILE_SOURCE)
  144.       flags |= O_LARGEFILE;
  145. #endif
  146.       if ((request->datafd = open (filename, flags, S_IRUSR | S_IWUSR)) < 0)
  147.         {
  148.           request->logging_function (gftp_logging_error, request->user_data,
  149.                                    _("Error: Cannot open local file %s: %sn"),
  150.                                    filename, g_strerror (errno));
  151.           return (-2);
  152.         }
  153.     }
  154.   else
  155.     request->datafd = fd;
  156.   if (ftruncate (request->datafd, startsize) == -1)
  157.     {
  158.       request->logging_function (gftp_logging_error, request->user_data,
  159.                                _("Error: Cannot truncate local file %s: %sn"),
  160.                                filename, g_strerror (errno));
  161.       gftp_disconnect (request);
  162.       return (-1);
  163.     }
  164.     
  165.   if (lseek (request->datafd, startsize, SEEK_SET) == -1)
  166.     {
  167.       request->logging_function (gftp_logging_error, request->user_data,
  168.                                  _("Error: Cannot seek on file %s: %sn"),
  169.                                  filename, g_strerror (errno));
  170.       gftp_disconnect (request);
  171.       return (-2);
  172.     }
  173.   return (0);
  174. }
  175. static int
  176. local_end_transfer (gftp_request * request)
  177. {
  178.   local_protocol_data * lpd;
  179.   lpd = request->protocol_data;
  180.   if (lpd->dir)
  181.     {
  182.       closedir (lpd->dir);
  183.       lpd->dir = NULL;
  184.     }
  185.   if (request->datafd > 0)
  186.     {
  187.       if (close (request->datafd) < 0)
  188.         request->logging_function (gftp_logging_error, request->user_data,
  189.                                    _("Error closing file descriptor: %sn"),
  190.                                    g_strerror (errno));
  191.       request->datafd = -1;
  192.     }
  193.   return (0);
  194. }
  195. static char *
  196. make_text_mode (gftp_file * fle, mode_t mode)
  197. {
  198.   char *str;
  199.   str = g_malloc0 (11);
  200.   
  201.   str[0] = '?';
  202.   if (S_ISREG (mode))
  203.     str[0] = '-';
  204.   if (S_ISLNK (mode))
  205.     {
  206.       fle->islink = 1; 
  207.       str[0] = 'l';
  208.     }
  209.   if (S_ISBLK (mode))
  210.      {
  211.        fle->isblock = 1;
  212.        str[0] = 'b';
  213.      }
  214.   if (S_ISCHR (mode))
  215.      {
  216.        fle->ischar = 1;
  217.        str[0] = 'c';
  218.     }
  219.   if (S_ISFIFO (mode))
  220.     {
  221.       fle->isfifo = 1;
  222.       str[0] = 'p';
  223.     }
  224.   if (S_ISSOCK (mode))
  225.     {
  226.       fle->issocket = 1;
  227.       str[0] = 's';
  228.     }
  229.   if (S_ISDIR (mode))
  230.     {
  231.       fle->isdir = 1;
  232.       str[0] = 'd';
  233.     }
  234.   str[1] = mode & S_IRUSR ? 'r' : '-';
  235.   str[2] = mode & S_IWUSR ? 'w' : '-';
  236.   if ((mode & S_ISUID) && (mode & S_IXUSR))
  237.     str[3] = 's';
  238.   else if (mode & S_ISUID)
  239.     str[3] = 'S';
  240.   else if (mode & S_IXUSR)
  241.     str[3] = 'x';
  242.   else
  243.     str[3] = '-';
  244.     
  245.   str[4] = mode & S_IRGRP ? 'r' : '-';
  246.   str[5] = mode & S_IWGRP ? 'w' : '-';
  247.   if ((mode & S_ISGID) && (mode & S_IXGRP))
  248.     str[6] = 's';
  249.   else if (mode & S_ISGID)
  250.     str[6] = 'S';
  251.   else if (mode & S_IXGRP)
  252.     str[6] = 'x';
  253.   else
  254.     str[6] = '-';
  255.   str[7] = mode & S_IROTH ? 'r' : '-';
  256.   str[8] = mode & S_IWOTH ? 'w' : '-';
  257.   if ((mode & S_ISVTX) && (mode & S_IXOTH))
  258.     str[9] = 't';
  259.   else if (mode & S_ISVTX)
  260.     str[9] = 'T';
  261.   else if (mode & S_IXOTH)
  262.     str[9] = 'x';
  263.   else
  264.     str[9] = '-';
  265.   return (str);
  266. }
  267. static int
  268. local_get_next_file (gftp_request * request, gftp_file * fle, int fd)
  269. {
  270.   local_protocol_data * lpd;
  271.   struct dirent *dirp;
  272.   char *user, *group;
  273.   struct passwd *pw;
  274.   struct group *gr;
  275.   struct stat st;
  276.   /* the struct passwd and struct group are not thread safe. But,
  277.      we're ok here because I have threading turned off for the local
  278.      protocol (see use_threads in local_init above) */
  279.   g_return_val_if_fail (request != NULL, -2);
  280.   g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
  281.   g_return_val_if_fail (fle != NULL, -2);
  282.   lpd = request->protocol_data;
  283.   memset (fle, 0, sizeof (*fle));
  284.   if ((dirp = readdir (lpd->dir)) == NULL)
  285.     {
  286.       closedir (lpd->dir);
  287.       lpd->dir = NULL;
  288.       return (-2);
  289.     }
  290.   fle->file = g_malloc (strlen (dirp->d_name) + 1);
  291.   strcpy (fle->file, dirp->d_name);
  292.   if (lstat (fle->file, &st) != 0)
  293.     {
  294.       closedir (lpd->dir);
  295.       lpd->dir = NULL;
  296.       return (-2);
  297.     }
  298.   if ((user = g_hash_table_lookup (lpd->userhash, 
  299.                                    GUINT_TO_POINTER(st.st_uid))) != NULL)
  300.     {
  301.       fle->user = g_malloc (strlen (user) + 1);
  302.       strcpy (fle->user, user);
  303.     }
  304.   else
  305.     {
  306.       if ((pw = getpwuid (st.st_uid)) == NULL)
  307.         fle->user = g_strdup_printf ("%u", st.st_uid); 
  308.       else
  309.         {
  310.           fle->user = g_malloc (strlen (pw->pw_name) + 1);
  311.           strcpy (fle->user, pw->pw_name);
  312.         }
  313.       user = g_malloc (strlen (fle->user) + 1);
  314.       strcpy (user, fle->user);
  315.       g_hash_table_insert (lpd->userhash, GUINT_TO_POINTER (st.st_uid), user);
  316.     }
  317.   if ((group = g_hash_table_lookup (lpd->grouphash, 
  318.                                     GUINT_TO_POINTER(st.st_gid))) != NULL)
  319.     {
  320.       fle->group = g_malloc (strlen (group) + 1);
  321.       strcpy (fle->group, group);
  322.     }
  323.   else
  324.     {
  325.       if ((gr = getgrgid (st.st_gid)) == NULL)
  326.         fle->group = g_strdup_printf ("%u", st.st_gid); 
  327.       else
  328.         {
  329.           fle->group = g_malloc (strlen (gr->gr_name) + 1);
  330.           strcpy (fle->group, gr->gr_name);
  331.         }
  332.       group = g_malloc (strlen (fle->group) + 1);
  333.       strcpy (group, fle->group);
  334.       g_hash_table_insert (lpd->grouphash, GUINT_TO_POINTER (st.st_gid), group);
  335.     }
  336.   fle->attribs = make_text_mode (fle, st.st_mode);
  337.   fle->datetime = st.st_mtime;
  338.   if ((fle->attribs[0] == 'b' || fle->attribs[0] == 'u' ||
  339.        fle->attribs[0] == 'c'))
  340.     fle->size = (off_t) st.st_rdev;
  341.   else
  342.     fle->size = st.st_size;
  343.   if (*fle->attribs == 'd')
  344.     fle->isdir = 1;
  345.   if (*fle->attribs == 'l')
  346.     fle->islink = 1;
  347.   if (strchr (fle->attribs, 'x') != NULL && !fle->isdir && !fle->islink)
  348.     fle->isexe = 1;
  349.   if (*fle->attribs == 'b')
  350.     fle->isblock = 1;
  351.   if (*fle->attribs == 'c')
  352.     fle->ischar = 1;
  353.   if (*fle->attribs == 's')
  354.     fle->issocket = 1;
  355.   if (*fle->attribs == 'p')
  356.     fle->isfifo = 1;
  357.   return (1);
  358. }
  359. static int
  360. local_list_files (gftp_request * request)
  361. {
  362.   local_protocol_data *lpd;
  363.   char *tempstr;
  364.   g_return_val_if_fail (request != NULL, -2);
  365.   g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
  366.   lpd = request->protocol_data;
  367.   tempstr = g_strconcat (request->directory, "/", NULL);
  368.   if ((lpd->dir = opendir (tempstr)) == NULL)
  369.     {
  370.       request->logging_function (gftp_logging_error, request->user_data,
  371.                            _("Could not get local directory listing %s: %sn"),
  372.                            tempstr, g_strerror (errno));
  373.       g_free (tempstr);
  374.       return (-1);
  375.     }
  376.   g_free (tempstr);
  377.   return (0);
  378. }
  379. static off_t 
  380. local_get_file_size (gftp_request * request, const char *filename)
  381. {
  382.   struct stat st;
  383.   if (stat (filename, &st) == -1)
  384.     return (-1);
  385.   return (st.st_size);
  386. }
  387. static int
  388. local_chdir (gftp_request * request, const char *directory)
  389. {
  390.   char tempstr[255];
  391.   g_return_val_if_fail (request != NULL, -2);
  392.   g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
  393.   g_return_val_if_fail (directory != NULL, -2);
  394.   if (chdir (directory) == 0)
  395.     {
  396.       request->logging_function (gftp_logging_misc, request->user_data,
  397.                           _("Successfully changed local directory to %sn"),
  398.                           directory);
  399.       if (request->directory != directory)
  400.         {
  401.           if (getcwd (tempstr, sizeof (tempstr)) == NULL)
  402.     {
  403.               request->logging_function (gftp_logging_error, request->user_data,
  404.                             _("Could not get current working directory: %sn"),
  405.                             g_strerror (errno));
  406.       return (-1);
  407.     }
  408.           if (request->directory)
  409.     g_free (request->directory);
  410.           request->directory = g_malloc (strlen (tempstr) + 1);
  411.           strcpy (request->directory, tempstr);
  412.         }
  413.       return (0);
  414.     }
  415.   request->logging_function (gftp_logging_error, request->user_data,
  416.                              _("Could not change local directory to %s: %sn"),
  417.                              directory, g_strerror (errno));
  418.   return (-1);
  419. }
  420. static int
  421. local_rmdir (gftp_request * request, const char *directory)
  422. {
  423.   g_return_val_if_fail (request != NULL, -2);
  424.   g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
  425.   g_return_val_if_fail (directory != NULL, -2);
  426.   if (rmdir (directory) == 0)
  427.     {
  428.       request->logging_function (gftp_logging_misc, request->user_data,
  429.                                  _("Successfully removed %sn"), directory);
  430.       return (0);
  431.     }
  432.   else
  433.     {
  434.       request->logging_function (gftp_logging_error, request->user_data,
  435.                               _("Error: Could not remove directory %s: %sn"),
  436.                               directory, g_strerror (errno));
  437.       return (-1);
  438.     }
  439. }
  440. static int
  441. local_rmfile (gftp_request * request, const char *file)
  442. {
  443.   g_return_val_if_fail (request != NULL, -2);
  444.   g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
  445.   g_return_val_if_fail (file != NULL, -2);
  446.   if (unlink (file) == 0)
  447.     {
  448.       request->logging_function (gftp_logging_misc, request->user_data,
  449.                                  _("Successfully removed %sn"), file);
  450.       return (0);
  451.     }
  452.   else
  453.     {
  454.       request->logging_function (gftp_logging_error, request->user_data,
  455.                                  _("Error: Could not remove file %s: %sn"),
  456.                                  file, g_strerror (errno));
  457.       return (-1);
  458.     }
  459. }
  460. static int
  461. local_mkdir (gftp_request * request, const char *directory)
  462. {
  463.   g_return_val_if_fail (request != NULL, -2);
  464.   g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
  465.   g_return_val_if_fail (directory != NULL, -2);
  466.   if (mkdir (directory, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0)
  467.     {
  468.       request->logging_function (gftp_logging_misc, request->user_data,
  469.                                  _("Successfully made directory %sn"),
  470.                                  directory);
  471.       return (0);
  472.     }
  473.   else
  474.     {
  475.       request->logging_function (gftp_logging_error, request->user_data,
  476.                                  _("Error: Could not make directory %s: %sn"),
  477.                                  directory, g_strerror (errno));
  478.       return (-1);
  479.     }
  480. }
  481. static int
  482. local_rename (gftp_request * request, const char *oldname,
  483.       const char *newname)
  484. {
  485.   g_return_val_if_fail (request != NULL, -2);
  486.   g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
  487.   g_return_val_if_fail (oldname != NULL, -2);
  488.   g_return_val_if_fail (newname != NULL, -2);
  489.   if (rename (oldname, newname) == 0)
  490.     {
  491.       request->logging_function (gftp_logging_misc, request->user_data,
  492.                                  _("Successfully renamed %s to %sn"),
  493.                                  oldname, newname);
  494.       return (0);
  495.     }
  496.   else
  497.     {
  498.       request->logging_function (gftp_logging_error, request->user_data,
  499.                                  _("Error: Could not rename %s to %s: %sn"),
  500.                                  oldname, newname, g_strerror (errno));
  501.       return (-1);
  502.     }
  503. }
  504. static int
  505. local_chmod (gftp_request * request, const char *file, int mode)
  506. {
  507.   char buf[10];
  508.   int newmode;
  509.   g_return_val_if_fail (request != NULL, -2);
  510.   g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
  511.   g_return_val_if_fail (file != NULL, -2);
  512.   g_snprintf (buf, sizeof (buf), "%d", mode);
  513.   newmode = strtol (buf, NULL, 8);
  514.   if (chmod (file, newmode) == 0) 
  515.     {
  516.       request->logging_function (gftp_logging_misc, request->user_data, 
  517.                                  _("Successfully changed mode of %s to %dn"),
  518.                                  file, mode);
  519.       return (0);
  520.     }
  521.   else 
  522.     {
  523.       request->logging_function (gftp_logging_error, request->user_data, 
  524.                           _("Error: Could not change mode of %s to %d: %sn"),
  525.                           file, mode, g_strerror (errno));
  526.       return (-1);
  527.     }
  528. }
  529. static int
  530. local_set_file_time (gftp_request * request, const char *file,
  531.      time_t datetime)
  532. {
  533.   struct utimbuf time_buf;
  534.   g_return_val_if_fail (request != NULL, -2);
  535.   g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, -2);
  536.   g_return_val_if_fail (file != NULL, -2);
  537.   time_buf.modtime = time_buf.actime = datetime;
  538.   return (utime (file, &time_buf));
  539. }
  540. static gint
  541. hash_compare (gconstpointer path1, gconstpointer path2)
  542. {
  543.   return (GPOINTER_TO_UINT (path1) == GPOINTER_TO_UINT (path2));
  544. }
  545. static guint
  546. hash_function (gconstpointer key)
  547. {
  548.   return (GPOINTER_TO_UINT (key));
  549. }
  550. void
  551. local_init (gftp_request * request)
  552. {
  553.   local_protocol_data *lpd;
  554.   g_return_if_fail (request != NULL);
  555.   request->protonum = GFTP_LOCAL_NUM;
  556.   request->init = local_init;
  557.   request->destroy = local_destroy;
  558.   request->connect = local_connect;
  559.   request->disconnect = local_disconnect;
  560.   request->get_file = local_get_file;
  561.   request->put_file = local_put_file;
  562.   request->transfer_file = NULL;
  563.   request->get_next_file_chunk = NULL;
  564.   request->put_next_file_chunk = NULL;
  565.   request->end_transfer = local_end_transfer;
  566.   request->abort_transfer = local_end_transfer; /* NOTE: uses end_transfer */
  567.   request->list_files = local_list_files;
  568.   request->get_next_file = local_get_next_file;
  569.   request->set_data_type = NULL;
  570.   request->get_file_size = local_get_file_size;
  571.   request->chdir = local_chdir;
  572.   request->rmdir = local_rmdir;
  573.   request->rmfile = local_rmfile;
  574.   request->mkdir = local_mkdir;
  575.   request->rename = local_rename;
  576.   request->chmod = local_chmod;
  577.   request->set_file_time = local_set_file_time;
  578.   request->site = NULL;
  579.   request->parse_url = NULL;
  580.   request->set_config_options = NULL;
  581.   request->swap_socks = NULL;
  582.   request->url_prefix = "file";
  583.   request->protocol_name = "Local";
  584.   request->need_hostport = 0;
  585.   request->need_userpass = 0;
  586.   request->use_cache = 0;
  587.   request->use_threads = 0;
  588.   request->always_connected = 1;
  589.   gftp_set_config_options (request);
  590.   lpd = g_malloc0 (sizeof (*lpd));
  591.   request->protocol_data = lpd;
  592.   lpd->userhash = g_hash_table_new (hash_function, hash_compare);
  593.   lpd->grouphash = g_hash_table_new (hash_function, hash_compare);
  594.   if (request->hostname != NULL)
  595.     g_free (request->hostname);
  596.   request->hostname = g_strdup (_("local filesystem"));
  597. }