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

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.o
server:$(objects)
	g++ -o server $(objects)  

Server.o:Server.cpp
	g++ -c Server.cpp
FileServer.o:FileServer.cpp FileServer.h ../Head/Command.h
	g++ -c FileServer.cpp
TMServer.o:../TMServer/TMServer.cpp ../TMServer/TMServer.h ../Head/Command.h ../Head/Uncopy.h
	g++ -c ../TMServer/TMServer.cpp
TConnection.o:../TConnection/TConnection.cpp ../TConnection/TConnection.h
	g++ -c ../TConnection/TConnection.cpp
ByteStream.o:../ByteStream/ByteStream.cpp ../ByteStream/ByteStream.h
	g++ -c ../ByteStream/ByteStream.cpp

rebuild:clean server

clean:  
	-rm server $(objects)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值