/*-
* Copyright (c) 2002-2018 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>
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 + args->whence;
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: 0x%X", sizeof(off_t), args->offset >> 32, args->offset & 0xFFFFFF, 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: %i", args->whence);
break;
}
kprintf("loff: %ld", fd->offset);
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) {
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
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) {
if (fd != 0x0) {
fd->mp->fs->vfsWrite(fd, ptr, fd->offset, size * nmemb);
fd->offset += size * nmemb;
}
return (0x0);
}
int fseek(fileDescriptor_t *tmpFd, long 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;
/* 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);
}
/* XXX - Temp */
memset(tmpFd, 0x0, sizeof(fileDescriptor_t));
path = file;
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);
}
//kprintf("[fO: %s]", file);
/* 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 (NULL);
}
/* 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;
// XXX Can't do this
//assert( fd );
if (fd == 0)
return (0x0);
spinLock(&fdTable_lock);
for (tmpFd = fdTable; tmpFd != 0x0; tmpFd = tmpFd->next) {
if (tmpFd == fd) {
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) {
//kpanic("Mount Point Bad");
return (0x0);
}
mp->fs->vfsUnlink(path, mp);
return (0x0);
}