| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: udf_vnops.c,v 1.46 2009/06/24 17:09:13 reinoud Exp $ */ | | 1 | /* $NetBSD: udf_vnops.c,v 1.47 2009/06/25 17:16:33 reinoud Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2006, 2008 Reinoud Zandijk | | 4 | * Copyright (c) 2006, 2008 Reinoud Zandijk |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -22,27 +22,27 @@ | | | @@ -22,27 +22,27 @@ |
22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | | 22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | | 23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | | 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | * | | 26 | * |
27 | * Generic parts are derived from software contributed to The NetBSD Foundation | | 27 | * Generic parts are derived from software contributed to The NetBSD Foundation |
28 | * by Julio M. Merino Vidal, developed as part of Google's Summer of Code | | 28 | * by Julio M. Merino Vidal, developed as part of Google's Summer of Code |
29 | * 2005 program. | | 29 | * 2005 program. |
30 | * | | 30 | * |
31 | */ | | 31 | */ |
32 | | | 32 | |
33 | #include <sys/cdefs.h> | | 33 | #include <sys/cdefs.h> |
34 | #ifndef lint | | 34 | #ifndef lint |
35 | __KERNEL_RCSID(0, "$NetBSD: udf_vnops.c,v 1.46 2009/06/24 17:09:13 reinoud Exp $"); | | 35 | __KERNEL_RCSID(0, "$NetBSD: udf_vnops.c,v 1.47 2009/06/25 17:16:33 reinoud Exp $"); |
36 | #endif /* not lint */ | | 36 | #endif /* not lint */ |
37 | | | 37 | |
38 | | | 38 | |
39 | #include <sys/param.h> | | 39 | #include <sys/param.h> |
40 | #include <sys/systm.h> | | 40 | #include <sys/systm.h> |
41 | #include <sys/namei.h> | | 41 | #include <sys/namei.h> |
42 | #include <sys/resourcevar.h> /* defines plimit structure in proc struct */ | | 42 | #include <sys/resourcevar.h> /* defines plimit structure in proc struct */ |
43 | #include <sys/kernel.h> | | 43 | #include <sys/kernel.h> |
44 | #include <sys/file.h> /* define FWRITE ... */ | | 44 | #include <sys/file.h> /* define FWRITE ... */ |
45 | #include <sys/stat.h> | | 45 | #include <sys/stat.h> |
46 | #include <sys/buf.h> | | 46 | #include <sys/buf.h> |
47 | #include <sys/proc.h> | | 47 | #include <sys/proc.h> |
48 | #include <sys/mount.h> | | 48 | #include <sys/mount.h> |
| @@ -1815,75 +1815,118 @@ udf_readlink(void *v) | | | @@ -1815,75 +1815,118 @@ udf_readlink(void *v) |
1815 | /* uiomove() to destination */ | | 1815 | /* uiomove() to destination */ |
1816 | if (!error) | | 1816 | if (!error) |
1817 | uiomove(targetbuf, PATH_MAX - targetlen, uio); | | 1817 | uiomove(targetbuf, PATH_MAX - targetlen, uio); |
1818 | | | 1818 | |
1819 | free(pathbuf, M_UDFTEMP); | | 1819 | free(pathbuf, M_UDFTEMP); |
1820 | free(targetbuf, M_UDFTEMP); | | 1820 | free(targetbuf, M_UDFTEMP); |
1821 | free(tmpname, M_UDFTEMP); | | 1821 | free(tmpname, M_UDFTEMP); |
1822 | | | 1822 | |
1823 | return error; | | 1823 | return error; |
1824 | } | | 1824 | } |
1825 | | | 1825 | |
1826 | /* --------------------------------------------------------------------- */ | | 1826 | /* --------------------------------------------------------------------- */ |
1827 | | | 1827 | |
| | | 1828 | /* |
| | | 1829 | * Check if source directory is in the path of the target directory. Target |
| | | 1830 | * is supplied locked, source is unlocked. The target is always vput before |
| | | 1831 | * returning. Modeled after UFS. |
| | | 1832 | * |
| | | 1833 | * If source is on the path from target to the root, return error. |
| | | 1834 | */ |
| | | 1835 | |
1828 | static int | | 1836 | static int |
1829 | udf_on_rootpath(struct udf_node *fnode, struct udf_node *tdnode) | | 1837 | udf_on_rootpath(struct udf_node *source, struct udf_node *target) |
1830 | { | | 1838 | { |
1831 | struct udf_mount *ump = tdnode->ump; | | 1839 | struct udf_mount *ump = target->ump; |
1832 | struct udf_node *res_node; | | 1840 | struct udf_node *res_node; |
1833 | struct long_ad icb_loc; | | 1841 | struct long_ad icb_loc, *root_icb; |
1834 | const char *name; | | 1842 | const char *name; |
1835 | int namelen; | | 1843 | int namelen; |
1836 | int error, found; | | 1844 | int error, found; |
1837 | | | 1845 | |
1838 | /* if fnode is on the path from tdnode to the root, return error */ | | 1846 | name = ".."; |
1839 | name = ".."; | | 1847 | namelen = 2; |
1840 | namelen = 2; | | 1848 | error = 0; |
1841 | while (fnode != tdnode) { | | 1849 | res_node = target; |
1842 | DPRINTF(NODE, ("udf_on_rootpath : fnode %p, tdnode %p\n", | | 1850 | |
1843 | fnode, tdnode)); | | 1851 | root_icb = &ump->fileset_desc->rootdir_icb; |
1844 | if (tdnode->vnode->v_vflag & VV_ROOT) { | | 1852 | |
1845 | /* found root, accept */ | | 1853 | /* if nodes are equal, it is no use looking */ |
1846 | /* DPRINTF(NODE, ("\tCOUGHT, pre-vput\n")); */ | | 1854 | if (udf_check_icb_equal(&source->loc, &target->loc)) { |
1847 | vput(tdnode->vnode); | | 1855 | error = EEXIST; |
1848 | DPRINTF(NODE, ("\tCOUGHT: valid\n")); | | 1856 | goto out; |
1849 | return 0; | | 1857 | } |
| | | 1858 | |
| | | 1859 | /* nothing can exist before the root */ |
| | | 1860 | if (udf_check_icb_equal(root_icb, &target->loc)) { |
| | | 1861 | error = 0; |
| | | 1862 | goto out; |
| | | 1863 | } |
| | | 1864 | |
| | | 1865 | for (;;) { |
| | | 1866 | DPRINTF(NODE, ("udf_on_rootpath : " |
| | | 1867 | "source vp %p, looking at vp %p\n", |
| | | 1868 | source->vnode, res_node->vnode)); |
| | | 1869 | |
| | | 1870 | /* sanity check */ |
| | | 1871 | if (res_node->vnode->v_type != VDIR) { |
| | | 1872 | error = ENOTDIR; |
| | | 1873 | goto out; |
1850 | } | | 1874 | } |
| | | 1875 | |
1851 | /* go down one level */ | | 1876 | /* go down one level */ |
1852 | error = udf_lookup_name_in_dir(tdnode->vnode, name, namelen, | | 1877 | error = udf_lookup_name_in_dir(res_node->vnode, name, namelen, |
1853 | &icb_loc, &found); | | 1878 | &icb_loc, &found); |
1854 | | | | |
1855 | DPRINTF(NODE, ("\tlookup of '..' resulted in error %d, " | | 1879 | DPRINTF(NODE, ("\tlookup of '..' resulted in error %d, " |
1856 | "found %d\n", error, found)); | | 1880 | "found %d\n", error, found)); |
1857 | /* DPRINTF(NODE, ("\tvput %p\n", tdnode->vnode)); */ | | | |
1858 | vput(tdnode->vnode); | | | |
1859 | | | 1881 | |
1860 | if (error) /* now what? bail out */ | | 1882 | if (!found) |
1861 | return EINVAL; | | 1883 | error = ENOENT; |
1862 | if (!found) /* unlikely */ | | 1884 | if (error) |
1863 | return EINVAL; | | 1885 | goto out; |
1864 | | | 1886 | |
1865 | DPRINTF(NODE, ("\tgetting .. node\n")); | | 1887 | /* did we encounter source node? */ |
| | | 1888 | if (udf_check_icb_equal(&icb_loc, &source->loc)) { |
| | | 1889 | error = EINVAL; |
| | | 1890 | goto out; |
| | | 1891 | } |
| | | 1892 | |
| | | 1893 | /* did we encounter the root node? */ |
| | | 1894 | if (udf_check_icb_equal(&icb_loc, root_icb)) { |
| | | 1895 | error = 0; |
| | | 1896 | goto out; |
| | | 1897 | } |
| | | 1898 | |
| | | 1899 | /* push our intermediate node, we're done with it */ |
| | | 1900 | /* DPRINTF(NODE, ("\tvput %p\n", target->vnode)); */ |
| | | 1901 | vput(res_node->vnode); |
| | | 1902 | |
| | | 1903 | DPRINTF(NODE, ("\tgetting the .. node\n")); |
1866 | error = udf_get_node(ump, &icb_loc, &res_node); | | 1904 | error = udf_get_node(ump, &icb_loc, &res_node); |
1867 | DPRINTF(NODE, ("\treported error %d\n", error)); | | | |
1868 | if (error) /* argh, bail out */ | | | |
1869 | return EINVAL; | | | |
1870 | | | 1905 | |
1871 | tdnode = res_node; | | 1906 | if (error) { /* argh, bail out */ |
| | | 1907 | KASSERT(res_node == NULL); |
| | | 1908 | // res_node = NULL; |
| | | 1909 | goto out; |
| | | 1910 | } |
1872 | } | | 1911 | } |
1873 | DPRINTF(NODE, ("\tCOUGHT: invalid\n")); | | 1912 | out: |
1874 | vput(tdnode->vnode); | | 1913 | DPRINTF(NODE, ("\tresult: %svalid, error = %d\n", error?"in":"", error)); |
1875 | | | 1914 | |
1876 | return EINVAL; | | 1915 | /* put our last node */ |
| | | 1916 | if (res_node) |
| | | 1917 | vput(res_node->vnode); |
| | | 1918 | |
| | | 1919 | return error; |
1877 | } | | 1920 | } |
1878 | | | 1921 | |
1879 | /* note: i tried to follow the logics of the tmpfs rename code */ | | 1922 | /* note: i tried to follow the logics of the tmpfs rename code */ |
1880 | int | | 1923 | int |
1881 | udf_rename(void *v) | | 1924 | udf_rename(void *v) |
1882 | { | | 1925 | { |
1883 | struct vop_rename_args /* { | | 1926 | struct vop_rename_args /* { |
1884 | struct vnode *a_fdvp; | | 1927 | struct vnode *a_fdvp; |
1885 | struct vnode *a_fvp; | | 1928 | struct vnode *a_fvp; |
1886 | struct componentname *a_fcnp; | | 1929 | struct componentname *a_fcnp; |
1887 | struct vnode *a_tdvp; | | 1930 | struct vnode *a_tdvp; |
1888 | struct vnode *a_tvp; | | 1931 | struct vnode *a_tvp; |
1889 | struct componentname *a_tcnp; | | 1932 | struct componentname *a_tcnp; |
| @@ -1940,35 +1983,58 @@ udf_rename(void *v) | | | @@ -1940,35 +1983,58 @@ udf_rename(void *v) |
1940 | if (fvp->v_type == VDIR && tvp->v_type != VDIR) { | | 1983 | if (fvp->v_type == VDIR && tvp->v_type != VDIR) { |
1941 | error = ENOTDIR; | | 1984 | error = ENOTDIR; |
1942 | goto out; | | 1985 | goto out; |
1943 | } | | 1986 | } |
1944 | /* if we're moving a non-directory, make sure dest is no dir */ | | 1987 | /* if we're moving a non-directory, make sure dest is no dir */ |
1945 | if (fvp->v_type != VDIR && tvp->v_type == VDIR) { | | 1988 | if (fvp->v_type != VDIR && tvp->v_type == VDIR) { |
1946 | error = EISDIR; | | 1989 | error = EISDIR; |
1947 | goto out; | | 1990 | goto out; |
1948 | } | | 1991 | } |
1949 | } | | 1992 | } |
1950 | | | 1993 | |
1951 | /* check if moving a directory to a new parent is allowed */ | | 1994 | /* check if moving a directory to a new parent is allowed */ |
1952 | if ((fdnode != tdnode) && (fvp->v_type == VDIR)) { | | 1995 | if ((fdnode != tdnode) && (fvp->v_type == VDIR)) { |
| | | 1996 | /* release tvp since we might encounter it and lock up */ |
| | | 1997 | if (tvp) |
| | | 1998 | vput(tvp); |
| | | 1999 | |
| | | 2000 | /* vref tdvp since we lose its ref in udf_on_rootpath */ |
1953 | vref(tdvp); | | 2001 | vref(tdvp); |
| | | 2002 | |
| | | 2003 | /* search if fnode is a component of tdnode's path to root */ |
1954 | error = udf_on_rootpath(fnode, tdnode); | | 2004 | error = udf_on_rootpath(fnode, tdnode); |
| | | 2005 | |
1955 | DPRINTF(NODE, ("Dir rename allowed ? %s\n", error ? "NO":"YES")); | | 2006 | DPRINTF(NODE, ("Dir rename allowed ? %s\n", error ? "NO":"YES")); |
1956 | | | 2007 | |
1957 | /* tdnode is vput()'ed, relock */ | | 2008 | if (error) { |
1958 | (void) vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY); | | 2009 | /* compensate for our vref earlier */ |
| | | 2010 | vrele(tdvp); |
| | | 2011 | goto out; |
| | | 2012 | } |
| | | 2013 | |
| | | 2014 | /* relock tdvp; its still here due to the vref earlier */ |
| | | 2015 | vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY); |
1959 | | | 2016 | |
1960 | if (error) | | 2017 | /* |
| | | 2018 | * re-lookup tvp since the parent has been unlocked, so could |
| | | 2019 | * have changed/removed in the meantime. |
| | | 2020 | */ |
| | | 2021 | tcnp->cn_flags &= ~SAVESTART; |
| | | 2022 | error = relookup(tdvp, &tvp, tcnp); |
| | | 2023 | if (error) { |
| | | 2024 | vput(tdvp); |
1961 | goto out; | | 2025 | goto out; |
| | | 2026 | } |
| | | 2027 | tnode = (tvp == NULL) ? NULL : VTOI(tvp); |
1962 | } | | 2028 | } |
1963 | | | 2029 | |
1964 | /* remove existing entry if present */ | | 2030 | /* remove existing entry if present */ |
1965 | if (tvp) | | 2031 | if (tvp) |
1966 | udf_dir_detach(tdnode->ump, tdnode, tnode, tcnp); | | 2032 | udf_dir_detach(tdnode->ump, tdnode, tnode, tcnp); |
1967 | | | 2033 | |
1968 | /* create new directory entry for the node */ | | 2034 | /* create new directory entry for the node */ |
1969 | error = udf_dir_attach(tdnode->ump, tdnode, fnode, &fvap, tcnp); | | 2035 | error = udf_dir_attach(tdnode->ump, tdnode, fnode, &fvap, tcnp); |
1970 | if (error) | | 2036 | if (error) |
1971 | goto out; | | 2037 | goto out; |
1972 | | | 2038 | |
1973 | /* unlink old directory entry for the node, if failing, unattach new */ | | 2039 | /* unlink old directory entry for the node, if failing, unattach new */ |
1974 | error = udf_dir_detach(tdnode->ump, fdnode, fnode, fcnp); | | 2040 | error = udf_dir_detach(tdnode->ump, fdnode, fnode, fcnp); |