一个简单的文件共享工程 -- FileServer

来源:互联网 发布:淘宝天猫网店交易平台 编辑:程序博客网 时间:2024/05/17 07:54

FileServer文件夹中文件:

FileServer.h:

#ifndef __FILE_SERVER_H__#define __FILE_SERVER_H__#include "../TMServer/TMServer.h"class FileServer : public TMServer{public:    FileServer(const char * host, const char * serv);    ~FileServer();protected:    virtual bool handle(ConnNode & conn, unsigned char cmd,                         char * data, unsigned short uslen);private:    bool handle_ls_req(ConnNode & conn, char * data, unsigned short uslen);    bool handle_cd_req(ConnNode & conn, char * data, unsigned short uslen);    bool handle_mkdir_req(ConnNode & conn, char * data, unsigned short uslen);    bool handle_touch_req(ConnNode & conn, char * data, unsigned short uslen);    bool handle_rm_req(ConnNode & conn, char * data, unsigned short uslen);    bool handle_download_req(ConnNode & conn, char * data, unsigned short uslen);    bool handle_upload_req(ConnNode & conn, char * data, unsigned short uslen);private:    void writelength(char * buff, unsigned short & uslen);    int checkdir(char * cwd, char * data, char * buff, unsigned short uslen);    int checkall(char * cwd, char *& data, bool & dir,                  char * buff, unsigned short uslen);    bool mkdir(char *& data, char * buff, unsigned short uslen);    bool rmcwd(char * buff, unsigned short uslen);    bool upsend(int sockfd, unsigned char state, char * buff, unsigned short uslen);    int upfile(int sockfd, char * filename, char * buff, unsigned short uslen);    int updir(int sockfd, char * pathname, char * buff, unsigned short uslen);};#endif
FileServer.cpp:

