Newer
Older
UbixOS / sys / fs / vfs / file.c
/*-
 * Copyright (c) 2002-2018, 2020 The UbixOS Project.
 * All rights reserved.
 *
 * This was developed by Christopher W. Olsen for the UbixOS Project.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted
 * provided that the following conditions are met:
 *
 * 1) Redistributions of source code must retain the above copyright notice, this list of
 *    conditions, the following disclaimer and the list of authors.
 * 2) Redistributions in binary form must reproduce the above copyright notice, this list of
 *    conditions, the following disclaimer and the list of authors in the documentation and/or
 *    other materials provided with the distribution.
 * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to
 *    endorse or promote products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <ubixos/sched.h>
#include <vfs/vfs.h>
#include <ubixos/vitals.h>
#include <ubixos/kpanic.h>
#include <ubixos/spinlock.h>
#include <lib/kmalloc.h>
#include <string.h>
#include <vmm/paging.h>
#include <lib/kprintf.h>
#include <assert.h>
#include <sys/descrip.h>
#include "../fat/fat_filelib.h"

static struct spinLock fdTable_lock = SPIN_LOCK_INITIALIZER
;

fileDescriptor_t *fdTable = 0x0;

fileDescriptor_t *vfs_fileTable = 0x0;

int sys_fwrite(struct thread *td, struct sys_fwrite_args *uap) {
    char *t = uap->buf;

    if (uap->fd == 0x0) {
        tty_print((char*) uap->buf, _current->term);
    }
    else {

#ifdef DEBUG_VFS
    kprintf("uap->size: %i, FD: [0x%X], BUF: [0x%X][%c]\n", uap->nbytes, uap->fd, uap->buf, t[0]);
#endif

        fwrite(uap->buf, uap->nbytes, 1, uap->fd->fd);
    }

    td->td_retval[0] = 0x0;

    return (0);
}

/* USER */

void sysFwrite(char *ptr, int size, userFileDescriptor *userFd) {
    if (userFd == 0x0) {
        tty_print(ptr, _current->term);
    }
    else {
        fwrite(ptr, size, 1, userFd->fd);
    }
    return;
}

int sys_fgetc(struct thread *td, struct sys_fgetc_args *args) {
    char c;

    if (args->FILE->fd == 0x0) {

        while (1) {

            if (_current->term == tty_foreground) {
                c = getchar();

                if (c != 0x0) {
                    td->td_retval[0] = c;
                    return (0);
                }

                sched_yield();

            }
            else {
                sched_yield();
            }
            /*
             else {
             kprintf("Waking Task: %i\n",tty_foreground->owner);
             sched_setStatus(tty_foreground->owner,READY);
             kprintf("Sleeping Task: %i\n",_current->id);
             sched_setStatus(_current->id,WAIT);
             sched_yield();
             }
             */
        }
    }
    else {
        c = fgetc(args->FILE->fd);
        td->td_retval[0] = c;
        return (0);
    }
}

void sysRmDir() {
    return;
}

int sys_fseek(struct thread *td, struct sys_fseek_args *args) {
    kprintf("offset: %ld, whence: 0x%X", args->offset, args->whence);

    // TODO : coredump?
    if (args->FILE == NULL) {
        td->td_retval[0] = -1;
        return (-1);
    }

    if (args->FILE->fd == NULL) {
        td->td_retval[0] = -1;
        return (-1);
    }

    switch (args->whence) {
        case 0:
            args->FILE->fd->offset = args->offset;
            break;
        case 1:
            args->FILE->fd->offset += args->offset;
            break;
        default:
            kprintf("seek-whence: %i", args->whence);
            break;
    }

    td->td_retval[0] = args->FILE->fd->offset & 0xFFFFFFFF;
    return (0);
}

int sys_lseek(struct thread *td, struct sys_lseek_args *args) {
    int error = 0;
    struct file *fdd = 0x0;
    fileDescriptor_t *fd = 0x0;

    getfd(td, &fdd, args->fd);

    fd = fdd->fd;

    if (fdd == 0 || fdd->fd == 0x0) {
        error = -1;
        kprintf("ERROR!");
    }

    //kprintf("loffset(%i): %i:%i, whence: %i", sizeof(off_t), args->offset >> 32, args->offset & 0xFFFFFFFF, args->whence);
    //kprintf("loffset(%i): %qd, whence: %i", sizeof(off_t), args->offset, args->whence);

    switch (args->whence) {
        case SEEK_SET:
            fd->offset = args->offset;
            td->td_retval[0] = fd->offset & 0xFFFFFFFF;
            td->td_retval[1] = fd->offset >> 32;
            break;
        case SEEK_CUR:
            fd->offset += args->offset;
            td->td_retval[0] = fd->offset & 0xFFFFFFFF;
            td->td_retval[1] = fd->offset >> 32;
            break;
        default:
            kprintf("seek-whence: %iqd", args->whence);
            break;
    }

    // kprintf("loff: %qd:%s", fd->offset, ((FL_FILE*) fd->res)->filename);

    return (error);
}

