/*## (c) SECURITY EXPLORATIONS    2018 poland                                #*/
/*##     http://www.security-explorations.com                                #*/

/* THIS SOFTWARE IS PROTECTED BY DOMESTIC AND INTERNATIONAL COPYRIGHT LAWS    */
/* UNAUTHORISED COPYING OF THIS SOFTWARE IN EITHER SOURCE OR BINARY FORM IS   */
/* EXPRESSLY FORBIDDEN. ANY USE, INCLUDING THE REPRODUCTION, MODIFICATION,    */
/* DISTRIBUTION, TRANSMISSION, RE-PUBLICATION, STORAGE OR DISPLAY OF ANY      */
/* PART OF THE SOFTWARE, FOR COMMERCIAL OR ANY OTHER PURPOSES REQUIRES A      */
/* VALID LICENSE FROM THE COPYRIGHT HOLDER.                                   */

/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS    */
/* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,*/
/* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    */
/* SECURITY EXPLORATIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF  */
/* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE     */
/* SOFTWARE.                                                                  */

import java.lang.*;
import java.util.*;
import java.io.*;

public class FS {
 private static int getcwd;
 private static int chdir;

 private static int cwdbuf;
 private static int lnkbuf;

 private static NativeCode nc;

 private static String cwd;
 private static String jcwd;

 public static String ignored_dirs[]={
  "/dev",
 };

 public static String ignored_files[]={
  "/proc/kcore",
  "/proc/timer_list",
  "/proc/stpti4_core/memapi"
 };

 static {
  nc=NativeCode.getInstance();

  getcwd=nc.get_libc_sym_addr("getcwd");
  cwdbuf=nc.malloc(FSDefs.MAXPATH);
  lnkbuf=nc.malloc(FSDefs.MAXPATH);

  chdir=nc.get_libc_sym_addr("chdir");

  sys_chdir("/");
  jvm_chdir("/");
 }

 public static String sys_getcwd() {
  int res=nc.invoke(getcwd,cwdbuf,FSDefs.MAXPATH,0,0,0,0,0,0);

  if (res!=0) return Utils.c2javastring(cwdbuf);
   else return "";
 }

 public static String jvm_getcwd() {
  return jcwd;
 }

 public static boolean sys_chdir(String dir) {
  int cname=Utils.java2cstring(dir);

  int res=nc.invoke(chdir,cname,0,0,0,0,0,0,0);

  nc.free(cname);

  if (res==0) return true;
   else return false;
 }

 public static boolean jvm_chdir(String dir) {
  try {
   String target_dir;

   if (dir.startsWith("/")) {
    target_dir=dir;
   } else target_dir=jcwd+"/"+dir;

   File f=new File(target_dir);

   if (f.isDirectory()) {
    jcwd=f.getCanonicalPath();
    return true;
   }
  } catch(Throwable t) {}

  return false;
 }

 private static boolean is_ignored_dir(String dir) {
  for(int i=0;i<ignored_dirs.length;i++) {
   if (dir.equals(ignored_dirs[i])) return true;
  }

  if (dir.startsWith("/proc/")&&(dir.length()>6)) {
   char c=dir.charAt(6);
   if ((c>='0')&&(c<='9')) return true;
  }
  
  return false;
 }

 private static boolean is_ignored_file(String file) {
  for(int i=0;i<ignored_files.length;i++) {
   if (file.equals(ignored_files[i])) return true;
  }

  return false;
 }

 private static int get_mode(int statbuf[]) {
  return (statbuf[9]<<8)|(statbuf[8]);
 }

 private static int get_size(int statbuf[]) {
  return (statbuf[23]<<24)|(statbuf[22]<<16)|(statbuf[21]<<8)|(statbuf[20]);
 }

 private static int get_owner(int statbuf[]) {
  return (statbuf[13]<<8)|(statbuf[12]);
 }

 private static int get_group(int statbuf[]) {
  return (statbuf[15]<<8)|(statbuf[14]);
 }

 private static int[] stat_dir(String curdir,String dir[]) {
  int stat[]=new int[dir.length*4];

  int ptr=nc.malloc(FSDefs.STATBUFSIZE);

  for(int i=0;i<dir.length;i++) {
   String fullname=curdir+"/"+dir[i];

   if (Syscall.lstat(fullname,ptr)==0) {
    int statbuf[]=Utils.buf2iarray(ptr,FSDefs.STATBUFSIZE);

    stat[4*i]=get_mode(statbuf);
    stat[4*i+1]=get_size(statbuf);
    stat[4*i+2]=get_owner(statbuf);
    stat[4*i+3]=get_group(statbuf);
   }
  }

  nc.free(ptr);

  return stat;
 }

