From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 129728 invoked by alias); 22 Sep 2019 07:11:53 -0000 Mailing-List: contact cygwin-help@cygwin.com; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner@cygwin.com Mail-Followup-To: cygwin@cygwin.com Received: (qmail 129721 invoked by uid 89); 22 Sep 2019 07:11:53 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-5.2 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_2,KAM_SHORT,RCVD_IN_DNSWL_LOW,SPF_PASS autolearn=ham version=3.3.1 spammy=specifications, Seven, ended, strips X-HELO: lb3-smtp-cloud8.xs4all.net Received: from lb3-smtp-cloud8.xs4all.net (HELO lb3-smtp-cloud8.xs4all.net) (194.109.24.29) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sun, 22 Sep 2019 07:11:42 +0000 Received: from tmp.E9gxmFiH2g ([83.162.234.136]) by smtp-cloud8.xs4all.net with ESMTPSA id Bw1yinWyNKKNGBw1zigYnH; Sun, 22 Sep 2019 09:11:40 +0200 Date: Sun, 22 Sep 2019 07:34:00 -0000 Message-ID: <22effcaa7390026126e1edb46155299b@smtp-cloud8.xs4all.net> From: Houder Reply-To: cygwin@cygwin.com To: cygwin@cygwin.com Subject: Re: Odd, is it not? mkdir 'e:\' cannot be undone by rmdir 'e:\' ... References: <20190827152549.GY11632@calimero.vinschen.de> <3E262D05-F393-453A-9E43-B248DDE50812@solidrocksystems.com> <20190828125939.GL11632@calimero.vinschen.de> <421ac447-b249-da21-1ca5-228041cfc884@redhat.com> <20190828141556.GM11632@calimero.vinschen.de> <20190828142220.GN11632@calimero.vinschen.de> <4a87b7a940fb0cf76aac5f3bc5b1a8b3@smtp-cloud7.xs4all.net> <3eca1ecf200f0075efd154544c2fd5b4@smtp-cloud7.xs4all.net> <8b163d0f-680f-e4ea-098c-703d0fac87fd@cornell.edu> In-Reply-to: <8b163d0f-680f-e4ea-098c-703d0fac87fd@cornell.edu> Content-Type: text/plain; charset=UTF-8; format=fixed User-Agent: mua.awk 0.99 X-SW-Source: 2019-09/txt/msg00222.txt.bz2 On Sat, 21 Sep 2019 15:42:36, Ken Brown wrote: [snip] > I'll fix this and then look at your patches to mkdir and rmdir. It would > be very helpful if you would write these as a patch series with cover letter, > using git format-patch, and send them to the cygwin-patches list. Hi Ken, I think this will be my last post. In order to help you understand what I have been thinking, I describe (using terse language as in telegrams) what I think path_conv::check() in path.cc does (should do) with regard to "Unix path resolution", and as a _consequence_ of that understanding, what mkdir() and rmdir() in dir.cc must do. (also included are URLs to "standards" I have been studying) - 1. - Farewell I will be hospitalized soon, and I do not think I will be back here (any time soon?). Therefore, if you believe that the rational behind my modifications is valid, (and you like to do all this), you are welcome to carry them out yourself. I will not be able to carry them out myself. - 2. - rmdir(2) not in agreement w/ Posix (and Linux) 64-++ uname -a CYGWIN_NT-6.1 Seven 3.1.0(0.340/5/3) 2019-09-15 17:57 x86_64 Cygwin 64-++ ln -s bar foo 64-++ ls -l foo lrwxrwxrwx 1 Henri None 3 Sep 22 07:28 foo -> bar 64-++ mkdir bar 64-++ rmdir foo rmdir: failed to remove 'foo': Not a directory <==== Correct! 64-++ rmdir foo/ # directory bar has been deleted -- Posix does not # allow this to happen! 64-++ ls -l bar ls: cannot access 'bar': No such file or directory The same applies to mkdir(2). Eric Blake fixed mkdir() in winsup/cygwin/dir.cc in 2009, but he did not fix rmdir() in winsup/cygwin/dir.cc at the same time. Why he did not, I am unable to tell. - 3. - Path Resolution Call flow: mkdir() (and rmdir() ) in winsup/cygwin/dir.cc path_conv::check() in winsup/cygwin/path.cc <==== path resolution mkdir() (or rmdir(2) ) in winsup/cygwin/fhandler_disk_file.cc To simplify what happens when either mkdir(1) or rmdir(1) is called: - mkdir() (and rmdir() ) in dir.cc are "the system call entries" - path_conv::check() performs the "Unix path resolution" (and a lot of other things, I do not care about at the moment) - mkdir() (likewise rmdir() ) in fhandler_disk_file.cc is called by mkdir() in dir.cc, but only if the latter is "satisfied" with the result of path resolution - mkdir() (and rmdir() ) in fhandler_disk_file.cc do not perform path resolution -- these functions use the path as "computed" by path_conv::check() Path Resolution (summarized): pathname = /prefix/final[/] (in general, there is a difference between a path not ending w/ slash and a pathname that ends w/ a slash) - if final/ is a symlnk, it is followed and the target must exist and must be a directory - the exceptions to this rule are mkdir(2) and rmdir(2) (in principle, both these system calls ignore (strip!) the trailing slash) - if final is a symlnk, it is followed by default (but the target does not have to exist, let alone be a directory) - however a system call can specify that the symlnk must NOT be followed; mkdir(2) and rmdir(2) are examples of these system calls (because, again, both mkdir(2) and rmdir(2) do _not_ accept a symlnk as argument, according to specification) path_conv::check() is "common code" to all system calls w/ arguments that specify a pathname, i.e. this method does NOT know about the system calls mkdir() and rmdir(). This method only knows whether or not the pathname ended w/ a slash or not, and whether or not the system call specified to follow a symlnk or not (only relevant in case the pathname did NOT end w/ a slash). Because both mkdir(2) and rmdir(2) should not accept a symlnk as argument, they must both strip trailing slashes AND specify "do not follow". My understanding of what "path resolution" must do (that is, what method path_conv::check() must do wrt Unix path resolution, is based on studying the URLs I include below. Regards, Henri ----- file: references.txt Bzzt. Posix goes over the top in an attempt to make the difference between final and final/ as general as is possible. According to Posix (with regard to "path resolution"), both mkdir(newdir/) and rmdir(existing-dir/) obey the rules. [1] - However the argument to both mkdir(2) and rmdir(2) must be a directory; a symbolic link is NOT allowed in case of these system calls ("functions"). Said differently, there is NO need to specify the argument WITH a trailing slash: confusion does not exist: the argument must be a directory. Moreover, if a symbolic link is specified as an argument in these cases, "path resolution" should NOT follow this symbolic link. That is why both mkdir(2) and rmdir(2) will strip a trailing slash; they also specify "do not follow" for the same reason. [1] however, my interpretation is, that rmdir(existing-dir/) should succeed if the target of "existing-dir" (a symbolic link) s indeed a directory ... But that is wrong! (a symlnk as argument should be rejected by rmdir(2)! ) Similar reasoning applies to mkdir(newdir/) -- the call should be rejected if "newdir" is a symlnk. Linux ignores the difference between final and final/ in case of mkdir(2) and rmdir(2) - the trailing slash is irrelevant here - and silently strips the trailing slash (any implementation will do the same thing in order to be "posix-compliant"). References: Posix: The Open Group Base Specifications Issue 7, 2018 edition IEEE Std 1003.1-2017 (Revision of IEEE Std 1003.1-2008) Copyright (c) 2001-2018 IEEE and The Open Group - https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13 ( 4.13 Pathname Resolution -- general concepts ) - https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_13 ( A.4.13 Pathname Resolution -- appendix ) "POSIX.1-2017 requires that a pathname with a trailing be rejected unless it refers to a file that is a directory or to a file that is to be created as a directory." Henri: this would allow rmdir(existing-dir/), where existing-dir is a symlnk that refers to an _existing_ Henri: directory to succeed; but that is wrong! rmdir(2) does not allow a symlnk as an argument! Henri: similar reasoning applies to mkdir(newdir/) -- mkdir(2) must reject the call if newdir is a symlnk. - - https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html ( mkdir(2) -- functions ) "If path names a symbolic link, mkdir() shall fail and set errno to [EEXIST]." - https://pubs.opengroup.org/onlinepubs/9699919799/functions/rmdir.html ( rmdir(2) -- functions ) "If path names a symbolic link, then rmdir() shall fail and set errno to [ENOTDIR]." Linux: - http://man7.org/linux/man-pages/man7/path_resolution.7.html ( man 7 path_resolution ) "Step 3: find the final entry -- Henri: (Linux!) the final entry is WITHOUT a trailing slash Henri: (Linux!) final/ is not considered the final entry: it must be a directory (or if a symlink, the target must be directory) and that directory must exist. The lookup of the final component of the pathname goes just like that of all other components, as described in the previous step, with two Henri: that is, a symlnk is followed BY DEFAULT! differences: (i) the final component need not be a directory (at least as far as the path resolution process is concerned—it may have to be a directory, or a nondirectory, because of the requirements of the specific system call), and (ii) it is not necessarily an error if the component is not found—maybe we are just creating it. The details on the treatment of the final entry are described in the manual pages of the specific system calls." Henri: in case of final (i.e. w/o trailing slash), a system call can direct Henri: "path resolution" NOT to follow a symlnk (my interpretation) "Final symlink Henri: (Linux!) again, the final symlink is WITHOUT a trailing slash! If the last component of a pathname is a symbolic link, then it depends on the system call whether the file referred to will be the symbolic link or the result of path resolution on its contents. For example, the system call lstat(2) will operate on the symlink, while stat(2) operates on the file pointed to by the symlink." ---------- Henri: my conclusion wrt "path resolution": - if final/ is a symlnk, it is followed and the target must exist and must be a directory - the exceptions to this rule are mkdir(2) and rmdir(2) (in principle, both these system calls ignore (strip!) the trailing slash) - if final is a symlnk, it is followed by default (but the target does not have to exist, let alone be a directory) - however a system call can specify that the symlnk must NOT be followed; mkdir(2) and rmdir(2) are examples of these system calls (because, again, both mkdir(2) and rmdir(2) do _not_ accept a symlnk as argument, according to specification) ---------- - http://man7.org/linux/man-pages/man7/symlink.7.html ( man 7 symlink ) "System calls The first area is symbolic links used as filename arguments for system calls. Except as noted below, all system calls follow symbolic links. For example, if there were a symbolic link slink which pointed to a file named afile, the system call open("slink" ...) would return a file descriptor referring to the file afile." - http://man7.org/linux/man-pages/man2/mkdir.2.html ( man 2 mkdir ) "EEXIST: pathname already exists (not necessarily as a directory). This includes the case where pathname is a symbolic link, dangling or not." - http://man7.org/linux/man-pages/man2/rmdir.2.html ( man 2 rmdir ) "ENOTDIR: pathname, or a component used as a directory in pathname, is NOT, in fact, a directory." - - https://lwn.net/Articles/649115/ ( Pathname lookup in Linux -- June, 2015, by Neil Brown ) - https://www.kernel.org/doc/html/latest/filesystems/path-lookup.html ( Pathname lookup ) ===== -- Problem reports: http://cygwin.com/problems.html FAQ: http://cygwin.com/faq/ Documentation: http://cygwin.com/docs.html Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple