return -EFAULT;
        }
 
-       return do_utimes(filename, tvs ? ktvs : NULL);
+       return do_utimes(AT_FDCWD, filename, tvs ? ktvs : NULL);
 }
 
 #define MAX_SELECT_SECONDS \
 
                        return -EFAULT;
        }
 
-       return do_utimes(filename, (tvs ? &ktvs[0] : NULL));
+       return do_utimes(AT_FDCWD, filename, (tvs ? &ktvs[0] : NULL));
 }
 
 /* These are here just in case some old sparc32 binary calls it. */
 asmlinkage long sparc32_open(const char __user *filename,
                             int flags, int mode)
 {
-       return do_sys_open(filename, flags, mode);
+       return do_sys_open(AT_FDCWD, filename, flags, mode);
 }
 
 extern unsigned long do_mremap(unsigned long addr,
 
                tv[0].tv_usec = 0;
                tv[1].tv_usec = 0;
        }
-       return do_utimes(filename, t ? tv : NULL);
+       return do_utimes(AT_FDCWD, filename, t ? tv : NULL);
 }
 
-asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval __user *t)
+asmlinkage long compat_sys_futimesat(int dfd, char __user *filename, struct compat_timeval __user *t)
 {
        struct timeval tv[2];
 
                    get_user(tv[1].tv_usec, &t[1].tv_usec))
                        return -EFAULT; 
        } 
-       return do_utimes(filename, t ? tv : NULL);
+       return do_utimes(dfd, filename, t ? tv : NULL);
+}
+
+asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval __user *t)
+{
+       return compat_sys_futimesat(AT_FDCWD, filename, t);
 }
 
 asmlinkage long compat_sys_newstat(char __user * filename,
                struct compat_stat __user *statbuf)
 {
        struct kstat stat;
-       int error = vfs_stat(filename, &stat);
+       int error = vfs_stat_fd(AT_FDCWD, filename, &stat);
 
        if (!error)
                error = cp_compat_stat(&stat, statbuf);
                struct compat_stat __user *statbuf)
 {
        struct kstat stat;
-       int error = vfs_lstat(filename, &stat);
+       int error = vfs_lstat_fd(AT_FDCWD, filename, &stat);
 
        if (!error)
                error = cp_compat_stat(&stat, statbuf);
        return error;
 }
 
+asmlinkage long compat_sys_newfstatat(int dfd, char __user *filename,
+               struct compat_stat __user *statbuf, int flag)
+{
+       struct kstat stat;
+       int error = -EINVAL;
+
+       if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
+               goto out;
+
+       if (flag & AT_SYMLINK_NOFOLLOW)
+               error = vfs_lstat_fd(dfd, filename, &stat);
+       else
+               error = vfs_stat_fd(dfd, filename, &stat);
+
+       if (!error)
+               error = cp_compat_stat(&stat, statbuf);
+
+out:
+       return error;
+}
+
 asmlinkage long compat_sys_newfstat(unsigned int fd,
                struct compat_stat __user * statbuf)
 {
 asmlinkage long
 compat_sys_open(const char __user *filename, int flags, int mode)
 {
-       return do_sys_open(filename, flags, mode);
+       return do_sys_open(AT_FDCWD, filename, flags, mode);
+}
+
+/*
+ * Exactly like fs/open.c:sys_openat(), except that it doesn't set the
+ * O_LARGEFILE flag.
+ */
+asmlinkage long
+compat_sys_openat(int dfd, const char __user *filename, int flags, int mode)
+{
+       return do_sys_open(dfd, filename, flags, mode);
 }
 
 /*
 
        int err;
        struct file *file;
 
-       err = path_lookup_open(name, LOOKUP_FOLLOW, &nd, FMODE_READ);
+       err = path_lookup_open(AT_FDCWD, name, LOOKUP_FOLLOW, &nd, FMODE_READ);
        file = ERR_PTR(err);
 
        if (!err) {
 
 #include <linux/audit.h>
 #include <linux/capability.h>
 #include <linux/file.h>
+#include <linux/fcntl.h>
+#include <linux/namei.h>
 #include <asm/namei.h>
 #include <asm/uaccess.h>
 
 }
 
 /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */
-int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata *nd)
+static int fastcall do_path_lookup(int dfd, const char *name,
+                               unsigned int flags, struct nameidata *nd)
 {
        int retval = 0;
 
                }
                nd->mnt = mntget(current->fs->rootmnt);
                nd->dentry = dget(current->fs->root);
