[freenos] [freenos commit] r225 - Implemented the notion of current directory in the VirtualFileSystem.

  • From: codesite-noreply@xxxxxxxxxx
  • To: freenos@xxxxxxxxxxxxx
  • Date: Fri, 10 Jul 2009 16:09:33 +0000

Author: nieklinnenbank
Date: Fri Jul 10 09:07:14 2009
New Revision: 225

Added:
   trunk/bin/sh/ChangeDirCommand.cpp
   trunk/bin/sh/ChangeDirCommand.h
Modified:
   trunk/bin/ls/Main.cpp
   trunk/bin/sh/SConscript
   trunk/bin/sh/Shell.cpp
   trunk/lib/libposix/unistd.cpp
   trunk/lib/libposix/unistd.h
   trunk/srv/filesystem/FileSystem.h
   trunk/srv/filesystem/FileSystemMessage.h
   trunk/srv/filesystem/virtual/VirtualFileSystem.cpp
   trunk/srv/filesystem/virtual/VirtualFileSystem.h

Log:
Implemented the notion of current directory in the VirtualFileSystem.
Additionally, a POSIX-1.2008 compliant getcwd() function has been added.
Shell now using this information in the system prompt, and 'ls' defaults
to the current directory if no argument is given.


Modified: trunk/bin/ls/Main.cpp
==============================================================================
--- trunk/bin/ls/Main.cpp       (original)
+++ trunk/bin/ls/Main.cpp       Fri Jul 10 09:07:14 2009
@@ -20,25 +20,29 @@
 #include <dirent.h>
 #include <string.h>
 #include <errno.h>
+#include <unistd.h>
 #include <TerminalCodes.h>

 int main(int argc, char **argv)
 {
     DIR *d;
     struct dirent *dent;
+    char path[255];

-    /* Verify command-line arguments. */
-    if (argc <= 1)
+    /* Grab command-line arguments, if any */
+    if (argc > 1)
     {
-       printf("usage: %s DIRECTORY\r\n",
-               argv[0]);
-       return EXIT_FAILURE;
+       strncpy(path, argv[1], sizeof(path));
+       path[sizeof(path) - 1] = 0;
     }
+    else
+       getcwd(path, sizeof(path));
+
     /* Attempt to open the directory. */
-    if (!(d = opendir(argv[1])))
+    if (!(d = opendir(path)))
     {
        printf("%s: failed to open '%s': %s\r\n",
-               argv[0], argv[1], strerror(errno));
+               argv[0], path, strerror(errno));
        return EXIT_FAILURE;
     }
     /* Read directory. */

Added: trunk/bin/sh/ChangeDirCommand.cpp
==============================================================================
--- (empty file)
+++ trunk/bin/sh/ChangeDirCommand.cpp   Fri Jul 10 09:07:14 2009
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2009 Niek Linnenbank
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <API/IPCMessage.h>
+#include <FileSystem.h>
+#include <FileSystemPath.h>
+#include <FileSystemMessage.h>
+#include <Config.h>
+#include <Macros.h>
+#include <String.h>
+#include <List.h>
+#include <ListIterator.h>
+#include "ChangeDirCommand.h"
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+int ChangeDirCommand::execute(Size nparams, char **params)
+{
+    FileSystemMessage msg;
+    FileSystemPath path;
+    String *last = ZERO;
+    List<String> lst;
+    char cwd[PATHLEN], buf[PATHLEN];
+    struct stat st;
+
+    /* First stat the file. */
+    if (stat(params[0], &st) != 0)
+    {
+       printf("Failed to stat() `%s': %s\r\n",
+               params[0], strerror(errno));
+       return errno;
+    }
+    /* Must be a directory. */
+    if (!S_ISDIR(st.st_mode))
+    {
+       printf("`%s' is not a directory\r\n",
+               params[0]);
+       return -1;
+    }
+    /* What's the current working dir? */
+    getcwd(cwd, PATHLEN);
+
+    /* Relative or absolute? */
+    if (params[0][0] != '/')
+    {
+       snprintf(buf, sizeof(buf), "%s/%s", cwd, params[0]);
+       path.parse(buf);
+       memset(buf, 0, sizeof(buf));
+       
+       /* Process '..' */
+       for (ListIterator<String> i(path.split()); i.hasNext(); i++)
+       {
+           if ((**i.current())[0] != '.')
+           {
+               lst.insertTail(i.current());
+               last = i.current();
+           }
+           else if ((**i.current())[1] == '.' && last)
+           {
+               lst.remove(last);
+           }
+       }
+       /* Construct final path. */
+       for (ListIterator<String> i(&lst); i.hasNext(); i++)
+       {
+           strcat(buf, "/");
+           strcat(buf, **i.current());
+       }
+       msg.buffer = buf;
+    }
+    else
+       msg.buffer = params[0];
+
+    /* Fall back to slash? */
+    if (!buf[0])
+    {
+       strcpy(buf, "/");
+    }
+    /* Fill the message. */
+    msg.action = SetCurrentDir;
+    msg.procID = getpid();
+
+    /* Ask VFS. */
+    IPCMessage(VFSSRV_PID, SendReceive, &msg, sizeof(msg));
+
+    /* Done. */
+    return msg.result;
+}
+
+INITOBJ(ChangeDirCommand, cdCmd, LIBCRT_DEFAULT)