#include <errno.h>#include <fcntl.h>#include <sys/stat.h>#include <cstdio>#include <cstring>#include <cassert>#include "../ByteStream/ByteStream.h"#include "../Head/Command.h"#include "FileServer.h"FileServer::FileServer(const char * host, const char * serv) : TMServer(host, serv){    }FileServer::~FileServer(){    }bool FileServer::handle(ConnNode & conn, unsigned char cmd,                         char * data, unsigned short uslen){    switch (cmd)    {        case ls:        {            return(handle_ls_req(conn, data, uslen));        }        case cd:        {            return(handle_cd_req(conn, data, uslen));        }        case mk:        {            return(handle_mkdir_req(conn, data, uslen));        }        case touch:        {            return(handle_touch_req(conn, data, uslen));        }        case rm:        {            return(handle_rm_req(conn, data, uslen));        }        case download:        {            return(handle_download_req(conn, data, uslen));        }        case upload:        {            return(handle_upload_req(conn, data, uslen));        }        default:        {            return(false);        }    }}bool FileServer::handle_ls_req(ConnNode & conn, char * data,                                unsigned short uslen){    char buff[BUFFSIZ] = { 0 };    const int reserved = sizeof(unsigned short) + sizeof(unsigned char);    char * ptr = buff + reserved;    unsigned short left = BUFFSIZ - 1 - reserved;    int n;    if (-1 == (n = checkdir(conn.cwd, data, ptr, left))) {        return(false);    }    else if (1 == n) {        *ptr = '\0';        struct dirent * dirp;        DIR           * dp;        if (NULL == (dp = opendir("."))) {            snprintf(ptr, left, "%s\n", strerror(errno));        }        else {            bool fine = true;            while (NULL != (dirp = readdir(dp))) {                if (strcmp(dirp->d_name, ".") == 0 ||                    strcmp(dirp->d_name, "..") == 0) {                    continue;                }                int len = strlen(dirp->d_name);                if (left <= len + 1) {                    buff[sizeof(unsigned short)] = (unsigned char)' ';                    writelength(buff, uslen);                    buff[sizeof(unsigned short)] = (unsigned char)0;                    if (!send(conn.sockfd, buff, uslen)) {                        fine = false;                        break;                    }                    ptr  = buff + reserved;                    left = BUFFSIZ - 1 - reserved;                }                snprintf(ptr, left, "%s\n", dirp->d_name);                ptr  += len + 1;                left -= len + 1;            }            if (-1 == closedir(dp)) {                printf("closedir error: %s\n", strerror(errno));            }            if (!fine) {                return(false);            }        }    }    buff[sizeof(unsigned short)] = (unsigned char)' ';    writelength(buff, uslen);    buff[sizeof(unsigned short)] = (unsigned char)1;    return(send(conn.sockfd, buff, uslen));}bool FileServer::handle_cd_req(ConnNode & conn, char * data,                                unsigned short uslen){    char buff[BUFFSIZ] = { 0 };    const int reserved = sizeof(unsigned short);    char * ptr = buff + reserved;    unsigned short left = BUFFSIZ - 1 - reserved;    if (0 == strlen(data)) {        strcpy(conn.cwd, TMServer::ConnNode::root);        *ptr = '\0';    }    else {        int n;        if (-1 == (n = checkdir(conn.cwd, data, ptr, left))) {            return(false);        }        else if (1 == n) {            strcpy(conn.cwd, ptr);            *ptr = '\0';        }    }    writelength(buff, uslen);    return(send(conn.sockfd, buff, uslen));}bool FileServer::handle_mkdir_req(ConnNode & conn, char * data, unsigned short uslen){    char buff[BUFFSIZ] = { 0 };    const int reserved = sizeof(unsigned short);    char * ptr = buff + reserved;    unsigned short left = BUFFSIZ - 1 - reserved;    if (-1 == chdir(conn.cwd)) {        printf("chdir to %s error: %s\n", conn.cwd, strerror(errno));        return(false);    }    if (!mkdir(data, ptr, left)) {        writelength(buff, uslen);        return(send(conn.sockfd, buff, uslen));    }    int len = strlen(data);    if ('/' != data[len - 1] && -1 == ::mkdir(data, DIR_MODE) && EEXIST != errno) {        snprintf(ptr, left, "%s\n", strerror(errno));    }    else {        *ptr = '\0';    }    writelength(buff, uslen);    return(send(conn.sockfd, buff, uslen));}bool FileServer::handle_touch_req(ConnNode & conn, char * data, unsigned short uslen){    char buff[BUFFSIZ] = { 0 };    const int reserved = sizeof(unsigned short);    char * ptr = buff + reserved;    unsigned short left = BUFFSIZ - 1 - reserved;    if (-1 == chdir(conn.cwd)) {        printf("chdir to %s error: %s\n", conn.cwd, strerror(errno));        return(false);    }    if (!mkdir(data, ptr, left)) {        writelength(buff, uslen);        return(send(conn.sockfd, buff, uslen));    }    int len = strlen(data);    if ('/' != data[len - 1]) {        int fd;        if (-1 == (fd = open(data, O_WRONLY | O_CREAT | O_EXCL, FILE_MODE))) {            snprintf(ptr, left, "%s\n", strerror(errno));        }        else {            if (-1 == ::close(fd)) {                printf("close error: %s\n", strerror(errno));            }            *ptr = '\0';        }    }    else {        snprintf(ptr, left, "Invalid filename\n");    }    writelength(buff, uslen);    return(send(conn.sockfd, buff, uslen));}bool FileServer::handle_rm_req(ConnNode & conn, char * data,                                unsigned short uslen){    char buff[BUFFSIZ] = { 0 };    const int reserved = sizeof(unsigned short);    char * ptr = buff + reserved;    unsigned short left = BUFFSIZ - 1 - reserved;    bool dir;    int  n;    if (-1 == (n = checkall(conn.cwd, data, dir, ptr, left))) {        return(false);    }    else if (1 == n) {        if (dir) {            bool root = (0 == strcmp(TMServer::ConnNode::root, ptr));            if (rmcwd(ptr, left)) {                if (!root && -1 == rmdir(ptr)) {                    snprintf(ptr, left, "%s\n", strerror(errno));                }                else {                    *ptr = '\0';                }            }            adjustcwd();        }        else {            if (-1 == unlink(data)) {                snprintf(ptr, left, "%s\n", strerror(errno));            }            else {                *ptr = '\0';            }        }    }     writelength(buff, uslen);    return(send(conn.sockfd, buff, uslen));}bool FileServer::handle_download_req(ConnNode & conn, char * data,                                      unsigned short uslen){    char buff[BUFFSIZ] = { 0 };    const int reserved = sizeof(unsigned short) + sizeof(unsigned char);    char * ptr = buff + reserved;    unsigned short left = BUFFSIZ - 1 - reserved;    bool dir;    int  n;    if (-1 == (n = checkall(conn.cwd, data, dir, ptr, left))) {        return(false);    }    else if (1 == n) {        if (dir) {            if (-1 == chdir("..")) {                snprintf(ptr, left, "Failed when chdir\n");            }            else {                char pathname[PATH_MAX + 1] = { 0 };                int index = strlen(ptr) - 2;                while (index >= 0) {                    if ('/' == ptr[index]) {                        break;                    }                    --index;                }                ++index;                strcpy(pathname, ptr + index);                if (1 == (n = updir(conn.sockfd, pathname, ptr, left))) {                    *ptr = '\0';                }            }        }        else {            if (1 == (n = upfile(conn.sockfd, data, ptr, left))) {                *ptr = '\0';            }        }    }    if (-1 == n) {        return(false);    }    return(upsend(conn.sockfd, done, buff, strlen(ptr) + 1));}bool FileServer::handle_upload_req(ConnNode & conn, char * data,                                    unsigned short uslen){    char buff[BUFFSIZ] = { 0 };    int  fd = -1;    char laststate = done;    if (-1 == chdir(conn.cwd)) {        printf("chdir to %s error: %s\n", conn.cwd, strerror(errno));        return(false);    }    while (true) {        unsigned short uslen = sizeof(unsigned short);        if (!setrcvlow(conn.sockfd, uslen)) {            return(false);        }        if (!recv(conn.sockfd, buff, uslen)) {            return(false);        }        IBStream is(buff, uslen);        is >> uslen;        assert(uslen > 0);        if (!setrcvlow(conn.sockfd, uslen)) {            return(false);        }        if (!recv(conn.sockfd, buff, uslen)) {            return(false);        }        switch (buff[0])        {            case snddir:            {                if (-1 == ::mkdir(buff + 1, DIR_MODE) && EEXIST != errno) {                    printf("mkdir error: %s\n", strerror(errno));                }                break;            }            case sndfile:            {                if (-1 != fd) {                    ::close(fd);                }                int index = 0;                while (++index > 0 && -1 != access(buff + 1, F_OK)) {                    snprintf(buff + 1 + (uslen - 2), BUFFSIZ - 1 - uslen, "(%d)", index);                }                if (-1 == (fd = open(buff + 1, O_WRONLY | O_CREAT, FILE_MODE))) {                    printf("open error: %s\n", strerror(errno));                }                break;            }            case sndtxt:            {                if (sndfile != laststate && sndtxt != laststate) {                    if (-1 != fd) {                        ::close(fd);                    }                    printf("error: state from (%d) to (%d)\n", laststate, buff[0]);                    return(false);                }                uslen -= 1;                if (-1 != fd) {                    if (uslen != write(fd, buff + 1, uslen)) {                        printf("write error: %s\n", strerror(errno));                    }                }                break;            }            case done:            {                if (-1 != fd) {                    ::close(fd);                }                return(true);            }            default:            {                if (-1 != fd) {                    ::close(fd);                }                printf("error: unknown state (%d)\n", buff[0]);                return(false);            }        }        laststate = buff[0];    }}void FileServer::writelength(char * buff, unsigned short & uslen){    const int reserved = sizeof(unsigned short);    OBStream os(buff, reserved);    uslen = strlen(buff + reserved);    if (uslen > 0) {        uslen += 1;    }    os << uslen;    uslen += reserved;}int FileServer::checkdir(char * cwd, char * data,                          char * buff, unsigned short uslen){    if (-1 == chdir(cwd)) {        printf("chdir to %s error: %s\n", cwd, strerror(errno));        return(-1);    }    if (-1 == chdir(data)) {        snprintf(buff, uslen, "%s\n", strerror(errno));        return(0);    }    if (NULL == getcwd(buff, uslen)) {        snprintf(buff, uslen, "%s\n", strerror(errno));        return(0);    }    int len = strlen(buff);    if ('/' != buff[len - 1]) {        buff[len] = '/';        buff[len + 1] = '\0';    }    if (0 != strncmp(TMServer::ConnNode::root, buff,                      strlen(TMServer::ConnNode::root))) {        snprintf(buff, uslen, "Do not have permission"                              " to access the directory\n");        return(0);           }    return(1);}int FileServer::checkall(char * cwd, char *& data, bool & dir,                          char * buff, unsigned short uslen){    if (-1 == chdir(cwd)) {        printf("chdir to %s error: %s\n", cwd, strerror(errno));        return(-1);    }    struct stat sbuf;    if (-1 == lstat(data, &sbuf)) {        snprintf(buff, uslen, "%s\n", strerror(errno));        return(0);    }    if (S_ISDIR(sbuf.st_mode)) {        dir = true;        return(checkdir(cwd, data, buff, uslen));    }    else {        dir = false;        int    n = 1;        char * slash = strrchr(data, '/');        if (NULL != slash) {            *slash = '\0';            if (1 == (n = checkdir(cwd, data, buff, uslen))) {                data = slash + 1;            }        }        return(n);    }}bool FileServer::mkdir(char *& data, char * buff, unsigned short uslen){    int len = strlen(data);    int index = 0;    while (index < len) {        if (' ' != data[index] &&             '/' != data[index] &&             '.' != data[index]) {            break;        }        ++index;    }    if (index >= len) {        snprintf(buff, uslen, "Invalid filename\n");        return(false);    }    data += index;    len  -= index;    index = 0;    while (index < len) {        if ('/' == data[index]) {            data[index] = '\0';            if (-1 == ::mkdir(data, DIR_MODE) && EEXIST != errno) {                snprintf(buff, uslen, "%s\n", strerror(errno));                return(false);            }            data[index] = '/';        }        ++index;    }    return(true);}bool FileServer::rmcwd(char * buff, unsigned short uslen){    struct dirent * dirp;    DIR           * dp;    struct stat     sbuf;    char            cwd[PATH_MAX + 1];    bool            fine = true;    if (NULL == getcwd(cwd, PATH_MAX + 1)) {        snprintf(buff, uslen, "Failed when getcwd\n");        return(false);    }            if (NULL == (dp = opendir("."))) {        snprintf(buff, uslen, "Failed when opendir\n");        return(false);    }    while (NULL != (dirp = readdir(dp))) {        if (strcmp(dirp->d_name, ".") == 0 ||            strcmp(dirp->d_name, "..") == 0) {            continue;        }        if (-1 == lstat(dirp->d_name, &sbuf)) {            continue;        }        if (S_ISDIR(sbuf.st_mode)) {            if (-1 == chdir(dirp->d_name)) {                snprintf(buff, uslen, "Failed when chdir\n");                fine = false;                break;            }            if (!rmcwd(buff, uslen)) {                fine = false;                break;            }            if (-1 == chdir(cwd)) {                snprintf(buff, uslen, "Failed when chdir\n");                fine = false;                break;            }            if (-1 == rmdir(dirp->d_name)) {                snprintf(buff, uslen, "Failed when rmdir\n");                fine = false;                break;            }        }        else {            if (-1 == unlink(dirp->d_name)) {                snprintf(buff, uslen, "Failed when unlink\n");                fine = false;                break;            }        }    }    if (-1 == closedir(dp) && fine) {        snprintf(buff, uslen, "Failed when closedir\n");        fine = false;    }    return(fine);}bool FileServer::upsend(int sockfd, unsigned char state,                         char * buff, unsigned short uslen){    uslen += sizeof(unsigned char);    OBStream os(buff, sizeof(unsigned short) + sizeof(unsigned char));    os << uslen << state;    uslen += sizeof(unsigned short);    return(send(sockfd, buff, uslen));}int FileServer::upfile(int sockfd, char * filename,                        char * buff, unsigned short uslen){    const int      reserved = sizeof(unsigned short) + sizeof(unsigned char);    unsigned short filelen = strlen(filename);    strcpy(buff + reserved, filename);    if (!upsend(sockfd, sndfile, buff, filelen + 1)) {        return(-1);    }    int fd;    if (-1 == (fd = open(filename, O_RDONLY))) {        snprintf(buff, uslen, "Failed when open\n");        return(0);    }    char           * ptr  = buff  + reserved;    unsigned short   left = uslen - reserved;    unsigned short   size = 0;    int              n    = 0;    int              ret  = 1;    while ((n = read(fd, ptr, left)) > 0) {        ptr  += n;        left -= n;        size += n;        if (0 == left || size >= 4096 - reserved) {            if (!upsend(sockfd, sndtxt, buff, size)) {                ret = -1;                break;            }            ptr  = buff  + reserved;            left = uslen - reserved;            size = 0;        }    }    do {        if (size > 0) {            if (!upsend(sockfd, sndtxt, buff, size)) {                ret = -1;            }        }        if (1 != ret) {            break;        }        if (-1 == n) {            snprintf(buff, uslen, "Failed when read\n");            ret = 0;            break;        }    } while (false);    if (-1 == ::close(fd) && 1 == ret) {        snprintf(buff, uslen, "Failed when close\n");        ret = 0;    }    return(ret);}int FileServer::updir(int sockfd, char * pathname,                       char * buff, unsigned short uslen){    struct dirent * dirp;    DIR           * dp;    struct stat     sbuf;    int             ret = 1;    int             pathlen = strlen(pathname);    const int       reserved = sizeof(unsigned short) + sizeof(unsigned char);    strcpy(buff + reserved, pathname);    if (!upsend(sockfd, snddir, buff, pathlen + 1)) {        return(-1);    }    if (NULL == (dp = opendir(pathname))) {        snprintf(buff, uslen, "Failed when opendir\n");        return(0);    }    while (NULL != (dirp = readdir(dp))) {        if (strcmp(dirp->d_name, ".") == 0 ||            strcmp(dirp->d_name, "..") == 0) {            continue;        }        strcat(pathname, dirp->d_name);        if (-1 == lstat(pathname, &sbuf)) {            pathname[pathlen] = '\0';            continue;        }        if (S_ISDIR(sbuf.st_mode)) {            strcat(pathname, "/");            if (1 != (ret = updir(sockfd, pathname, buff, uslen))) {                break;            }        }        else {            if (1 != (ret = upfile(sockfd, pathname, buff, uslen))) {                break;            }        }        pathname[pathlen] = '\0';    }    pathname[pathlen] = '\0';    if (-1 == closedir(dp) && 1 == ret) {        snprintf(buff, uslen, "Failed when closedir\n");        ret = 0;    }    return(ret);}
Server.cpp:

#include <cstdio>#include <cstdlib>#include "FileServer.h"int main(int argc, char ** argv){    if (3 != argc) {        printf("usage: %s <host> <serv>\n", argv[0]);        exit(1);    }    FileServer server(argv[1], argv[2]);    server.mainloop();    return(0);}
makefile:

objects=Server.o FileServer.o TMServer.o TConnection.o ByteStream.oserver:$(objects)g++ -o server $(objects)  Server.o:Server.cppg++ -c Server.cppFileServer.o:FileServer.cpp FileServer.h ../Head/Command.hg++ -c FileServer.cppTMServer.o:../TMServer/TMServer.cpp ../TMServer/TMServer.h ../Head/Command.h ../Head/Uncopy.hg++ -c ../TMServer/TMServer.cppTConnection.o:../TConnection/TConnection.cpp ../TConnection/TConnection.hg++ -c ../TConnection/TConnection.cppByteStream.o:../ByteStream/ByteStream.cpp ../ByteStream/ByteStream.hg++ -c ../ByteStream/ByteStream.cpprebuild:clean serverclean:  -rm server $(objects)