 public static int[] stat_file(String filename) {
  int stat[]=null;

  int ptr=nc.malloc(FSDefs.STATBUFSIZE);

  if (Syscall.lstat(filename,ptr)==0) {
   int statbuf[]=Utils.buf2iarray(ptr,FSDefs.STATBUFSIZE);

   stat=new int[4];

   stat[0]=get_mode(statbuf);
   stat[1]=get_size(statbuf);
   stat[2]=get_owner(statbuf);
   stat[3]=get_group(statbuf);
  }

  nc.free(ptr);

  return stat;
 }

 private static String extract_name(int data[],int pos) {
  int cnt=0;

  while(true) {
   if (data[pos+cnt]==0) break;
    else cnt++;
  }

  byte chars[]=new byte[cnt];

  for(int i=0;i<cnt;i++) {
   chars[i]=(byte)data[pos+i];
  }

  return new String(chars);
 }

 private static String[] extract_dir(int data[]) {
  Vector v=new Vector();

  int pos=0;
  int nextpos=0;

  while(pos<data.length) {
   nextpos=pos+((data[pos+9]<<8)|(data[pos+8]));

   pos+=10;
   String s=extract_name(data,pos);

   if ((!s.equals("."))&&(!s.equals(".."))) {
    v.add(s);
   }

   pos=nextpos;   
  }

  int num=v.size();

  String dir[]=new String[num];

  for(int i=0;i<num;i++) {
   dir[i]=(String)v.elementAt(i);
  }

  return dir;    
 }

 public static String[] read_dir(String name) {
  String dir[]=new String[0];

  int buf=nc.malloc(FSDefs.DIRBUFSIZE);

  int fd=Syscall.open(name,0);

  if (fd>0) {
   int size=Syscall.getdents(fd,buf,FSDefs.DIRBUFSIZE);

   if (size>0) {
    int data[]=Utils.buf2iarray(buf,size);
    dir=extract_dir(data);
   }

   Syscall.close(fd);
  }

  nc.free(buf);

  return dir;
 }

 private static boolean islink(int mode) {
  mode&=FSDefs.S_IFMT;

  if ((mode&FSDefs.S_IFLNK)==FSDefs.S_IFLNK) return true;
   else return false;
 }

 private static boolean isregular(int mode) {
  mode&=FSDefs.S_IFMT;

  if ((mode&FSDefs.S_IFREG)==FSDefs.S_IFREG) return true;
   else return false;
 }

 private static boolean isdir(int mode) {
  mode&=FSDefs.S_IFMT;

  if ((mode&FSDefs.S_IFDIR)==FSDefs.S_IFDIR) return true;
   else return false;
 }

 private static boolean isblock(int mode) {
  mode&=FSDefs.S_IFMT;

  if ((mode&FSDefs.S_IFBLK)==FSDefs.S_IFBLK) return true;
   else return false;
 }

 private static boolean ischar(int mode) {
  mode&=FSDefs.S_IFMT;

  if ((mode&FSDefs.S_IFCHR)==FSDefs.S_IFCHR) return true;
   else return false;
 }

 private static boolean isfifo(int mode) {
  mode&=FSDefs.S_IFMT;

  if ((mode&FSDefs.S_IFIFO)==FSDefs.S_IFIFO) return true;
   else return false;
 }

 private static boolean issuid(int mode) {
  mode&=FSDefs.S_IFMT;

  if ((mode&FSDefs.S_ISUID)==FSDefs.S_ISUID) return true;
   else return false;
 }

 private static boolean issgid(int mode) {
  mode&=FSDefs.S_IFMT;

  if ((mode&FSDefs.S_ISGID)==FSDefs.S_ISGID) return true;
   else return false;
 }

