/*
  ns.c
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif

#include <stdio.h>
#include <limits.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/param.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/unistd.h>
#include "iiimcfint.h"
#include <EIMIL.h>
#include <locale.h>
#include <langinfo.h>

#include <sys/errno.h>
extern int errno;

#include <dirent.h>
#include "csconv.h"
#define CSC_OPEN_LOCALE "csconv_open_locale"
#define CSC_OPEN        "csconv_open"
#define CSC_CONV        "csconv"
#define CSC_CLOSE       "csconv_close"

typedef csconv_t        (* csc_open_locale_t)(const char *, const char *, const char *);
typedef csconv_t        (* csc_open_t)(const char *, const char *);
typedef size_t          (* csc_conv_t)(csconv_t, const char **, size_t *, char **, size_t *);
typedef int             (* csc_close_t)(csconv_t);

static void *                   csc_handle;
static csc_open_locale_t        csc_open_locale;
static csc_open_t               csc_open;
static csc_conv_t               csc_conv;
static csc_close_t              csc_close;

static char *current_locale = 0;
static Bool skip_native_to_utf8_conv = False;

static void
dlopen_csconv()
{
    csc_handle = dlopen(CSC_PATH, RTLD_LAZY);
    if (NULL == csc_handle) {
        csc_handle = (void *)(-1);
        return;
    }

    csc_open_locale = (csc_open_locale_t)dlsym(csc_handle, CSC_OPEN_LOCALE);
    csc_open = (csc_open_t)dlsym(csc_handle, CSC_OPEN);
    csc_conv = (csc_conv_t)dlsym(csc_handle, CSC_CONV);
    csc_close = (csc_close_t)dlsym(csc_handle, CSC_CLOSE);

    if ((NULL == csc_open_locale) || (NULL == csc_open) ||
	(NULL == csc_conv) || (NULL == csc_close)) {
        dlclose(csc_handle);
        csc_handle = (void *)(-1);
        return;
    }
}

int
iiimcf_convert_NativeToUTF8(
    char *encoding, 
    char *from_buf,
    size_t from_left,
    char **to_buf, 
    size_t *to_left
)
{
    char *dst;
    size_t ret = 0;
    static csconv_t csconv_cd = NULL;

    if (current_locale == NULL) {
	current_locale = (char*)strdup(setlocale(LC_CTYPE, NULL));
    }

    do {
	if (((void *)(-1) == csc_handle) || ((csconv_t)(-1) == csconv_cd)) {
	    continue;
	}
	if (NULL == csc_handle) {
	    dlopen_csconv();
	    if ((void *)(-1) == csc_handle) {
		continue;
	    }
	}
	if (NULL == csconv_cd) {
	    csconv_cd = (csc_open_locale)(current_locale, "UTF-8", encoding);
	    if ((csconv_t)(-1) == csconv_cd) {
		continue;
	    }
	}

	dst = *((char **)to_buf);

	ret = csc_conv(csconv_cd,
		       (const char **)&from_buf, &from_left,
		       &dst, to_left);
	return ret;
    } while (0);

    return ret;
}

IIIMF_status
iiimcf_perform_file_operation(
    IIIMCF_handle_rec *ph,
    IIIMP_message *pmes        
)
{
    IIIMP_file_operation_v *pfop = &pmes->v.file_operation;

    ASSERT(pmes->opcode == IM_FILE_OPERATION);

    switch(pfop->type) {
      case IIIMP_FILE_OPERATION_TYPE_OPEN:
       return iiimcf_open(ph, (IIIMP_open *)pfop->value);

      case IIIMP_FILE_OPERATION_TYPE_READ:
       return iiimcf_read(ph, (IIIMP_read *)pfop->value);

      case IIIMP_FILE_OPERATION_TYPE_WRITE:
       return iiimcf_write(ph, (IIIMP_write *)pfop->value);

      case IIIMP_FILE_OPERATION_TYPE_CLOSE:
       return iiimcf_close(ph, (IIIMP_close *)pfop->value);

      case IIIMP_FILE_OPERATION_TYPE_OPENDIR:
       return iiimcf_opendir(ph, (IIIMP_opendir *)pfop->value);

      case IIIMP_FILE_OPERATION_TYPE_CLOSEDIR:
       return iiimcf_closedir(ph, (IIIMP_closedir *)pfop->value);

      case IIIMP_FILE_OPERATION_TYPE_MKDIR:
       return iiimcf_mkdir(ph, (IIIMP_mkdir *)pfop->value);

      case IIIMP_FILE_OPERATION_TYPE_RMDIR:
       return iiimcf_rmdir(ph, (IIIMP_rmdir *)pfop->value);

      case IIIMP_FILE_OPERATION_TYPE_SYMLINK:
       return iiimcf_symlink(ph, (IIIMP_symlink *)pfop->value);

      case IIIMP_FILE_OPERATION_TYPE_STAT:
       return iiimcf_stat(ph, (IIIMP_stat *)pfop->value);

      case IIIMP_FILE_OPERATION_TYPE_LSTAT:
       return iiimcf_lstat(ph, (IIIMP_lstat *)pfop->value);

      case IIIMP_FILE_OPERATION_TYPE_FSTAT:
       return iiimcf_fstat(ph, (IIIMP_fstat *)pfop->value);

      case IIIMP_FILE_OPERATION_TYPE_CREAT:
       return iiimcf_creat(ph, (IIIMP_creat *)pfop->value);

      case IIIMP_FILE_OPERATION_TYPE_LSEEK:
       return iiimcf_lseek(ph, (IIIMP_lseek *)pfop->value);

      case IIIMP_FILE_OPERATION_TYPE_UNLINK:
       return iiimcf_unlink(ph, (IIIMP_unlink *)pfop->value);

      case IIIMP_FILE_OPERATION_TYPE_RENAME:
       return iiimcf_rename(ph, (IIIMP_rename *)pfop->value);

      case IIIMP_FILE_OPERATION_TYPE_FCNTL:
       return iiimcf_fcntl(ph, (IIIMP_fcntl *)pfop->value);

      case IIIMP_FILE_OPERATION_TYPE_TRUNCATE:
       return iiimcf_truncate(ph, (IIIMP_truncate *)pfop->value);

      case IIIMP_FILE_OPERATION_TYPE_FTRUNCATE:
       return iiimcf_ftruncate(ph, (IIIMP_ftruncate *)pfop->value);

    }

    return IIIMF_STATUS_FAIL;
}

IIIMF_status
iiimcf_open(
    IIIMCF_handle_rec *ph,
    IIIMP_open *po        
)
{
    IIIMF_status st_r = IIIMF_STATUS_SUCCESS;
    IIIMP_open_reply *por;
    IIIMP_message *preply;
    int ns_count;
    char path[PATH_MAX];
    int i;

    errno = 0;

    ns_count = ph->num_of_ns;

    if (!ns_count) {
	ph->pns = (IIIMCF_ns *) calloc(10, sizeof(IIIMCF_ns));
    } else if (ns_count > 10) {
	ph->pns = (IIIMCF_ns *) realloc((IIIMCF_ns *)ph->pns, (ns_count + 1) * sizeof(IIIMCF_ns));
    }
    if (!ph->pns) return IIIMF_STATUS_MALLOC;

    ph->pns[ns_count].ns_id = po->ns_id;

    ph->pns[ns_count].filename = (char *) calloc((po->filename->len + 1), sizeof(char));
    for(i=0; i<po->filename->len; i++) {
	ph->pns[ns_count].filename[i] = po->filename->ptr[i];
    }
    ph->pns[ns_count].filename[i] = '\0';
    (void) memset((char *)path, '\0', sizeof(path));
    if (strstr(ph->pns[ns_count].filename, ".iiim")) {
	snprintf(path, sizeof(path), "%s/%s",ph->penv->home_dir, ph->pns[ns_count].filename);
    } else {
	snprintf(path, sizeof(path), "%s",ph->pns[ns_count].filename);
    }
    check_pathname(path);

    ph->pns[ns_count].nsc_fd = open(path, po->flags);
    if (ph->pns[ns_count].nsc_fd < 0) {
        por = iiimp_open_reply_new(ph->data_s, ph->pns[ns_count].nsc_fd, errno);
	preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_OPEN_REPLY, por); 
	st_r = iiimcf_send_message(ph, preply, 1);
	return st_r; 
    }
    ph->num_of_ns = ns_count + 1;

    por = iiimp_open_reply_new(ph->data_s, po->ns_id, errno);
    preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_OPEN_REPLY, por); 
    st_r = iiimcf_send_message(ph, preply, 1);

    return st_r;
}

IIIMF_status
iiimcf_read(
    IIIMCF_handle_rec *ph,
    IIIMP_read *pr        
)
{
    IIIMP_read_reply *prr;
    IIIMP_message *preply;
    int i;
    void *ptr;
    int nread = -1;

    errno = 0;

    for (i=0; i<ph->num_of_ns; i++) {
	if (ph->pns[i].ns_id == pr->ns_id) {
	    ptr = (char *) calloc(pr->size + 1, sizeof(char));
	    nread = read(ph->pns[i].nsc_fd, ptr, pr->size);
            prr = iiimp_read_reply_new(ph->data_s, pr->ns_id, nread, errno, ptr); 
	    preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_READ_REPLY, prr);
	    return iiimcf_send_message(ph, preply, 1);
	}
    } 
    return IIIMF_STATUS_FAIL;
}

IIIMF_status
iiimcf_write(
    IIIMCF_handle_rec *ph,
    IIIMP_write *pw        
)
{
    int i;
    IIIMP_write_reply *pwr;
    IIIMP_message *preply;
    errno = 0;
    int nwrite = -1;

    for (i=0; i<ph->num_of_ns; i++) {
	if (ph->pns[i].ns_id == pw->ns_id) {
	    nwrite = write(ph->pns[i].nsc_fd, pw->object, pw->size);
	    pwr = iiimp_write_reply_new(ph->data_s, pw->ns_id, nwrite, errno); 
            preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_WRITE_REPLY, pwr);
	    return iiimcf_send_message(ph, preply, 1);
	}
    } 
    return IIIMF_STATUS_FAIL;
}

IIIMF_status
iiimcf_close(
    IIIMCF_handle_rec *ph,
    IIIMP_close *pc        
)
{
    int i, ret;
    IIIMP_close_reply *iclr;
    IIIMP_message *preply;
    errno = 0;

    for (i=0; i<ph->num_of_ns; i++) {
	if (ph->pns[i].ns_id == pc->ns_id) {
	    if ((ret = close(ph->pns[i].nsc_fd)) < 0) {
                iclr = iiimp_close_reply_new(ph->data_s, ret, errno);
                preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_CLOSE_REPLY, iclr);
		return iiimcf_send_message(ph, preply, 1);
            }
	}
    } 
    iclr = iiimp_close_reply_new(ph->data_s, pc->ns_id, errno);
    preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_CLOSE_REPLY, iclr);
    return iiimcf_send_message(ph, preply, 1);
}

IIIMF_status
iiimcf_opendir(
    IIIMCF_handle_rec *ph,
    IIIMP_opendir *pod
)
{
    int i, ns_count, nitems, data_len;
    IIIMP_message *preply;
    IIIMP_opendir_reply *podr;
    char path[PATH_MAX];
    char buf[PATH_MAX];
    struct dirent *entry;
    IIIMP_utf8string *pstart, *pcurr, *pstr;
    char *to_utf8;
    size_t to_len;
    char *encoding;
    errno = 0;

    pstart = pcurr = pstr = NULL;

    ns_count = ph->num_of_ns;

    if (!ns_count) {
        ph->pns = (IIIMCF_ns *) calloc(10, sizeof(IIIMCF_ns));
    } else if (ns_count > 10) {
        ph->pns = (IIIMCF_ns *) realloc((IIIMCF_ns *)ph->pns, (ns_count + 1) * sizeof(IIIMCF_ns));
    }
    if (!ph->pns) return IIIMF_STATUS_MALLOC;

    ph->pns[ns_count].ns_id = pod->ns_id;

    ph->pns[ns_count].dirname = (char *) calloc((pod->dirname->len + 1), sizeof(char));
    for (i=0; i<pod->dirname->len; i++) {
        ph->pns[ns_count].dirname[i] = pod->dirname->ptr[i];
    }
    ph->pns[ns_count].dirname[i] = '\0';
    (void) memset((char *)path, '\0', sizeof(path));
    if (strstr(ph->pns[ns_count].dirname, ".iiim")) {
	snprintf(path, sizeof(path), "%s/%s",ph->penv->home_dir, ph->pns[ns_count].dirname);
    } else {
	snprintf(path, sizeof(path), "%s",ph->pns[ns_count].dirname);
    }
    check_pathname(path);

    ph->pns[ns_count].nsc_dirp = (DIR *)NULL;
    ph->pns[ns_count].nsc_dirp = opendir(path);
    if (ph->pns[ns_count].nsc_dirp == NULL) {
	podr = iiimp_opendir_reply_new(ph->data_s, 0, errno, 0, NULL);
	preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_OPENDIR_REPLY, podr);
	return iiimcf_send_message(ph, preply, 1);
    }   
    i = 0;
    if (current_locale == NULL) {
	current_locale = (char *)strdup(setlocale(LC_CTYPE, NULL));
    }
    encoding = nl_langinfo(CODESET);
    if (!strcasecmp(encoding, "UTF-8") || !strcasecmp(encoding, "UTF8")) {
	skip_native_to_utf8_conv = True;
    }

    while ((entry = readdir(ph->pns[ns_count].nsc_dirp)) != NULL) {
	if (skip_native_to_utf8_conv) {
	    (void) memset((char *)buf, '\0', sizeof(buf));
	    snprintf(buf, sizeof(buf), "%s",entry->d_name);
	    pstr = iiimp_utf8string_new(ph->data_s, entry->d_reclen, buf);
	}else {
	    to_utf8 = (char *)calloc(1, sizeof(buf));
	    to_len = PATH_MAX;
	    (void) memset((char *)buf, '\0', sizeof(buf));
	    snprintf(buf, sizeof(buf), "%s",entry->d_name);
	    iiimcf_convert_NativeToUTF8(encoding, buf, entry->d_reclen, &to_utf8, &to_len);
	    data_len = PATH_MAX - to_len;
	    pstr = iiimp_utf8string_new(ph->data_s, data_len, to_utf8);
	    free(to_utf8);
	}
	if (!pstr) {
	    podr = iiimp_opendir_reply_new(ph->data_s, pod->ns_id, errno, 0, NULL);
	    preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_OPENDIR_REPLY, podr);
	    return iiimcf_send_message(ph, preply, 1);
	}
	if (!pstart) pstart = pstr;
	else pcurr->next = pstr;
	pcurr = pstr;
	i++;
    }
    nitems = i;
    podr = iiimp_opendir_reply_new(ph->data_s, pod->ns_id, errno, nitems, pstart);
    preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_OPENDIR_REPLY, podr);
    return iiimcf_send_message(ph, preply, 1);
}

IIIMF_status
iiimcf_closedir(
    IIIMCF_handle_rec *ph,
    IIIMP_closedir *pcd
)
{
    int i, ret;
    IIIMP_message *preply;
    IIIMP_closedir_reply *pcdr;
    errno = 0;

    for (i=0; i<ph->num_of_ns; i++) {
        if (ph->pns[i].ns_id == pcd->ns_id) {
            if ((ret = closedir(ph->pns[i].nsc_dirp)) < 0) {
                pcdr = iiimp_closedir_reply_new(ph->data_s, ret, errno);
                preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_CLOSEDIR_REPLY, pcdr);
		return iiimcf_send_message(ph, preply, 1);
            }
        }
    }
    pcdr = iiimp_closedir_reply_new(ph->data_s, pcd->ns_id, errno);
    preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_CLOSEDIR_REPLY, pcdr);
    return iiimcf_send_message(ph, preply, 1);
}

IIIMF_status
iiimcf_mkdir(
    IIIMCF_handle_rec *ph,
    IIIMP_mkdir *pm        
)
{
    int i, ret;
    IIIMP_message *preply;
    IIIMP_mkdir_reply *pmr;
    char path[PATH_MAX];
    char *dirname;
    errno = 0;

    dirname = (char *)calloc((pm->path->len + 1), sizeof(char));
    for (i=0; i<pm->path->len; i++) {
        dirname[i] = pm->path->ptr[i];
    }
    dirname[i] = '\0';
    (void) memset((char *)path, '\0', sizeof(path));
    if (strstr(dirname, ".iiim")) {
	snprintf(path, sizeof(path), "%s/%s",ph->penv->home_dir, dirname);
    } else {
	snprintf(path, sizeof(path), "%s",dirname);
    }
    check_pathname(path);
    free(dirname);

    if ((ret = mkdir(path, pm->mode)) < 0) {
	pmr = iiimp_mkdir_reply_new(ph->data_s, ret, errno); 
        preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_MKDIR_REPLY, pmr);
	return iiimcf_send_message(ph, preply, 1);
    }
    pmr = iiimp_mkdir_reply_new(ph->data_s, pm->ns_id, errno); 
    preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_MKDIR_REPLY, pmr);
    return iiimcf_send_message(ph, preply, 1);
}

IIIMF_status
iiimcf_rmdir(
    IIIMCF_handle_rec *ph,
    IIIMP_rmdir *pr        
)
{
    int i, ret;
    IIIMP_message *preply;
    IIIMP_rmdir_reply *prr;
    char path[PATH_MAX];
    char *dirname;
    errno = 0;

    dirname = (char *)calloc((pr->path->len + 1), sizeof(char));
    for (i=0; i<pr->path->len; i++) {
        dirname[i] = pr->path->ptr[i];
    }
    dirname[i] = '\0';
    (void) memset((char *)path, '\0', sizeof(path));
    if (strstr(dirname, ".iiim")) {
	snprintf(path, sizeof(path), "%s/%s",ph->penv->home_dir, dirname);
    } else {
	snprintf(path, sizeof(path), "%s",dirname);
    }
    check_pathname(path);
    free(dirname);
    
    if ((ret = rmdir(path)) < 0) {
        prr = iiimp_rmdir_reply_new(ph->data_s, ret, errno);
        preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_RMDIR_REPLY, prr);
        return iiimcf_send_message(ph, preply, 1);
    }
    prr = iiimp_rmdir_reply_new(ph->data_s, pr->ns_id, errno);
    preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_RMDIR_REPLY, prr);
    return iiimcf_send_message(ph, preply, 1);
}

IIIMF_status
iiimcf_symlink(
    IIIMCF_handle_rec *ph,
    IIIMP_symlink *ps        
)
{
    int i, ret;
    IIIMP_message *preply;
    IIIMP_symlink_reply *psr;
    char dest_path[PATH_MAX];
    char src_path[PATH_MAX];
    char *dest;
    char *src;
    errno = 0;

    dest = (char *)calloc((ps->dest->len + 1), sizeof(char));
    for (i=0; i<ps->dest->len; i++) {
        dest[i] = ps->dest->ptr[i];
    }
    dest[i] = '\0';
    (void) memset((char *)dest_path, '\0', sizeof(dest_path));
    if (strstr(dest, ".iiim")) {
	snprintf(dest_path, sizeof(dest_path), "%s/%s",ph->penv->home_dir, dest);
    } else {
	snprintf(dest_path, sizeof(dest_path), "%s",dest);
    }
    check_pathname(dest_path);

    src = (char *)calloc((ps->src->len + 1), sizeof(char));
    for (i=0; i<ps->src->len; i++) {
        src[i] = ps->src->ptr[i];
    }
    src[i] = '\0';
    (void) memset((char *)src_path, '\0', sizeof(src_path));
    if (strstr(src, ".iiim")) {
	snprintf(src_path, sizeof(src_path), "%s/%s",ph->penv->home_dir, src);
    } else {
	snprintf(src_path, sizeof(src_path), "%s",src);
    }
    check_pathname(src_path);
    free(dest);
    free(src);

    if ((ret = symlink(dest_path, src_path)) < 0) {
        psr = iiimp_symlink_reply_new(ph->data_s, ret, errno);
        preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_SYMLINK_REPLY, psr);
        return iiimcf_send_message(ph, preply, 1);
    }
    psr = iiimp_symlink_reply_new(ph->data_s, ps->ns_id, errno);
    preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_SYMLINK_REPLY, psr);
    return iiimcf_send_message(ph, preply, 1);
}

IIIMF_status
iiimcf_stat(
    IIIMCF_handle_rec *ph,
    IIIMP_stat *ps         
)   
{   
    int i, ret;
    IIIMP_message *preply;
    IIIMP_stat_reply *psr;
    char path[PATH_MAX];
    char *dirname; 
    struct stat buf;
    iiimp_stat_struct *im_buf;
    errno = 0;
    
    dirname = (char *)calloc((ps->path->len + 1), sizeof(char));

    for (i=0; i<ps->path->len; i++) {
        dirname[i] = ps->path->ptr[i];
    }
    dirname[i] = '\0';

    (void) memset((char *)path, '\0', sizeof(path));
    if (strstr(dirname, ".iiim")) {
	snprintf(path, sizeof(path), "%s/%s",ph->penv->home_dir, dirname);
    } else {
        snprintf(path, sizeof(path), "%s",dirname);
    }
    check_pathname(path);
    free(dirname);

    if ((ret = stat(path, &buf)) < 0) {
        psr = iiimp_stat_reply_new(ph->data_s, ret, errno, (iiimp_stat_struct *)NULL);
        preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_STAT_REPLY, psr);
        return iiimcf_send_message(ph, preply, 1);
    }
    im_buf = (iiimp_stat_struct *) calloc(1, sizeof(iiimp_stat_struct));

    im_buf->s_mode = buf.st_mode;
    im_buf->s_nlink = buf.st_nlink;
    im_buf->s_uid = buf.st_uid;
    im_buf->s_gid = buf.st_gid;
    im_buf->s_atime = buf.st_atime;
    im_buf->s_mtime = buf.st_mtime;
    im_buf->s_ctime = buf.st_ctime;
    im_buf->s_blksize = buf.st_blksize;

    im_buf->s_dev = buf.st_dev;
    im_buf->s_rdev = buf.st_rdev;
    im_buf->s_ino = buf.st_ino;
    im_buf->s_size = buf.st_size;
    im_buf->s_blocks = buf.st_blocks;

    psr = iiimp_stat_reply_new(ph->data_s, ps->ns_id, errno, im_buf);
    preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_STAT_REPLY, psr);
    return iiimcf_send_message(ph, preply, 1);
}

IIIMF_status
iiimcf_lstat(
    IIIMCF_handle_rec *ph,
    IIIMP_lstat *pl
)
{
    int i, ret;
    IIIMP_message *preply;
    IIIMP_lstat_reply *plr;
    char path[PATH_MAX];
    char *dirname;
    struct stat buf;
    iiimp_stat_struct *im_buf;
    errno = 0;

    dirname = (char *)calloc((pl->path->len + 1), sizeof(char));

    for (i=0; i<pl->path->len; i++) {
        dirname[i] = pl->path->ptr[i];
    }
    dirname[i] = '\0';

    (void) memset((char *)path, '\0', sizeof(path));
    if (strstr(dirname, ".iiim")) {
	snprintf(path, sizeof(path), "%s/%s",ph->penv->home_dir, dirname);
    } else {
        snprintf(path, sizeof(path), "%s",dirname);
    }
    check_pathname(path);
    free(dirname);

    if ((ret = lstat(path, &buf)) < 0) {
        plr = iiimp_lstat_reply_new(ph->data_s, ret, errno, (iiimp_stat_struct *)NULL);
        preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_LSTAT_REPLY, plr);
        return iiimcf_send_message(ph, preply, 1);
    }

    im_buf = (iiimp_stat_struct *) calloc(1, sizeof(iiimp_stat_struct));

    im_buf->s_mode = buf.st_mode;
    im_buf->s_nlink = buf.st_nlink;
    im_buf->s_uid = buf.st_uid;
    im_buf->s_gid = buf.st_gid;
    im_buf->s_atime = buf.st_atime;
    im_buf->s_mtime = buf.st_mtime;
    im_buf->s_ctime = buf.st_ctime;
    im_buf->s_blksize = buf.st_blksize;

    im_buf->s_dev = buf.st_dev;
    im_buf->s_rdev = buf.st_rdev;
    im_buf->s_ino = buf.st_ino;
    im_buf->s_size = buf.st_size;
    im_buf->s_blocks = buf.st_blocks;

    plr = iiimp_lstat_reply_new(ph->data_s, pl->ns_id, errno, im_buf);
    preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_LSTAT_REPLY, plr);
    return iiimcf_send_message(ph, preply, 1);
}

IIIMF_status
iiimcf_fstat(
    IIIMCF_handle_rec *ph,
    IIIMP_fstat *pf
)
{
    int i, ret;
    IIIMP_message *preply;
    IIIMP_fstat_reply *pfr;
    struct stat buf;
    iiimp_stat_struct *im_buf;
    errno = 0;

    for (i=0; i<ph->num_of_ns; i++) {
	if (ph->pns[i].ns_id == pf->ns_id) {
	    if ((ret = fstat(ph->pns[i].nsc_fd, &buf)) < 0) {
		pfr = iiimp_fstat_reply_new(ph->data_s, ret, errno, (iiimp_stat_struct *)NULL);
		preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_FSTAT_REPLY, pfr);
		return iiimcf_send_message(ph, preply, 1);
	    } 
	    im_buf = (iiimp_stat_struct *) calloc(1, sizeof(iiimp_stat_struct));
	    im_buf->s_mode = buf.st_mode;
	    im_buf->s_nlink = buf.st_nlink;
	    im_buf->s_uid = buf.st_uid;
	    im_buf->s_gid = buf.st_gid;
	    im_buf->s_atime = buf.st_atime;
	    im_buf->s_mtime = buf.st_mtime;
	    im_buf->s_ctime = buf.st_ctime;
	    im_buf->s_blksize = buf.st_blksize;
    
	    im_buf->s_dev = buf.st_dev;
	    im_buf->s_rdev = buf.st_rdev;
	    im_buf->s_ino = buf.st_ino;
	    im_buf->s_size = buf.st_size;
	    im_buf->s_blocks = buf.st_blocks;
    
	    pfr = iiimp_fstat_reply_new(ph->data_s, pf->ns_id, errno, im_buf);
	    preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_FSTAT_REPLY, pfr);
	    return iiimcf_send_message(ph, preply, 1);
	}
    }
    return IIIMF_STATUS_FAIL;
}

IIIMF_status
iiimcf_creat(
    IIIMCF_handle_rec *ph,
    IIIMP_creat *pc        
)
{
    int i, ret;
    IIIMP_message *preply;
    IIIMP_creat_reply *pcr;
    char path[PATH_MAX];
    char *dirname;
    errno = 0;

    dirname = (char *)calloc((pc->path->len + 1), sizeof(char));
    for (i=0; i<pc->path->len; i++) {
        dirname[i] = pc->path->ptr[i];
    }
    dirname[i] = '\0';
    (void) memset((char *)path, '\0', sizeof(path));
    snprintf(path, sizeof(path), "%s",dirname);
    if (strstr(dirname, ".iiim")) {
	snprintf(path, sizeof(path), "%s/%s",ph->penv->home_dir, dirname);
    } else {
	snprintf(path, sizeof(path), "%s",dirname);
    }
    check_pathname(path);
    free(dirname);

    if ((ret = creat(path, pc->mode)) < 0) {
        pcr = iiimp_creat_reply_new(ph->data_s, ret, errno);
        preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_CREAT_REPLY, pcr);
        return iiimcf_send_message(ph, preply, 1);
    }
    pcr = iiimp_creat_reply_new(ph->data_s, pc->ns_id, errno);
    preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_CREAT_REPLY, pcr);
    return iiimcf_send_message(ph, preply, 1);
}

IIIMF_status
iiimcf_lseek(
    IIIMCF_handle_rec *ph,
    IIIMP_lseek *pl
)
{
    int i;
    off_t pos = (off_t) -1;
    IIIMP_message *preply;
    IIIMP_lseek_reply *plr;
    errno = 0;

    for (i=0; i<ph->num_of_ns; i++) {
	if (ph->pns[i].ns_id == pl->ns_id) {
	    pos = lseek(ph->pns[i].nsc_fd, pl->offset, pl->whence);
            if (pos < 0) {
		plr = iiimp_lseek_reply_new(ph->data_s, pl->ns_id, errno, pos);
		preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_LSEEK_REPLY, plr);
		return iiimcf_send_message(ph, preply, 1);
            }
	    break;
	}
    }
    plr = iiimp_lseek_reply_new(ph->data_s, pl->ns_id, errno, pos);
    preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_LSEEK_REPLY, plr);
    return iiimcf_send_message(ph, preply, 1);
}

IIIMF_status
iiimcf_unlink(
    IIIMCF_handle_rec *ph,
    IIIMP_unlink *pu        
)
{
    int i, ret;
    IIIMP_message *preply;
    IIIMP_unlink_reply *pur;
    char path[PATH_MAX];
    char *dirname;
    errno = 0;

    dirname = (char *)calloc((pu->path->len + 1), sizeof(char));
    for (i=0; i<pu->path->len; i++) {
        dirname[i] = pu->path->ptr[i];
    }
    dirname[i] = '\0';
    (void) memset((char *)path, '\0', sizeof(path));
    if (strstr(dirname, ".iiim")) {
	snprintf(path, sizeof(path), "%s/%s",ph->penv->home_dir, dirname);
    } else {
	snprintf(path, sizeof(path), "%s",dirname);
    }
    check_pathname(path);
    free(dirname);

    if ((ret = unlink(path)) < 0) {
        pur = iiimp_unlink_reply_new(ph->data_s, ret, errno);
        preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_UNLINK_REPLY, pur);
        return iiimcf_send_message(ph, preply, 1);
    }
    pur = iiimp_unlink_reply_new(ph->data_s, pu->ns_id, errno);
    preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_UNLINK_REPLY, pur);
    return iiimcf_send_message(ph, preply, 1);
}

IIIMF_status
iiimcf_rename(
    IIIMCF_handle_rec *ph,
    IIIMP_rename *pr        
)
{
    int i, ret;
    IIIMP_message *preply;
    IIIMP_rename_reply *prr;
    char old_buf[PATH_MAX];
    char new_buf[PATH_MAX];
    char *old_name;
    char *new_name;
    errno = 0;

    old_name = (char *)calloc((pr->old_name->len + 1), sizeof(char));
    for (i=0; i<pr->old_name->len; i++) {
        old_name[i] = pr->old_name->ptr[i];
    }
    old_name[i] = '\0';
    (void) memset((char *)old_buf, '\0', sizeof(old_buf));
    if (strstr(old_name, ".iiim")) {
	snprintf(old_buf, sizeof(old_buf), "%s/%s",ph->penv->home_dir, old_name);
    } else {
	snprintf(old_buf, sizeof(old_buf), "%s",old_name);
    }
    check_pathname(old_buf);

    new_name = (char *)calloc((pr->new_name->len + 1), sizeof(char));
    for (i=0; i<pr->new_name->len; i++) {
        new_name[i] = pr->new_name->ptr[i];
    }
    new_name[i] = '\0';
    (void) memset((char *)new_buf, '\0', sizeof(new_buf));
    snprintf(new_buf, sizeof(new_buf), "%s",new_name);
    if (strstr(new_name, ".iiim")) {
	snprintf(new_buf, sizeof(new_buf), "%s/%s",ph->penv->home_dir, new_name);
    } else {
	snprintf(new_buf, sizeof(new_buf), "%s",new_name);
    }
    check_pathname(new_buf);
    free(old_name);
    free(new_name);

    if ((ret = rename(old_buf, new_buf)) < 0) {
        prr = iiimp_rename_reply_new(ph->data_s, ret, errno);
        preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_RENAME_REPLY, prr);
        return iiimcf_send_message(ph, preply, 1);
    }

    prr = iiimp_rename_reply_new(ph->data_s, pr->ns_id, errno);
    preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_RENAME_REPLY, prr);
    return iiimcf_send_message(ph, preply, 1);
}

IIIMF_status
iiimcf_fcntl(
    IIIMCF_handle_rec *ph,
    IIIMP_fcntl *pf        
)
{
    int i, ret = 0;
    IIIMP_message *preply;
    IIIMP_fcntl_reply *pfr;
    errno = 0;
    
    for (i=0; i<ph->num_of_ns; i++) {
	if (ph->pns[i].ns_id == pf->ns_id) {
	    if ((ret = fcntl(ph->pns[i].nsc_fd, pf->cmd, pf->arg)) < 0) {
		pfr = iiimp_fcntl_reply_new(ph->data_s, pf->ns_id, errno, ret);
		preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_RENAME_REPLY, pfr);
		return iiimcf_send_message(ph, preply, 1);
	    }
	    break;
	}
    }
    pfr = iiimp_fcntl_reply_new(ph->data_s, pf->ns_id, errno, ret);
    preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_RENAME_REPLY, pfr);
    return iiimcf_send_message(ph, preply, 1);
}

IIIMF_status
iiimcf_truncate(
    IIIMCF_handle_rec *ph,
    IIIMP_truncate *pt        
)
{
    int i, ret;
    IIIMP_message *preply;
    IIIMP_truncate_reply *ptr;
    char path[PATH_MAX];
    char *dirname;
    errno = 0;

    dirname = (char *)calloc((pt->path->len + 1), sizeof(char));
    for (i=0; i<pt->path->len; i++) {
        dirname[i] = pt->path->ptr[i];
    }
    dirname[i] = '\0';
    (void) memset((char *)path, '\0', sizeof(path));
    if (strstr(dirname, ".iiim")) {
	snprintf(path, sizeof(path), "%s/%s",ph->penv->home_dir, dirname);
    } else {
	snprintf(path, sizeof(path), "%s",dirname);
    }
    check_pathname(path);
    free(dirname);

    if ((ret = truncate(path, pt->length)) < 0) {
        ptr = iiimp_truncate_reply_new(ph->data_s, ret, errno);
        preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_RENAME_REPLY, ptr);
        return iiimcf_send_message(ph, preply, 1);
    }
    ptr = iiimp_truncate_reply_new(ph->data_s, ret, errno);
    preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_RENAME_REPLY, ptr);
    return iiimcf_send_message(ph, preply, 1);
}

IIIMF_status
iiimcf_ftruncate(
    IIIMCF_handle_rec *ph,
    IIIMP_ftruncate *pf
)
{
    int i, ret;
    IIIMP_message *preply;
    IIIMP_ftruncate_reply *pfr;
    errno = 0;

    for (i=0; i<ph->num_of_ns; i++) {
	if (ph->pns[i].ns_id == pf->ns_id) {
	    if ((ret = ftruncate(ph->pns[i].nsc_fd, pf->length)) < 0) {
		pfr = iiimp_ftruncate_reply_new(ph->data_s, ret, errno);
		preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_FTRUNCATE_REPLY, pfr);
		return iiimcf_send_message(ph, preply, 1);
	    }
	    pfr = iiimp_ftruncate_reply_new(ph->data_s, ret, errno);
	    preply = iiimp_file_operation_reply_new(ph->data_s, ph->im_id, IIIMP_FILE_OPERATION_TYPE_FTRUNCATE_REPLY, pfr);
	    return iiimcf_send_message(ph, preply, 1);
	}
    }
    return IIIMF_STATUS_FAIL;
}

/* Local Variables: */
/* c-file-style: "iiim-project" */
/* End: */