-       } else {
+       } else if (dfd == AT_FDCWD) {
                nd->mnt = mntget(current->fs->pwdmnt);
                nd->dentry = dget(current->fs->pwd);
+       } else {
+               struct file *file;
+               int fput_needed;
+               struct dentry *dentry;
+
+               file = fget_light(dfd, &fput_needed);
+               if (!file) {
+                       retval = -EBADF;
+                       goto out_fail;
+               }
+
+               dentry = file->f_dentry;
+
+               if (!S_ISDIR(dentry->d_inode->i_mode)) {
+                       retval = -ENOTDIR;
+                       fput_light(file, fput_needed);
+                       goto out_fail;
+               }
+
+               retval = file_permission(file, MAY_EXEC);
+               if (retval) {
+                       fput_light(file, fput_needed);
+                       goto out_fail;
+               }
+
+               nd->mnt = mntget(file->f_vfsmnt);
+               nd->dentry = dget(dentry);
+
+               fput_light(file, fput_needed);
        }
        read_unlock(¤t->fs->lock);
        current->total_link_count = 0;
        if (unlikely(current->audit_context
                     && nd && nd->dentry && nd->dentry->d_inode))
                audit_inode(name, nd->dentry->d_inode, flags);
+out_fail:
        return retval;
 }
 
