//******************************************************************************
//*this code is protected by the GNU affero GPLv3
//*author:Sylvain BERTRAND <sylvain.bertrand AT gmail dot com>
//* <digital.ragnarok AT gmail dot com>
//******************************************************************************
#include <ulinux/compiler_types.h>
#include <ulinux/types.h>
#include <ulinux/error.h>
#include <ulinux/fs.h>
#include <ulinux/file.h>
#include <ulinux/dirent.h>
#include <ulinux/utils/ascii/string/string.h>
#include <ulinux/sysc.h>
#ifndef QUIET
#include <stdarg.h>
#include <ulinux/utils/ascii/string/vsprintf.h>
#endif
#include "globals.h"
#define DIRENTS_BUF_SZ 8192
static k_ut is_current(k_u8 *n)
{
if(n[0]=='.'&&n[1]==0) return 1;
return 0;
}
static k_ut is_parent(k_u8 *n)
{
if(n[0]=='.'&&n[1]=='.'&&n[2]==0) return 1;
return 0;
}
static k_ut is_newroot(k_u8 *n)
{
#define NEWROOT (k_u8*)"newroot"
return u_a_strncmp(n,NEWROOT,sizeof(NEWROOT)-1)?0:1;
}
static void unlink(k_i parent_fd,k_u8 *n,k_i flgs)
{
k_l r=sysc(unlinkat,3,parent_fd,n,flgs);
if(K_ISERR(r)){
OUT("ERROR(%ld):unable to remove dir entry:%s\n",r,n);
sysc(exit_group,1,-1);
}
}
static void dir_del(k_i parent_fd);
static void dirent_del(k_i parent_fd,struct k_dirent64 *d)
{
if(d->type==K_DT_DIR){
if(!is_current(d->name)&&!is_parent(d->name)){
k_i dir_fd;
do
dir_fd=(k_i)sysc(openat,4,parent_fd,d->name,K_O_RDONLY|K_O_NONBLOCK,0);
while(dir_fd==-K_EINTR);
if(K_ISERR(dir_fd)){
OUT("ERROR(%d):unable to open subdir:%s\n",dir_fd,d->name);
sysc(exit_group,1,-1);
}else{
dir_del(dir_fd);
k_l r;
do r=sysc(close,1,dir_fd); while(r==-K_EINTR);
if(K_ISERR(r)){
OUT("ERROR(%ld):unable to close dir fd\n",r);
sysc(exit_group,1,-1);
}
}
unlink(parent_fd,d->name,K_AT_REMOVEDIR);
}
}else unlink(parent_fd,d->name,0);
}
static void dir_del(k_i parent_fd)
{
k_u8 dirents[DIRENTS_BUF_SZ];
while(1){
k_l r=sysc(getdents64,3,parent_fd,dirents,DIRENTS_BUF_SZ);
if(K_ISERR(r)){
OUT("ERROR(%ld):getdents error\n",r);
sysc(exit_group,1,-1);
}
if(!r) break;
k_l i=0;
while(i<r){
struct k_dirent64 *d=(struct k_dirent64*)(dirents+i);
dirent_del(parent_fd,d);
i+=d->rec_len;
}
}
}
void ramfs_cleanup(void)
{
OUTC(PRE "cleaning ramfs...");
k_i root_fd;
do
root_fd=(k_i)sysc(open,3,"/",K_O_RDONLY|K_O_NONBLOCK,0);
while(root_fd==-K_EINTR);
if(K_ISERR(root_fd)){
OUT("ERROR(%d):unable to open root dir\n",root_fd);
sysc(exit_group,1,-1);
}
k_u8 dirents[DIRENTS_BUF_SZ];
while(1){
k_l r=sysc(getdents64,3,root_fd,dirents,DIRENTS_BUF_SZ);
if(K_ISERR(r)){
OUT("ERROR(%ld):getdents error\n",r);
sysc(exit_group,1,-1);
}
if(!r) break;
k_l i=0;
while(i<r){
struct k_dirent64 *d=(struct k_dirent64*)(dirents+i);
if(!is_newroot(d->name)) dirent_del(root_fd,d);
i+=d->rec_len;
}
}
k_l r;
do r=sysc(close,1,root_fd); while(r==-K_EINTR);
if(K_ISERR(r)){
OUT("ERROR(%ld):unable to root dir fd\n",r);
sysc(exit_group,1,-1);
}
OUTC("done\n");
}