static void fsp_disconnect (gftp_request * request) { fsp_protocol_data * lpd; g_return_if_fail (request != NULL); g_return_if_fail (request->protonum == GFTP_FSP_NUM); lpd = request->protocol_data; g_return_if_fail (lpd != NULL); if(lpd->file) { fsp_fclose(lpd->file); lpd->file=NULL; } fsp_close_session(lpd->fsp); lpd->fsp=NULL; request->datafd = -1; if(lpd->dir) { fsp_closedir(lpd->dir); lpd->dir=NULL; } }
static int fsp_abort_transfer (gftp_request * request) { 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); lpd = request->protocol_data; g_return_val_if_fail (lpd->fsp != NULL, GFTP_EFATAL); if (lpd->dir) { fsp_closedir (lpd->dir); lpd->dir = NULL; } if (lpd ->file) { if(lpd->file->writing && lpd->file->pos>0) { /* need to cancel upload in progress */ lpd->file->writing=0; fsp_install(lpd->fsp,"",0); } /* we can safely ignore file close error on abort */ fsp_fclose(lpd->file); lpd->file=NULL; } return (0); }
static int fsp_end_transfer (gftp_request * request) { 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); lpd = request->protocol_data; g_return_val_if_fail (lpd->fsp != NULL, GFTP_EFATAL); if (lpd->dir) { fsp_closedir (lpd->dir); lpd->dir = NULL; } if (lpd ->file) { if(fsp_fclose(lpd->file)) { lpd -> file = NULL; request->logging_function (gftp_logging_error, request, _("Error: Error closing file: %s\n"), g_strerror (errno)); return GFTP_EFATAL; } lpd->file=NULL; } return (0); }
static int fsp_put_file (gftp_request * request, const char *filename, off_t startsize, off_t totalsize) { 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); g_return_val_if_fail (filename != NULL, GFTP_EFATAL); lpd = request->protocol_data; g_return_val_if_fail (lpd != NULL,GFTP_EFATAL); g_return_val_if_fail (lpd->fsp != NULL,GFTP_EFATAL); if(lpd->file != NULL) { fsp_fclose(lpd->file); lpd->file=NULL; } if(fsp_canupload(lpd->fsp,filename)) { request->logging_function (gftp_logging_error, request, _("Error: Cannot upload file %s\n"), filename ); return (GFTP_ERETRYABLE); } lpd->file=fsp_fopen(lpd->fsp,filename, "wb"); if(lpd->file == NULL) { request->logging_function (gftp_logging_error, request, _("Error: Cannot write to file %s: %s\n"), filename, g_strerror (errno)); return (GFTP_ERETRYABLE); } if (fsp_fseek (lpd->file, startsize, SEEK_SET) == -1) { request->logging_function (gftp_logging_error, request, _("Error: Cannot seek on file %s: %s\n"), filename, g_strerror (errno)); gftp_disconnect (request); return (GFTP_ERETRYABLE); } return (0); }
static off_t fsp_get_file (gftp_request * request, const char *filename, off_t startsize) { fsp_protocol_data * lpd; struct stat sb; g_return_val_if_fail (request != NULL,GFTP_EFATAL); g_return_val_if_fail (request->protonum == GFTP_FSP_NUM,GFTP_EFATAL); g_return_val_if_fail (filename != NULL, GFTP_EFATAL); lpd = request->protocol_data; g_return_val_if_fail (lpd != NULL,GFTP_EFATAL); g_return_val_if_fail (lpd->fsp != NULL,GFTP_EFATAL); /* CHECK: close prev. opened file, is this needed? */ if(lpd->file != NULL) { fsp_fclose(lpd->file); lpd->file=NULL; } if(fsp_stat(lpd->fsp,filename,&sb)) return (GFTP_ERETRYABLE); if(!S_ISREG(sb.st_mode)) return (GFTP_ERETRYABLE); lpd->file=fsp_fopen(lpd->fsp,filename,"rb"); if (fsp_fseek (lpd->file, startsize, SEEK_SET) == -1) { request->logging_function (gftp_logging_error, request, _("Error: Cannot seek on file %s: %s\n"), filename, g_strerror (errno)); gftp_disconnect (request); return (GFTP_ERETRYABLE); } return (sb.st_size); }
static void do_fsp(struct connection *conn) { FSP_SESSION *ses; struct stat sb; struct uri *uri = conn->uri; struct auth_entry *auth; unsigned char *host = get_uri_string(uri, URI_HOST); unsigned char *data = get_uri_string(uri, URI_DATA); unsigned short port = (unsigned short)get_uri_port(uri); unsigned char *password = NULL; decode_uri(data); if (uri->passwordlen) { password = get_uri_string(uri, URI_PASSWORD); } else { auth = find_auth(uri); if (auth) password = auth->password; } /* fsp_open_session may not set errno if getaddrinfo fails * https://sourceforge.net/tracker/index.php?func=detail&aid=2036798&group_id=93841&atid=605738 * Try to detect this bug and use an ELinks-specific error * code instead, so that we can display a message anyway. */ errno = 0; ses = fsp_open_session(host, port, password); if (!ses) { if (errno) fsp_error(connection_state_for_errno(errno)); else fsp_error(connection_state(S_FSP_OPEN_SESSION_UNKN)); } /* fsplib 0.8 ABI depends on _FILE_OFFSET_BITS * https://sourceforge.net/tracker/index.php?func=detail&aid=1674729&group_id=93841&atid=605738 * If ELinks and fsplib are using different values of * _FILE_OFFSET_BITS, then they get different definitions of * struct stat, and the st_size stored by fsp_stat is * typically not the same as the st_size read by ELinks. * Fortunately, st_mode seems to have the same offset and size * in both versions of struct stat. * * If all the bytes used by the 32-bit st_size are also used * by the 64-bit st_size, then ELinks may be able to guess * which ones they are, because the current version 2 of FSP * supports only 32-bit file sizes in protocol packets. Begin * by filling struct stat with 0xAA so that it's easier to * detect which bytes fsp_stat has left unchanged. (Only * sb.st_size really needs to be filled, but filling the rest * too helps viewing the data with a debugger.) */ memset(&sb, 0xAA, sizeof(sb)); if (fsp_stat(ses, data, &sb)) fsp_error(connection_state_for_errno(errno)); if (S_ISDIR(sb.st_mode)) { fsp_directory(ses, uri); } else { /* regular file */ char buf[READ_SIZE]; FSP_FILE *file = fsp_fopen(ses, data, "r"); int r; if (!file) { fsp_error(connection_state_for_errno(errno)); } #if SIZEOF_OFF_T >= 8 if (sb.st_size < 0 || sb.st_size > 0xFFFFFFFF) { /* Probably a _FILE_OFFSET_BITS mismatch as * described above. Try to detect which half * of st_size is the real size. This may * depend on the endianness of the processor * and on the padding in struct stat. */ if ((sb.st_size & 0xFFFFFFFF00000000ULL) == 0xAAAAAAAA00000000ULL) sb.st_size = sb.st_size & 0xFFFFFFFF; else if ((sb.st_size & 0xFFFFFFFF) == 0xAAAAAAAA) sb.st_size = (sb.st_size >> 32) & 0xFFFFFFFF; else /* Can't figure it out. */ sb.st_size = 1; } #endif /* Send filesize */ fprintf(stderr, "%" OFF_PRINT_FORMAT "\n", (off_print_T) sb.st_size); fclose(stderr); while ((r = fsp_fread(buf, 1, READ_SIZE, file)) > 0) { int off = 0; while (r) { int w = safe_write(STDOUT_FILENO, buf + off, r); if (w == -1) goto out; off += w; r -= w; } } out: fsp_fclose(file); fsp_close_session(ses); exit(0); }