Added: trunk/bin/sh/ChangeDirCommand.h
==============================================================================
--- (empty file)
+++ trunk/bin/sh/ChangeDirCommand.h     Fri Jul 10 09:07:14 2009
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2009 Niek Linnenbank
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __SH_CHANGE_DIR_COMMAND
+#define __SH_CHANGE_DIR_COMMAND
+
+#include <Factory.h>
+#include <Types.h>
+#include "ShellCommand.h"
+
+/**
+ * Change the current working directory.
+ */
+class ChangeDirCommand : public ShellCommand, public Factory<ChangeDirCommand>
+{
+    public:
+
+       /**
+        * Constructor function.
+        */
+       ChangeDirCommand() : ShellCommand("cd", 1)
+       {
+       }
+
+       /**
+        * Get the help string for this command.
+        * @return Pointer to character string describing what the command does.
+        */
+       const char * help()
+       {
+           return "Change the current working directory";
+       }
+
+       /**
+        * Executes the command.
+        * @param nparams Number of parameters given.
+        * @param params Array of parameters.
+        * @return Error code or zero on success.
+        */
+       int execute(Size nparams, char **params);
+};
+
+#endif /* __SH_CHANGE_DIR_COMMAND */

Modified: trunk/bin/sh/SConscript
==============================================================================
--- trunk/bin/sh/SConscript     (original)
+++ trunk/bin/sh/SConscript     Fri Jul 10 09:07:14 2009
@@ -21,5 +21,6 @@
                      [ 'memory', 'filesystem', 'filesystem/virtual', 
'terminal' ])

 env.Program('sh', [ 'Main.cpp', 'Shell.cpp', 'HelpCommand.cpp',
-                   'ShellCommand.cpp', 'WriteCommand.cpp', 'ExitCommand.cpp' ],
+                   'ShellCommand.cpp', 'WriteCommand.cpp', 'ExitCommand.cpp',
+                   'ChangeDirCommand.cpp' ],
                     LIBS = env['LIBS'], LIBPATH = env['LIBPATH'])

Modified: trunk/bin/sh/Shell.cpp
==============================================================================
--- trunk/bin/sh/Shell.cpp      (original)
+++ trunk/bin/sh/Shell.cpp      Fri Jul 10 09:07:14 2009
@@ -143,13 +143,17 @@

 void Shell::prompt()
 {
-    char tmp[128];
+    char host[128], cwd[128];

     /* Retrieve current hostname. */
-    gethostname(tmp, sizeof(tmp));
+    gethostname(host, sizeof(host));
+
+    /* Retrieve current working directory. */
+    getcwd(cwd, sizeof(cwd));

     /* Print out the prompt. */
-    printf(WHITE "(" GREEN "%s" WHITE ") # ", tmp);
+    printf(WHITE "(" GREEN "%s" WHITE ") " BLUE "%s" WHITE " # ",
+          host, cwd);
 }

 Size Shell::parse(char *cmdline, char **argv, Size maxArgv)

