Пример #1
0
static void do_nlst(session_t *sess)
{
	if(get_transfer_fd(sess) == 0)
                return;

        ftp_reply(sess, FTP_DATACONN, "Here comes the directory listing.");

        list_common(sess, 0);
        close(sess->data_fd);
        sess->data_fd = -1;

        ftp_reply(sess, FTP_TRANSFEROK, "Directory send OK.");
}
Пример #2
0
//获取目录详细清单
void do_cmd_list(session_t *pses)
{
    //创建数据连接
    if(get_transfer_fd(pses) < 0)
        return;
    //150
    ftp_reply(pses->ctrl_fd, FTP_DATACONN, "Here comes the directory listing.");
    //传输列表
    getdirlist(pses,1);
    //关闭数据套接字
    close(pses->data_fd);
    pses->data_fd = -1;
    //226
    ftp_reply(pses->ctrl_fd, FTP_TRANSFEROK, "Directory send OK.");
}
Пример #3
0
static void do_list(session_t *sess)
{
	if(get_transfer_fd(sess) == 0)
		return;

	ftp_reply(sess, FTP_DATACONN, "Here comes the directory listing.");

	//transfer list	
	list_common(sess, 1);

	//client will still wait the data from server if the fd do not closed
	close(sess->data_fd);
	sess->data_fd = -1;

	ftp_reply(sess, FTP_TRANSFEROK, "Directory send OK.");
}
Пример #4
0
/**
 *do_nlst - 处理列出目录列表命令,可用windows登录,命令短清单
 *@sess:会话结构体
 */
void ftpproto::do_nlst(session_t* sess)
{
	//创建数据连接,主动用connect,被动用accept
	if (get_transfer_fd(sess))//连接失败
	{
		LCWFTPD_LOG(DEBUG,"get_transfer_fd(sess)");
		 return;
	}
	//150响应
	ftp_reply(sess,FTP_DATACONN,"Here comes the directory listing.");
	//传输列表
	list_common(sess,0);//0表示短清单
	//关闭数据链接套接字,客户端貌似是通过判断套接字关闭从而判断数据是否接收完毕
	close(sess->data_fd);
	sess->data_fd = -1;
	//226响应
	ftp_reply(sess,FTP_TRANSFEROK,"Directory send OK.");
}
Пример #5
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();
}
Пример #6
0
void upload_common(session_t* sess, int is_append)
{
	if(get_transfer_fd(sess) == 0)
                return;

        int fd = open(sess->arg, O_CREAT | O_WRONLY, 0666);
        if(fd == -1)
        {
                ftp_reply(sess, FTP_UPLOADFAIL, "Could not creat file.");
                return;
        }

        int ret = 0;
	ret = lock_file_write(fd);

        if(ret == -1)
        {
                ftp_reply(sess, FTP_UPLOADFAIL, "Could not creat file.");
                return;
        }

	long long offset = sess->restart_pos;	
	sess->restart_pos = 0;

	if(!is_append && offset == 0)   //STOR
	{
		ftruncate(fd, 0);
		if(lseek(fd, 0, SEEK_SET) < 0)
		{
			ftp_reply(sess, FTP_UPLOADFAIL, "Could not creat file.");
                	return;
		}
	}

	else if(!is_append && offset != 0)  //REST + STOR
	{
		if(lseek(fd, offset, SEEK_SET) < 0)
		{
			ftp_reply(sess, FTP_UPLOADFAIL, "Could not creat file.");
                        return;
		}
	}

	else if(is_append)
	{
		if(lseek(fd, 0, SEEK_END) < 0)
		{
			ftp_reply(sess, FTP_UPLOADFAIL, "Could not creat file.");
                        return;
		}
	}
	
	struct stat sbuf;
        fstat(fd, &sbuf);

	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;
	char buf[65536] = {0};

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

	while(1)
	{
		ret = read(sess->data_fd, buf, sizeof(buf));
		if(ret == -1)
		{
			if(errno == EINTR)
				continue;
			
			flag = 2;
			break;
		}
		
		else if(ret == 0)
		{
			flag = 0;
			break;
		}

		limit_rate(sess, ret, 1);

		if(sess->abor_received)	
		{
			flag = 2;	
			break;
		}

		if(writen(fd, buf, ret) != ret)
		{
			flag = 1;
			break;
		}	
	}	

	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 to write file.");
	
	else if(flag == 2)
		ftp_reply(sess, FTP_BADSENDNET, "Failure read from network stream.");

	check_abor(sess);
	start_cmdio_alarm();
}
Пример #7
0
/**
 *upload_common - 上传文件
 *@sess:会话结构体
 *@is_append:是否以appe方式上传,0表示STOR方式,1表示APPE方式
 */