-static int __path_lookup_intent_open(const char *name, unsigned int lookup_flags,
-               struct nameidata *nd, int open_flags, int create_mode)
+int fastcall path_lookup(const char *name, unsigned int flags,
+                       struct nameidata *nd)
+{
+       return do_path_lookup(AT_FDCWD, name, flags, nd);
+}
+
+static int __path_lookup_intent_open(int dfd, const char *name,
+               unsigned int lookup_flags, struct nameidata *nd,
+               int open_flags, int create_mode)
 {
        struct file *filp = get_empty_filp();
        int err;
        nd->intent.open.file = filp;
        nd->intent.open.flags = open_flags;
        nd->intent.open.create_mode = create_mode;
-       err = path_lookup(name, lookup_flags|LOOKUP_OPEN, nd);
+       err = do_path_lookup(dfd, name, lookup_flags|LOOKUP_OPEN, nd);
        if (IS_ERR(nd->intent.open.file)) {
                if (err == 0) {
                        err = PTR_ERR(nd->intent.open.file);
  * @nd: pointer to nameidata
  * @open_flags: open intent flags
  */
-int path_lookup_open(const char *name, unsigned int lookup_flags,
+int path_lookup_open(int dfd, const char *name, unsigned int lookup_flags,
                struct nameidata *nd, int open_flags)
 {
-       return __path_lookup_intent_open(name, lookup_flags, nd,
+       return __path_lookup_intent_open(dfd, name, lookup_flags, nd,
                        open_flags, 0);
 }
 
  * @open_flags: open intent flags
  * @create_mode: create intent flags
  */
-static int path_lookup_create(const char *name, unsigned int lookup_flags,
-                             struct nameidata *nd, int open_flags,
-                             int create_mode)
+static int path_lookup_create(int dfd, const char *name,
+                             unsigned int lookup_flags, struct nameidata *nd,
+                             int open_flags, int create_mode)
 {
-       return __path_lookup_intent_open(name, lookup_flags|LOOKUP_CREATE, nd,
-                       open_flags, create_mode);
+       return __path_lookup_intent_open(dfd, name, lookup_flags|LOOKUP_CREATE,
+                       nd, open_flags, create_mode);
 }
 
 int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags,
        int err = PTR_ERR(tmp);
 
        if (!IS_ERR(tmp)) {
-               err = __path_lookup_intent_open(tmp, lookup_flags, nd, open_flags, 0);
+               err = __path_lookup_intent_open(AT_FDCWD, tmp, lookup_flags, nd, open_flags, 0);
                putname(tmp);
        }
        return err;
  * that namei follows links, while lnamei does not.
  * SMP-safe
  */
-int fastcall __user_walk(const char __user *name, unsigned flags, struct nameidata *nd)
+int fastcall __user_walk_fd(int dfd, const char __user *name, unsigned flags,
+                           struct nameidata *nd)
 {
        char *tmp = getname(name);
        int err = PTR_ERR(tmp);
 
        if (!IS_ERR(tmp)) {
-               err = path_lookup(tmp, flags, nd);
+               err = do_path_lookup(dfd, tmp, flags, nd);
                putname(tmp);
        }
        return err;
 }
 
+int fastcall __user_walk(const char __user *name, unsigned flags, struct nameidata *nd)
+{
+       return __user_walk_fd(AT_FDCWD, name, flags, nd);
+}
+
 /*
  * It's inline, so penalty for filesystems that don't use sticky bit is
  * minimal.
  * for symlinks (where the permissions are checked later).
  * SMP-safe
  */
-int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
+int open_namei(int dfd, const char *pathname, int flag,
+               int mode, struct nameidata *nd)
 {
        int acc_mode, error;
        struct path path;
         * The simplest case - just a plain lookup.
         */
        if (!(flag & O_CREAT)) {
-               error = path_lookup_open(pathname, lookup_flags(flag), nd, flag);
+               error = path_lookup_open(dfd, pathname, lookup_flags(flag),
+                                        nd, flag);
                if (error)
                        return error;
                goto ok;
        /*
         * Create - we need to know the parent.
         */
-       error = path_lookup_create(pathname, LOOKUP_PARENT, nd, flag, mode);
+       error = path_lookup_create(dfd,pathname,LOOKUP_PARENT,nd,flag,mode);
        if (error)
                return error;
 
        return error;
 }
 
-asmlinkage long sys_mknod(const char __user * filename, int mode, unsigned dev)
+asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode,
+                               unsigned dev)
 {
        int error = 0;
        char * tmp;
        if (IS_ERR(tmp))
                return PTR_ERR(tmp);
 
-       error = path_lookup(tmp, LOOKUP_PARENT, &nd);
+       error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd);
        if (error)
                goto out;
        dentry = lookup_create(&nd, 0);
        return error;
 }
 
+asmlinkage long sys_mknod(const char __user *filename, int mode, unsigned dev)
+{
+       return sys_mknodat(AT_FDCWD, filename, mode, dev);
+}
+
 int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
 {
        int error = may_create(dir, dentry, NULL);
        return error;
 }
 
-asmlinkage long sys_mkdir(const char __user * pathname, int mode)
+asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, int mode)
 {
        int error = 0;
        char * tmp;
                struct dentry *dentry;
                struct nameidata nd;
 
-               error = path_lookup(tmp, LOOKUP_PARENT, &nd);
+               error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd);
                if (error)
                        goto out;
                dentry = lookup_create(&nd, 1);
        return error;
 }
 
+asmlinkage long sys_mkdir(const char __user *pathname, int mode)
+{
+       return sys_mkdirat(AT_FDCWD, pathname, mode);
+}
+
 /*
  * We try to drop the dentry early: we should have
  * a usage count of 2 if we're the only user of this
        return error;
 }
 
-asmlinkage long sys_rmdir(const char __user * pathname)
+static long do_rmdir(int dfd, const char __user *pathname)
 {
        int error = 0;
        char * name;
        if(IS_ERR(name))
                return PTR_ERR(name);
 
-       error = path_lookup(name, LOOKUP_PARENT, &nd);
+       error = do_path_lookup(dfd, name, LOOKUP_PARENT, &nd);
        if (error)
                goto exit;
 
        return error;
 }
 
+asmlinkage long sys_rmdir(const char __user *pathname)
+{
+       return do_rmdir(AT_FDCWD, pathname);
+}
+
 int vfs_unlink(struct inode *dir, struct dentry *dentry)
 {
        int error = may_delete(dir, dentry, 0);
  * writeout happening, and we don't want to prevent access to the directory
  * while waiting on the I/O.
  */
-asmlinkage long sys_unlink(const char __user * pathname)
+static long do_unlinkat(int dfd, const char __user *pathname)
 {
        int error = 0;
        char * name;
        if(IS_ERR(name))
                return PTR_ERR(name);
 
-       error = path_lookup(name, LOOKUP_PARENT, &nd);
+       error = do_path_lookup(dfd, name, LOOKUP_PARENT, &nd);
        if (error)
                goto exit;
        error = -EISDIR;
        goto exit2;
 }
 
+asmlinkage long sys_unlinkat(int dfd, const char __user *pathname, int flag)
+{
+       if ((flag & ~AT_REMOVEDIR) != 0)
+               return -EINVAL;
+
+       if (flag & AT_REMOVEDIR)
+               return do_rmdir(dfd, pathname);
+
+       return do_unlinkat(dfd, pathname);
+}
+
+asmlinkage long sys_unlink(const char __user *pathname)
+{
+       return do_unlinkat(AT_FDCWD, pathname);
+}
+
 int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, int mode)
 {
        int error = may_create(dir, dentry, NULL);
        return error;
 }
 
-asmlinkage long sys_symlink(const char __user * oldname, const char __user * newname)
+asmlinkage long sys_symlinkat(const char __user *oldname,
+                             int newdfd, const char __user *newname)
 {
        int error = 0;
        char * from;
                struct dentry *dentry;
                struct nameidata nd;
 
-               error = path_lookup(to, LOOKUP_PARENT, &nd);
+               error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd);
                if (error)
                        goto out;
                dentry = lookup_create(&nd, 0);
        return error;
 }
 