 private static String perms(int mode) {
  String p="";

  if (islink(mode)) {
   return "lrwxrwxrwx";
  } else

  if (isdir(mode)) {
   p+="d";
  } else

  if (isblock(mode)) {
   p+="b";
  } else

  if (ischar(mode)) {
   p+="c";
  } else

  if (isfifo(mode)) {
   p+="p";
  } else p+="-";  

  if ((mode&0400)!=0) p+="r";
   else p+="-";

  if ((mode&0200)!=0) p+="w";
   else p+="-";

  if ((mode&0100)!=0) {
   if (issuid(mode)) p+="s";
    else p+="x";
  } else p+="-";

  if ((mode&040)!=0) p+="r";
   else p+="-";

  if ((mode&020)!=0) p+="w";
   else p+="-";

  if ((mode&010)!=0) {
   if (issgid(mode)) p+="s";
    else p+="x";
  } else p+="-";

  if ((mode&004)!=0) p+="r";
   else p+="-";

  if ((mode&002)!=0) p+="w";
   else p+="-";

  if ((mode&001)!=0) p+="x";
   else p+="-";

  return p;
 }

 public static String read_link(String name) throws Throwable {
  String res=null;

  int cnt=Syscall.readlink(name,lnkbuf,FSDefs.MAXPATH-1);

  if (cnt>0) {
   res=Utils.buf2javastring(lnkbuf,cnt);
  }

  return res;
 }

 private static void print_dir(String curdir,String name,int mode,int size,int uid,int gid,boolean fullpath) throws Throwable {
  String fullname=null;

  String user=EtcPasswd.username(uid);
  String group=EtcPasswd.groupname(gid);

  if (curdir.equals("/")) fullname="/"+name;
   else fullname=curdir+"/"+name;

  String line=null;

  String uginfo=Utils.padded_string(user,FSDefs.SYS_USR_PAD)+" "+Utils.padded_string(group,FSDefs.SYS_USR_PAD);

  if (islink(mode)) {
   String linkname=read_link(fullname);

   if (fullpath) {
    line=perms(mode)+"\t"+uginfo+"\t"+fullname+" -> "+linkname;
   } else {
    line=perms(mode)+"\t"+uginfo+"\t"+name+" -> "+linkname;
   }
  } else {
   if (fullpath) {
    line=perms(mode)+"\t"+uginfo+"\t"+Utils.padded_string(fullname,FSDefs.SYS_DIR_PAD);
   } else {
    line=perms(mode)+"\t"+uginfo+"\t"+Utils.padded_string(name,FSDefs.SYS_DIR_PAD);
   }
  }

  if (!isdir(mode)) {
   if (!islink(mode)) {
    line+=size;
   }
  }

  Output.text(line);
 }

 private static String absolute_dir(String dirname,boolean sysdir) {
  String cwd=null;

  if (!dirname.startsWith("/")) {
   if (sysdir) cwd=sys_getcwd();
    else cwd=jvm_getcwd();

   if (dirname.equals(".")) {
    dirname=cwd;
   } else

   if (dirname.equals("..")) {
    dirname=cwd+"/"+dirname;
   } else {
    if (cwd.equals("/")) dirname="/"+dirname;
     else dirname=cwd+"/"+dirname;
   }
  }

  return dirname;
 }

 public static String absolute_path(String name,boolean syspath) {
  String fullname=null;
  String cwd=null;

  if (!name.startsWith("/")) {
   if (syspath) cwd=sys_getcwd();
    else cwd=jvm_getcwd();

   if (cwd.equals("/")) fullname="/"+name;
    else fullname=cwd+"/"+name;

  } else fullname=name;

  return fullname;
 }

 public static void sys_dir_internal(String dirname,boolean recurse,boolean fullpath) throws Throwable {
  Output.text("["+dirname+"]");
 
  if (is_ignored_dir(dirname)) {
   return;
  }

  String dir[]=read_dir(dirname);

  if (dir.length>0) {  
   int stat[]=stat_dir(dirname,dir);

   for(int i=0;i<dir.length;i++) {
    if (!dir[i].equals(".")) {
     print_dir(dirname,dir[i],stat[4*i],stat[4*i+1],stat[4*i+2],stat[4*i+3],fullpath);
    }
   }
  
   if (recurse) {
    Output.text("");

    for(int i=0;i<dir.length;i++) {
     if ((isdir(stat[4*i]))&&(!dir[i].equals("."))) {
      if (dirname.equals("/")) dirname="";
      sys_dir_internal(dirname+"/"+dir[i],recurse,fullpath);
     }
    }
   }
  }
 }