void ftpproto::upload_common(session_t* sess,int is_append)
{
	//创建数据连接,主动用connect,被动用accept
	if (get_transfer_fd(sess))//连接失败
	{
		 LCWFTPD_LOG(DEBUG,"get_transfer_fd(sess)");
		 return;
	}
	//保存断点,REST命令保存断点
	long long offset = sess->restart_pos;
	sess->restart_pos = 0;//断点置为0
	//以创建,只写的方式打开文件,权限默认0666,实际的权限时0666 & umask
	int fd = open(sess->arg,O_CREAT | O_WRONLY ,0666);//以只读方式打开文件
	LCWFTPD_LOG(DEBUG,"file name:%s",sess->arg);//文件名是有带路径的
	if (-1 == fd)
	{
		//创建失败
		ftp_reply(sess,FTP_UPLOADFAIL,"Could not cteate file.");
		return;
	}
	int ret;
	//加写锁
	ret = lcw_systools.lock_file_write(fd);
	if (-1 ==ret)
	{
		ftp_reply(sess,FTP_UPLOADFAIL,"Could not cteate file.");
		return;
	}
	//查看下是什么方式上传
	if (!is_append && offset == 0)//STOR上传
	{
		//把原来文件的长度清零
		ftruncate(fd,0);
		if (lseek(fd,0,SEEK_SET) < 0)//文件定位到文件头的位置
		{
			ftp_reply(sess,FTP_UPLOADFAIL,"Could not cteate file.");
			return;
		} 
	}
	else if (!is_append && offset != 0)//REST+STOR 断点续传
	{
		if (lseek(fd,offset,SEEK_SET) < 0)//将读写位置指向文件头后再增加offset个位移量
		{
			ftp_reply(sess,FTP_UPLOADFAIL,"Could not cteate file.");
			return;
		}
	}
	else if (is_append)//APPE 断点续传
	{//将读写位置指向文件尾后再增加offset个位移量
		if (lseek(fd,0,SEEK_END) < 0)//偏移到文件末尾
		{
			ftp_reply(sess,FTP_UPLOADFAIL,"Could not cteate file.");
			return;
		}
	}
	//获取文件状态
	struct stat sbuf;
	ret = fstat(fd,&sbuf);//将文件状态保存在sbuf中
	if (!S_ISREG(sbuf.st_mode))
	{//不是一个普通文件
		ftp_reply(sess,FTP_UPLOADFAIL,"Could not create file.");
		return;
	}

	char text[1024] = {0};
	if (sess->is_ascii)//TYPE A
	{
		 //ASCII码模式(实际上我们这里都是以二进制方式进行传输)
		sprintf(text,"Opening ASCII mode data connection for %s (%lld bytes).",
			 sess->arg,(long long)sbuf.st_size);
	}
	else//TYPE I
	{
		//二进制模式
		sprintf(text,"Opening BINARY mode data connection for %s (%lld bytes).",
			 sess->arg,(long long)sbuf.st_size);
	}

	//150响应
	ftp_reply(sess,FTP_DATACONN,text);
	
	//上传文件
	//这个buf变大的时候传输速度可相应有所提高
	//可提供一个配置项来配置这个65536//64K
	char buf[1024];
	int flag = 0;//标志变量
	while(1)
	{
		ret = read(sess->data_fd,buf,sizeof(buf));//从数据套接字中读取数据到buf
		if (-1 == ret)
		{
			if (errno == EINTR)//被信号中断
			{
				 continue;
			}
			else
			{
				flag = 2;//失败
				break;
			}
		}
		else if (0 == ret)
		{//读取完毕
			 flag = 0;//成功
			 break;
		}
		if (lcw_systools.writen(fd,buf,ret) != ret)//写入文件
		{
			flag = 1;//失败
			break;
		} 
	}
	//关闭数据链接套接字,客户端貌似是通过判断套接字关闭从而判断数据是否接收完毕
	close(sess->data_fd);
	sess->data_fd = -1;
    //关闭文件
    close(fd);
	if (0 == flag)//成功
	{
		//226响应
		ftp_reply(sess,FTP_TRANSFEROK,"Transfer complete.");
	}
	else if (1 == flag)
	{//写入本地失败  451
		 ftp_reply(sess,FTP_BADSENDFILE,"Failure writting to local file.");
	}
	else if (2 == flag)
	{//读取网络失败  426
		ftp_reply(sess,FTP_BADSENDNET,"Failure reading from network stream.");
	}
}
Пример #8
0
/**
 *do_retr -  下载文件,断点续载
 *@sess:会话结构体
 */
