├── .gitignore ├── Makefile ├── README.md ├── client ├── clidtp.cpp ├── clidtp.h ├── client.cpp ├── clipi.cpp ├── clipi.h ├── ui.cpp └── ui.h ├── common ├── common.cpp ├── common.h ├── database.cpp ├── database.h ├── error.cpp ├── error.h ├── packet.cpp ├── packet.h ├── pi.cpp ├── pi.h ├── socket.cpp ├── socket.h ├── sockstream.cpp └── sockstream.h ├── include ├── sqlite3.h └── sqlite3ext.h ├── lib └── libsqlite3.so └── server ├── server.cpp ├── server.h ├── srvdtp.cpp ├── srvdtp.h ├── srvpi.cpp └── srvpi.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | *.slo 7 | *.lo 8 | 9 | # Precompiled Headers 10 | *.gch 11 | *.pch 12 | 13 | # Libraries 14 | *.lib 15 | *.a 16 | *.la 17 | *.lo 18 | 19 | # Shared objects (inc. Windows DLLs) 20 | *.dll 21 | # *.so 22 | # *.so.* 23 | *.dylib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | *.i*86 30 | *.x86_64 31 | *.hex 32 | 33 | # Debug files 34 | *.dSYM/ 35 | 36 | # Other files 37 | .depend 38 | *.db 39 | test 40 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC := g++ 2 | CFLAGS := -std=c++11 -g -Wall -O3 -Iinclude 3 | CPPFLAGS := $(CFLAGS) 4 | LIBS := -pthread -lsqlite3 -lcrypto -Llib #-Wl,-rpath=/home/wenchy/GitHub/tinyFTP/lib 5 | 6 | FILE:=/usr/lib/libsqlite3.so 7 | 8 | SRV_EXE := server/server.out 9 | CLI_EXE := client/client.out 10 | EXE := $(SRV_EXE) $(CLI_EXE) 11 | 12 | SRV_SRC = $(wildcard server/*.cpp) 13 | CLI_SRC = $(wildcard client/*.cpp) 14 | COM_SRC = $(wildcard common/*.cpp) 15 | SRC = $(SRV_SRC) $(CLI_SRC) $(COM_SRC) 16 | 17 | SRV_OBJ = $(SRV_SRC:.cpp=.o) 18 | CLI_OBJ = $(CLI_SRC:.cpp=.o) 19 | COM_OBJ = $(COM_SRC:.cpp=.o) 20 | OBJ = $(SRV_OBJ) $(CLI_OBJ) $(COM_OBJ) 21 | 22 | all: depend $(EXE) 23 | 24 | .PHONY: all 25 | 26 | $(SRV_EXE): $(SRV_OBJ) $(COM_OBJ) 27 | $(CC) $(CPPFLAGS) $^ -o $@ $(LIBS) 28 | $(CLI_EXE): $(CLI_OBJ) $(COM_OBJ) 29 | $(CC) $(CPPFLAGS) $^ -o $@ $(LIBS) 30 | depend: 31 | $(shell if [ -f $(FILE) ]; then break; else sudo cp lib/libsqlite3.so /usr/lib; fi;) 32 | $(CC) -MM $(SRC) > .depend 33 | -include .depend 34 | clean: 35 | @rm -f $(EXE) $(OBJ) .depend 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tinyFTP 2 | Implementation of a tiny FTP client and server 3 | 4 | ## Introduction to tinyFTP 5 | 6 | I spent 21 days to finish this project from Aug 3 to Aug 24, 2015 , and very happy to share with you. You can fork from my Github repository [tinyFTP](https://github.com/Wenchy/tinyFTP). Also, you can pull requests if you have any questions. I will continue updating this interesting project, and start to spend some time to finish a more interesting project **tinyHttpd**, a tiny web server just for fun. 7 | 8 | > **PDF Online**: 9 | > [tinyFTP_en](https://mozilla.github.io/pdf.js/web/viewer.html?file=https://wenchy.github.io/misc/2015-08-26-tinyFTP_en.pdf) 10 | > [tinyFTP_zh](https://mozilla.github.io/pdf.js/web/viewer.html?file=https://wenchy.github.io/misc/2015-08-26-tinyFTP_zh.pdf) 11 | > 12 | > **PDF Download**: 13 | > [tinyFTP_en](https://wenchy.github.io/misc/2015-08-26-tinyFTP_en.pdf) 14 | > [tinyFTP_zh](https://wenchy.github.io/misc/2015-08-26-tinyFTP_zh.pdf) 15 | 16 | ## Platform 17 | 18 | Ubuntu14.04 64bit 19 | 20 | ## Basics 21 | 22 | ### Commands 23 | 24 | ftp [ip-address] 25 | 26 | - **GET**: `get [remote-file] [local-file]` 27 | - **PUT**: `put [local-file] [remote-file]` 28 | - **RGET**: `get [remote-dir] [local-dir]` 29 | - **RPUT**: `put [local-dir] [remote-dir]` 30 | - **LS**: `ls [remote-dir]` local: **LLS** 31 | - **CD**: `cd [DIR]` local: **LCD** 32 | - **RM**: `rm [remote-file]` local: **LRM** 33 | - **PWD**: `pwd [-a]` local: **LPWD** 34 | - **MKDIR**: `mkdir [remote-dir]` local: **LMKDIR** 35 | - **RMDIR**: `rmdir [remote-dir]` 36 | - **SHELL**: `shell [shell-cmd-string]` local: **LSHELL** 37 | - **USERADD**: `useradd -u [username] -p [password]` 38 | - **USERDEL**: `userdel [username]` 39 | - **QUIT**: `quit` 40 | - **HELP**: `help [command]` 41 | 42 | ### Special attention 43 | 1. *anonymous* user can only `GET` a file, but not `PUT`, `MKDIR`, `RM`, `RMDIR`, or `shell`. 44 | 2. *admin* user has permission to do `USERADD` and `USERDEL` command. 45 | 46 | ## Features 47 | 48 | - Multithread concurrency Model for server 49 | - User authentication 50 | - Salting password 51 | - User space isolation 52 | - Breakpoint resume 53 | - Flash transmission 54 | 55 | ## FTP model 56 | 57 | ``` 58 | ------------- 59 | |/---------\| 60 | || User || -------- 61 | ||Interface|<--->| User | 62 | |\----^----/| -------- 63 | ---------- | | | 64 | |/------\| FTP Commands |/----V----\| 65 | ||Server|<---------------->| Client || 66 | || PI || FTP Replies || PI || 67 | |\--^---/| |\----^----/| 68 | | | | | | | 69 | -------- |/--V---\| Data |/----V----\| -------- 70 | | File |<--->|Server|<---------------->| Client |<--->| File | 71 | |System| || DTP || Connection || DTP || |System| 72 | -------- |\------/| |\---------/| -------- 73 | ---------- ------------- 74 | 75 | Server-FTP Client-FTP 76 | 77 | NOTES: 1. The data connection may be used in either direction. 78 | 2. The data connection need not exist all of the time. 79 | 80 | Figure 1 Model for FTP Use 81 | 82 | ``` 83 | 84 | In the model described in Figure 1, the user-protocol interpreter 85 | initiates the control connection. The control connection follows 86 | the Telnet protocol. At the initiation of the user, standard FTP 87 | commands are generated by the user-PI and transmitted to the 88 | server process via the control connection. (The user may 89 | establish a direct control connection to the server-FTP, from a 90 | TAC terminal for example, and generate standard FTP commands 91 | independently, bypassing the user-FTP process.) Standard replies 92 | are sent from the server-PI to the user-PI over the control 93 | connection in response to the commands. 94 | 95 | The FTP commands specify the parameters for the data connection 96 | (data port, transfer mode, representation type, and structure) and 97 | the nature of file system operation (store, retrieve, append, 98 | delete, etc.). The user-DTP or its designate should "listen" on 99 | the specified data port, and the server initiate the data 100 | connection and data transfer in accordance with the specified 101 | parameters. 102 | 103 | ## TODO 104 | 1. Breakpoint resume for `GET` command. 105 | 2. Enhance admin's permission to do more management. 106 | 3. Reactor concurrency Model for server: `epoll` implementation. 107 | 4. **Deamon** server. 108 | 5. **syslogd**: format log messages. 109 | 6. `DEBUG` macro for easy debugging. 110 | 7. Robust error handling, especially for internet exception. 111 | 8. More elegant **class** design, make full use of powerful features of **C++**. 112 | -------------------------------------------------------------------------------- /client/clidtp.cpp: -------------------------------------------------------------------------------- 1 | #include "clidtp.h" 2 | 3 | CliDTP::CliDTP(Packet * ppacket, CliPI * pcliPI) 4 | { 5 | this->ppacket = ppacket; 6 | this->pcliPI = pcliPI; 7 | } 8 | 9 | void CliDTP::sendFile(const char *pathname, FILE *fp, uint32_t nslice, uint32_t sindex, uint16_t slicecap) 10 | { 11 | Packet & packet = *(this->ppacket); 12 | 13 | off64_t curpos = sindex * slicecap; 14 | if (lseek64(fileno(fp), curpos, SEEK_SET) < 0) 15 | { 16 | Error::ret("lseek64"); 17 | return; 18 | } 19 | 20 | int n; 21 | char body[PBODYCAP]; 22 | //int oldProgress = 0, newProgress = 0; 23 | string hfilesize = getFileSizeString(pathname); 24 | if(nslice == 0) 25 | { 26 | fprintf(stderr, "\033[2K\r\033[0m%-40s%10s\t100%%", pathname, hfilesize.c_str()); 27 | } else { 28 | while( (n = fread(body, sizeof(char), PBODYCAP, fp)) >0 ) 29 | { 30 | packet.sendDATA_FILE(nslice, ++sindex, n, body); 31 | 32 | // newProgress = (sindex*1.0)/nslice*100; 33 | // if (newProgress > oldProgress) 34 | // { 35 | // fprintf(stderr, "\033[2K\r\033[0m%-40s%10s\t%3d%%", pathname, hfilesize.c_str(), newProgress); 36 | // } 37 | // oldProgress = newProgress; 38 | } 39 | 40 | } 41 | 42 | fclose(fp); 43 | //printf("EOF [%s]\n", pathname); 44 | packet.sendSTAT_EOF(); 45 | 46 | // continue reading progress tip sended by server 47 | while (pcliPI->recvOnePacket()) 48 | { 49 | if (packet.getTagid() == TAG_STAT && packet.getStatid() == STAT_PGS) 50 | { 51 | cerr << packet.getSBody(); 52 | } else if (packet.getTagid() == TAG_STAT && packet.getStatid() == STAT_WAIT){ 53 | cerr << endl << packet.getSBody(); 54 | } else if (packet.getTagid() == TAG_STAT && packet.getStatid() == STAT_EOT){ 55 | cout << packet.getSBody() << endl; 56 | //cout << endl; 57 | break; 58 | } else { 59 | cout << "unknown packet" << endl; 60 | packet.print(); 61 | break; 62 | } 63 | } 64 | } 65 | 66 | void CliDTP::recvFile(const char *pathname, FILE *fp, uint32_t nslice, uint32_t sindex, uint16_t slicecap) 67 | { 68 | Packet & packet = *(this->ppacket); 69 | string hfilesize; 70 | int m; 71 | int oldProgress = 0, newProgress = 0; 72 | off64_t curpos = sindex * slicecap; 73 | if (lseek64(fileno(fp), curpos, SEEK_SET) < 0) 74 | { 75 | Error::ret("lseek64"); 76 | return; 77 | } 78 | 79 | while(pcliPI->recvOnePacket()) 80 | { 81 | switch(packet.getTagid()) 82 | { 83 | case TAG_STAT: 84 | { 85 | switch(packet.getStatid()) 86 | { 87 | case STAT_OK: 88 | { 89 | //cout << packet.getSBody() < getDiskAvailable()) 96 | { 97 | packet.sendSTAT_ERR("insufficient disk space"); 98 | Error::msg("insufficient disk space"); 99 | return; 100 | } else { 101 | packet.sendSTAT_OK("sufficient disk space, ok to tranfer"); 102 | } 103 | break; 104 | } 105 | case STAT_ERR: 106 | { 107 | cerr << packet.getSBody() < oldProgress) 153 | { 154 | //printf("\033[2K\r\033[0m"); 155 | fprintf(stderr, "\033[2K\r\033[0m%-40s%10s\t%3d%%", pathname, hfilesize.c_str(), newProgress); 156 | } 157 | oldProgress = newProgress; 158 | } 159 | 160 | break; 161 | } 162 | case DATA_TEXT: 163 | { 164 | //cout << packet.getSBody() <"); 15 | 16 | 17 | UI userInterface(argv[1]); 18 | userInterface.run(); 19 | 20 | // while ( (n = cliSocket.tcpRecv(connfd, recvline, MAXLINE, 0)) > 0) 21 | // { 22 | // recvline[n] = 0; // null terminate 23 | // if (fputs(recvline, stdout) == EOF) 24 | // Error::sys("fputs error"); 25 | // } 26 | // if (n < 0) 27 | // Error::sys("read error"); 28 | 29 | exit(0); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /client/clipi.cpp: -------------------------------------------------------------------------------- 1 | #include "clipi.h" 2 | 3 | 4 | std::map CliPI::helpMap = { //{"USER", "user username"}, 5 | //{"PASS", "pass password"}, 6 | {"USERADD", "useradd -u [username] -p [password]"}, 7 | {"USERDEL", "userdel [username]"}, 8 | 9 | {"GET", "get [remote-file] [local-file]"}, 10 | {"PUT", "put [local-file] [remote-file]"}, 11 | {"LS", "ls [remote-dir]"}, 12 | {"LLS", "lls same as local ls"}, 13 | {"CD", "cd [remote-dir]"}, 14 | {"LCD", "lcd [local-dir]"}, 15 | {"RM", "rm [remote-file]"}, 16 | {"LRM", "lrm same as local rm"}, 17 | {"PWD", "pwd [-a]"}, 18 | {"LPWD", "lpwd same as local pwd"}, 19 | {"MKDIR", "mkdir [remote-dir]"}, 20 | {"LMKDIR", "lmkdir same as local mkdir"}, 21 | {"QUIT", "quit"}, 22 | {"HELP", "help [cmd]"}, 23 | 24 | {"MGET", "mget [file]..."}, 25 | {"MPUT", "mput [file]..."}, 26 | {"RGET", "rget [dir]"}, 27 | {"RPUT", "rput [dir]"}, 28 | {"RMDIR", "rmdir [dir]"}, 29 | {"SHELL", "shell [remote-shell-cmd]"}, 30 | 31 | //{"BINARY", "binary"}, 32 | //{"ASCII", "ascii"} 33 | }; 34 | 35 | CliPI::CliPI(const char *host): packet(this), readpacket(this) 36 | { 37 | Socket cliSocket(CLI_SOCKET, host, CTRPORT); 38 | connfd = cliSocket.init(); 39 | connSockStream.init(connfd); 40 | } 41 | 42 | bool CliPI::recvOnePacket() 43 | { 44 | int n; 45 | packet.reset(NPACKET); 46 | if ( (n = connSockStream.readn(packet.getPs(), PACKSIZE)) == 0) 47 | { 48 | this->saveUserState(); 49 | Socket::tcpClose(connfd); 50 | Error::quit("server terminated prematurely"); 51 | } else if (n < 0){ 52 | this->saveUserState(); 53 | Socket::tcpClose(connfd); 54 | Error::ret("connSockStream.readn() error"); 55 | Error::quit_pthread("socket connection exception"); 56 | } else { 57 | packet.ntohp(); 58 | //packet.print(); 59 | } 60 | return true; 61 | } 62 | 63 | bool CliPI::sendOnePacketBlocked(PacketStruct * ps, size_t nbytes) 64 | { 65 | int m; 66 | if ( (m = connSockStream.writen(ps, nbytes)) < 0 || (size_t)m != nbytes ) 67 | { 68 | this->saveUserState(); 69 | Socket::tcpClose(connfd); 70 | Error::ret("connSockStream.writen()"); 71 | Error::quit_pthread("socket connection exception"); 72 | return false; 73 | } else { 74 | return true; 75 | } 76 | } 77 | 78 | bool CliPI::sendOnePacket(PacketStruct * ps, size_t nbytes) 79 | { 80 | int n, m; 81 | bool sendFlag = false; 82 | int maxfdp1; 83 | fd_set rset, wset; 84 | 85 | FD_ZERO(&rset); 86 | FD_ZERO(&wset); 87 | 88 | while(!sendFlag) { 89 | FD_SET(connfd, &rset); 90 | 91 | FD_SET(connfd, &wset); 92 | 93 | maxfdp1 = connfd + 1; 94 | if (select(maxfdp1, &rset, &wset, NULL, NULL) < 0) 95 | { 96 | this->saveUserState(); 97 | Socket::tcpClose(connfd); 98 | Error::ret("select error"); 99 | Error::quit_pthread("socket connection exception"); 100 | } 101 | 102 | if (FD_ISSET(connfd, &rset)) /* socket is readable */ 103 | { 104 | readpacket.reset(NPACKET); 105 | if ( (n = connSockStream.readn(readpacket.getPs(), PACKSIZE)) == 0) 106 | { 107 | this->saveUserState(); 108 | Socket::tcpClose(connfd); 109 | Error::quit_pthread("server terminated prematurely"); 110 | } else if (n < 0){ 111 | this->saveUserState(); 112 | Socket::tcpClose(connfd); 113 | Error::ret("connSockStream.readn() error"); 114 | Error::quit_pthread("socket connection exception"); 115 | } else { 116 | if (n == PACKSIZE) 117 | { 118 | //readpacket.print(); 119 | readpacket.ntohp(); 120 | if (readpacket.getTagid() == TAG_STAT && readpacket.getStatid() == STAT_PGS) 121 | { 122 | cerr << readpacket.getSBody(); 123 | } 124 | //printf("sendOnePacket method recive one packet: %s\n", readpacket.getSBody().c_str()); 125 | //readpacket.print(); 126 | } else { 127 | printf("ERROR: sendOnePacket method recive one packet: n != PACKSIZE"); 128 | } 129 | 130 | } 131 | } 132 | if (FD_ISSET(connfd, &wset)) /* socket is writable */ 133 | { 134 | if ( (m = connSockStream.writen(ps, nbytes)) < 0 || (size_t)m != nbytes ) 135 | { 136 | this->saveUserState(); 137 | Socket::tcpClose(connfd); 138 | Error::ret("connSockStream.writen()"); 139 | Error::quit_pthread("socket connection exception"); 140 | } else { 141 | sendFlag = true; 142 | } 143 | } 144 | } 145 | return true; 146 | } 147 | 148 | void CliPI::run(uint16_t cmdid, std::vector & paramVector) 149 | { 150 | switch(cmdid) 151 | { 152 | case USER: 153 | cmdUSER(paramVector); 154 | break; 155 | case PASS: 156 | cmdPASS(paramVector); 157 | break; 158 | case USERADD: 159 | cmdUSERADD(paramVector); 160 | break; 161 | case USERDEL: 162 | cmdUSERDEL(paramVector); 163 | break; 164 | case GET: 165 | cmdGET(paramVector); 166 | break; 167 | case RGET: 168 | cmdRGET(paramVector); 169 | break; 170 | case PUT: 171 | cmdPUT(paramVector); 172 | break; 173 | case RPUT: 174 | cmdRPUT(paramVector); 175 | break; 176 | case LS: 177 | cmdLS(paramVector); 178 | break; 179 | case LLS: 180 | cmdLLS(paramVector); 181 | break; 182 | case CD: 183 | cmdCD(paramVector); 184 | break; 185 | case LCD: 186 | cmdLCD(paramVector); 187 | break; 188 | case RM: 189 | cmdRM(paramVector); 190 | break; 191 | case LRM: 192 | cmdLRM(paramVector); 193 | break; 194 | case PWD: 195 | cmdPWD(paramVector); 196 | break; 197 | case LPWD: 198 | cmdLPWD(paramVector); 199 | break; 200 | case MKDIR: 201 | cmdMKDIR(paramVector); 202 | break; 203 | case LMKDIR: 204 | cmdLMKDIR(paramVector); 205 | break; 206 | case RMDIR: 207 | cmdRMDIR(paramVector); 208 | break; 209 | case SHELL: 210 | cmdSHELL(paramVector); 211 | break; 212 | case LSHELL: 213 | cmdLSHELL(paramVector); 214 | break; 215 | case QUIT: 216 | cmdQUIT(paramVector); 217 | break; 218 | case HELP: 219 | cmdHELP(paramVector); 220 | break; 221 | default: 222 | Error::msg("Client: Sorry! this command function not finished yet.\n"); 223 | break; 224 | } 225 | 226 | } 227 | void CliPI::split(std::string src, std::string token, vector& vect) 228 | { 229 | int nbegin=0; 230 | int nend=0; 231 | while(nend != -1 && (unsigned int)nbegin < src.length() ) 232 | { 233 | nend = src.find_first_of(token, nbegin); 234 | if(nend == -1) { 235 | vect.push_back(src.substr(nbegin, src.length()-nbegin)); 236 | } else { 237 | if (nend != nbegin ) 238 | { 239 | vect.push_back(src.substr(nbegin, nend-nbegin)); 240 | } 241 | 242 | } 243 | nbegin = nend + 1; 244 | } 245 | } 246 | 247 | string CliPI::getEncodedParams(std::vector & paramVector) 248 | { 249 | string encodedParams; 250 | if(!paramVector.empty()) 251 | { 252 | vector::iterator iter=paramVector.begin(); 253 | encodedParams += *iter; 254 | for (++iter; iter!=paramVector.end(); ++iter) 255 | { 256 | encodedParams += DELIMITER + *iter; 257 | } 258 | } 259 | 260 | return encodedParams; 261 | } 262 | 263 | bool CliPI::cmdUSER(std::vector & paramVector) 264 | { 265 | if(paramVector.empty() || paramVector.size() != 1) 266 | { 267 | Error::msg("Usage: [username]"); 268 | return false; 269 | } else { 270 | packet.sendCMD(USER, getEncodedParams(paramVector)); 271 | // first receive response 272 | recvOnePacket(); 273 | if (packet.getTagid() == TAG_STAT) { 274 | if (packet.getStatid() == STAT_OK) { 275 | return true; 276 | } else if (packet.getStatid() == STAT_ERR){ 277 | cerr<< packet.getSBody() << endl; 278 | return false; 279 | } else { 280 | Error::msg("CliPI::cmdUSER: unknown statid %d", packet.getStatid()); 281 | return false; 282 | } 283 | 284 | } else { 285 | Error::msg("CliPI::cmdUSER: unknown tagid %d", packet.getTagid()); 286 | return false; 287 | } 288 | } 289 | 290 | } 291 | 292 | bool CliPI::cmdPASS(std::vector & paramVector) 293 | { 294 | if(paramVector.empty() || paramVector.size() != 2) 295 | { 296 | Error::msg("Usage: [password]"); 297 | for (vector::iterator iter=paramVector.begin(); iter!=paramVector.end(); ++iter) 298 | { 299 | std::cout << *iter << '\n'; 300 | } 301 | return false; 302 | } 303 | 304 | paramVector[1] = encryptPassword(paramVector[1]); 305 | packet.sendCMD(PASS, getEncodedParams(paramVector)); 306 | 307 | // first receive response 308 | recvOnePacket(); 309 | if (packet.getTagid() == TAG_STAT) { 310 | if (packet.getStatid() == STAT_OK) { 311 | // init userID, same as session id 312 | char buf[MAXLINE]; 313 | snprintf (buf, MAXLINE, "%u", packet.getSesid()); 314 | userID = buf; 315 | cout<< packet.getSBody() << endl; 316 | return true; 317 | } else if (packet.getStatid() == STAT_ERR){ 318 | cerr<< packet.getSBody() << endl; 319 | return false; 320 | } else { 321 | Error::msg("CliPI::cmdPASS: unknown statid %d", packet.getStatid()); 322 | return false; 323 | } 324 | 325 | } else { 326 | Error::msg("CliPI::cmdPASS: unknown tagid %d", packet.getTagid()); 327 | return false; 328 | } 329 | 330 | } 331 | 332 | void CliPI::cmdUSERADD(std::vector & paramVector) 333 | { 334 | if(paramVector.size() == 4 && paramVector[0] == "-u" && paramVector[2] == "-p") 335 | { 336 | paramVector.erase(paramVector.begin()); 337 | paramVector.erase(paramVector.begin()+1); 338 | 339 | paramVector[1] = encryptPassword(paramVector[1]); 340 | 341 | packet.sendCMD(USERADD, getEncodedParams(paramVector)); 342 | 343 | // first receive response 344 | recvOnePacket(); 345 | if (packet.getTagid() == TAG_STAT) { 346 | if (packet.getStatid() == STAT_OK) { 347 | cout<< packet.getSBody() << endl; 348 | return; 349 | } else if (packet.getStatid() == STAT_ERR){ 350 | cerr<< packet.getSBody() << endl; 351 | return; 352 | } else { 353 | Error::msg("CliPI::cmdPASS: unknown statid %d", packet.getStatid()); 354 | return; 355 | } 356 | 357 | } else { 358 | Error::msg("CliPI::cmdPASS: unknown tagid %d", packet.getTagid()); 359 | return; 360 | } 361 | } else { 362 | std::cout << "Usage: " << helpMap["USERADD"] << std::endl; 363 | return; 364 | } 365 | 366 | } 367 | 368 | void CliPI::cmdUSERDEL(std::vector & paramVector) 369 | { 370 | if(paramVector.size() == 1) 371 | { 372 | packet.sendCMD(USERDEL, getEncodedParams(paramVector)); 373 | 374 | // first receive response 375 | recvOnePacket(); 376 | if (packet.getTagid() == TAG_STAT) { 377 | if (packet.getStatid() == STAT_OK) { 378 | cout<< packet.getSBody() << endl; 379 | return; 380 | } else if (packet.getStatid() == STAT_ERR){ 381 | cerr<< packet.getSBody() << endl; 382 | return; 383 | } else { 384 | Error::msg("CliPI::cmdPASS: unknown statid %d", packet.getStatid()); 385 | return; 386 | } 387 | 388 | } else { 389 | Error::msg("CliPI::cmdPASS: unknown tagid %d", packet.getTagid()); 390 | return; 391 | } 392 | } else { 393 | std::cout << "Usage: " << helpMap["USERDEL"] << std::endl; 394 | return; 395 | } 396 | } 397 | 398 | void CliPI::cmdGET(std::vector & paramVector) 399 | { 400 | if(paramVector.empty() || paramVector.size() > 2) 401 | { 402 | std::cout << "Usage: " << helpMap["GET"] << std::endl; 403 | return; 404 | } 405 | 406 | string pathname; 407 | uint32_t nslice = 0; 408 | uint32_t sindex = 0; 409 | 410 | char buf[MAXLINE]; 411 | if (paramVector.size() == 1){ 412 | vector pathVector; 413 | split(paramVector[0], "/", pathVector); 414 | pathname = pathVector.back(); 415 | } else if (paramVector.size() == 2){ 416 | pathname = paramVector[1]; 417 | } 418 | 419 | if ((access(pathname.c_str(), F_OK)) == 0) { 420 | 421 | // string md5str = visualmd5sumNslice(pathname, tmp_sindex); 422 | // if (md5str.empty()) 423 | // { 424 | // printf("md5sum error\n"); 425 | // return; 426 | // } 427 | // packet.sendSTAT_MD5(md5str); 428 | // recvOnePacket(); 429 | // if(packet.getTagid() == TAG_STAT && packet.getStatid() == STAT_OK) 430 | // { 431 | // sindex = tmp_sindex; 432 | // //cout << packet.getSBody() <packet), this); 458 | cliDTP.recvFile(pathname.c_str(), fp, nslice, sindex); 459 | 460 | /*while(recvOnePacket()) 461 | { 462 | switch(packet.getTagid()) 463 | { 464 | case TAG_CMD: 465 | { 466 | switch(packet.getCmdid()) 467 | { 468 | case GET: 469 | { 470 | break; 471 | } 472 | case LMKDIR: 473 | { 474 | break; 475 | } 476 | default: 477 | { 478 | Error::msg("unknown cmdid: %d", packet.getCmdid()); 479 | break; 480 | } 481 | } 482 | break; 483 | } 484 | case TAG_STAT: 485 | { 486 | switch(packet.getStatid()) 487 | { 488 | case STAT_OK: 489 | { 490 | CliDTP cliDTP(&(this->packet), this); 491 | cliDTP.recvFile(pathname.c_str(), fp, nslice, sindex); 492 | return; 493 | } 494 | case STAT_BPR: 495 | { 496 | //cout << "File size match: " < paramVector; 498 | split(packet.getSBody(), DELIMITER, paramVector); 499 | cout << "File size match: " << paramVector[1] << "/" << paramVector[0] << endl; 500 | uint32_t tmp_sindex = std::stoul(paramVector[1]); 501 | 502 | string md5str = visualmd5sumNslice(pathname, tmp_sindex); 503 | if (md5str.empty()) 504 | { 505 | printf("md5sum error\n"); 506 | return; 507 | } 508 | packet.sendSTAT_MD5(md5str); 509 | recvOnePacket(); 510 | if(packet.getTagid() == TAG_STAT && packet.getStatid() == STAT_OK) 511 | { 512 | sindex = tmp_sindex; 513 | //cout << packet.getSBody() < paramVector; 579 | while (printf("%s", prompt), getline(std::cin, inputline)) 580 | { 581 | paramVector.clear(); 582 | std::istringstream is(inputline); 583 | while(is >> word) 584 | paramVector.push_back(word); 585 | 586 | // if user enter nothing, assume special anonymous user 587 | if (paramVector.size() == 1){ 588 | if (paramVector[0] == "y"){ 589 | return true; 590 | } else if (paramVector[0] == "n"){ 591 | return false; 592 | } else { 593 | continue; 594 | } 595 | } else { 596 | continue; 597 | } 598 | } 599 | return false; 600 | } 601 | 602 | void CliPI::rmdirDFS() 603 | { 604 | DIR *cur_dir = opendir("."); 605 | struct dirent *ent = NULL; 606 | struct stat st; 607 | 608 | if (!cur_dir) 609 | { 610 | Error::ret("opendir"); 611 | return; 612 | } 613 | 614 | while ((ent = readdir(cur_dir)) != NULL) 615 | { 616 | stat(ent->d_name, &st); 617 | 618 | if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) 619 | { 620 | continue; 621 | } 622 | 623 | if (S_ISDIR(st.st_mode)) 624 | { 625 | if( chdir(ent->d_name) == -1) 626 | { 627 | Error::sys("CliPI::rmdirDFS chdir"); 628 | return; 629 | } else { 630 | this->rmdirDFS(); 631 | if( chdir("..") == -1) 632 | { 633 | Error::sys("CliPI::rmdirDFS chdir(..)"); 634 | return; 635 | } 636 | } 637 | } 638 | 639 | remove(ent->d_name); 640 | } 641 | 642 | closedir(cur_dir); 643 | } 644 | 645 | void CliPI::removeDir(const char *path_raw, bool removeSelf) 646 | { 647 | char old_path[MAXLINE]; 648 | 649 | if (!path_raw) 650 | { 651 | return; 652 | } 653 | 654 | if ( !getcwd(old_path, MAXLINE)) 655 | { 656 | Error::sys("getcwd"); 657 | } 658 | 659 | if (chdir(path_raw) == -1) 660 | { 661 | fprintf(stderr, "not a dir or access error\n"); 662 | Error::sys("removeDir chdir(path_raw)"); 663 | return; 664 | } 665 | 666 | printf("path_raw : %s\n", path_raw); 667 | this->rmdirDFS(); 668 | if (chdir(old_path) == -1) 669 | { 670 | Error::sys("removeDir chdir(path_raw)"); 671 | return; 672 | } 673 | 674 | if (removeSelf) 675 | { 676 | unlink(old_path); 677 | } 678 | } 679 | 680 | void CliPI::cmdRGET(std::vector & paramVector) 681 | { 682 | if(paramVector.empty() || paramVector.size() > 2) 683 | { 684 | std::cout << "Usage: " << helpMap["RGET"] << std::endl; 685 | return; 686 | } 687 | string pathname; 688 | char buf[MAXLINE]; 689 | if (paramVector.size() == 1){ 690 | vector pathVector; 691 | split(paramVector[0], "/", pathVector); 692 | pathname = pathVector.back(); 693 | } else if (paramVector.size() == 2){ 694 | pathname = paramVector[1]; 695 | } 696 | 697 | if ((access(pathname.c_str(), F_OK)) == 0) { // already exists 698 | snprintf(buf, MAXLINE, "[%s] already exists, overwrite ? (y/n) ", pathname.c_str()); 699 | if(!confirmYN(buf)) 700 | { 701 | return; 702 | } else { 703 | // yes to overwite 704 | //removeDir(paramVector[0].c_str(), false); 705 | string shellCMD = "rm -rf " + pathname; 706 | if (system(shellCMD.c_str()) == -1) { 707 | printf("%s\n", strerror_r(errno, buf, MAXLINE)); 708 | return; 709 | } else { 710 | // OK 711 | printf("Dir '%s' emptied and removed\n", pathname.c_str()); 712 | } 713 | } 714 | } 715 | 716 | packet.sendCMD(RGET, getEncodedParams(paramVector)); 717 | 718 | CliDTP cliDTP(&(this->packet), this); 719 | 720 | while(recvOnePacket()) 721 | { 722 | switch(packet.getTagid()) 723 | { 724 | case TAG_CMD: 725 | { 726 | switch(packet.getCmdid()) 727 | { 728 | case GET: 729 | { 730 | //cout << packet.getSBody() < paramVector; 732 | split(packet.getSBody(), DELIMITER, paramVector); 733 | // cmdGET(paramVector[0], paramVector[1]); 734 | cmdGET(paramVector); 735 | break; 736 | } 737 | case LMKDIR: 738 | { 739 | if (cmdLMKDIR(packet.getSBody())) 740 | { 741 | packet.sendSTAT_OK(); 742 | } else { 743 | packet.sendSTAT_ERR(); 744 | return; 745 | } 746 | break; 747 | } 748 | default: 749 | { 750 | Error::msg("unknown cmdid: %d", packet.getCmdid()); 751 | break; 752 | } 753 | } 754 | break; 755 | } 756 | case TAG_STAT: 757 | { 758 | switch(packet.getStatid()) 759 | { 760 | case STAT_OK: 761 | { 762 | //cout << packet.getSBody() < & paramVector) 820 | { 821 | if(paramVector.empty() || paramVector.size() > 2) 822 | { 823 | std::cout << "Usage: " << helpMap["PUT"] << std::endl; 824 | return; 825 | } 826 | char pathname[MAXLINE]; 827 | char buf[MAXLINE]; 828 | uint32_t nslice = 0; 829 | uint32_t sindex = 0; 830 | 831 | strcpy(pathname,paramVector[0].c_str()); 832 | struct stat statBuf; 833 | int n = stat(paramVector[0].c_str(), &statBuf); 834 | if(!n) // stat call success 835 | { 836 | if (S_ISREG(statBuf.st_mode)){ 837 | ; 838 | } else if (S_ISDIR(statBuf.st_mode)){ 839 | cout << "put: cannot upload [" << pathname << "]: Is a directory" << endl; 840 | return; 841 | } else { 842 | cout << "put: [" << pathname << "] not a regular file or directory" << endl; 843 | return; 844 | } 845 | 846 | } else { // stat error 847 | Error::msg("stat: %s", strerror_r(errno, buf, MAXLINE)); 848 | return; 849 | } 850 | 851 | 852 | FILE *fp; 853 | if ( (fp = fopen(pathname, "rb")) == NULL) 854 | { 855 | Error::msg("%s", strerror_r(errno, buf, MAXLINE)); 856 | return; 857 | } else if ( (n = getFileNslice(pathname, &nslice)) < 0) { 858 | if ( n == -2) { 859 | Error::msg("Too large file size.", buf); 860 | } else { 861 | Error::msg("File stat error."); 862 | } 863 | return; 864 | } else { 865 | // first check file size 866 | string sizestr = getFilesize(string(pathname)); 867 | if (sizestr.empty()) 868 | { 869 | Error::ret("getFilesize error"); 870 | return; 871 | } 872 | paramVector.push_back(sizestr); 873 | packet.sendCMD(PUT, getEncodedParams(paramVector)); 874 | } 875 | 876 | while(recvOnePacket()) 877 | { 878 | switch(packet.getTagid()) 879 | { 880 | case TAG_CMD: 881 | { 882 | switch(packet.getCmdid()) 883 | { 884 | case GET: 885 | { 886 | break; 887 | } 888 | case LMKDIR: 889 | { 890 | break; 891 | } 892 | default: 893 | { 894 | Error::msg("unknown cmdid: %d", packet.getCmdid()); 895 | break; 896 | } 897 | } 898 | break; 899 | } 900 | case TAG_STAT: 901 | { 902 | switch(packet.getStatid()) 903 | { 904 | case STAT_OK: 905 | { 906 | CliDTP cliDTP(&(this->packet), this); 907 | cliDTP.sendFile(pathname, fp, nslice, sindex); 908 | return; 909 | } 910 | case STAT_BPR: 911 | { 912 | //cout << "File size match: " < paramVector; 914 | split(packet.getSBody(), DELIMITER, paramVector); 915 | cout << "File size match: " << paramVector[1] << "/" << paramVector[0] << endl; 916 | uint32_t tmp_sindex = std::stoul(paramVector[1]); 917 | 918 | string md5str = visualmd5sumNslice(pathname, tmp_sindex); 919 | if (md5str.empty()) 920 | { 921 | printf("md5sum error\n"); 922 | return; 923 | } 924 | packet.sendSTAT_MD5(md5str); 925 | recvOnePacket(); 926 | if(packet.getTagid() == TAG_STAT && packet.getStatid() == STAT_OK) 927 | { 928 | sindex = tmp_sindex; 929 | //cout << packet.getSBody() < & paramVector) 1017 | { 1018 | //printf("RPUT request\n"); 1019 | 1020 | if(paramVector.empty() || paramVector.size() > 2) 1021 | { 1022 | std::cout << "Usage: " << helpMap["RPUT"] << std::endl; 1023 | return; 1024 | } 1025 | 1026 | char buf[MAXLINE]; 1027 | struct stat statBuf; 1028 | int n = stat(paramVector[0].c_str(), &statBuf); 1029 | if(!n) // stat call success 1030 | { 1031 | if (S_ISREG(statBuf.st_mode)){ 1032 | cout << "rput: [" << paramVector[0] << "] not a directory" << endl; 1033 | return; 1034 | } else if (S_ISDIR(statBuf.st_mode)){ 1035 | ; 1036 | } else { 1037 | cout << "rput: [" << paramVector[0] << "] not a regular file or directory" << endl; 1038 | return; 1039 | } 1040 | 1041 | } else { // stat error 1042 | Error::msg("stat: %s", strerror_r(errno, buf, MAXLINE)); 1043 | return; 1044 | } 1045 | 1046 | string clipath = paramVector[0]; 1047 | string srvpath; 1048 | vector pathVector; 1049 | if (paramVector.size() == 1) 1050 | { 1051 | split(paramVector[0], "/", pathVector); 1052 | srvpath = pathVector.back(); 1053 | } else { 1054 | srvpath = paramVector[1]; 1055 | } 1056 | 1057 | packet.sendCMD(RPUT, getEncodedParams(paramVector)); 1058 | while(recvOnePacket()) 1059 | { 1060 | if (packet.getTagid() == TAG_STAT) 1061 | { 1062 | if (packet.getStatid() == STAT_OK) 1063 | { 1064 | cout << packet.getSBody() < > dirQueue; 1098 | dirQueue.push(pair(srvrootpath, clirootpath)); 1099 | 1100 | while(!dirQueue.empty()) 1101 | { 1102 | pair dirPair = dirQueue.front(); 1103 | string srvpath = dirPair.first; 1104 | string clipath = dirPair.second; 1105 | 1106 | std::vector paramVector = {srvpath}; 1107 | if (cmdMKDIR(paramVector)) 1108 | { 1109 | dirQueue.pop(); // server create dir successfully 1110 | } else { 1111 | return; 1112 | } 1113 | 1114 | // then iterate this client dir 1115 | DIR * dir= opendir(clipath.c_str()); 1116 | char buf[MAXLINE]; 1117 | if(!dir) 1118 | { 1119 | // send STAT_ERR Response 1120 | // GNU-specific strerror_r: char *strerror_r(int errnum, char *buf, size_t buflen); 1121 | packet.sendSTAT_ERR(strerror_r(errno, buf, MAXLINE)); 1122 | return; 1123 | } else { 1124 | // send STAT_OK 1125 | packet.sendSTAT_OK(); 1126 | } 1127 | 1128 | struct dirent* e; 1129 | if (srvpath.back() != '/') 1130 | { 1131 | srvpath += "/"; 1132 | } 1133 | if (clipath.back() != '/') 1134 | { 1135 | clipath += "/"; 1136 | } 1137 | 1138 | while( (e = readdir(dir)) ) 1139 | { 1140 | if(e->d_type == 4 && strcmp(e->d_name, ".") && strcmp(e->d_name, "..")) 1141 | { 1142 | dirQueue.push(pair(srvpath + e->d_name, clipath + e->d_name)); 1143 | } 1144 | else if(e->d_type == 8) 1145 | { 1146 | std::vector paramVector = {clipath + e->d_name, srvpath + e->d_name}; 1147 | cmdPUT(paramVector); 1148 | } 1149 | } 1150 | closedir(dir); 1151 | 1152 | } 1153 | } 1154 | void CliPI::cmdLS(std::vector & paramVector) 1155 | { 1156 | if(paramVector.size() > 1) 1157 | { 1158 | std::cout << "Usage: " << helpMap["LS"] << std::endl; 1159 | return; 1160 | } 1161 | 1162 | packet.sendCMD(LS, getEncodedParams(paramVector)); 1163 | 1164 | // first receive response 1165 | recvOnePacket(); 1166 | if (packet.getTagid() == TAG_STAT) { 1167 | if (packet.getStatid() == STAT_OK) { 1168 | //cout<< packet.getSBody() << endl; 1169 | } else if (packet.getStatid() == STAT_ERR){ 1170 | cerr<< packet.getSBody() << endl; 1171 | return; 1172 | } else { 1173 | Error::msg("unknown statid %d", packet.getStatid()); 1174 | return; 1175 | } 1176 | 1177 | } else { 1178 | Error::msg("unknown tagid %d", packet.getTagid()); 1179 | return; 1180 | } 1181 | int cnt = 0; 1182 | while(recvOnePacket()) 1183 | { 1184 | if (packet.getTagid() == TAG_DATA && packet.getDataid() == DATA_LIST) { 1185 | ++cnt; 1186 | cerr << packet.getSBody(); 1187 | if (packet.getSindex() == 0) 1188 | { 1189 | continue; 1190 | } 1191 | 1192 | 1193 | disable_terminal_return(); 1194 | char ch; 1195 | /* Key reading loop */ 1196 | while(fprintf(stderr, "\n\033[7mpage %d (press j for page down or q to quit)\033[0m", cnt), ch = getc(stdin)) 1197 | { 1198 | if (ch == 'j') 1199 | { 1200 | packet.sendSTAT(STAT_CTN, "continue"); 1201 | fprintf(stderr, "\033[2K\r\033[0m"); 1202 | break; 1203 | } else if (ch == 'q') 1204 | { 1205 | packet.sendSTAT(STAT_TERM, "terminate"); 1206 | break; 1207 | } else { 1208 | fprintf(stderr, "error\n"); 1209 | continue; 1210 | } 1211 | } 1212 | restore_terminal_settings(); 1213 | 1214 | 1215 | } else if (packet.getTagid() == TAG_STAT && packet.getStatid() == STAT_EOT){ 1216 | //cout << endl << packet.getSBody() << endl; 1217 | cout << endl; 1218 | break; 1219 | } else { 1220 | Error::msg("unknown tagid %d with statid %d", packet.getTagid(), packet.getStatid()); 1221 | return; 1222 | } 1223 | } 1224 | } 1225 | 1226 | void CliPI::cmdLLS(std::vector & paramVector) 1227 | { 1228 | string shellCMD = "ls --color=auto"; 1229 | for (auto it = paramVector.begin(); it != paramVector.end(); ++it){ 1230 | //std::cout << *it << std::endl; 1231 | shellCMD += " " + *it; 1232 | } 1233 | if (system(shellCMD.c_str()) == -1) { 1234 | char buf[MAXLINE]; 1235 | std::cout << "system(): " << strerror_r(errno, buf, MAXLINE) << std::endl; 1236 | } 1237 | } 1238 | 1239 | void CliPI::cmdCD(std::vector & paramVector) 1240 | { 1241 | if(paramVector.empty() || paramVector.size() != 1) 1242 | { 1243 | std::cout << "Usage: " << helpMap["CD"] << std::endl; 1244 | return; 1245 | } 1246 | 1247 | packet.sendCMD(CD, getEncodedParams(paramVector)); 1248 | 1249 | // first receive response 1250 | recvOnePacket(); 1251 | if (packet.getTagid() == TAG_STAT) { 1252 | if (packet.getStatid() == STAT_OK) { 1253 | cout << packet.getSBody() < & paramVector) 1271 | { 1272 | if(paramVector.empty() || paramVector.size() != 1) 1273 | { 1274 | std::cout << "Usage: " << helpMap["LCD"] << std::endl; 1275 | return; 1276 | } 1277 | 1278 | int n; 1279 | //char buf[MAXLINE]; 1280 | if( (n = chdir(paramVector[0].c_str())) == -1) 1281 | { 1282 | // GNU-specific strerror_r: char *strerror_r(int errnum, char *buf, size_t buflen); 1283 | Error::ret("lcd"); 1284 | return; 1285 | } 1286 | } 1287 | 1288 | void CliPI::cmdRM(std::vector & paramVector) 1289 | { 1290 | if(paramVector.empty() || paramVector.size() != 1) 1291 | { 1292 | std::cout << "Usage: " << helpMap["RM"] << std::endl; 1293 | return; 1294 | } 1295 | 1296 | packet.sendCMD(RM, getEncodedParams(paramVector)); 1297 | 1298 | // first receive response 1299 | recvOnePacket(); 1300 | if (packet.getTagid() == TAG_STAT) { 1301 | if (packet.getStatid() == STAT_OK) { 1302 | cout << packet.getSBody() < & paramVector) 1320 | { 1321 | string shellCMD = "rm"; 1322 | for (auto it = paramVector.begin(); it != paramVector.end(); ++it){ 1323 | //std::cout << *it << std::endl; 1324 | shellCMD += " " + *it; 1325 | } 1326 | if (system(shellCMD.c_str()) == -1) { 1327 | char buf[MAXLINE]; 1328 | std::cout << "system(): " << strerror_r(errno, buf, MAXLINE) << std::endl; 1329 | } 1330 | } 1331 | 1332 | void CliPI::cmdPWD(std::vector & paramVector) 1333 | { 1334 | if(paramVector.size() > 1) 1335 | { 1336 | std::cout << "Usage: " << helpMap["PWD"] << std::endl; 1337 | return; 1338 | } else if (paramVector.size() == 1 && paramVector[0] != "-a") 1339 | { 1340 | std::cout << "Usage: " << helpMap["PWD"] << std::endl; 1341 | return; 1342 | } 1343 | 1344 | packet.sendCMD(PWD, getEncodedParams(paramVector)); 1345 | 1346 | // first receive response 1347 | recvOnePacket(); 1348 | if (packet.getTagid() == TAG_STAT) { 1349 | if (packet.getStatid() == STAT_OK) { 1350 | cout << packet.getSBody() < & paramVector) 1367 | { 1368 | string shellCMD = "pwd"; 1369 | for (auto it = paramVector.begin(); it != paramVector.end(); ++it){ 1370 | //std::cout << *it << std::endl; 1371 | shellCMD += " " + *it; 1372 | } 1373 | if (system(shellCMD.c_str()) == -1) { 1374 | char buf[MAXLINE]; 1375 | std::cout << "system(): " << strerror_r(errno, buf, MAXLINE) << std::endl; 1376 | } 1377 | } 1378 | 1379 | bool CliPI::cmdMKDIR(std::vector & paramVector) 1380 | { 1381 | if(paramVector.empty() || paramVector.size() != 1) 1382 | { 1383 | std::cout << "Usage: " << helpMap["MKDIR"] << std::endl; 1384 | return false; 1385 | } 1386 | 1387 | packet.sendCMD(MKDIR, getEncodedParams(paramVector)); 1388 | 1389 | // first receive response 1390 | recvOnePacket(); 1391 | if (packet.getTagid() == TAG_STAT) { 1392 | if (packet.getStatid() == STAT_OK) { 1393 | cout << packet.getSBody() < & paramVector) 1426 | { 1427 | string shellCMD = "mkdir"; 1428 | for (auto it = paramVector.begin(); it != paramVector.end(); ++it){ 1429 | //std::cout << *it << std::endl; 1430 | shellCMD += " " + *it; 1431 | } 1432 | if (system(shellCMD.c_str()) == -1) { 1433 | char buf[MAXLINE]; 1434 | std::cout << "system(): " << strerror_r(errno, buf, MAXLINE) << std::endl; 1435 | } 1436 | } 1437 | 1438 | void CliPI::cmdRMDIR(std::vector & paramVector) 1439 | { 1440 | if(paramVector.empty() || paramVector.size() != 1) 1441 | { 1442 | std::cout << "Usage: " << helpMap["RMDIR"] << std::endl; 1443 | return; 1444 | } 1445 | 1446 | packet.sendCMD(RMDIR, getEncodedParams(paramVector)); 1447 | 1448 | // first receive response 1449 | recvOnePacket(); 1450 | if (packet.getTagid() == TAG_STAT) { 1451 | if (packet.getStatid() == STAT_OK) { 1452 | cout << packet.getSBody() < & paramVector) 1469 | { 1470 | string shellcmdstring; 1471 | for (auto it = paramVector.begin(); it != paramVector.end(); ++it){ 1472 | //std::cout << *it << std::endl; 1473 | shellcmdstring += " " + *it; 1474 | } 1475 | if (system(shellcmdstring.c_str()) == -1) { 1476 | char buf[MAXLINE]; 1477 | std::cout << "system(): " << strerror_r(errno, buf, MAXLINE) << std::endl; 1478 | } 1479 | } 1480 | 1481 | void CliPI::cmdSHELL(std::vector & paramVector) 1482 | { 1483 | if(paramVector.empty() || paramVector.size() == 0) 1484 | { 1485 | std::cout << "Usage: " << helpMap["SHELL"] << std::endl; 1486 | return; 1487 | } 1488 | 1489 | packet.sendCMD(SHELL, getEncodedParams(paramVector)); 1490 | 1491 | 1492 | while(recvOnePacket()) 1493 | { 1494 | switch(packet.getTagid()) 1495 | { 1496 | case TAG_CMD: 1497 | { 1498 | switch(packet.getCmdid()) 1499 | { 1500 | case GET: 1501 | { 1502 | break; 1503 | } 1504 | case LMKDIR: 1505 | { 1506 | break; 1507 | } 1508 | default: 1509 | { 1510 | Error::msg("unknown cmdid: %d", packet.getCmdid()); 1511 | break; 1512 | } 1513 | } 1514 | break; 1515 | } 1516 | case TAG_STAT: 1517 | { 1518 | switch(packet.getStatid()) 1519 | { 1520 | case STAT_OK: 1521 | { 1522 | cout << packet.getSBody() < & paramVector) 1580 | { 1581 | if(paramVector.size() != 0) 1582 | { 1583 | std::cout << "Usage: " << helpMap["QUIT"] << std::endl; 1584 | return; 1585 | } 1586 | 1587 | Socket::tcpClose(connfd); 1588 | 1589 | exit(1); 1590 | } 1591 | 1592 | void CliPI::cmdHELP(std::vector & paramVector) 1593 | { 1594 | if(paramVector.size() == 0) 1595 | { 1596 | int i = 1; 1597 | std::cout << "commands:" << std::endl; 1598 | for (map::iterator iter=helpMap.begin(); iter!=helpMap.end(); ++iter, ++i) 1599 | { 1600 | std::cout << "\t" << iter->first; 1601 | if (i % 5 == 0) 1602 | { 1603 | std::cout << std::endl; 1604 | } 1605 | } 1606 | 1607 | if ((i -1) % 5 != 0){ 1608 | std::cout << std::endl; 1609 | } 1610 | 1611 | } else if(paramVector.size() == 1){ 1612 | map::iterator iter = helpMap.find(toUpper(paramVector[0])); 1613 | if (iter != helpMap.end()) 1614 | { 1615 | std::cout << "Usage: " << helpMap[toUpper(paramVector[0])] << std::endl; 1616 | } else { 1617 | std::cerr << paramVector[0] << ": command not found" << std::endl; 1618 | } 1619 | } else { 1620 | std::cout << "Usage: " << helpMap["HELP"] << std::endl; 1621 | } 1622 | return; 1623 | } 1624 | 1625 | int CliPI::getFileNslice(const char *pathname, uint32_t *pnslice_o) 1626 | { 1627 | 1628 | unsigned long filesize = 0, n = MAXNSLICE; 1629 | 1630 | struct stat statbuff; 1631 | if(stat(pathname, &statbuff) < 0){ 1632 | return -1; // error 1633 | } else { 1634 | if (statbuff.st_size == 0) 1635 | { 1636 | return 0; // file is empty. 1637 | } else { 1638 | filesize = statbuff.st_size; 1639 | } 1640 | } 1641 | if (filesize % SLICECAP == 0) 1642 | { 1643 | *pnslice_o = filesize/SLICECAP; 1644 | } else if ( (n = filesize/SLICECAP + 1) > MAXNSLICE ){ 1645 | Error::msg("too large file size: %d\n (MAX: %d)", n, MAXNSLICE); 1646 | return -2; 1647 | } else { 1648 | *pnslice_o = filesize/SLICECAP + 1; 1649 | } 1650 | //printf("getFileNslice nslice: %d\n", *pnslice_o); 1651 | return 1; 1652 | } 1653 | 1654 | string CliPI::toUpper(string &s) 1655 | { 1656 | string upperStr; 1657 | for(string::size_type i=0; i < s.size(); i++) 1658 | upperStr += toupper(s[i]); 1659 | return upperStr; 1660 | } 1661 | 1662 | string CliPI::toLower(string &s) 1663 | { 1664 | string upperStr; 1665 | for(string::size_type i=0; i < s.size(); i++) 1666 | upperStr += tolower(s[i]); 1667 | return upperStr; 1668 | } 1669 | int CliPI::getConnfd() 1670 | { 1671 | return this->connfd; 1672 | } 1673 | void CliPI::saveUserState() 1674 | { 1675 | std::cout<< "\n\033[32msave user state ok\033[0m" << std::endl; 1676 | } -------------------------------------------------------------------------------- /client/clipi.h: -------------------------------------------------------------------------------- 1 | #ifndef _TINYFTP_CLIPI_H_ 2 | #define _TINYFTP_CLIPI_H_ 3 | 4 | #include "../common/common.h" 5 | #include "../common/error.h" 6 | #include "../common/packet.h" 7 | #include "../common/sockstream.h" 8 | #include "../common/socket.h" 9 | #include "../common/pi.h" 10 | #include "clidtp.h" 11 | 12 | // Client Protocol Interpreter (CliPI) 13 | class CliPI : public PI 14 | { 15 | public: 16 | CliPI(const char *host); 17 | bool recvOnePacket(); 18 | bool sendOnePacket(PacketStruct * ps, size_t nbytes); 19 | bool sendOnePacketBlocked(PacketStruct * ps, size_t nbytes); 20 | void run(uint16_t cmdid, std::vector & cmdVector); 21 | void split(std::string src, std::string token, vector& vect); 22 | string getEncodedParams(std::vector & paramVector); 23 | 24 | bool cmdUSER(std::vector & cmdVector); 25 | bool cmdPASS(std::vector & cmdVector); 26 | void cmdUSERADD(std::vector & cmdVector); 27 | void cmdUSERDEL(std::vector & cmdVector); 28 | 29 | void cmdGET(std::vector & cmdVector); 30 | //void cmdGET(string srvpath, string clipath); 31 | void cmdRGET(std::vector & cmdVector); 32 | void cmdPUT(std::vector & cmdVector); 33 | void cmdRPUT(std::vector & cmdVector); 34 | void RPUT_iterate(string srvrootpath, string clirootpath); 35 | //void flashPUT(vector & paramVector); 36 | void cmdLS(std::vector & cmdVector); 37 | void cmdLLS(std::vector & cmdVector); 38 | void cmdCD(std::vector & cmdVector); 39 | void cmdLCD(std::vector & cmdVector); 40 | void cmdRM(std::vector & cmdVector); 41 | void cmdLRM(std::vector & cmdVector); 42 | void cmdPWD(std::vector & cmdVector); 43 | void cmdLPWD(std::vector & cmdVector); 44 | bool cmdMKDIR(std::vector & cmdVector); 45 | void cmdLMKDIR(std::vector & cmdVector); 46 | bool cmdLMKDIR(string path); 47 | void cmdRMDIR(std::vector & cmdVector); 48 | void cmdSHELL(std::vector & cmdVector); 49 | void cmdLSHELL(std::vector & cmdVector); 50 | void cmdQUIT(std::vector & cmdVector); 51 | void cmdHELP(std::vector & cmdVector); 52 | 53 | int getConnfd(); 54 | 55 | private: 56 | int getFileNslice(const char *pathname, uint32_t *pnslice_o); 57 | string toUpper(string &s); 58 | string toLower(string &s); 59 | bool confirmYN(const char * prompt); 60 | void rmdirDFS(); 61 | void removeDir(const char *path_raw, bool removeSelf); 62 | void saveUserState(); 63 | 64 | 65 | 66 | 67 | 68 | private: 69 | Packet packet; 70 | Packet readpacket; 71 | SockStream connSockStream; 72 | string userID; // for simple, userID is equal to session ID 73 | int connfd; 74 | // uint16_t cmdid; 75 | // std::vector cmdVector; 76 | //CliDTP cliDTP; 77 | static std::map helpMap; 78 | 79 | }; 80 | 81 | #endif /* _TINYFTP_CLIPI_H_ */ -------------------------------------------------------------------------------- /client/ui.cpp: -------------------------------------------------------------------------------- 1 | #include "ui.h" 2 | 3 | // command init 4 | map UI::cmdMap = { {"USER", USER}, 5 | {"PASS", PASS}, 6 | {"USERADD", USERADD}, 7 | {"USERDEL", USERDEL}, 8 | 9 | {"GET", GET}, 10 | {"PUT", PUT}, 11 | {"LS", LS}, 12 | {"LLS", LLS}, 13 | {"CD", CD}, 14 | {"LCD", LCD}, 15 | {"RM", RM}, 16 | {"LRM", LRM}, 17 | {"PWD", PWD}, 18 | {"LPWD", LPWD}, 19 | {"MKDIR", MKDIR}, 20 | {"LMKDIR", LMKDIR}, 21 | {"QUIT", QUIT}, 22 | {"HELP", HELP}, 23 | 24 | {"MGET", MGET}, 25 | {"MPUT", MPUT}, 26 | {"RGET", RGET}, 27 | {"RPUT", RPUT}, 28 | {"RMDIR", RMDIR}, 29 | 30 | {"SHELL", SHELL}, 31 | {"LSHELL", LSHELL}, 32 | 33 | {"BINARY", BINARY}, 34 | {"ASCII", ASCII} 35 | }; 36 | 37 | UI::UI(const char *host): cliPI(host) 38 | { 39 | 40 | } 41 | 42 | void UI::run() 43 | { 44 | string word; 45 | string inputline; 46 | 47 | // user validate commands 48 | //while (printf("\033[35mUsername for 'tinyFTP': \033[0m"), getline(std::cin, inputline)) 49 | while (printf("Username for 'tinyFTP': "), getline(std::cin, inputline)) 50 | { 51 | // clear cmdVector each time when user input 52 | this->cmdVector.clear(); 53 | 54 | std::istringstream is(inputline); 55 | while(is >> word) 56 | this->cmdVector.push_back(word); 57 | 58 | // if user enter nothing, assume special anonymous user 59 | if (this->cmdVector.empty()) 60 | { 61 | this->cmdVector.push_back("anonymous"); 62 | this->cmdVector.push_back("anonymous"); 63 | if (!cliPI.cmdPASS(this->cmdVector)) 64 | { 65 | continue; 66 | } else { 67 | break; 68 | } 69 | } 70 | 71 | if (!cliPI.cmdUSER(this->cmdVector)) 72 | { 73 | continue; 74 | } else { 75 | char *password = getpass("\033[35mPassword for 'tinyFTP': \033[0m"); 76 | // printf("\033[35mPassword for 'tinyFTP': \033[0m"); 77 | // getline(std::cin, inputline); 78 | // std::istringstream isPass(inputline); 79 | // while(isPass >> word) 80 | // { 81 | // this->cmdVector.push_back(word); 82 | // //std::cout << word << endl; 83 | // } 84 | this->cmdVector.push_back(password); 85 | if (!cliPI.cmdPASS(this->cmdVector)) 86 | { 87 | continue; 88 | } else { 89 | break; 90 | } 91 | } 92 | } 93 | this->username = this->cmdVector[0]; 94 | 95 | 96 | int maxfdp1; 97 | fd_set rset; 98 | int connfd = cliPI.getConnfd(); 99 | 100 | FD_ZERO(&rset); 101 | 102 | printf("%s@tinyFTP> ", username.c_str()); 103 | while(1) 104 | { 105 | fflush(stdout); 106 | FD_SET(connfd, &rset); 107 | FD_SET(fileno(stdin), &rset); 108 | maxfdp1 = connfd + 1; 109 | if (select(maxfdp1, &rset, NULL, NULL, NULL) < 0) 110 | Error::sys("select error"); 111 | 112 | if (FD_ISSET(connfd, &rset)) { /* socket is readable */ 113 | cliPI.recvOnePacket(); 114 | } 115 | 116 | if (FD_ISSET(fileno(stdin), &rset)) /* input is readable */ 117 | { 118 | getline(std::cin, inputline); 119 | cmdRun(inputline); 120 | printf("%s@tinyFTP> ", username.c_str()); 121 | } 122 | } 123 | 124 | // other ftp commands: first cout prompt (use "," operator) 125 | // while (printf("%s@tinyFTP> ", username.c_str()), getline(std::cin, inputline)) 126 | // { 127 | // cmdRun(inputline); 128 | // } 129 | 130 | } 131 | void UI::cmdRun(string & inputline) 132 | { 133 | // clear cmdVector each time when user input 134 | this->cmdVector.clear(); 135 | //std::cout << "inputline: " << inputline << inputline.size() << std::endl; 136 | 137 | // split input string 138 | for (auto it = inputline.begin(); it < inputline.end(); ++it) 139 | { 140 | string param; 141 | for(; it < inputline.end(); ++it) 142 | { 143 | if ((*it) == ' ' || (*it) == '\t') 144 | { 145 | break; 146 | } else if ((*it) == '\\' && (it + 1) != inputline.end() && *(it + 1) == ' ') 147 | { 148 | param += ' '; 149 | ++it; 150 | } else { 151 | param += *it; 152 | } 153 | } 154 | if (!param.empty()) 155 | { 156 | this->cmdVector.push_back(param); 157 | } 158 | } 159 | 160 | // for (auto it = cmdVector.cbegin(); it != cmdVector.cend(); ++it) 161 | // std::cout << it->size() << "cmdVector: " << *it << std::endl; 162 | 163 | // std::istringstream is(inputline); 164 | // while(is >> word) 165 | // this->cmdVector.push_back(word); 166 | 167 | if (!cmdCheck()) 168 | { 169 | return; 170 | } else { 171 | // remove command word, others are params 172 | cmdVector.erase(cmdVector.begin()); 173 | cliPI.run(this->cmdid, this->cmdVector); 174 | } 175 | 176 | // for (auto it = cmdVector.cbegin(); it != cmdVector.cend(); ++it) 177 | // std::cout << "cmdVector" << *it << std::endl; 178 | // for (std::vector::size_type i = 0; i < cmdVector.size(); i++) 179 | // std::cout << cmdVecto 180 | } 181 | bool UI::cmdCheck() 182 | { 183 | if (cmdVector.empty()) 184 | { 185 | return false; 186 | } 187 | map::iterator iter = cmdMap.find(toUpper(cmdVector[0])); 188 | if (iter != cmdMap.end()) 189 | { 190 | this->cmdid = iter->second; 191 | return true; 192 | } else { 193 | std::cerr << cmdVector[0] << ": command not found" << std::endl; 194 | return false; 195 | } 196 | } 197 | 198 | string UI::toUpper(string &s) 199 | { 200 | string upperStr; 201 | for(string::size_type i=0; i < s.size(); i++) 202 | upperStr += toupper(s[i]); 203 | return upperStr; 204 | } -------------------------------------------------------------------------------- /client/ui.h: -------------------------------------------------------------------------------- 1 | #ifndef _TINYFTP_UI_H_ 2 | #define _TINYFTP_UI_H_ 3 | 4 | #include "../common/common.h" 5 | #include "../common/error.h" 6 | #include "../common/sockstream.h" 7 | 8 | #include "clipi.h" 9 | 10 | 11 | typedef struct command 12 | { 13 | short int id; 14 | std::vector argVec; 15 | 16 | } Command; 17 | 18 | // User Interface (UI) 19 | class UI 20 | { 21 | public: 22 | UI(const char *host); 23 | void run(); 24 | 25 | private: 26 | // first elemment is command. other is options 27 | std::vector cmdVector; 28 | uint16_t cmdid; 29 | CliPI cliPI; 30 | string username; 31 | 32 | void cmdRun(string & inputline); 33 | // decode the input line to a command 34 | bool cmdCheck(); 35 | //void appendArg(struct command* c, char* s); 36 | static map cmdMap; 37 | 38 | string toUpper(string &s); 39 | }; 40 | 41 | #endif /* _TINYFTP_UI_H_ */ -------------------------------------------------------------------------------- /common/common.cpp: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "error.h" 3 | void 4 | Fclose(FILE *fp) 5 | { 6 | if (fclose(fp) != 0) 7 | Error::sys("fclose error"); 8 | } 9 | 10 | void 11 | Fclose(FILE **fp) 12 | { 13 | if (fclose(*fp) != 0) 14 | Error::sys("fclose error"); 15 | *fp = NULL; 16 | } 17 | 18 | FILE * 19 | Fdopen(int fd, const char *type) 20 | { 21 | FILE *fp; 22 | 23 | if ( (fp = fdopen(fd, type)) == NULL) 24 | Error::sys("fdopen error"); 25 | 26 | return(fp); 27 | } 28 | 29 | char * 30 | Fgets(char *ptr, int n, FILE *stream) 31 | { 32 | char *rptr; 33 | 34 | if ( (rptr = fgets(ptr, n, stream)) == NULL && ferror(stream)) 35 | Error::sys("fgets error"); 36 | 37 | return (rptr); 38 | } 39 | 40 | FILE * 41 | Fopen(const char *filename, const char *mode) 42 | { 43 | FILE *fp; 44 | 45 | if ( (fp = fopen(filename, mode)) == NULL) 46 | Error::sys("fopen error"); 47 | 48 | return(fp); 49 | } 50 | 51 | void 52 | Fputs(const char *ptr, FILE *stream) 53 | { 54 | if (fputs(ptr, stream) == EOF) 55 | Error::sys("fputs error"); 56 | } 57 | void * 58 | Malloc(size_t size) 59 | { 60 | void *ptr; 61 | 62 | if ( (ptr = malloc(size)) == NULL) 63 | Error::sys("malloc error"); 64 | memset(ptr, 0, size); 65 | return(ptr); 66 | } 67 | 68 | 69 | void 70 | Pthread_create(pthread_t *tid, const pthread_attr_t *attr, 71 | void * (*func)(void *), void *arg) 72 | { 73 | int n; 74 | 75 | if ( (n = pthread_create(tid, attr, func, arg)) == 0) 76 | return; 77 | errno = n; 78 | Error::sys("pthread_create error"); 79 | } 80 | 81 | void 82 | Pthread_join(pthread_t tid, void **status) 83 | { 84 | int n; 85 | 86 | if ( (n = pthread_join(tid, status)) == 0) 87 | return; 88 | errno = n; 89 | Error::sys("pthread_join error"); 90 | } 91 | 92 | void 93 | Pthread_detach(pthread_t tid) 94 | { 95 | int n; 96 | 97 | if ( (n = pthread_detach(tid)) == 0) 98 | return; 99 | errno = n; 100 | Error::sys("pthread_detach error"); 101 | } 102 | 103 | void 104 | Pthread_kill(pthread_t tid, int signo) 105 | { 106 | int n; 107 | 108 | if ( (n = pthread_kill(tid, signo)) == 0) 109 | return; 110 | errno = n; 111 | Error::sys("pthread_kill error"); 112 | } 113 | 114 | void 115 | Pthread_mutexattr_init(pthread_mutexattr_t *attr) 116 | { 117 | int n; 118 | 119 | if ( (n = pthread_mutexattr_init(attr)) == 0) 120 | return; 121 | errno = n; 122 | Error::sys("pthread_mutexattr_init error"); 123 | } 124 | 125 | #ifdef _POSIX_THREAD_PROCESS_SHARED 126 | void 127 | Pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int flag) 128 | { 129 | int n; 130 | 131 | if ( (n = pthread_mutexattr_setpshared(attr, flag)) == 0) 132 | return; 133 | errno = n; 134 | Error::sys("pthread_mutexattr_setpshared error"); 135 | } 136 | #endif 137 | 138 | void 139 | Pthread_mutex_init(pthread_mutex_t *mptr, pthread_mutexattr_t *attr) 140 | { 141 | int n; 142 | 143 | if ( (n = pthread_mutex_init(mptr, attr)) == 0) 144 | return; 145 | errno = n; 146 | Error::sys("pthread_mutex_init error"); 147 | } 148 | 149 | /* include Pthread_mutex_lock */ 150 | void 151 | Pthread_mutex_lock(pthread_mutex_t *mptr) 152 | { 153 | int n; 154 | 155 | if ( (n = pthread_mutex_lock(mptr)) == 0) 156 | return; 157 | errno = n; 158 | Error::sys("pthread_mutex_lock error"); 159 | } 160 | /* end Pthread_mutex_lock */ 161 | 162 | void 163 | Pthread_mutex_unlock(pthread_mutex_t *mptr) 164 | { 165 | int n; 166 | 167 | if ( (n = pthread_mutex_unlock(mptr)) == 0) 168 | return; 169 | errno = n; 170 | Error::sys("pthread_mutex_unlock error"); 171 | } 172 | 173 | void 174 | Pthread_cond_broadcast(pthread_cond_t *cptr) 175 | { 176 | int n; 177 | 178 | if ( (n = pthread_cond_broadcast(cptr)) == 0) 179 | return; 180 | errno = n; 181 | Error::sys("pthread_cond_broadcast error"); 182 | } 183 | 184 | void 185 | Pthread_cond_signal(pthread_cond_t *cptr) 186 | { 187 | int n; 188 | 189 | if ( (n = pthread_cond_signal(cptr)) == 0) 190 | return; 191 | errno = n; 192 | Error::sys("pthread_cond_signal error"); 193 | } 194 | 195 | void 196 | Pthread_cond_wait(pthread_cond_t *cptr, pthread_mutex_t *mptr) 197 | { 198 | int n; 199 | 200 | if ( (n = pthread_cond_wait(cptr, mptr)) == 0) 201 | return; 202 | errno = n; 203 | Error::sys("pthread_cond_wait error"); 204 | } 205 | 206 | void 207 | Pthread_cond_timedwait(pthread_cond_t *cptr, pthread_mutex_t *mptr, 208 | const struct timespec *tsptr) 209 | { 210 | int n; 211 | 212 | if ( (n = pthread_cond_timedwait(cptr, mptr, tsptr)) == 0) 213 | return; 214 | errno = n; 215 | Error::sys("pthread_cond_timedwait error"); 216 | } 217 | 218 | void 219 | Pthread_once(pthread_once_t *ptr, void (*func)(void)) 220 | { 221 | int n; 222 | 223 | if ( (n = pthread_once(ptr, func)) == 0) 224 | return; 225 | errno = n; 226 | Error::sys("pthread_once error"); 227 | } 228 | 229 | void 230 | Pthread_key_create(pthread_key_t *key, void (*func)(void *)) 231 | { 232 | int n; 233 | 234 | if ( (n = pthread_key_create(key, func)) == 0) 235 | return; 236 | errno = n; 237 | Error::sys("pthread_key_create error"); 238 | } 239 | 240 | void 241 | Pthread_setspecific(pthread_key_t key, const void *value) 242 | { 243 | int n; 244 | 245 | if ( (n = pthread_setspecific(key, value)) == 0) 246 | return; 247 | errno = n; 248 | Error::sys("pthread_setspecific error"); 249 | } 250 | 251 | 252 | 253 | int getFileNslice(const char *pathname, uint32_t *pnslice_o) 254 | { 255 | 256 | unsigned long filesize = 0, n = MAXNSLICE; 257 | 258 | struct stat statbuff; 259 | if(stat(pathname, &statbuff) < 0){ 260 | return -1; // error 261 | } else { 262 | if (statbuff.st_size == 0) 263 | { 264 | return 0; // file is empty. 265 | } else { 266 | filesize = statbuff.st_size; 267 | } 268 | } 269 | if (filesize % SLICECAP == 0) 270 | { 271 | *pnslice_o = filesize/SLICECAP; 272 | } else if ( (n = filesize/SLICECAP + 1) > MAXNSLICE ){ 273 | Error::msg("too large file size: %d\n (MAX: %d)", n, MAXNSLICE); 274 | return -2; 275 | } else { 276 | *pnslice_o = filesize/SLICECAP + 1; 277 | } 278 | //printf("getFileNslice nslice: %d\n", *pnslice_o); 279 | return 1; 280 | } 281 | 282 | string getFileSizeString(const char *pathname) 283 | { 284 | 285 | unsigned long filesize = 0; 286 | unsigned long n = 0; 287 | string hsize_o; 288 | char buf[MAXLINE]; 289 | unsigned long kbase = 1024; 290 | unsigned long mbase = 1024 * 1024; 291 | unsigned long gbase = 1024 * 1024 * 1024; 292 | 293 | 294 | struct stat statbuff; 295 | if(stat(pathname, &statbuff) < 0){ 296 | hsize_o = "error"; 297 | return hsize_o; // error 298 | } else { 299 | if (statbuff.st_size == 0) 300 | { 301 | hsize_o = "0B"; // file is empty. 302 | } else { 303 | filesize = statbuff.st_size; 304 | if (filesize / kbase == 0) 305 | { 306 | snprintf(buf, MAXLINE, "%lu", filesize); 307 | hsize_o += buf; 308 | hsize_o +="B"; 309 | } else if ( filesize / mbase == 0 ){ 310 | snprintf(buf, MAXLINE, "%lu", filesize / kbase); 311 | hsize_o += buf; 312 | n = (filesize % kbase)* 100 / kbase; 313 | if (n != 0) 314 | { 315 | hsize_o += "."; 316 | snprintf(buf, MAXLINE, "%02lu", n); 317 | hsize_o += buf; 318 | } 319 | hsize_o +="K"; 320 | } else if ( filesize / gbase == 0 ){ 321 | snprintf(buf, MAXLINE, "%2lu", filesize / mbase); 322 | hsize_o += buf; 323 | n = (filesize % mbase)* 100 / mbase; 324 | if (n != 0) 325 | { 326 | hsize_o += "."; 327 | snprintf(buf, MAXLINE, "%02lu", n); 328 | hsize_o += buf; 329 | } 330 | hsize_o +="M"; 331 | } else { 332 | snprintf(buf, MAXLINE, "%lu", filesize / gbase); 333 | hsize_o += buf; 334 | n = (filesize % gbase) * 100 / gbase ; 335 | //printf("filesize n: %lu\n", n); 336 | if (n != 0) 337 | { 338 | hsize_o += "."; 339 | snprintf(buf, MAXLINE, "%02lu", n); 340 | hsize_o += buf; 341 | } 342 | hsize_o +="G"; 343 | } 344 | } 345 | } 346 | return hsize_o; 347 | } 348 | 349 | string visualmd5sum(const char * pathname) 350 | { 351 | int n; 352 | char buf[SLICECAP]; 353 | unsigned char out[MD5_DIGEST_LENGTH]; 354 | string md5str; 355 | int oldProgress = 0, newProgress = 0; 356 | MD5_CTX ctx; 357 | 358 | uint32_t nslice = 0, sindex = 0; 359 | string tipstr; 360 | tipstr += "\033[32mMD5SUM\033[0m("; 361 | tipstr += pathname; 362 | tipstr += ")"; 363 | string hfilesize = getFileSizeString(pathname); 364 | if ( (n = getFileNslice(pathname, &nslice)) < 0) { 365 | Error::msg("getFileNslice error"); 366 | return md5str; 367 | } 368 | 369 | FILE *fp; 370 | if ( (fp = fopen(pathname, "rb")) == NULL) 371 | { 372 | Error::ret("md5sum#fopen"); 373 | return md5str; 374 | } 375 | 376 | MD5_Init(&ctx); 377 | while( (n = fread(buf, sizeof(char), SLICECAP, fp)) >0 ) 378 | { 379 | MD5_Update(&ctx, buf, n); 380 | if (nslice > (1024 * 512)) 381 | { 382 | newProgress = (++sindex*1.0)/nslice*100; 383 | if (newProgress > oldProgress) 384 | { 385 | //printf("\033[2K\r\033[0m"); 386 | fprintf(stderr, "\033[2K\r\033[0m%-40s%10s\t%3d%%", tipstr.c_str(), hfilesize.c_str(), newProgress); 387 | } 388 | oldProgress = newProgress; 389 | } 390 | } 391 | if (nslice > (1024 * 512)) 392 | printf("\n"); 393 | 394 | MD5_Final(out, &ctx); 395 | 396 | for(n = 0; n< MD5_DIGEST_LENGTH; n++) 397 | { 398 | snprintf(buf, SLICECAP, "%02x", out[n]); 399 | md5str += buf; 400 | } 401 | 402 | return md5str; 403 | } 404 | 405 | string md5sum(const char * pathname) 406 | { 407 | int n; 408 | char buf[SLICECAP]; 409 | unsigned char out[MD5_DIGEST_LENGTH]; 410 | string md5str; 411 | MD5_CTX ctx; 412 | 413 | 414 | FILE *fp; 415 | if ( (fp = fopen(pathname, "rb")) == NULL) 416 | { 417 | Error::ret("md5sum#fopen"); 418 | return md5str; 419 | } 420 | 421 | MD5_Init(&ctx); 422 | while( (n = fread(buf, sizeof(char), SLICECAP, fp)) >0 ) 423 | { 424 | MD5_Update(&ctx, buf, n); 425 | } 426 | printf("\n"); 427 | 428 | MD5_Final(out, &ctx); 429 | 430 | for(n = 0; n< MD5_DIGEST_LENGTH; n++) 431 | { 432 | snprintf(buf, SLICECAP, "%02x", out[n]); 433 | md5str += buf; 434 | } 435 | 436 | return md5str; 437 | } 438 | 439 | string visualmd5sumNslice(const char * pathname, uint32_t nslice) 440 | { 441 | int n; 442 | char buf[SLICECAP]; 443 | unsigned char out[MD5_DIGEST_LENGTH]; 444 | string md5str; 445 | int oldProgress = 0, newProgress = 0; 446 | MD5_CTX ctx; 447 | 448 | uint32_t fileslice =0, sindex = 0; 449 | if ( (n = getFileNslice(pathname, &fileslice)) < 0) { 450 | Error::msg("getFileNslice error"); 451 | return md5str; 452 | } 453 | int percent = (nslice*1.0)/fileslice*100; 454 | snprintf(buf, SLICECAP, "%u/%u %3d%%", nslice, fileslice, percent); 455 | string tipstr; 456 | tipstr += "\033[32mMD5SUM\033[0m("; 457 | tipstr += pathname; 458 | tipstr += " "; 459 | tipstr += buf; 460 | tipstr += ")"; 461 | string hfilesize = getFileSizeString(pathname); 462 | 463 | 464 | FILE *fp; 465 | if ( (fp = fopen(pathname, "rb")) == NULL) 466 | { 467 | Error::ret("md5sum#fopen"); 468 | return md5str; 469 | } 470 | 471 | MD5_Init(&ctx); 472 | while( (n = fread(buf, sizeof(char), SLICECAP, fp)) >0 ) 473 | { 474 | ++sindex; 475 | MD5_Update(&ctx, buf, n); 476 | 477 | if (nslice > (1024 * 512)) 478 | { 479 | newProgress = (sindex*1.0)/nslice*100; 480 | if (newProgress > oldProgress) 481 | { 482 | fprintf(stderr, "\033[2K\r\033[0m%-40s%10s\t%3d%%", tipstr.c_str(), hfilesize.c_str(), newProgress); 483 | } 484 | oldProgress = newProgress; 485 | } 486 | 487 | if ( sindex == nslice) 488 | { 489 | break; 490 | } 491 | } 492 | if (nslice > (1024 * 512)) 493 | printf("\n"); 494 | 495 | MD5_Final(out, &ctx); 496 | 497 | for(n = 0; n< MD5_DIGEST_LENGTH; n++) 498 | { 499 | snprintf(buf, SLICECAP, "%02x", out[n]); 500 | md5str += buf; 501 | } 502 | 503 | return md5str; 504 | } 505 | 506 | string md5sumNslice(const char * pathname, uint32_t nslice) 507 | { 508 | int n; 509 | char buf[SLICECAP]; 510 | unsigned char out[MD5_DIGEST_LENGTH]; 511 | string md5str; 512 | MD5_CTX ctx; 513 | uint32_t sindex = 0; 514 | 515 | FILE *fp; 516 | if ( (fp = fopen(pathname, "rb")) == NULL) 517 | { 518 | Error::ret("md5sum#fopen"); 519 | return md5str; 520 | } 521 | 522 | MD5_Init(&ctx); 523 | while( (n = fread(buf, sizeof(char), SLICECAP, fp)) >0 ) 524 | { 525 | MD5_Update(&ctx, buf, n); 526 | if ((++sindex) == nslice) 527 | { 528 | break; 529 | } 530 | } 531 | 532 | MD5_Final(out, &ctx); 533 | 534 | for(n = 0; n< MD5_DIGEST_LENGTH; n++) 535 | { 536 | snprintf(buf, SLICECAP, "%02x", out[n]); 537 | md5str += buf; 538 | } 539 | 540 | return md5str; 541 | } 542 | 543 | string md5sum(const char * str, int len) 544 | { 545 | int n; 546 | MD5_CTX ctx; 547 | char buf[SLICECAP]; 548 | unsigned char out[MD5_DIGEST_LENGTH]; 549 | string md5str; 550 | 551 | MD5_Init(&ctx); 552 | MD5_Update(&ctx, str, len); 553 | MD5_Final(out, &ctx); 554 | 555 | for(n = 0; n< MD5_DIGEST_LENGTH; n++) 556 | { 557 | snprintf(buf, SLICECAP, "%02x", out[n]); 558 | md5str += buf; 559 | } 560 | 561 | return md5str; 562 | } 563 | 564 | unsigned long long getFilesize(const char * pathname) 565 | { 566 | struct stat statbuff; 567 | if(stat(pathname, &statbuff) < 0) 568 | { 569 | Error::ret("getFilesize#stat"); 570 | return 0; 571 | } else 572 | { 573 | return (unsigned long long)statbuff.st_size; 574 | } 575 | } 576 | 577 | string getFilesize(string pathname) 578 | { 579 | struct stat statbuff; 580 | char buf[MAXLINE]; 581 | string sizestr; 582 | if(stat(pathname.c_str(), &statbuff) < 0) 583 | { 584 | Error::ret("getFilesize#stat"); 585 | return sizestr; 586 | } else 587 | { 588 | snprintf(buf, MAXLINE, "%llu", (unsigned long long)statbuff.st_size); 589 | sizestr = buf; 590 | return sizestr; 591 | } 592 | } 593 | 594 | string size2str(unsigned long filesize) 595 | { 596 | unsigned long n = 0; 597 | string hsize_o; 598 | char buf[MAXLINE]; 599 | unsigned long kbase = 1024; 600 | unsigned long mbase = 1024 * 1024; 601 | unsigned long gbase = 1024 * 1024 * 1024; 602 | 603 | 604 | if (filesize == 0) 605 | { 606 | hsize_o = "0B"; // file is empty. 607 | } 608 | else 609 | { 610 | if (filesize / kbase == 0) 611 | { 612 | snprintf(buf, MAXLINE, "%lu", filesize); 613 | hsize_o += buf; 614 | hsize_o +="B"; 615 | } else if ( filesize / mbase == 0 ){ 616 | snprintf(buf, MAXLINE, "%lu", filesize / kbase); 617 | hsize_o += buf; 618 | n = (filesize % kbase)* 100 / kbase; 619 | if (n != 0) 620 | { 621 | hsize_o += "."; 622 | snprintf(buf, MAXLINE, "%02lu", n); 623 | hsize_o += buf; 624 | } 625 | hsize_o +="K"; 626 | } else if ( filesize / gbase == 0 ){ 627 | snprintf(buf, MAXLINE, "%2lu", filesize / mbase); 628 | hsize_o += buf; 629 | n = (filesize % mbase)* 100 / mbase; 630 | if (n != 0) 631 | { 632 | hsize_o += "."; 633 | snprintf(buf, MAXLINE, "%02lu", n); 634 | hsize_o += buf; 635 | } 636 | hsize_o +="M"; 637 | } else { 638 | snprintf(buf, MAXLINE, "%lu", filesize / gbase); 639 | hsize_o += buf; 640 | n = (filesize % gbase) * 100 / gbase ; 641 | //printf("filesize n: %lu\n", n); 642 | if (n != 0) 643 | { 644 | hsize_o += "."; 645 | snprintf(buf, MAXLINE, "%02lu", n); 646 | hsize_o += buf; 647 | } 648 | hsize_o +="G"; 649 | } 650 | } 651 | return hsize_o; 652 | } 653 | 654 | // string getFileSizeString(const char *pathname) 655 | // { 656 | 657 | // unsigned long filesize = 0; 658 | // unsigned long n = 0; 659 | // string hsize_o; 660 | // char buf[MAXLINE]; 661 | // unsigned long kbase = 1024; 662 | // unsigned long mbase = 1024 * 1024; 663 | // unsigned long gbase = 1024 * 1024 * 1024; 664 | 665 | 666 | // struct stat statbuff; 667 | // if(stat(pathname, &statbuff) < 0){ 668 | // hsize_o = "error"; 669 | // return hsize_o; // error 670 | // } else { 671 | // if (statbuff.st_size == 0) 672 | // { 673 | // hsize_o = "0B"; // file is empty. 674 | // } else { 675 | // filesize = statbuff.st_size; 676 | // if (filesize / kbase == 0) 677 | // { 678 | // snprintf(buf, MAXLINE, "%lu", filesize); 679 | // hsize_o += buf; 680 | // hsize_o +="B"; 681 | // } else if ( filesize / mbase == 0 ){ 682 | // snprintf(buf, MAXLINE, "%lu", filesize / kbase); 683 | // hsize_o += buf; 684 | // n = (filesize % kbase)* 100 / kbase; 685 | // if (n != 0) 686 | // { 687 | // hsize_o += "."; 688 | // snprintf(buf, MAXLINE, "%02lu", n); 689 | // hsize_o += buf; 690 | // } 691 | // hsize_o +="K"; 692 | // } else if ( filesize / gbase == 0 ){ 693 | // snprintf(buf, MAXLINE, "%2lu", filesize / mbase); 694 | // hsize_o += buf; 695 | // n = (filesize % mbase)* 100 / mbase; 696 | // if (n != 0) 697 | // { 698 | // hsize_o += "."; 699 | // snprintf(buf, MAXLINE, "%02lu", n); 700 | // hsize_o += buf; 701 | // } 702 | // hsize_o +="M"; 703 | // } else { 704 | // snprintf(buf, MAXLINE, "%lu", filesize / gbase); 705 | // hsize_o += buf; 706 | // n = (filesize % gbase) * 100 / gbase ; 707 | // //printf("filesize n: %lu\n", n); 708 | // if (n != 0) 709 | // { 710 | // hsize_o += "."; 711 | // snprintf(buf, MAXLINE, "%02lu", n); 712 | // hsize_o += buf; 713 | // } 714 | // hsize_o +="G"; 715 | // } 716 | // } 717 | // } 718 | // return hsize_o; 719 | // } 720 | 721 | 722 | 723 | string encryptPassword(string password) 724 | { 725 | string saltedPass = PASSSALT0 + password + PASSSALT1; 726 | //cout << "***********saltedPass: " << saltedPass << endl; 727 | saltedPass = md5sum(saltedPass.c_str(), saltedPass.size()); 728 | //cout << "***********saltedPass: " << saltedPass << endl; 729 | return saltedPass; 730 | } 731 | 732 | string getCurrentTime() 733 | { 734 | char buf[MAXLINE]; 735 | time_t ticks; 736 | struct tm *p; 737 | time(&ticks); 738 | p=localtime(&ticks); 739 | snprintf(buf, MAXLINE, "%04d%02d%02d%02d%02d%02d", (1900 + p->tm_year), (1+p->tm_mon), p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec); 740 | return string(buf); 741 | } 742 | 743 | unsigned long long getDiskAvailable() 744 | { 745 | struct statfs diskInfo; 746 | 747 | statfs(ROOTDIR, &diskInfo); 748 | unsigned long long blocksize = diskInfo.f_bsize; 749 | unsigned long long availableDisk; 750 | 751 | /*unsigned long long totalsize = blocksize * diskInfo.f_blocks; // Total_size 752 | printf("Total_size = %llu B = %llu KB = %llu MB = %llu GB\n", 753 | totalsize, totalsize>>10, totalsize>>20, totalsize>>30); 754 | 755 | unsigned long long freeDisk = diskInfo.f_bfree * blocksize; // Disk_free 756 | availableDisk = diskInfo.f_bavail * blocksize; // Disk_available 757 | printf("Disk_free = %llu MB = %llu GB\nDisk_available = %llu MB = %llu GB\n", 758 | freeDisk>>20, freeDisk>>30, availableDisk>>20, availableDisk>>30);*/ 759 | 760 | 761 | availableDisk = diskInfo.f_bavail * blocksize; 762 | return availableDisk; 763 | } 764 | 765 | static struct termios oldt; 766 | 767 | void restore_terminal_settings(void) 768 | { 769 | //Apply saved settings 770 | tcsetattr(0, TCSANOW, &oldt); 771 | } 772 | 773 | //make terminal read 1 char at a time 774 | void disable_terminal_return(void) 775 | { 776 | struct termios newt; 777 | 778 | //save terminal settings 779 | tcgetattr(0, &oldt); 780 | //init new settings 781 | newt = oldt; 782 | //change settings 783 | newt.c_lflag &= ~(ICANON | ECHO); 784 | //apply settings 785 | tcsetattr(0, TCSANOW, &newt); 786 | 787 | //make sure settings will be restored when program ends 788 | atexit(restore_terminal_settings); 789 | } 790 | string getInode(const char * pathname) 791 | { 792 | string inode; 793 | 794 | struct stat statBuf; 795 | char buf[MAXLINE]; 796 | if (stat(pathname, &statBuf) < 0) 797 | { 798 | Error::ret("\033[31mstat\033[0m"); 799 | } else { 800 | snprintf(buf, MAXLINE, "%lu", statBuf.st_ino); 801 | inode = buf; 802 | } 803 | return inode; 804 | } 805 | 806 | 807 | 808 | 809 | -------------------------------------------------------------------------------- /common/common.h: -------------------------------------------------------------------------------- 1 | /* common header. Tabs are set for 4 spaces, not 8 */ 2 | 3 | #ifndef _TINYFTP_COMMON_H_ 4 | #define _TINYFTP_COMMON_H_ 5 | 6 | #define _LARGEFILE_SOURCE 7 | #define _LARGEFILE64_SOURCE 8 | #define _FILE_OFFSET_BITS 64 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include // sockaddr_in{} and other Internet definitions 16 | #include // inet(3) functions 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | 32 | // c++ header 33 | // #include 34 | // #include 35 | // #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | using namespace std; 44 | 45 | // using std::map; 46 | // using std::string; 47 | // using std::iostream; 48 | 49 | #define DEBUG 1 50 | 51 | #define DBFILENAME "tinyFTP.db" 52 | #define ROOTDIR "/home/tinyFTP/" 53 | #define ROOTDIR_LEN strlen(ROOTDIR) 54 | #define KERNELDIR "/home/tinyFTP/.tinyFTP/" 55 | #define GHOSTDIR "/home/tinyFTP/.tinyFTP/ghost/" 56 | 57 | #define PASSSALT0 "&5@f#fe)" // password salt 58 | #define PASSSALT1 "@tinyFTP" // password salt 59 | 60 | #define DELIMITER "\x1F" // UD(unit separator) 61 | 62 | // MACRO constants 63 | #define LISTENQ 1024 // 2nd argument(backlog) to listen() 64 | 65 | // Miscellaneous constants 66 | #define MAXLINE 256 // max text line length 67 | //#define BUFFSIZE 8192 // 8K Bytes buffer size for reads and writes 68 | 69 | //#define PORT 2121 // server: listening port 70 | #define CTRPORT 2121 // server: control listening port 71 | #define DATPORT 2020 // server: data pistening port 72 | 73 | // Following shortens all the typecasts of pointer arguments 74 | #define SA struct sockaddr 75 | 76 | class Database; 77 | typedef struct threadArg 78 | { 79 | int fd; 80 | uint32_t sesid; 81 | 82 | char buf[MAXLINE]; 83 | Database * pdb; 84 | 85 | } ThreadArg; 86 | 87 | typedef enum sockType 88 | { 89 | SRV_SOCKET, // server socket tyoe 90 | CLI_SOCKET // client socket type 91 | } SockType; 92 | 93 | /********************************************************* 94 | ******************* packet ****************************** 95 | *********************************************************/ 96 | typedef enum packetStoreType 97 | { 98 | HPACKET, // Host storage type 99 | NPACKET // Network storage type 100 | } PacketStoreType; 101 | 102 | // typedef enum packetType 103 | // { 104 | // SRV_PACKET, // server socket tyoe 105 | // CLI_PACKET // client socket type 106 | // } PacketType; 107 | 108 | /************************** CtrPacket **********************************/ 109 | 110 | #define PHEADSIZE 20 // packet header size 111 | #define PBODYCAP 512 // packet body capcacity 112 | #define SLICECAP 512 // slice capcacity 113 | #define SSLICECAP "512" // slice capcacity 114 | #define MAXNSLICE 4294967295 // max slice count: the maximum positive integer value 115 | // TCP control packet deinition, communication protocol 116 | #pragma pack(4) 117 | typedef struct packetStruct 118 | { 119 | /* packet header */ 120 | uint32_t sesid; // Session id 121 | uint16_t tagid; // different packet type: CMD, DATA, INFO 122 | 123 | uint16_t cmdid; // Command: ID 124 | uint16_t statid; // status code id 125 | uint16_t dataid; // data type id 126 | 127 | uint32_t nslice; // Data: whole number of file slices 128 | uint32_t sindex; // Data: slice index 129 | 130 | uint16_t bsize; // the real size of body 131 | /* packet body */ 132 | char body[PBODYCAP]; // packet body 133 | 134 | } PacketStruct; 135 | 136 | // // tagid: CMD 137 | // #pragma pack(4) 138 | // typedef struct cmdBodyStruct 139 | // { 140 | // uint16_t cmdid; // Command: ID 141 | 142 | // } CmdBodyStruct; 143 | 144 | // // tagid: INFO 145 | // #pragma pack(4) 146 | // typedef struct infoBodyStruct 147 | // { 148 | // uint16_t status; // status code 149 | 150 | // } InfoBodyStruct; 151 | 152 | // // tagid: Data 153 | // #pragma pack(4) 154 | // typedef struct dataBodyStruct 155 | // { 156 | // uint16_t nslice; // Data: whole number of file slices 157 | // uint16_t sindex; // Data: slice index 158 | // char slice[SLICECAP]; // packet body 159 | 160 | // } DataBodyStruct; 161 | 162 | #define PACKSIZE sizeof(PacketStruct) 163 | 164 | typedef enum tagID 165 | { 166 | TAG_CMD = 1, 167 | TAG_STAT, 168 | TAG_DATA 169 | } TagID; 170 | 171 | // different file transfer control commands 172 | typedef enum cmdID 173 | { 174 | USER = 1, 175 | PASS, 176 | USERADD, 177 | USERDEL, 178 | 179 | GET, 180 | PUT, 181 | LS, 182 | LLS, // local ls 183 | CD, 184 | LCD, 185 | RM, 186 | LRM, 187 | PWD, 188 | LPWD, 189 | MKDIR, 190 | LMKDIR, 191 | QUIT, 192 | HELP, 193 | 194 | MGET, 195 | MPUT, 196 | RGET, 197 | RPUT, 198 | RMDIR, 199 | 200 | SHELL, 201 | LSHELL, 202 | 203 | BINARY, 204 | ASCII 205 | } CmdID; 206 | 207 | typedef enum statID 208 | { 209 | STAT_OK = 1, 210 | STAT_BPR, // breakpoint resume 211 | STAT_CFM, // confirm 212 | STAT_MD5, // md5sum 213 | STAT_PGS, // progress 214 | STAT_FAIL, // fail 215 | STAT_ERR, // error 216 | STAT_CTN, // continue 217 | STAT_TERM, // terminate 218 | STAT_SIZE, // size 219 | STAT_WAIT, // wait 220 | //STAT_DONE, // transaction done 221 | STAT_EOF, // end of file 222 | STAT_EOT // end of transfer 223 | } StatID; 224 | 225 | typedef enum dataID 226 | { 227 | DATA_FILE = 1, 228 | DATA_TEXT, 229 | DATA_LIST, 230 | DATA_NAME, 231 | DATA_OTHER 232 | } DataID; 233 | 234 | /********************************************************* 235 | ******************* functions *************************** 236 | *********************************************************/ 237 | 238 | void Fclose(FILE *fp); 239 | void Fclose(FILE **fp); 240 | FILE * Fdopen(int fd, const char *type); 241 | char * Fgets(char *ptr, int n, FILE *stream); 242 | FILE * Fopen(const char *filename, const char *mode); 243 | void Fputs(const char *ptr, FILE *stream); 244 | void * Malloc(size_t size); 245 | 246 | 247 | 248 | void Pthread_create(pthread_t *, const pthread_attr_t *, 249 | void * (*)(void *), void *); 250 | void Pthread_join(pthread_t, void **); 251 | void Pthread_detach(pthread_t); 252 | void Pthread_kill(pthread_t, int); 253 | 254 | void Pthread_mutexattr_init(pthread_mutexattr_t *); 255 | void Pthread_mutexattr_setpshared(pthread_mutexattr_t *, int); 256 | void Pthread_mutex_init(pthread_mutex_t *, pthread_mutexattr_t *); 257 | void Pthread_mutex_lock(pthread_mutex_t *); 258 | void Pthread_mutex_unlock(pthread_mutex_t *); 259 | 260 | void Pthread_cond_broadcast(pthread_cond_t *); 261 | void Pthread_cond_signal(pthread_cond_t *); 262 | void Pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *); 263 | void Pthread_cond_timedwait(pthread_cond_t *, pthread_mutex_t *, 264 | const struct timespec *); 265 | 266 | void Pthread_key_create(pthread_key_t *, void (*)(void *)); 267 | void Pthread_setspecific(pthread_key_t, const void *); 268 | void Pthread_once(pthread_once_t *, void (*)(void)); 269 | 270 | string size2str(unsigned long filesize); 271 | int getFileNslice(const char *pathname, uint32_t *pnslice_o); 272 | string getFileSizeString(const char *pathname); 273 | string visualmd5sum(const char * pathname); 274 | string md5sum(const char * pathname); 275 | string visualmd5sumNslice(const char * pathname, uint32_t nslice); 276 | string md5sumNslice(const char * pathname, uint32_t nslice); 277 | string md5sum(const char * str, int len); 278 | unsigned long long getFilesize(const char * pathname); 279 | string getFilesize(string pathname); 280 | string encryptPassword(string password); 281 | string getCurrentTime(); 282 | unsigned long long getDiskAvailable(); 283 | 284 | void restore_terminal_settings(void); 285 | void disable_terminal_return(void); 286 | 287 | string getInode(const char * pathname); 288 | 289 | #endif /* __TINYFTP_COMMON_H__ */ 290 | -------------------------------------------------------------------------------- /common/database.cpp: -------------------------------------------------------------------------------- 1 | #include "database.h" 2 | 3 | // static int pre_callback(void *data, int argc, char **argv, char **azColName){ 4 | // fprintf(stdout, "%s: \n", (const char*)data); 5 | // for(int i=0; i > & resultMapVector = ((Database *)pDatabase)->getResult(); 16 | map kvMap; 17 | for(int i=0; i(azColName[i], argv[i]) ); 20 | } 21 | resultMapVector.push_back(kvMap); 22 | } 23 | return 0; 24 | 25 | } 26 | 27 | Database::Database(const char * zDbFilename): dbFilename(zDbFilename) 28 | { 29 | 30 | //create tinyFTP root working diretory 31 | 32 | DIR* d = opendir(ROOTDIR); 33 | if(d) 34 | { 35 | fprintf(stderr, "Already exists: %s\n", ROOTDIR); 36 | closedir(d); 37 | } else if(mkdir(ROOTDIR, 0777) == -1) 38 | { 39 | char buf[MAXLINE]; 40 | fprintf(stdout, "Error(%s): %s\n", ROOTDIR, strerror_r(errno, buf, MAXLINE)); 41 | } else { 42 | fprintf(stdout, "Directory created: %s\n", ROOTDIR); 43 | } 44 | 45 | // create tinyFTP/.tinyFTP/ working diretory 46 | d = opendir(KERNELDIR); 47 | if(d) 48 | { 49 | fprintf(stderr, "Already exists: %s\n", KERNELDIR); 50 | closedir(d); 51 | } else if(mkdir(KERNELDIR, 0777) == -1) 52 | { 53 | char buf[MAXLINE]; 54 | fprintf(stdout, "Error(%s): %s\n", KERNELDIR, strerror_r(errno, buf, MAXLINE)); 55 | } else { 56 | fprintf(stdout, "Directory created: %s\n", KERNELDIR); 57 | } 58 | 59 | // create tinyFTP/.tinyFTP/ghost/ working diretory 60 | d = opendir(GHOSTDIR); 61 | if(d) 62 | { 63 | fprintf(stderr, "Already exists: %s\n", GHOSTDIR); 64 | closedir(d); 65 | } else if(mkdir(GHOSTDIR, 0777) == -1) 66 | { 67 | char buf[MAXLINE]; 68 | fprintf(stdout, "Error(%s): %s\n", GHOSTDIR, strerror_r(errno, buf, MAXLINE)); 69 | } else { 70 | fprintf(stdout, "Directory created: %s\n", GHOSTDIR); 71 | } 72 | 73 | 74 | 75 | //clean(); 76 | zErrMsg = NULL; 77 | /* Open database */ 78 | string dirString = KERNELDIR; 79 | rc = sqlite3_open((dirString + dbFilename).c_str(), &pDb); 80 | if( rc ){ 81 | fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(pDb)); 82 | exit(0); 83 | }else{ 84 | fprintf(stdout, "Open database successfully: %s\n", (dirString + dbFilename).c_str()); 85 | } 86 | } 87 | 88 | void Database::traverseFiles(string dirpath) 89 | { 90 | DIR * dir= opendir(dirpath.c_str()); 91 | 92 | if(!dir) 93 | { 94 | Error::ret("opendir"); 95 | return; 96 | } 97 | 98 | if (dirpath.back() != '/') 99 | { 100 | dirpath += "/"; 101 | } 102 | struct dirent* e; 103 | while( (e = readdir(dir)) ) 104 | { 105 | if(e->d_type == 4 && strcmp(e->d_name, ".") && strcmp(e->d_name, "..")) 106 | { 107 | traverseFiles(dirpath + e->d_name); 108 | } 109 | else if(e->d_type == 8) 110 | { 111 | string filepath = dirpath + e->d_name; 112 | 113 | string inode = getInode(filepath.c_str()); 114 | 115 | cout << "\n\nmd5sum: " << filepath << " ..." << endl; 116 | string md5str = md5sum(filepath.c_str()); 117 | string sizestr = getFilesize(filepath); 118 | cout << "filepath: " << filepath << "md5str: " << md5str << "sizestr: " << sizestr << endl; 119 | 120 | string ghostfilename; 121 | ghostfilename += getCurrentTime(); 122 | ghostfilename += "_" + md5str + "_"; 123 | ghostfilename += e->d_name; 124 | string ghostPath = GHOSTDIR + ghostfilename; 125 | 126 | if (!md5str.empty() && !sizestr.empty()) 127 | { 128 | std::map selectParamMap = { {"MD5SUM", md5str} }; 129 | if (select("file", selectParamMap)) 130 | { 131 | vector< map > resultMapVector = getResult(); 132 | if (resultMapVector.empty()) 133 | { 134 | std::map insertParamMap = { {"MD5SUM", md5str}, 135 | {"MD5RAND", "NULL"}, 136 | {"ABSPATH", ghostPath}, 137 | {"FILENAME", ghostfilename}, 138 | {"INODE", inode}, 139 | {"SIZE", sizestr} }; 140 | if (insert("file", insertParamMap)) 141 | { 142 | Error::msg("Success: insert new file MD5SUM"); 143 | 144 | if (link(filepath.c_str(), ghostPath.c_str()) < 0) 145 | { 146 | Error::ret("\033[31mlink\033[0m"); 147 | cerr << filepath << ":" << ghostPath << endl; 148 | } 149 | 150 | } else { 151 | Error::msg("\033[31mDatabase insert error\033[0m"); 152 | } 153 | 154 | } else { 155 | Error::msg("\033[31mMD5SUM already exist\033[0m"); 156 | printResult(); 157 | } 158 | } else { 159 | Error::msg("\033[31mDatabase select error\033[0m"); 160 | } 161 | } 162 | } 163 | } 164 | closedir(dir); 165 | } 166 | 167 | // void Database::init1(const char * zDbFilename) 168 | // { 169 | // //clean(); 170 | // dbFilename = zDbFilename; 171 | // zErrMsg = NULL; 172 | // /* Open database */ 173 | // rc = sqlite3_open(dbFilename.c_str(), &pDb); 174 | // if( rc ){ 175 | // fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(pDb)); 176 | // exit(0); 177 | // }else{ 178 | // fprintf(stdout, "Open database successfully\n"); 179 | // } 180 | // } 181 | 182 | void Database::init() 183 | { 184 | std::map insertParamMap0 = { {"id", "1"}, 185 | {"username", "admin"}, 186 | {"password", encryptPassword("admin")} }; 187 | std::map insertParamMap1 = { {"id", "2"}, 188 | {"username", "anonymous"}, 189 | {"password", encryptPassword("anonymous")} }; 190 | std::map insertParamMap2 = { {"id", "3"}, 191 | {"username", "charles"}, 192 | {"password", encryptPassword("charles")} }; 193 | std::map insertParamMap3 = { {"id", "4"}, 194 | {"username", "davey"}, 195 | {"password", encryptPassword("davey")} }; 196 | 197 | std::map selectParamMap = { {"id", "1"}, {"username", "Paul"} }; 198 | std::map updateParamMap = { {"username", "davey"}, {"password", "dddd"} }; 199 | 200 | create(); 201 | insert("user", insertParamMap0); 202 | insert("user", insertParamMap1); 203 | insert("user", insertParamMap2); 204 | insert("user", insertParamMap3); 205 | //select("user", selectParamMap); 206 | 207 | // init user's root working directory 208 | if(findALL("user")) 209 | { 210 | vector< map > myresultMapVector; 211 | getResult(myresultMapVector); 212 | for (vector< map >::iterator iter=myresultMapVector.begin(); iter!=myresultMapVector.end(); ++iter) 213 | { 214 | string dirString(ROOTDIR); 215 | dirString += (*iter)["USERNAME"]; 216 | DIR* d = opendir(dirString.c_str()); 217 | if(d) 218 | { 219 | fprintf(stderr, "Already exists: %s\n", dirString.c_str()); 220 | closedir(d); 221 | }else if(mkdir(dirString.c_str(), 0777) == -1) 222 | { 223 | char buf[MAXLINE]; 224 | fprintf(stdout, "Error(%s): %s\n", dirString.c_str(), strerror_r(errno, buf, MAXLINE)); 225 | } else { 226 | fprintf(stdout, "Directory created: %s\n", dirString.c_str()); 227 | } 228 | 229 | //traverseFiles(dirString); 230 | } 231 | } 232 | 233 | 234 | 235 | //update("user", "2", updateParamMap); 236 | //find("user", "2"); 237 | } 238 | 239 | Database & Database::create() 240 | { 241 | std::cout << "Database::create" << std::endl; 242 | 243 | /* Create SQL statement */ 244 | const char *sql_table_user = "CREATE TABLE USER(" \ 245 | "ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," \ 246 | "USERNAME TEXT UNIQUE NOT NULL," \ 247 | "PASSWORD TEXT NOT NULL," \ 248 | "RCWD TEXT DEFAULT '/', " \ 249 | "CREATE_AT DATETIME DEFAULT (datetime('now', 'localtime'))," \ 250 | "UPDATE_AT DATETIME DEFAULT (datetime('now', 'localtime'))," \ 251 | "STATE INTEGER DEFAULT 0 );"; 252 | 253 | const char *sql_table_file = "CREATE TABLE FILE(" \ 254 | "ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," \ 255 | "MD5SUM TEXT UNIQUE NOT NULL," \ 256 | "MD5RAND TEXT NOT NULL," \ 257 | "ABSPATH TEXT NOT NULL," \ 258 | "FILENAME TEXT NOT NULL," \ 259 | "INODE INTEGER NOT NULL," \ 260 | "SIZE INTEGER NOT NULL," \ 261 | "CREATE_AT DATETIME DEFAULT (datetime('now', 'localtime'))," \ 262 | "UPDATE_AT DATETIME DEFAULT (datetime('now', 'localtime'))," \ 263 | "VALID INTEGER DEFAULT 1 ," \ 264 | "ACCESS INTEGER DEFAULT 0 );"; 265 | 266 | // interrupted file 267 | const char *sql_table_ifile = "CREATE TABLE IFILE(" \ 268 | "ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," \ 269 | "USERID TEXT NOT NULL," \ 270 | "ABSPATH TEXT NOT NULL," \ 271 | "FILENAME TEXT NOT NULL," \ 272 | "SIZE INTEGER NOT NULL," \ 273 | "MD5SUM TEXT NOT NULL," \ 274 | "NSLICE INTEGER NOT NULL," \ 275 | "SINDEX INTEGER NOT NULL," \ 276 | "SLICECAP INTEGER NOT NULL," \ 277 | "CREATE_AT DATETIME DEFAULT (datetime('now', 'localtime'))," \ 278 | "UPDATE_AT DATETIME DEFAULT (datetime('now', 'localtime'))," \ 279 | "VALID INTEGER DEFAULT 1 );"; 280 | 281 | /* Execute SQL statement */ 282 | execute(sql_table_user, NULL); 283 | execute(sql_table_file, NULL); 284 | execute(sql_table_ifile, NULL); 285 | 286 | return *this; 287 | } 288 | 289 | Database & Database::createTable() 290 | { 291 | /* Create SQL statement */ 292 | const char *sql_user = "CREATE TABLE USER(" \ 293 | "ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," \ 294 | "USERNAME TEXT UNIQUE NOT NULL," \ 295 | "PASSWORD TEXT NOT NULL," \ 296 | "CREATE_AT DATETIME DEFAULT (datetime('now', 'localtime'))," \ 297 | "UPDATE_AT DATETIME DEFAULT (datetime('now', 'localtime'))," \ 298 | "STATE INTEGER DEFAULT 0 );"; 299 | 300 | /* Execute SQL statement */ 301 | execute(sql_user, NULL); 302 | 303 | return *this; 304 | } 305 | 306 | bool Database::execute(const char *sql, Database * pDatabase) 307 | { 308 | /* Clear resultMap */ 309 | resultMapVector.clear(); 310 | /* Execute SQL statement */ 311 | rc = sqlite3_exec(pDb, sql, callback, pDatabase, &zErrMsg); 312 | if ( rc != SQLITE_OK ){ 313 | fprintf(stderr, "\033[31mDatabase execute error: %s\033[0m\n", zErrMsg); 314 | sqlite3_free(zErrMsg); 315 | return false; 316 | } else { 317 | fprintf(stdout, "\033[32mDatabase execute successfully\033[0m\n"); 318 | printResult(); 319 | return true; 320 | } 321 | } 322 | 323 | bool Database::insert(string tblname, map & kvMap) 324 | { 325 | /* Create SQL statement */ 326 | sqlSring.clear(); 327 | string valString; 328 | sqlSring += "INSERT INTO " + tblname + " ('"; 329 | valString += "VALUES ('"; 330 | 331 | map::iterator it=kvMap.begin(); 332 | 333 | sqlSring += it->first; 334 | valString += it->second; 335 | for (++it; it!=kvMap.end(); ++it) 336 | { 337 | sqlSring += "', '" + it->first; 338 | valString += "', '" + it->second; 339 | } 340 | sqlSring += "') "; 341 | valString += "') "; 342 | sqlSring += valString; 343 | 344 | std::cout << "insert: " << sqlSring << std::endl; 345 | /* Execute SQL statement and return*/ 346 | return execute(sqlSring.c_str(), this); 347 | } 348 | 349 | bool Database::select(string tblname, map & kvMap) 350 | { 351 | /* Construct SQL statement */ 352 | sqlSring.clear(); 353 | sqlSring += "SELECT * from "; 354 | sqlSring += tblname; 355 | sqlSring += " WHERE "; 356 | 357 | map::iterator it=kvMap.begin(); 358 | sqlSring += it->first + "='" + it->second + "'"; 359 | for (++it; it!=kvMap.end(); ++it) 360 | { 361 | sqlSring += " and " + it->first + "='" + it->second + "'"; 362 | } 363 | std::cout << "query: " << sqlSring << std::endl; 364 | /* Execute SQL statement */ 365 | return execute(sqlSring.c_str(), this); 366 | } 367 | 368 | 369 | bool Database::selectNewest(string tblname, map & kvMap) 370 | { 371 | /* Construct SQL statement */ 372 | sqlSring.clear(); 373 | sqlSring += "SELECT * from "; 374 | sqlSring += tblname; 375 | sqlSring += " WHERE "; 376 | 377 | map::iterator it=kvMap.begin(); 378 | sqlSring += it->first + "='" + it->second + "'"; 379 | for (++it; it!=kvMap.end(); ++it) 380 | { 381 | sqlSring += " and " + it->first + "='" + it->second + "'"; 382 | } 383 | sqlSring += " order by ID desc"; 384 | std::cout << "query: " << sqlSring << std::endl; 385 | /* Execute SQL statement */ 386 | return execute(sqlSring.c_str(), this); 387 | } 388 | 389 | 390 | 391 | bool Database::update(string tblname, string id, map & kvMap) 392 | { 393 | /* Construct SQL statement */ 394 | sqlSring.clear(); 395 | sqlSring += "UPDATE "; 396 | sqlSring += tblname; 397 | sqlSring += " SET "; 398 | 399 | map::iterator it=kvMap.begin(); 400 | sqlSring += it->first + "='" + it->second + "'"; 401 | for (++it; it!=kvMap.end(); ++it) 402 | { 403 | sqlSring += ", " + it->first + "='" + it->second + "'"; 404 | } 405 | sqlSring += " WHERE id='" + id + "'"; 406 | std::cout << "update: " << sqlSring << std::endl; 407 | /* Execute SQL statement */ 408 | return execute(sqlSring.c_str(), this); 409 | } 410 | 411 | bool Database::update(string tblname, map & whereMap, map & kvMap) 412 | { 413 | /* Construct SQL statement */ 414 | sqlSring.clear(); 415 | sqlSring += "UPDATE "; 416 | sqlSring += tblname; 417 | sqlSring += " SET "; 418 | 419 | map::iterator it=kvMap.begin(); 420 | sqlSring += it->first + "='" + it->second + "'"; 421 | for (++it; it!=kvMap.end(); ++it) 422 | { 423 | sqlSring += ", " + it->first + "='" + it->second + "'"; 424 | } 425 | sqlSring += " WHERE "; 426 | 427 | map::iterator iter=whereMap.begin(); 428 | sqlSring += iter->first + "='" + iter->second + "'"; 429 | for (++iter; iter!=whereMap.end(); ++iter) 430 | { 431 | sqlSring += " and " + iter->first + "='" + iter->second + "'"; 432 | } 433 | std::cout << "update: " << sqlSring << std::endl; 434 | /* Execute SQL statement */ 435 | return execute(sqlSring.c_str(), this); 436 | } 437 | 438 | bool Database::remove(string tblname, string id) 439 | { 440 | /* Create merged SQL statement */ 441 | sqlSring.clear(); 442 | sqlSring += "DELETE FROM "; //SET column1 = value1, column2 = value2...., columnN = valueN 443 | sqlSring += tblname; 444 | sqlSring += " WHERE id='" + id + "'"; 445 | 446 | /* Execute SQL statement */ 447 | return execute(sqlSring.c_str(), this); 448 | } 449 | 450 | bool Database::remove(string tblname, map & kvMap) 451 | { 452 | /* Create merged SQL statement */ 453 | sqlSring.clear(); 454 | sqlSring += "DELETE FROM "; //SET column1 = value1, column2 = value2...., columnN = valueN 455 | sqlSring += tblname; 456 | sqlSring += " WHERE "; 457 | 458 | map::iterator it=kvMap.begin(); 459 | sqlSring += it->first + "='" + it->second + "'"; 460 | for (++it; it!=kvMap.end(); ++it) 461 | { 462 | sqlSring += " and " + it->first + "='" + it->second + "'"; 463 | } 464 | std::cout << "remove: " << sqlSring << std::endl; 465 | /* Execute SQL statement */ 466 | return execute(sqlSring.c_str(), this); 467 | } 468 | 469 | bool Database::find(string tblname, string id) 470 | { 471 | sqlSring.clear(); 472 | sqlSring += "SELECT * from " + tblname + " WHERE id='"; 473 | sqlSring += id +"'"; 474 | std::cout << "find: " << sqlSring << std::endl; 475 | return execute(sqlSring.c_str(), this); 476 | } 477 | 478 | bool Database::findALL(string tblname) 479 | { 480 | sqlSring.clear(); 481 | sqlSring += "SELECT * from " + tblname; 482 | std::cout << "findALL: " << sqlSring << std::endl; 483 | return execute(sqlSring.c_str(), this); 484 | } 485 | 486 | void Database::getResult(vector< map > & resultMapVector_o) 487 | { 488 | resultMapVector_o.swap(this->resultMapVector); 489 | } 490 | 491 | vector< map > & Database::getResult() 492 | { 493 | 494 | return this->resultMapVector; 495 | 496 | } 497 | 498 | bool Database::first() 499 | { 500 | 501 | return false; 502 | } 503 | void Database::printResult() 504 | { 505 | for (vector< map >::iterator iter=resultMapVector.begin(); iter!=resultMapVector.end(); ++iter) 506 | { 507 | for (map::iterator it=iter->begin(); it!=iter->end(); ++it) 508 | std::cout << it->first << ": " << it->second << '\n'; 509 | std::cout << '\n'; 510 | } 511 | } 512 | void Database::clean() 513 | { 514 | if( unlink(dbFilename.c_str()) !=0 ) 515 | { 516 | char buf[MAXLINE]; 517 | fprintf(stderr, "DB clean error: %s\n", strerror_r(errno, buf, MAXLINE)); 518 | 519 | } else { 520 | fprintf(stderr, "DB cleaned\n"); 521 | } 522 | } 523 | 524 | void Database::dump() 525 | { 526 | 527 | } 528 | 529 | Database::~Database() 530 | { 531 | sqlite3_close(pDb); 532 | } 533 | 534 | // int main() 535 | // { 536 | // Database db(DBFILENAME); 537 | // db.init(); 538 | // return 0; 539 | // } -------------------------------------------------------------------------------- /common/database.h: -------------------------------------------------------------------------------- 1 | #ifndef _TINYFTP_DATABASE_H_ 2 | #define _TINYFTP_DATABASE_H_ 3 | 4 | #include "common.h" 5 | #include "error.h" 6 | #include 7 | 8 | // Database class 9 | class Database 10 | { 11 | public: 12 | // Database(){} 13 | Database(const char * zDbFilename); 14 | // void init1(const char * zDbFilename); 15 | 16 | Database & create(); 17 | Database & createTable(); 18 | void traverseFiles(string dirpath); 19 | bool execute(const char *sql, Database * pDatabase); 20 | bool insert(string tblname, map & paramMap); 21 | bool selectNewest(string tblname, map & kvMap); 22 | bool select(string tblname, map & paramMap); 23 | bool update(string tblname, string id, map & paramMap); 24 | bool update(string tblname, map & whereMap, map & kvMap); 25 | bool remove(string tblname, string id); 26 | bool remove(string tblname, map & kvMap); 27 | vector< map > & getResult(); 28 | void getResult(vector< map > & resultMapVector_o); 29 | //Database & select(string tblname, map & paramMap); 30 | bool first(); 31 | bool find(string tblname, string id); 32 | bool findALL(string tblname); 33 | void printResult(); 34 | void clean(); 35 | void dump(); 36 | 37 | void init(); 38 | 39 | ~Database(); 40 | 41 | private: 42 | std::string dbFilename; 43 | string sqlSring; 44 | sqlite3 *pDb; 45 | char *zErrMsg; 46 | int rc; 47 | vector< map > resultMapVector; 48 | }; 49 | 50 | #endif /* _TINYFTP_DATABASE_H_ */ 51 | -------------------------------------------------------------------------------- /common/error.cpp: -------------------------------------------------------------------------------- 1 | #include "error.h" 2 | 3 | /* Init the daemon_proc flag */ 4 | bool Error::daemon_proc = false; 5 | 6 | /* Nonfatal error related to system call 7 | * * Print message and return */ 8 | void Error::ret(const char *fmt, ...) 9 | { 10 | va_list ap; 11 | 12 | va_start(ap, fmt); 13 | doit(1, LOG_INFO, fmt, ap); 14 | va_end(ap); 15 | return; 16 | } 17 | 18 | /* Fatal error related to system call 19 | * Print message and terminate */ 20 | void Error::sys(const char *fmt, ...) 21 | { 22 | va_list ap; 23 | 24 | va_start(ap, fmt); 25 | doit(1, LOG_ERR, fmt, ap); 26 | va_end(ap); 27 | //exit(1); 28 | pthread_exit((void *)1); 29 | } 30 | 31 | /* Fatal error related to system call 32 | * Print message, dump core, and terminate */ 33 | void Error::dump(const char *fmt, ...) 34 | { 35 | va_list ap; 36 | 37 | va_start(ap, fmt); 38 | doit(1, LOG_ERR, fmt, ap); 39 | va_end(ap); 40 | abort(); /* dump core and terminate */ 41 | exit(1); /* shouldn't get here */ 42 | } 43 | 44 | /* Nonfatal error unrelated to system call 45 | * Print message and return */ 46 | void Error::msg(const char *fmt, ...) 47 | { 48 | va_list ap; 49 | 50 | va_start(ap, fmt); 51 | doit(0, LOG_INFO, fmt, ap); 52 | va_end(ap); 53 | return; 54 | } 55 | 56 | /* Fatal error unrelated to system call 57 | * Print message and terminate */ 58 | void Error::quit(const char *fmt, ...) 59 | { 60 | va_list ap; 61 | 62 | va_start(ap, fmt); 63 | doit(0, LOG_ERR, fmt, ap); 64 | va_end(ap); 65 | //exit(1); 66 | pthread_exit((void *)1); 67 | } 68 | 69 | /* Fatal error unrelated to system call 70 | * Print message and terminate */ 71 | void Error::quit_pthread(const char *fmt, ...) 72 | { 73 | va_list ap; 74 | 75 | va_start(ap, fmt); 76 | doit(0, LOG_ERR, fmt, ap); 77 | va_end(ap); 78 | pthread_exit((void *)1); 79 | } 80 | 81 | /* Print message and return to caller 82 | * Caller specifies "errnoflag" and "level" */ 83 | void Error::doit(int errnoflag, int level, const char *fmt, va_list ap) 84 | { 85 | int errno_save, n; 86 | char buf[MAXLINE + 1]; 87 | char errmsg[MAXLINE + 1]; 88 | 89 | errno_save = errno; /* value caller might want printed */ 90 | #ifdef HAVE_VSNPRINTF 91 | vsnprintf(buf, MAXLINE, fmt, ap); /* safe */ 92 | #else 93 | vsprintf(buf, fmt, ap); /* not safe */ 94 | #endif 95 | n = strlen(buf); 96 | if (errnoflag) 97 | { 98 | snprintf(buf + n, MAXLINE - n, ": %s", strerror_r(errno_save, errmsg, MAXLINE)); 99 | } 100 | strcat(buf, "\n"); 101 | 102 | if (Error::daemon_proc) { 103 | syslog(level, "%s", buf); 104 | return; 105 | } else { 106 | fflush(stdout); /* in case stdout and stderr are the same */ 107 | fputs(buf, stderr); 108 | fflush(stderr); 109 | } 110 | return; 111 | } -------------------------------------------------------------------------------- /common/error.h: -------------------------------------------------------------------------------- 1 | #ifndef _TINYFTP_ERROR_H_ 2 | #define _TINYFTP_ERROR_H_ 3 | 4 | #include "common.h" 5 | 6 | #include /* ANSI C header file */ 7 | #include /* for syslog() */ 8 | 9 | 10 | class Error 11 | { 12 | public: 13 | /* Nonfatal error related to system call 14 | * * Print message and return */ 15 | static void ret(const char *fmt, ...); 16 | 17 | /* Fatal error related to system call 18 | * * Print message and terminate */ 19 | static void sys(const char *fmt, ...); 20 | 21 | /* Fatal error related to system call 22 | * * Print message, dump core, and terminate */ 23 | static void dump(const char *fmt, ...); 24 | 25 | /* Nonfatal error unrelated to system call 26 | * * Print message and return */ 27 | static void msg(const char *fmt, ...); 28 | 29 | /* Fatal error unrelated to system call 30 | * * Print message and terminate */ 31 | static void quit(const char *fmt, ...); 32 | 33 | static void quit_pthread(const char *fmt, ...); 34 | 35 | private: 36 | static void doit(int, int, const char *, va_list); 37 | static bool daemon_proc; /* set true by daemon_init() */ 38 | }; 39 | 40 | #endif /* _TINYFTP_ERROR_H_ */ -------------------------------------------------------------------------------- /common/packet.cpp: -------------------------------------------------------------------------------- 1 | #include "packet.h" 2 | 3 | Packet::Packet(PI * ppi) 4 | { 5 | this->pstype = HPACKET; 6 | ps = (PacketStruct*) Malloc(PACKSIZE); 7 | prePs = (PacketStruct*) Malloc(PACKSIZE); 8 | ps->sesid = 0; 9 | this->ppi = ppi; 10 | } 11 | 12 | // Packet::Packet(PacketStoreType pstype) 13 | // { 14 | // init(pstype); 15 | // } 16 | // void Packet::init(PacketStoreType pstype) 17 | // { 18 | // this->pstype = pstype; 19 | // ps = (PacketStruct*) Malloc(PACKSIZE); 20 | // } 21 | void Packet::fill(uint16_t tagid, uint16_t cmdid, uint16_t statid, uint16_t dataid, uint32_t nslice, uint32_t sindex, uint16_t bsize, const char * body) 22 | { 23 | ps->tagid = tagid; 24 | 25 | ps->cmdid = cmdid; 26 | ps->statid = statid; 27 | ps->dataid = dataid; 28 | 29 | ps->nslice = nslice; 30 | ps->sindex = sindex; 31 | ps->bsize = bsize; 32 | 33 | if (bsize > PBODYCAP) 34 | { 35 | Error::msg("\033[31mPacket::fill error: bsize=%d, bsize > PBODYCAP\033[0m", bsize); 36 | return; 37 | } 38 | if(body != NULL && bsize != 0){ 39 | memcpy(ps->body, body, bsize); 40 | } 41 | } 42 | 43 | void Packet::fillCmd(uint16_t cmdid, uint16_t bsize, const char * body) 44 | { 45 | fill(TAG_CMD, cmdid, 0, 0, 0, 0, bsize, body); 46 | } 47 | 48 | void Packet::fillStat(uint16_t statid, uint16_t bsize, const char * body) 49 | { 50 | fill(TAG_STAT, 0, statid, 0, 0, 0, bsize, body); 51 | } 52 | 53 | void Packet::fillData(uint16_t dataid, uint32_t nslice, uint32_t sindex, uint16_t bsize, const char * body) 54 | { 55 | fill(TAG_DATA, 0, 0, dataid, nslice, sindex, bsize, body); 56 | } 57 | 58 | void Packet::setSessionID(uint32_t sesid) 59 | { 60 | ps->sesid = sesid; 61 | //printf("setSessionID: %u\n", ps->sesid); 62 | } 63 | 64 | void Packet::reset(PacketStoreType pstype) 65 | { 66 | //must keep sesid 67 | if (this->pstype == NPACKET){ 68 | if (pstype == HPACKET){ 69 | ps->sesid = ntohl(ps->sesid); 70 | } 71 | } else if (this->pstype == HPACKET){ 72 | this->savePacketState(); 73 | if (pstype == NPACKET){ 74 | ps->sesid = htonl(ps->sesid); 75 | } 76 | } 77 | this->pstype = pstype; 78 | 79 | ps->tagid = 0; 80 | 81 | ps->cmdid = 0; 82 | ps->statid = 0; 83 | ps->dataid = 0; 84 | 85 | ps->nslice = 0; 86 | ps->sindex = 0; 87 | ps->bsize = 0; 88 | 89 | memset(ps->body, 0, PBODYCAP); 90 | } 91 | void Packet::savePacketState() 92 | { 93 | prePs->sesid = ps->sesid; 94 | 95 | prePs->tagid = ps->tagid; 96 | 97 | prePs->cmdid = ps->cmdid; 98 | prePs->statid = ps->statid; 99 | prePs->dataid = ps->dataid; 100 | 101 | prePs->nslice = ps->nslice; 102 | prePs->sindex = ps->sindex; 103 | prePs->bsize = ps->bsize; 104 | } 105 | 106 | void Packet::zero() 107 | { 108 | memset(ps, 0, PACKSIZE); 109 | } 110 | 111 | void Packet::ntohp() 112 | { 113 | if (pstype == HPACKET){ 114 | Error::msg("already in HOST byte order\n"); 115 | return; 116 | } 117 | ps->sesid = ntohl(ps->sesid); 118 | ps->tagid = ntohs(ps->tagid); 119 | 120 | ps->cmdid = ntohs(ps->cmdid); 121 | ps->statid = ntohs(ps->statid); 122 | ps->dataid = ntohs(ps->dataid); 123 | 124 | ps->nslice = ntohl(ps->nslice); 125 | ps->sindex = ntohl(ps->sindex); 126 | ps->bsize = ntohs(ps->bsize); 127 | 128 | this->pstype = HPACKET; 129 | 130 | } 131 | 132 | 133 | void Packet::htonp() 134 | { 135 | if (pstype == NPACKET){ 136 | Error::msg("already in NETWORK byte order\n"); 137 | return; 138 | } 139 | 140 | ps->sesid = htonl(ps->sesid); 141 | ps->tagid = htons(ps->tagid); 142 | 143 | ps->cmdid = htons(ps->cmdid); 144 | ps->statid = htons(ps->statid); 145 | ps->dataid = htons(ps->dataid); 146 | 147 | ps->nslice = htonl(ps->nslice); 148 | ps->sindex = htonl(ps->sindex); 149 | ps->bsize = htons(ps->bsize); 150 | 151 | this->pstype = NPACKET; 152 | 153 | } 154 | 155 | void Packet::print() 156 | { 157 | if (!DEBUG) 158 | return; 159 | 160 | if (pstype == HPACKET) 161 | { 162 | printf("\t\t[HOST Packet: %p]\n", ps); 163 | 164 | } 165 | else if (pstype == NPACKET) 166 | { 167 | printf("\t\t[NETWORK Packet: %p]\n", ps); 168 | } 169 | else { 170 | Error::msg("unknown PacketStoreType\n"); 171 | return; 172 | } 173 | 174 | printf("\t\tsesid = %u\n", ps->sesid); 175 | printf("\t\ttagid = %d\n", ps->tagid); 176 | printf("\t\tcmdid = %d\n", ps->cmdid); 177 | printf("\t\tstatid = %d\n", ps->statid); 178 | printf("\t\tdataid = %d\n", ps->dataid); 179 | printf("\t\tnslice = %u\n", ps->nslice); 180 | printf("\t\tsindex = %u\n", ps->sindex); 181 | printf("\t\tbsize = %d\n", ps->bsize); 182 | if (pstype == HPACKET) 183 | { 184 | printf("\t\tbody = %s\n", this->getSBody().c_str()); 185 | } 186 | 187 | 188 | fflush(stdout); 189 | } 190 | 191 | 192 | void Packet::pprint() 193 | { 194 | printf("\t\t[Previous HOST Packet: %p]\n", prePs); 195 | printf("\t\tsesid = %u\n", prePs->sesid); 196 | printf("\t\ttagid = %d\n", prePs->tagid); 197 | printf("\t\tcmdid = %d\n", prePs->cmdid); 198 | printf("\t\tstatid = %d\n", prePs->statid); 199 | printf("\t\tdataid = %d\n", prePs->dataid); 200 | printf("\t\tnslice = %u\n", prePs->nslice); 201 | printf("\t\tsindex = %u\n", prePs->sindex); 202 | printf("\t\tbsize = %d\n", prePs->bsize); 203 | 204 | fflush(stdout); 205 | } 206 | 207 | void Packet::sendCMD(uint16_t cmdid, string sbody) 208 | { 209 | // send OK 210 | this->reset(HPACKET); 211 | this->fillCmd(cmdid, sbody.size(), sbody.c_str()); 212 | this->htonp(); 213 | ppi->sendOnePacket(this->ps, PACKSIZE); 214 | } 215 | 216 | void Packet::sendCMD_GET(const char *body) 217 | { 218 | // send OK 219 | this->reset(HPACKET); 220 | this->fillCmd(GET, strlen(body), body); 221 | this->htonp(); 222 | ppi->sendOnePacket(this->ps, PACKSIZE); 223 | } 224 | 225 | void Packet::sendCMD_GET(string sbody) 226 | { 227 | // send OK 228 | this->reset(HPACKET); 229 | this->fillCmd(GET, sbody.size(), sbody.c_str()); 230 | this->htonp(); 231 | ppi->sendOnePacket(this->ps, PACKSIZE); 232 | } 233 | 234 | void Packet::sendCMD_LMKDIR(const char *body) 235 | { 236 | // send OK 237 | this->reset(HPACKET); 238 | this->fillCmd(LMKDIR, strlen(body), body); 239 | this->htonp(); 240 | ppi->sendOnePacket(this->ps, PACKSIZE); 241 | } 242 | 243 | void Packet::sendCMD_LMKDIR(string sbody) 244 | { 245 | // send OK 246 | this->reset(HPACKET); 247 | this->fillCmd(LMKDIR, sbody.size(), sbody.c_str()); 248 | this->htonp(); 249 | ppi->sendOnePacket(this->ps, PACKSIZE); 250 | } 251 | 252 | // void Packet::sendDATA_FILE(uint16_t dataid, uint32_t nslice, uint32_t sindex, uint16_t bsize, char * body) 253 | // { 254 | // //this->print(); 255 | // this->reset(HPACKET); 256 | // this->fillData(DATA_FILE, nslice, sindex, bsize, body); 257 | // //printf("sendDATA:\n"); 258 | // //this->print(); 259 | // this->htonp(); 260 | // ppi->sendOnePacket(this->ps, PACKSIZE); 261 | // } 262 | 263 | void Packet::sendDATA_FILE(uint32_t nslice, uint32_t sindex, uint16_t bsize, const char *body) 264 | { 265 | this->reset(HPACKET); 266 | this->fillData(DATA_FILE, nslice, sindex, bsize, body); 267 | this->htonp(); 268 | ppi->sendOnePacket(this->ps, PACKSIZE); 269 | } 270 | 271 | // void Packet::sendDATA_NAME(uint32_t nslice, uint32_t sindex, uint16_t bsize, char *body) 272 | // { 273 | // //this->print(); 274 | // this->reset(HPACKET); 275 | // this->fillData(DATA_NAME, nslice, sindex, bsize, body); 276 | // //printf("sendDATA:\n"); 277 | // //this->print(); 278 | // this->htonp(); 279 | // ppi->sendOnePacket(this->ps, PACKSIZE); 280 | // } 281 | void Packet::sendDATA_LIST(uint32_t nslice, uint32_t sindex, uint16_t bsize, const char *body) 282 | { 283 | this->reset(HPACKET); 284 | this->fillData(DATA_LIST, nslice, sindex, bsize, body); 285 | this->htonp(); 286 | ppi->sendOnePacket(this->ps, PACKSIZE); 287 | } 288 | 289 | void Packet::sendDATA_LIST(uint32_t nslice, uint32_t sindex, uint16_t bsize, string body) 290 | { 291 | this->reset(HPACKET); 292 | this->fillData(DATA_LIST, nslice, sindex, body.size(), body.c_str()); 293 | this->htonp(); 294 | ppi->sendOnePacket(this->ps, PACKSIZE); 295 | } 296 | void Packet::sendDATA_NAME(uint32_t nslice, uint32_t sindex, uint16_t bsize, const char *body) 297 | { 298 | this->reset(HPACKET); 299 | this->fillData(DATA_NAME, nslice, sindex, bsize, body); 300 | this->htonp(); 301 | ppi->sendOnePacket(this->ps, PACKSIZE); 302 | } 303 | 304 | void Packet::sendDATA_NAME(uint32_t nslice, uint32_t sindex, uint16_t bsize, string body) 305 | { 306 | this->reset(HPACKET); 307 | this->fillData(DATA_NAME, nslice, sindex, body.size(), body.c_str()); 308 | this->htonp(); 309 | ppi->sendOnePacket(this->ps, PACKSIZE); 310 | } 311 | void Packet::sendDATA_TEXT(const char *body) 312 | { 313 | // send OK 314 | this->reset(HPACKET); 315 | this->fillData(DATA_TEXT, 0, 0, strlen(body), body); 316 | this->htonp(); 317 | ppi->sendOnePacket(this->ps, PACKSIZE); 318 | } 319 | 320 | void Packet::sendDATA_TEXT(uint16_t bsize, const char *body) 321 | { 322 | // send OK 323 | this->reset(HPACKET); 324 | this->fillData(DATA_TEXT, 0, 0, bsize, body); 325 | this->htonp(); 326 | ppi->sendOnePacket(this->ps, PACKSIZE); 327 | } 328 | 329 | void Packet::sendDATA_TEXT(string body) 330 | { 331 | // send OK 332 | this->reset(HPACKET); 333 | this->fillData(DATA_TEXT, 0, 0, body.size(), body.c_str()); 334 | this->htonp(); 335 | ppi->sendOnePacket(this->ps, PACKSIZE); 336 | } 337 | 338 | void Packet::sendSTAT(uint16_t statid ,string body) 339 | { 340 | this->reset(HPACKET); 341 | this->fillStat(statid, body.size(), body.c_str()); 342 | this->htonp(); 343 | ppi->sendOnePacket(this->ps, PACKSIZE); 344 | } 345 | 346 | void Packet::sendSTAT_OK() 347 | { 348 | // send OK 349 | this->reset(HPACKET); 350 | char buf[MAXLINE]; 351 | snprintf(buf, MAXLINE, "\033[32mOK to transfer\033[0m"); 352 | this->fillStat(STAT_OK, strlen(buf), buf); 353 | this->htonp(); 354 | ppi->sendOnePacket(this->ps, PACKSIZE); 355 | } 356 | void Packet::sendSTAT_OK(const char *msg) 357 | { 358 | // send OK 359 | this->reset(HPACKET); 360 | char buf[MAXLINE]; 361 | snprintf(buf, MAXLINE, "\033[32m%s\033[0m", msg); 362 | this->fillStat(STAT_OK, strlen(buf), buf); 363 | this->htonp(); 364 | ppi->sendOnePacket(this->ps, PACKSIZE); 365 | } 366 | 367 | void Packet::sendSTAT_OK(string msg) 368 | { 369 | // send OK 370 | this->reset(HPACKET); 371 | char buf[MAXLINE]; 372 | snprintf(buf, MAXLINE, "\033[32m%s\033[0m", msg.c_str()); 373 | this->fillStat(STAT_OK, strlen(buf), buf); 374 | this->htonp(); 375 | ppi->sendOnePacket(this->ps, PACKSIZE); 376 | } 377 | 378 | void Packet::sendSTAT_BPR(string body) 379 | { 380 | this->reset(HPACKET); 381 | this->fillStat(STAT_BPR, body.size(), body.c_str()); 382 | this->htonp(); 383 | ppi->sendOnePacket(this->ps, PACKSIZE); 384 | } 385 | 386 | 387 | void Packet::sendSTAT_MD5(string body) 388 | { 389 | this->reset(HPACKET); 390 | this->fillStat(STAT_MD5, body.size(), body.c_str()); 391 | this->htonp(); 392 | ppi->sendOnePacket(this->ps, PACKSIZE); 393 | } 394 | void Packet::sendSTAT_PGS(string body) 395 | { 396 | this->reset(HPACKET); 397 | this->fillStat(STAT_PGS, body.size(), body.c_str()); 398 | this->htonp(); 399 | ppi->sendOnePacketBlocked(this->ps, PACKSIZE); 400 | } 401 | 402 | 403 | void Packet::sendSTAT_FAIL(string body) 404 | { 405 | this->reset(HPACKET); 406 | char buf[MAXLINE]; 407 | snprintf(buf, MAXLINE, "\033[31m%s\033[0m", body.c_str()); 408 | this->fillStat(STAT_FAIL, strlen(buf), buf); 409 | this->htonp(); 410 | ppi->sendOnePacket(this->ps, PACKSIZE); 411 | } 412 | 413 | void Packet::sendSTAT_CFM(const char *msg) 414 | { 415 | // send CFM 416 | this->reset(HPACKET); 417 | char buf[MAXLINE]; 418 | snprintf(buf, MAXLINE, "%s", msg); 419 | this->fillStat(STAT_CFM, strlen(buf), buf); 420 | this->htonp(); 421 | ppi->sendOnePacket(this->ps, PACKSIZE); 422 | } 423 | 424 | void Packet::sendSTAT_CFM(string msg) 425 | { 426 | // send CFM 427 | this->reset(HPACKET); 428 | char buf[MAXLINE]; 429 | snprintf(buf, MAXLINE, "%s", msg.c_str()); 430 | this->fillStat(STAT_CFM, strlen(buf), buf); 431 | this->htonp(); 432 | ppi->sendOnePacket(this->ps, PACKSIZE); 433 | } 434 | 435 | void Packet::sendSTAT_ERR() 436 | { 437 | // send ERR 438 | this->reset(HPACKET); 439 | char buf[MAXLINE]; 440 | snprintf(buf, MAXLINE, "\033[31mError occurred\033[0m"); 441 | this->fillStat(STAT_ERR, strlen(buf), buf); 442 | this->htonp(); 443 | ppi->sendOnePacket(this->ps, PACKSIZE); 444 | } 445 | 446 | void Packet::sendSTAT_ERR(const char *msg) 447 | { 448 | // send ERR 449 | this->reset(HPACKET); 450 | char buf[MAXLINE]; 451 | snprintf(buf, MAXLINE, "\033[31m%s\033[0m", msg); 452 | this->fillStat(STAT_ERR, strlen(buf), buf); 453 | this->htonp(); 454 | ppi->sendOnePacket(this->ps, PACKSIZE); 455 | } 456 | void Packet::sendSTAT_ERR(string msg) 457 | { 458 | // send ERR 459 | this->reset(HPACKET); 460 | char buf[MAXLINE]; 461 | snprintf(buf, MAXLINE, "\033[31m%s\033[0m", msg.c_str()); 462 | this->fillStat(STAT_ERR, strlen(buf), buf); 463 | this->htonp(); 464 | ppi->sendOnePacket(this->ps, PACKSIZE); 465 | } 466 | 467 | void Packet::sendSTAT_EOF() 468 | { 469 | // send EOT 470 | this->reset(HPACKET); 471 | char buf[MAXLINE]; 472 | snprintf(buf, MAXLINE, "\033[32mEnd of File\033[0m"); 473 | this->fillStat(STAT_EOF, strlen(buf), buf); 474 | this->htonp(); 475 | ppi->sendOnePacket(this->ps, PACKSIZE); 476 | } 477 | 478 | void Packet::sendSTAT_EOF(string msg) 479 | { 480 | // send ERR 481 | this->reset(HPACKET); 482 | char buf[MAXLINE]; 483 | snprintf(buf, MAXLINE, "\033[31m%s\033[0m", msg.c_str()); 484 | this->fillStat(STAT_EOF, strlen(buf), buf); 485 | this->htonp(); 486 | ppi->sendOnePacket(this->ps, PACKSIZE); 487 | } 488 | 489 | void Packet::sendSTAT_EOT() 490 | { 491 | // send EOT 492 | this->reset(HPACKET); 493 | char buf[MAXLINE]; 494 | snprintf(buf, MAXLINE, "\033[32mEnd of Tansfer\033[0m"); 495 | this->fillStat(STAT_EOT, strlen(buf), buf); 496 | this->htonp(); 497 | ppi->sendOnePacket(this->ps, PACKSIZE); 498 | } 499 | 500 | void Packet::sendSTAT_EOT(string msg) 501 | { 502 | // send ERR 503 | this->reset(HPACKET); 504 | char buf[MAXLINE]; 505 | snprintf(buf, MAXLINE, "\033[32m%s\033[0m", msg.c_str()); 506 | this->fillStat(STAT_EOT, strlen(buf), buf); 507 | this->htonp(); 508 | ppi->sendOnePacket(this->ps, PACKSIZE); 509 | } 510 | 511 | PacketStruct * Packet::getPs() 512 | { 513 | return ps; 514 | } 515 | uint32_t Packet::getSesid() 516 | { 517 | return ps->sesid; 518 | } 519 | 520 | uint16_t Packet::getTagid() 521 | { 522 | return ps->tagid; 523 | } 524 | uint16_t Packet::getCmdid() 525 | { 526 | return ps->cmdid; 527 | } 528 | 529 | uint16_t Packet::getStatid() 530 | { 531 | return ps->statid; 532 | } 533 | 534 | uint16_t Packet::getDataid() 535 | { 536 | return ps->dataid; 537 | } 538 | 539 | uint32_t Packet::getNslice() 540 | { 541 | return ps->nslice; 542 | } 543 | 544 | uint32_t Packet::getSindex() 545 | { 546 | return ps->sindex; 547 | } 548 | 549 | uint16_t Packet::getBsize() 550 | { 551 | return ps->bsize; 552 | } 553 | char * Packet::getBody() 554 | { 555 | return ps->body; 556 | } 557 | std::string Packet::getSBody() 558 | { 559 | char buf[PBODYCAP + 1] = {0}; 560 | strncpy(buf, ps->body, ps->bsize); 561 | return string(buf); 562 | } 563 | 564 | 565 | 566 | 567 | PacketStruct * Packet::getPrePs() 568 | { 569 | return prePs; 570 | } 571 | uint32_t Packet::getPreSesid() 572 | { 573 | return prePs->sesid; 574 | } 575 | 576 | uint16_t Packet::getPreTagid() 577 | { 578 | return prePs->tagid; 579 | } 580 | uint16_t Packet::getPreCmdid() 581 | { 582 | return prePs->cmdid; 583 | } 584 | 585 | uint16_t Packet::getPreStatid() 586 | { 587 | return prePs->statid; 588 | } 589 | 590 | uint16_t Packet::getPreDataid() 591 | { 592 | return prePs->dataid; 593 | } 594 | 595 | uint32_t Packet::getPreNslice() 596 | { 597 | return prePs->nslice; 598 | } 599 | 600 | string Packet::getPreSNslice() 601 | { 602 | char buf[MAXLINE] = {0}; 603 | snprintf(buf, MAXLINE, "%u", prePs->nslice); 604 | return string(buf); 605 | } 606 | 607 | uint32_t Packet::getPreSindex() 608 | { 609 | return prePs->sindex; 610 | } 611 | 612 | string Packet::getPreSSindex() 613 | { 614 | char buf[MAXLINE] = {0}; 615 | snprintf(buf, MAXLINE, "%u", prePs->sindex); 616 | return string(buf); 617 | } 618 | 619 | uint16_t Packet::getPreBsize() 620 | { 621 | return prePs->bsize; 622 | } 623 | 624 | Packet::~Packet() 625 | { 626 | free(ps); 627 | free(prePs); 628 | } -------------------------------------------------------------------------------- /common/packet.h: -------------------------------------------------------------------------------- 1 | #ifndef _TINYFTP_PACKET_H_ 2 | #define _TINYFTP_PACKET_H_ 3 | 4 | #include "common.h" 5 | #include "error.h" 6 | #include "sockstream.h" 7 | #include "pi.h" 8 | 9 | class Packet 10 | { 11 | public: 12 | Packet(PI * ppi); 13 | //Packet(PacketStoreType pstype = HPACKET); 14 | 15 | ~Packet(); 16 | 17 | void fillCmd(uint16_t cmdid, uint16_t bsize, const char * body); 18 | void fillStat(uint16_t statid, uint16_t bsize, const char * body); 19 | void fillData(uint16_t dataid, uint32_t nslice, uint32_t sindex, uint16_t bsize,const char * body); 20 | 21 | void setSessionID(uint32_t sesid); 22 | 23 | void reset(PacketStoreType pstype); 24 | void savePacketState(); 25 | void zero(); 26 | 27 | // network byte order to host byte order 28 | void ntohp(); 29 | // host byte order to network byte order 30 | void htonp(); 31 | 32 | void print(); 33 | void pprint(); 34 | 35 | void sendCMD(uint16_t cmdid, string sbody); 36 | void sendCMD_GET(const char *body); 37 | void sendCMD_GET(string sbody); 38 | void sendCMD_LMKDIR(const char *body); 39 | void sendCMD_LMKDIR(string sbody); 40 | 41 | //void sendDATA_FILE(uint32_t nslice, uint32_t sindex, uint16_t bsize, char *body); 42 | void sendDATA_FILE(uint32_t nslice, uint32_t sindex, uint16_t bsize, const char *body); 43 | 44 | void sendDATA_LIST(uint32_t nslice, uint32_t sindex, uint16_t bsize, const char *body); 45 | void sendDATA_LIST(uint32_t nslice, uint32_t sindex, uint16_t bsize, string body); 46 | 47 | void sendDATA_NAME(uint32_t nslice, uint32_t sindex, uint16_t bsize, const char *body); 48 | void sendDATA_NAME(uint32_t nslice, uint32_t sindex, uint16_t bsize, string body); 49 | 50 | void sendDATA_TEXT(const char *msg); 51 | void sendDATA_TEXT(uint16_t bsize, const char *body); 52 | void sendDATA_TEXT(string msg); 53 | 54 | void sendSTAT(uint16_t statid, string body); 55 | 56 | void sendSTAT_OK(); 57 | void sendSTAT_OK(const char *msg); 58 | void sendSTAT_OK(string msg); 59 | 60 | void sendSTAT_BPR(string body); 61 | 62 | void sendSTAT_MD5(string body); 63 | 64 | void sendSTAT_PGS(string body); 65 | 66 | void sendSTAT_FAIL(string body); 67 | 68 | 69 | void sendSTAT_CFM(const char *msg); 70 | void sendSTAT_CFM(string msg); 71 | 72 | void sendSTAT_ERR(); 73 | void sendSTAT_ERR(const char *msg); 74 | void sendSTAT_ERR(string msg); 75 | 76 | void sendSTAT_EOF(); 77 | void sendSTAT_EOF(string msg); 78 | 79 | void sendSTAT_EOT(); 80 | void sendSTAT_EOT(string msg); 81 | 82 | PacketStruct * getPs(); 83 | uint32_t getSesid(); 84 | uint16_t getTagid(); 85 | uint16_t getCmdid(); 86 | uint16_t getStatid(); 87 | uint16_t getDataid(); 88 | uint32_t getNslice(); 89 | uint32_t getSindex(); 90 | uint16_t getBsize(); 91 | char * getBody(); 92 | std::string getSBody(); 93 | 94 | PacketStruct * getPrePs(); 95 | uint32_t getPreSesid(); 96 | uint16_t getPreTagid(); 97 | uint16_t getPreCmdid(); 98 | uint16_t getPreStatid(); 99 | uint16_t getPreDataid(); 100 | uint32_t getPreNslice(); 101 | string getPreSNslice(); 102 | uint32_t getPreSindex(); 103 | string getPreSSindex(); 104 | uint16_t getPreBsize(); 105 | 106 | 107 | 108 | private: 109 | PacketStruct *ps; 110 | 111 | PacketStruct *prePs; // previous PacketStruct 112 | PacketStoreType pstype; 113 | PI * ppi; 114 | 115 | //void init(PacketStoreType pstype = HPACKET); 116 | void fill(uint16_t tagid, uint16_t cmdid, uint16_t statid, uint16_t dataid, uint32_t nslice, uint32_t sindex, uint16_t bsize, const char * body); 117 | 118 | 119 | }; 120 | 121 | #endif /* _TINYFTP_PACKET_H_ */ -------------------------------------------------------------------------------- /common/pi.cpp: -------------------------------------------------------------------------------- 1 | #include "pi.h" -------------------------------------------------------------------------------- /common/pi.h: -------------------------------------------------------------------------------- 1 | #ifndef _TINYFTP_PI_H_ 2 | #define _TINYFTP_PI_H_ 3 | #include "common.h" 4 | 5 | class PI 6 | { 7 | public: 8 | virtual bool recvOnePacket() = 0; 9 | virtual bool sendOnePacket(PacketStruct * ps, size_t nbytes) = 0; 10 | virtual bool sendOnePacketBlocked(PacketStruct * ps, size_t nbytes) = 0; 11 | // virtual bool recvOnePacket(){ printf("virtual bool recvOnePacket()\n"); return true; } 12 | // virtual bool sendOnePacket(PacketStruct * ps, size_t nbytes){ printf("virtual bool sendOnePacket(Packet * ps, size_t nbytes)\n"); return true; } 13 | }; 14 | 15 | #endif /* _TINYFTP_PI_H_ */ -------------------------------------------------------------------------------- /common/socket.cpp: -------------------------------------------------------------------------------- 1 | #include "socket.h" 2 | 3 | int Socket::init() 4 | { 5 | struct sockaddr_in servaddr; 6 | int optval = 1; 7 | sockfd = tcpSocket(AF_INET, SOCK_STREAM, 0); 8 | servaddr.sin_family = AF_INET; 9 | servaddr.sin_port = htons(port); 10 | 11 | // Eliminates "Address already in use" error from bind 12 | if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 13 | (const void *)&optval, sizeof(int)) < 0) 14 | Error::sys("setsockopt"); 15 | 16 | if (socktype == SRV_SOCKET){ 17 | servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 18 | tcpBind(sockfd, (SA *) &servaddr, sizeof(servaddr)); 19 | tcpListen(sockfd, LISTENQ); 20 | } else if (socktype == CLI_SOCKET){ 21 | if (inet_pton(AF_INET, host, &servaddr.sin_addr) < 0) 22 | Error::quit("inet_pton error for %s", host); 23 | tcpConnect(sockfd, (SA *)&servaddr, sizeof(servaddr)); 24 | } else { 25 | Error::quit("Unkown SockType"); 26 | } 27 | /* For client, this sockfd is connfd, 28 | * for server, this sockfd is listenfd. */ 29 | return sockfd; 30 | } 31 | int Socket::tcpAccept(int fd, struct sockaddr *sa, socklen_t *salenptr) 32 | { 33 | int n; 34 | 35 | again: 36 | if ( (n = accept(fd, sa, salenptr)) < 0) { 37 | #ifdef EPROTO 38 | if (errno == EPROTO || errno == ECONNABORTED) 39 | #else 40 | if (errno == ECONNABORTED) 41 | #endif 42 | goto again; 43 | else 44 | Error::sys("accept error"); 45 | } 46 | return(n); 47 | } 48 | 49 | void Socket::tcpBind(int fd, const struct sockaddr *sa, socklen_t salen) 50 | { 51 | if (bind(fd, sa, salen) < 0) 52 | Error::sys("bind error"); 53 | } 54 | 55 | void Socket::tcpConnect(int fd, const struct sockaddr *sa, socklen_t salen) 56 | { 57 | if (connect(fd, sa, salen) < 0) 58 | Error::sys("connect error"); 59 | } 60 | 61 | void Socket::tcpListen(int fd, int backlog) 62 | { 63 | char *ptr; 64 | 65 | /*4can override 2nd argument with environment variable */ 66 | if ( (ptr = getenv("LISTENQ")) != NULL) 67 | backlog = atoi(ptr); 68 | 69 | if (listen(fd, backlog) < 0) 70 | Error::sys("listen error"); 71 | } 72 | 73 | ssize_t Socket::tcpRecv(int fd, void *ptr, size_t nbytes, int flags) 74 | { 75 | ssize_t n; 76 | 77 | if ( (n = recv(fd, ptr, nbytes, flags)) < 0) 78 | Error::sys("recv error"); 79 | return(n); 80 | } 81 | 82 | void Socket::tcpSend(int fd, const void *ptr, size_t nbytes, int flags) 83 | { 84 | if (send(fd, ptr, nbytes, flags) != (ssize_t)nbytes) 85 | Error::sys("send error"); 86 | } 87 | 88 | void Socket::tcpSetsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) 89 | { 90 | if (setsockopt(fd, level, optname, optval, optlen) < 0) 91 | Error::sys("setsockopt error"); 92 | } 93 | 94 | void Socket::tcpShutdown(int fd, int how) 95 | { 96 | if (shutdown(fd, how) < 0) 97 | Error::sys("shutdown error"); 98 | } 99 | 100 | int Socket::tcpSocket(int family, int type, int protocol) 101 | { 102 | int n; 103 | 104 | if ( (n = socket(family, type, protocol)) < 0) 105 | Error::sys("socket error"); 106 | return(n); 107 | } 108 | 109 | void Socket::tcpClose(int fd) 110 | { 111 | if (close(fd) == -1) 112 | Error::sys("close error"); 113 | } -------------------------------------------------------------------------------- /common/socket.h: -------------------------------------------------------------------------------- 1 | #ifndef _TINYFTP_SOCKET_H_ 2 | #define _TINYFTP_SOCKET_H_ 3 | 4 | #include "common.h" 5 | #include "error.h" 6 | 7 | class Socket 8 | { 9 | public: 10 | Socket( SockType socktype, /* CLI_SOCKET or SRV_SOCKET */ 11 | const char *host, /* NULL means INADDR_ANY for server */ 12 | short port) 13 | { 14 | this->socktype = socktype; 15 | this->host = host; 16 | this->port = port; 17 | }; 18 | int init(); 19 | static int tcpAccept(int fd, struct sockaddr *sa, socklen_t *salenptr); 20 | void tcpBind(int fd, const struct sockaddr *sa, socklen_t salen); 21 | void tcpConnect(int fd, const struct sockaddr *sa, socklen_t salen); 22 | void tcpListen(int fd, int backlog); 23 | ssize_t tcpRecv(int fd, void *ptr, size_t nbytes, int flags); 24 | void tcpSend(int fd, const void *ptr, size_t nbytes, int flags); 25 | void tcpSetsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen); 26 | void tcpShutdown(int fd, int how); 27 | int tcpSocket(int family, int type, int protocol); 28 | static void tcpClose(int fd); 29 | 30 | private: 31 | SockType socktype; // client or server socket indicator 32 | const char *host; // IP-Address or domain name 33 | short port; 34 | int sockfd; // listenfd for server, connfd for client 35 | 36 | }; 37 | 38 | #endif /* _TINYFTP_SOCKET_H_ */ 39 | -------------------------------------------------------------------------------- /common/sockstream.cpp: -------------------------------------------------------------------------------- 1 | #include "sockstream.h" 2 | 3 | ssize_t /* Read "n" bytes from a descriptor. */ 4 | SockStream::readn(void *vptr, size_t n) 5 | { 6 | size_t nleft; 7 | ssize_t nread; 8 | char *ptr; 9 | 10 | ptr = (char *)vptr; 11 | nleft = n; 12 | while (nleft > 0) { 13 | if ( (nread = read(fd, ptr, nleft)) < 0) { 14 | if (errno == EINTR) 15 | nread = 0; /* and call read() again */ 16 | else 17 | return(-1); 18 | } else if (nread == 0) 19 | break; /* EOF */ 20 | 21 | nleft -= nread; 22 | ptr += nread; 23 | } 24 | return(n - nleft); /* return >= 0 */ 25 | } 26 | /* end readn */ 27 | 28 | ssize_t 29 | SockStream::Readn(void *ptr, size_t nbytes) 30 | { 31 | ssize_t n; 32 | 33 | if ( (n = readn(ptr, nbytes)) < 0) 34 | Error::sys("readn error"); 35 | return(n); 36 | } 37 | 38 | 39 | ssize_t /* Write "n" bytes to a descriptor. */ 40 | SockStream::writen(const void *vptr, size_t n) 41 | { 42 | size_t nleft; 43 | ssize_t nwritten; 44 | const char *ptr; 45 | 46 | ptr = (const char*)vptr; 47 | nleft = n; 48 | while (nleft > 0) { 49 | if ( (nwritten = write(fd, ptr, nleft)) <= 0) { 50 | if (nwritten < 0 && errno == EINTR) 51 | nwritten = 0; /* and call write() again */ 52 | else 53 | return(-1); /* error */ 54 | } 55 | 56 | nleft -= nwritten; 57 | ptr += nwritten; 58 | } 59 | return(n); 60 | } 61 | /* end writen */ 62 | 63 | void 64 | SockStream::Writen(void *ptr, size_t nbytes) 65 | { 66 | ssize_t n; 67 | if ( (n = writen(ptr, nbytes)) < 0 || (size_t)n != nbytes) 68 | Error::sys("writen error"); 69 | } 70 | 71 | ssize_t SockStream::bufRead(char *ptr) 72 | { 73 | 74 | if (read_cnt <= 0) { 75 | again: 76 | if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) { 77 | if (errno == EINTR) 78 | goto again; 79 | return(-1); 80 | } else if (read_cnt == 0) 81 | return(0); 82 | read_ptr = read_buf; 83 | } 84 | 85 | read_cnt--; 86 | *ptr = *read_ptr++; 87 | return(1); 88 | } 89 | 90 | ssize_t SockStream::readline(void *vptr, size_t maxlen) 91 | { 92 | ssize_t rc; 93 | size_t n; 94 | char c, *ptr; 95 | 96 | ptr = (char *)vptr; 97 | for (n = 1; n < maxlen; n++) { 98 | if ( (rc = bufRead(&c)) == 1) { 99 | *ptr++ = c; 100 | if (c == '\n') 101 | break; /* newline is stored, like fgets() */ 102 | } else if (rc == 0) { 103 | *ptr = 0; 104 | return(n - 1); /* EOF, n - 1 bytes were read */ 105 | } else 106 | return(-1); /* error, errno set by read() */ 107 | } 108 | 109 | *ptr = 0; /* null terminate like fgets() */ 110 | return(n); 111 | } 112 | /* end readline */ 113 | 114 | ssize_t SockStream::readlineBuf(void **vptrptr) 115 | { 116 | if (read_cnt) 117 | *vptrptr = read_ptr; 118 | return(read_cnt); 119 | } 120 | 121 | 122 | ssize_t SockStream::Readline(void *ptr, size_t maxlen) 123 | { 124 | ssize_t n; 125 | 126 | if ( (n = readline(ptr, maxlen)) < 0) 127 | Error::sys("readline error"); 128 | return(n); 129 | } 130 | -------------------------------------------------------------------------------- /common/sockstream.h: -------------------------------------------------------------------------------- 1 | #ifndef _TINYFTP_SOCKSTREAM_H_ 2 | #define _TINYFTP_SOCKSTREAM_H_ 3 | 4 | #include "common.h" 5 | #include "error.h" 6 | 7 | 8 | class SockStream 9 | { 10 | public: 11 | SockStream(){}; 12 | SockStream(int fd){ this->fd = fd; }; 13 | 14 | void init(int fd){ this->fd = fd; }; 15 | 16 | /* Read "n" bytes from a fd. */ 17 | ssize_t readn(void *vptr, size_t n); 18 | 19 | /* Wrapper for readn */ 20 | ssize_t Readn(void *ptr, size_t nbytes); 21 | 22 | /* Wrapper for writen */ 23 | void Writen(void *ptr, size_t nbytes); 24 | 25 | /* Write "n" bytes to a descriptor. */ 26 | ssize_t writen(const void *vptr, size_t n); 27 | 28 | /* bytes remained in read buffer. */ 29 | ssize_t readlineBuf(void **vptrptr); 30 | /* Wrapper for readline. */ 31 | ssize_t Readline(void *ptr, size_t maxlen); 32 | 33 | private: 34 | 35 | 36 | 37 | 38 | /* Buffered read for readline. */ 39 | ssize_t bufRead(char *ptr); 40 | /* read one line to a descriptor. */ 41 | ssize_t readline(void *vptr, size_t maxlen); 42 | 43 | int fd; 44 | 45 | int read_cnt; 46 | char *read_ptr; 47 | char read_buf[MAXLINE]; 48 | 49 | }; 50 | 51 | #endif /* _TINYFTP_SOCKSTREAM_H_ */ -------------------------------------------------------------------------------- /include/sqlite3ext.h: -------------------------------------------------------------------------------- 1 | /* 2 | ** 2006 June 7 3 | ** 4 | ** The author disclaims copyright to this source code. In place of 5 | ** a legal notice, here is a blessing: 6 | ** 7 | ** May you do good and not evil. 8 | ** May you find forgiveness for yourself and forgive others. 9 | ** May you share freely, never taking more than you give. 10 | ** 11 | ************************************************************************* 12 | ** This header file defines the SQLite interface for use by 13 | ** shared libraries that want to be imported as extensions into 14 | ** an SQLite instance. Shared libraries that intend to be loaded 15 | ** as extensions by SQLite should #include this file instead of 16 | ** sqlite3.h. 17 | */ 18 | #ifndef _SQLITE3EXT_H_ 19 | #define _SQLITE3EXT_H_ 20 | #include "sqlite3.h" 21 | 22 | typedef struct sqlite3_api_routines sqlite3_api_routines; 23 | 24 | /* 25 | ** The following structure holds pointers to all of the SQLite API 26 | ** routines. 27 | ** 28 | ** WARNING: In order to maintain backwards compatibility, add new 29 | ** interfaces to the end of this structure only. If you insert new 30 | ** interfaces in the middle of this structure, then older different 31 | ** versions of SQLite will not be able to load each other's shared 32 | ** libraries! 33 | */ 34 | struct sqlite3_api_routines { 35 | void * (*aggregate_context)(sqlite3_context*,int nBytes); 36 | int (*aggregate_count)(sqlite3_context*); 37 | int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*)); 38 | int (*bind_double)(sqlite3_stmt*,int,double); 39 | int (*bind_int)(sqlite3_stmt*,int,int); 40 | int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64); 41 | int (*bind_null)(sqlite3_stmt*,int); 42 | int (*bind_parameter_count)(sqlite3_stmt*); 43 | int (*bind_parameter_index)(sqlite3_stmt*,const char*zName); 44 | const char * (*bind_parameter_name)(sqlite3_stmt*,int); 45 | int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*)); 46 | int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*)); 47 | int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*); 48 | int (*busy_handler)(sqlite3*,int(*)(void*,int),void*); 49 | int (*busy_timeout)(sqlite3*,int ms); 50 | int (*changes)(sqlite3*); 51 | int (*close)(sqlite3*); 52 | int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*, 53 | int eTextRep,const char*)); 54 | int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*, 55 | int eTextRep,const void*)); 56 | const void * (*column_blob)(sqlite3_stmt*,int iCol); 57 | int (*column_bytes)(sqlite3_stmt*,int iCol); 58 | int (*column_bytes16)(sqlite3_stmt*,int iCol); 59 | int (*column_count)(sqlite3_stmt*pStmt); 60 | const char * (*column_database_name)(sqlite3_stmt*,int); 61 | const void * (*column_database_name16)(sqlite3_stmt*,int); 62 | const char * (*column_decltype)(sqlite3_stmt*,int i); 63 | const void * (*column_decltype16)(sqlite3_stmt*,int); 64 | double (*column_double)(sqlite3_stmt*,int iCol); 65 | int (*column_int)(sqlite3_stmt*,int iCol); 66 | sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol); 67 | const char * (*column_name)(sqlite3_stmt*,int); 68 | const void * (*column_name16)(sqlite3_stmt*,int); 69 | const char * (*column_origin_name)(sqlite3_stmt*,int); 70 | const void * (*column_origin_name16)(sqlite3_stmt*,int); 71 | const char * (*column_table_name)(sqlite3_stmt*,int); 72 | const void * (*column_table_name16)(sqlite3_stmt*,int); 73 | const unsigned char * (*column_text)(sqlite3_stmt*,int iCol); 74 | const void * (*column_text16)(sqlite3_stmt*,int iCol); 75 | int (*column_type)(sqlite3_stmt*,int iCol); 76 | sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol); 77 | void * (*commit_hook)(sqlite3*,int(*)(void*),void*); 78 | int (*complete)(const char*sql); 79 | int (*complete16)(const void*sql); 80 | int (*create_collation)(sqlite3*,const char*,int,void*, 81 | int(*)(void*,int,const void*,int,const void*)); 82 | int (*create_collation16)(sqlite3*,const void*,int,void*, 83 | int(*)(void*,int,const void*,int,const void*)); 84 | int (*create_function)(sqlite3*,const char*,int,int,void*, 85 | void (*xFunc)(sqlite3_context*,int,sqlite3_value**), 86 | void (*xStep)(sqlite3_context*,int,sqlite3_value**), 87 | void (*xFinal)(sqlite3_context*)); 88 | int (*create_function16)(sqlite3*,const void*,int,int,void*, 89 | void (*xFunc)(sqlite3_context*,int,sqlite3_value**), 90 | void (*xStep)(sqlite3_context*,int,sqlite3_value**), 91 | void (*xFinal)(sqlite3_context*)); 92 | int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*); 93 | int (*data_count)(sqlite3_stmt*pStmt); 94 | sqlite3 * (*db_handle)(sqlite3_stmt*); 95 | int (*declare_vtab)(sqlite3*,const char*); 96 | int (*enable_shared_cache)(int); 97 | int (*errcode)(sqlite3*db); 98 | const char * (*errmsg)(sqlite3*); 99 | const void * (*errmsg16)(sqlite3*); 100 | int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**); 101 | int (*expired)(sqlite3_stmt*); 102 | int (*finalize)(sqlite3_stmt*pStmt); 103 | void (*free)(void*); 104 | void (*free_table)(char**result); 105 | int (*get_autocommit)(sqlite3*); 106 | void * (*get_auxdata)(sqlite3_context*,int); 107 | int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**); 108 | int (*global_recover)(void); 109 | void (*interruptx)(sqlite3*); 110 | sqlite_int64 (*last_insert_rowid)(sqlite3*); 111 | const char * (*libversion)(void); 112 | int (*libversion_number)(void); 113 | void *(*malloc)(int); 114 | char * (*mprintf)(const char*,...); 115 | int (*open)(const char*,sqlite3**); 116 | int (*open16)(const void*,sqlite3**); 117 | int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); 118 | int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); 119 | void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*); 120 | void (*progress_handler)(sqlite3*,int,int(*)(void*),void*); 121 | void *(*realloc)(void*,int); 122 | int (*reset)(sqlite3_stmt*pStmt); 123 | void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*)); 124 | void (*result_double)(sqlite3_context*,double); 125 | void (*result_error)(sqlite3_context*,const char*,int); 126 | void (*result_error16)(sqlite3_context*,const void*,int); 127 | void (*result_int)(sqlite3_context*,int); 128 | void (*result_int64)(sqlite3_context*,sqlite_int64); 129 | void (*result_null)(sqlite3_context*); 130 | void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*)); 131 | void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*)); 132 | void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*)); 133 | void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*)); 134 | void (*result_value)(sqlite3_context*,sqlite3_value*); 135 | void * (*rollback_hook)(sqlite3*,void(*)(void*),void*); 136 | int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*, 137 | const char*,const char*),void*); 138 | void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*)); 139 | char * (*snprintf)(int,char*,const char*,...); 140 | int (*step)(sqlite3_stmt*); 141 | int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*, 142 | char const**,char const**,int*,int*,int*); 143 | void (*thread_cleanup)(void); 144 | int (*total_changes)(sqlite3*); 145 | void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*); 146 | int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*); 147 | void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*, 148 | sqlite_int64),void*); 149 | void * (*user_data)(sqlite3_context*); 150 | const void * (*value_blob)(sqlite3_value*); 151 | int (*value_bytes)(sqlite3_value*); 152 | int (*value_bytes16)(sqlite3_value*); 153 | double (*value_double)(sqlite3_value*); 154 | int (*value_int)(sqlite3_value*); 155 | sqlite_int64 (*value_int64)(sqlite3_value*); 156 | int (*value_numeric_type)(sqlite3_value*); 157 | const unsigned char * (*value_text)(sqlite3_value*); 158 | const void * (*value_text16)(sqlite3_value*); 159 | const void * (*value_text16be)(sqlite3_value*); 160 | const void * (*value_text16le)(sqlite3_value*); 161 | int (*value_type)(sqlite3_value*); 162 | char *(*vmprintf)(const char*,va_list); 163 | /* Added ??? */ 164 | int (*overload_function)(sqlite3*, const char *zFuncName, int nArg); 165 | /* Added by 3.3.13 */ 166 | int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**); 167 | int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**); 168 | int (*clear_bindings)(sqlite3_stmt*); 169 | /* Added by 3.4.1 */ 170 | int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*, 171 | void (*xDestroy)(void *)); 172 | /* Added by 3.5.0 */ 173 | int (*bind_zeroblob)(sqlite3_stmt*,int,int); 174 | int (*blob_bytes)(sqlite3_blob*); 175 | int (*blob_close)(sqlite3_blob*); 176 | int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64, 177 | int,sqlite3_blob**); 178 | int (*blob_read)(sqlite3_blob*,void*,int,int); 179 | int (*blob_write)(sqlite3_blob*,const void*,int,int); 180 | int (*create_collation_v2)(sqlite3*,const char*,int,void*, 181 | int(*)(void*,int,const void*,int,const void*), 182 | void(*)(void*)); 183 | int (*file_control)(sqlite3*,const char*,int,void*); 184 | sqlite3_int64 (*memory_highwater)(int); 185 | sqlite3_int64 (*memory_used)(void); 186 | sqlite3_mutex *(*mutex_alloc)(int); 187 | void (*mutex_enter)(sqlite3_mutex*); 188 | void (*mutex_free)(sqlite3_mutex*); 189 | void (*mutex_leave)(sqlite3_mutex*); 190 | int (*mutex_try)(sqlite3_mutex*); 191 | int (*open_v2)(const char*,sqlite3**,int,const char*); 192 | int (*release_memory)(int); 193 | void (*result_error_nomem)(sqlite3_context*); 194 | void (*result_error_toobig)(sqlite3_context*); 195 | int (*sleep)(int); 196 | void (*soft_heap_limit)(int); 197 | sqlite3_vfs *(*vfs_find)(const char*); 198 | int (*vfs_register)(sqlite3_vfs*,int); 199 | int (*vfs_unregister)(sqlite3_vfs*); 200 | int (*xthreadsafe)(void); 201 | void (*result_zeroblob)(sqlite3_context*,int); 202 | void (*result_error_code)(sqlite3_context*,int); 203 | int (*test_control)(int, ...); 204 | void (*randomness)(int,void*); 205 | sqlite3 *(*context_db_handle)(sqlite3_context*); 206 | int (*extended_result_codes)(sqlite3*,int); 207 | int (*limit)(sqlite3*,int,int); 208 | sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*); 209 | const char *(*sql)(sqlite3_stmt*); 210 | int (*status)(int,int*,int*,int); 211 | int (*backup_finish)(sqlite3_backup*); 212 | sqlite3_backup *(*backup_init)(sqlite3*,const char*,sqlite3*,const char*); 213 | int (*backup_pagecount)(sqlite3_backup*); 214 | int (*backup_remaining)(sqlite3_backup*); 215 | int (*backup_step)(sqlite3_backup*,int); 216 | const char *(*compileoption_get)(int); 217 | int (*compileoption_used)(const char*); 218 | int (*create_function_v2)(sqlite3*,const char*,int,int,void*, 219 | void (*xFunc)(sqlite3_context*,int,sqlite3_value**), 220 | void (*xStep)(sqlite3_context*,int,sqlite3_value**), 221 | void (*xFinal)(sqlite3_context*), 222 | void(*xDestroy)(void*)); 223 | int (*db_config)(sqlite3*,int,...); 224 | sqlite3_mutex *(*db_mutex)(sqlite3*); 225 | int (*db_status)(sqlite3*,int,int*,int*,int); 226 | int (*extended_errcode)(sqlite3*); 227 | void (*log)(int,const char*,...); 228 | sqlite3_int64 (*soft_heap_limit64)(sqlite3_int64); 229 | const char *(*sourceid)(void); 230 | int (*stmt_status)(sqlite3_stmt*,int,int); 231 | int (*strnicmp)(const char*,const char*,int); 232 | int (*unlock_notify)(sqlite3*,void(*)(void**,int),void*); 233 | int (*wal_autocheckpoint)(sqlite3*,int); 234 | int (*wal_checkpoint)(sqlite3*,const char*); 235 | void *(*wal_hook)(sqlite3*,int(*)(void*,sqlite3*,const char*,int),void*); 236 | int (*blob_reopen)(sqlite3_blob*,sqlite3_int64); 237 | int (*vtab_config)(sqlite3*,int op,...); 238 | int (*vtab_on_conflict)(sqlite3*); 239 | /* Version 3.7.16 and later */ 240 | int (*close_v2)(sqlite3*); 241 | const char *(*db_filename)(sqlite3*,const char*); 242 | int (*db_readonly)(sqlite3*,const char*); 243 | int (*db_release_memory)(sqlite3*); 244 | const char *(*errstr)(int); 245 | int (*stmt_busy)(sqlite3_stmt*); 246 | int (*stmt_readonly)(sqlite3_stmt*); 247 | int (*stricmp)(const char*,const char*); 248 | int (*uri_boolean)(const char*,const char*,int); 249 | sqlite3_int64 (*uri_int64)(const char*,const char*,sqlite3_int64); 250 | const char *(*uri_parameter)(const char*,const char*); 251 | char *(*vsnprintf)(int,char*,const char*,va_list); 252 | int (*wal_checkpoint_v2)(sqlite3*,const char*,int,int*,int*); 253 | /* Version 3.8.7 and later */ 254 | int (*auto_extension)(void(*)(void)); 255 | int (*bind_blob64)(sqlite3_stmt*,int,const void*,sqlite3_uint64, 256 | void(*)(void*)); 257 | int (*bind_text64)(sqlite3_stmt*,int,const char*,sqlite3_uint64, 258 | void(*)(void*),unsigned char); 259 | int (*cancel_auto_extension)(void(*)(void)); 260 | int (*load_extension)(sqlite3*,const char*,const char*,char**); 261 | void *(*malloc64)(sqlite3_uint64); 262 | sqlite3_uint64 (*msize)(void*); 263 | void *(*realloc64)(void*,sqlite3_uint64); 264 | void (*reset_auto_extension)(void); 265 | void (*result_blob64)(sqlite3_context*,const void*,sqlite3_uint64, 266 | void(*)(void*)); 267 | void (*result_text64)(sqlite3_context*,const char*,sqlite3_uint64, 268 | void(*)(void*), unsigned char); 269 | int (*strglob)(const char*,const char*); 270 | /* Version 3.8.11 and later */ 271 | sqlite3_value *(*value_dup)(const sqlite3_value*); 272 | void (*value_free)(sqlite3_value*); 273 | int (*result_zeroblob64)(sqlite3_context*,sqlite3_uint64); 274 | int (*bind_zeroblob64)(sqlite3_stmt*, int, sqlite3_uint64); 275 | }; 276 | 277 | /* 278 | ** The following macros redefine the API routines so that they are 279 | ** redirected through the global sqlite3_api structure. 280 | ** 281 | ** This header file is also used by the loadext.c source file 282 | ** (part of the main SQLite library - not an extension) so that 283 | ** it can get access to the sqlite3_api_routines structure 284 | ** definition. But the main library does not want to redefine 285 | ** the API. So the redefinition macros are only valid if the 286 | ** SQLITE_CORE macros is undefined. 287 | */ 288 | #ifndef SQLITE_CORE 289 | #define sqlite3_aggregate_context sqlite3_api->aggregate_context 290 | #ifndef SQLITE_OMIT_DEPRECATED 291 | #define sqlite3_aggregate_count sqlite3_api->aggregate_count 292 | #endif 293 | #define sqlite3_bind_blob sqlite3_api->bind_blob 294 | #define sqlite3_bind_double sqlite3_api->bind_double 295 | #define sqlite3_bind_int sqlite3_api->bind_int 296 | #define sqlite3_bind_int64 sqlite3_api->bind_int64 297 | #define sqlite3_bind_null sqlite3_api->bind_null 298 | #define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count 299 | #define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index 300 | #define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name 301 | #define sqlite3_bind_text sqlite3_api->bind_text 302 | #define sqlite3_bind_text16 sqlite3_api->bind_text16 303 | #define sqlite3_bind_value sqlite3_api->bind_value 304 | #define sqlite3_busy_handler sqlite3_api->busy_handler 305 | #define sqlite3_busy_timeout sqlite3_api->busy_timeout 306 | #define sqlite3_changes sqlite3_api->changes 307 | #define sqlite3_close sqlite3_api->close 308 | #define sqlite3_collation_needed sqlite3_api->collation_needed 309 | #define sqlite3_collation_needed16 sqlite3_api->collation_needed16 310 | #define sqlite3_column_blob sqlite3_api->column_blob 311 | #define sqlite3_column_bytes sqlite3_api->column_bytes 312 | #define sqlite3_column_bytes16 sqlite3_api->column_bytes16 313 | #define sqlite3_column_count sqlite3_api->column_count 314 | #define sqlite3_column_database_name sqlite3_api->column_database_name 315 | #define sqlite3_column_database_name16 sqlite3_api->column_database_name16 316 | #define sqlite3_column_decltype sqlite3_api->column_decltype 317 | #define sqlite3_column_decltype16 sqlite3_api->column_decltype16 318 | #define sqlite3_column_double sqlite3_api->column_double 319 | #define sqlite3_column_int sqlite3_api->column_int 320 | #define sqlite3_column_int64 sqlite3_api->column_int64 321 | #define sqlite3_column_name sqlite3_api->column_name 322 | #define sqlite3_column_name16 sqlite3_api->column_name16 323 | #define sqlite3_column_origin_name sqlite3_api->column_origin_name 324 | #define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16 325 | #define sqlite3_column_table_name sqlite3_api->column_table_name 326 | #define sqlite3_column_table_name16 sqlite3_api->column_table_name16 327 | #define sqlite3_column_text sqlite3_api->column_text 328 | #define sqlite3_column_text16 sqlite3_api->column_text16 329 | #define sqlite3_column_type sqlite3_api->column_type 330 | #define sqlite3_column_value sqlite3_api->column_value 331 | #define sqlite3_commit_hook sqlite3_api->commit_hook 332 | #define sqlite3_complete sqlite3_api->complete 333 | #define sqlite3_complete16 sqlite3_api->complete16 334 | #define sqlite3_create_collation sqlite3_api->create_collation 335 | #define sqlite3_create_collation16 sqlite3_api->create_collation16 336 | #define sqlite3_create_function sqlite3_api->create_function 337 | #define sqlite3_create_function16 sqlite3_api->create_function16 338 | #define sqlite3_create_module sqlite3_api->create_module 339 | #define sqlite3_create_module_v2 sqlite3_api->create_module_v2 340 | #define sqlite3_data_count sqlite3_api->data_count 341 | #define sqlite3_db_handle sqlite3_api->db_handle 342 | #define sqlite3_declare_vtab sqlite3_api->declare_vtab 343 | #define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache 344 | #define sqlite3_errcode sqlite3_api->errcode 345 | #define sqlite3_errmsg sqlite3_api->errmsg 346 | #define sqlite3_errmsg16 sqlite3_api->errmsg16 347 | #define sqlite3_exec sqlite3_api->exec 348 | #ifndef SQLITE_OMIT_DEPRECATED 349 | #define sqlite3_expired sqlite3_api->expired 350 | #endif 351 | #define sqlite3_finalize sqlite3_api->finalize 352 | #define sqlite3_free sqlite3_api->free 353 | #define sqlite3_free_table sqlite3_api->free_table 354 | #define sqlite3_get_autocommit sqlite3_api->get_autocommit 355 | #define sqlite3_get_auxdata sqlite3_api->get_auxdata 356 | #define sqlite3_get_table sqlite3_api->get_table 357 | #ifndef SQLITE_OMIT_DEPRECATED 358 | #define sqlite3_global_recover sqlite3_api->global_recover 359 | #endif 360 | #define sqlite3_interrupt sqlite3_api->interruptx 361 | #define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid 362 | #define sqlite3_libversion sqlite3_api->libversion 363 | #define sqlite3_libversion_number sqlite3_api->libversion_number 364 | #define sqlite3_malloc sqlite3_api->malloc 365 | #define sqlite3_mprintf sqlite3_api->mprintf 366 | #define sqlite3_open sqlite3_api->open 367 | #define sqlite3_open16 sqlite3_api->open16 368 | #define sqlite3_prepare sqlite3_api->prepare 369 | #define sqlite3_prepare16 sqlite3_api->prepare16 370 | #define sqlite3_prepare_v2 sqlite3_api->prepare_v2 371 | #define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 372 | #define sqlite3_profile sqlite3_api->profile 373 | #define sqlite3_progress_handler sqlite3_api->progress_handler 374 | #define sqlite3_realloc sqlite3_api->realloc 375 | #define sqlite3_reset sqlite3_api->reset 376 | #define sqlite3_result_blob sqlite3_api->result_blob 377 | #define sqlite3_result_double sqlite3_api->result_double 378 | #define sqlite3_result_error sqlite3_api->result_error 379 | #define sqlite3_result_error16 sqlite3_api->result_error16 380 | #define sqlite3_result_int sqlite3_api->result_int 381 | #define sqlite3_result_int64 sqlite3_api->result_int64 382 | #define sqlite3_result_null sqlite3_api->result_null 383 | #define sqlite3_result_text sqlite3_api->result_text 384 | #define sqlite3_result_text16 sqlite3_api->result_text16 385 | #define sqlite3_result_text16be sqlite3_api->result_text16be 386 | #define sqlite3_result_text16le sqlite3_api->result_text16le 387 | #define sqlite3_result_value sqlite3_api->result_value 388 | #define sqlite3_rollback_hook sqlite3_api->rollback_hook 389 | #define sqlite3_set_authorizer sqlite3_api->set_authorizer 390 | #define sqlite3_set_auxdata sqlite3_api->set_auxdata 391 | #define sqlite3_snprintf sqlite3_api->snprintf 392 | #define sqlite3_step sqlite3_api->step 393 | #define sqlite3_table_column_metadata sqlite3_api->table_column_metadata 394 | #define sqlite3_thread_cleanup sqlite3_api->thread_cleanup 395 | #define sqlite3_total_changes sqlite3_api->total_changes 396 | #define sqlite3_trace sqlite3_api->trace 397 | #ifndef SQLITE_OMIT_DEPRECATED 398 | #define sqlite3_transfer_bindings sqlite3_api->transfer_bindings 399 | #endif 400 | #define sqlite3_update_hook sqlite3_api->update_hook 401 | #define sqlite3_user_data sqlite3_api->user_data 402 | #define sqlite3_value_blob sqlite3_api->value_blob 403 | #define sqlite3_value_bytes sqlite3_api->value_bytes 404 | #define sqlite3_value_bytes16 sqlite3_api->value_bytes16 405 | #define sqlite3_value_double sqlite3_api->value_double 406 | #define sqlite3_value_int sqlite3_api->value_int 407 | #define sqlite3_value_int64 sqlite3_api->value_int64 408 | #define sqlite3_value_numeric_type sqlite3_api->value_numeric_type 409 | #define sqlite3_value_text sqlite3_api->value_text 410 | #define sqlite3_value_text16 sqlite3_api->value_text16 411 | #define sqlite3_value_text16be sqlite3_api->value_text16be 412 | #define sqlite3_value_text16le sqlite3_api->value_text16le 413 | #define sqlite3_value_type sqlite3_api->value_type 414 | #define sqlite3_vmprintf sqlite3_api->vmprintf 415 | #define sqlite3_overload_function sqlite3_api->overload_function 416 | #define sqlite3_prepare_v2 sqlite3_api->prepare_v2 417 | #define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2 418 | #define sqlite3_clear_bindings sqlite3_api->clear_bindings 419 | #define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob 420 | #define sqlite3_blob_bytes sqlite3_api->blob_bytes 421 | #define sqlite3_blob_close sqlite3_api->blob_close 422 | #define sqlite3_blob_open sqlite3_api->blob_open 423 | #define sqlite3_blob_read sqlite3_api->blob_read 424 | #define sqlite3_blob_write sqlite3_api->blob_write 425 | #define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2 426 | #define sqlite3_file_control sqlite3_api->file_control 427 | #define sqlite3_memory_highwater sqlite3_api->memory_highwater 428 | #define sqlite3_memory_used sqlite3_api->memory_used 429 | #define sqlite3_mutex_alloc sqlite3_api->mutex_alloc 430 | #define sqlite3_mutex_enter sqlite3_api->mutex_enter 431 | #define sqlite3_mutex_free sqlite3_api->mutex_free 432 | #define sqlite3_mutex_leave sqlite3_api->mutex_leave 433 | #define sqlite3_mutex_try sqlite3_api->mutex_try 434 | #define sqlite3_open_v2 sqlite3_api->open_v2 435 | #define sqlite3_release_memory sqlite3_api->release_memory 436 | #define sqlite3_result_error_nomem sqlite3_api->result_error_nomem 437 | #define sqlite3_result_error_toobig sqlite3_api->result_error_toobig 438 | #define sqlite3_sleep sqlite3_api->sleep 439 | #define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit 440 | #define sqlite3_vfs_find sqlite3_api->vfs_find 441 | #define sqlite3_vfs_register sqlite3_api->vfs_register 442 | #define sqlite3_vfs_unregister sqlite3_api->vfs_unregister 443 | #define sqlite3_threadsafe sqlite3_api->xthreadsafe 444 | #define sqlite3_result_zeroblob sqlite3_api->result_zeroblob 445 | #define sqlite3_result_error_code sqlite3_api->result_error_code 446 | #define sqlite3_test_control sqlite3_api->test_control 447 | #define sqlite3_randomness sqlite3_api->randomness 448 | #define sqlite3_context_db_handle sqlite3_api->context_db_handle 449 | #define sqlite3_extended_result_codes sqlite3_api->extended_result_codes 450 | #define sqlite3_limit sqlite3_api->limit 451 | #define sqlite3_next_stmt sqlite3_api->next_stmt 452 | #define sqlite3_sql sqlite3_api->sql 453 | #define sqlite3_status sqlite3_api->status 454 | #define sqlite3_backup_finish sqlite3_api->backup_finish 455 | #define sqlite3_backup_init sqlite3_api->backup_init 456 | #define sqlite3_backup_pagecount sqlite3_api->backup_pagecount 457 | #define sqlite3_backup_remaining sqlite3_api->backup_remaining 458 | #define sqlite3_backup_step sqlite3_api->backup_step 459 | #define sqlite3_compileoption_get sqlite3_api->compileoption_get 460 | #define sqlite3_compileoption_used sqlite3_api->compileoption_used 461 | #define sqlite3_create_function_v2 sqlite3_api->create_function_v2 462 | #define sqlite3_db_config sqlite3_api->db_config 463 | #define sqlite3_db_mutex sqlite3_api->db_mutex 464 | #define sqlite3_db_status sqlite3_api->db_status 465 | #define sqlite3_extended_errcode sqlite3_api->extended_errcode 466 | #define sqlite3_log sqlite3_api->log 467 | #define sqlite3_soft_heap_limit64 sqlite3_api->soft_heap_limit64 468 | #define sqlite3_sourceid sqlite3_api->sourceid 469 | #define sqlite3_stmt_status sqlite3_api->stmt_status 470 | #define sqlite3_strnicmp sqlite3_api->strnicmp 471 | #define sqlite3_unlock_notify sqlite3_api->unlock_notify 472 | #define sqlite3_wal_autocheckpoint sqlite3_api->wal_autocheckpoint 473 | #define sqlite3_wal_checkpoint sqlite3_api->wal_checkpoint 474 | #define sqlite3_wal_hook sqlite3_api->wal_hook 475 | #define sqlite3_blob_reopen sqlite3_api->blob_reopen 476 | #define sqlite3_vtab_config sqlite3_api->vtab_config 477 | #define sqlite3_vtab_on_conflict sqlite3_api->vtab_on_conflict 478 | /* Version 3.7.16 and later */ 479 | #define sqlite3_close_v2 sqlite3_api->close_v2 480 | #define sqlite3_db_filename sqlite3_api->db_filename 481 | #define sqlite3_db_readonly sqlite3_api->db_readonly 482 | #define sqlite3_db_release_memory sqlite3_api->db_release_memory 483 | #define sqlite3_errstr sqlite3_api->errstr 484 | #define sqlite3_stmt_busy sqlite3_api->stmt_busy 485 | #define sqlite3_stmt_readonly sqlite3_api->stmt_readonly 486 | #define sqlite3_stricmp sqlite3_api->stricmp 487 | #define sqlite3_uri_boolean sqlite3_api->uri_boolean 488 | #define sqlite3_uri_int64 sqlite3_api->uri_int64 489 | #define sqlite3_uri_parameter sqlite3_api->uri_parameter 490 | #define sqlite3_uri_vsnprintf sqlite3_api->vsnprintf 491 | #define sqlite3_wal_checkpoint_v2 sqlite3_api->wal_checkpoint_v2 492 | /* Version 3.8.7 and later */ 493 | #define sqlite3_auto_extension sqlite3_api->auto_extension 494 | #define sqlite3_bind_blob64 sqlite3_api->bind_blob64 495 | #define sqlite3_bind_text64 sqlite3_api->bind_text64 496 | #define sqlite3_cancel_auto_extension sqlite3_api->cancel_auto_extension 497 | #define sqlite3_load_extension sqlite3_api->load_extension 498 | #define sqlite3_malloc64 sqlite3_api->malloc64 499 | #define sqlite3_msize sqlite3_api->msize 500 | #define sqlite3_realloc64 sqlite3_api->realloc64 501 | #define sqlite3_reset_auto_extension sqlite3_api->reset_auto_extension 502 | #define sqlite3_result_blob64 sqlite3_api->result_blob64 503 | #define sqlite3_result_text64 sqlite3_api->result_text64 504 | #define sqlite3_strglob sqlite3_api->strglob 505 | /* Version 3.8.11 and later */ 506 | #define sqlite3_value_dup sqlite3_api->value_dup 507 | #define sqlite3_value_free sqlite3_api->value_free 508 | #define sqlite3_result_zeroblob64 sqlite3_api->result_zeroblob64 509 | #define sqlite3_bind_zeroblob64 sqlite3_api->bind_zeroblob64 510 | #endif /* SQLITE_CORE */ 511 | 512 | #ifndef SQLITE_CORE 513 | /* This case when the file really is being compiled as a loadable 514 | ** extension */ 515 | # define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0; 516 | # define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v; 517 | # define SQLITE_EXTENSION_INIT3 \ 518 | extern const sqlite3_api_routines *sqlite3_api; 519 | #else 520 | /* This case when the file is being statically linked into the 521 | ** application */ 522 | # define SQLITE_EXTENSION_INIT1 /*no-op*/ 523 | # define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */ 524 | # define SQLITE_EXTENSION_INIT3 /*no-op*/ 525 | #endif 526 | 527 | #endif /* _SQLITE3EXT_H_ */ 528 | -------------------------------------------------------------------------------- /lib/libsqlite3.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wenchy/tinyFTP/95683072e3df7334dff68cc7bf82fb718e1cb3e1/lib/libsqlite3.so -------------------------------------------------------------------------------- /server/server.cpp: -------------------------------------------------------------------------------- 1 | #include "server.h" 2 | #include "../common/database.h" 3 | void * clientConnect(void * arg) 4 | { 5 | ThreadArg * pthreadArg = (ThreadArg *)arg; 6 | SrvPI srvPI(DBFILENAME, pthreadArg->fd); 7 | 8 | while (1) 9 | { 10 | srvPI.run(); 11 | } 12 | 13 | delete pthreadArg; 14 | return(NULL); 15 | } 16 | 17 | 18 | int main(int argc, char **argv) 19 | { 20 | { 21 | Database db(DBFILENAME); 22 | db.init(); 23 | } 24 | 25 | printf("MAXNSLICE: %lu\n", MAXNSLICE); 26 | struct sockaddr_in cliaddr; 27 | socklen_t len = sizeof(cliaddr); 28 | char buff[MAXLINE]; 29 | int listenfd, srvConnfd; 30 | 31 | Socket listenSocket(SRV_SOCKET, NULL, CTRPORT); 32 | listenfd = listenSocket.init(); 33 | 34 | std::cout << "Listen socket port: " << CTRPORT << std::endl; 35 | 36 | pthread_t tid; 37 | 38 | 39 | while (1) 40 | { 41 | srvConnfd = listenSocket.tcpAccept(listenfd, (SA *) &cliaddr, &len); 42 | printf("connection from %s, port %d\n", 43 | inet_ntop(AF_INET, &cliaddr.sin_addr.s_addr, buff, sizeof(buff)), ntohs(cliaddr.sin_port)); 44 | ThreadArg * pthreadArg = new ThreadArg; 45 | pthreadArg->fd = srvConnfd; 46 | Pthread_create(&tid, NULL, &clientConnect, pthreadArg); 47 | } 48 | return 0; 49 | } 50 | 51 | 52 | -------------------------------------------------------------------------------- /server/server.h: -------------------------------------------------------------------------------- 1 | #ifndef _TINYFTP_SERVER_H_ 2 | #define _TINYFTP_SERVER_H_ 3 | 4 | #include "../common/common.h" 5 | #include "../common/error.h" 6 | #include "../common/packet.h" 7 | #include "../common/sockstream.h" 8 | #include "../common/socket.h" 9 | 10 | #include "srvpi.h" 11 | 12 | 13 | #endif /* _TINYFTP_SERVER_H_ */ -------------------------------------------------------------------------------- /server/srvdtp.cpp: -------------------------------------------------------------------------------- 1 | #include "srvdtp.h" 2 | 3 | void * md5sumThreadFunc(void * arg) 4 | { 5 | ThreadArg * ptarg = (ThreadArg *)arg; 6 | const char * pathname = ptarg->buf; 7 | //Database db = *(ptarg->pdb); 8 | Database db(DBFILENAME); 9 | printf("************md5sumThreadFunc: %s\n", pathname); 10 | string md5str = md5sum(pathname); 11 | string sizestr = getFilesize(string(pathname)); 12 | cout << "md5sumThreadFunc # filepath: " << pathname << "md5str: " << md5str << "sizestr: " << sizestr << endl; 13 | 14 | if (!md5str.empty() && !sizestr.empty()) 15 | { 16 | std::map insertParamMap = { {"MD5SUM", md5str}, 17 | {"MD5RAND", "NULL"}, 18 | {"ABSPATH", pathname}, 19 | {"SIZE", sizestr} }; 20 | if (db.insert("file", insertParamMap)) 21 | { 22 | Error::msg("Success: insert new file MD5SUM"); 23 | } else { 24 | Error::msg("\033[31mDatabase insert error\033[0m"); 25 | } 26 | } 27 | 28 | delete ptarg; 29 | return(NULL); 30 | } 31 | 32 | SrvDTP::SrvDTP(Packet * ppacket, SrvPI * psrvPI) 33 | { 34 | this->ppacket = ppacket; 35 | this->psrvPI = psrvPI; 36 | } 37 | 38 | void SrvDTP::insertNewFileMD5SUM(const char * pathname, Database *pdb) 39 | { 40 | 41 | string inode = getInode(pathname); 42 | 43 | cout << "md5sum computing... " << endl; 44 | string md5str = md5sum(pathname); 45 | string sizestr = getFilesize(string(pathname)); 46 | cout << "insertNewFileMD5SUM # filepath: " << pathname << "md5str: " << md5str << "sizestr: " << sizestr << endl; 47 | 48 | string ghostfilename; 49 | ghostfilename += getCurrentTime(); 50 | ghostfilename += "_" + md5str + "_"; 51 | ghostfilename += psrvPI->getFilename(); 52 | string ghostPath = GHOSTDIR + ghostfilename; 53 | 54 | if (!md5str.empty() && !sizestr.empty()) 55 | { 56 | std::map selectParamMap = { {"MD5SUM", md5str} }; 57 | if (pdb->select("file", selectParamMap)) 58 | { 59 | vector< map > resultMapVector = pdb->getResult(); 60 | if (resultMapVector.empty()) 61 | { 62 | std::map insertParamMap = { {"MD5SUM", md5str}, 63 | {"MD5RAND", "NULL"}, 64 | {"ABSPATH", ghostPath}, 65 | {"FILENAME", ghostfilename}, 66 | {"INODE", inode}, 67 | {"SIZE", sizestr} }; 68 | if (pdb->insert("file", insertParamMap)) 69 | { 70 | Error::msg("Success: insert new file MD5SUM"); 71 | 72 | if (link(pathname, ghostPath.c_str()) < 0) 73 | { 74 | Error::ret("\033[31mlink\033[0m"); 75 | cerr << pathname << ":" << ghostPath << endl; 76 | } 77 | 78 | } else { 79 | Error::msg("\033[31mDatabase insert error\033[0m"); 80 | } 81 | } else { 82 | Error::msg("\033[31mThis MD5SUM already exists\033[0m"); 83 | /*std::map whereParamMap = { {"MD5SUM", md5sum(pathname)} }; 84 | std::map updateParamMap = { {"VALID", "1"} }; 85 | 86 | if (pdb->update("file", whereParamMap, updateParamMap)) 87 | { 88 | vector< map > resultMapVector = pdb->getResult(); 89 | if (!resultMapVector.empty()) 90 | { 91 | printf("Success: update VALID=1\n"); 92 | } else { 93 | printf("update: not find record\n"); 94 | } 95 | } else { 96 | Error::msg("\033[31mDatabase update error\033[0m"); 97 | }*/ 98 | } 99 | } else { 100 | Error::msg("\033[31mDatabase select error\033[0m"); 101 | } 102 | 103 | } 104 | } 105 | void SrvDTP::sendFile(const char *pathname, uint32_t nslice, uint32_t sindex, uint16_t slicecap) 106 | { 107 | //cout << endl << endl << pathname << endl << endl; 108 | Packet & packet = *(this->ppacket); 109 | char buf[MAXLINE]; 110 | Database * pdb = psrvPI->getPDB(); 111 | string inode = getInode(pathname); 112 | std::map selectParamMap = { {"INODE", inode} }; 113 | if (pdb->select("file", selectParamMap)) 114 | { 115 | vector< map > resultMapVector = pdb->getResult(); 116 | if (!resultMapVector.empty()) 117 | { 118 | string dbAccess = resultMapVector[0]["ACCESS"]; 119 | unsigned long long access = std::stoull(dbAccess) + 1; 120 | snprintf(buf, MAXLINE, "%llu", access); 121 | dbAccess = buf; 122 | 123 | std::map updateParamMap = { {"ACCESS", dbAccess} }; 124 | if (pdb->update("file", resultMapVector[0]["ID"], updateParamMap)) 125 | { 126 | cout << "update ACCESS+1 ok" <getFp()), curpos, SEEK_SET) < 0) 143 | // { 144 | // packet.sendSTAT_ERR(strerror_r(errno, buf, MAXLINE)); 145 | // return; 146 | // } else { 147 | // printf("Recv file [%s %u/%u] now\n", pathname, sindex, nslice); 148 | // // send STAT_OK 149 | // packet.sendSTAT_OK(); 150 | // } 151 | 152 | string sizestr = getFilesize(string(pathname)); 153 | if (sizestr.empty()) 154 | { 155 | packet.sendSTAT_ERR("getFilesize() failed"); 156 | return; 157 | } 158 | // confirm enough space to write on client host 159 | packet.sendSTAT(STAT_SIZE, sizestr); 160 | 161 | psrvPI->recvOnePacket(); 162 | if (packet.getTagid() == TAG_STAT && packet.getStatid() == STAT_ERR) 163 | { 164 | return; 165 | } else if (packet.getTagid() == TAG_STAT && packet.getStatid() == STAT_OK) 166 | { 167 | ; 168 | } else { 169 | Error::msg("unknown packet"); 170 | packet.print(); 171 | return; 172 | } 173 | 174 | //if ( (fp = fopen(pathname, "rb")) == NULL) 175 | if ( psrvPI->setFp(fopen(pathname, "rb")) == NULL) 176 | { 177 | // send STAT_ERR Response 178 | // GNU-specific strerror_r: char *strerror_r(int errnum, char *buf, size_t buflen); 179 | packet.sendSTAT_ERR(strerror_r(errno, buf, MAXLINE)); 180 | return; 181 | } else if ( (n = getFileNslice(pathname, &nslice)) <= 0) { 182 | if ( n == 0) { 183 | printf("EOF[%s]: 0 bytes\n", pathname); 184 | Fclose(&psrvPI->getFp()); 185 | packet.sendSTAT_OK(); 186 | packet.sendDATA_TEXT(getFileSizeString(pathname)); 187 | packet.sendDATA_FILE(0, 0, 0, NULL); 188 | packet.sendSTAT_EOF("EOF: 0 bytes"); 189 | return; 190 | } else if ( n == -2) { 191 | snprintf(buf, MAXLINE, "Too large file size"); 192 | packet.sendSTAT_ERR(buf); 193 | } else { 194 | snprintf(buf, MAXLINE, "File stat error"); 195 | packet.sendSTAT_ERR(buf); 196 | } 197 | return; 198 | } else { 199 | // send STAT_OK 200 | packet.sendSTAT_OK(); 201 | } 202 | 203 | packet.sendDATA_TEXT(getFileSizeString(pathname)); 204 | 205 | char body[PBODYCAP]; 206 | printf("Send [%s] now\n", pathname); 207 | 208 | while( (n = fread(body, sizeof(char), PBODYCAP, psrvPI->getFp())) >0 ) 209 | { 210 | packet.sendDATA_FILE(nslice, ++sindex, n, body); 211 | } 212 | 213 | // send EOF 214 | Fclose(&psrvPI->getFp()); 215 | printf("EOF [%s]\n", pathname); 216 | packet.sendSTAT_EOF(); 217 | } 218 | 219 | void SrvDTP::recvFile(const char *pathname, uint32_t nslice, uint32_t sindex, uint16_t slicecap) 220 | { 221 | Packet & packet = *(this->ppacket); 222 | char buf[MAXLINE]; 223 | 224 | if (psrvPI->getFilesize() > getDiskAvailable()) 225 | { 226 | packet.sendSTAT_ERR("insufficient disk space"); 227 | return; 228 | } 229 | 230 | 231 | if ( psrvPI->setFp(fopen(pathname, "ab")) == NULL) 232 | { 233 | // send STAT_ERR Response 234 | // GNU-specific strerror_r: char *strerror_r(int errnum, char *buf, size_t buflen); 235 | packet.sendSTAT_ERR(strerror_r(errno, buf, MAXLINE)); 236 | return; 237 | } else { 238 | 239 | if( (flock(fileno(psrvPI->getFp()), LOCK_EX | LOCK_NB)) < 0) 240 | { 241 | Error::ret("flock"); 242 | packet.sendSTAT_ERR(strerror_r(errno, buf, MAXLINE)); 243 | return; 244 | } 245 | 246 | off64_t n; 247 | off64_t curpos = sindex * slicecap; 248 | if ( ( n = lseek64(fileno(psrvPI->getFp()), curpos, SEEK_SET)) < 0) 249 | { 250 | packet.sendSTAT_ERR(strerror_r(errno, buf, MAXLINE)); 251 | return; 252 | } else { 253 | printf("Recv file [%s %u/%u] now\n", pathname, sindex, nslice); 254 | // send STAT_OK 255 | packet.sendSTAT_OK(); 256 | } 257 | } 258 | 259 | int m; 260 | 261 | int oldProgress = 0, newProgress = 0; 262 | string hfilesize = size2str(psrvPI->getFilesize()); 263 | while (psrvPI->recvOnePacket()) 264 | { 265 | if(packet.getTagid() == TAG_DATA && packet.getDataid() == DATA_FILE){ 266 | m = fwrite(packet.getBody(), sizeof(char), packet.getBsize(), psrvPI->getFp()); 267 | if (m != packet.getBsize()) 268 | { 269 | Error::msg("Recieved slice %d/%d: %d vs %d Bytes\n", packet.getSindex(), packet.getNslice(), packet.getBsize(), m); 270 | return; 271 | } 272 | 273 | newProgress = (packet.getSindex()*1.0)/packet.getNslice()*100; 274 | if (newProgress > oldProgress) 275 | { 276 | //printf("\033[2K\r\033[0m%-40s%10s\t%3d%%", pathname, hfilesize.c_str(), newProgress); 277 | snprintf(buf, MAXLINE, "\033[2K\r\033[0m%-40s%10s\t%3d%%", psrvPI->getClipath().c_str(), hfilesize.c_str(), newProgress); 278 | packet.sendSTAT_PGS(buf); 279 | } 280 | oldProgress = newProgress; 281 | 282 | //printf("Recieved packet %d: %d vs %d Bytes\n", packet.ps->sindex, packet.ps->bsize, m); 283 | } else if(packet.getTagid() == TAG_STAT) { 284 | if (packet.getStatid() == STAT_EOF) 285 | { 286 | if( (flock(fileno(psrvPI->getFp()), LOCK_UN )) < 0 ) 287 | { 288 | Error::ret("flock"); 289 | } 290 | Fclose(&psrvPI->getFp()); 291 | std::cout << packet.getSBody() << std::endl; 292 | 293 | // ThreadArg * pthreadArg = new ThreadArg; 294 | // pthread_t tid; 295 | // pthreadArg->pdb = psrvPI->getPDB(); 296 | // snprintf(pthreadArg->buf, MAXLINE, "%s", pathname); 297 | // Pthread_create(&tid, NULL, &md5sumThreadFunc, pthreadArg); 298 | 299 | if (psrvPI->getFilesize() > (256 * 1024 *1024)) // > 256M 300 | { 301 | packet.sendSTAT(STAT_WAIT, "MD5 computing..."); 302 | } 303 | 304 | insertNewFileMD5SUM(pathname, psrvPI->getPDB()); 305 | 306 | printf("EOT [%s]\n", pathname); 307 | packet.sendSTAT_EOT(" Done"); 308 | 309 | //insertNewFileMD5SUM(pathname, psrvPI->getPDB()); 310 | 311 | return; 312 | //continue; 313 | } else if (packet.getStatid() == STAT_EOT){ 314 | std::cout << packet.getSBody() << std::endl; 315 | return; 316 | } else { 317 | Error::msg("SrvDTP::recvFile TAG_STAT: unknown statid %d", packet.getStatid()); 318 | return; 319 | } 320 | 321 | } else { 322 | 323 | 324 | Error::msg("SrvDTP::recvFile: unknown tagid %d with statid %d", packet.getTagid(), packet.getStatid()); 325 | //packet.print(); 326 | return; 327 | } 328 | 329 | } 330 | } 331 | 332 | int SrvDTP::getFileNslice(const char *pathname,uint32_t *pnslice_o) 333 | { 334 | 335 | unsigned long filesize = 0, n = MAXNSLICE; 336 | 337 | struct stat statbuff; 338 | if(stat(pathname, &statbuff) < 0){ 339 | return -1; // error 340 | } else { 341 | if (statbuff.st_size == 0) 342 | { 343 | return 0; // file is empty. 344 | } else { 345 | filesize = statbuff.st_size; 346 | } 347 | } 348 | if (filesize % SLICECAP == 0) 349 | { 350 | *pnslice_o = filesize/SLICECAP; 351 | } else if ( (n = filesize/SLICECAP + 1) > MAXNSLICE ){ 352 | Error::msg("too large file size: %d\n (MAX: %d)", n, MAXNSLICE); 353 | return -2; 354 | } else { 355 | *pnslice_o = filesize/SLICECAP + 1; 356 | } 357 | //printf("getFileNslice nslice: %u\n", *pnslice_o); 358 | return 1; 359 | } 360 | 361 | string SrvDTP::getFileSizeString(const char *pathname) 362 | { 363 | 364 | unsigned long filesize = 0; 365 | unsigned long n = 0; 366 | string hsize_o; 367 | char buf[MAXLINE]; 368 | unsigned long kbase = 1024; 369 | unsigned long mbase = 1024 * 1024; 370 | unsigned long gbase = 1024 * 1024 * 1024; 371 | 372 | 373 | struct stat statbuff; 374 | if(stat(pathname, &statbuff) < 0){ 375 | hsize_o = "error"; 376 | return hsize_o; // error 377 | } else { 378 | if (statbuff.st_size == 0) 379 | { 380 | hsize_o = "0B"; // file is empty. 381 | } else { 382 | filesize = statbuff.st_size; 383 | if (filesize / kbase == 0) 384 | { 385 | snprintf(buf, MAXLINE, "%lu", filesize); 386 | hsize_o += buf; 387 | hsize_o +="B"; 388 | } else if ( filesize / mbase == 0 ){ 389 | snprintf(buf, MAXLINE, "%lu", filesize / kbase); 390 | hsize_o += buf; 391 | n = (filesize % kbase)* 100 / kbase; 392 | if (n != 0) 393 | { 394 | hsize_o += "."; 395 | snprintf(buf, MAXLINE, "%02lu", n); 396 | hsize_o += buf; 397 | } 398 | hsize_o +="K"; 399 | } else if ( filesize / gbase == 0 ){ 400 | snprintf(buf, MAXLINE, "%2lu", filesize / mbase); 401 | hsize_o += buf; 402 | n = (filesize % mbase)* 100 / mbase; 403 | if (n != 0) 404 | { 405 | hsize_o += "."; 406 | snprintf(buf, MAXLINE, "%02lu", n); 407 | hsize_o += buf; 408 | } 409 | hsize_o +="M"; 410 | } else { 411 | snprintf(buf, MAXLINE, "%lu", filesize / gbase); 412 | hsize_o += buf; 413 | n = (filesize % gbase) * 100 / gbase ; 414 | //printf("filesize n: %lu\n", n); 415 | if (n != 0) 416 | { 417 | hsize_o += "."; 418 | snprintf(buf, MAXLINE, "%02lu", n); 419 | hsize_o += buf; 420 | } 421 | hsize_o +="G"; 422 | } 423 | } 424 | } 425 | return hsize_o; 426 | } -------------------------------------------------------------------------------- /server/srvdtp.h: -------------------------------------------------------------------------------- 1 | #ifndef _TINYFTP_CLIPI_H_ 2 | #define _TINYFTP_CLIPI_H_ 3 | 4 | #include "../common/common.h" 5 | #include "../common/error.h" 6 | #include "../common/packet.h" 7 | #include "../common/socket.h" 8 | #include "../common/sockstream.h" 9 | #include "srvpi.h" 10 | 11 | class SrvPI; 12 | // Server Data Transfer Process (SrvDTP) 13 | class SrvDTP 14 | { 15 | public: 16 | SrvDTP(Packet * ppacket, SrvPI * psrvPI); 17 | //void init(SockStream & connSockStream, Packet & packet); 18 | void insertNewFileMD5SUM(const char * pathname, Database *pdb); 19 | void sendFile(const char *pathname, uint32_t nslice, uint32_t sindex, uint16_t slicecap = SLICECAP); 20 | void recvFile(const char *pathname, uint32_t nslice, uint32_t sindex, uint16_t slicecap = SLICECAP); 21 | int getFileNslice(const char *pathname, uint32_t *pnslice_o ); 22 | string getFileSizeString(const char *pathname); 23 | 24 | 25 | private: 26 | Packet * ppacket; 27 | SrvPI * psrvPI; 28 | 29 | }; 30 | 31 | #endif /* _TINYFTP_CLIPI_H_ */ -------------------------------------------------------------------------------- /server/srvpi.h: -------------------------------------------------------------------------------- 1 | #ifndef _TINYFTP_SRVPI_H_ 2 | #define _TINYFTP_SRVPI_H_ 3 | 4 | #include "../common/common.h" 5 | #include "../common/error.h" 6 | #include "../common/packet.h" 7 | #include "../common/socket.h" 8 | #include "../common/sockstream.h" 9 | #include "../common/database.h" 10 | #include "../common/pi.h" 11 | #include "srvdtp.h" 12 | 13 | // Server Protocol Interpreter (SrvPI) 14 | class SrvPI : public PI 15 | { 16 | public: 17 | SrvPI(string dbFilename, int connfd); 18 | bool checkBreakpoint(); 19 | bool checkGETBreakpoint(); 20 | bool recvOnePacket(); 21 | bool sendOnePacketBlocked(PacketStruct * ps, size_t nbytes); 22 | bool sendOnePacket(PacketStruct * ps, size_t nbytes); 23 | void run(); 24 | void split(std::string src, std::string token, vector& vect); 25 | 26 | void cmdUSER(); 27 | void cmdPASS(); 28 | void cmdUSERADD(); 29 | void cmdUSERDEL(); 30 | 31 | void cmdGET(); 32 | //void cmdGET(string pathname); 33 | void RGET_recurse(string srvpath, string clipath); 34 | void RGET_iterate(string srvpath, string clipath); 35 | void cmdRGET(); 36 | void cmdPUT(); 37 | bool sizecheck(string & sizestr); 38 | bool md5check(string & md5str, string newpath); 39 | void cmdPUT(string clipath, string srvpath); 40 | void cmdRPUT(); 41 | bool cmdLMKDIR(string path); 42 | void cmdLS(); 43 | void cmdCD(); 44 | void cmdRM(); 45 | void cmdPWD(); 46 | void cmdMKDIR(); 47 | void cmdRMDIR(); 48 | void cmdSHELL(); 49 | 50 | 51 | int getConnfd(); 52 | FILE* setFp(FILE *fp); 53 | FILE* & getFp(); 54 | Database * getPDB(); 55 | string getClipath(); 56 | string getFilename(); 57 | unsigned long long getFilesize(); 58 | ~SrvPI(); 59 | 60 | 61 | 62 | 63 | private: 64 | int sessionCommandPacketCount; 65 | Packet packet; 66 | Packet readpacket; 67 | int connfd; 68 | SockStream connSockStream; 69 | //SrvDTP srvDTP; 70 | Database db; 71 | 72 | string userID; // for simple, userID is equal to session ID 73 | std::string userRootDir; 74 | std::string userRCWD; // current working directory relative to userRootDir 75 | 76 | string abspath; 77 | string filename; 78 | string filesize; 79 | 80 | string clipath; 81 | 82 | FILE* fp; 83 | // -1: error, -2: CFM, 0: ok 84 | int combineAndValidatePath(uint16_t cmdid, string userinput, string & msg_o, string & abspath_o); 85 | int cmdPathProcess(uint16_t cmdid, string newAbsDir, string & msg_o); 86 | void saveUserState(); 87 | 88 | void rmdirDFS(); 89 | void removeDir(const char *path_raw, bool removeSelf); 90 | 91 | 92 | }; 93 | 94 | #endif /* _TINYFTP_SRVPI_H_ */ --------------------------------------------------------------------------------