int sys_chdir(struct thread *td, struct sys_chdir_args *args) {
    if (strstr(args->path, ":") == 0x0) {
        sprintf(_current->oInfo.cwd, "%s%s", _current->oInfo.cwd, args->path);
    }
    else {
        sprintf(_current->oInfo.cwd, args->path);
    }
    td->td_retval[0] = 0;
    return (0);
}

int sys_fchdir(struct thread *td, struct sys_fchdir_args *args) {
    int error = 0;
    struct file *fdd = 0x0;
    fileDescriptor_t *fd = 0x0;

    getfd(td, &fdd, args->fd);

    fd = fdd->fd;

    if (fdd == 0 || fdd->fd == 0x0) {
        error = -1;
    }
    else {
        if (strstr(fd->fileName, ":") == 0x0) {
            sprintf(_current->oInfo.cwd, "%s%s", _current->oInfo.cwd, fd->fileName);
        }
        else {
            sprintf(_current->oInfo.cwd, fd->fileName);
        }
    }
    return (error);
}

int sys_rename(struct thread *td, struct sys_rename_args *args) {
    td->td_retval[0] = 0;
    return (0);
}

int sysUnlink(const char *path, int *retVal) {
    *retVal = 0;
    return (*retVal);
}

/************************************************************************

 Function: void sysFopen();
 Description: Opens A File Descriptor For A User Task
 Notes:

 ************************************************************************/
//void sysFopen(const char *file,char *flags,userFileDescriptor *userFd) {
int sys_fopen(struct thread *td, struct sys_fopen_args *args) {
    kprintf("sys_fopen");
    if (args->FILE == NULL) {
        kprintf("Error: userFd == NULL, File: %s, Line: %i\n", __FILE__, __LINE__);
        return (-1);
    }

    args->FILE->fd = fopen(args->path, args->mode);
    if (args->FILE->fd != 0x0) {
        args->FILE->fdSize = args->FILE->fd->size;
    }
    /* Return */
    return (0);
}

/************************************************************************

 Function: void sysFread();
 Description: Reads SIZE Bytes From The userFd Into DATA
 Notes:

 ************************************************************************/
int sys_fread(struct thread *td, struct sys_fread_args *args) {

    /* TODO : coredump? */
    if (args->FILE == NULL)
        return (-1);

    if (args->FILE->fd == NULL)
        return (-1);

    td->td_retval[0] = fread(args->ptr, args->size, args->nmemb, args->FILE->fd);
    return (0);
}

/************************************************************************

 Function: void sysFclse();
 Description: Closes A File Descriptor For A User Task
 Notes:

 ************************************************************************/
int sys_fclose(struct thread *td, struct sys_fclose_args *args) {
    if (args->FILE == NULL) {
        return (-1);
    }
    if (args->FILE == NULL) {
        return (-1);
    }

    /* Return */
    return (fclose(args->FILE->fd));
}

/* KERNEL */

size_t fread( void *ptr, size_t size, size_t nmemb, fileDescriptor_t *fd ) {

	size_t i = 0x0;

    if (fd == 0x0) {

    	return (0x0);

    }

    if (nmemb == 0x0) {

    	nmemb = 1;  //Temp Fix

    }

    if( fd->fd_type == 0x100 ) {
    	return(0x0);
    }

    assert( fd );
    assert( fd->mp );
    assert( fd->mp->fs );

    i = fd->mp->fs->vfsRead( fd, ptr, fd->offset, size * nmemb );

    //fd->offset += size * nmemb;

    return( i );

}

size_t fwrite(void *ptr, int size, int nmemb, fileDescriptor_t *fd) {
    int res = 0x0;
    /*
     kprintf("fd[0x%X]\m", fd);
     kprintf("fd->mp[0x%X]\m", fd->mp);
     kprintf("fd->mp->fs[0x%X]\m", fd->mp->fs);
     */

    if (fd != 0x0) {
        res = fd->mp->fs->vfsWrite(fd, ptr, fd->offset, size * nmemb);
        fd->offset += size * nmemb;
    }
    return (res);
}