+asmlinkage long sys_symlink(const char __user *oldname, const char __user *newname)
+{
+       return sys_symlinkat(oldname, AT_FDCWD, newname);
+}
+
 int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
 {
        struct inode *inode = old_dentry->d_inode;
  * with linux 2.0, and to avoid hard-linking to directories
  * and other special files.  --ADM
  */
-asmlinkage long sys_link(const char __user * oldname, const char __user * newname)
+asmlinkage long sys_linkat(int olddfd, const char __user *oldname,
+                          int newdfd, const char __user *newname)
 {
        struct dentry *new_dentry;
        struct nameidata nd, old_nd;
        if (IS_ERR(to))
                return PTR_ERR(to);
 
-       error = __user_walk(oldname, 0, &old_nd);
+       error = __user_walk_fd(olddfd, oldname, 0, &old_nd);
        if (error)
                goto exit;
-       error = path_lookup(to, LOOKUP_PARENT, &nd);
+       error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd);
        if (error)
                goto out;
        error = -EXDEV;
        return error;
 }
 
+asmlinkage long sys_link(const char __user *oldname, const char __user *newname)
+{
+       return sys_linkat(AT_FDCWD, oldname, AT_FDCWD, newname);
+}
+
 /*
  * The worst of all namespace operations - renaming directory. "Perverted"
  * doesn't even start to describe it. Somebody in UCB had a heck of a trip...
        return error;
 }
 
-static int do_rename(const char * oldname, const char * newname)
+static int do_rename(int olddfd, const char *oldname,
+                       int newdfd, const char *newname)
 {
        int error = 0;
        struct dentry * old_dir, * new_dir;
        struct dentry * trap;
        struct nameidata oldnd, newnd;
 
-       error = path_lookup(oldname, LOOKUP_PARENT, &oldnd);
+       error = do_path_lookup(olddfd, oldname, LOOKUP_PARENT, &oldnd);
        if (error)
                goto exit;
 
-       error = path_lookup(newname, LOOKUP_PARENT, &newnd);
+       error = do_path_lookup(newdfd, newname, LOOKUP_PARENT, &newnd);
        if (error)
                goto exit1;
 
        return error;
 }
 
-asmlinkage long sys_rename(const char __user * oldname, const char __user * newname)
+asmlinkage long sys_renameat(int olddfd, const char __user *oldname,
+                            int newdfd, const char __user *newname)
 {
        int error;
        char * from;
        to = getname(newname);
        error = PTR_ERR(to);
        if (!IS_ERR(to)) {
-               error = do_rename(from,to);
+               error = do_rename(olddfd, from, newdfd, to);
                putname(to);
        }
        putname(from);
        return error;
 }
 
+asmlinkage long sys_rename(const char __user *oldname, const char __user *newname)
+{
+       return sys_renameat(AT_FDCWD, oldname, AT_FDCWD, newname);
+}
+
 int vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen, const char *link)
 {
        int len;
 };
 
 EXPORT_SYMBOL(__user_walk);
+EXPORT_SYMBOL(__user_walk_fd);
 EXPORT_SYMBOL(follow_down);
 EXPORT_SYMBOL(follow_up);
 EXPORT_SYMBOL(get_write_access); /* binfmt_aout */
 
 #include <linux/security.h>
 #include <linux/mount.h>
 #include <linux/vfs.h>
