ftp-server-minimal/ftpd_vfs.c
2020-01-26 02:20:59 +02:00

308 lines
No EOL
6.1 KiB
C

#include "ftpd_vfs.h"
#include "ftpd_util.h"
static struct vfs_mod_s* first = NULL;
void vfs_add_mod(struct vfs_mod_s* mod)
{
struct vfs_mod_s* elem;
if(first)
{
elem = first;
while(elem->next) elem = elem->next;
mod->next = NULL;
elem->next = mod;
} else first = mod;
}
vfs_mod_t* vfs_get_mod(ftpd_user_t* user,const char* wdir)
{
vfs_mod_t* mod;
mod = first;
while(mod)
{
if(mod->vfs_check(user,wdir)) break;
mod = mod->next;
}
return mod;
}
int vfs_list(ftpd_user_t* user,int mlsd)
{
vfs_mod_t* mod;
mod = vfs_get_mod(user,user->wdir);
if(!mod) return 1;
if(mod->vfs_list)
return mod->vfs_list(user,mlsd);
return 1;
}
int vfs_fallback_start_retr(ftpd_user_t* user,char* path,uint64_t size,int is_file)
{
dataconn_t* dc;
if(user->dlcommand == 0)
{
ftpd_user_send_replyf(user,"150 Opening BINARY mode data connection for %s (%llu).\r\n",
path,size);
user->dlcommand++;
}
else if(user->dlcommand == 1)
{
if(ftpd_user_make_dataconn(user))
{
ftpd_data_close(user,dc);
ftpd_user_send_reply(user,"425 Can't open data connection.\r\n");
user->dlcommand = 0;
return 0;
}
dc = ftpd_user_get_cur_dataconn(user);
if(is_file)
{
DWORD dwRestHigh,dwRestLow;
dwRestLow = user->rest & 0xFFFFFFFF;
dwRestHigh = user->rest >> 32;
SetFilePointer(dc->hFile,dwRestLow,&dwRestHigh,FILE_CURRENT);
dc->mode = DATACONN_SEND_FP;
} else dc->mode = DATACONN_SEND;
dc->event = ftpd_list_event_end;
user->dlcommand = 0;
}
return 0;
}
int vfs_fallback_start_stor(ftpd_user_t* user,char* path)
{
dataconn_t* dc;
if(user->dlcommand == 0)
{
ftpd_user_send_replyf(user,"150 Opening BINARY mode data connection for %s\r\n",
path);
user->dlcommand++;
}
else if(user->dlcommand == 1)
{
DWORD dwRestHigh,dwRestLow;
if(ftpd_user_make_dataconn(user))
{
ftpd_data_close(user,dc);
ftpd_user_send_reply(user,"425 Can't open data connection.\r\n");
user->dlcommand = 0;
return 0;
}
dc = ftpd_user_get_cur_dataconn(user);
dwRestLow = user->rest & 0xFFFFFFFF;
dwRestHigh = user->rest >> 32;
SetFilePointer(dc->hFile,dwRestLow,&dwRestHigh,FILE_CURRENT);
dc->mode = DATACONN_RECV_FP;
dc->close = ftpd_list_event_end;
user->dlcommand = 0;
}
return 0;
}
int vfs_retr(ftpd_user_t* user,char* path)
{
vfs_mod_t* mod;
if(path[0] == '/')
mod = vfs_get_mod(user,path);
else mod = vfs_get_mod(user,user->wdir);
if(!mod) return 1;
if(mod->vfs_retr)
return mod->vfs_retr(user,path);
return 1;
}
int vfs_stor(ftpd_user_t* user,char* path)
{
vfs_mod_t* mod;
if(path[0] == '/')
mod = vfs_get_mod(user,path);
else mod = vfs_get_mod(user,user->wdir);
if(!mod) return 1;
if(mod->vfs_stor)
return mod->vfs_stor(user,path);
return 1;
}
int vfs_appe(ftpd_user_t* user,char* path)
{
vfs_mod_t* mod;
if(path[0] == '/')
mod = vfs_get_mod(user,path);
else mod = vfs_get_mod(user,user->wdir);
if(!mod) return 1;
if(mod->vfs_appe)
return mod->vfs_appe(user,path);
return 1;
}
int vfs_dele(ftpd_user_t* user,char* path)
{
vfs_mod_t* mod;
if(path[0] == '/')
mod = vfs_get_mod(user,path);
else mod = vfs_get_mod(user,user->wdir);
if(!mod) return 1;
if(mod->vfs_dele)
return mod->vfs_dele(user,path);
return 1;
}
int vfs_size(ftpd_user_t* user,char* path)
{
vfs_mod_t* mod;
if(path[0] == '/')
mod = vfs_get_mod(user,path);
else mod = vfs_get_mod(user,user->wdir);
if(!mod) return 1;
if(mod->vfs_size)
return mod->vfs_size(user,path);
return 1;
}
int vfs_cwd(ftpd_user_t* user,char* path)
{
vfs_mod_t* mod;
if(path[0] == '/')
mod = vfs_get_mod(user,path);
else mod = vfs_get_mod(user,user->wdir);
if(!mod) return 1;
if(mod->vfs_cwd)
return mod->vfs_cwd(user,path);
return 1;
}
int vfs_mkd(ftpd_user_t* user,char* path)
{
vfs_mod_t* mod;
if(path[0] == '/')
mod = vfs_get_mod(user,path);
else mod = vfs_get_mod(user,user->wdir);
if(!mod) return 1;
if(mod->vfs_mkd)
return mod->vfs_mkd(user,path);
return 1;
}
//Replaces '\\' to '/'
int vfs_fix_slashes(char* buf)
{
int i;
for(i = 0; buf[i]; i++)
if(buf[i] == '\\') buf[i] = '/';
}
int vfs_changepath(ftpd_user_t* user,char* path)
{
char buf[MAX_PATH];
char newpath[MAX_PATH];
int last,cwd_root;
//First, we need to determine is it absolute or relative path
strncpy(newpath,path,MAX_PATH-1);
vfs_fix_slashes(newpath);
cwd_root = 0;
// ../dir1
if(!memcmp(newpath,"..",2) && strcmp(user->wdir,"/"))
{
char* c;
strncpy(buf,user->wdir,MAX_PATH-1);
//wdir /mnt/D/dir1/dir2
c = strrchr(buf,'/');
if(c == buf)
{
//We got root dir
strncpy(buf,"/",MAX_PATH-1);
cwd_root = 1;
}
else
{
*c = '\0';
if(newpath[2] != '\0')
strncat(buf,newpath+2,MAX_PATH-1);
}
}
else
{
//new path /mnt/D/dir1
if(newpath[0] == '/') //Absolute path
{
strncpy(buf,newpath,MAX_PATH);
}
else
{
//FIXME BUG! CWD home => "home" is current directory (without wdir slash)
buf[0] = '\0';
strncpy(buf,user->wdir,MAX_PATH-1);
if(strcmp(user->wdir,"/")) //If not "/" root dir
strncat(buf,"/",MAX_PATH-1);
strncat(buf,newpath,MAX_PATH-1);
}
}
vfs_fix_slashes(buf);
if(strcmp(buf,"/") && cwd_root == 0)
{
//Remove last slash
last = strlen(buf)-1;
if(buf[last] == '/') buf[last] = '\0';
}
//Now call vfs_cwd
if(vfs_cwd(user,buf))
return 1;
strncpy(user->wdir,buf,MAX_PATH-1);
return 0;
}
void vfs_reply_dir(dataconn_t* dc,int mlsd,
int dir,int year,int month,int day,
int hour,int minute,int second,
uint64_t size,const char* name)
{
if(mlsd)
{
ftpd_dc_send_replyf(dc,"type=%s;modify=%04d%02d%02d%02d%02d%02d;size=%llu; %s\r\n",
dir ? "dir" : "file",year,month,day,hour,minute,second,size,name);
}
else
{
ftpd_dc_send_replyf(dc,"%crwxr-xr-x 1 ftp ftp %llu %s %02d %04d %s\r\n",
dir ? 'd' : '-',size,get_month(month),day,year,name);
}
}