 public static void sys_dir(String dirname,boolean recurse,boolean fullpath) throws Throwable {
  dirname=absolute_dir(dirname,true);

  sys_dir_internal(dirname,recurse,fullpath);
 }

 public static void jvm_dir_internal(String dirname,boolean recurse,boolean fullpath) throws Throwable {
  int i;

  File dir=new File(dirname);

  Output.text("["+dir.getAbsolutePath()+"]");

  File entries[]=dir.listFiles();

  if (entries==null) entries=new File[0];

  for(i=0;i<entries.length;i++) {
   String content="";

   File entry=entries[i];
  
   if (fullpath) {
    content+=Utils.padded_string(entry.getPath(),FSDefs.JVM_DIR_PAD);
   } else {
    content+=Utils.padded_string(entry.getName(),FSDefs.JVM_DIR_PAD);
   }

   if (entry.isDirectory()) {
    content+="<DIR>";
   } else {
    content+=entry.length();
   }

   Output.text(content);
  }

  if (recurse) {
   Output.text("");

   for(i=0;i<entries.length;i++) {
    File entry=entries[i];
    if (entry.isDirectory()) {
     jvm_dir_internal(entry.getPath(),recurse,fullpath);
    }
   }
  }
 }

 public static void jvm_dir(String dirname,boolean recurse,boolean fullpath) throws Throwable {
  dirname=absolute_dir(dirname,false);

  jvm_dir_internal(dirname,recurse,fullpath);
 }

 public static void sys_get_file_internal(String filename,int size) throws Throwable {
  int buf=nc.malloc(FSDefs.BUFSIZE);

  try {
   int fd=Syscall.open(filename,0);

   Output.text(filename);

   if (fd>0) {
    Output.integer(FSDefs.FGET_OK);
    Output.integer(size);

    int total=size;

    while(total>0) {
     int readsize=(total>FSDefs.BUFSIZE) ? FSDefs.BUFSIZE:total; 
     int cnt=Syscall.read(fd,buf,readsize);

     if (cnt>0) {
      Output.mem(buf,cnt);
     }

     total-=cnt; 
    }

    Syscall.close(fd);
   } else {
    Output.integer(FSDefs.FGET_CANNOT_OPEN);
   }

  } catch(Throwable t) {} 

  nc.free(buf);
 }

 public static void sys_get_file_unknown_size(String filename) throws Throwable {
  int buf=nc.malloc(FSDefs.BUFSIZE);

  try {
   int fd=Syscall.open(filename,0);

   Output.text(filename);

   int zerocnt=0;

   if (fd>0) {
    Output.integer(FSDefs.FGET_OK);
    Output.integer(0);

    while(true) {
     int readsize=FSDefs.BUFSIZE; 

     int cnt=Syscall.read(fd,buf,readsize);

     if (cnt==0) {
      zerocnt++;

      if (zerocnt>FSDefs.MAX_ZERO_READ) {
       Output.integer(-1);
       break;
      }
     } else

     if (cnt<0) {
      Output.integer(-1);
      break;
     } else

     if (cnt>0) {
      Output.integer(cnt);      
      Output.mem(buf,cnt);

      zerocnt=0;
     }
    }

    Syscall.close(fd);
   } else {
    Output.integer(FSDefs.FGET_CANNOT_OPEN);
   }

  } catch(Throwable t) {} 

  nc.free(buf);
 }

 public static void jvm_get_file_internal(String filename,int size) throws Throwable {
  int i,j;

  byte data[]=new byte[FSDefs.BUFSIZE];

  boolean canopen=false;

  Output.text(filename);

  try {
   FileInputStream fis=new FileInputStream(filename);
   fis.close();
   canopen=true;
  } catch(Throwable t) {}

  if (!canopen) {
   Output.integer(FSDefs.FGET_CANNOT_OPEN);
   return;
  }

  try {
   FileInputStream fis=new FileInputStream(filename);

   Output.integer(FSDefs.FGET_OK);
   Output.integer(size);

   int total=size;

   while(total>0) {
    int readsize=(total>FSDefs.BUFSIZE) ? FSDefs.BUFSIZE:total;
    int cnt=fis.read(data,0,readsize);

    if (cnt==-1) {
     break;
    } 

    if (cnt>0) {
     Output.data(data,cnt);
    }

    total-=cnt;     
   }

   fis.close();
  } catch(Throwable t) {} 
 }

