int main(void) { int filefd; int filefd_out; loff_t off = 0; filefd = open(token_file, O_RDWR | O_CREAT | O_TRUNC, 0600); filefd_out = open(token_file, O_RDWR | O_CREAT | O_TRUNC, 0600); write(filefd, TOKEN, TOKEN_SIZE); sendfile64(filefd_out, filefd, &off, TOKEN_SIZE); atomic_printf( "sendfile %zu bytes from %d to %d; off changed from 0 to %" PRId64 "\n", TOKEN_SIZE, filefd, filefd_out, off); lseek(filefd_out, 0, SEEK_SET); verify_token(filefd_out); lseek(filefd, 0, SEEK_SET); sendfile64(filefd_out, filefd, NULL, TOKEN_SIZE); atomic_printf("sendfile %zu bytes from %d to %d\n", TOKEN_SIZE, filefd, filefd_out); lseek(filefd_out, 0, SEEK_SET); verify_token(filefd_out); /* The test driver will clean up after us if the test failed * before this. */ unlink(token_file); unlink(token_file_out); atomic_puts("EXIT-SUCCESS"); return 0; }
/* Send COUNT bytes from file associated with IN_FD starting at OFFSET to descriptor OUT_FD. */ ssize_t sendfile (int out_fd, int in_fd, off_t *offset, size_t count) { if (offset == NULL || sizeof (off_t) == sizeof (off64_t)) return sendfile64 (out_fd, in_fd, (off64_t *) offset, count); else { off64_t ofs = *offset; ssize_t ret = sendfile64 (out_fd, in_fd, &ofs, count); *offset = ofs; return ret; } }
static int send_buffer( off64_t offset, size_t count, int fd, long long *total) { off64_t off = offset; ssize_t bytes, bytes_remaining = count; int ops = 0; *total = 0; while (count > 0) { bytes = sendfile64(file->fd, fd, &off, bytes_remaining); if (bytes == 0) break; if (bytes < 0) { perror("sendfile64"); return -1; } ops++; *total += bytes; if (bytes >= bytes_remaining) break; bytes_remaining -= bytes; } return ops; }
ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count) { size_t total=0; ssize_t ret; size_t hdr_len = 0; /* * Send the header first. * Use MSG_MORE to cork the TCP output until sendfile is called. */ if (header) { hdr_len = header->length; while (total < hdr_len) { ret = sys_send(tofd, header->data + total,hdr_len - total, MSG_MORE); if (ret == -1) return -1; total += ret; } } total = count; while (total) { ssize_t nwritten; do { #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILE64) nwritten = sendfile64(tofd, fromfd, &offset, total); #else nwritten = sendfile(tofd, fromfd, &offset, total); #endif } while (nwritten == -1 && errno == EINTR); if (nwritten == -1) { if (errno == ENOSYS || errno == EINVAL) { /* Ok - we're in a world of pain here. We just sent * the header, but the sendfile failed. We have to * emulate the sendfile at an upper layer before we * disable it's use. So we do something really ugly. * We set the errno to a strange value so we can detect * this at the upper level and take care of it without * layer violation. JRA. */ errno = EINTR; /* Normally we can never return this. */ } return -1; } if (nwritten == 0) return -1; /* I think we're at EOF here... */ total -= nwritten; } return count + hdr_len; }
TEST(sys_sendfile, sendfile64) { TemporaryFile src_file; ASSERT_EQ(5, TEMP_FAILURE_RETRY(write(src_file.fd, "hello", 5))); TemporaryFile dst_file; off64_t offset = 2; size_t count = 2; ssize_t rc = sendfile64(dst_file.fd, src_file.fd, &offset, count); ASSERT_EQ(2, rc); ASSERT_EQ(4, offset); ASSERT_EQ(0, lseek(dst_file.fd, 0, SEEK_SET)); char buf[3]; buf[2] = '\0'; ASSERT_EQ(2, TEMP_FAILURE_RETRY(read(dst_file.fd, &buf, 2))); ASSERT_STREQ("ll", buf); }
ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count) { size_t total=0; ssize_t ret; size_t hdr_len = 0; /* * Send the header first. * Use MSG_MORE to cork the TCP output until sendfile is called. */ if (header) { hdr_len = header->length; while (total < hdr_len) { ret = sys_send(tofd, header->data + total,hdr_len - total, MSG_MORE); if (ret == -1) return -1; total += ret; } } total = count; while (total) { ssize_t nwritten; do { #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILE64) nwritten = sendfile64(tofd, fromfd, &offset, total); #else nwritten = sendfile(tofd, fromfd, &offset, total); #endif } while (nwritten == -1 && errno == EINTR); if (nwritten == -1) return -1; if (nwritten == 0) return -1; /* I think we're at EOF here... */ total -= nwritten; } return count + hdr_len; }
ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count) { size_t total=0; struct iovec hdtrl[2]; size_t hdr_len = 0; if (header) { /* Set up the header/trailer iovec. */ hdtrl[0].iov_base = header->data; hdtrl[0].iov_len = hdr_len = header->length; } else { hdtrl[0].iov_base = NULL; hdtrl[0].iov_len = hdr_len = 0; } hdtrl[1].iov_base = NULL; hdtrl[1].iov_base = 0; total = count; while (total + hdtrl[0].iov_len) { ssize_t nwritten; /* * HPUX guarantees that if any data was written before * a signal interrupt then sendfile returns the number of * bytes written (which may be less than requested) not -1. * nwritten includes the header data sent. */ do { #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILE64) nwritten = sendfile64(tofd, fromfd, offset, total, &hdtrl[0], 0); #else nwritten = sendfile(tofd, fromfd, offset, total, &hdtrl[0], 0); #endif } while (nwritten == -1 && errno == EINTR); if (nwritten == -1) return -1; if (nwritten == 0) return -1; /* I think we're at EOF here... */ /* * If this was a short (signal interrupted) write we may need * to subtract it from the header data, or null out the header * data altogether if we wrote more than hdtrl[0].iov_len bytes. * We change nwritten to be the number of file bytes written. */ if (hdtrl[0].iov_base && hdtrl[0].iov_len) { if (nwritten >= hdtrl[0].iov_len) { nwritten -= hdtrl[0].iov_len; hdtrl[0].iov_base = NULL; hdtrl[0].iov_len = 0; } else { /* iov_base is defined as a void *... */ hdtrl[0].iov_base = ((char *)hdtrl[0].iov_base) + nwritten; hdtrl[0].iov_len -= nwritten; nwritten = 0; } } total -= nwritten; offset += nwritten; } return count + hdr_len; }
bool CClientThread::ProcessPacket(CRData *data) { uchar id; if( data->getUChar(&id)==true ) { switch(id) { case ID_GET_GAMELIST: { #ifdef CHECK_IDENT std::string ident; data->getStr(&ident); if(!FileServ::checkIdentity(ident)) { Log("Identity check failed -1", LL_DEBUG); return false; } #endif hFile=0; std::vector<std::wstring> games=get_maps(); Log("Sending game list", LL_DEBUG); EnableNagle(); CWData data; data.addUChar( ID_GAMELIST ); data.addUInt( (unsigned int)games.size() ); stack.Send(clientpipe, data); for(size_t i=0;i<games.size();++i) { std::string version; std::wstring udir; version=getFile(wnarrow(map_file(games[i]+L"\\version.uri",true,&udir))); if( udir!=L"" ) games[i]+=L"|"+udir; std::string game=Server->ConvertToUTF8(games[i]); stack.Send(clientpipe, (char*)game.c_str(), game.size() ); stack.Send(clientpipe, (char*)version.c_str(), version.size() ); } Log("done.", LL_DEBUG); DisableNagle(); }break; case ID_GET_FILE_RESUME: case ID_GET_FILE: case ID_GET_FILE_RESUME_HASH: { std::string s_filename; if(data->getStr(&s_filename)==false) break; #ifdef CHECK_IDENT std::string ident; data->getStr(&ident); if(!FileServ::checkIdentity(ident)) { Log("Identity check failed -2", LL_DEBUG); return false; } #endif std::wstring o_filename=Server->ConvertToUnicode(s_filename); _i64 start_offset=0; bool offset_set=data->getInt64(&start_offset); Log("Sending file "+Server->ConvertToUTF8(o_filename), LL_DEBUG); std::wstring filename=map_file(o_filename); Log("Mapped name: "+Server->ConvertToUTF8(filename), LL_DEBUG); if(filename.empty()) { char ch=ID_BASE_DIR_LOST; int rc=SendInt(&ch, 1); if(rc==SOCKET_ERROR) { Log("Error: Socket Error - DBG: Send BASE_DIR_LOST -1", LL_DEBUG); return false; } Log("Info: Base dir lost -1", LL_DEBUG); break; } cmd_id=id; if( id==ID_GET_FILE_RESUME_HASH ) { hash_func.init(); } #ifdef _WIN32 if(filename.size()<2 || (filename[0]!='\\' && filename[1]!='\\' ) ) { filename=L"\\\\?\\"+filename; } if(bufmgr==NULL) { bufmgr=new CBufMgr(NBUFFERS,READSIZE); } #endif #ifndef LINUX #ifndef BACKUP_SEM hFile=CreateFileW(filename.c_str(), FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED|FILE_FLAG_SEQUENTIAL_SCAN, NULL); #else hFile=CreateFileW(filename.c_str(), FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED|FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_SEQUENTIAL_SCAN, NULL); #endif if(hFile == INVALID_HANDLE_VALUE) { hFile=NULL; #ifdef CHECK_BASE_PATH std::wstring basePath=map_file(getuntil(L"/",o_filename)+L"/"); if(!isDirectory(basePath)) { char ch=ID_BASE_DIR_LOST; int rc=SendInt(&ch, 1); if(rc==SOCKET_ERROR) { Log("Error: Socket Error - DBG: Send BASE_DIR_LOST", LL_DEBUG); return false; } Log("Info: Base dir lost", LL_DEBUG); break; } #endif char ch=ID_COULDNT_OPEN; int rc=SendInt(&ch, 1); if(rc==SOCKET_ERROR) { Log("Error: Socket Error - DBG: Send COULDNT OPEN", LL_DEBUG); return false; } Log("Info: Couldn't open file", LL_DEBUG); break; } currfilepart=0; sendfilepart=0; sent_bytes=start_offset; LARGE_INTEGER filesize; GetFileSizeEx(hFile, &filesize); curr_filesize=filesize.QuadPart; next_checkpoint=start_offset+c_checkpoint_dist; if(next_checkpoint>curr_filesize) next_checkpoint=curr_filesize; if( offset_set==false || id==ID_GET_FILE_RESUME || id==ID_GET_FILE_RESUME_HASH ) { CWData data; data.addUChar(ID_FILESIZE); data.addUInt64(filesize.QuadPart); int rc=SendInt(data.getDataPtr(), data.getDataSize()); if(rc==SOCKET_ERROR) { Log("Error: Socket Error - DBG: SendSize", LL_DEBUG); CloseHandle(hFile); hFile=NULL; return false; } } if(filesize.QuadPart==0) { CloseHandle(hFile); hFile=NULL; break; } for(_i64 i=start_offset;i<filesize.QuadPart && stopped==false;i+=READSIZE) { bool last; if(i+READSIZE<filesize.QuadPart) last=false; else { last=true; Log("Reading last file part", LL_DEBUG); } while(bufmgr->nfreeBufffer()==0 && stopped==false) { int rc; SleepEx(0,true); rc=SendData(); if(rc==-1) { Log("Error: Send failed in file loop -1", LL_DEBUG); CloseThread(hFile); } else if(rc==0) SleepEx(1,true); } if( stopped==false ) ReadFilePart(hFile, i, last); if(FileServ::isPause() ) { DWORD starttime=GetTickCount(); while(GetTickCount()-starttime<5000) { SleepEx(500,true); int rc=SendData(); if(rc==-1) { Log("Error: Send failed in file pause loop -2", LL_DEBUG); CloseThread(hFile); } } } } while(bufmgr->nfreeBufffer()!=NBUFFERS && stopped==false) { SleepEx(0,true); int rc; rc=SendData(); if( rc==2 && bufmgr->nfreeBufffer()!=NBUFFERS ) { Log("Error: File end and not all Buffers are free!-1", LL_WARNING); } if(rc==-1) { Log("Error: Send failed in off file loop -3", LL_DEBUG); CloseHandle(hFile); hFile=NULL; break; } else if(rc==0) SleepEx(1,true); } if( stopped==false ) { Log("Closed file.", LL_DEBUG); CloseHandle(hFile); hFile=NULL; } #else //LINUX hFile=open64(Server->ConvertToUTF8(filename).c_str(), O_RDONLY|O_LARGEFILE); if(hFile == INVALID_HANDLE_VALUE) { #ifdef CHECK_BASE_PATH std::wstring basePath=map_file(getuntil(L"/",o_filename)+L"/"); if(!isDirectory(basePath)) { char ch=ID_BASE_DIR_LOST; int rc=SendInt(&ch, 1); if(rc==SOCKET_ERROR) { Log("Error: Socket Error - DBG: Send BASE_DIR_LOST", LL_DEBUG); return false; } Log("Info: Base dir lost", LL_DEBUG); break; } #endif hFile=0; char ch=ID_COULDNT_OPEN; int rc=SendInt(&ch, 1); if(rc==SOCKET_ERROR) { Log("Error: Socket Error - DBG: Send COULDNT OPEN", LL_DEBUG); return false; } Log("Info: Couldn't open file", LL_DEBUG); break; } currfilepart=0; sendfilepart=0; struct stat64 stat_buf; fstat64(hFile, &stat_buf); off64_t filesize=stat_buf.st_size; curr_filesize=filesize; if( offset_set==false || id==ID_GET_FILE_RESUME || id==ID_GET_FILE_RESUME_HASH ) { CWData data; data.addUChar(ID_FILESIZE); data.addUInt64(filesize); int rc=SendInt(data.getDataPtr(), data.getDataSize() ); if(rc==SOCKET_ERROR) { Log("Error: Socket Error - DBG: SendSize", LL_DEBUG); CloseHandle(hFile); hFile=0; return false; } } if(filesize==0) { CloseHandle(hFile); hFile=0; break; } off64_t foffset=start_offset; unsigned int s_bsize=8192; if(id==ID_GET_FILE || id==ID_GET_FILE_RESUME ) { s_bsize=32768; next_checkpoint=curr_filesize; } else { next_checkpoint=start_offset+c_checkpoint_dist; if(next_checkpoint>curr_filesize) next_checkpoint=curr_filesize; } char *buf=new char[s_bsize]; bool has_error=false; while( foffset < filesize ) { size_t count=(std::min)((size_t)s_bsize, (size_t)(next_checkpoint-foffset)); if( clientpipe==NULL && ( id==ID_GET_FILE || id==ID_GET_FILE_RESUME ) ) { ssize_t rc=sendfile64(int_socket, hFile, &foffset, count); if(rc>0) { foffset+=rc; } else { Log("Error: Reading and sending from file failed", LL_DEBUG); CloseHandle(hFile); delete []buf; return false; } } else { ssize_t rc=read(hFile, buf, count); if(rc>0) { rc=SendInt(buf, rc); if(rc==SOCKET_ERROR) { Log("Error: Sending data failed"); CloseHandle(hFile); delete []buf; return false; } else if(id==ID_GET_FILE_RESUME_HASH) { hash_func.update((unsigned char*)buf, rc); } foffset+=rc; } else { Log("Error: Reading from file failed", LL_DEBUG); CloseHandle(hFile); delete []buf; return false; } if(id==ID_GET_FILE_RESUME_HASH && foffset==next_checkpoint) { hash_func.finalize(); SendInt((char*)hash_func.raw_digest_int(), 16); next_checkpoint+=c_checkpoint_dist; if(next_checkpoint>curr_filesize) next_checkpoint=curr_filesize; hash_func.init(); } } if(FileServ::isPause() ) { Sleep(500); } } CloseHandle(hFile); delete []buf; hFile=0; #endif }break; case ID_GET_FILE_BLOCKDIFF: { bool b=GetFileBlockdiff(data); if(!b) return false; }break; case ID_BLOCK_REQUEST: { if(state==CS_BLOCKHASH) { Handle_ID_BLOCK_REQUEST(data); } }break; } } if( stopped==true ) return false; else return true; }
static void do_send(int fd) { LOG(glogfd, LOG_TRACE, "%s:%s:%d\n", ID, FUNC, LN); int ret = SEND_ADD_EPOLLIN; int n = 0; struct conn *curcon = &acon[fd]; if (curcon->fd < 0) { LOG(glogfd, LOG_DEBUG, "fd %d already be closed %s\n", fd, FUNC); return; } int localfd; off_t start; char* data; size_t len; if(!mybuff_getdata(&(curcon->send_buff), &data, &len)) { LOG(glogfd, LOG_TRACE, "fd[%d] get len from data [%d]\n", fd, len); while (1) { n = send(fd, data, len, MSG_DONTWAIT | MSG_NOSIGNAL); if(n > 0) { LOG(glogfd, LOG_NORMAL, "fd[%d] send len %d, datalen %d\n", fd, n, len); mybuff_skipdata(&(curcon->send_buff), n); if (n < len) ret = SEND_ADD_EPOLLOUT; curcon->send_len += n; } else if(errno == EINTR) continue; else if(errno == EAGAIN) ret = SEND_ADD_EPOLLOUT; else { LOG(glogfd, LOG_ERROR, "%s:%s:%d fd[%d] send err %d:%d:%m\n", ID, FUNC, LN, fd, n, len); ret = SEND_CLOSE; } break; } } if(ret == SEND_ADD_EPOLLIN && !mybuff_getfile(&(curcon->send_buff), &localfd, &start, &len)) { LOG(glogfd, LOG_TRACE, "fd[%d] get len from file [%d]\n", fd, len); size_t len1 = len > GSIZE ? GSIZE : len; while (1) { n = sendfile64(fd, localfd, &start, len1); if(n > 0) { mybuff_skipfile(&(curcon->send_buff), n); LOG(glogfd, LOG_TRACE, "%s:%s:%d fd[%d] send len %d, datalen %d\n", ID, FUNC, LN, fd, n, len1); if(n < len) ret = SEND_ADD_EPOLLOUT; curcon->send_len += n; } else if(errno == EINTR) continue; else if(errno == EAGAIN || errno == ENOENT) ret = SEND_ADD_EPOLLOUT; else { LOG(glogfd, LOG_ERROR, "%s:%s:%d fd[%d] send err %d:%d:%m\n", ID, FUNC, LN, fd, n, len); ret = SEND_CLOSE; } break; } } switch (ret) { case SEND_CLOSE: do_close(fd); return; case SEND_ADD_EPOLLIN: modify_fd_event(fd, EPOLLIN); break; case SEND_ADD_EPOLLOUT: modify_fd_event(fd, EPOLLOUT); break; case SEND_ADD_EPOLLALL: modify_fd_event(fd, EPOLLOUT|EPOLLIN); break; } if (n > 0 && solib.svc_send_once) solib.svc_send_once(fd); if (ret == SEND_ADD_EPOLLIN && solib.svc_send) if (solib.svc_send(fd) == SEND_CLOSE) { LOG(glogfd, LOG_ERROR, "%s:%s:%d send close\n", ID, FUNC, LN); do_close(fd); } }
/*! * \brief Copy data as avoid overwriting. * \param sourceFile [in] Path of source file. * \param destPath [in] Path of directory put duplicated file. * \param destName [in] Name of duplicated file.<br> * Don't rename, if value is null. * \return Value is zero, if process is succeed.<br /> * Value is error number a.k.a. "errno", if process is failure. */ int copyFile(char const *sourceFile, char const *destPath, char const *destName) { char rpath[PATH_MAX]; if (unlikely(!isCopiablePath(sourceFile, rpath))) { return EINVAL; } int result = 0; /* Make file name. */ char *newFile = destName == NULL ? createFilename(destPath, (char *)sourceFile) : createFilename(destPath, (char *)destName); /* Failure make filename. */ if (unlikely(newFile == NULL)) { logger->printWarnMsg("Couldn't allocate copy source file path."); /* * Because exist below two pattern when "createFilename" return NULL. * 1, Illegal argument. "errno" don't change. * 2, No usable memory. "errno" maybe "ENOMEM". */ return (errno != 0) ? errno : EINVAL; } /* Get uniq file name. */ char *destFile = createUniquePath(newFile, false); if (unlikely(destFile == NULL)) { logger->printWarnMsg("Couldn't allocate unique destination file name."); free(newFile); return ENOMEM; } /* Open copy source file. */ int sourceFd = open(sourceFile, O_RDONLY); if (unlikely(sourceFd < 0)) { result = errno; logger->printWarnMsgWithErrno("Couldn't open copy source file."); free(newFile); free(destFile); return result; } /* Get source file size */ struct stat st; if (unlikely(fstat(sourceFd, &st) != 0)) { result = errno; logger->printWarnMsgWithErrno("Couldn't open copy destination file."); free(newFile); free(destFile); close(sourceFd); return result; } /* Open destination file. */ int destFd = open(destFile, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR); if (unlikely(destFd < 0)) { result = errno; logger->printWarnMsgWithErrno("Couldn't open copy destination file."); free(newFile); free(destFile); close(sourceFd); return result; } /* Copy data */ if (st.st_size > 0) { if (unlikely(sendfile64(destFd, sourceFd, NULL, st.st_size) == -1)) { result = errno; logger->printWarnMsgWithErrno("Couldn't copy file."); } } else { /* This route is for files in procfs */ char buf[1024]; ssize_t read_size; while ((read_size = read(sourceFd, buf, 1024)) > 0) { if (write(destFd, buf, (size_t)read_size) == -1) { read_size = -1; break; } } if (read_size == -1) { result = errno; logger->printWarnMsgWithErrno("Couldn't copy file."); } } /* Clean up */ close(sourceFd); if (unlikely((close(destFd) != 0) && (result == 0))) { result = errno; logger->printWarnMsgWithErrno("Couldn't write copy file data."); } free(newFile); free(destFile); return result; }
bool TCPSocket::writeFile(const char* filename, int64_t off_end, int64_t off_beg) { #if defined(DUNE_OS_LINUX) int fd = open64(filename, O_RDONLY); if (fd == -1) return false; int64_t remaining = off_end; off64_t offset = 0; if (off_beg > 0) { offset = off_beg; remaining -= off_beg; } while (remaining >= 0) { ssize_t rv = sendfile64(m_handle, fd, &offset, c_block_size); if (rv == -1) { close(fd); return false; } remaining -= rv; Concurrency::Scheduler::yield(); } close(fd); return true; #else std::ifstream ifs(filename, std::ios::binary); int64_t remaining = off_end; if (off_beg > 0) { ifs.seekg(off_beg, std::ios::beg); if (ifs.fail()) return false; remaining -= off_beg; } char bfr[c_block_size]; int64_t rv = 0; while (remaining >= 0) { ifs.read(bfr, c_block_size); rv = write(bfr, ifs.gcount()); if (rv == -1) return false; remaining -= rv; } return true; #endif }
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."); } }