您的位置:首页 > 其它

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

2012-06-03 13:13 302 查看
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)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息