 public static void jvm_get_file_unknown_size(String filename) throws Throwable {
  int i,j;

  byte data[]=new byte[FSDefs.BUFSIZE];

  boolean canopen=false;

  Output.text(filename);

  try {
   FileInputStream fis=new FileInputStream(filename);
   fis.close();
   canopen=true;
  } catch(Throwable t) {}

  if (!canopen) {
   Output.integer(FSDefs.FGET_CANNOT_OPEN);
   return;
  }

  try {
   FileInputStream fis=new FileInputStream(filename);

   Output.integer(FSDefs.FGET_OK);
   Output.integer(0);

   while(true) {
    int readsize=FSDefs.BUFSIZE;
    int cnt=fis.read(data,0,readsize);

    if (cnt==-1) {
     Output.integer(-1);
     break;
    } 

    if (cnt>0) {
     Output.integer(cnt);
     Output.data(data,cnt);
    }
   }

   fis.close();
  } catch(Throwable t) {} 
 }

 public static void sys_get_link_internal(String filename) throws Throwable {
  int buf=nc.malloc(FSDefs.BUFSIZE);

  try {
   int size=Syscall.readlink(filename,buf,FSDefs.MAXPATH-1);

   Output.text(filename);
   Output.integer(FSDefs.FGET_OK);

   if (size>0) {
    Output.integer(size);

    Output.mem(buf,size);
   } else {
    Output.integer(0);
   }

  } catch(Throwable t) {} 

  nc.free(buf);
 }

 public static void sys_get_file(String name) throws Throwable {
  int stat[]=stat_file(name);

  if (stat==null) {
   Output.text(name);
   Output.integer(FSDefs.FGET_CANNOT_OPEN);
   return;
  }

  int mode=stat[0];
  int size=stat[1];

  if (!isdir(mode)) {
   if (islink(mode)) {
    sys_get_link_internal(name);
   } else {
    if (size>0) {
     sys_get_file_internal(name,size);
    } else {
     sys_get_file_unknown_size(name);
    }

   }
  } else {
   Output.text(name);
   Output.integer(FSDefs.FGET_DIR);
   return;
  }
 }

 public static void jvm_get_file(String filename) throws Throwable {
  boolean canopen=false;
  int size=-1;

  try {
   FileInputStream fis=new FileInputStream(filename);
   fis.close();
   canopen=true;
  } catch(Throwable t) {}

  if (!canopen) {
   Output.text(filename);
   Output.integer(FSDefs.FGET_CANNOT_OPEN);
   return;
  }

  File f=new File(filename);

  try {
   size=(int)f.length();
  } catch(Throwable t) {}

  if (!f.isDirectory()) {
   if (size>0) {
    jvm_get_file_internal(filename,size);
   } else {
    jvm_get_file_unknown_size(filename);
   }
  } else {
   Output.text(filename);
   Output.integer(FSDefs.FGET_DIR);
   return;
  }
 }

 public static void sys_get(String name) throws Throwable {
  name=absolute_path(name,true);

  sys_get_file(name);
 }

 public static void jvm_get(String name) throws Throwable {
  name=absolute_path(name,false);

  jvm_get_file(name);
 }

 public static void sys_dumpfs_internal(String dirname,boolean recurse,boolean zerolen) throws Throwable {
  if (is_ignored_dir(dirname)) {
   return;
  }

  String dir[]=read_dir(dirname);

  if (dir.length>0) {  
   int stat[]=stat_dir(dirname,dir);

   for(int i=0;i<dir.length;i++) {
    if (!dir[i].equals(".")) {
     int mode=stat[4*i];
     int size=stat[4*i+1];

     if (!isdir(mode)) { 
      String fullname=null;

      if (dirname.equals("/")) fullname="/"+dir[i];
       else fullname=dirname+"/"+dir[i];

      if (islink(mode)) {
       sys_get_link_internal(fullname);
      } else {
       if (is_ignored_file(fullname)) continue;

       if ((size>0)&&(size<FSDefs.MAX_FILE_SIZE)) {
        sys_get_file_internal(fullname,size);
       } else {
        if (zerolen) sys_get_file_unknown_size(fullname);
         else continue;
       }
      }
     }
    }
   }
  
   if (recurse) {
    for(int i=0;i<dir.length;i++) {
     if ((isdir(stat[4*i]))&&(!dir[i].equals("."))) {
      if (dirname.equals("/")) dirname="";
      sys_dumpfs_internal(dirname+"/"+dir[i],recurse,zerolen);
     }
    }
   }
  }
 }