+#include <linux/fcntl.h>
 #include <asm/uaccess.h>
 #include <linux/fs.h>
 #include <linux/personality.h>
 
                error = get_user(newattrs.ia_atime.tv_sec, ×->actime);
                newattrs.ia_atime.tv_nsec = 0;
-               if (!error) 
+               if (!error)
                        error = get_user(newattrs.ia_mtime.tv_sec, ×->modtime);
                newattrs.ia_mtime.tv_nsec = 0;
                if (error)
  * must be owner or have write permission.
  * Else, update from *times, must be owner or super user.
  */
-long do_utimes(char __user * filename, struct timeval * times)
+long do_utimes(int dfd, char __user *filename, struct timeval *times)
 {
        int error;
        struct nameidata nd;
        struct inode * inode;
        struct iattr newattrs;
 
-       error = user_path_walk(filename, &nd);
+       error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
 
        if (error)
                goto out;
        return error;
 }
 
-asmlinkage long sys_utimes(char __user * filename, struct timeval __user * utimes)
+asmlinkage long sys_futimesat(int dfd, char __user *filename, struct timeval __user *utimes)
 {
        struct timeval times[2];
 
        if (utimes && copy_from_user(×, utimes, sizeof(times)))
                return -EFAULT;
-       return do_utimes(filename, utimes ? times : NULL);
+       return do_utimes(dfd, filename, utimes ? times : NULL);
+}
+
+asmlinkage long sys_utimes(char __user *filename, struct timeval __user *utimes)
+{
+       return sys_futimesat(AT_FDCWD, filename, utimes);
 }
 
 
  * We do this by temporarily clearing all FS-related capabilities and
  * switching the fsuid/fsgid around to the real ones.
  */
-asmlinkage long sys_access(const char __user * filename, int mode)
+asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
 {
        struct nameidata nd;
        int old_fsuid, old_fsgid;
        else
                current->cap_effective = current->cap_permitted;
 
-       res = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd);
+       res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd);
        if (!res) {
                res = vfs_permission(&nd, mode);
                /* SuS v2 requires we report a read only fs too */
        return res;
 }
 
+asmlinkage long sys_access(const char __user *filename, int mode)
+{
+       return sys_faccessat(AT_FDCWD, filename, mode);
+}
+
 asmlinkage long sys_chdir(const char __user * filename)
 {
        struct nameidata nd;
        return err;
 }
 