Modified: trunk/lib/libposix/unistd.cpp
==============================================================================
--- trunk/lib/libposix/unistd.cpp       (original)
+++ trunk/lib/libposix/unistd.cpp       Fri Jul 10 09:07:14 2009
@@ -152,3 +152,22 @@
     strlcpy(name, "localhost", namelen);
     return 0;
 }
+
+char *getcwd(char *buf, size_t size)
+{
+    FileSystemMessage msg;
+
+    /* Fill message. */
+    msg.buffer = buf;
+    msg.procID = getpid();
+    msg.action = GetCurrentDir;
+
+    /* Ask VFS. */
+    IPCMessage(VFSSRV_PID, SendReceive, &msg, sizeof(msg));
+
+    /* Set errno. */
+    errno = msg.result;
+
+    /* All done. */
+    return errno == ESUCCESS ? buf : ZERO;
+}

Modified: trunk/lib/libposix/unistd.h
==============================================================================
--- trunk/lib/libposix/unistd.h (original)
+++ trunk/lib/libposix/unistd.h Fri Jul 10 09:07:14 2009
@@ -248,6 +248,23 @@
 extern C int gethostname(char *name, size_t namelen);

 /**
+ * @brief Get the pathname of the current working directory.
+ *
+ * The getcwd() function shall place an absolute pathname of the
+ * current working directory in the array pointed to by buf, and
+ * return buf. The pathname shall contain no components that are
+ * dot or dot-dot, or are symbolic links.
+ *
+ * @param buf Output buffer, to store the current directory.
+ * @param size Size of the output buffer.
+ * @return Upon successful completion, getcwd() shall return
+ *         the buf argument. Otherwise, getcwd() shall return
+ *         a null pointer and set errno to indicate the error.
+ *         The contents of the array pointed to by buf are then undefined.
+ */
+extern C char *getcwd(char *buf, size_t size);
+
+/**
  * @}
  */


