# HG changeset patch # User masneyb # Date 1154051094 0 # Node ID 3751478bb260f1991fbd83144f6aaf236b770e3b # Parent 78bad9db6cb0b0c34d84cd38564a49242481ec52 2006-7-27 Brian Masney * lib/protocols.c (gftp_get_all_subdirs) - split this function into several smaller functions. Added support for getting the true file size if it is a symlink. Added more error handling. Fixed a segfault that may occur when transferring deeply nested directories * lib/fsp.c lib/gftp.h lib/local.c lib/protocols.c lib/rfc2068.c lib/rfc959.c lib/sshv2.c (*_chdir) - removed support for passing the request->directory into this function. There is no longer a need for this. (*_stat_filename) - added support for getting the file size diff -r 78bad9db6cb0 -r 3751478bb260 ChangeLog --- a/ChangeLog Thu Jul 27 18:25:38 2006 +0000 +++ b/ChangeLog Fri Jul 28 01:44:54 2006 +0000 @@ -1,3 +1,15 @@ +2006-7-27 Brian Masney + * lib/protocols.c (gftp_get_all_subdirs) - split this function into + several smaller functions. Added support for getting the true file + size if it is a symlink. Added more error handling. Fixed a segfault + that may occur when transferring deeply nested directories + + * lib/fsp.c lib/gftp.h lib/local.c lib/protocols.c lib/rfc2068.c + lib/rfc959.c lib/sshv2.c (*_chdir) - removed support for passing + the request->directory into this function. There is no longer a + need for this. (*_stat_filename) - added support for getting the + file size + 2006-7-21 Brian Masney * src/gtk/transfer.c (transfer_done) - fixed race condition that would occur when selecting Stop Transfer and then Start Transfer @@ -3484,7 +3496,7 @@ * cvsclean - added this script - * *.[ch] - added $Id: ChangeLog,v 1.456 2006/07/21 13:30:11 masneyb Exp $ tags + * *.[ch] - added $Id: ChangeLog,v 1.457 2006/07/28 01:44:52 masneyb Exp $ tags * debian/* - updated files from Debian maintainer diff -r 78bad9db6cb0 -r 3751478bb260 lib/fsp.c --- a/lib/fsp.c Thu Jul 27 18:25:38 2006 +0000 +++ b/lib/fsp.c Fri Jul 28 01:44:54 2006 +0000 @@ -278,10 +278,10 @@ static int fsp_stat_filename (gftp_request * request, const char *filename, - mode_t * mode) + mode_t * mode, off_t * filesize) { + fsp_protocol_data * lpd; struct stat st; - fsp_protocol_data * lpd; g_return_val_if_fail (request != NULL, GFTP_EFATAL); g_return_val_if_fail (request->protonum == GFTP_FSP_NUM, GFTP_EFATAL); @@ -294,6 +294,8 @@ return (GFTP_ERETRYABLE); *mode = st.st_mode; + *filesize = st.st_size; + return (0); } @@ -417,19 +419,16 @@ olddir=NULL; /* build new directory string */ - if (request->directory != directory) - { - olddir = request->directory; + olddir = request->directory; - if (*directory != '/' && request->directory != NULL) - { - tempstr = g_strconcat (request->directory, "/", directory, NULL); - request->directory = gftp_expand_path (request, tempstr); - g_free (tempstr); - } - else - request->directory = gftp_expand_path (request, directory); + if (*directory != '/' && request->directory != NULL) + { + tempstr = g_strconcat (request->directory, "/", directory, NULL); + request->directory = gftp_expand_path (request, tempstr); + g_free (tempstr); } + else + request->directory = gftp_expand_path (request, directory); if (fsp_getpro (lpd->fsp,request->directory,NULL) == 0) { diff -r 78bad9db6cb0 -r 3751478bb260 lib/gftp.h --- a/lib/gftp.h Thu Jul 27 18:25:38 2006 +0000 +++ b/lib/gftp.h Fri Jul 28 01:44:54 2006 +0000 @@ -254,7 +254,9 @@ done_edit : 1, /* Edit the file when done transfering? */ done_rm : 1, /* Remove the file when done */ transfer_done : 1, /* Is current file transfer done? */ - is_fd : 1; /* Is this a file descriptor? */ + is_fd : 1, /* Is this a file descriptor? */ + exists_other_side; /* The file exists on the other side during + the file transfer */ char transfer_action; /* See the GFTP_TRANS_ACTION_* vars above */ /*@null@*/ void *user_data; }; @@ -452,7 +454,8 @@ int (*abort_transfer) ( gftp_request * request ); int (*stat_filename) ( gftp_request * request, const char *filename, - mode_t * mode ); + mode_t * mode, + off_t * filesize ); int (*list_files) ( gftp_request * request ); int (*get_next_file) ( gftp_request * request, gftp_file *fle, @@ -927,7 +930,8 @@ int gftp_stat_filename ( gftp_request * request, const char *filename, - mode_t * mode ); + mode_t * mode, + off_t * filesize ); void gftp_set_hostname ( gftp_request * request, const char *hostname ); diff -r 78bad9db6cb0 -r 3751478bb260 lib/local.c --- a/lib/local.c Thu Jul 27 18:25:38 2006 +0000 +++ b/lib/local.c Fri Jul 28 01:44:54 2006 +0000 @@ -28,8 +28,7 @@ static void -local_remove_key (/*@unused@*/ gpointer key, gpointer value, - /*@unused@*/ gpointer user_data) +local_remove_key (gpointer key, gpointer value, gpointer user_data) { g_free (value); } @@ -155,7 +154,7 @@ static int local_put_file (gftp_request * request, const char *filename, int fd, - off_t startsize, /*@unused@*/ off_t totalsize) + off_t startsize, off_t totalsize) { int flags; @@ -226,8 +225,8 @@ static int -local_stat_filename (/*@unused@*/ gftp_request * request, const char *filename, - mode_t * mode) +local_stat_filename (gftp_request * request, const char *filename, + mode_t * mode, off_t * filesize) { struct stat st; @@ -235,6 +234,8 @@ return (GFTP_ERETRYABLE); *mode = st.st_mode; + *filesize = st.st_size; + return (0); } @@ -360,7 +361,7 @@ static off_t -local_get_file_size (/*@unused@*/ gftp_request * request, const char *filename) +local_get_file_size (gftp_request * request, const char *filename) { struct stat st; @@ -373,7 +374,7 @@ static int local_chdir (gftp_request * request, const char *directory) { - char tempstr[255]; + char tempstr[MAXNAMLEN]; g_return_val_if_fail (request != NULL, GFTP_EFATAL); g_return_val_if_fail (request->protonum == GFTP_LOCAL_NUM, GFTP_EFATAL); @@ -385,28 +386,25 @@ _("Successfully changed local directory to %s\n"), directory); - if (request->directory != directory) + if (getcwd (tempstr, sizeof (tempstr)) == NULL) { - if (getcwd (tempstr, sizeof (tempstr)) == NULL) - { - request->logging_function (gftp_logging_error, request, - _("Could not get current working directory: %s\n"), - g_strerror (errno)); - return (GFTP_ERETRYABLE); - } - - if (request->directory) - g_free (request->directory); - request->directory = g_strdup (tempstr); + request->logging_function (gftp_logging_error, request, + _("Could not get current working directory: %s\n"), + g_strerror (errno)); + return (GFTP_ERETRYABLE); } + if (request->directory) + g_free (request->directory); + + request->directory = g_strdup (tempstr); return (0); } else { request->logging_function (gftp_logging_error, request, - _("Could not change local directory to %s: %s\n"), - directory, g_strerror (errno)); + _("Could not change local directory to %s: %s\n"), + directory, g_strerror (errno)); return (GFTP_ERETRYABLE); } } diff -r 78bad9db6cb0 -r 3751478bb260 lib/protocols.c --- a/lib/protocols.c Thu Jul 27 18:25:38 2006 +0000 +++ b/lib/protocols.c Fri Jul 28 01:44:54 2006 +0000 @@ -345,13 +345,14 @@ int -gftp_stat_filename (gftp_request * request, const char *filename, mode_t * mode) +gftp_stat_filename (gftp_request * request, const char *filename, mode_t * mode, + off_t * filesize) { g_return_val_if_fail (request != NULL, GFTP_EFATAL); g_return_val_if_fail (filename != NULL, GFTP_EFATAL); if (request->stat_filename != NULL) - return (request->stat_filename (request, filename, mode)); + return (request->stat_filename (request, filename, mode, filesize)); else return (0); } @@ -1864,7 +1865,6 @@ GHashTable * dirhash; gftp_file * fle; off_t *newsize; - char * newname; dirhash = g_hash_table_new (string_hash_function, string_hash_compare); *ret = gftp_list_files (request); @@ -1873,10 +1873,9 @@ fle = g_malloc0 (sizeof (*fle)); while (gftp_get_next_file (request, NULL, fle) > 0) { - newname = fle->file; newsize = g_malloc (sizeof (*newsize)); *newsize = fle->size; - g_hash_table_insert (dirhash, newname, newsize); + g_hash_table_insert (dirhash, fle->file, newsize); fle->file = NULL; gftp_file_destroy (fle, 0); } @@ -1905,6 +1904,9 @@ static void gftp_destroy_dir_hash (GHashTable * dirhash) { + if (dirhash == NULL) + return; + g_hash_table_foreach (dirhash, destroy_hash_ent, NULL); g_hash_table_destroy (dirhash); } @@ -1919,10 +1921,10 @@ off_t *newsize; char *newname; - if (getothdir && transfer->toreq) + if (getothdir && transfer->toreq != NULL) { dirhash = gftp_gen_dir_hash (transfer->toreq, ret); - if (*ret < 0) + if (*ret == GFTP_EFATAL) return (NULL); } else @@ -1930,7 +1932,10 @@ *ret = gftp_list_files (transfer->fromreq); if (*ret < 0) - return (NULL); + { + gftp_destroy_dir_hash (dirhash); + return (NULL); + } fle = g_malloc (sizeof (*fle)); templist = NULL; @@ -1944,7 +1949,12 @@ if (dirhash && (newsize = g_hash_table_lookup (dirhash, fle->file)) != NULL) - fle->startsize = *newsize; + { + fle->exists_other_side = 1; + fle->startsize = *newsize; + } + else + fle->exists_other_side = 0; if (transfer->toreq && fle->destfile == NULL) fle->destfile = gftp_build_path (transfer->toreq, @@ -1965,41 +1975,51 @@ templist = g_list_append (templist, fle); - fle = g_malloc (sizeof (*fle)); + fle = g_malloc0 (sizeof (*fle)); } gftp_end_transfer (transfer->fromreq); gftp_file_destroy (fle, 1); - - if (dirhash != NULL) - gftp_destroy_dir_hash (dirhash); + gftp_destroy_dir_hash (dirhash); return (templist); } -int -gftp_get_all_subdirs (gftp_transfer * transfer, - void (*update_func) (gftp_transfer * transfer)) +static void +_cleanup_get_all_subdirs (gftp_transfer * transfer, char *oldfromdir, + char *oldtodir, + void (*update_func) (gftp_transfer * transfer)) { - char *oldfromdir, *oldtodir, *newname, *pos; - int forcecd, remotechanged, ret; - GList * templist, * lastlist; + if (update_func != NULL) + { + transfer->numfiles = transfer->numdirs = -1; + update_func (transfer); + } + + if (oldfromdir != NULL) + g_free (oldfromdir); + + if (oldtodir != NULL) + g_free (oldtodir); +} + + +static GList * +_setup_current_directory_transfer (gftp_transfer * transfer, int *ret) +{ GHashTable * dirhash; + char *pos, *newname; gftp_file * curfle; + GList * lastlist; off_t *newsize; - mode_t st_mode; - - g_return_val_if_fail (transfer != NULL, GFTP_EFATAL); - g_return_val_if_fail (transfer->fromreq != NULL, GFTP_EFATAL); - g_return_val_if_fail (transfer->files != NULL, GFTP_EFATAL); - + + *ret = 0; if (transfer->toreq != NULL) { - ret = 0; - dirhash = gftp_gen_dir_hash (transfer->toreq, &ret); - if (ret < 0) - return (ret); + dirhash = gftp_gen_dir_hash (transfer->toreq, ret); + if (*ret == GFTP_EFATAL) + return (NULL); } else dirhash = NULL; @@ -2015,13 +2035,22 @@ if (dirhash != NULL && (newsize = g_hash_table_lookup (dirhash, pos)) != NULL) - curfle->startsize = *newsize; + { + curfle->exists_other_side = 1; + curfle->startsize = *newsize; + } + else + curfle->exists_other_side = 0; if (curfle->size < 0 && GFTP_IS_CONNECTED (transfer->fromreq)) { curfle->size = gftp_get_file_size (transfer->fromreq, curfle->file); - if (curfle->size < 0) - return (curfle->size); + if (curfle->size == GFTP_EFATAL) + { + gftp_destroy_dir_hash (dirhash); + *ret = curfle->size; + return (NULL); + } } if (transfer->toreq && curfle->destfile == NULL) @@ -2043,12 +2072,37 @@ break; } - if (dirhash != NULL) - gftp_destroy_dir_hash (dirhash); + gftp_destroy_dir_hash (dirhash); + + return (lastlist); +} + + +int +gftp_get_all_subdirs (gftp_transfer * transfer, + void (*update_func) (gftp_transfer * transfer)) +{ + GList * templist, * lastlist; + char *oldfromdir, *oldtodir; + gftp_file * curfle; + off_t linksize; + mode_t st_mode; + int ret; + + g_return_val_if_fail (transfer != NULL, GFTP_EFATAL); + g_return_val_if_fail (transfer->fromreq != NULL, GFTP_EFATAL); + g_return_val_if_fail (transfer->files != NULL, GFTP_EFATAL); + + if (transfer->files == NULL) + return (0); + + ret = 0; + lastlist = _setup_current_directory_transfer (transfer, &ret); + if (lastlist == NULL) + return (ret); oldfromdir = oldtodir = NULL; - remotechanged = 0; - forcecd = 0; + for (templist = transfer->files; templist != NULL; templist = templist->next) { curfle = templist->data; @@ -2056,84 +2110,107 @@ if (S_ISLNK (curfle->st_mode) && !S_ISDIR (curfle->st_mode)) { st_mode = 0; - ret = gftp_stat_filename (transfer->fromreq, curfle->file, &st_mode); + linksize = 0; + ret = gftp_stat_filename (transfer->fromreq, curfle->file, &st_mode, + &linksize); if (ret < 0) - return (ret); + { + _cleanup_get_all_subdirs (transfer, oldfromdir, oldtodir, + update_func); + return (ret); + } else if (S_ISDIR (st_mode)) curfle->st_mode = st_mode; + else + curfle->size = linksize; } - if (curfle->st_mode & S_IFDIR) + if (!(curfle->st_mode & S_IFDIR)) { - oldfromdir = transfer->fromreq->directory; - transfer->fromreq->directory = g_strdup (curfle->file); - - if (transfer->toreq != NULL) + transfer->numfiles++; + continue; + } + + /* Got a directory... */ + if (oldfromdir == NULL) + oldfromdir = g_strdup (transfer->fromreq->directory); + + ret = gftp_set_directory (transfer->fromreq, curfle->file); + if (ret < 0) + { + _cleanup_get_all_subdirs (transfer, oldfromdir, oldtodir, + update_func); + return (ret); + } + + if (transfer->toreq != NULL) + { + if (oldtodir == NULL) + oldtodir = g_strdup (transfer->toreq->directory); + + if (curfle->exists_other_side) { - oldtodir = transfer->toreq->directory; - transfer->toreq->directory = g_strdup (curfle->destfile); - } - - forcecd = 1; - ret = gftp_set_directory (transfer->fromreq, - transfer->fromreq->directory); - if (ret < 0) - return (ret); - - if (curfle->startsize > 0 && transfer->toreq != NULL) - { - remotechanged = 1; - ret = gftp_set_directory (transfer->toreq, - transfer->toreq->directory); - if (ret < 0) - return (ret); - } - - ret = 0; - lastlist->next = gftp_get_dir_listing (transfer, - curfle->startsize > 0, - &ret); - if (ret < 0) - return (ret); - - if (lastlist->next != NULL) + ret = gftp_set_directory (transfer->toreq, curfle->destfile); + if (ret == GFTP_EFATAL) + { + _cleanup_get_all_subdirs (transfer, oldfromdir, oldtodir, + update_func); + return (ret); + } + } + else { - lastlist->next->prev = lastlist; - for (; lastlist->next != NULL; lastlist = lastlist->next); + if (transfer->toreq->directory != NULL) + g_free (transfer->toreq->directory); + + transfer->toreq->directory = g_strdup (curfle->destfile); } - - transfer->numdirs++; - if (update_func != NULL) - update_func (transfer); - - transfer->fromreq->directory = oldfromdir; - if (transfer->toreq != NULL) - transfer->toreq->directory = oldtodir; + } + + ret = 0; + lastlist->next = gftp_get_dir_listing (transfer, + curfle->exists_other_side, &ret); + if (ret < 0) + { + _cleanup_get_all_subdirs (transfer, oldfromdir, oldtodir, + update_func); + return (ret); } - else - transfer->numfiles++; + + if (lastlist->next != NULL) + { + lastlist->next->prev = lastlist; + for (; lastlist->next != NULL; lastlist = lastlist->next); + } + + transfer->numdirs++; + if (update_func != NULL) + update_func (transfer); } - if (forcecd) + if (oldfromdir != NULL) { - ret = gftp_set_directory (transfer->fromreq, - transfer->fromreq->directory); + ret = gftp_set_directory (transfer->fromreq, oldfromdir); if (ret < 0) - return (ret); + { + _cleanup_get_all_subdirs (transfer, oldfromdir, oldtodir, + update_func); + return (ret); + } } - if (remotechanged && transfer->toreq != NULL) + if (oldtodir != NULL) { - ret = gftp_set_directory (transfer->toreq, transfer->toreq->directory); + ret = gftp_set_directory (transfer->toreq, oldtodir); if (ret < 0) - return (ret); + { + _cleanup_get_all_subdirs (transfer, oldfromdir, oldtodir, + update_func); + return (ret); + } } - if (update_func != NULL) - { - transfer->numfiles = transfer->numdirs = -1; - update_func (transfer); - } + _cleanup_get_all_subdirs (transfer, oldfromdir, oldtodir, update_func); return (0); } diff -r 78bad9db6cb0 -r 3751478bb260 lib/rfc2068.c --- a/lib/rfc2068.c Thu Jul 27 18:25:38 2006 +0000 +++ b/lib/rfc2068.c Fri Jul 28 01:44:54 2006 +0000 @@ -640,27 +640,26 @@ static int rfc2068_chdir (gftp_request * request, const char *directory) { - char *tempstr, *olddir; + char *tempstr; g_return_val_if_fail (request != NULL, GFTP_EFATAL); g_return_val_if_fail (directory != NULL, GFTP_EFATAL); - if (request->directory != directory) + if (*directory != '/' && request->directory != NULL) { - olddir = request->directory; + tempstr = g_strconcat (request->directory, "/", directory, NULL); + g_free (request->directory); + request->directory = gftp_expand_path (request, tempstr); + g_free (tempstr); + } + else + { + if (request->directory != NULL) + g_free (request->directory); - if (*directory != '/' && request->directory != NULL) - { - tempstr = g_strconcat (request->directory, "/", directory, NULL); - request->directory = gftp_expand_path (request, tempstr); - g_free (tempstr); - } - else - request->directory = gftp_expand_path (request, directory); + request->directory = gftp_expand_path (request, directory); + } - if (olddir != NULL) - g_free (olddir); - } return (0); } diff -r 78bad9db6cb0 -r 3751478bb260 lib/rfc959.c --- a/lib/rfc959.c Thu Jul 27 18:25:38 2006 +0000 +++ b/lib/rfc959.c Fri Jul 28 01:44:54 2006 +0000 @@ -378,11 +378,8 @@ else if (ret != '2') return (GFTP_ERETRYABLE); - if (directory != request->directory) - { - if ((ret = rfc959_getcwd (request)) < 0) - return (ret); - } + if ((ret = rfc959_getcwd (request)) < 0) + return (ret); return (0); } diff -r 78bad9db6cb0 -r 3751478bb260 lib/sshv2.c --- a/lib/sshv2.c Thu Jul 27 18:25:38 2006 +0000 +++ b/lib/sshv2.c Fri Jul 28 01:44:54 2006 +0000 @@ -1416,38 +1416,32 @@ g_return_val_if_fail (request != NULL, GFTP_EFATAL); g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, GFTP_EFATAL); - if (request->directory != directory) - { - len = 0; - tempstr = sshv2_initialize_string_with_path (request, directory, - &len, NULL); + len = 0; + tempstr = sshv2_initialize_string_with_path (request, directory, &len, NULL); - ret = sshv2_send_command (request, SSH_FXP_REALPATH, tempstr, len); + ret = sshv2_send_command (request, SSH_FXP_REALPATH, tempstr, len); - g_free (tempstr); - if (ret < 0) - return (ret); + g_free (tempstr); + if (ret < 0) + return (ret); - ret = sshv2_read_status_response (request, &message, -1, SSH_FXP_STATUS, - SSH_FXP_NAME); - if (ret < 0) - return (ret); + ret = sshv2_read_status_response (request, &message, -1, SSH_FXP_STATUS, + SSH_FXP_NAME); + if (ret < 0) + return (ret); - message.pos += 4; - if ((ret = sshv2_buffer_get_int32 (request, &message, 1, 1, NULL)) < 0) - return (ret); + message.pos += 4; + if ((ret = sshv2_buffer_get_int32 (request, &message, 1, 1, NULL)) < 0) + return (ret); - if ((dir = sshv2_buffer_get_string (request, &message, 1)) == NULL) - return (GFTP_EFATAL); - - if (request->directory) - g_free (request->directory); + if ((dir = sshv2_buffer_get_string (request, &message, 1)) == NULL) + return (GFTP_EFATAL); - request->directory = dir; - sshv2_message_free (&message); - return (0); - } + if (request->directory) + g_free (request->directory); + request->directory = dir; + sshv2_message_free (&message); return (0); } @@ -1744,7 +1738,7 @@ static int sshv2_stat_filename (gftp_request * request, const char *filename, - mode_t * mode) + mode_t * mode, off_t * filesize) { gftp_file fle; int ret; @@ -1755,6 +1749,8 @@ return (ret); *mode = fle.st_mode; + *filesize = fle.size; + gftp_file_destroy (&fle, 0); return (0);