func (fs *FileSystem) lastDir(proc *Process, path string) (*common.Inode, string, error) { var rip *common.Inode if filepath.IsAbs(path) { rip = proc.rootdir } else { rip = proc.workdir } // If directory has been removed or path is empty, return ENOENT if rip.Nlinks == 0 || len(path) == 0 { return nil, "", common.ENOENT } // We're going to use this inode, so make a copy of it rip = fs.itable.DupInode(rip) pathlist := strings.Split(path, string(filepath.Separator)) if filepath.IsAbs(path) { pathlist = pathlist[1:] } // Scan the path component by component for i := 0; i < len(pathlist)-1; i++ { // Fetch the next component in the path newrip, err := fs.advance(proc, rip, pathlist[i]) // Current inode obsolete or irrelevant fs.itable.PutInode(rip) if newrip == nil || err != nil { return nil, "", common.ENOENT } // Continue to the next component rip = newrip } if rip.Type() != common.I_DIRECTORY { // The penultimate path entry was not a directory, so return nil fs.itable.PutInode(rip) return nil, "", common.ENOTDIR } return rip, pathlist[len(pathlist)-1], nil }
func (fs *FileSystem) do_open(proc *Process, path string, oflags int, omode uint16) (common.Fd, error) { // Remap the bottom two bits of oflags bits := mode_map[oflags&common.O_ACCMODE] var err error var rip *common.Inode var exist bool = false // If O_CREATE is set, try to make the file if oflags&common.O_CREAT > 0 { // Create a new node by calling new_node() omode := common.I_REGULAR | (omode & common.ALL_MODES & proc.umask) dirp, newrip, _, err := fs.new_node(proc, path, omode, common.NO_ZONE) if err == nil { exist = false } else if err != common.EEXIST { return nil, err } else { exist = (oflags&common.O_EXCL == 0) } // we don't need the parent directory fs.itable.PutInode(dirp) rip = newrip } else { // grab the inode at the given path rip, err = fs.eatPath(proc, path) if err != nil { return nil, err } } // Find an available filp entry for the file descriptor fdindex := -1 for i := 0; i < len(proc.files); i++ { if proc.files[i] == nil { fdindex = i break } } if fdindex == -1 { return nil, common.EMFILE } err = nil // we'll use this to set error codes if exist { // if the file existed already // TODO: Check permissions here switch rip.Type() { case common.I_REGULAR: if oflags&common.O_TRUNC > 0 { common.Truncate(rip, 0, fs.bcache) // Flush the inode so it gets written on next block cache fs.itable.FlushInode(rip) } case common.I_DIRECTORY: // Directories cannot be opened in this system err = common.EISDIR default: panic("NYI: Process.Open with non regular/directory") } } if err != nil { // Something went wrong, so release the inode fs.itable.PutInode(rip) return nil, err } // Make sure there is a 'File' server running if rip.File == nil { // Spawn a file process to handle reading/writing rip.File = file.NewFile(rip) } // Create a new 'filp' object to expose to the user filp := &filp{1, 0, rip.File, rip, bits, new(sync.Mutex)} proc.files[fdindex] = filp return filp, nil }