3744 lines
84 KiB
C++
3744 lines
84 KiB
C++
// SHCSDK.cpp : DLL 응용 프로그램에 대한 진입점을 정의합니다.
|
|
//
|
|
|
|
#ifdef WIN32
|
|
|
|
#include <winsock2.h>
|
|
#include <ws2tcpip.h>
|
|
#include <windows.h>
|
|
#include <io.h>
|
|
#include <math.h>
|
|
#include <vector>
|
|
#include <iostream>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <atlstr.h>
|
|
|
|
typedef __int32 int32_t;
|
|
typedef unsigned __int32 uint32_t;
|
|
|
|
typedef BOOL (WINAPI *API_GET_FILE_SIZE_EX)(HANDLE hFile,PLARGE_INTEGER lpFileSize);
|
|
|
|
#else
|
|
#include <sys/param.h> // for HZ
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/tcp.h>
|
|
#include <arpa/inet.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <fcntl.h>
|
|
#include <ctype.h>
|
|
#include <netdb.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
|
|
typedef int BOOL;
|
|
typedef void* LPVOID;
|
|
typedef char* LPSTR;
|
|
typedef const char* LPCSTR;
|
|
typedef unsigned int UINT;
|
|
typedef unsigned int DWORD;
|
|
typedef unsigned int* LPDWORD;
|
|
typedef unsigned long long UINT64;
|
|
|
|
typedef int SOCKET;
|
|
typedef int __int32;
|
|
typedef long long __int64;
|
|
typedef struct sockaddr SOCKADDR;
|
|
|
|
#define closesocket(a) close(a)
|
|
|
|
#define FALSE 0
|
|
#define TRUE 1
|
|
|
|
#define INVALID_SOCKET -1
|
|
#define SOCKET_ERROR -1
|
|
#define _O_CREAT O_CREAT
|
|
#define _O_TRUNC O_TRUNC
|
|
#define _O_APPEND O_APPEND
|
|
#define _O_RDONLY O_RDONLY
|
|
#define _O_WRONLY O_WRONLY
|
|
#define _O_BINARY 0
|
|
#define _O_RANDOM 0
|
|
|
|
#define _S_IFDIR S_IFDIR
|
|
|
|
#define _lseeki64 lseek64
|
|
#define _stati64 stat64
|
|
//tael
|
|
#define lseek64 lseek
|
|
#define stat64 stat
|
|
#define open64 open
|
|
|
|
#endif
|
|
|
|
#include <time.h>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <set>
|
|
|
|
#include "solbox_util.h" // dadamin : Implement a function that does not exist.
|
|
#include "SHCSDK.h"
|
|
#include "GTS_INFO.h"
|
|
|
|
#include "ne_request.h"
|
|
#include "ne_session.h"
|
|
#include "ne_xml.h"
|
|
#include "ne_dates.h"
|
|
|
|
#ifndef off64_t
|
|
#define off64_t INT64
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
# pragma comment(lib, "ws2_32.lib")
|
|
#endif
|
|
|
|
#define MAX_TRY 3
|
|
#define PRIVATE_KEY "gE\x8bk\xc6\x23{2i\x98<dsH3f"
|
|
#define DEFAULT_SESSIONID "ANONYMOUS0123456"
|
|
#define DEFAULT_EXPIRE_TIME 75
|
|
|
|
using namespace std;
|
|
|
|
typedef vector<PSHFILE_STRUCT> VECTOR_SHFILELIST, *PVECTOR_SHFILELIST;
|
|
|
|
typedef struct SHCSDK_HANDLE {
|
|
ne_session* pnsess;
|
|
ne_inet_addr** hostlist;
|
|
int nhostcnt;
|
|
ne_uri nuri;
|
|
string sPath;
|
|
string sAuth;
|
|
bool bWorking;
|
|
sh_callback proc;
|
|
void* pParam;
|
|
int nError;
|
|
string sError;
|
|
#ifdef WIN32
|
|
HANDLE hFile;
|
|
#else
|
|
int nFileDesc;
|
|
#endif
|
|
INT64 iFilePos;
|
|
INT64 nFileSize;
|
|
clock_t cOldTick;
|
|
int nTranStop;
|
|
string sRedirect;
|
|
long nSpeedLimit;
|
|
clock_t starttick;
|
|
PVECTOR_SHFILELIST pvecshfl;
|
|
set<PVECTOR_SHFILELIST> setFileList;
|
|
string sSessionID;
|
|
int nAuthExpire;
|
|
} SHCSDK_STRUCT, *PSHCSDK_STRUCT;
|
|
|
|
enum {
|
|
SHSTOP_NO = 0,
|
|
SHSTOP_BYUSER,
|
|
SHSTOP_BYERROR,
|
|
};
|
|
|
|
typedef struct {
|
|
int nTag;
|
|
UINT nRootPathLen;
|
|
PSHFILE_STRUCT pshf;
|
|
PVECTOR_SHFILELIST pvec;
|
|
} SHFILELIST_PARSER_STRUCT, *PSHFILELIST_PARSER_STRUCT;
|
|
|
|
enum {
|
|
SHFLTAG_UNKNOWN = 0,
|
|
SHFLTAG_PATH,
|
|
SHFLTAG_TYPE,
|
|
SHFLTAG_SIZE,
|
|
SHFLTAG_LASTMODIFIED,
|
|
SHFLTAG_SOURCE,
|
|
};
|
|
|
|
#define URL_SIZE 1024
|
|
#define PATH_SIZE 2048
|
|
|
|
#define TERM_TICKCOUNT (CLOCKS_PER_SEC >> 3)
|
|
|
|
DWORD dwTransferd;
|
|
|
|
static int timeout = 5;
|
|
|
|
static int _connect_time_out = 5;
|
|
static int _read_time_out = 120; // neon library 기본 설정값은 120초
|
|
//
|
|
|
|
#ifdef WIN32
|
|
HINSTANCE g_hInst;
|
|
|
|
#ifdef _DEBUG
|
|
#define _CRTDBG_MAP_ALLOC
|
|
#include <crtdbg.h>
|
|
#define SET_CRT_DEBUG_FIELD(a) _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
|
|
#define CLEAR_CRT_DEBUG_FIELD(a) _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
|
|
#else
|
|
#define SET_CRT_DEBUG_FIELD(a) ((void) 0)
|
|
#define CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
|
|
#endif
|
|
|
|
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
|
|
{
|
|
#ifdef DEBUG
|
|
SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF | _CRTDBG_DELAY_FREE_MEM_DF );
|
|
//_CrtSetBreakAlloc(76);
|
|
#endif
|
|
g_hInst = (HINSTANCE)hModule;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static int __nonblock_win32(SOCKET s)
|
|
{
|
|
int ul = 1;
|
|
int result;
|
|
|
|
result = ioctlsocket( s, FIONBIO, (u_long FAR*)&ul );
|
|
|
|
return result;
|
|
}
|
|
#else
|
|
int GetLastError()
|
|
{
|
|
return errno;
|
|
}
|
|
|
|
void SetLastError(int nError)
|
|
{
|
|
errno = nError;
|
|
}
|
|
|
|
#include <sys/time.h>
|
|
clock_t GetTickCount(void)
|
|
{
|
|
struct timeval tv;
|
|
|
|
if (gettimeofday(&tv, NULL) < 0) return 0;
|
|
else {
|
|
/* It's micro second. 1/1000000 sec.
|
|
* window api's GetTickCount is mili second. 1/1000 sec.
|
|
* conv it!
|
|
*/
|
|
return (clock_t)((clock_t)(tv.tv_sec * 1000) + tv.tv_usec / 1000);
|
|
}
|
|
}
|
|
|
|
static int __nonblock(int fd)
|
|
{
|
|
int result;
|
|
int flags;
|
|
|
|
flags = fcntl(fd, F_GETFL, 0);
|
|
result = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
|
|
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
inline int WaitForBandCtl(double dWrite, long double ldDesiredBand)
|
|
{
|
|
struct timeval tv;
|
|
int iWaitTimeInt = 0;
|
|
double dWaitTime = 0.00;
|
|
unsigned long ulWaitTimeDec = 0;
|
|
fd_set fakeFD;
|
|
|
|
FD_ZERO(&fakeFD);
|
|
if((dWrite <= 0) || (ldDesiredBand <= 0)) {
|
|
return -1;
|
|
}
|
|
|
|
memset((char *)&tv, 0, sizeof(tv));
|
|
dWaitTime = (double)( 1 / (double)(ldDesiredBand/dWrite));
|
|
iWaitTimeInt = (int)(dWaitTime);
|
|
ulWaitTimeDec = (long)((dWaitTime - iWaitTimeInt) * 1000);
|
|
|
|
tv.tv_sec = iWaitTimeInt;
|
|
tv.tv_usec = ulWaitTimeDec;
|
|
#ifdef WIN32
|
|
Sleep((DWORD)(dWaitTime*1000));
|
|
#else
|
|
usleep((DWORD)(dWaitTime*1000));
|
|
#endif
|
|
return 1;
|
|
}
|
|
|
|
static void ReplaceAll(string& sValue, LPCSTR pszOld, LPCSTR pszNew)
|
|
{
|
|
#ifndef WIN32
|
|
if (strlen(pszOld) != strlen(pszNew)) {
|
|
#endif
|
|
string sOld = pszOld;
|
|
string sNew = pszNew;
|
|
|
|
size_t s;
|
|
while ((s = sValue.find(sOld)) != string::npos)
|
|
sValue.replace(s, sOld.length(), sNew);
|
|
#ifndef WIN32
|
|
} else {
|
|
char *pszValue, *p, *r;
|
|
|
|
pszValue = (char *)malloc(sValue.length() + 1);
|
|
strcpy(pszValue, sValue.c_str());
|
|
|
|
r = pszValue;
|
|
while ((p = strstr(r, pszOld))) {
|
|
memcpy(p, pszNew, strlen(pszNew));
|
|
r = p;
|
|
}
|
|
|
|
sValue.clear();
|
|
sValue = pszValue;
|
|
free(pszValue);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// 세션 상태를 콜백으로 받는 함수
|
|
static void status_cb(void *userdata, ne_session_status status,
|
|
const ne_session_status_info *info)
|
|
{
|
|
switch (status) {
|
|
case ne_status_connected:
|
|
{
|
|
ne_socket *sock = get_session_socket((ne_session *)userdata);
|
|
// 타임 아웃 값 지정함(30초)
|
|
// 마지막 데이터 전송 완료(실제 전송 완료되지 않고 커널 응답) 후
|
|
// close 호출 된 경우 해당 옵션 미지정된 경우 네트워크 상 전송할 데이터 남아
|
|
// 있더라도 해당 데이터 모두 삭제됨
|
|
struct linger l = {1, 30};
|
|
#ifdef WIN32
|
|
setsockopt(ne_sock_fd(sock), SOL_SOCKET, SO_LINGER,(char*) &l, sizeof l);
|
|
#else // WIN32
|
|
setsockopt(ne_sock_fd(sock), SOL_SOCKET, SO_LINGER, &l, sizeof l);
|
|
#endif // WIN32
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// 세션 생성 및 추가 설정
|
|
static bool solbox_session_create(PSHCSDK_STRUCT psdk)
|
|
{
|
|
psdk->pnsess = ne_session_create(psdk->nuri.scheme, psdk->nuri.host, psdk->nuri.port);
|
|
|
|
// 세션의 상태 notifier 함수 등록
|
|
ne_set_notifier(psdk->pnsess, status_cb, psdk->pnsess);
|
|
|
|
return true;
|
|
}
|
|
|
|
//세션의 파괴 및 추가 작업
|
|
static void solbox_session_destroy(PSHCSDK_STRUCT psdk)
|
|
{
|
|
ne_session_destroy(psdk->pnsess);
|
|
}
|
|
|
|
|
|
// dns cache 기능을 사용하기 위한 함수이다.
|
|
//
|
|
//static bool solbox_session_create(PSHCSDK_STRUCT psdk)
|
|
//{
|
|
// const ne_inet_addr** result;
|
|
// int nResultCnt;
|
|
//
|
|
// result = solbox_resolve(psdk->nuri.host, &nResultCnt);
|
|
// ne_free(result);
|
|
// result = solbox_resolve("bd-04-fhs001.ktsh.co.kr", &nResultCnt);
|
|
// ne_free(result);
|
|
// result = solbox_resolve("bd-04-fhs001.ktsh.co.kr", &nResultCnt);
|
|
// ne_free(result);
|
|
// result = solbox_resolve("bd-04-fhs001.ktsh.co.kr", &nResultCnt);
|
|
// ne_free(result);
|
|
// result = solbox_resolve(psdk->nuri.host, &nResultCnt);
|
|
// if( result == NULL )
|
|
// {
|
|
// // host 에러입니다.
|
|
// return false;
|
|
// }
|
|
//
|
|
// psdk->pnsess = ne_session_create(psdk->nuri.scheme, psdk->nuri.host, psdk->nuri.port);
|
|
//
|
|
// ne_set_addrlist(psdk->pnsess, result, nResultCnt);
|
|
// ne_free(result);
|
|
// return true;
|
|
//}
|
|
|
|
static string GetErrorMessage(int nError)
|
|
{
|
|
string sError;
|
|
|
|
if (nError >= SHCERRNO_UNDEFINED && nError < SHCERRNO_MAX) {
|
|
switch (nError) {
|
|
case SHCERRNO_UNDEFINED:
|
|
sError = "알 수 없는 오류입니다.";
|
|
break;
|
|
case SHCERRNO_INVALIDHDL:
|
|
sError = "잘못된 SDK 핸들입니다.";
|
|
break;
|
|
case SHCERRNO_INVALIDFLHDL:
|
|
sError = "잘못된 파일리스트 핸들입니다.";
|
|
break;
|
|
case SHCERRNO_SERVICE:
|
|
sError = "서버 응답이 정상적이지 않습니다..";
|
|
break;
|
|
case SHCERRNO_AUTHORIZATION:
|
|
sError = "인증에 실패 했습니다.";
|
|
break;
|
|
case SHCERRNO_ISBUSY:
|
|
sError = "다른 작업을 처리하고 있는 중 입니다.";
|
|
break;
|
|
case SHCERRNO_EXISTSFILE:
|
|
sError = "지정한 이름을 가진 파일 또는 디렉토리가 이미 존재합니다.";
|
|
break;
|
|
case SHCERRNO_NOEXISTSFILE:
|
|
sError = "파일 또는 디렉토리가 존재하지 않습니다.";
|
|
break;
|
|
case SHCERRNO_NOAVAILQUOTA:
|
|
sError = "사용 가능한 용량이 부족합니다.";
|
|
break;
|
|
case SHCERRNO_ALREADYEXIST:
|
|
sError = "폴더가 이미 존재 합니다.";
|
|
break;
|
|
case SHCERRNO_RESP_TIMEOUT:
|
|
sError = "소켓 읽기 실패입니다.";
|
|
break;
|
|
case SHCERRNO_NE_LOOKUP:
|
|
sError = "호스트 정보에대해 룩업에 실패했습니다.";
|
|
break;
|
|
case SHCERRNO_NE_CONNECT:
|
|
sError = "서버에 연결을 하지 못했습니다.";
|
|
break;
|
|
case SHCERRNO_TRAGETBIGGER:
|
|
sError = "대상 데이터의 크기가 전송할 데이터 크기와 동일하거나 큽니다.";
|
|
break;
|
|
case SHCERRNO_DNS_TIMEOUT:
|
|
sError = "DNS 쿼리 시간초과입니다.";
|
|
break;
|
|
case SHCERRNO_EXT_OVERFLOW:
|
|
sError = "download 시 확장 값이 512Bytes를 초과하였습니다.";
|
|
break;
|
|
|
|
}
|
|
}
|
|
else {
|
|
#ifdef WIN32
|
|
LPVOID lpError;
|
|
|
|
if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
NULL, nError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpError, 0, NULL))
|
|
sError = "알 수 없는 오류입니다.";
|
|
else
|
|
sError = (LPCSTR)lpError;
|
|
|
|
LocalFree(lpError);
|
|
#else
|
|
sError = strerror(nError);
|
|
#endif
|
|
}
|
|
|
|
return sError;
|
|
}
|
|
|
|
int StrTrim(char* dst, const char* src, int len)
|
|
{
|
|
register int dlen, i;
|
|
register char *sp;
|
|
char *buff;
|
|
|
|
if(!len) return 0;
|
|
|
|
buff = (char *)calloc(1, len + 1);
|
|
strncpy(buff, src, len);
|
|
|
|
/* R-Trim */
|
|
sp = buff + len -1; dlen = len -1;
|
|
while(1){
|
|
if(dlen <= 0) break;
|
|
else if(*sp != ' ' && *sp != 0x00) break;
|
|
else *sp = 0x00;
|
|
sp --; dlen --;
|
|
}
|
|
dlen = strlen(buff); sp = buff; i = 0;
|
|
|
|
/* L-Trim */
|
|
while(i < dlen){ if(*sp != ' ' && *sp != 0x00) break; sp ++; i++; }
|
|
dlen = strlen(sp);
|
|
strcpy(dst, sp);
|
|
free(buff);
|
|
return dlen;
|
|
}
|
|
static INT64 sh_atoi(LPCSTR pszSize)
|
|
{
|
|
#ifdef WIN32
|
|
return _atoi64(pszSize);
|
|
#else
|
|
return strtoll(pszSize, NULL, 10);
|
|
#endif
|
|
}
|
|
|
|
static BOOL DeleteDirectory(LPCSTR pszDirectory)
|
|
{
|
|
#ifdef WIN32
|
|
string sDirectory = pszDirectory;
|
|
sDirectory += "\\*";
|
|
|
|
WIN32_FIND_DATA w32fd;
|
|
|
|
HANDLE hFindFile = FindFirstFile(sDirectory.c_str(), &w32fd);
|
|
while (hFindFile != INVALID_HANDLE_VALUE) {
|
|
if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
|
if (w32fd.cFileName[0] != '.') {
|
|
if (!DeleteDirectory(w32fd.cFileName))
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
if (!DeleteFile(w32fd.cFileName))
|
|
return false;
|
|
}
|
|
|
|
if (!FindNextFile(hFindFile, &w32fd))
|
|
break;
|
|
}
|
|
|
|
FindClose(hFindFile);
|
|
|
|
return RemoveDirectory(pszDirectory);
|
|
#else
|
|
#define PATH_MAX 4096
|
|
char buf[PATH_MAX + 5];
|
|
int ret;
|
|
|
|
snprintf(buf, PATH_MAX, "/bin/rm -rf %s", pszDirectory);
|
|
ret = system(buf);
|
|
|
|
return (ret == 0);
|
|
#endif
|
|
}
|
|
|
|
static int _sh_send(SOCKET s, char *pszBuf, int nLen)
|
|
{
|
|
int iSent = 0, nSentLen;
|
|
fd_set wset;
|
|
struct timeval tv;
|
|
|
|
FD_ZERO(&wset);
|
|
FD_SET(s, &wset);
|
|
tv.tv_sec = timeout;
|
|
tv.tv_usec = 0;
|
|
do {
|
|
if (select(s + 1, NULL, &wset, NULL, &tv) < 0) break;
|
|
if (!FD_ISSET(s, &wset)) break;
|
|
|
|
nSentLen = send(s, pszBuf + iSent, nLen, 0);
|
|
|
|
iSent += nSentLen;
|
|
nLen -= nSentLen;
|
|
} while (nLen > 0 && nSentLen > 0);
|
|
|
|
return nLen > 0 ? SOCKET_ERROR : iSent;
|
|
}
|
|
|
|
// format : Thu, 15 Dec 2005 05:22:33 GMT
|
|
static string FormatLastModified(LPCSTR pszTime)
|
|
{
|
|
string sTime;
|
|
|
|
// RFC1123_FORMAT to time_t format & GMT+9(32400 sec)
|
|
// "Thu, 15 Dec 2005 05:22:33 GMT" 이런 형태를 RFC1122_FORMAT 이라한다.
|
|
// RFC1122_FORMAT 포맷을 인자로 넘겨서 time_t를 얻을 수 있었고,
|
|
// 얻은 값에다가 9시간에 해당하는 sec를 더해서 GMT+9를 구한다.
|
|
time_t t = ne_rfc1123_parse(pszTime) + 32400;
|
|
|
|
// time_t to struct tm
|
|
// 위 과정에서 이미 GMT+9가 처리되었으므로,
|
|
// 기존 소스처럼 복잡한 과정을 거치지 않아도 된다.
|
|
// 단지 time_t 값을 속성을 알고 year에 1900을 mon1을 더해준다.
|
|
struct tm stm;
|
|
stm = *gmtime(&t);
|
|
stm.tm_year = stm.tm_year + 1900;
|
|
stm.tm_mon = stm.tm_mon + 1;
|
|
|
|
// 최종적으로 표현하고자 하는 날짜 포맷으로 변경처리한다.
|
|
char szTemp[20];
|
|
sprintf(szTemp, "%04d-%02d-%02d ", stm.tm_year, stm.tm_mon, stm.tm_mday);
|
|
sTime = szTemp;
|
|
sprintf(szTemp, " %02d:%02d:%02d", stm.tm_hour, stm.tm_min, stm.tm_sec);
|
|
sTime += szTemp;
|
|
|
|
return sTime;
|
|
}
|
|
|
|
// format : Fri Jan 27 12:12:22 2006 Thu
|
|
static bool ParseSntpString(LPCSTR pszTime, struct tm* ptm)
|
|
{
|
|
string sTime = pszTime;
|
|
sTime.erase(sTime.find_last_not_of(" \t\n") + 1);
|
|
sTime.erase(0, sTime.find_first_not_of(" \t\n"));
|
|
|
|
if (sTime == "")
|
|
return false;
|
|
|
|
int iString = 0;
|
|
string::size_type stBegin = 0, stEnd = 0;
|
|
do {
|
|
stEnd = sTime.find(' ', stBegin);
|
|
|
|
string sToken = sTime.substr(stBegin, stEnd - stBegin);
|
|
|
|
switch (iString) {
|
|
case 1:
|
|
if (sToken == "Jan") ptm->tm_mon = 1;
|
|
else if (sToken == "Feb") ptm->tm_mon = 2;
|
|
else if (sToken == "Mar") ptm->tm_mon = 3;
|
|
else if (sToken == "Apr") ptm->tm_mon = 4;
|
|
else if (sToken == "May") ptm->tm_mon = 5;
|
|
else if (sToken == "Jun") ptm->tm_mon = 6;
|
|
else if (sToken == "Jul") ptm->tm_mon = 7;
|
|
else if (sToken == "Aug") ptm->tm_mon = 8;
|
|
else if (sToken == "Sep") ptm->tm_mon = 9;
|
|
else if (sToken == "Oct") ptm->tm_mon = 10;
|
|
else if (sToken == "Nov") ptm->tm_mon = 11;
|
|
else if (sToken == "Dec") ptm->tm_mon = 12;
|
|
break;
|
|
case 2:
|
|
ptm->tm_mday = atoi(sToken.c_str());
|
|
break;
|
|
case 3:
|
|
ptm->tm_hour = atoi(sToken.substr(0, 2).c_str()) + 9;
|
|
ptm->tm_min = atoi(sToken.substr(3, 5).c_str());
|
|
ptm->tm_sec = atoi(sToken.substr(6, 8).c_str());
|
|
break;
|
|
case 4:
|
|
ptm->tm_year = atoi(sToken.c_str());
|
|
break;
|
|
}
|
|
|
|
if (iString++ >= 4)
|
|
break;
|
|
|
|
stBegin = stEnd + 1;
|
|
} while (stEnd != string::npos);
|
|
|
|
return true;
|
|
}
|
|
|
|
static INT64 sh_filelength(int nFd)
|
|
{
|
|
#ifdef WIN32
|
|
return _filelengthi64(nFd);
|
|
#else
|
|
INT64 nLength = lseek64(nFd, 0, SEEK_END);
|
|
lseek64(nFd, 0, SEEK_SET);
|
|
|
|
return nLength;
|
|
#endif
|
|
}
|
|
|
|
static BOOL check_suthstring(const char* pszAuthstring)
|
|
{
|
|
char* pAuth;
|
|
char* pData;
|
|
char* pSrc;
|
|
char* context = NULL;
|
|
char szDst[128]={0};
|
|
BOOL bResult;
|
|
|
|
pSrc = new char[strlen(pszAuthstring)+1];
|
|
|
|
memcpy(pSrc,pszAuthstring,strlen(pszAuthstring)+1);
|
|
|
|
|
|
#ifdef WIN32
|
|
pAuth = strtok_s((char*)pSrc,":", &context);
|
|
#else // WIN32
|
|
pAuth = strtok_r((char*)pSrc,":",&context);
|
|
#endif // WIN32
|
|
|
|
|
|
if(pAuth == NULL)
|
|
bResult = FALSE;
|
|
else
|
|
{
|
|
#ifdef WIN32
|
|
pData = strtok_s(NULL,":", &context);
|
|
#else // WIN32
|
|
pAuth = strtok_r(NULL,":",&context);
|
|
#endif // WIN32
|
|
if(pData == NULL)
|
|
bResult = FALSE;
|
|
else
|
|
{
|
|
md5_buffer(pAuth,szDst);
|
|
|
|
#ifdef WIN32
|
|
if(stricmp(pData,szDst) == 0)
|
|
#else
|
|
if(strcasecmp(pData,szDst) == 0)
|
|
#endif
|
|
{
|
|
strcpy((char*)pszAuthstring,pAuth);
|
|
bResult = TRUE;
|
|
}
|
|
else
|
|
bResult = FALSE;
|
|
}
|
|
}
|
|
|
|
delete []pSrc;
|
|
|
|
return bResult;
|
|
}
|
|
|
|
static int _sh_recv(SOCKET s, char *pszBuf, int nLen)
|
|
{
|
|
int iRecv = 0, nRecvLen;
|
|
fd_set rset;
|
|
struct timeval tv;
|
|
|
|
FD_ZERO(&rset);
|
|
FD_SET(s, &rset);
|
|
tv.tv_sec = timeout;
|
|
tv.tv_usec = 0;
|
|
|
|
do {
|
|
if (select(s + 1, &rset, NULL, NULL, &tv) < 0) break;
|
|
if (!FD_ISSET(s, &rset)) break;
|
|
|
|
nRecvLen = recv(s, pszBuf + iRecv, nLen, 0);
|
|
|
|
iRecv += nRecvLen;
|
|
nLen -= nRecvLen;
|
|
} while (nLen > 0 && nRecvLen > 0);
|
|
|
|
return nLen < 0 ? SOCKET_ERROR : iRecv;
|
|
}
|
|
|
|
typedef struct _s_time_sync_t
|
|
{
|
|
int32_t sync_info;
|
|
}time_sync_t;
|
|
|
|
#define AUTHPRIME 137897
|
|
|
|
static time_t get_time_from_sntp()
|
|
{
|
|
char szHost[128];
|
|
int nRecv;
|
|
time_sync_t tst;
|
|
int nWrite;
|
|
time_sync_t *pSyncInfo = NULL;
|
|
#ifdef WIN32
|
|
tm *ttm=NULL;
|
|
#endif
|
|
|
|
int32_t ltime = (int32_t)time(NULL);
|
|
|
|
if (ne_sock_init() != NE_OK)
|
|
{
|
|
#ifdef _DEBUG
|
|
printf("time sever connect error : sock init fail\n");
|
|
#endif
|
|
return time(NULL);
|
|
}
|
|
|
|
// Get server time
|
|
struct addrinfo *result;
|
|
strcpy(szHost, SNTP_DOMAIN);
|
|
if (isalpha(szHost[0]))
|
|
{
|
|
struct addrinfo hints = {0};
|
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
hints.ai_family = PF_UNSPEC;
|
|
|
|
if( getaddrinfo( szHost, NULL, &hints, &result ) != 0 )
|
|
{
|
|
#ifdef _DEBUG
|
|
printf("time sever connect error : getaddrinfo fail\n");
|
|
#endif
|
|
return time(NULL);
|
|
}
|
|
|
|
struct sockaddr_in * addr = (struct sockaddr_in *)result->ai_addr;
|
|
sprintf(szHost, "%s", inet_ntoa(addr->sin_addr));
|
|
freeaddrinfo(result);
|
|
}
|
|
|
|
#ifndef WIN32
|
|
#define RETRY 2
|
|
int recv_err = 0;
|
|
|
|
recv_retry:
|
|
#endif
|
|
|
|
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
if (sock == INVALID_SOCKET)
|
|
{
|
|
#ifdef WIN32
|
|
int nRet = WSAGetLastError();
|
|
#endif
|
|
#ifdef _DEBUG
|
|
printf("time sever connect error : socket create fail\n");
|
|
#endif
|
|
|
|
return time(NULL);
|
|
}
|
|
|
|
sockaddr_in sa;
|
|
sa.sin_family = AF_INET;
|
|
sa.sin_addr.s_addr = inet_addr(szHost);
|
|
sa.sin_port = htons(SNTP_PORT);
|
|
|
|
#ifdef WIN32
|
|
__nonblock_win32(sock);
|
|
|
|
if (connect(sock, (SOCKADDR*)&sa, sizeof(sa)) == SOCKET_ERROR)
|
|
{
|
|
|
|
if (WSAEWOULDBLOCK == WSAGetLastError())
|
|
{
|
|
fd_set wfd, efd;
|
|
struct timeval tv;
|
|
FD_ZERO(&wfd);
|
|
FD_ZERO(&efd);
|
|
FD_SET(sock, &wfd);
|
|
FD_SET(sock, &efd);
|
|
tv.tv_sec = timeout;
|
|
tv.tv_usec = 0;
|
|
int result = select(0, 0, &wfd, &efd,&tv);
|
|
if (SOCKET_ERROR == result || 0 == result)
|
|
{
|
|
int nRet = WSAGetLastError();
|
|
#ifdef _DEBUG
|
|
printf("time sever connect error : select fail\n");
|
|
#endif
|
|
return time(NULL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef _DEBUG
|
|
printf("time sever connect error : unknown error code\n");
|
|
#endif
|
|
return time(NULL);
|
|
}
|
|
}
|
|
|
|
#else // WIN32
|
|
__nonblock(sock);
|
|
{
|
|
int i, nRet;
|
|
for (i = 0; i < (timeout * 10); i++) {
|
|
errno = 0;
|
|
if (connect(sock, (SOCKADDR*)&sa, sizeof(sa)) != SOCKET_ERROR) {
|
|
;
|
|
} else {
|
|
nRet = errno;
|
|
}
|
|
|
|
if (errno == EISCONN) {
|
|
break;
|
|
}
|
|
|
|
if (((i + 1) % 10) == 0) {
|
|
shutdown(sock, SHUT_RDWR);
|
|
close(sock);
|
|
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|
if (sock == INVALID_SOCKET)
|
|
{
|
|
return time(NULL);
|
|
}
|
|
__nonblock(sock);
|
|
/* Elenoa */
|
|
}
|
|
usleep(100000);
|
|
}
|
|
|
|
if (errno != EISCONN && errno != 0)
|
|
{
|
|
return time(NULL);
|
|
}
|
|
}
|
|
#endif // WIN32
|
|
|
|
tst.sync_info = ltime + AUTHPRIME - (ltime % AUTHPRIME);
|
|
|
|
tst.sync_info = htonl(tst.sync_info);
|
|
nWrite = _sh_send(sock, (char *)&tst, sizeof(tst));
|
|
|
|
if(nWrite < 0)
|
|
{
|
|
closesocket(sock);
|
|
#ifndef WIN32
|
|
if (recv_err <= RETRY) {
|
|
recv_err ++;
|
|
goto recv_retry;
|
|
}
|
|
#endif
|
|
#ifdef _DEBUG
|
|
printf("time sever connect error : send fail\n");
|
|
#endif
|
|
|
|
return time(NULL);
|
|
}
|
|
|
|
nRecv = _sh_recv(sock, szHost, sizeof(szHost));
|
|
|
|
if (nRecv < 4)
|
|
{
|
|
closesocket(sock);
|
|
#ifndef WIN32
|
|
if (recv_err <= RETRY) {
|
|
recv_err ++;
|
|
goto recv_retry;
|
|
}
|
|
#endif
|
|
#ifdef _DEBUG
|
|
printf("time sever connect error : recv fail\n");
|
|
#endif
|
|
|
|
return time(NULL);
|
|
}
|
|
|
|
pSyncInfo = (time_sync_t *)&szHost;
|
|
pSyncInfo->sync_info = ntohl(pSyncInfo->sync_info);
|
|
closesocket(sock);
|
|
|
|
return pSyncInfo->sync_info;
|
|
}
|
|
|
|
static string URLEncode(LPCSTR pszURL)
|
|
{
|
|
char szEncoded[URL_SIZE];
|
|
char* pszEncoded = szEncoded;
|
|
|
|
while (*pszURL != (char)NULL) {
|
|
if ((*pszURL >= 'a' && *pszURL <= 'z') || (*pszURL >= 'A' && *pszURL <= 'Z')
|
|
|| (*pszURL >= '0' && *pszURL <= '9') || *pszURL == '/')
|
|
*pszEncoded = (char)*pszURL;
|
|
else {
|
|
*pszEncoded++ = '%';
|
|
|
|
char szBuf[10];
|
|
sprintf(szBuf, "%02X", *pszURL);
|
|
int nBufLen = (int)strlen(szBuf);
|
|
*pszEncoded++ = szBuf[nBufLen - 2];
|
|
*pszEncoded = szBuf[nBufLen - 1];
|
|
}
|
|
|
|
pszEncoded++;
|
|
pszURL++;
|
|
}
|
|
*pszEncoded = (char)NULL;
|
|
|
|
string sRet = szEncoded;
|
|
|
|
return sRet;
|
|
}
|
|
|
|
static string URLDecode(LPCSTR pszURL)
|
|
{
|
|
char szOut[URL_SIZE], szHex[3];
|
|
|
|
::memset(szOut, 0, sizeof(szOut));
|
|
|
|
for (int i = 0, j = 0; pszURL[i]; i++, j++) {
|
|
if (pszURL[i] == '%') {
|
|
szHex[0] = pszURL[++i];
|
|
szHex[1] = pszURL[++i];
|
|
szHex[2] = 0;
|
|
#ifdef WIN32
|
|
sscanf((char*)szHex, "%x", &szOut[j]);
|
|
#else
|
|
szOut[j] = (char)strtol(szHex, NULL, 16);
|
|
#endif
|
|
} else {
|
|
szOut[j] = pszURL[i];
|
|
}
|
|
}
|
|
|
|
string sRet = szOut;
|
|
|
|
return sRet;
|
|
}
|
|
|
|
static string PathEncode(LPCSTR pszPath)
|
|
{
|
|
if (pszPath[0] == '/')
|
|
pszPath += 1;
|
|
|
|
string sRetPath = "";
|
|
string sSrcPath = pszPath;
|
|
|
|
string::size_type stBegin = 0, stEnd = 0;
|
|
do {
|
|
stEnd = sSrcPath.find('/', stBegin);
|
|
|
|
string sPath = sSrcPath.substr(stBegin, stEnd - stBegin);
|
|
sRetPath += "/" + URLEncode(sPath.c_str());
|
|
|
|
stBegin = stEnd + 1;
|
|
} while (stEnd != string::npos);
|
|
|
|
return sRetPath;
|
|
}
|
|
|
|
void __tea_encrypt(uint32_t *v, uint32_t *k)
|
|
{
|
|
uint32_t v0 = v[0], v1 = v[1], sum = 0, i; /* set up */
|
|
uint32_t delta = 0x9e3779b9; /* a key schedule constant */
|
|
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3]; /* cache key */
|
|
|
|
for (i = 0; i < 32; i++) { /* basic cycle start */
|
|
sum += delta;
|
|
v0 += (v1 << 4) + (k0 ^ v1) + (sum ^ (v1 >> 5)) + k1;
|
|
v1 += (v0 << 4) + (k2 ^ v0) + (sum ^ (v0 >> 5)) + k3; /* end cycle */
|
|
}
|
|
|
|
v[0] = v0; v[1] = v1;
|
|
}
|
|
|
|
|
|
void __tea_decrypt(uint32_t *v, uint32_t *k)
|
|
{
|
|
uint32_t v0 = v[0], v1 = v[1], sum = 0xC6EF3720, i; /* set up */
|
|
uint32_t delta = 0x9e3779b9; /* a key schedule constant */
|
|
uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3]; /* cache key */
|
|
|
|
for (i = 0; i < 32; i++) { /* basic cycle start */
|
|
v1 -= (v0 << 4) + k2 ^ v0 + sum ^ (v0 >> 5) + k3;
|
|
v0 -= (v1 << 4) + k0 ^ v1 + sum ^ (v1 >> 5) + k1;
|
|
sum -= delta; /* end cycle */
|
|
}
|
|
|
|
v[0] = v0; v[1] = v1;
|
|
}
|
|
|
|
|
|
void tea_encrypt(char *buf, int len)
|
|
{
|
|
int __len = (len + 7) >> 3;
|
|
int i;
|
|
//char *key = PRIVATE_KEY;
|
|
|
|
for (i = 0; i < __len; i++) {
|
|
__tea_encrypt((((uint32_t *)buf) + (i << 1)), (uint32_t *)PRIVATE_KEY);
|
|
}
|
|
}
|
|
|
|
|
|
void tea_decrypt(char *buf, int len)
|
|
{
|
|
int __len = (len + 7) >> 3;
|
|
int i;
|
|
|
|
for (i = 0; i < __len; i++) {
|
|
__tea_decrypt((((uint32_t *)buf) + (i << 1)), (uint32_t *)PRIVATE_KEY);
|
|
}
|
|
}
|
|
|
|
static int ResponseBodyReader(void* userdata, const char* buf, size_t len)
|
|
{
|
|
if (len == 0)
|
|
return 0;
|
|
|
|
string* psBody = (string*)userdata;
|
|
|
|
char* pszTemp = new char[len + 1];
|
|
memcpy(pszTemp, buf, len);
|
|
pszTemp[len] = (char)NULL;
|
|
|
|
(*psBody) += pszTemp;
|
|
|
|
delete []pszTemp;
|
|
|
|
return NE_OK;
|
|
}
|
|
|
|
char* get_auth_str(PSHCSDK_STRUCT psdk, LPCSTR pszPath, int nFlag)
|
|
{
|
|
unsigned char pszAuth[4096];
|
|
unsigned char *bintoken = NULL;
|
|
char szTemp[16];
|
|
// string sAuth;
|
|
int nRet;
|
|
|
|
ne_unbase64(psdk->sAuth.c_str(),&bintoken);
|
|
|
|
if (bintoken == NULL)
|
|
return NULL;
|
|
|
|
char* context = NULL;
|
|
char* pData = NULL;
|
|
#ifdef WIN32
|
|
pData = strtok_s((char*)bintoken,":", &context);
|
|
#else // WIN32
|
|
pData = strtok_r((char*)bintoken,":", &context);
|
|
#endif // WIN32
|
|
|
|
if(pData == NULL)
|
|
{
|
|
if(bintoken) ne_free(bintoken);
|
|
return NULL;
|
|
}
|
|
|
|
int nAuthSize = 4+16+16+psdk->sAuth.size()+8;
|
|
|
|
|
|
int32_t ltime = 0;
|
|
|
|
switch(nFlag)
|
|
{
|
|
case 0: // 서버에서 시간 값을 가져온다.
|
|
ltime = get_time_from_sntp();
|
|
break;
|
|
case 1:
|
|
ltime = time(NULL);
|
|
break;
|
|
}
|
|
|
|
int32_t kkk = ltime + psdk->nAuthExpire;
|
|
|
|
memcpy(pszAuth,(unsigned char *)&kkk,sizeof(kkk));
|
|
|
|
md5_buffer_bin(psdk->sSessionID.c_str(),szTemp);
|
|
memcpy(pszAuth+4,szTemp,sizeof(szTemp));
|
|
|
|
md5_buffer_bin(pszPath,szTemp);
|
|
memcpy(pszAuth+4+16,szTemp,sizeof(szTemp));
|
|
|
|
memcpy(pszAuth+4+16+16,psdk->sAuth.c_str(),psdk->sAuth.size());
|
|
|
|
int nlength = 4 + 16 + 16 + psdk->sAuth.size();
|
|
|
|
nRet = nlength % 8;
|
|
|
|
if (nRet > 0)
|
|
memset((char*)pszAuth + 4 + 16 + 16 + psdk->sAuth.size(),0x20,8-nRet);
|
|
else
|
|
nRet = 8;
|
|
|
|
tea_encrypt((char*)pszAuth,nlength + 8 - nRet);
|
|
char* pszTemp = new char[nlength + 8 -nRet + strlen(pData) + 1];
|
|
|
|
memcpy(pszTemp,pData,strlen(pData));
|
|
memcpy(pszTemp+strlen(pData),":",1);
|
|
memcpy(pszTemp+strlen(pData)+1,pszAuth,nlength + 8 -nRet);
|
|
|
|
char* pResult = ne_base64((const unsigned char*)pszTemp,nlength + 8 -nRet + strlen(pData) + 1);
|
|
string sAuth;
|
|
sAuth = "Basic ";
|
|
sAuth += pResult;
|
|
|
|
if(bintoken) ne_free(bintoken);
|
|
if(pResult) ne_free(pResult);
|
|
if(pszTemp) delete [] pszTemp;
|
|
|
|
return strdup(sAuth.c_str());
|
|
}
|
|
|
|
static ssize_t UploadProvider(void *userdata, char *buffer, size_t buflen)
|
|
{
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)userdata;
|
|
|
|
if (buflen == 0)
|
|
return 0;
|
|
|
|
if (clock() > psdk->cOldTick + TERM_TICKCOUNT || psdk->iFilePos >= psdk->nFileSize)
|
|
{
|
|
if (psdk->proc)
|
|
{
|
|
if (!psdk->proc(psdk->pParam, psdk->iFilePos)) {
|
|
psdk->nTranStop = SHSTOP_BYUSER;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if(psdk->nSpeedLimit > 0)
|
|
{
|
|
double t = (double)(GetTickCount() - psdk->starttick);
|
|
double q = (double)((double)dwTransferd/ t*1000);
|
|
|
|
DWORD m_dbLimit = psdk->nSpeedLimit * 1024;
|
|
|
|
if (q > m_dbLimit)
|
|
{
|
|
DWORD dwret = (DWORD)((((q*t)/m_dbLimit)-t));
|
|
#ifdef WIN32
|
|
Sleep(dwret);
|
|
#else
|
|
usleep(dwret);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
psdk->cOldTick = clock();
|
|
}
|
|
|
|
#ifdef WIN32
|
|
DWORD nRead;
|
|
ReadFile(psdk->hFile,buffer,(DWORD)buflen,&nRead,NULL);
|
|
#else
|
|
int nRead = read(psdk->nFileDesc, buffer, (UINT)buflen);
|
|
#endif
|
|
if (nRead < 0) {
|
|
psdk->nTranStop = SHSTOP_BYERROR;
|
|
|
|
psdk->nError = GetLastError();
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
return -1;
|
|
}
|
|
|
|
dwTransferd += nRead;
|
|
psdk->iFilePos += nRead;
|
|
|
|
return nRead;
|
|
}
|
|
|
|
static int DownloadProvider(void* userdata, const char* buf, size_t len)
|
|
{
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)userdata;
|
|
|
|
if (len == 0)
|
|
return 0;
|
|
|
|
DWORD nWritten, nTotal = 0;
|
|
do {
|
|
#ifdef WIN32
|
|
WriteFile(psdk->hFile,buf,(DWORD)len,&nWritten,NULL);
|
|
#else
|
|
nWritten = write(psdk->nFileDesc, buf + nTotal, (UINT)len - nTotal);
|
|
#endif
|
|
if (nWritten < 0) {
|
|
psdk->nTranStop = SHSTOP_BYERROR;
|
|
|
|
psdk->nError = GetLastError();
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
return 1;
|
|
}
|
|
|
|
nTotal += nWritten;
|
|
} while (nTotal < (DWORD)len);
|
|
|
|
dwTransferd += nTotal;
|
|
psdk->iFilePos += nTotal;
|
|
|
|
if (clock() > psdk->cOldTick + TERM_TICKCOUNT || psdk->iFilePos >= psdk->nFileSize)
|
|
{
|
|
if (psdk->proc)
|
|
{
|
|
if (!psdk->proc(psdk->pParam, psdk->iFilePos))
|
|
{
|
|
psdk->nTranStop = SHSTOP_BYUSER;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if(psdk->nSpeedLimit > 0)
|
|
{
|
|
double t = (double)(GetTickCount() - psdk->starttick);
|
|
double q = (double)((double)dwTransferd/ t*1000);
|
|
DWORD m_dbLimit = psdk->nSpeedLimit * 1024;
|
|
|
|
if (q > m_dbLimit)
|
|
{
|
|
DWORD dwret = (DWORD)((((q*t)/m_dbLimit)-t));
|
|
#ifdef WIN32
|
|
Sleep(dwret);
|
|
#else
|
|
usleep(dwret);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
psdk->cOldTick = clock();
|
|
}
|
|
|
|
return NE_OK;
|
|
}
|
|
|
|
static int FileListSTagParser(void *userdata, int parent, const char *nspace, const char *name, const char **atts)
|
|
{
|
|
PSHFILELIST_PARSER_STRUCT pshflp = (PSHFILELIST_PARSER_STRUCT)userdata;
|
|
|
|
if (strcmp(name, "response") == 0) {
|
|
pshflp->pshf = new SHFILE_STRUCT;
|
|
::memset(pshflp->pshf, 0, sizeof(SHFILE_STRUCT));
|
|
}
|
|
else if (strcmp(name, "href") == 0) {
|
|
pshflp->nTag = SHFLTAG_PATH;
|
|
}
|
|
else if (strcmp(name, "collection") == 0) {
|
|
pshflp->pshf->attr = SHFILEATTR_FOLDER;
|
|
}
|
|
else if (strcmp(name, "getcontentlength") == 0) {
|
|
pshflp->nTag = SHFLTAG_SIZE;
|
|
}
|
|
else if (strcmp(name, "getlastmodified") == 0) {
|
|
pshflp->nTag = SHFLTAG_LASTMODIFIED;
|
|
}
|
|
else if (strcmp(name, "source") == 0) {
|
|
pshflp->nTag = SHFLTAG_SOURCE;
|
|
}
|
|
else {
|
|
pshflp->nTag = SHFLTAG_UNKNOWN;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static string PathDecode(LPCSTR pszPath)
|
|
{
|
|
if (pszPath[0] == '/')
|
|
pszPath += 1;
|
|
|
|
string sRetPath = "";
|
|
string sSrcPath = pszPath;
|
|
|
|
string::size_type stBegin = 0, stEnd = 0;
|
|
do {
|
|
stEnd = sSrcPath.find('/', stBegin);
|
|
|
|
string sPath = URLDecode(sSrcPath.substr(stBegin, stEnd - stBegin).c_str());
|
|
sRetPath += "/" + sPath;
|
|
|
|
stBegin = stEnd + 1;
|
|
} while (stEnd != string::npos);
|
|
|
|
ReplaceAll(sRetPath, "*amp;", "&");
|
|
|
|
return sRetPath;
|
|
}
|
|
|
|
static int FileListDataParser(void *userdata, int state, const char *data, size_t len)
|
|
{
|
|
PSHFILELIST_PARSER_STRUCT pshflp = (PSHFILELIST_PARSER_STRUCT)userdata;
|
|
|
|
|
|
switch (pshflp->nTag) {
|
|
case SHFLTAG_PATH:
|
|
if (!pshflp->pshf->path) {
|
|
if (len >= pshflp->nRootPathLen) {
|
|
int nPathLen = (int)len - pshflp->nRootPathLen;
|
|
char szPath[PATH_SIZE];
|
|
memcpy(szPath, data + pshflp->nRootPathLen, nPathLen);
|
|
szPath[nPathLen - (nPathLen > 1 && szPath[nPathLen - 1] == '/' ? 1 : 0)] = (char)NULL;
|
|
|
|
string sPath = PathDecode(szPath).c_str();
|
|
pshflp->pshf->path = new char[sPath.length() + 1];
|
|
strcpy(pshflp->pshf->path, sPath.c_str());
|
|
}
|
|
else {
|
|
pshflp->pshf->path = new char[PATH_SIZE];
|
|
strcpy(pshflp->pshf->path, "*myself*");
|
|
}
|
|
}
|
|
break;
|
|
case SHFLTAG_TYPE:
|
|
break;
|
|
case SHFLTAG_SIZE:
|
|
if (isdigit(data[0])) {
|
|
char szSize[20];
|
|
memcpy(szSize, data, len);
|
|
szSize[len] = (char)NULL;
|
|
|
|
pshflp->pshf->size = sh_atoi(szSize);
|
|
}
|
|
break;
|
|
case SHFLTAG_LASTMODIFIED:
|
|
if (!pshflp->pshf->lastModified) {
|
|
char szTime[30];
|
|
memcpy(szTime, data, len);
|
|
szTime[len] = (char)NULL;
|
|
|
|
string sTime = FormatLastModified(szTime);
|
|
pshflp->pshf->lastModified = new char[sTime.length() + 1];
|
|
pshflp->pshf->lastModified_gmt = new char[sizeof(szTime)];
|
|
strcpy(pshflp->pshf->lastModified_gmt,szTime);
|
|
strcpy(pshflp->pshf->lastModified, sTime.c_str());
|
|
}
|
|
break;
|
|
case SHFLTAG_SOURCE:
|
|
if (!pshflp->pshf->source) {
|
|
char szSource[PATH_SIZE];
|
|
memcpy(szSource, data, len);
|
|
szSource[len] = (char)NULL;
|
|
|
|
pshflp->pshf->source = new char[strlen(szSource) + 1];
|
|
strcpy(pshflp->pshf->source, szSource);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int FileListETagParser(void *userdata, int state, const char *nspace, const char *name)
|
|
{
|
|
PSHFILELIST_PARSER_STRUCT pshflp = (PSHFILELIST_PARSER_STRUCT)userdata;
|
|
|
|
if (strcmp(name, "response") == 0) {
|
|
if (pshflp->pshf) {
|
|
pshflp->pvec->push_back(pshflp->pshf);
|
|
}
|
|
|
|
pshflp->pshf = NULL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void FreeFileListVector(PVECTOR_SHFILELIST pvec)
|
|
{
|
|
for (VECTOR_SHFILELIST::iterator iter = pvec->begin(); iter != pvec->end(); iter++) {
|
|
PSHFILE_STRUCT pshf = (*iter);
|
|
delete []pshf->path;
|
|
delete []pshf->lastModified;
|
|
delete []pshf->lastModified_gmt;
|
|
delete []pshf->source;
|
|
delete pshf;
|
|
}
|
|
|
|
pvec->clear();
|
|
delete pvec;
|
|
}
|
|
|
|
static bool DoCommand(PSHCSDK_STRUCT psdk, LPCSTR pszMethod, LPCSTR pszPath, LPCSTR pszHeaders, LPCSTR pszBody,
|
|
bool bParseBody, LPVOID pSTagParser, LPVOID pDataParser, LPVOID pETagParser, LPVOID pParam,int nFrom)
|
|
{
|
|
bool bRet = false;
|
|
int nRet;
|
|
string sBody;
|
|
ne_status* pnstat;
|
|
string sAuth;
|
|
|
|
#ifdef _NEWAUTH
|
|
char* pszAuth = NULL;
|
|
#endif
|
|
|
|
ne_request *pnreq = ne_request_create(psdk->pnsess, pszMethod, PathEncode(pszPath).c_str());
|
|
if (!pnreq) {
|
|
psdk->nError = SHCERRNO_UNDEFINED;
|
|
psdk->sError = ne_get_error(psdk->pnsess);
|
|
goto EXIT_DOCOMMAND;
|
|
}
|
|
|
|
#ifdef _NEWAUTH
|
|
pszAuth = get_auth_str(psdk,pszPath, nFrom);
|
|
|
|
ne_add_request_header(pnreq, "Authorization",pszAuth);
|
|
#else // _SP_SDK_
|
|
ne_add_request_header(pnreq, "Authorization", psdk->sAuth.c_str());
|
|
#endif
|
|
|
|
ne_add_request_header(pnreq, "Cache-Control", "no-cache");
|
|
|
|
if (pszHeaders && strlen(pszHeaders) > 0) {
|
|
string sHeaders = pszHeaders;
|
|
|
|
string::size_type stBegin = 0, stEnd = 0;
|
|
do {
|
|
stEnd = sHeaders.find(',', stBegin);
|
|
|
|
string sHeader = sHeaders.substr(stBegin, stEnd - stBegin);
|
|
|
|
string::size_type stDivider = sHeader.find('|');
|
|
ne_add_request_header(pnreq, sHeader.substr(0, stDivider).c_str(), sHeader.substr(stDivider + 1, sHeader.length()).c_str());
|
|
|
|
stBegin = stEnd + 1;
|
|
} while (stEnd != string::npos);
|
|
}
|
|
|
|
if (pszBody && strlen(pszBody) > 0)
|
|
ne_set_request_body_buffer(pnreq, pszBody, strlen(pszBody));
|
|
|
|
if (bParseBody)
|
|
ne_add_response_body_reader(pnreq, ne_accept_2xx, ResponseBodyReader, &sBody);
|
|
|
|
nRet = ne_request_dispatch(pnreq);
|
|
|
|
if (nRet != NE_OK) {
|
|
psdk->nError = nRet;
|
|
psdk->sError = ne_get_error(psdk->pnsess);
|
|
goto EXIT_DOCOMMAND;
|
|
}
|
|
|
|
pnstat = (ne_status*)ne_get_status(pnreq);
|
|
if (pnstat->code != 0 && (pnstat->code < 200 || pnstat->code >= 300)) {
|
|
psdk->nError = pnstat->code;
|
|
psdk->sError = ne_get_error(psdk->pnsess);
|
|
goto EXIT_DOCOMMAND;
|
|
}
|
|
|
|
if (bParseBody) {
|
|
ReplaceAll(sBody, "&", "*amp;");
|
|
|
|
ne_xml_parser* pnxparser = ne_xml_create();
|
|
ne_xml_push_handler(pnxparser, (ne_xml_startelm_cb*)pSTagParser, (ne_xml_cdata_cb*)pDataParser, (ne_xml_endelm_cb*)pETagParser, pParam);
|
|
ne_xml_parse(pnxparser, sBody.c_str(), sBody.length());
|
|
ne_xml_destroy(pnxparser);
|
|
}
|
|
|
|
bRet = true;
|
|
|
|
EXIT_DOCOMMAND:
|
|
switch (psdk->nError) {
|
|
case 400:
|
|
psdk->nError = SHCERRNO_SERVICE;
|
|
break;
|
|
case 401:
|
|
psdk->nError = SHCERRNO_AUTHORIZATION;
|
|
break;
|
|
case 403:
|
|
psdk->nError = SHCERRNO_SERVICE;
|
|
break;
|
|
case 404:
|
|
psdk->sRedirect = ne_get_response_header(pnreq, "Redirect") != NULL ? ne_get_response_header(pnreq, "Redirect") : "";
|
|
psdk->nError = SHCERRNO_NOEXISTSFILE;
|
|
break;
|
|
case 500:
|
|
psdk->nError = SHCERRNO_SERVICE;
|
|
break;
|
|
case NE_TIMEOUT:
|
|
psdk->nError = SHCERRNO_RESP_TIMEOUT;
|
|
break;
|
|
case NE_LOOKUP:
|
|
psdk->nError = SHCERRNO_NE_LOOKUP;
|
|
break;
|
|
case NE_CONNECT:
|
|
psdk->nError = SHCERRNO_NE_CONNECT;
|
|
break;
|
|
}
|
|
|
|
if (pnreq)
|
|
ne_request_destroy(pnreq);
|
|
|
|
#ifdef _NEWAUTH
|
|
//pizon
|
|
//fprintf(stderr , "pszAuth:%s:%p:\n" , pszAuth , pszAuth);
|
|
if(pszAuth)
|
|
free(pszAuth);
|
|
#endif
|
|
|
|
sBody.clear();
|
|
return bRet;
|
|
}
|
|
|
|
static bool DoUploaduffer(PSHCSDK_STRUCT psdk, LPCSTR dstPath, int nWritePolicy,
|
|
//up_stream data_func,
|
|
ssize_t (*data_func)(
|
|
void* userval,
|
|
char* buf,
|
|
size_t len
|
|
),
|
|
INT64 beginset, // point to write
|
|
INT64 nbytes, // amount to write
|
|
void* userval, // User-supplied value for callback
|
|
int nFrom)
|
|
{
|
|
bool ret = false;
|
|
|
|
// 현재 URI 보관
|
|
bool bFindSource = true;
|
|
bool bSessionChange = false;
|
|
ne_uri nuri = psdk->nuri;
|
|
string strAuth;
|
|
|
|
// 업로드 코드 시작
|
|
string sPath = psdk->sPath + dstPath;
|
|
string sHeaders;
|
|
int nRet;
|
|
|
|
ne_request *pnreq = NULL;
|
|
|
|
psdk->nError = 0; //setting NOERROR
|
|
#ifdef _NEWAUTH
|
|
char* pszAuth = get_auth_str(psdk,sPath.c_str(),nFrom);
|
|
#endif
|
|
|
|
sPath = PathEncode(sPath.c_str());
|
|
|
|
if(data_func == NULL) {
|
|
goto EXIT_DOUPLOADUFFER;
|
|
}
|
|
|
|
// write total size
|
|
psdk->nFileSize = nbytes;
|
|
|
|
// check policy
|
|
if (nWritePolicy == SHWRITEPOLICY_OVERWRITE) {
|
|
PVECTOR_SHFILELIST pvec = (PVECTOR_SHFILELIST)sh_get_filelist((HSHSDK)psdk, dstPath, 0);
|
|
if (pvec && pvec->size() > 0) {
|
|
sh_free_filelist((HSHSDK)psdk, (HSHFILELIST)pvec);
|
|
|
|
if (!sh_delete((HSHSDK)psdk, dstPath)) {
|
|
// delete fail
|
|
goto EXIT_DOUPLOADUFFER;
|
|
}
|
|
} else {
|
|
if(psdk->nError != 0 && psdk->nError != SHCERRNO_NOEXISTSFILE)
|
|
goto EXIT_DOUPLOADUFFER;
|
|
}
|
|
|
|
if (pvec)
|
|
sh_free_filelist((HSHSDK)psdk, (HSHFILELIST)pvec);
|
|
|
|
} else if (nWritePolicy == SHWRITEPOLICY_APPEND) {
|
|
PVECTOR_SHFILELIST pvec = (PVECTOR_SHFILELIST)sh_get_filelist((HSHSDK)psdk, dstPath, 0);
|
|
if (pvec && pvec->size() > 0) {
|
|
PSHFILE_STRUCT pshf = sh_get_file((HSHSDK)psdk, (HSHFILELIST)pvec, 0);
|
|
|
|
char szRange[100];
|
|
INT64 startpos, endpos;
|
|
startpos = (beginset >= 0 ? beginset : pshf->size);
|
|
endpos = startpos + psdk->nFileSize;
|
|
#ifdef WIN32
|
|
sprintf(szRange, "bytes %I64d-%I64d/%I64d", startpos, endpos - 1, endpos);
|
|
#else // !WIN32
|
|
sprintf(szRange, "bytes %lld-%lld/%lld", startpos, endpos - 1, endpos);
|
|
#endif // WIN32
|
|
sHeaders = "Content-Range|";
|
|
sHeaders += szRange;
|
|
|
|
if (pshf->source && strlen(pshf->source) > 7) {
|
|
bSessionChange = true;
|
|
solbox_session_destroy(psdk);
|
|
|
|
solbox_uri_parse(pshf->source, &psdk->nuri);
|
|
|
|
if (psdk->nuri.path)
|
|
free(psdk->nuri.path);
|
|
psdk->nuri.path = strdup("/dav");
|
|
|
|
if (!psdk->nuri.scheme)
|
|
psdk->nuri.scheme = strdup("http");
|
|
|
|
if (psdk->nuri.port == 0)
|
|
psdk->nuri.port = 80;
|
|
|
|
if( solbox_session_create(psdk) == false )
|
|
{
|
|
psdk->nError = SHCERRNO_DNS_TIMEOUT;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
goto EXIT_DOUPLOADUFFER;
|
|
}
|
|
psdk->sPath = psdk->nuri.path;
|
|
}
|
|
|
|
bFindSource = false;
|
|
}
|
|
|
|
if (pvec)
|
|
sh_free_filelist((HSHSDK)psdk, (HSHFILELIST)pvec);
|
|
} else {
|
|
PVECTOR_SHFILELIST pvec = (PVECTOR_SHFILELIST)sh_get_filelist((HSHSDK)psdk, dstPath, 0);
|
|
if (pvec && pvec->size() > 0) {
|
|
sh_free_filelist((HSHSDK)psdk, (HSHFILELIST)pvec);
|
|
|
|
psdk->nError = SHCERRNO_EXISTSFILE;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
goto EXIT_DOUPLOADUFFER;
|
|
}
|
|
|
|
if (pvec)
|
|
sh_free_filelist((HSHSDK)psdk, (HSHFILELIST)pvec);
|
|
}
|
|
|
|
// change session
|
|
if (bFindSource) {
|
|
for (int i = 0; !bSessionChange && i < MAX_TRY; i++) {
|
|
PVECTOR_SHFILELIST pvec = (PVECTOR_SHFILELIST)sh_get_filelist((HSHSDK)psdk, dstPath, 0);
|
|
if (pvec && pvec->size() > 0) {
|
|
sh_free_filelist((HSHSDK)psdk, (HSHFILELIST)pvec);
|
|
|
|
psdk->nError = SHCERRNO_EXISTSFILE;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
goto EXIT_DOUPLOADUFFER;
|
|
}
|
|
|
|
if (pvec)
|
|
sh_free_filelist((HSHSDK)psdk, (HSHFILELIST)pvec);
|
|
|
|
if (psdk->sRedirect == "")
|
|
break;
|
|
|
|
if (i > 0)
|
|
ne_uri_free(&psdk->nuri);
|
|
|
|
bSessionChange = true;
|
|
solbox_session_destroy(psdk);
|
|
|
|
solbox_uri_parse(psdk->sRedirect.c_str(), &psdk->nuri);
|
|
|
|
if (!psdk->nuri.scheme)
|
|
psdk->nuri.scheme = strdup("http");
|
|
|
|
if (psdk->nuri.port == 0)
|
|
psdk->nuri.port = 80;
|
|
|
|
if( solbox_session_create(psdk) == false )
|
|
{
|
|
psdk->nError = SHCERRNO_DNS_TIMEOUT;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
goto EXIT_DOUPLOADUFFER;
|
|
}
|
|
psdk->sPath = psdk->nuri.path;
|
|
|
|
if (i == (MAX_TRY - 1)) {
|
|
sHeaders = "Force|YES";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// put request
|
|
pnreq = ne_request_create(psdk->pnsess, "PUT", sPath.c_str());
|
|
if (!pnreq) {
|
|
psdk->nError = SHCERRNO_UNDEFINED;
|
|
psdk->sError = ne_get_error(psdk->pnsess);
|
|
goto EXIT_DOUPLOADUFFER;
|
|
}
|
|
|
|
#ifdef _NEWAUTH
|
|
strAuth = "Basic ";
|
|
strAuth += psdk->sAuth;
|
|
|
|
ne_add_request_header(pnreq, "Authorization", strAuth.c_str());
|
|
#else // _SP_SDK_
|
|
ne_add_request_header(pnreq, "Authorization", psdk->sAuth.c_str());
|
|
#endif
|
|
|
|
if (sHeaders.length() > 0) {
|
|
string::size_type stBegin = 0, stEnd = 0;
|
|
do {
|
|
stEnd = sHeaders.find(',', stBegin);
|
|
|
|
string sHeader = sHeaders.substr(stBegin, stEnd - stBegin);
|
|
|
|
string::size_type stDivider = sHeader.find('|');
|
|
ne_add_request_header(pnreq, sHeader.substr(0, stDivider).c_str(), sHeader.substr(stDivider + 1, sHeader.length()).c_str());
|
|
|
|
stBegin = stEnd + 1;
|
|
} while (stEnd != string::npos);
|
|
}
|
|
|
|
INT64 body_size;
|
|
if (beginset > 0) {
|
|
body_size = psdk->nFileSize - beginset;
|
|
} else {
|
|
body_size = psdk->nFileSize;
|
|
}
|
|
|
|
ne_set_request_body_provider(pnreq, psdk->nFileSize - psdk->iFilePos, data_func, userval);
|
|
|
|
nRet = ne_request_dispatch(pnreq);
|
|
|
|
if (psdk->nTranStop == SHSTOP_NO) {
|
|
if (nRet != NE_OK) {
|
|
psdk->nError = nRet;
|
|
psdk->sError = ne_get_error(psdk->pnsess);
|
|
goto EXIT_DOUPLOADUFFER;
|
|
}
|
|
|
|
ne_status* pnstat = (ne_status*)ne_get_status(pnreq);
|
|
if (pnstat->code != 0 && (pnstat->code < 200 || pnstat->code >= 300)) {
|
|
psdk->nError = pnstat->code;
|
|
psdk->sError = ne_get_error(psdk->pnsess);
|
|
goto EXIT_DOUPLOADUFFER;
|
|
}
|
|
}
|
|
ne_end_request(pnreq);
|
|
|
|
ret = true;
|
|
|
|
EXIT_DOUPLOADUFFER:
|
|
|
|
switch (psdk->nError) {
|
|
case 404:
|
|
psdk->nError = SHCERRNO_NOEXISTSFILE;
|
|
break;
|
|
}
|
|
|
|
#ifdef _NEWAUTH
|
|
if(pszAuth) {
|
|
free(pszAuth);
|
|
pszAuth =NULL;
|
|
}
|
|
#endif // _NEWAUTH
|
|
|
|
if (pnreq)
|
|
ne_request_destroy(pnreq);
|
|
|
|
if (bSessionChange) {
|
|
// CHG : dadamin / 2010.12.16 - Redirection 실패 시 최초에 받은 uri 정보로 환원함.
|
|
// 이처럼 변경하는 이유는 신규(2010.12.16) 개발될 SDK에서는 대표 URI를 사용하지 않고
|
|
// dns resolve해서 나온 IP 하나만 사용하기 때문에 301로 연결 성공한 정보를 그대로 사용함.
|
|
if( ret == false )
|
|
{
|
|
solbox_session_destroy(psdk);
|
|
ne_uri_free(&psdk->nuri);
|
|
psdk->nuri = nuri;
|
|
if( solbox_session_create(psdk) == false )
|
|
{
|
|
// 바로 리턴하기때문에 후처리는 하지 않아도 된다.
|
|
psdk->nError = SHCERRNO_DNS_TIMEOUT;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
}
|
|
psdk->sPath = "/dav";
|
|
}
|
|
else
|
|
{
|
|
psdk->sPath = "/dav";
|
|
ne_uri_free(&nuri);
|
|
}
|
|
}
|
|
|
|
#ifdef WIN32
|
|
CString strTemp;
|
|
strTemp.Format("UploadBuffer %s : %s : %d", ret ? "SUCCESS" : "ERROR", dstPath, psdk->nError);
|
|
OutputDebugString(strTemp);
|
|
#endif // WIN32
|
|
|
|
return ret;
|
|
}
|
|
|
|
static bool DoUpload(PSHCSDK_STRUCT psdk, LPCSTR pszSrcFile, LPCSTR pszDstFile, int nWritePolicy, INT64 nAvailQuota,int nFrom, LPCSTR extSession)
|
|
{
|
|
// 현재 URI 보관
|
|
bool bFindSource = true;
|
|
bool bSessionChange = false;
|
|
ne_uri nuri = psdk->nuri;
|
|
string strAuth;
|
|
|
|
// 업로드 코드 시작
|
|
string sPath = psdk->sPath + pszDstFile;
|
|
string sHeaders;
|
|
int nRet;
|
|
|
|
ne_request *pnreq = NULL;
|
|
|
|
bool bResult = false;
|
|
|
|
psdk->nError = 0; // setting NOERROR
|
|
#ifdef _NEWAUTH
|
|
char* pszAuth = get_auth_str(psdk,sPath.c_str(),nFrom);
|
|
#endif
|
|
|
|
sPath = PathEncode(sPath.c_str());
|
|
|
|
#ifdef WIN32
|
|
psdk->hFile = CreateFile(pszSrcFile,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
|
|
#else
|
|
psdk->nFileDesc = open64(pszSrcFile, _O_RDONLY | _O_BINARY | _O_RANDOM);
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
if (psdk->hFile == INVALID_HANDLE_VALUE){
|
|
#else
|
|
if (psdk->nFileDesc == -1) {
|
|
#endif
|
|
psdk->nError = GetLastError();
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
goto EXIT_DOUPLOAD;
|
|
}
|
|
|
|
#ifdef WIN32
|
|
LARGE_INTEGER filesize;
|
|
filesize.QuadPart = 0;
|
|
filesize.LowPart = SetFilePointer(psdk->hFile, filesize.LowPart, &filesize.HighPart, FILE_END);
|
|
psdk->nFileSize = filesize.QuadPart;
|
|
SetFilePointer(psdk->hFile,0, 0, FILE_BEGIN);
|
|
#else
|
|
psdk->nFileSize = sh_filelength(psdk->nFileDesc);
|
|
#endif
|
|
|
|
if (psdk->nFileSize == -1L) {
|
|
psdk->nError = GetLastError();
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
goto EXIT_DOUPLOAD;
|
|
}
|
|
|
|
if (nWritePolicy == SHWRITEPOLICY_OVERWRITE) {
|
|
PVECTOR_SHFILELIST pvec = (PVECTOR_SHFILELIST)sh_get_filelist((HSHSDK)psdk, pszDstFile, 0);
|
|
if (pvec && pvec->size() > 0) {
|
|
sh_free_filelist((HSHSDK)psdk, (HSHFILELIST)pvec);
|
|
|
|
if (!sh_delete((HSHSDK)psdk, pszDstFile))
|
|
{
|
|
goto EXIT_DOUPLOAD;
|
|
}
|
|
} else {
|
|
if( psdk->nError != 0 && psdk->nError != SHCERRNO_NOEXISTSFILE )
|
|
goto EXIT_DOUPLOAD;
|
|
}
|
|
/* Elenoa ADD START */
|
|
if (pvec)
|
|
sh_free_filelist((HSHSDK)psdk, (HSHFILELIST)pvec);
|
|
/* Elenoa ADD END */
|
|
}
|
|
else if (nWritePolicy == SHWRITEPOLICY_APPEND)
|
|
{
|
|
PVECTOR_SHFILELIST pvec = (PVECTOR_SHFILELIST)sh_get_filelist((HSHSDK)psdk, pszDstFile, 0);
|
|
if (pvec && pvec->size() > 0)
|
|
{
|
|
PSHFILE_STRUCT pshf = sh_get_file((HSHSDK)psdk, (HSHFILELIST)pvec, 0);
|
|
|
|
// CHG : dadamin / 2011.01.05 - 대상 파일이 동일하거나 더 큰 경우 에러 처리함
|
|
if (psdk->nFileSize <= pshf->size)
|
|
{
|
|
sh_free_filelist((HSHSDK)psdk, (HSHFILELIST)pvec);
|
|
bResult = false;
|
|
psdk->nError = SHCERRNO_TRAGETBIGGER;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
goto EXIT_DOUPLOAD;
|
|
}
|
|
|
|
#ifdef WIN32
|
|
// Windows Large file
|
|
LARGE_INTEGER li;
|
|
li.QuadPart = pshf->size;
|
|
|
|
li.LowPart = SetFilePointer(psdk->hFile,li.LowPart, &li.HighPart, FILE_BEGIN);
|
|
psdk->iFilePos = li.QuadPart;
|
|
#else
|
|
psdk->iFilePos = _lseeki64(psdk->nFileDesc, pshf->size, SEEK_SET);
|
|
#endif
|
|
if (psdk->iFilePos == -1L) {
|
|
sh_free_filelist((HSHSDK)psdk, (HSHFILELIST)pvec);
|
|
goto EXIT_DOUPLOAD;
|
|
}
|
|
|
|
char szRange[100];
|
|
#ifdef WIN32
|
|
sprintf(szRange, "bytes %I64d-%I64d/%I64d", psdk->iFilePos, psdk->nFileSize - 1, psdk->nFileSize);
|
|
#else
|
|
sprintf(szRange, "bytes %lld-%lld/%lld", psdk->iFilePos, psdk->nFileSize - 1, psdk->nFileSize);
|
|
#endif
|
|
|
|
sHeaders = "Content-Range|";
|
|
sHeaders += szRange;
|
|
|
|
if (pshf->source && strlen(pshf->source) > 7) {
|
|
bSessionChange = true;
|
|
solbox_session_destroy(psdk);
|
|
|
|
// CHG : dadamin / 2010.12.15 버전UP(0.29.5)에 따른 ne_uri_parse 하위 호환성 결로 발생한 문제 수정
|
|
solbox_uri_parse(pshf->source, &psdk->nuri);
|
|
|
|
if (psdk->nuri.path)
|
|
free(psdk->nuri.path);
|
|
psdk->nuri.path = strdup("/dav");
|
|
|
|
if (!psdk->nuri.scheme)
|
|
psdk->nuri.scheme = strdup("http");
|
|
|
|
if (psdk->nuri.port == 0)
|
|
psdk->nuri.port = 80;
|
|
|
|
if( solbox_session_create(psdk) == false )
|
|
{
|
|
psdk->nError = SHCERRNO_DNS_TIMEOUT;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
goto EXIT_DOUPLOAD;
|
|
}
|
|
psdk->sPath = psdk->nuri.path;
|
|
}
|
|
|
|
bFindSource = false;
|
|
}
|
|
sh_free_filelist((HSHSDK)psdk, (HSHFILELIST)pvec);
|
|
}
|
|
else {
|
|
PVECTOR_SHFILELIST pvec = (PVECTOR_SHFILELIST)sh_get_filelist((HSHSDK)psdk, pszDstFile, 0);
|
|
if (pvec && pvec->size() > 0) {
|
|
sh_free_filelist((HSHSDK)psdk, (HSHFILELIST)pvec);
|
|
|
|
psdk->nError = SHCERRNO_EXISTSFILE;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
goto EXIT_DOUPLOAD;
|
|
}
|
|
/* Elenoa ADD START */
|
|
if (pvec)
|
|
sh_free_filelist((HSHSDK)psdk, (HSHFILELIST)pvec);
|
|
/* Elenoa ADD END */
|
|
}
|
|
|
|
if ((UINT64)nAvailQuota < (UINT64)(psdk->nFileSize - psdk->iFilePos)) {
|
|
psdk->nError = SHCERRNO_NOAVAILQUOTA;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
goto EXIT_DOUPLOAD;
|
|
}
|
|
|
|
if (bFindSource) {
|
|
for (int i = 0; !bSessionChange && i < MAX_TRY; i++) {
|
|
PVECTOR_SHFILELIST pvec = (PVECTOR_SHFILELIST)sh_get_filelist((HSHSDK)psdk, pszDstFile, 0);
|
|
if (pvec && pvec->size() > 0) {
|
|
sh_free_filelist((HSHSDK)psdk, (HSHFILELIST)pvec);
|
|
|
|
psdk->nError = SHCERRNO_EXISTSFILE;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
goto EXIT_DOUPLOAD;
|
|
}
|
|
/* Elenoa ADD START */
|
|
if (pvec)
|
|
sh_free_filelist((HSHSDK)psdk, (HSHFILELIST)pvec);
|
|
/* Elenoa ADD END */
|
|
|
|
if (psdk->sRedirect == "")
|
|
break;
|
|
|
|
if (i > 0)
|
|
ne_uri_free(&psdk->nuri);
|
|
|
|
bSessionChange = true;
|
|
solbox_session_destroy(psdk);
|
|
|
|
// CHG : dadamin / 2010.12.15 버전UP(0.29.5)에 따른 ne_uri_parse 하위 호환성 결여로 발생한 문제 수정
|
|
solbox_uri_parse(psdk->sRedirect.c_str(), &psdk->nuri);
|
|
|
|
if (!psdk->nuri.scheme)
|
|
psdk->nuri.scheme = strdup("http");
|
|
|
|
if (psdk->nuri.port == 0)
|
|
psdk->nuri.port = 80;
|
|
|
|
if( solbox_session_create(psdk) == false )
|
|
{
|
|
psdk->nError = SHCERRNO_DNS_TIMEOUT;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
goto EXIT_DOUPLOAD;
|
|
}
|
|
psdk->sPath = psdk->nuri.path;
|
|
|
|
if (i == (MAX_TRY - 1)) {
|
|
sHeaders = "Force|YES";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
pnreq = ne_request_create(psdk->pnsess, "PUT", sPath.c_str());
|
|
if (!pnreq) {
|
|
psdk->nError = SHCERRNO_UNDEFINED;
|
|
psdk->sError = ne_get_error(psdk->pnsess);
|
|
goto EXIT_DOUPLOAD;
|
|
}
|
|
|
|
#ifdef _NEWAUTH
|
|
// 2011.06.02 : 업로드 시 신인증(auth timeout 체크) 체계로 수행할 경우
|
|
// body까지 전송 후에 관련 에러 받을 수 있으므로
|
|
// 관련 에러(401) 받기까지 시간 소요가 긴다.
|
|
// 또한, 재시도 로직으로 인해서 업로드를 이중으되어지는 문제도 있다.
|
|
// 그러므로, 업로드 관련 인증을 수행하지 않게 이전 인증체제를 사용한다.
|
|
strAuth = "Basic ";
|
|
strAuth += psdk->sAuth;
|
|
|
|
ne_add_request_header(pnreq, "Authorization", strAuth.c_str());
|
|
#else // _SP_SDK_
|
|
ne_add_request_header(pnreq, "Authorization", psdk->sAuth.c_str());
|
|
#endif
|
|
// toto
|
|
if ( extSession != NULL )
|
|
{
|
|
if ( strlen( extSession ) > 512)
|
|
{
|
|
psdk->nError = SHCERRNO_EXT_OVERFLOW;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
goto EXIT_DOUPLOAD;
|
|
}
|
|
ne_add_request_header(pnreq, "SB_ExtSession", extSession);
|
|
}
|
|
|
|
if (sHeaders.length() > 0) {
|
|
string::size_type stBegin = 0, stEnd = 0;
|
|
do {
|
|
stEnd = sHeaders.find(',', stBegin);
|
|
|
|
string sHeader = sHeaders.substr(stBegin, stEnd - stBegin);
|
|
|
|
string::size_type stDivider = sHeader.find('|');
|
|
ne_add_request_header(pnreq, sHeader.substr(0, stDivider).c_str(), sHeader.substr(stDivider + 1, sHeader.length()).c_str());
|
|
|
|
stBegin = stEnd + 1;
|
|
} while (stEnd != string::npos);
|
|
}
|
|
|
|
//dadamin : 32bit Large File Support / Simplify LFS support, drop *64 transition functions
|
|
ne_set_request_body_provider(pnreq, psdk->nFileSize - psdk->iFilePos, UploadProvider, psdk);
|
|
|
|
nRet = ne_request_dispatch(pnreq);
|
|
|
|
if (psdk->nTranStop == SHSTOP_NO) {
|
|
if (nRet != NE_OK) {
|
|
psdk->nError = nRet;
|
|
psdk->sError = ne_get_error(psdk->pnsess);
|
|
goto EXIT_DOUPLOAD;
|
|
}
|
|
|
|
ne_status* pnstat = (ne_status*)ne_get_status(pnreq);
|
|
if (pnstat->code != 0 && (pnstat->code < 200 || pnstat->code >= 300)) {
|
|
psdk->nError = pnstat->code;
|
|
psdk->sError = ne_get_error(psdk->pnsess);
|
|
goto EXIT_DOUPLOAD;
|
|
}
|
|
}
|
|
ne_end_request(pnreq);
|
|
|
|
bResult = true;
|
|
|
|
EXIT_DOUPLOAD:
|
|
switch (psdk->nError) {
|
|
case 404:
|
|
psdk->nError = SHCERRNO_NOEXISTSFILE;
|
|
break;
|
|
}
|
|
|
|
#ifdef _NEWAUTH
|
|
if(pszAuth)
|
|
free(pszAuth);
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
if(psdk->hFile != NULL)
|
|
{
|
|
CloseHandle(psdk->hFile);
|
|
psdk->hFile = NULL;
|
|
}
|
|
#else
|
|
if (psdk->nFileDesc != -1)
|
|
{
|
|
close(psdk->nFileDesc);
|
|
psdk->nFileDesc = -1;
|
|
}
|
|
#endif
|
|
|
|
if (pnreq)
|
|
ne_request_destroy(pnreq);
|
|
|
|
if (bSessionChange) {
|
|
// CHG : dadamin / 2010.12.16 - Redirection 실패 시 최초에 받은 uri 정보로 환원함.
|
|
// 이처럼 변경하는 이유는 신규(2010.12.16) 개발될 SDK에서는 대표 URI를 사용하지 않고
|
|
// dns resolve해서 나온 IP 하나만 사용하기 때문에 301로 연결 성공한 정보를 그대로 사용함.
|
|
if( bResult == false )
|
|
{
|
|
solbox_session_destroy(psdk);
|
|
ne_uri_free(&psdk->nuri);
|
|
psdk->nuri = nuri;
|
|
if( solbox_session_create(psdk) == false )
|
|
{
|
|
// 바로 리턴하기때문에 후처리는 하지 않아도 된다.
|
|
psdk->nError = SHCERRNO_DNS_TIMEOUT;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
}
|
|
psdk->sPath = "/dav";
|
|
}
|
|
else
|
|
{
|
|
psdk->sPath = "/dav";
|
|
ne_uri_free(&nuri);
|
|
}
|
|
}
|
|
#ifdef WIN32
|
|
CString strTemp;
|
|
strTemp.Format("Upload %s : %s : %d", bResult ? "SUCCESS" : "ERROR", pszDstFile, psdk->nError);
|
|
OutputDebugString(strTemp);
|
|
#endif
|
|
|
|
return bResult;
|
|
}
|
|
|
|
static bool DoDownloadBuffer(PSHCSDK_STRUCT psdk, LPCSTR pszSrcFile,
|
|
int (*data_func)(
|
|
void* userval,
|
|
const char* buf,
|
|
size_t len), // If len is zero the transfer is restarted from the begining
|
|
INT64 beginset, // point to read
|
|
INT64 nbytes, // amount to read
|
|
void* userval, // User-supplied value for callback
|
|
int nFrom)
|
|
{
|
|
string sPath = psdk->sPath + pszSrcFile;
|
|
string sHeaders;
|
|
PSHFILE_STRUCT pshf;
|
|
int nRet;
|
|
|
|
ne_request *pnreq = NULL;
|
|
char* pszAuth;
|
|
bool bResult = false;
|
|
|
|
ne_uri prvenuri = psdk->nuri;
|
|
char szrange[100] = {0};
|
|
REPEAT_FUNC:
|
|
|
|
#ifdef _NEWAUTH
|
|
pszAuth = get_auth_str(psdk,sPath.c_str(),nFrom);
|
|
#endif
|
|
|
|
sPath = PathEncode(sPath.c_str());
|
|
|
|
PVECTOR_SHFILELIST pvec = (PVECTOR_SHFILELIST)sh_get_filelist((HSHSDK)psdk, pszSrcFile, 0);
|
|
if (!pvec || pvec->size() == 0)
|
|
goto EXIT_DODOWNLOADBUFFER;
|
|
|
|
if(data_func == NULL)
|
|
goto EXIT_DODOWNLOADBUFFER;
|
|
|
|
pshf = sh_get_file((HSHSDK)psdk, (HSHFILELIST)pvec, 0);
|
|
|
|
pnreq = ne_request_create(psdk->pnsess, "GET", sPath.c_str());
|
|
if (!pnreq) {
|
|
psdk->nError = SHCERRNO_UNDEFINED;
|
|
psdk->sError = ne_get_error(psdk->pnsess);
|
|
goto EXIT_DODOWNLOADBUFFER;
|
|
}
|
|
|
|
#ifdef _NEWAUTH
|
|
ne_add_request_header(pnreq, "Authorization", pszAuth);
|
|
#else // _SP_SDK_
|
|
ne_add_request_header(pnreq, "Authorization", psdk->sAuth.c_str());
|
|
#endif
|
|
|
|
// make range get header
|
|
if(beginset > 0)
|
|
{
|
|
if(nbytes > 0)
|
|
{
|
|
sprintf(szrange,
|
|
#ifdef WIN32
|
|
"bytes=%I64d-%I64d",
|
|
#else
|
|
"bytes=%lld-%lld",
|
|
#endif
|
|
beginset, beginset + nbytes - 1);
|
|
}
|
|
else
|
|
{
|
|
sprintf(szrange,
|
|
#ifdef WIN32
|
|
"bytes=%I64d-%I64d",
|
|
#else
|
|
"bytes=%lld-%lld",
|
|
#endif
|
|
beginset, pshf->size);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sprintf(szrange,
|
|
#ifdef WIN32
|
|
"bytes=%I64d-%I64d",
|
|
#else
|
|
"bytes=%lld-%lld",
|
|
#endif
|
|
psdk->iFilePos, pshf->size);
|
|
}
|
|
|
|
if (szrange[0] != '\0')
|
|
{
|
|
sHeaders += "Range|";
|
|
sHeaders += szrange;
|
|
sHeaders += ",Accept-Ranges|bytes";
|
|
}
|
|
|
|
if (sHeaders.length() > 0) {
|
|
string::size_type stBegin = 0, stEnd = 0;
|
|
do {
|
|
stEnd = sHeaders.find(',', stBegin);
|
|
|
|
string sHeader = sHeaders.substr(stBegin, stEnd - stBegin);
|
|
|
|
string::size_type stDivider = sHeader.find('|');
|
|
ne_add_request_header(pnreq, sHeader.substr(0, stDivider).c_str(), sHeader.substr(stDivider + 1, sHeader.length()).c_str());
|
|
|
|
stBegin = stEnd + 1;
|
|
} while (stEnd != string::npos);
|
|
}
|
|
|
|
ne_add_response_body_reader(pnreq, ne_accept_2xx, data_func, userval);
|
|
//psdk->nFileSize = pshf->size;
|
|
|
|
nRet = ne_request_dispatch(pnreq);
|
|
|
|
if (psdk->nTranStop == SHSTOP_NO) {
|
|
if (nRet != NE_OK) {
|
|
psdk->nError = nRet;
|
|
psdk->sError = ne_get_error(psdk->pnsess);
|
|
goto EXIT_DODOWNLOADBUFFER;
|
|
}
|
|
|
|
ne_status* pnstat = (ne_status*)ne_get_status(pnreq);
|
|
if (pnstat->code != 0 && (pnstat->code < 200 || pnstat->code >= 300)) {
|
|
psdk->nError = pnstat->code;
|
|
psdk->sError = ne_get_error(psdk->pnsess);
|
|
goto EXIT_DODOWNLOADBUFFER;
|
|
}
|
|
}
|
|
ne_end_request(pnreq);
|
|
|
|
bResult = true;
|
|
|
|
EXIT_DODOWNLOADBUFFER:
|
|
sh_free_filelist((HSHSDK)psdk, (HSHFILELIST)pvec);
|
|
|
|
#ifdef _NEWAUTH
|
|
if(pszAuth)
|
|
free(pszAuth);
|
|
#endif
|
|
|
|
string sRedirection;
|
|
if (pnreq) {
|
|
const char *pszLocation = ne_get_response_header(pnreq, "Location");
|
|
if (pszLocation)
|
|
sRedirection = pszLocation;
|
|
ne_request_destroy(pnreq);
|
|
}
|
|
|
|
// Redirection
|
|
if (psdk->nError == 301 && sRedirection != "") {
|
|
solbox_session_destroy(psdk);
|
|
|
|
// 지정된 곳으로 접속
|
|
ne_uri nuri;
|
|
// CHG : dadamin / 2010.12.15 버전UP(0.29.5)에 따른 ne_uri_parse 하위 호환성 결여로 발생한 문제 수정
|
|
solbox_uri_parse(sRedirection.c_str(), &nuri);
|
|
|
|
if (!nuri.scheme)
|
|
nuri.scheme = strdup("http");
|
|
|
|
if (nuri.port == 0)
|
|
nuri.port = 80;
|
|
|
|
psdk->sPath = nuri.path;
|
|
psdk->sPath.erase(psdk->sPath.find('/', 1), string::npos);
|
|
|
|
psdk->nuri = nuri;
|
|
|
|
if( solbox_session_create(psdk) == false )
|
|
{
|
|
ne_uri_free(&prvenuri);
|
|
psdk->nError = SHCERRNO_DNS_TIMEOUT;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
return false;
|
|
}
|
|
|
|
psdk->iFilePos = 0;
|
|
psdk->cOldTick = clock();
|
|
psdk->nTranStop = SHSTOP_NO;
|
|
bResult = DoDownloadBuffer(psdk, pszSrcFile, data_func, beginset, nbytes, userval, nFrom);
|
|
|
|
// CHG : dadamin / 2010.12.16 - Redirection 실패 시 최초에 받은 uri 정보로 환원함.
|
|
// 이처럼 변경하는 이유는 신규(2010.12.16) 개발될 SDK에서는 대표 URI를 사용하지 않고
|
|
// dns resolve해서 나온 IP 하나만 사용하기 때문에 301로 연결 성공한 정보를 그대로 사용함.
|
|
if(!bResult)
|
|
{
|
|
// 원래 서버로 재접속
|
|
solbox_session_destroy(psdk);
|
|
ne_uri_free(&psdk->nuri);
|
|
psdk->nuri = prvenuri;
|
|
if( solbox_session_create(psdk) == false )
|
|
{
|
|
psdk->nError = SHCERRNO_DNS_TIMEOUT;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
}
|
|
psdk->sPath = "/dav";
|
|
}
|
|
else
|
|
{
|
|
psdk->sPath = "/dav";
|
|
ne_uri_free(&prvenuri);
|
|
}
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
static bool DoDownload(PSHCSDK_STRUCT psdk, LPCSTR pszSrcFile, LPCSTR pszDstFile, int nWritePolicy, INT64 nAvailQuota,int nFrom, LPCSTR extSession)
|
|
{
|
|
string sPath = psdk->sPath + pszSrcFile;
|
|
string sHeaders;
|
|
PSHFILE_STRUCT pshf;
|
|
char* pszAuth;
|
|
|
|
ne_request *pnreq = NULL;
|
|
bool bResult = false;
|
|
int nFlag = 0;
|
|
#ifndef WIN32
|
|
mode_t mode;
|
|
#endif // !WIN32
|
|
#ifdef _NEWAUTH
|
|
pszAuth = get_auth_str(psdk,sPath.c_str(),nFrom);
|
|
#endif
|
|
|
|
sPath = PathEncode(sPath.c_str());
|
|
|
|
PVECTOR_SHFILELIST pvec = NULL;
|
|
struct _stati64 stDstFile;
|
|
int nRet = _stati64(pszDstFile, &stDstFile);
|
|
if (nWritePolicy == SHWRITEPOLICY_NONE) {
|
|
if (nRet != -1) {
|
|
psdk->nError = SHCERRNO_EXISTSFILE;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
goto EXIT_DODOWNLOAD;
|
|
}
|
|
}
|
|
else {
|
|
if (nRet != -1 && (stDstFile.st_mode & _S_IFDIR)) {
|
|
if (nWritePolicy == SHWRITEPOLICY_OVERWRITE) {
|
|
if (!DeleteDirectory(pszDstFile)) {
|
|
psdk->nError = GetLastError();
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
goto EXIT_DODOWNLOAD;
|
|
}
|
|
}
|
|
else {
|
|
psdk->nError = SHCERRNO_EXISTSFILE;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
}
|
|
}
|
|
}
|
|
|
|
pvec = (PVECTOR_SHFILELIST)sh_get_filelist((HSHSDK)psdk, pszSrcFile, 0);
|
|
if (!pvec || pvec->size() == 0)
|
|
{
|
|
goto EXIT_DODOWNLOAD;
|
|
}
|
|
|
|
#ifdef WIN32
|
|
nFlag=nWritePolicy;
|
|
switch (nWritePolicy)
|
|
{
|
|
case SHWRITEPOLICY_OVERWRITE:
|
|
case SHWRITEPOLICY_NONE :
|
|
nFlag = CREATE_ALWAYS;
|
|
break;
|
|
case SHWRITEPOLICY_APPEND:
|
|
nFlag = OPEN_ALWAYS;
|
|
break;
|
|
}
|
|
#else
|
|
nFlag = _O_CREAT | _O_WRONLY | _O_BINARY | _O_RANDOM;
|
|
switch (nWritePolicy)
|
|
{
|
|
case SHWRITEPOLICY_OVERWRITE: nFlag |= _O_TRUNC; break;
|
|
case SHWRITEPOLICY_APPEND: nFlag |= _O_APPEND; break;
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef WIN32
|
|
psdk->hFile = CreateFile(pszDstFile,GENERIC_WRITE,FILE_SHARE_READ,NULL,nFlag,FILE_ATTRIBUTE_NORMAL,NULL);
|
|
if (psdk->hFile == INVALID_HANDLE_VALUE) {
|
|
#else
|
|
// 일부 linux 계열(Ubuntu) mode 인자를 넣지 않고 O_CREAT를 수행할 수 없게 되어 있음.
|
|
mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; // 파일의 권한 0644
|
|
|
|
psdk->nFileDesc = open64(pszDstFile, nFlag, mode);
|
|
if (psdk->nFileDesc == -1L) {
|
|
#endif
|
|
psdk->nError = GetLastError();
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
goto EXIT_DODOWNLOAD;
|
|
}
|
|
|
|
pshf = sh_get_file((HSHSDK)psdk, (HSHFILELIST)pvec, 0);
|
|
|
|
#ifdef WIN32
|
|
LARGE_INTEGER li;
|
|
li.QuadPart = 0;
|
|
|
|
li.LowPart = SetFilePointer(psdk->hFile, li.LowPart, &li.HighPart, FILE_END);
|
|
psdk->iFilePos = li.QuadPart;
|
|
#else
|
|
psdk->iFilePos = _lseeki64(psdk->nFileDesc, 0, SEEK_END);
|
|
#endif
|
|
if (psdk->iFilePos == -1L)
|
|
{
|
|
psdk->nError = GetLastError();
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
goto EXIT_DODOWNLOAD;
|
|
}
|
|
|
|
if (pshf->size > 0 && psdk->iFilePos >= pshf->size)
|
|
{
|
|
bResult = false;
|
|
psdk->nError = SHCERRNO_TRAGETBIGGER;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
goto EXIT_DODOWNLOAD;
|
|
}
|
|
|
|
if (nWritePolicy == SHWRITEPOLICY_APPEND)
|
|
{
|
|
char szRange[100];
|
|
|
|
#ifdef WIN32
|
|
sprintf(szRange, "bytes=%I64d-%I64d", psdk->iFilePos, pshf->size);
|
|
#else
|
|
sprintf(szRange, "bytes=%lld-%lld", psdk->iFilePos, pshf->size);
|
|
#endif
|
|
sHeaders += "Range|";
|
|
sHeaders += szRange;
|
|
sHeaders += ",Accept-Ranges|bytes";
|
|
}
|
|
|
|
if ((UINT64)nAvailQuota < (UINT64)(pshf->size - psdk->iFilePos)) {
|
|
psdk->nError = SHCERRNO_NOAVAILQUOTA;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
goto EXIT_DODOWNLOAD;
|
|
}
|
|
|
|
pnreq = ne_request_create(psdk->pnsess, "GET", sPath.c_str());
|
|
if (!pnreq) {
|
|
psdk->nError = SHCERRNO_UNDEFINED;
|
|
psdk->sError = ne_get_error(psdk->pnsess);
|
|
goto EXIT_DODOWNLOAD;
|
|
}
|
|
|
|
#ifdef _NEWAUTH
|
|
ne_add_request_header(pnreq, "Authorization", pszAuth);
|
|
#else // _SP_SDK_
|
|
ne_add_request_header(pnreq, "Authorization", psdk->sAuth.c_str());
|
|
#endif
|
|
|
|
// toto
|
|
if ( extSession != NULL )
|
|
{
|
|
if ( strlen( extSession ) > 512)
|
|
{
|
|
psdk->nError = SHCERRNO_EXT_OVERFLOW;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
goto EXIT_DODOWNLOAD;
|
|
}
|
|
ne_add_request_header(pnreq, "SB_ExtSession", extSession);
|
|
}
|
|
|
|
if (sHeaders.length() > 0) {
|
|
string::size_type stBegin = 0, stEnd = 0;
|
|
do {
|
|
stEnd = sHeaders.find(',', stBegin);
|
|
|
|
string sHeader = sHeaders.substr(stBegin, stEnd - stBegin);
|
|
|
|
string::size_type stDivider = sHeader.find('|');
|
|
ne_add_request_header(pnreq, sHeader.substr(0, stDivider).c_str(), sHeader.substr(stDivider + 1, sHeader.length()).c_str());
|
|
|
|
stBegin = stEnd + 1;
|
|
} while (stEnd != string::npos);
|
|
}
|
|
|
|
ne_add_response_body_reader(pnreq, ne_accept_2xx, DownloadProvider, psdk);
|
|
psdk->nFileSize = pshf->size;
|
|
|
|
nRet = ne_request_dispatch(pnreq);
|
|
|
|
if (psdk->nTranStop == SHSTOP_NO) {
|
|
if (nRet != NE_OK) {
|
|
psdk->nError = nRet;
|
|
psdk->sError = ne_get_error(psdk->pnsess);
|
|
goto EXIT_DODOWNLOAD;
|
|
}
|
|
|
|
ne_status* pnstat = (ne_status*)ne_get_status(pnreq);
|
|
if (pnstat->code != 0 && (pnstat->code < 200 || pnstat->code >= 300)) {
|
|
psdk->nError = pnstat->code;
|
|
psdk->sError = ne_get_error(psdk->pnsess);
|
|
goto EXIT_DODOWNLOAD;
|
|
}
|
|
}
|
|
ne_end_request(pnreq);
|
|
|
|
bResult = true;
|
|
|
|
EXIT_DODOWNLOAD:
|
|
sh_free_filelist((HSHSDK)psdk, (HSHFILELIST)pvec);
|
|
|
|
#ifdef _NEWAUTH
|
|
if(pszAuth)
|
|
free(pszAuth);
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
if (psdk->hFile != NULL) {
|
|
CloseHandle(psdk->hFile);
|
|
psdk->hFile = NULL;
|
|
}
|
|
#else
|
|
if (psdk->nFileDesc) {
|
|
close(psdk->nFileDesc);
|
|
psdk->nFileDesc = -1;
|
|
}
|
|
#endif
|
|
|
|
string sRedirection;
|
|
if (pnreq) {
|
|
const char *pszLocation = ne_get_response_header(pnreq, "Location");
|
|
if (pszLocation)
|
|
sRedirection = pszLocation;
|
|
ne_request_destroy(pnreq);
|
|
}
|
|
|
|
ne_uri prvenuri;
|
|
// Redirection
|
|
if (psdk->nError == 301 && sRedirection != "") {
|
|
solbox_session_destroy(psdk);
|
|
|
|
// 지정된 곳으로 접속
|
|
ne_uri nuri;
|
|
// CHG : dadamin / 2010.12.15 버전UP(0.29.5)에 따른 ne_uri_parse 하위 호환성 결로 발생한 문제 수정
|
|
solbox_uri_parse(sRedirection.c_str(), &nuri);
|
|
|
|
if (!nuri.scheme)
|
|
nuri.scheme = strdup("http");
|
|
|
|
if (nuri.port == 0)
|
|
nuri.port = 80;
|
|
|
|
prvenuri = psdk->nuri;
|
|
|
|
psdk->sPath = nuri.path;
|
|
psdk->sPath.erase(psdk->sPath.find('/', 1), string::npos);
|
|
|
|
psdk->nuri = nuri;
|
|
|
|
if( solbox_session_create(psdk) == false )
|
|
{
|
|
ne_uri_free(&prvenuri);
|
|
psdk->nError = SHCERRNO_DNS_TIMEOUT;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
return false;
|
|
}
|
|
|
|
#ifdef WIN32
|
|
psdk->hFile = NULL;
|
|
#else
|
|
psdk->nFileDesc = -1;
|
|
#endif
|
|
psdk->iFilePos = 0;
|
|
psdk->cOldTick = clock();
|
|
psdk->nTranStop = SHSTOP_NO;
|
|
bResult = DoDownload(psdk, pszSrcFile, pszDstFile, nWritePolicy == SHWRITEPOLICY_NONE ? SHWRITEPOLICY_OVERWRITE : nWritePolicy, nAvailQuota,nFrom, extSession);
|
|
|
|
// 원래 서버로 재접속
|
|
// CHG : dadamin / 2010.12.16 - Redirection 실패 시 최초에 받은 uri 정보로 환원함.
|
|
// 이처럼 변경하는 이유는 신규(2010.12.16) 개발될 SDK에서는 대표 URI를 사용하지 않고
|
|
// dns resolve해서 나온 IP 하나만 사용하기 때문에 301로 연결 성공한 정보를 그대로 사용함.
|
|
if( bResult == false )
|
|
{
|
|
solbox_session_destroy(psdk);
|
|
ne_uri_free(&psdk->nuri);
|
|
psdk->nuri = prvenuri;
|
|
if( solbox_session_create(psdk) == false )
|
|
{
|
|
psdk->nError = SHCERRNO_DNS_TIMEOUT;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
}
|
|
psdk->sPath = "/dav";
|
|
}
|
|
else
|
|
{
|
|
psdk->sPath = "/dav";
|
|
ne_uri_free(&prvenuri);
|
|
}
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
// interfal function
|
|
|
|
// output interface
|
|
WIN32DLL
|
|
HSHSDK sh_init(const char *url, const char *authString, sh_callback proc, void *param)
|
|
{
|
|
PSHCSDK_STRUCT psdk = new SHCSDK_STRUCT;
|
|
const ne_inet_addr** result;
|
|
int nResultCnt;
|
|
|
|
if (!psdk)
|
|
return NULL;
|
|
|
|
psdk->pnsess = NULL;
|
|
psdk->pvecshfl = NULL;
|
|
|
|
// neon.lib init...
|
|
if (ne_sock_init() != NE_OK)
|
|
return NULL;
|
|
|
|
// CHG : dadamin / 2010.12.15 버전UP(0.29.5)에 따른 ne_uri_parse 하위 호환성 결로 발생한 문제 수정
|
|
int nNeonRet = solbox_uri_parse(url, &psdk->nuri);
|
|
if (nNeonRet != NE_OK)
|
|
return NULL;
|
|
|
|
if (!psdk->nuri.scheme)
|
|
psdk->nuri.scheme = strdup("http");
|
|
|
|
if (psdk->nuri.port == 0)
|
|
psdk->nuri.port = 80;
|
|
|
|
|
|
if( solbox_session_create(psdk) == false )
|
|
{
|
|
psdk->nError = SHCERRNO_DNS_TIMEOUT;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
goto EXIT_SH_INIT;
|
|
}
|
|
|
|
if (!psdk->pnsess)
|
|
goto EXIT_SH_INIT;
|
|
|
|
|
|
// time out setting
|
|
ne_set_read_timeout(psdk->pnsess, _read_time_out);
|
|
ne_set_connect_timeout(psdk->pnsess, _connect_time_out);
|
|
// time out setting
|
|
|
|
psdk->sPath = psdk->nuri.path;
|
|
|
|
#ifdef _NEWAUTH
|
|
psdk->sAuth = authString;
|
|
#else // _SP_SDK_
|
|
psdk->sAuth = "Basic ";
|
|
psdk->sAuth += authString;
|
|
#endif
|
|
|
|
psdk->nError = 0;
|
|
psdk->sError = "";
|
|
|
|
psdk->proc = proc;
|
|
psdk->pParam = param;
|
|
|
|
psdk->bWorking = false;
|
|
|
|
psdk->sSessionID = DEFAULT_SESSIONID;
|
|
|
|
psdk->nAuthExpire = DEFAULT_EXPIRE_TIME;
|
|
|
|
#ifdef WIN32
|
|
psdk->hFile = NULL;
|
|
#else
|
|
psdk->nFileDesc = -1;
|
|
#endif
|
|
|
|
psdk->nTranStop = SHSTOP_NO;
|
|
|
|
psdk->starttick = GetTickCount();
|
|
|
|
psdk->nSpeedLimit = 0;
|
|
|
|
dwTransferd = 0;
|
|
return psdk;
|
|
|
|
EXIT_SH_INIT:
|
|
int nError = GetLastError();
|
|
|
|
ne_uri_free(&psdk->nuri);
|
|
|
|
if (psdk->pnsess)
|
|
solbox_session_destroy(psdk);
|
|
|
|
delete psdk;
|
|
|
|
SetLastError(nError);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
WIN32DLL int sh_set_sessionID(HSHSDK hshsdk,const char *pszID)
|
|
{
|
|
if(!hshsdk)
|
|
return FALSE;
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
|
|
psdk->sSessionID = pszID;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
WIN32DLL const char* sh_get_sessionID(HSHSDK hshsdk)
|
|
{
|
|
if(!hshsdk)
|
|
return FALSE;
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
|
|
return psdk->sSessionID.c_str();
|
|
}
|
|
|
|
WIN32DLL
|
|
void sh_free(HSHSDK hshsdk)
|
|
{
|
|
if (!hshsdk)
|
|
return;
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
|
|
for (set<PVECTOR_SHFILELIST>::iterator iter = psdk->setFileList.begin(); iter != psdk->setFileList.end(); iter++)
|
|
FreeFileListVector(*iter);
|
|
|
|
ne_uri_free(&psdk->nuri);
|
|
|
|
if (psdk->pnsess)
|
|
solbox_session_destroy(psdk);
|
|
|
|
dwTransferd = 0;
|
|
|
|
delete psdk;
|
|
}
|
|
|
|
WIN32DLL
|
|
int sh_get_error_number(HSHSDK hshsdk)
|
|
{
|
|
if (!hshsdk)
|
|
return SHCERRNO_INVALIDHDL;
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
|
|
return psdk->nError;
|
|
}
|
|
|
|
WIN32DLL
|
|
const char* sh_get_error_message(HSHSDK hshsdk)
|
|
{
|
|
if (!hshsdk)
|
|
return GetErrorMessage(SHCERRNO_INVALIDHDL).c_str();
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
|
|
return psdk->sError.c_str();
|
|
}
|
|
|
|
WIN32DLL
|
|
HSHFILELIST sh_get_filelist(HSHSDK hshsdk, const char* path, unsigned int depth)
|
|
{
|
|
if (!hshsdk)
|
|
return NULL;
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
psdk->nError = SHCERRNO_NOERROR;
|
|
|
|
string sPath = psdk->sPath;
|
|
if (path[0] != '/')
|
|
sPath += "/";
|
|
sPath += path;
|
|
|
|
char szDepth[10];
|
|
if (depth <= 1)
|
|
sprintf(szDepth, "%d", depth);
|
|
else
|
|
strcpy(szDepth, "infinity");
|
|
|
|
string sHeaders = "Depth|";
|
|
sHeaders += szDepth;
|
|
|
|
string sBody = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
|
|
sBody += "<D:propfind xmlns:D=\"DAV:\">";
|
|
sBody += "<D:prop>";
|
|
sBody += "<D:resourcetype/>";
|
|
sBody += "<D:getcontentlength/>";
|
|
sBody += "<D:getlastmodified/>";
|
|
sBody += "<D:source/>";
|
|
sBody += "</D:prop>";
|
|
sBody += "</D:propfind>";
|
|
|
|
SHFILELIST_PARSER_STRUCT shflp;
|
|
::memset(&shflp, 0, sizeof(SHFILELIST_PARSER_STRUCT));
|
|
|
|
shflp.nRootPathLen = (UINT)psdk->sPath.length();
|
|
|
|
shflp.pvec = new VECTOR_SHFILELIST;
|
|
if (shflp.pvec) {
|
|
if (DoCommand(psdk, "PROPFIND", sPath.c_str(), sHeaders.c_str(), sBody.c_str(), true,
|
|
(LPVOID)FileListSTagParser, (LPVOID)FileListDataParser, (LPVOID)FileListETagParser, &shflp,1))
|
|
{
|
|
psdk->setFileList.insert(shflp.pvec);
|
|
psdk->pvecshfl = shflp.pvec;
|
|
|
|
VECTOR_SHFILELIST::iterator iter = shflp.pvec->begin();
|
|
if (strcmp((*iter)->path, "*myself*") == 0)
|
|
strcpy((*iter)->path, sPath.substr(psdk->sPath.length(), string::npos).c_str());
|
|
}
|
|
else
|
|
{
|
|
if (psdk->nError == SHCERRNO_AUTHORIZATION)
|
|
{
|
|
if (DoCommand(psdk, "PROPFIND", sPath.c_str(), sHeaders.c_str(), sBody.c_str(), true,
|
|
(LPVOID)FileListSTagParser, (LPVOID)FileListDataParser, (LPVOID)FileListETagParser, &shflp,0))
|
|
{
|
|
psdk->setFileList.insert(shflp.pvec);
|
|
psdk->pvecshfl = shflp.pvec;
|
|
|
|
VECTOR_SHFILELIST::iterator iter = shflp.pvec->begin();
|
|
if (strcmp((*iter)->path, "*myself*") == 0)
|
|
strcpy((*iter)->path, sPath.substr(psdk->sPath.length(), string::npos).c_str());
|
|
}
|
|
else
|
|
{
|
|
FreeFileListVector(shflp.pvec);
|
|
shflp.pvec = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FreeFileListVector(shflp.pvec);
|
|
shflp.pvec = NULL;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
psdk->nError = GetLastError();
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
}
|
|
|
|
sPath.clear();
|
|
sBody.clear();
|
|
return shflp.pvec;
|
|
}
|
|
|
|
WIN32DLL
|
|
long sh_get_filelist_count(HSHSDK hshsdk, HSHFILELIST hshfl)
|
|
{
|
|
if (!hshsdk)
|
|
return -1;
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
psdk->nError = SHCERRNO_NOERROR;
|
|
|
|
if (!hshfl) {
|
|
psdk->nError = SHCERRNO_INVALIDFLHDL;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
return -1;
|
|
}
|
|
|
|
if (psdk->pvecshfl != hshfl) {
|
|
set<PVECTOR_SHFILELIST>::iterator iter = psdk->setFileList.find((PVECTOR_SHFILELIST)hshfl);
|
|
if (iter == psdk->setFileList.end()) {
|
|
psdk->nError = SHCERRNO_INVALIDFLHDL;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
return -1;
|
|
}
|
|
|
|
psdk->pvecshfl = (*iter);
|
|
}
|
|
|
|
return (long)psdk->pvecshfl->size();
|
|
}
|
|
|
|
WIN32DLL
|
|
PSHFILE_STRUCT sh_get_file(HSHSDK hshsdk, HSHFILELIST hshfl, long index)
|
|
{
|
|
if (!hshsdk)
|
|
return NULL;
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
psdk->nError = SHCERRNO_NOERROR;
|
|
|
|
if (!hshfl) {
|
|
psdk->nError = SHCERRNO_INVALIDFLHDL;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
return NULL;
|
|
}
|
|
|
|
if (psdk->pvecshfl != hshfl) {
|
|
set<PVECTOR_SHFILELIST>::iterator iter = psdk->setFileList.find((PVECTOR_SHFILELIST)hshfl);
|
|
if (iter == psdk->setFileList.end()) {
|
|
psdk->nError = SHCERRNO_INVALIDFLHDL;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
return NULL;
|
|
}
|
|
|
|
psdk->pvecshfl = (*iter);
|
|
}
|
|
|
|
return psdk->pvecshfl->at(index);
|
|
}
|
|
|
|
WIN32DLL
|
|
void sh_free_filelist(HSHSDK hshsdk, HSHFILELIST hshfl)
|
|
{
|
|
if (!hshsdk || !hshfl)
|
|
return;
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
PVECTOR_SHFILELIST pvec = (PVECTOR_SHFILELIST)hshfl;
|
|
|
|
set<PVECTOR_SHFILELIST>::iterator iter = psdk->setFileList.find(pvec);
|
|
if (iter == psdk->setFileList.end())
|
|
return;
|
|
|
|
FreeFileListVector(pvec);
|
|
psdk->setFileList.erase(pvec);
|
|
|
|
psdk->pvecshfl = NULL;
|
|
}
|
|
|
|
WIN32DLL
|
|
int sh_make_directory(HSHSDK hshsdk, const char* directory)
|
|
{
|
|
if (!hshsdk)
|
|
return FALSE;
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
psdk->nError = 0;
|
|
|
|
if (sh_file_exist(hshsdk,directory))
|
|
{
|
|
psdk->nError = SHCERRNO_ALREADYEXIST;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
return false;
|
|
}
|
|
|
|
string sDirectory = psdk->sPath;
|
|
if (directory[0] != '/')
|
|
sDirectory += "/";
|
|
sDirectory += directory;
|
|
|
|
int nRet = DoCommand(psdk, "MKCOL", sDirectory.c_str(), "", "", false, NULL, NULL, NULL, NULL, 1);
|
|
|
|
if (!nRet)
|
|
{
|
|
if (sh_get_error_number(psdk) == SHCERRNO_AUTHORIZATION)
|
|
nRet = DoCommand(psdk, "MKCOL", sDirectory.c_str(),"","",false,NULL,NULL,NULL,NULL,0);
|
|
}
|
|
|
|
return nRet;
|
|
}
|
|
|
|
WIN32DLL
|
|
int sh_copy(HSHSDK hshsdk, const char* srcPath, const char* dstPath, int overwrite)
|
|
{
|
|
if (!hshsdk)
|
|
return FALSE;
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
psdk->nError = SHCERRNO_NOERROR;
|
|
|
|
string sSrcPath = psdk->sPath;
|
|
if (srcPath[0] != '/')
|
|
sSrcPath += "/";
|
|
sSrcPath += srcPath;
|
|
|
|
string sDstPath = psdk->sPath;
|
|
if (dstPath[0] != '/')
|
|
sDstPath += "/";
|
|
sDstPath += dstPath;
|
|
|
|
string sHeader = "New-uri|" + PathEncode(sDstPath.c_str()) + ",Overwrite|";
|
|
sHeader += (overwrite ? "T" : "F");
|
|
|
|
int nRet = DoCommand(psdk, "COPY", sSrcPath.c_str(), sHeader.c_str(),"", false, NULL, NULL, NULL, NULL, 1);
|
|
|
|
if (!nRet)
|
|
{
|
|
if (sh_get_error_number(psdk) == SHCERRNO_AUTHORIZATION)
|
|
nRet = DoCommand(psdk, "COPY", sSrcPath.c_str(), sHeader.c_str(),"",false,NULL,NULL,NULL,NULL,0);
|
|
}
|
|
|
|
return nRet;
|
|
}
|
|
|
|
WIN32DLL
|
|
int sh_move(HSHSDK hshsdk, const char* srcPath, const char* dstPath, int overwrite)
|
|
{
|
|
if (!hshsdk)
|
|
return FALSE;
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
psdk->nError = SHCERRNO_NOERROR;
|
|
|
|
string sSrcPath = psdk->sPath;
|
|
if (srcPath[0] != '/')
|
|
sSrcPath += "/";
|
|
sSrcPath += srcPath;
|
|
|
|
string sDstPath = psdk->sPath;
|
|
if (dstPath[0] != '/')
|
|
sDstPath += "/";
|
|
sDstPath += dstPath;
|
|
|
|
string sHeader = "New-uri|" + PathEncode(sDstPath.c_str()) + ",Overwrite|";
|
|
sHeader += (overwrite ? "T" : "F");
|
|
|
|
int nRet = DoCommand(psdk, "MOVE", sSrcPath.c_str(), sHeader.c_str(), "", false, NULL, NULL, NULL, NULL, 1);
|
|
|
|
if(!nRet)
|
|
{
|
|
if (sh_get_error_number(psdk) == SHCERRNO_AUTHORIZATION)
|
|
nRet = DoCommand(psdk, "MOVE", sSrcPath.c_str(), sHeader.c_str(),"",false,NULL,NULL,NULL,NULL,0);
|
|
}
|
|
return nRet;
|
|
}
|
|
|
|
WIN32DLL
|
|
int sh_delete(HSHSDK hshsdk, const char* path)
|
|
{
|
|
if (!hshsdk)
|
|
return FALSE;
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
psdk->nError = SHCERRNO_NOERROR;
|
|
|
|
int ncount=0;
|
|
|
|
// 경로가 '////////' 형식인경우
|
|
for(int i=0;i<strlen(path);i++)
|
|
{
|
|
if(path[i] == '/')
|
|
ncount++;
|
|
}
|
|
|
|
if (path == NULL || strlen(path) == 0 || (strlen(path) == 1 && path[0] == '/') || (ncount == strlen(path))) {
|
|
psdk->nError = SHCERRNO_SERVICE;
|
|
psdk->sError = "루트는 삭제할 수 없습니다.";
|
|
return FALSE;
|
|
}
|
|
|
|
string sPath = psdk->sPath;
|
|
if (path[0] != '/')
|
|
sPath += "/";
|
|
sPath += path;
|
|
|
|
int nRet = DoCommand(psdk, "DELETE", sPath.c_str(), "", "" , false, NULL, NULL, NULL, NULL, 1);
|
|
|
|
if (!nRet)
|
|
{
|
|
if (sh_get_error_number(psdk) == SHCERRNO_AUTHORIZATION)
|
|
nRet = DoCommand(psdk, "DELETE", sPath.c_str(),"","",false,NULL,NULL,NULL,NULL,0);
|
|
}
|
|
return nRet;
|
|
}
|
|
|
|
WIN32DLL
|
|
int sh_upload_buffer(
|
|
HSHSDK hshsdk, // SDK handle
|
|
const char *dstPath, // Destination file
|
|
int writePolicy, // Write policy flag
|
|
up_stream proc, // user defined function
|
|
INT64 nbytes, // write size
|
|
void* userval // User-supplied value for callback
|
|
) {
|
|
int ret = 0;
|
|
|
|
if (!hshsdk)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
psdk->nError = SHCERRNO_NOERROR;
|
|
|
|
if (psdk->bWorking) {
|
|
psdk->nError = SHCERRNO_ISBUSY;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
return ret;
|
|
}
|
|
|
|
#ifdef WIN32
|
|
psdk->hFile = NULL;
|
|
#else
|
|
psdk->nFileDesc = -1;
|
|
#endif
|
|
psdk->iFilePos = 0;
|
|
psdk->cOldTick = clock();
|
|
psdk->nTranStop = SHSTOP_NO;
|
|
|
|
ret = DoUploaduffer(psdk, dstPath, writePolicy, proc, 0, nbytes, userval, 1);
|
|
|
|
if (!ret)
|
|
{
|
|
switch( sh_get_error_number(psdk) )
|
|
{
|
|
case 401:
|
|
DoUploaduffer(psdk, dstPath, writePolicy, proc, 0, nbytes, userval, 0);
|
|
break;
|
|
case NE_LOOKUP:
|
|
// 2011.06.20 : DNS lookup 실패 시 1회 재시도
|
|
DoUploaduffer(psdk, dstPath, writePolicy, proc, 0, nbytes, userval, 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
WIN32DLL
|
|
int sh_upload_buffer_r(
|
|
HSHSDK hshsdk, // SDK handle
|
|
const char *dstPath, // Destination file
|
|
int writePolicy, // Write policy flag
|
|
up_stream proc, // user defined function
|
|
INT64 beginpos, // write start position
|
|
INT64 nbytes, // write size
|
|
void* userval // User-supplied value for callback
|
|
)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (!hshsdk)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
psdk->nError = SHCERRNO_NOERROR;
|
|
|
|
if (psdk->bWorking) {
|
|
psdk->nError = SHCERRNO_ISBUSY;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
return ret;
|
|
}
|
|
|
|
#ifdef WIN32
|
|
psdk->hFile = NULL;
|
|
#else
|
|
psdk->nFileDesc = -1;
|
|
#endif
|
|
psdk->iFilePos = 0;
|
|
psdk->cOldTick = clock();
|
|
psdk->nTranStop = SHSTOP_NO;
|
|
|
|
ret = DoUploaduffer(psdk, dstPath, writePolicy, proc, beginpos, nbytes, userval, 1);
|
|
|
|
if (!ret)
|
|
{
|
|
switch( sh_get_error_number(psdk) )
|
|
{
|
|
case 401:
|
|
DoUploaduffer(psdk, dstPath, writePolicy, proc, beginpos, nbytes, userval, 0);
|
|
break;
|
|
case NE_LOOKUP:
|
|
// 2011.06.20 : DNS lookup 실패 시 1회 재시도
|
|
DoUploaduffer(psdk, dstPath, writePolicy, proc, beginpos, nbytes, userval, 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
WIN32DLL
|
|
int sh_upload(HSHSDK hshsdk, const char *srcPath, const char *dstPath, int writePolicy, INT64 availQuota, const char *extSession)
|
|
{
|
|
if (!hshsdk)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
psdk->nError = SHCERRNO_NOERROR;
|
|
|
|
if (psdk->bWorking) {
|
|
psdk->nError = SHCERRNO_ISBUSY;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
return FALSE;
|
|
}
|
|
#ifdef WIN32
|
|
psdk->hFile = NULL;
|
|
#else
|
|
psdk->nFileDesc = -1;
|
|
#endif
|
|
psdk->iFilePos = 0;
|
|
psdk->cOldTick = clock();
|
|
psdk->nTranStop = SHSTOP_NO;
|
|
|
|
int nRet = DoUpload(psdk, srcPath, dstPath, writePolicy, availQuota,1, extSession);
|
|
|
|
if (!nRet)
|
|
{
|
|
switch( sh_get_error_number(psdk) )
|
|
{
|
|
case 401:
|
|
// 2011.06.02 : 401 에러 발생 경우 body를 모두 전송 후 리턴 되기 때문에 iFilePos를 초기화하여 시도하여함.
|
|
psdk->iFilePos = 0;
|
|
nRet = DoUpload(psdk, srcPath, dstPath, writePolicy, availQuota,0, extSession);
|
|
break;
|
|
case NE_LOOKUP:
|
|
// 2011.06.20 : DNS lookup 실패 시 1회 재시도
|
|
psdk->iFilePos = 0;
|
|
nRet = DoUpload(psdk, srcPath, dstPath, writePolicy, availQuota,1, extSession);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return nRet;
|
|
}
|
|
|
|
WIN32DLL int sh_download_buffer(
|
|
HSHSDK hshsdk, // SDK handle
|
|
const char *srcPath, // Source file
|
|
down_stream proc,
|
|
INT64 beginpos,
|
|
void* userval // User-supplied value for callback
|
|
)
|
|
{
|
|
if (!hshsdk)
|
|
return FALSE;
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
psdk->nError = SHCERRNO_NOERROR;
|
|
|
|
if (psdk->bWorking) {
|
|
psdk->nError = SHCERRNO_ISBUSY;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
return FALSE;
|
|
}
|
|
|
|
psdk->iFilePos = 0;
|
|
psdk->cOldTick = clock();
|
|
psdk->nTranStop = SHSTOP_NO;
|
|
|
|
int nRet = DoDownloadBuffer(psdk, srcPath, proc, beginpos, -1, userval, 1);
|
|
|
|
if(!nRet)
|
|
{
|
|
switch( sh_get_error_number(psdk) )
|
|
{
|
|
case 401:
|
|
nRet = DoDownloadBuffer(psdk, srcPath, proc, beginpos, -1, userval,0);
|
|
break;
|
|
case NE_LOOKUP:
|
|
// 2011.06.20 : DNS lookup 실패 시 1회 재시도
|
|
nRet = DoDownloadBuffer(psdk, srcPath, proc, beginpos, -1, userval,1);
|
|
break;
|
|
}
|
|
}
|
|
return nRet;
|
|
}
|
|
|
|
// sh_download_buffer range version for GAMPLE
|
|
//
|
|
WIN32DLL
|
|
int sh_download_buffer_r(
|
|
HSHSDK hshsdk, // SDK handle
|
|
const char *srcPath, // Source file
|
|
down_stream proc, // user defined function
|
|
INT64 beginpos, // point to read
|
|
INT64 nbytes, // amount to read
|
|
void* userval // User-supplied value for callback
|
|
)
|
|
{
|
|
|
|
if (!hshsdk)
|
|
return FALSE;
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
psdk->nError = SHCERRNO_NOERROR;
|
|
|
|
if (psdk->bWorking) {
|
|
psdk->nError = SHCERRNO_ISBUSY;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
return FALSE;
|
|
}
|
|
|
|
psdk->iFilePos = 0;
|
|
psdk->cOldTick = clock();
|
|
psdk->nTranStop = SHSTOP_NO;
|
|
|
|
int nRet = DoDownloadBuffer(psdk, srcPath, proc, beginpos, nbytes, userval, 1);
|
|
|
|
if(!nRet)
|
|
{
|
|
switch ( sh_get_error_number(psdk) )
|
|
{
|
|
case 401:
|
|
nRet = DoDownloadBuffer(psdk, srcPath, proc, beginpos, nbytes, userval,0);
|
|
break;
|
|
case NE_LOOKUP:
|
|
// 2011.06.20 : DNS lookup 실패 시 1회 재시도
|
|
nRet = DoDownloadBuffer(psdk, srcPath, proc, beginpos, nbytes, userval, 1);
|
|
break;
|
|
}
|
|
}
|
|
return nRet;
|
|
}
|
|
|
|
|
|
WIN32DLL
|
|
int sh_download(HSHSDK hshsdk, const char *srcPath, const char *dstPath, int writePolicy, INT64 availQuota, const char *extSession)
|
|
{
|
|
if (!hshsdk)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
psdk->nError = SHCERRNO_NOERROR;
|
|
|
|
if (psdk->bWorking) {
|
|
psdk->nError = SHCERRNO_ISBUSY;
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
return FALSE;
|
|
}
|
|
#ifdef WIN32
|
|
psdk->hFile = NULL;
|
|
#else
|
|
psdk->nFileDesc = -1;
|
|
#endif
|
|
|
|
psdk->iFilePos = 0;
|
|
psdk->cOldTick = clock();
|
|
psdk->nTranStop = SHSTOP_NO;
|
|
|
|
//pizon
|
|
int nRet = DoDownload(psdk, srcPath, dstPath, writePolicy, availQuota, 1, extSession);
|
|
|
|
if(!nRet)
|
|
{
|
|
switch( sh_get_error_number(psdk) )
|
|
{
|
|
case 401:
|
|
nRet = DoDownload(psdk, srcPath, dstPath, writePolicy, availQuota,0, extSession);
|
|
break;
|
|
case NE_LOOKUP:
|
|
// 2011.06.20 : DNS lookup 실패 시 1회 재시도
|
|
nRet = DoDownload(psdk, srcPath, dstPath, writePolicy, availQuota, 1, extSession);
|
|
break;
|
|
}
|
|
}
|
|
return nRet;
|
|
}
|
|
|
|
WIN32DLL
|
|
int sh_set_limit(HSHSDK hshsdk,int nLimit)
|
|
{
|
|
if (!hshsdk)
|
|
return FALSE;
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
|
|
psdk->nSpeedLimit = nLimit;
|
|
return TRUE;
|
|
}
|
|
|
|
WIN32DLL
|
|
int sh_get_limit(HSHSDK hshsdk)
|
|
{
|
|
if (!hshsdk)
|
|
return FALSE;
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
|
|
return psdk->nSpeedLimit;
|
|
}
|
|
|
|
WIN32DLL
|
|
INT64 sh_get_filepos(HSHSDK hshsdk)
|
|
{
|
|
if(!hshsdk)
|
|
return FALSE;
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
|
|
return psdk->iFilePos;
|
|
}
|
|
|
|
WIN32DLL
|
|
bool sh_file_exist(
|
|
HSHSDK hshsdk, // SDK Handle
|
|
const char *path) // file/folder Path
|
|
|
|
{
|
|
// 파일 목록 가져오기
|
|
HSHFILELIST hshfl = sh_get_filelist(hshsdk, path, 0);
|
|
|
|
if (!hshfl)
|
|
return false;
|
|
else
|
|
{
|
|
// 메모리 정리
|
|
PVECTOR_SHFILELIST pvec = (PVECTOR_SHFILELIST)hshfl;
|
|
if (pvec && pvec->size() > 0) {
|
|
sh_free_filelist(hshsdk, (HSHFILELIST)pvec);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
#include "mcrypt.h"
|
|
#define ENCRYPT_KEY "I'm your father"
|
|
#define INIT_VECTOR "1234567890123456"
|
|
#define ENCRYPT_BIT 24
|
|
|
|
WIN32DLL
|
|
int sh_encrypt(const char *text, char *encrypted)
|
|
{
|
|
MCRYPT mcrypt = NULL;
|
|
BOOL bResult = FALSE;
|
|
struct tm *stm;
|
|
char szKey[ENCRYPT_BIT];
|
|
char szIV[ENCRYPT_BIT];
|
|
char szBuf[1024];
|
|
time_t tnow;
|
|
|
|
tnow = get_time_from_sntp();
|
|
if(tnow == 0)
|
|
goto EXIT_SH_ENCRYPT;
|
|
|
|
stm = gmtime((time_t*)&tnow);
|
|
|
|
// encrypt
|
|
mcrypt = mcrypt_module_open(MCRYPT_BLOWFISH, NULL, MCRYPT_CBC, NULL);
|
|
if (mcrypt == MCRYPT_FAILED)
|
|
return FALSE;
|
|
|
|
::memset(szKey, 0, ENCRYPT_BIT);
|
|
strcpy(szKey, ENCRYPT_KEY);
|
|
|
|
memcpy(szIV, INIT_VECTOR, ENCRYPT_BIT);
|
|
|
|
if (mcrypt_generic_init(mcrypt, szKey, ENCRYPT_BIT, szIV) < 0)
|
|
goto EXIT_SH_ENCRYPT;
|
|
|
|
sprintf(szBuf, "%s%04d%02d%02d%02d%02d%02d", text, stm->tm_year, stm->tm_mon, stm->tm_mday, stm->tm_hour, stm->tm_min, stm->tm_sec);
|
|
|
|
#ifndef WIN32
|
|
{
|
|
#endif
|
|
int nBufSize = (int)strlen(szBuf);
|
|
mcrypt_generic(mcrypt, szBuf, nBufSize);
|
|
|
|
mcrypt_generic_deinit(mcrypt);
|
|
|
|
char szEncrypted[URL_SIZE];
|
|
char* pszEncrypted = ne_base64((const unsigned char *)szBuf, nBufSize);
|
|
int nEncryptedSize = (int)strlen(pszEncrypted);
|
|
|
|
memcpy(szEncrypted, pszEncrypted, nEncryptedSize);
|
|
free(pszEncrypted);
|
|
|
|
memcpy(&szEncrypted[nEncryptedSize], szIV, ENCRYPT_BIT);
|
|
szEncrypted[nEncryptedSize + ENCRYPT_BIT] = (char)NULL;
|
|
|
|
strcpy(encrypted, URLEncode(szEncrypted).c_str());
|
|
|
|
bResult = TRUE;
|
|
#ifndef WIN32
|
|
}
|
|
#endif
|
|
|
|
EXIT_SH_ENCRYPT:
|
|
mcrypt_module_close(mcrypt);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
void sh_set_sntp_timeout(int second)
|
|
{
|
|
timeout = second;
|
|
}
|
|
|
|
void sh_set_C_timeout(int second)
|
|
{
|
|
sh_set_sntp_timeout(second);
|
|
sh_set_connect_timeout(second);
|
|
}
|
|
|
|
int sh_set_auth_expire(HSHSDK hshsdk,int ntime)
|
|
{
|
|
if(!hshsdk)
|
|
return FALSE;
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
|
|
psdk->nAuthExpire = ntime;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
int sh_get_auth_expire(HSHSDK hshsdk)
|
|
{
|
|
if(!hshsdk)
|
|
return FALSE;
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
|
|
return psdk->nAuthExpire;
|
|
}
|
|
|
|
void sh_set_connect_timeout(int second)
|
|
{
|
|
if( 0 < second ) second = 0;
|
|
|
|
_connect_time_out = second;
|
|
}
|
|
|
|
void sh_set_response_timeout(int second)
|
|
{
|
|
if( 0 < second ) second = 0;
|
|
_read_time_out = second;
|
|
}
|
|
|
|
// NEW 2010-03-29
|
|
// 특정 시간(tStart) 이후에 업로드된 리스트를 얻어온다.
|
|
// 고객의 요청에 의해 해당 인터페이스 추가.
|
|
WIN32DLL
|
|
HSHFILELIST sh_get_filelist_certain_time(HSHSDK hshsdk, const char* path, time_t tStart, unsigned int depth)
|
|
{
|
|
if (!hshsdk)
|
|
return NULL;
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
psdk->nError = 0;
|
|
|
|
string sPath = psdk->sPath;
|
|
if (path[0] != '/')
|
|
sPath += "/";
|
|
sPath += path;
|
|
|
|
char szDepth[10];
|
|
if (depth <= 1)
|
|
sprintf(szDepth, "%d", depth);
|
|
else
|
|
strcpy(szDepth, "infinity");
|
|
|
|
string sHeaders = "Depth|";
|
|
sHeaders += szDepth;
|
|
|
|
// sh_get_filelist_certain_time() 함수를 추가로 만들게 된 코드다.
|
|
char szTime[20];
|
|
memset(szTime, 0x00, 20);
|
|
if (tStart > 0 )
|
|
{
|
|
// time * 1000000 을 하는 이유는
|
|
// 아파치에서 filetime을 구하는 식이 이미 정해져 있어서.
|
|
// 아파치의 룰에 맞추기 위해서 적용한다.
|
|
sprintf(szTime, "%lld", tStart * 1000000);
|
|
sHeaders += ",";
|
|
sHeaders += "StartTime|";
|
|
sHeaders += szTime;
|
|
}
|
|
|
|
string sBody = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
|
|
sBody += "<D:propfind xmlns:D=\"DAV:\">";
|
|
sBody += "<D:prop>";
|
|
sBody += "<D:resourcetype/>";
|
|
sBody += "<D:getcontentlength/>";
|
|
sBody += "<D:getlastmodified/>";
|
|
sBody += "<D:source/>";
|
|
sBody += "</D:prop>";
|
|
sBody += "</D:propfind>";
|
|
|
|
SHFILELIST_PARSER_STRUCT shflp;
|
|
::memset(&shflp, 0, sizeof(SHFILELIST_PARSER_STRUCT));
|
|
|
|
shflp.nRootPathLen = (UINT)psdk->sPath.length();
|
|
|
|
shflp.pvec = new VECTOR_SHFILELIST;
|
|
if (shflp.pvec) {
|
|
if (DoCommand(psdk, "PROPFIND", sPath.c_str(), sHeaders.c_str(), sBody.c_str(), true,
|
|
(LPVOID)FileListSTagParser, (LPVOID)FileListDataParser, (LPVOID)FileListETagParser, &shflp, 1))
|
|
{
|
|
psdk->setFileList.insert(shflp.pvec);
|
|
psdk->pvecshfl = shflp.pvec;
|
|
|
|
VECTOR_SHFILELIST::iterator iter = shflp.pvec->begin();
|
|
if (strcmp((*iter)->path, "*myself*") == 0)
|
|
strcpy((*iter)->path, sPath.substr(psdk->sPath.length(), string::npos).c_str());
|
|
}
|
|
else
|
|
{
|
|
if (psdk->nError == SHCERRNO_AUTHORIZATION)
|
|
{
|
|
if (DoCommand(psdk, "PROPFIND", sPath.c_str(), sHeaders.c_str(), sBody.c_str(), true,
|
|
(LPVOID)FileListSTagParser, (LPVOID)FileListDataParser, (LPVOID)FileListETagParser, &shflp,0))
|
|
{
|
|
psdk->setFileList.insert(shflp.pvec);
|
|
psdk->pvecshfl = shflp.pvec;
|
|
|
|
VECTOR_SHFILELIST::iterator iter = shflp.pvec->begin();
|
|
if (strcmp((*iter)->path, "*myself*") == 0)
|
|
strcpy((*iter)->path, sPath.substr(psdk->sPath.length(), string::npos).c_str());
|
|
}
|
|
else
|
|
{
|
|
FreeFileListVector(shflp.pvec);
|
|
shflp.pvec = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FreeFileListVector(shflp.pvec);
|
|
shflp.pvec = NULL;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
psdk->nError = GetLastError();
|
|
psdk->sError = GetErrorMessage(psdk->nError);
|
|
}
|
|
|
|
sPath.clear();
|
|
sBody.clear();
|
|
return shflp.pvec;
|
|
}
|
|
// 전송 관련 callback 함수 등록
|
|
WIN32DLL
|
|
int sh_set_transfer_callback (HSHSDK hshsdk, sh_callback proc, void *param)
|
|
{
|
|
if (!hshsdk)
|
|
return 1;
|
|
|
|
PSHCSDK_STRUCT psdk = (PSHCSDK_STRUCT)hshsdk;
|
|
psdk->proc = proc;
|
|
psdk->pParam = param;
|
|
|
|
return 0;
|
|
}
|
|
|
|
WIN32DLL
|
|
int sh_open (
|
|
HSHSDK hshsdk, // SDK handle
|
|
const char *path // Path
|
|
)
|
|
{
|
|
char ppath[2048] = {0};
|
|
char *find = strrchr((char*)path, '/');
|
|
strncpy(ppath, path, strlen(path) - strlen(find));
|
|
|
|
int r = sh_make_directory(hshsdk, ppath) ;
|
|
if (r == 0)
|
|
{
|
|
if ( sh_get_error_number(hshsdk) == SHCERRNO_ALREADYEXIST )
|
|
return true;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
WIN32DLL
|
|
int sh_send_append (
|
|
HSHSDK hshsdk, // SDK handle
|
|
const char *dstPath, // Destination file
|
|
up_stream proc, // user defined function
|
|
INT64 nbytes, // write size
|
|
void* userval // User-supplied value for callback
|
|
)
|
|
{
|
|
return sh_upload_buffer_r(hshsdk, dstPath, SHWRITEPOLICY_APPEND, proc, -1, nbytes, userval);
|
|
}
|
|
|
|
WIN32DLL
|
|
int sh_send_block (
|
|
HSHSDK hshsdk, // SDK handle
|
|
const char *dstPath, // Destination file
|
|
up_stream proc, // user defined function
|
|
INT64 beingpos, // write start position
|
|
INT64 nbytes, // write size
|
|
void* userval // User-supplied value for callback
|
|
)
|
|
{
|
|
return sh_upload_buffer_r(hshsdk, dstPath, SHWRITEPOLICY_APPEND, proc, beingpos, nbytes, userval);
|
|
}
|