-asmlinkage long sys_chmod(const char __user * filename, mode_t mode)
+asmlinkage long sys_fchmodat(int dfd, const char __user *filename,
+                            mode_t mode)
 {
        struct nameidata nd;
        struct inode * inode;
        int error;
        struct iattr newattrs;
 
-       error = user_path_walk(filename, &nd);
+       error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
        if (error)
                goto out;
        inode = nd.dentry->d_inode;
        return error;
 }
 
+asmlinkage long sys_chmod(const char __user *filename, mode_t mode)
+{
+       return sys_fchmodat(AT_FDCWD, filename, mode);
+}
+
 static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
 {
        struct inode * inode;
        return error;
 }
 
+asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user,
+                            gid_t group, int flag)
+{
+       struct nameidata nd;
+       int error = -EINVAL;
+       int follow;
+
+       if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
+               goto out;
+
+       follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
+       error = __user_walk_fd(dfd, filename, follow, &nd);
+       if (!error) {
+               error = chown_common(nd.dentry, user, group);
+               path_release(&nd);
+       }
+out:
+       return error;
+}
+
 asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group)
 {
        struct nameidata nd;
  * for the internal routines (ie open_namei()/follow_link() etc). 00 is
  * used by symlinks.
  */
-struct file *filp_open(const char * filename, int flags, int mode)
+static struct file *do_filp_open(int dfd, const char *filename, int flags,
+                                int mode)
 {
        int namei_flags, error;
        struct nameidata nd;
        if ((namei_flags+1) & O_ACCMODE)
                namei_flags++;
 
-       error = open_namei(filename, namei_flags, mode, &nd);
+       error = open_namei(dfd, filename, namei_flags, mode, &nd);
        if (!error)
                return nameidata_to_filp(&nd, flags);
 
        return ERR_PTR(error);
 }
+
+struct file *filp_open(const char *filename, int flags, int mode)
+{
+       return do_filp_open(AT_FDCWD, filename, flags, mode);
+}
 EXPORT_SYMBOL(filp_open);
 
 /**
 EXPORT_SYMBOL(put_unused_fd);
 
 /*
- * Install a file pointer in the fd array.  
+ * Install a file pointer in the fd array.
  *
  * The VFS is full of places where we drop the files lock between
  * setting the open_fds bitmap and installing the file in the file
 
 EXPORT_SYMBOL(fd_install);
 
-long do_sys_open(const char __user *filename, int flags, int mode)
+long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
 {
        char *tmp = getname(filename);
        int fd = PTR_ERR(tmp);
        if (!IS_ERR(tmp)) {
                fd = get_unused_fd();
                if (fd >= 0) {
-                       struct file *f = filp_open(tmp, flags, mode);
+                       struct file *f = do_filp_open(dfd, tmp, flags, mode);
                        if (IS_ERR(f)) {
                                put_unused_fd(fd);
                                fd = PTR_ERR(f);
        if (force_o_largefile())
                flags |= O_LARGEFILE;
 
-       return do_sys_open(filename, flags, mode);
+       return do_sys_open(AT_FDCWD, filename, flags, mode);
 }
 EXPORT_SYMBOL_GPL(sys_open);
 
+asmlinkage long sys_openat(int dfd, const char __user *filename, int flags,
+                          int mode)
+{
+       if (force_o_largefile())
+               flags |= O_LARGEFILE;
+
+       return do_sys_open(dfd, filename, flags, mode);
+}
+EXPORT_SYMBOL_GPL(sys_openat);
+
 #ifndef __alpha__
 
 /*
 
 
 EXPORT_SYMBOL(vfs_getattr);
 
-int vfs_stat(char __user *name, struct kstat *stat)
+int vfs_stat_fd(int dfd, char __user *name, struct kstat *stat)
 {
        struct nameidata nd;
        int error;
 
-       error = user_path_walk(name, &nd);
+       error = __user_walk_fd(dfd, name, LOOKUP_FOLLOW, &nd);
        if (!error) {
                error = vfs_getattr(nd.mnt, nd.dentry, stat);
                path_release(&nd);
        return error;
 }
 
+int vfs_stat(char __user *name, struct kstat *stat)
+{
+       return vfs_stat_fd(AT_FDCWD, name, stat);
+}
+
 EXPORT_SYMBOL(vfs_stat);
 
-int vfs_lstat(char __user *name, struct kstat *stat)
+int vfs_lstat_fd(int dfd, char __user *name, struct kstat *stat)
 {
        struct nameidata nd;
        int error;
 
-       error = user_path_walk_link(name, &nd);
+       error = __user_walk_fd(dfd, name, 0, &nd);
        if (!error) {
                error = vfs_getattr(nd.mnt, nd.dentry, stat);
                path_release(&nd);
        return error;
 }
 
+int vfs_lstat(char __user *name, struct kstat *stat)
+{
+       return vfs_lstat_fd(AT_FDCWD, name, stat);
+}
+
 EXPORT_SYMBOL(vfs_lstat);
 
 int vfs_fstat(unsigned int fd, struct kstat *stat)
 asmlinkage long sys_stat(char __user * filename, struct __old_kernel_stat __user * statbuf)
 {
        struct kstat stat;
-       int error = vfs_stat(filename, &stat);
+       int error = vfs_stat_fd(AT_FDCWD, filename, &stat);
 
        if (!error)
                error = cp_old_stat(&stat, statbuf);
 asmlinkage long sys_lstat(char __user * filename, struct __old_kernel_stat __user * statbuf)
 {
        struct kstat stat;
-       int error = vfs_lstat(filename, &stat);
+       int error = vfs_lstat_fd(AT_FDCWD, filename, &stat);
 
        if (!error)
                error = cp_old_stat(&stat, statbuf);
        return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
 }
 
-asmlinkage long sys_newstat(char __user * filename, struct stat __user * statbuf)
+asmlinkage long sys_newstat(char __user *filename, struct stat __user *statbuf)
 {
        struct kstat stat;
-       int error = vfs_stat(filename, &stat);
+       int error = vfs_stat_fd(AT_FDCWD, filename, &stat);
 
        if (!error)
                error = cp_new_stat(&stat, statbuf);
 
        return error;
 }
-asmlinkage long sys_newlstat(char __user * filename, struct stat __user * statbuf)
+
+asmlinkage long sys_newlstat(char __user *filename, struct stat __user *statbuf)
 {
        struct kstat stat;
-       int error = vfs_lstat(filename, &stat);
+       int error = vfs_lstat_fd(AT_FDCWD, filename, &stat);
 
        if (!error)
                error = cp_new_stat(&stat, statbuf);
 
        return error;
 }
-asmlinkage long sys_newfstat(unsigned int fd, struct stat __user * statbuf)
+
+asmlinkage long sys_newfstatat(int dfd, char __user *filename,
+                               struct stat __user *statbuf, int flag)
+{
+       struct kstat stat;
+       int error = -EINVAL;
+
+       if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
+               goto out;
+
+       if (flag & AT_SYMLINK_NOFOLLOW)
+               error = vfs_lstat_fd(dfd, filename, &stat);
+       else
+               error = vfs_stat_fd(dfd, filename, &stat);
+
+       if (!error)
+               error = cp_new_stat(&stat, statbuf);
+
+out:
+       return error;
+}
+
+asmlinkage long sys_newfstat(unsigned int fd, struct stat __user *statbuf)
 {
        struct kstat stat;
        int error = vfs_fstat(fd, &stat);
        return error;
 }
 
-asmlinkage long sys_readlink(const char __user * path, char __user * buf, int bufsiz)
+asmlinkage long sys_readlinkat(int dfd, const char __user *path,
+                               char __user *buf, int bufsiz)
 {
        struct nameidata nd;
        int error;
        if (bufsiz <= 0)
                return -EINVAL;
 
-       error = user_path_walk_link(path, &nd);
+       error = __user_walk_fd(dfd, path, 0, &nd);
        if (!error) {
                struct inode * inode = nd.dentry->d_inode;
 
        return error;
 }
 
+asmlinkage long sys_readlink(const char __user *path, char __user *buf,
+                               int bufsiz)
+{
+       return sys_readlinkat(AT_FDCWD, path, buf, bufsiz);
+}
+
 
 /* ---------- LFS-64 ----------- */
 #ifdef __ARCH_WANT_STAT64
 
 #define DN_ATTRIB      0x00000020      /* File changed attibutes */
 #define DN_MULTISHOT   0x80000000      /* Don't remove notifier */
 
+#define AT_FDCWD               -100    /* Special value used to indicate
+                                           openat should use the current
+                                           working directory. */
+#define AT_SYMLINK_NOFOLLOW    0x100   /* Do not follow symbolic links.  */
+#define AT_REMOVEDIR           0x200   /* Remove directory instead of
+                                           unlinking file.  */
+
 #ifdef __KERNEL__
 
 #ifndef force_o_largefile
 
 
 extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
                       struct file *filp);
