/* Next File Transfer Client Copyright (C) 2020 Ian Cowburn This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include static const char *name; static void *Malloc(size_t len) { void *p; p = malloc(len); if (!p) { perror(name); exit(EXIT_FAILURE); } return p; } static char *GetLine(char *buff, size_t len) { size_t l; if (feof(stdin)) { return NULL; } printf("NFT> "); if (!fgets(buff, len, stdin)) { return NULL; } l = strlen(buff); if (l > 0 && buff[l-1]=='\n') { buff[l-1]=0; } if (l) { return buff; } else { return GetLine(buff, len); } } static int Connect(const char *n, int p) { struct hostent *remote; struct sockaddr_in addr; int sock; if (!(remote = gethostbyname(n))) { fprintf(stderr,"%s: unknown host %s\n",name,n); exit(EXIT_FAILURE); } memcpy(&addr.sin_addr, remote->h_addr, remote->h_length); if ((sock = socket(AF_INET, SOCK_STREAM, 0))==-1) { perror(name); exit(EXIT_FAILURE); } addr.sin_family = AF_INET; addr.sin_port = htons(p); if (connect(sock,(void*)&addr,sizeof(addr)) == -1) { perror(name); exit(EXIT_FAILURE); } return sock; } static int Read(int sock, char *buff, size_t len) { while(len > 0) { size_t rd; rd = read(sock, buff, len); if (rd == -1) { perror(name); return 0; } else if (rd == 0) { return 0; } else { len -= rd; buff += rd; } } return 1; } static int Write(int sock, const char *buff, size_t len) { while(len > 0) { size_t wr; wr = write(sock, buff, len); if (wr == -1) { perror(name); return 0; } else if (wr == 0) { return 0; } else { len -= wr; buff += wr; } } return 1; } static int WriteBlock(int sock, const char *block, size_t len) { char buff[32]; if (len > 99999) { fprintf(stderr, "%s: length of block %zu too large\n", name, len); return 0; } snprintf(buff, sizeof buff, "%.5zu", len); if (!Write(sock, buff, 5)) { return 0; } if (!Write(sock, block, len)) { return 0; } return 1; } static size_t ReadSize(int sock) { char buff[32]; if (!Read(sock, buff, 5)) { return 0; } return atoi(buff); } static size_t FileSize(const char *path) { struct stat st; if (stat(path, &st) == 0) { return st.st_size; } else { return 0; } } static int Put(int sock, const char *path) { int quit = 0; char status[3] = {0}; size_t len; int fd; if ((len = FileSize(path)) == 0) { perror(path); } else { char *buff; int fd; buff = Malloc(len); fd = open(path, O_RDONLY); read(fd, buff, len); close(fd); if (!Write(sock, "PF", 2)) { quit = 1; } if (!quit && !WriteBlock(sock, path, strlen(path))) { quit = 1; } if (!quit && !WriteBlock(sock, buff, len)) { quit = 1; } if (!quit && Read(sock, status, 2)) { if (strcmp(status, "!E") == 0) { printf("Command failed\n"); } } else { quit = 1; } } return quit; } static int Get(int sock, const char *path) { int quit = 0; char status[3] = {0}; int fd; if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC)) == -1) { perror(path); return 0; } if (!Write(sock, "GF", 2)) { quit = 1; } if (!quit && !WriteBlock(sock, path, strlen(path))) { quit = 1; } if (!quit && Read(sock, status, 2)) { if (strcmp(status, "!E") == 0) { printf("Command failed\n"); } else { size_t len; if ((len = ReadSize(sock)) > 0) { char buff[100000]; if (Read(sock, buff, len)) { write(fd, buff, len); } else { quit = 1; } } } } else { quit = 1; } close(fd); return quit; } static int Cd(int sock, const char *path) { int quit = 0; return quit; } static int Mkdir(int sock, const char *path) { int quit = 0; return quit; } int main(int argc, char *argv[]) { char buff[1024]; int sock; int quit = 0; if ((name = strrchr(argv[0], '/'))) { name++; } else { name = argv[0]; } if (argc<3) { fprintf(stderr,"%s: usage %s host port\n",name,name); exit(EXIT_FAILURE); } sock = Connect(argv[1],atoi(argv[2])); while(!quit && GetLine(buff, sizeof buff)) { char *tok; tok = strtok(buff, " \t"); if (strcmp(tok, "exit") == 0) { break; } else if (strcmp(tok, "put") == 0) { quit = Put(sock, strtok(NULL, " \t")); } else if (strcmp(tok, "get") == 0) { quit = Get(sock, strtok(NULL, " \t")); } else if (strcmp(tok, "cd") == 0) { quit = Cd(sock, strtok(NULL, " \t")); } else if (strcmp(tok, "mkdir") == 0) { quit = Mkdir(sock, strtok(NULL, " \t")); } else { printf("Unrecognised command '%s'\n", tok); } } close(sock); return EXIT_SUCCESS; }