Ejemplo n.º 1
0
static void do_retr(session_t *sess)
{
	if(get_transfer_fd(sess) == 0)
                return;
	
	int fd = open(sess->arg, O_RDONLY);
	if(fd == -1)
	{
		ftp_reply(sess, FTP_FILEFAIL, "1Failed to open file.");
		return;
	}

	int ret;
	ret = lock_file_read(fd);	
	if(ret == -1)
	{
		ftp_reply(sess, FTP_FILEFAIL, "Failed to open file.");
                return;		
	}

	//device file can not be downloaded
	struct stat sbuf;
	ret = fstat(fd, &sbuf);
	if(!S_ISREG(sbuf.st_mode))
	{
		ftp_reply(sess, FTP_FILEFAIL, "Failed to open file.");
                return;
	}
	
	long long offset = sess->restart_pos;
        sess->restart_pos = 0;

	if(offset != 0)
	{
		ret = lseek(fd, offset, SEEK_SET);
		if(ret == -1)
		{
			ftp_reply(sess, FTP_FILEFAIL, "Failed to open file.");
	                return;
		}
	}

	char text[1024] = {0};
	if(sess->is_ascii)
	{
		sprintf(text, "Opening ASCII mode data conection for %s (%lld bytes).",
                sess->arg, (long long)sbuf.st_size);
	}
	else
	{
		sprintf(text, "Opening BINARY mode data conection for %s (%lld bytes).",
		sess->arg, (long long)sbuf.st_size);
	}	

        ftp_reply(sess, FTP_DATACONN, text);

	int flag = 0;
	long long bytes_to_send = sbuf.st_size;

	if(offset > bytes_to_send)
		bytes_to_send = 0;
	else
		bytes_to_send -= offset;

	sess->bw_transfer_start_sec = get_time_sec();
	sess->bw_transfer_start_usec = get_time_usec();

	while(bytes_to_send)
	{
		int num_this_time = bytes_to_send > 65536 ? 65536 : bytes_to_send;
		ret = sendfile(sess->data_fd, fd, NULL, num_this_time);
		if(ret == -1)
		{
			flag = 2;
			break;
		}
		
		limit_rate(sess, ret, 0);
		if(sess->abor_received)
		{
			flag = 2;
			break;
		}	

		bytes_to_send -= ret;
	}

        close(sess->data_fd);
        sess->data_fd = -1;
	close(fd);

	if(flag == 0)
        	ftp_reply(sess, FTP_TRANSFEROK, "Transfer complete.");

	else if(flag == 1)
		ftp_reply(sess, FTP_BADSENDFILE, "Failure reading from local file.");

	else if(flag == 2)
		ftp_reply(sess, FTP_BADSENDNET, "Failure writing to network stream.");

	check_abor(sess);
	start_cmdio_alarm();
}
Ejemplo n.º 2
0
void do_cmd_retr(session_t *pses)
{
    //创建数据连接
    if(get_transfer_fd(pses) < 0)
        return;

    long long offset = 0;
    if(pses->restart_pos > 0)   //是否需要断点续传
    {
        offset = pses->restart_pos;
        pses->restart_pos = 0;
    }
    //打开文件
    int fd = open(pses->arg, O_RDONLY);
    if(fd < 0)
    {
        ftp_reply(pses->ctrl_fd, FTP_FILEFAIL, "Failed to open file.");
        return;
    }
    //给文件加读锁
    int iret = lock_file_read(fd);
    if(iret == -1)
    {
        ftp_reply(pses->ctrl_fd, FTP_FILEFAIL, "Failed to open file.");
        return;
    }
    //判定文件属性是否是普通文件
    struct stat sbuf;
    iret = fstat(fd, &sbuf);
    if(!S_ISREG(sbuf.st_mode))
    {
        ftp_reply(pses->ctrl_fd, FTP_FILEFAIL, "Failed to open file.");
        return;
    }

    //定位到断点
    if(offset > 0)
    {
        iret = lseek(fd, offset, SEEK_SET);
        if(iret < 0)
        {
            ftp_reply(pses->ctrl_fd, FTP_FILEFAIL, "Failed to open file.");
            return;
        }
    }
    //150 应答
    char sendbuf[1024] = {0};
    if(pses->is_ascii)
    {
        sprintf(sendbuf, "Opening ASCII mode data connection for %s (%lld bytes).",
                pses->arg, (long long)sbuf.st_size);
    }
    else
    {
        sprintf(sendbuf, "Opening BINARY mode data connection for %s (%lld bytes).",
                pses->arg, (long long)sbuf.st_size);
    }
    ftp_reply(pses->ctrl_fd, FTP_DATACONN, sendbuf);

    //传输文件
    int flag = 0;
    long long bytes_to_send = sbuf.st_size;
    if(offset > bytes_to_send)      //客户端发来的断点位置超过了文件长度
    {
        bytes_to_send = 0;
    }
    else
    {
        bytes_to_send -= offset;
    }
    //发送数据
    while(bytes_to_send > 0)
    {
        int num_this_time = bytes_to_send > 4096 ? 4096 : bytes_to_send;
        iret = sendfile64(pses->data_fd, fd, NULL, num_this_time);
        if(iret < 0)
        {
            flag = -2;
            break;
        }
        bytes_to_send -= iret;
    }
    //发送成功
    if(bytes_to_send == 0)
    {
        flag = 0;
    }
    //关闭数据套接字
    close(pses->data_fd);
    pses->data_fd = -1;

    //关闭文件
    unlock_file(fd);
    close(fd);

    if(flag == 0)
    {
        //226
        ftp_reply(pses->ctrl_fd, FTP_TRANSFEROK, "Transfer complete.");
    }
    else if(flag == -2)
    {
        //451
        ftp_reply(pses->ctrl_fd, FTP_BADSENDNET, "Failure writting to network stream.");
    }
}