-extern long do_sys_open(const char __user *filename, int flags, int mode);
+extern long do_sys_open(int fdf, const char __user *filename, int flags,
+                       int mode);
 extern struct file *filp_open(const char *, int, int);
 extern struct file * dentry_open(struct dentry *, struct vfsmount *, int);
 extern int filp_close(struct file *, fl_owner_t id);
 }
 extern int do_pipe(int *);
 
-extern int open_namei(const char *, int, int, struct nameidata *);
+extern int open_namei(int dfd, const char *, int, int, struct nameidata *);
 extern int may_open(struct nameidata *, int, int);
 
 extern int kernel_read(struct file *, unsigned long, char *, unsigned long);
 
 extern int vfs_stat(char __user *, struct kstat *);
 extern int vfs_lstat(char __user *, struct kstat *);
+extern int vfs_stat_fd(int dfd, char __user *, struct kstat *);
+extern int vfs_lstat_fd(int dfd, char __user *, struct kstat *);
 extern int vfs_fstat(unsigned int, struct kstat *);
 
 extern int vfs_ioctl(struct file *, unsigned int, unsigned int, unsigned long);
 
 #define LOOKUP_ACCESS          (0x0400)
 
 extern int FASTCALL(__user_walk(const char __user *, unsigned, struct nameidata *));