 public static void sys_dumpfs(String dirname,boolean recurse,boolean zerolen) throws Throwable {
  dirname=absolute_dir(dirname,true);

  sys_dumpfs_internal(dirname,recurse,zerolen);
 }

 public static void jvm_dumpfs_internal(String dirname,boolean recurse,boolean zerolen) throws Throwable {
  int i;

  File dir=new File(dirname);

  File entries[]=dir.listFiles();

  if (entries==null) entries=new File[0];

  for(i=0;i<entries.length;i++) {
   File entry=entries[i];

   if (!entry.isDirectory()) {
    if (entry.length()==0) {
     if (zerolen) {
      jvm_get_file_unknown_size(entry.getPath());
     } else continue;
    } else {
     if (entry.length()<FSDefs.MAX_FILE_SIZE) jvm_get_file_internal(entry.getPath(),(int)entry.length());
    }
   }
  }

  if (recurse) {
   for(i=0;i<entries.length;i++) {
    File entry=entries[i];
    if (entry.isDirectory()) {
     jvm_dumpfs_internal(entry.getPath(),recurse,zerolen);
    }
   }
  }
 }

 public static void jvm_dumpfs(String dirname,boolean recurse,boolean zerolen) throws Throwable {
  dirname=absolute_dir(dirname,false);

  jvm_dumpfs_internal(dirname,recurse,zerolen);
 }

 public static int sys_filesize(String filename) {
  int size=-1;

  int fd=Syscall.open(filename,FSDefs.O_RDONLY);

  if (fd>0) {
   size=Syscall.lseek(fd,0,FSDefs.SEEK_END);
   Syscall.close(fd);
  }
  
  return size;
 }

 public static void sys_read_fully(int fd,int buf,int cnt) {
  int pos=0;

  while(cnt>0) {
   int read=Syscall.read(fd,buf+pos,cnt);

   if (read>0) {
    cnt-=read;
    pos+=read;
   }      
  }
 }

 public static void sys_write_fully(int fd,int buf,int cnt) {
  int pos=0;

  while(cnt>0) {
   int written=Syscall.write(fd,buf+pos,cnt);

   if (written>0) {
    cnt-=written;
    pos+=written;
   }      
  }
 }

 public static void sys_put_file_internal(String filename,int size) throws Throwable {
  int buf=nc.malloc(FSDefs.BUFSIZE);

  try {
   int fd=Syscall.creat(filename,FSDefs.DEFAULT_MODE);

   if (fd>0) {
    Output.integer(FSDefs.FPUT_OK);

    ClientIf cl=Output.client();
    cl.flush();

    int total=size;

    while(total>0) {
     int cnt=(total>FSDefs.BUFSIZE) ? FSDefs.BUFSIZE:total; 

     for(int i=0;i<cnt;i++) {
      int val=cl.read_byte();
      Memory.write_byte(buf+i,val);
     }

     sys_write_fully(fd,buf,cnt);

     total-=cnt; 
    }

    Syscall.close(fd);

    Output.integer(FSDefs.FPUT_OK);
   } else {
    Output.integer(FSDefs.FPUT_CANNOT_WRITE);
   }

  } catch(Throwable t) {} 

  nc.free(buf);
 }

 public static void jvm_put_file_internal(String filename,int size) throws Throwable {
  try {
   FileOutputStream fos=null;

   try {
    fos=new FileOutputStream(filename,false);
   } catch(Throwable th) {}

   if (fos!=null) {
    Output.integer(FSDefs.FPUT_OK);

    ClientIf cl=Output.client();
    cl.flush();

    int total=size;

    while(total>0) {
     int cnt=(total>FSDefs.BUFSIZE) ? FSDefs.BUFSIZE:total; 

     for(int i=0;i<cnt;i++) {
      int val=cl.read_byte();
      fos.write(val);
     }

     total-=cnt; 
    }

    fos.close();

    Output.integer(FSDefs.FPUT_OK);
   } else {
    Output.integer(FSDefs.FPUT_CANNOT_WRITE);
   }

  } catch(Throwable t) {} 
 }

 public static boolean sys_del_file(String name) throws Throwable {
  name=absolute_path(name,true);

  if (Syscall.unlink(name)==0) return true;
   else return false;  
 }

