308 lines
No EOL
6.1 KiB
C
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);
|
|
}
|
|
} |