From owner-freebsd-bugs@FreeBSD.ORG Mon Feb 16 00:50:54 2015 Return-Path: Delivered-To: freebsd-bugs@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id D7CB53F1 for ; Mon, 16 Feb 2015 00:50:54 +0000 (UTC) Received: from kenobi.freebsd.org (kenobi.freebsd.org [IPv6:2001:1900:2254:206a::16:76]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id B843DEA1 for ; Mon, 16 Feb 2015 00:50:54 +0000 (UTC) Received: from bugs.freebsd.org ([127.0.1.118]) by kenobi.freebsd.org (8.14.9/8.14.9) with ESMTP id t1G0osYf011835 for ; Mon, 16 Feb 2015 00:50:54 GMT (envelope-from bugzilla-noreply@freebsd.org) From: bugzilla-noreply@freebsd.org To: freebsd-bugs@FreeBSD.org Subject: [Bug 197695] Add facility to retrieve a canonical path for a currently open file descriptor Date: Mon, 16 Feb 2015 00:50:54 +0000 X-Bugzilla-Reason: AssignedTo X-Bugzilla-Type: new X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: Base System X-Bugzilla-Component: kern X-Bugzilla-Version: 11.0-CURRENT X-Bugzilla-Keywords: X-Bugzilla-Severity: Affects Many People X-Bugzilla-Who: s_bugzilla@nedprod.com X-Bugzilla-Status: New X-Bugzilla-Priority: --- X-Bugzilla-Assigned-To: freebsd-bugs@FreeBSD.org X-Bugzilla-Target-Milestone: --- X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: bug_id short_desc product version rep_platform op_sys bug_status bug_severity priority component assigned_to reporter Message-ID: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: 7bit X-Bugzilla-URL: https://bugs.freebsd.org/bugzilla/ Auto-Submitted: auto-generated MIME-Version: 1.0 X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 16 Feb 2015 00:50:54 -0000 https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=197695 Bug ID: 197695 Summary: Add facility to retrieve a canonical path for a currently open file descriptor Product: Base System Version: 11.0-CURRENT Hardware: Any OS: Any Status: New Severity: Affects Many People Priority: --- Component: kern Assignee: freebsd-bugs@FreeBSD.org Reporter: s_bugzilla@nedprod.com I recently discovered that FreeBSD is the only one of the major operating systems which does not provide a method of retrieving a current canonical path for a currently open file descriptor. I think this should be fixed, as without this facility writing code which implements race-free file entry unlinking is extremely tough - you simply cannot avoid accidentally deleting the wrong file if another process changes out the filing system underneath you, and you cannot use the trick of openat() + statat() + unlinkat() on the current path of a file descriptor to ensure you are deleting the correct file (of course, it would be super great if POSIX allowed one to delete and rename files via open file descriptor like Windows does and then life would be much easier writing race free filing system code. But I digress). How other OSs implement path reading: * Windows: NtQueryObject(hFile, ObjectNameInformation, nameFull.Buffer, sizeof(nameFull.Buffer), &returnedLength). This returns the NT kernel path for an open file handle. With a bit of work, this can be converted into a DOS style path. On Windows, the NT kernel path used to open a handle is retained per handle, so hard links for the same file don't confound. Also, NT usefully supplies a boolean which indicates if the file is deleted or not. * Linux: readlink("/proc/self/fd/NNN", buffer, sizeof(buffer)) returning the length of the buffer filled. Linux usefully prepends (older kernels) or appends (newer kernels) the string "(deleted)" if the file is deleted. Unfortunately hard links can confound on Linux, so the path returned may be very different to the one you opened. You basically get back _some_ path referring to that inode, whichever the kernel found first in its caches. * Mac OS X: fnctl(fd, F_GETPATH, buffer). No size of the buffer is supplied which I think was a real oversight. No return of how much of the buffer was filled either. Also, if the file is deleted you just get back the last known good path, and I don't know if this API is confounded by hard links. How FreeBSD might implement this: 1. /proc is deprecated on FreeBSD, so Linux's approach is out. I dislike the OS X API as OS X did it, but if one added a size_t* bufsize and let one query the buffer size by passing a null buffer it would look a lot better. Some method of indicating if the file is deleted (e.g. a null string return) even better again. 2. As an alternative to implementing our own F_GETPATH which doesn't match OS X's API, the following code could work: size_t len; int mib[4]={CTL_KERN, KERN_PROC, KERN_PROC_FILEDESC, getpid()}; BOOST_AFIO_ERRHOS(sysctl(mib, 4, NULL, &len, NULL, 0)); std::vector buffer(len*2); BOOST_AFIO_ERRHOS(sysctl(mib, 4, buffer.data(), &len, NULL, 0)); for(char *p=buffer.data(); pkf_fd==fd) { lock_guard g(pathlock); _path=path::string_type(kif->kf_path); return _path; } p+=kif->kf_structsize; } Right now FreeBSD returns path information per fd via KERN_PROC_FILEDESC for just about every type of file descriptor *except* regular files. If you use procstat you'll see this for yourself - regular files always get a null path. Ideally speaking the kernel would track the path used to open each fd as it changed over time, this would prevent hard link confounding. However, I can see that would require filing system support. One alternative could be to return a null terminated sequence of path fragments within its mounted filing system, one per hard link, but again I can see filing system support might be needed. Looking at kernel source code, ZFS provides a ZFS_IOC_OBJ_TO_PATH ioctl which will return you a path from a supplied ZFS object, however I note that it returns exactly one path, so I assume that ZFS objects are one per hard link. UFS appears to provide a SAVENAME facility in ufs_lookup_ino(), so in theory there it's easy. I didn't look into the other filing systems, but it doesn't look like implementing this would be hard for someone familiar with the FreeBSD kernel. And procstat and lsof would now return more useful information, also a win. Niall -- You are receiving this mail because: You are the assignee for the bug.