int kern_fseek(fileDescriptor_t *tmpFd, u_int32_t offset, int whence) {
    tmpFd->offset = offset + whence;
    return (tmpFd->offset);
}

/************************************************************************

 Function: int feof(fileDescriptor_t *fd)
 Description: Check A File Descriptor For EOF And Return Result
 Notes:

 ************************************************************************/
int feof(fileDescriptor_t *fd) {
    if (fd->status == fdEof) {
        return (-1);
    }
    return (0);
}

/************************************************************************

 Function: int fputc(int ch,fileDescriptor_t *fd)
 Description: This Will Write Character To FD
 Notes:

 ************************************************************************/
int fputc(int ch, fileDescriptor_t *fd) {
    if (fd != 0x0) {
        ch = fd->mp->fs->vfsWrite(fd, (char*) ch, fd->offset, 1);
        fd->offset++;
        return (ch);
    }
    /* Return NULL If FD Is Not Found */
    return (0x0);
}

/************************************************************************

 Function: int fgetc(fileDescriptor_T *fd)
 Description: This Will Return The Next Character In A FD Stream
 Notes:

 ************************************************************************/
int fgetc(fileDescriptor_t *fd) {
    int ch = 0x0;
    kprintf("[%s:%i]", __FILE__, __LINE__);
    /* If Found Return Next Char */
    if (fd != 0x0) {
        fd->mp->fs->vfsRead(fd, (char*) &ch, fd->offset, 1);
        fd->offset++;
        return (ch);
    }

    /* Return NULL If FD Is Not Found */
    return (0x0);
}

/************************************************************************

 Function: fileDescriptor_t *fopen(const char *file,cont char *flags)
 Description: This Will Open A File And Return A File Descriptor
 Notes:

 08/05/02 - Just Started A Rewrite Of This Function Should Work Out Well

 ************************************************************************/

fileDescriptor_t* fopen(const char *file, const char *flags) {

    int i = 0x0;
    char *path = 0x0;
    char *mountPoint = 0x0;
    char fileName[1024];
    fileDescriptor_t *tmpFd = 0x0;

    /* Allocate Memory For File Descriptor */
    if ((tmpFd = (fileDescriptor_t*) kmalloc(sizeof(fileDescriptor_t))) == 0x0) {
        kprintf("Error: tmpFd == NULL, File: %s, Line: %i\n", __FILE__, __LINE__);
        return (NULL);
    }

    memset(tmpFd, 0x0, sizeof(fileDescriptor_t));

    path = file;

    /* Determine if path is relative or absolute */
    if (path[0] == "." && path[1] == '\0')
        strcpy(fileName, _current->oInfo.cwd);
    else
        strcpy(fileName, file);

    path = 0x0;

    if (strstr(fileName, ":")) {
        mountPoint = (char*) strtok((char*) &fileName, ":");
        path = strtok(NULL, "\n");
    }
    else {
        path = fileName;
    }

    if (path[0] == '/')
        strcpy(tmpFd->fileName, path);
    else
        sprintf(tmpFd->fileName, "/%s", path);

    /* Find our mount point or set default to sys */
    if (mountPoint == 0x0) {
        tmpFd->mp = vfs_findMount("sys");
    }
    else {
        tmpFd->mp = vfs_findMount(mountPoint);
    }

    if (tmpFd->mp == 0x0) {
        kprintf("Mount Point Bad\n");
        return (0x0);
    }

    /* This Will Set Up The Descriptor Modes */
    tmpFd->mode = 0;
    for (i = 0; '\0' != flags[i]; i++) {
        switch (flags[i]) {
            case 'w':
            case 'W':
                tmpFd->mode |= fileWrite;
                break;
            case 'r':
            case 'R':
                tmpFd->mode |= fileRead;
                break;
            case 'b':
            case 'B':
                tmpFd->mode |= fileBinary;
                break;
            case 'a':
            case 'A':
                tmpFd->mode |= fileAppend;
                break;
            default:
                kprintf("Invalid mode '%c' for fopen\n", flags[i]);
                break;
        }
    }

    /* Search For The File */
    if (tmpFd->mp->fs->vfsOpenFile(tmpFd->fileName, tmpFd) == 0x1) {
        /* If The File Is Found Then Set Up The Descriptor */

        /* in order to save resources we will allocate the buffer later when it is needed */

        tmpFd->buffer = (char*) kmalloc(4096);

        if (tmpFd->buffer == 0x0) {
            kfree(tmpFd);
            kprintf("Error: tmpFd->buffer == NULL, File: %s, Line: %i\n", __FILE__, __LINE__);
            spinUnlock(&fdTable_lock);
            return (0x0);
        }

        /* Set Its Status To Open */
        tmpFd->status = fdOpen;

        /* Initial File Offset Is Zero */
        tmpFd->offset = 0;
        tmpFd->prev = 0x0;

        /* we do not want to be in a spinlock longer than we need to, so
         it has been moved to here. */
        spinLock(&fdTable_lock);

        /* Increment Number Of Open Files */
        systemVitals->openFiles++;

        tmpFd->next = fdTable;

        if (fdTable != 0x0)
            fdTable->prev = tmpFd;

        fdTable = tmpFd;

        spinUnlock(&fdTable_lock);

        /* Return The FD */
        return (tmpFd);
    }
    else {
        //kprintf("Freeing");
        kfree(tmpFd->buffer);
        kfree(tmpFd);
        spinUnlock(&fdTable_lock);
        //MrOlsen (2016-01-13) NOTE: We don't need this right now kprintf("File Not Found? %s\n",file);
        return (0x0);
    }

    /* Return NULL */
    return (0x0);
}