void ftpproto::do_retr(session_t* sess)
{
	//创建数据连接,主动用connect,被动用accept
	if (get_transfer_fd(sess))//连接失败
	{//get_transfer_fd里面会开启数据通道的传输闹钟,等下传输结束记得关掉
		 LCWFTPD_LOG(DEBUG,"get_transfer_fd(sess)");
		 return;
	}
	 LCWFTPD_LOG(DEBUG,"data_fd int do_retr:%d",sess->data_fd);
	//保存断点
	long long offset = sess->restart_pos;
	sess->restart_pos = 0;//断点位置为0

	int fd = open(sess->arg,O_RDONLY);//以只读方式打开文件
	if (-1 == fd)
	{
		//打开失败
		ftp_reply(sess,FTP_FILEFAIL,"Failed to open file.");
		return;
	}
	int ret;
	//加读锁
	ret = lcw_systools.lock_file_read(fd);
	if (-1 ==ret)
	{//加锁失败
		ftp_reply(sess,FTP_FILEFAIL,"Failed to open file.");
	}
	//判断是否是普通文件,设备文件是不能下载的
	struct stat sbuf;
	ret = fstat(fd,&sbuf);//将文件状态保存在sbuf中
	if (!S_ISREG(sbuf.st_mode))
	{//不是一个普通文件
		ftp_reply(sess,FTP_FILEFAIL,"Failed to open file.");
		return;
	}
	
	if (offset != 0)//如果有断点
	{
		ret = lseek(fd,offset,SEEK_SET);//定位断点
		if (-1 == ret)
		{
			//定位失败
			ftp_reply(sess,FTP_FILEFAIL,"Failed to lseek");
			return;
		}
	}
	char text[1024] = {0};
	if (sess->is_ascii)//TYPE A
	{
		 //ASCII码模式(实际上我们这里都是以二进制方式进行传输)
		sprintf(text,"Opening ASCII mode data connection for %s (%lld bytes).",
			 sess->arg,(long long)sbuf.st_size);
	}
	else//TYPE I
	{
		//二进制模式
		sprintf(text,"Opening BINARY mode data connection for %s (%lld bytes).",
			 sess->arg,(long long)sbuf.st_size);
	}
	//150响应
	ftp_reply(sess,FTP_DATACONN,text);
	//下载文件
	int flag = 0;//标志变量
	//sendfile直接在内核空间操作,不涉及拷贝,效率较高
	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)
	{
		int num_this_time = bytes_to_send > 4096 ? 4096:bytes_to_send;
		ret = sendfile(sess->data_fd,fd,NULL,num_this_time);//不会返回EINTR,ret是发送成功的字节数
		if (-1 == ret)
		{
			//发送失败
			flag = 2;
			break;
		}
		bytes_to_send -= ret;//更新剩下的字节数
	}

	if (bytes_to_send == 0)
	{
		//发送成功
		flag = 0;
	}
	//关闭数据链接套接字,客户端貌似是通过判断套接字关闭从而判断数据是否接收完毕
	close(sess->data_fd);
	sess->data_fd = -1;
	//关闭文件
    close(fd);
	if (0 == flag)//成功并且没有收到abor
	{
		//226响应
		ftp_reply(sess,FTP_TRANSFEROK,"Transfer complete.");
	}
	else if (1 == flag)
	{//文件读取失败 451
		 ftp_reply(sess,FTP_BADSENDFILE,"Failure reading from local file.");
	}
	else if (2 == flag)
	{//文件发送失败 426
		ftp_reply(sess,FTP_BADSENDNET,"Failure writting to network stream.");
	}
}
Пример #9
0
    //上传文件
int upload_common(session_t *pses, int fd, int is_append)
 {
     int iret;
     //创建数据连接
     if(get_transfer_fd(pses) < 0)
         return -3;

     long long offset = 0;
     if(pses->restart_pos > 0)   //是否需要断点续传
     {
         offset = pses->restart_pos;
         pses->restart_pos = 0;
     }

     //判定文件上传模式
     if(!is_append && (offset == 0))
     {
        //STOR 模式
        ftruncate(fd, 0);
        iret = lseek(fd, 0, SEEK_SET);
        if(iret < 0)
        {
            ftp_reply(pses->ctrl_fd, FTP_UPLOADFAIL, "Could not create file.");
            return -3;
        }
     }
     else if(!is_append && (offset > 0))
     {
         //REST + STOR
         iret = lseek(fd, offset, SEEK_SET);
         if(iret < 0)
         {
             ftp_reply(pses->ctrl_fd, FTP_UPLOADFAIL, "Could not create file.");
             return -3;
         }
     }
     else if(is_append)
     {
        //APPE
         iret = lseek(fd, 0, SEEK_END);
         if(iret < 0)
         {
             ftp_reply(pses->ctrl_fd, FTP_UPLOADFAIL, "Could not create file.");
             return -3;
         }
     }

     //获取文件信息
     struct stat sbuf;
     iret = fstat(fd, &sbuf);
     if(iret < 0)
     {
         printf("fstat error\n");
         return -3;
     }
     //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;
     char recvbuf[1024];
     while(true)
     {
         memset(recvbuf, 0, sizeof(recvbuf));
         iret = readn(pses->data_fd, recvbuf, sizeof(recvbuf));
         if(iret < 0)
         {
             if(errno == EINTR)
             {
                continue;
             }
             else
             {
                 flag = -2;
                 break;
             }
         }
         else if(iret == 0)
         {
             flag = 0;
             break;
         }

         if(writen(fd, recvbuf, sizeof(recvbuf)) != iret)
         {
             flag = -1;
             break;
         }
     }
     return flag;
 }
Пример #10
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.");
    }
}