+extern int FASTCALL(__user_walk_fd(int dfd, const char __user *, unsigned, struct nameidata *));
 #define user_path_walk(name,nd) \
-       __user_walk(name, LOOKUP_FOLLOW, nd)
+       __user_walk_fd(AT_FDCWD, name, LOOKUP_FOLLOW, nd)
 #define user_path_walk_link(name,nd) \
-       __user_walk(name, 0, nd)
+       __user_walk_fd(AT_FDCWD, name, 0, nd)
 extern int FASTCALL(path_lookup(const char *, unsigned, struct nameidata *));
 extern int FASTCALL(path_walk(const char *, struct nameidata *));
 extern int FASTCALL(link_path_walk(const char *, struct nameidata *));
 extern void path_release_on_umount(struct nameidata *);
 
 extern int __user_path_lookup_open(const char __user *, unsigned lookup_flags, struct nameidata *nd, int open_flags);
-extern int path_lookup_open(const char *, unsigned lookup_flags, struct nameidata *, int open_flags);
+extern int path_lookup_open(int dfd, const char *name, unsigned lookup_flags, struct nameidata *, int open_flags);
 extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry,
                int (*open)(struct inode *, struct file *));
 extern struct file *nameidata_to_filp(struct nameidata *nd, int flags);
 
 extern int do_settimeofday(struct timespec *tv);
 extern int do_sys_settimeofday(struct timespec *tv, struct timezone *tz);
 #define do_posix_clock_monotonic_gettime(ts) ktime_get_ts(ts)
-extern long do_utimes(char __user *filename, struct timeval *times);
+extern long do_utimes(int dfd, char __user *filename, struct timeval *times);
 struct itimerval;
 extern int do_setitimer(int which, struct itimerval *value,
                        struct itimerval *ovalue);