/************************************************************************

 Function: int fclose(fileDescriptor_t *fd);
 Description: This Will Close And Free A File Descriptor
 Notes:

 ************************************************************************/
int fclose(fileDescriptor_t *fd) {
    fileDescriptor_t *tmpFd = 0x0;

    if (fd == 0)
        return (0x0);

    spinLock(&fdTable_lock);

    for (tmpFd = fdTable; tmpFd != 0x0; tmpFd = tmpFd->next) {

        if (tmpFd == fd) {

            if (fd->dup > 0) {
                fd->dup--;
            }
            else {
                if (fd->res != 0x0)
                    fl_fclose(fd->res);

                if (tmpFd->prev)
                    tmpFd->prev->next = tmpFd->next;
                if (tmpFd->next)
                    tmpFd->next->prev = tmpFd->prev;

                if (tmpFd == fdTable)
                    fdTable = tmpFd->next;

                systemVitals->openFiles--;

                spinUnlock(&fdTable_lock);

                if (tmpFd->buffer != NULL) {
                    kfree(tmpFd->buffer);
                }

                kfree(tmpFd);
                return (0x0);
            }
        }
    }

    spinUnlock(&fdTable_lock);
    return (0x1);
}

/* UBU */

/************************************************************************

 Function: void sysMkDir(const char *path)
 Description: This Will Create A New Directory
 Notes:

 ************************************************************************/
void sysMkDir(const char *path) {
    fileDescriptor_t *tmpFD = 0x0;
    char tmpDir[1024];
    char rootPath[256];
    char *dir = 0x0;  //UBU*mountPoint = 0x0;
    char *tmp = 0x0;
    rootPath[0] = '\0';
    dir = (char*) path;

    if (strstr(path, ":") == 0x0) {
        sprintf(tmpDir, "%s%s", _current->oInfo.cwd, path);
        dir = (char*) &tmpDir;
    }
    while (strstr(dir, "/")) {
        if (rootPath[0] == 0x0)
            sprintf(rootPath, "%s/", strtok(dir, "/"));
        else
            sprintf(rootPath, "%s%s/", rootPath, strtok(dir, "/"));
        tmp = strtok(NULL, "\n");
        dir = tmp;
    }

    //kprintf("rootPath: [%s]\n",rootPath);
    tmpFD = fopen(rootPath, "rb");

    if (tmpFD->mp == 0x0) {
        kprintf("Invalid Mount Point\n");
    }
    tmpFD->mp->fs->vfsMakeDir(dir, tmpFD);

    fclose(tmpFD);

    return;
}

/************************************************************************

 Function: int unlink(const char *node)
 Description: This will unlink a file
 Notes:

 ************************************************************************/

int unlink(const char *node) {
    char *path = 0x0, *mountPoint = 0x0;
    struct vfs_mountPoint *mp = 0x0;

    path = (char*) strtok((char*) node, "@");

    mountPoint = strtok(NULL, "\n");

    if (mountPoint == 0x0) {
        mp = vfs_findMount("sys"); /* _current->oInfo.container; */
    }
    else {
        mp = vfs_findMount(mountPoint);
    }
    if (mp == 0x0) {

        kprintf("DBG: Mount Point Bad");
        //kpanic("Mount Point Bad");
        return (0x0);

    }

    mp->fs->vfsUnlink(path, mp);

    return (0x0);
}