Modified: trunk/srv/filesystem/FileSystem.h
==============================================================================
--- trunk/srv/filesystem/FileSystem.h   (original)
+++ trunk/srv/filesystem/FileSystem.h   Fri Jul 10 09:07:14 2009
@@ -142,10 +142,11 @@
          */
        void ioHandler(FileSystemMessage *msg)
        {
+           FileSystemMessage vfs;
            FileSystemPath path;
            FileCache *fc = ZERO;
            File *f = ZERO;
-           char buf[PATHLEN];
+           char buf[PATHLEN], tmp[PATHLEN];

            /*
             * Find the file, either in cache, storage or via
@@ -159,15 +160,35 @@

                    /* Copy the path first. */
                    if (VMCopy(msg->procID, Read, (Address) buf,
-                             (Address) msg->buffer + strlen(mountPath), PATHLEN) 
<= 0)
+                             (Address) msg->buffer, PATHLEN) <= 0)
                    {
                        msg->error(EACCES, IODone);
                        return;
                    }
                    else
                    {
-                       /* Parse the path. */
-                       path.parse(buf);
+                       /* Is the path relative? */
+                       if (buf[0] != '/')
+                       {
+                           vfs.action = GetCurrentDir;
+                           vfs.buffer = tmp;
+                           vfs.procID = msg->procID;
+                       
+                           /*
+                            * Ask for their current directory.
+                            * TODO: this can be much more efficient, if we can
+                            *       map the user process table in our address 
space!
+ * TODO: this is also buggy... what if VFS tries to contact us meanwhile...
+                            */
+                           IPCMessage(VFSSRV_PID, SendReceive, &vfs, 
sizeof(vfs));
+                       
+                           /* Reconstruct path. */
+                           snprintf(tmp, sizeof(tmp), "%s/%s", tmp,
+                                    buf);
+                           path.parse(tmp);
+                       }
+                       else
+                           path.parse(buf + strlen(mountPath));

                        /* No need to lookup caches for creation. */    
                        if (msg->action == CreateFile)

Modified: trunk/srv/filesystem/FileSystemMessage.h
==============================================================================
--- trunk/srv/filesystem/FileSystemMessage.h    (original)
+++ trunk/srv/filesystem/FileSystemMessage.h    Fri Jul 10 09:07:14 2009
@@ -31,20 +31,22 @@
  */
 typedef enum FileSystemAction
 {
-    CreateFile  = 0,
-    OpenFile    = 1,
-    ReadFile    = 2,
-    WriteFile   = 3,
-    SeekFile    = 4,
-    StatFile    = 5,
-    ChangeFile  = 6,
-    CloseFile   = 7,
-    Mount      = 8,
-    Unmount    = 9,
-    MountInfo   = 10,
-    NewProcess  = 11,
-    KillProcess = 12,
-    IODone      = 13,
+    CreateFile    = 0,
+    OpenFile      = 1,
+    ReadFile      = 2,
+    WriteFile     = 3,
+    SeekFile      = 4,
+    StatFile      = 5,
+    ChangeFile    = 6,
+    CloseFile     = 7,
+    Mount        = 8,
+    Unmount      = 9,
+    MountInfo     = 10,
+    NewProcess    = 11,
+    KillProcess   = 12,
+    IODone        = 13,
+    GetCurrentDir = 14,
+    SetCurrentDir = 15,
 }
 FileSystemAction;


Modified: trunk/srv/filesystem/virtual/VirtualFileSystem.cpp
==============================================================================
--- trunk/srv/filesystem/virtual/VirtualFileSystem.cpp  (original)
+++ trunk/srv/filesystem/virtual/VirtualFileSystem.cpp Fri Jul 10 09:07:14 2009
@@ -44,6 +44,8 @@
     addIPCHandler(MountInfo,   &VirtualFileSystem::mountInfoHandler);
     addIPCHandler(NewProcess,  &VirtualFileSystem::newProcessHandler);
     addIPCHandler(KillProcess, &VirtualFileSystem::killProcessHandler);
+    addIPCHandler(GetCurrentDir, &VirtualFileSystem::currentDirHandler);
+    addIPCHandler(SetCurrentDir, &VirtualFileSystem::currentDirHandler);

     /* Wait for process server to sync BootPrograms from BootImages. */
     for (Size i = 0; i < info.moduleCount; i++)
@@ -75,7 +77,6 @@

 void VirtualFileSystem::ioHandler(FileSystemMessage *msg)
 {
-    char path[PATHLEN];
     FileSystemMount *mount;
     FileDescriptor *fd;
     ProcessID fsID;
@@ -95,15 +96,8 @@
        case OpenFile:
        case StatFile:

-           /* Obtain full path first. */
-           if ((msg->result = VMCopy(msg->from, Read, (Address) path,
-                                    (Address) msg->buffer, PATHLEN)) < 0)
-           {
-               msg->error(msg->result);
-               return;
-           }
            /* Retrieve mountpoint. */
-           if (!(mount = findMount(path)))
+           if (!(mount = findMount(msg)))
            {
                msg->error(ENOENT);
                return;
@@ -154,9 +148,7 @@
 void VirtualFileSystem::ioDoneHandler(FileSystemMessage *msg)
 {
     FileDescriptor *fd;
-    char path[PATHLEN];
     FileSystemMount *mount;
-    Error err;

     /* Retrieve correct mountpoint or filedescriptor. */
     switch (msg->savedAction)
@@ -164,15 +156,8 @@
        case OpenFile:
        case StatFile:

-           /* Obtain full path first. */
-           if ((err = VMCopy(msg->procID, Read, (Address) path,
-                                    (Address) msg->buffer, PATHLEN) < 0))
-           {
-               msg->error(err, IODone, msg->procID);
-               return;
-           }
            /* Retrieve mountpoint. */
-           if (!(mount = findMount(path)))
+           if (!(mount = findMount(msg)))
            {
                msg->error(ENOENT, IODone, msg->procID);
                return;
@@ -255,17 +240,23 @@

 void VirtualFileSystem::newProcessHandler(FileSystemMessage *msg)
 {
-    /* Fill in the new process. */
+    /* Fill in identities. */
     procs[msg->procID].userID  = msg->userID;
     procs[msg->procID].groupID = msg->groupID;

-    /* Copy file descriptor from parent, if any. */
+    /* Copy file descriptors, and current directory from parent, if any. */
     if (msg->parentID != ANY)
+    {
        procs[msg->procID].files = new Array<FileDescriptor>(
                                        procs[msg->parentID].files);
+       strlcpy(procs[msg->procID].currentDir,
+               procs[msg->parentID].currentDir, PATHLEN);
+    }
     else
+    {
        procs[msg->procID].files = new Array<FileDescriptor>;
-
+       strncpy(procs[msg->procID].currentDir, "/", PATHLEN);
+    }
     /* Success. */
     msg->result = ESUCCESS;
 }
@@ -283,6 +274,38 @@
     msg->result = ESUCCESS;
 }

+void VirtualFileSystem::currentDirHandler(FileSystemMessage *msg)
+{
+    /* Only allow same owner. */
+    if (!(procs[msg->from].userID == 0 ||
+         (procs[msg->from].userID == procs[msg->procID].userID)))
+    {
+       msg->result = EPERM;
+       return;
+    }
+    /* Handle request. */
+    switch (msg->action)
+    {
+       case GetCurrentDir:
+           msg->result = VMCopy(msg->from, Write,
+                               (Address) procs[msg->procID].currentDir,
+                               (Address) msg->buffer, PATHLEN);
+           break;
+       
+       case SetCurrentDir:
+           msg->result = VMCopy(msg->from, Read,
+                               (Address) procs[msg->procID].currentDir,
+                               (Address) msg->buffer, PATHLEN);
+       default:
+           break;
+    }
+    /* Mark with ESUCCESS? */
+    if (msg->result > 0)
+    {
+       msg->size   = msg->result;
+       msg->result = ESUCCESS;
+    }
+}

 void VirtualFileSystem::insertMount(char *path, ProcessID pid, ulong opts)
 {
@@ -299,11 +322,28 @@
     }
 }

-FileSystemMount * VirtualFileSystem::findMount(char *path)
+FileSystemMount * VirtualFileSystem::findMount(FileSystemMessage *msg)
 {
-    Size length = 0, len;
     FileSystemMount *m = ZERO;
+    Size length = 0, len;
+    char path[PATHLEN], tmp[PATHLEN];

+    /* Obtain full path first. */
+    if (VMCopy(msg->procID, Read, (Address) path,
+             (Address) msg->buffer, PATHLEN) < 0)
+    {
+       return ZERO;
+    }
+    /* Force string terminate. */
+    path[PATHLEN-1] = ZERO;
+
+    /* Is the path relative? */
+    if (path[0] != '/')
+    {
+       snprintf(tmp, sizeof(tmp), "%s/%s",
+                procs[msg->procID].currentDir, path);
+       strlcpy(path, tmp, PATHLEN);
+    }
     /* Find the longest match. */
     for (Size i = 0; i < MAX_MOUNTS; i++)
     {
@@ -322,5 +362,6 @@
            }
        }
     }
+    /* All done. */
     return m;
 }

Modified: trunk/srv/filesystem/virtual/VirtualFileSystem.h
==============================================================================
--- trunk/srv/filesystem/virtual/VirtualFileSystem.h    (original)
+++ trunk/srv/filesystem/virtual/VirtualFileSystem.h Fri Jul 10 09:07:14 2009
@@ -90,13 +90,8 @@
     /** Total number of open files. */
     Size fileCount;

-    /** Current working directory.
-     char curdir[len];
-     */
-
-    /** Root directory
-     char rootdir[len];
-      */
+    /** Current working directory. */
+    char currentDir[PATHLEN];
 }
 UserProcessFSEntry;

@@ -151,6 +146,12 @@
        void killProcessHandler(FileSystemMessage *msg);

        /**
+        * Get or set the current directory.
+        * @param msg Input message.
+        */
+       void currentDirHandler(FileSystemMessage *msg);
+
+       /**
         * Creats a new mount.
         * @param path Full path of the new mount.
         * @param pid Process which handles the mountpoint.
@@ -160,10 +161,10 @@

        /**
         * Lookup the mount for a given path.
-        * @param path Path of the mountpoint to find.
+        * @param msg Message containing a path pointer.
         * @return Pointer to mount if found, ZERO otherwise.
         */
-       FileSystemMount * findMount(char *path);
+       FileSystemMount * findMount(FileSystemMessage *msg);
        
        /** Mounted filesystems. */
        static FileSystemMount mounts[MAX_MOUNTS];

Other related posts:

  • » [freenos] [freenos commit] r225 - Implemented the notion of current directory in the VirtualFileSystem. - codesite-noreply