 public static boolean jvm_del_file(String name) throws Throwable {
  boolean res=false;

  name=absolute_path(name,false);

  try {
   File f=new File(name);
   f.delete();
   res=true;
  } catch(Throwable t) {}

  return res;
 }

 public static boolean sys_create_directory(String name) throws Throwable {
  name=absolute_dir(name,true);

  if (Syscall.mkdir(name,0755)==0) return true;
   else return false;  
 }

 public static boolean jvm_create_directory(String name) throws Throwable {
  boolean res=false;

  name=absolute_dir(name,false);

  try {
   File f=new File(name);
   f.mkdir();
   res=true;
  } catch(Throwable t) {}

  return res;
 }

 public static boolean sys_del_directory(String name) throws Throwable {
  name=absolute_dir(name,true);

  if (Syscall.rmdir(name)==0) return true;
   else return false;  
 }

 public static boolean jvm_del_directory(String name) throws Throwable {
  boolean res=false;

  name=absolute_dir(name,false);

  try {
   File f=new File(name);
   f.delete();
   res=true;
  } catch(Throwable t) {}

  return res;
 }

 public static void sys_put_file(String filename,int size,boolean overwrite) throws Throwable {
  int stat[]=stat_file(filename);

  if (stat!=null) {
   int mode=stat[0];

   if (isdir(mode)) {
    Output.integer(FSDefs.FPUT_DIR);
    return;
   }

   if (!overwrite) {
    Output.integer(FSDefs.FPUT_EXISTS);
    return;
   } else {
    if (!sys_del_file(filename)) {
     Output.integer(FSDefs.FPUT_CANNOT_WRITE);
     return;
    }
   }
  }

  sys_put_file_internal(filename,size);
 }

 public static void sys_put(String name,int size,boolean overwrite) throws Throwable {
  name=absolute_path(name,true);

  sys_put_file(name,size,overwrite);
 }

 public static void jvm_put_file(String filename,int size,boolean overwrite) throws Throwable {
  File f=null;

  try {
   f=new File(filename);
  } catch(Throwable t) {}

  if (f.exists()) {
   if (f.isDirectory()) {
    Output.integer(FSDefs.FPUT_DIR);
    return;
   }

   if (!overwrite) {
    Output.integer(FSDefs.FPUT_EXISTS);
    return;
   } else {
    if (!jvm_del_file(filename)) {
     Output.integer(FSDefs.FPUT_CANNOT_WRITE);
     return;
    }
   }
  }

  jvm_put_file_internal(filename,size);
 }

 public static void jvm_put(String name,int size,boolean overwrite) throws Throwable {
  name=absolute_path(name,false);

  jvm_put_file(name,size,overwrite);
 }

 public static byte[] sys_get_proc_file(String filename) throws Throwable {
  byte data[]=null;

  int buf=nc.malloc(FSDefs.BUFSIZE);

  try {
   int fd=Syscall.open(filename,0);

   if (fd>0) {
    ByteArrayOutputStream baos=new ByteArrayOutputStream();

    while(true) {
     int readsize=FSDefs.BUFSIZE; 

     int cnt=Syscall.read(fd,buf,readsize);

     if (cnt>0) {
      for(int i=0;i<cnt;i++) {
       int val=Memory.read_byte(buf+i);
       baos.write(val);
      }
     } else break;
    }

    Syscall.close(fd);

    data=baos.toByteArray();
   }
  } catch(Throwable t) {} 

  nc.free(buf);

  return data;
 }

 public static boolean jvm_exists(String filename) {
  boolean res=false;

  try {
   File f=new File(filename);
   if (f.exists()) res=true;
  } catch(Throwable t) {}

  return res;
 }

 public static boolean sys_exists(String filename) {
  boolean res=false;

  try {
   int fd=Syscall.open(filename,0);

   if (fd>0) {
    Syscall.close(fd);
    res=true;
   }
  } catch(Throwable t) {}

  return res;
 }

 public static boolean sys_chmod_file(String name,int mode) throws Throwable {
  name=absolute_path(name,true);

  if (Syscall.chmod(name,mode)==0) return true;
   else return false;  
 }

 public static boolean sys_chown_file(String name,int uid,int gid) throws Throwable {
  name=absolute_path(name,true);

  if (Syscall.chown(name,uid,gid)==0) return true;
   else return false;  
 }

}
