Doc. no. | N4003 |
Date: | 2014-05-24 |
Project: | Programming Language C++ |
Reply to: | Beman Dawes <bdawes at acm dot org> |
Revised 2014-05-24 at 12:05:47 UTC
Reference ISO/IEC TS 18822
Also see:
The purpose of this document is to record the status of issues which have come before the File System Study Group (SG3) of the INCITS PL22.16 and ISO WG21 C++ Standards Committee. Issues represent potential defects in the ISO/IEC TS 18822 document.
This document contains only study group issues which are actively being
considered by the Study Group, i.e., issues which have a
status of New, Open,
Ready, or Review. See
The issues in these lists are not necessarily formal ISO Defect Reports (DR's). While some issues will eventually be elevated to official Defect Report status, other issues will be disposed of in other ways. See Issue Status.
This document includes [bracketed italicized notes] as a reminder to the SG3 of current progress on issues. Such notes are strictly unofficial and should be read with caution as they may be incomplete or incorrect. Be aware that SG3 support for a particular resolution can quickly change if new viewpoints or killer examples are presented in subsequent discussions.
For the most current official version of this document see http://www.open-std.org/jtc1/sc22/wg21/. Requests for further information about this document should include the document number above, reference ISO/IEC TS 18822, and be submitted to Information Technology Industry Council (ITI), 1250 Eye Street NW, Washington, DC 20005.
Public information as to how to obtain a copy of the C++ Standard, join the standards committee, submit an issue, or comment on an issue can be found in the comp.std.c++ FAQ.
Issues reported to the SG3 transition through a variety of statuses, indicating their progress towards a resolution. Typically, most issues will flow through the following stages.
New - The issue has not yet been reviewed by the SG3. Any Proposed Resolution is purely a suggestion from the issue submitter, and should not be construed as the view of SG3.
Open - The SG3 has discussed the issue but is not yet ready to move the issue forward. There are several possible reasons for open status:
A Proposed Resolution for an open issue is still not be construed as the view of SG3. Comments on the current state of discussions are often given at the end of open issues in an italic font. Such comments are for information only and should not be given undue importance.
Review - Exact wording of a Proposed Resolution is now available for review on an issue for which the SG3 previously reached informal consensus.
Ready - The SG3 has reached consensus that the issue is a defect in the Standard, the Proposed Resolution is correct, and the issue is ready to forward to the full committee for further action as a Defect Report (DR).
Typically, an issue must have a proposed resolution in the currently published issues list, whose wording does not change during SG3 review, to move to the Ready status.
Voting - This status should not be seen in a published issues list, but is a marker for use during meetings to indicate an issues was Ready in the pre-meeting mailing, the Proposed Resolution is correct, and the issue will be offered to the working group at the end of the current meeting to apply to the current working paper (WP) or to close in some other appropriate manner. This easily distinguishes such issues from those moving to Ready status during the meeting itself, that should not be forwarded until the next meeting. If the issue does not move forward, it should fall back to one of the other open states before the next list is published.
Immediate - This status should not be seen in a published issues list, but is a marker for use during meetings to indicate an issues was not Ready in the pre-meeting mailing, but the Proposed Resolution is correct, and the issue will be offered to the working group at the end of the current meeting to apply to the current working paper (WP) or to close in some other appropriate manner. This status is used only rarely, typically for fixes that are both small and obvious, and usually within a meeting of the expected publication of a revised standard. If the issue does not move forward, it should fall back to one of the other open states before the next list is published.
In addition, there are a few ways to categorise and issue that remains open to a resolution within the library, but is not actively being worked on.
Deferred - The SG3 has discussed the issue, is not yet ready to move the issue forward, but neither does it deem the issue significant enough to delay publishing a standard or Technical Report. A typical deferred issue would be seeking to clarify wording that might be technically correct, but easily mis-read.
A Proposed Resolution for a deferred issue is still not be construed as the view of SG3. Comments on the current state of discussions are often given at the end of open issues in an italic font. Such comments are for information only and should not be given undue importance.
Core - The SG3 has discussed the issue, and feels that some key part of resolving the issue is better handled by a cleanup of the language in the Core part of the standard. The issue is passed to the Core Working Group, which should ideally open a corresponding issue that can be linked from the library issue. Such issues will be revisitted after Core have made (or declined to make) any changes.
EWG - The SG3 has discussed the issue, and wonder that some key part of resolving the issue is better handled by some (hopefully small) extension to the language. The issue is passed to the Evolution Working Group, which should ideally open a corresponding issue that can be linked from the library issue. Such issues will be revisitted after Evoltion have made (or declined to make) any recommendations. Positive recommendations from EWG will often mean the issue transition to Core status while we wait for some proposed new feature to land in the working paper.
Ultimately, all issues should reach closure with one of the following statuses.
DR - (Defect Report) - The full WG21/PL22.16 committee has voted to forward the issue to the Project Editor to be processed as a Potential Defect Report. The Project Editor reviews the issue, and then forwards it to the WG21 Convenor, who returns it to the full committee for final disposition. This issues list accords the status of DR to all these Defect Reports regardless of where they are in that process.
WP - (Working Paper) - The proposed resolution has not been accepted as a Technical Corrigendum, but the full WG21/PL22.16 committee has voted to apply the Defect Report's Proposed Resolution to the working paper.
C++11 - (C++ Standard, as revised for 2011) - The full WG21/PL22.16 committee has voted to accept the Defect Report's Proposed Resolution into the published 2011 revision to the C++ standard, ISO/IEC TS 18822.
CD1 - (Committee Draft 2008) - The full WG21/PL22.16 committee has voted to accept the Defect Report's Proposed Resolution into the Fall 2008 Committee Draft.
TC1 - (Technical Corrigenda 1) - The full WG21/PL22.16 committee has voted to accept the Defect Report's Proposed Resolution as a Technical Corrigenda. Action on this issue is thus complete and no further action is possible under ISO rules.
TRDec - (Decimal TR defect) - The SG3 has voted to accept the Defect Report's Proposed Resolution into the Decimal TR. Action on this issue is thus complete and no further action is expected.
Resolved - The SG3 has reached consensus that the issue is a defect in the Standard, but the resolution adopted to resolve the issue came via some other mechanism than this issue in the list - typically by applying a formal paper, occasionally as a side effect of consolidating several interacting issue resolutions into a single issue.
Dup - The SG3 has reached consensus that the issue is a duplicate of another issue, and will not be further dealt with. A Rationale identifies the duplicated issue's issue number.
NAD - The SG3 has reached consensus that the issue is not a defect in the Standard.
NAD Editorial - The SG3 has reached consensus that the issue can either be handled editorially, or is handled by a paper (usually linked to in the rationale).
NAD Future - In addition to the regular status, the SG3 believes that this issue should be revisited at the next revision of the standard.
NAD Concepts - This status reflects an evolution of the language during the development of C++11, where a new feature entered the language, called concepts, that fundamentally changed the way templates would be specified and written. While this language feature was removed towards the end of the C++11 project, there is a clear intent to revisit this part of the language design. During that development, a number of issues were opened against the updated library related to use of that feature, or requesting fixes that would require exliciit use of the concepts feature. All such issues have been closed with this status, and may be revisitted should this or a similar language feature return for a future standard.
Tentatively - This is a status qualifier. The issue has been reviewed online, or at an unofficial meeting, but not in an official meeting, and some support has been formed for the qualified status. Tentatively qualified issues may be moved to the unqualified status and forwarded to full committee (if Ready) within the same meeting. Unlike Ready issues, Tentatively Ready issues will be reviewed in subcommittee prior to forwarding to full committee. When a status is qualified with Tentatively, the issue is still considered active.
Pending - This is a status qualifier. When prepended to a status this indicates the issue has been processed by the committee, and a decision has been made to move the issue to the associated unqualified status. However for logistical reasons the indicated outcome of the issue has not yet appeared in the latest working paper.
Issues are always given the status of New when they first appear on the issues list. They may progress to Open or Review while the SG3 is actively working on them. When the SG3 has reached consensus on the disposition of an issue, the status will then change to Dup, NAD, or Ready as appropriate. Once the full PL22.16 committee votes to forward Ready issues to the Project Editor, they are given the status of Defect Report ( DR). These in turn may become the basis for Technical Corrigenda (TC1), or are closed without action other than a Record of Response (Resolved ). The intent of this SG3 process is that only issues which are truly defects in the Standard move to the formal ISO DR status.
Section: X 4.14 [fs.def.parent] Status: Open Submitter: CH-3 Opened: 2014-01-20 Last modified: 2014-05-22
View all issues with Open status.
Discussion:
The concept of a parent directory for dot or dotdot exists, but the definition doesn't apply.
Suggested action:
Remove the paragraph. This concept does not apply to dot and dot-dot. Add a definition for dot and dot-dot.
[2014-02-07, Beman Dawes comments]
Suggest it is editorial and should be passed to the project editor.
[ 2014-02-11 Issaquah: Beman to provide wording for review next meeting. Also see related issue 5. ]
[22 May 2014 Beman Dawes comments:]
I've now reviewed this issue carefully and believe it is NAD. "parent" is used in four places in the WP, and so deserves a definition. The current definition is copied word-for-word and in its entirety from the POSIX definition. I believe strongly that the File System TS needs to stay in alignment with POSIX on this matter, and that the best way to do that is simply to use the POSIX wording.
Proposed resolution:
Section: X 8.1 [path.generic] Status: Open Submitter: CH-4 Opened: 2014-01-20 Last modified: 2014-05-22
View all issues with Open status.
Discussion:
8.1 [path.generic] says: "The filename dot-dot is treated as a reference to the parent directory." So it must be specified what "/.." and "/../.." refer to.
Add a statement what the parent directory of the root directory is.
[2014-02-07, Beman Dawes suggests wording]
[ 2014-02-11 Issaquah: Implementation defined. See wiki notes for rationale. Beman to provide wording for review next meeting. ]
[22 May 2014 Beman provides wording, taken directly from POSIX.]
Proposed resolution:
Change 8.1 [path.generic]:
The filename dot is treated as a reference to the current directory. The filename dot-dot is treated as a reference to the parent directory. What the filename dot-dot refers to relative to the root directory is implementation-defined. Specific filenames may have special meanings for a particular operating system.
Section: X 6 & 15 Status: Open Submitter: GB-1 Opened: 2014-01-20 Last modified: 2014-05-19
View all issues with Open status.
Discussion:
There is no relative() operation, to complement both absolute() and canonical()
The TS introduces relative paths.
They are defined in section 4.18 relative path [fs.def.relative-path]
A decomposition method relative_path() is described in section 8.4.9 path decomposition [path.decompose]
Two query methods to determine if a path either has_relative_path() or is_relative() described in 8.4.10 path query [path.query]
However there is no way to create a relative path as a path relative to another. Methods are provided to create absolute and canonical paths.
In section 15.1 Absolute [fs.op.absolute]:
path absolute(const path& p, const path& base=current_path());
and in section 15.2 Canonical [fs.op.canonical]
path canonical(const path& p, const path& base = current_path());
path canonical(const path& p, error_code& ec);
path canonical(const path& p, const path& base, error_code& ec);
By providing a operations to achieve absolute and canonical paths there is no impediment to providing a similar operation relative() that attempts to return a new path relative to some base path.
For example:
path relative(const path& p, const path& to = current_path());
path relative(const path& p, error_code& ec);
path relative(const path& p, const path& to, error_code& ec);
This would return a path, if possible, that is relative to to. The implementation can make use of absolute() and canonical() to determine the relative path, if it exists.
The File System TS is based on the boost::filesystem library and it too suffers from this anomaly. There are open tickets for this in Boost Trac:
and it is the subject of several posts on StackOverflow for example:
http://stackoverflow.com/questions/10167382/boostfilesystem-get-relative-path
http://stackoverflow.com/questions/5772992/get-relative-path-from-two-absolute-paths
Other languages typically provide a similar function. For example python provides:
os.path.relpath(path[, start])
Return a relative filepath to path either from the current directory or from an optional start directory. This is a path computation: the filesystem is not accessed to confirm the existence or nature of path or start. start defaults to os.curdir.
[2014-02-07, Beman Dawes comments]
A relative()
function is useful and much requested.
I've seen such a function provided by users and have written it myself in app code.
It is one of those things I've been meaning to do for years, and have just never gotten around to.
That said, my mild preference is to treat this as "NAD, Future" for File System TS1, but treat it as a priority for TS2.
[ 2014-02-11 Issaquah ]
The LWG/SG-3 voted strongly in favor of adding this functionality, and doing so in this TS. That implies quite a bit of work before the next meeting to validate that the proposed interface works as desired for various platforms. There was general agreement not to hold FS STS1 if this functionality isn't ready when the rest of the TS is ready.
[2014-05-19 Beman Dawes supplied wording. The design benefited from discussions with Jamie Allsop, who was the source of the original NB comment. Thanks to Bjorn Reese for corrections and suggestions. Although there was also discussion and experimentation with additional relative functions that took into account symlinks and normalization, these are not proposed here since even the proponents of such functions were unsure of appropriate semantics.]
Original proposed resolution:
Modify header <filesystem> synopsis, 6 [fs.filesystem.synopsis], by adding the operational functions after canonical:
path relative(const path& p, const path& to = current_path()); path relative(const path& p, error_code& ec); path relative(const path& p, const path& to, error_code& ec);
Insert the section:
15.3 Relative [fs.op.relative]
path relative(const path& p, const path& to = current_path()); path relative(const path& p, error_code& ec); path relative(const path& p, const path& to, error_code& ec);Overview: Return a relative path of p to the current directory or from an optional to path.
Returns: A relative path such that canonical(to)/relative(p,to) == canonical(p), otherwise path(). If canonical(to) == canonical(p) the path path(".") is returned. For the overload without a to argument, to is current_path(). Signatures with argument ec return path() if an error occurs.
Throws: As specified in Error reporting.
Remarks: !exists(p) or !exists(to) or !is_directory(to) is an error.
and bump all following sections up by 0.1. Update the contents and any cross-references accordingly.
Question: Should Returns be specified in terms of equivalence? For example: equivalent( canonical(to)/relative(p,to), canonical(p) )
Question: Should canonical(to) == canonical(p) return path(".") or path()? Why?
Question: Should to be spelled start?
Proposed resolution:
To 6 Header <experimental/filesystem> synopsis [fs.filesystem.synopsis], add:
path lexically_relative(const path& p, const path& base);
At the end of 8.6 path non-member functions [path.non-member], add
8.6.3
path
lexically_relative function [path.lexically.relative]path lexically_relative(const path& p, const path& base);Creates a path from the trailing elements of
p
that are lexically relative tobase
, which must be a prefix ofp
.Effects: If the number of elements in [
p.begin(), p.end()
) is less than or equal to the number of elements in [base.begin(), base.end()
), or if any element in [base.begin(), base.end()
) is not equal to the corresponding element in [p.begin(), p.end()
), throw an exception of typefilesystem_error
.Remarks: Equality or inequality are determined by
path::operator==
orpath::operator!=
respectively.Returns: An object of class
path
containing the first element ofp
that does not have a corresponding element inbase,
followed by the subsequent elements ofp
appended as if bypath::operator/=
.Throws:
filesystem_error
.[Note: Behavior is determined by the lexical value of the elements of
p
andbase
- the external file system is not accessed. The case where an element ofbase
is not equal to corresponding element ofp
is treated as an error to avoid returning an incorrect result in the event of symlinks. --end note]A possible implementation would be:
auto mm = std::mismatch( p.begin(), p.end(), base.begin(), base.end()); if (mm.first == p.end() || mm.second != base.end()) { throw filesystem_error( "p does not begin with base, so can not be made relative to base", p, base, error_code(errc::invalid_argument, generic_category())); } path tmp(*mm.first++); for (; mm.first != p.end(); ++mm.first) tmp /= *mm.first; return tmp;
Section: X 13.1 [directory_iterator.members] Status: Open Submitter: CH-13 Opened: 2014-01-20 Last modified: 2014-04-18
View all issues with Open status.
Discussion:
The behaviour of increment is underspecified: What happens if the implementation detects an endless loop (e.g. caused by links)? What happens with automounting and possible race conditions?
More information on this can be found here.
Suggested action:
Specify the required behaviour in these cases.
[2014-02-13 LWG/SG-3 Issaquah: STL will provide wording for next meeting for the endless loop case. The other cases are covered by existing wording in the front matter.]
Proposed resolution:
Section: X 15.4 [fs.op.copy_file] Status: Review Submitter: CH-15 Opened: 2014-01-20 Last modified: 2014-05-24
View all issues with Review status.
Discussion:
Even if to and from are different paths, they may be equivalent.
Specify what happens if (options & copy_options::overwrite_existing) but from and to resolve to the same file.
[2014-02-09, Beman Dawes: Need advice on this issue:]
What do existing implentations do? Possible resolutions:[2014-02-13 LWG/SG-3 Issaquah: LWG/SG-3 decided to treat equivalence in this case as an error. Beman to provide wording.]
[2014-04-09 Beman provided wording as requested. The Effects were rewritten to increase clarity. Behavior remains unchanged except for treating equivalence as an error.]
Proposed resolution:
Change 15.4 [fs.op.copy_file]:Precondition: At most one constant from each
copy_options
option group ([enum.copy_options]) is present inoptions
.Effects:
Ifexists(to) &&
!(options & (copy_options::skip_existing | copy_options::overwrite_existing | copy_options::update_existing))
report a file already exists error as specified in Error reporting (7).
If!exists(to) || (options & copy_options::overwrite_existing) || ((options & copy_options::update_existing) && last_write_time(from) > last_write_time(to)) || !(options & (copy_options::skip_existing | copy_options::overwrite_existing | copy_options::update_existing))
copy the contents and attributes of the filefrom
resolves to the fileto
resolves to.Report a file already exists error as specified in Error reporting (7) if:
exists(to)
andequivalent(from, to)
, orexists(to)
and(options & (copy_options::skip_existing | copy_options::overwrite_existing | copy_options::update_existing)) == copy_options::none.
Otherwise copy the contents and attributes of the file
from
resolves to the fileto
resolves to if:
!exists(to)
, orexists(to)
and(options & copy_options::overwrite_existing) != copy_options::none
, orexists(to)
and(options & copy_options::update_existing) != copy_options::none
andfrom
is more recent thanto
, determined as if by use of thelast_write_time
function.Otherwise no effects.
Returns:
true
if thefrom
file was copied, otherwisefalse
. The signature with argumentec
returnfalse
if an error occurs.Throws: As specified in Error reporting (7).
Complexity: At most one direct or indirect invocation of
status(to)
.
Section: X 15.14 [fs.op.file_size] Status: Review Submitter: FI-9 Opened: 2014-01-20 Last modified: 2014-04-18
View all issues with Review status.
Discussion:
"The signature with argument ec returns static_cast<uintmax_t>(-1) if an error occurs.", one would expect that both signatures return that if an error occurs?
Clarify the Returns clause, and apply the same for every function that returns an uintmax_t where applicable.
[2014-02-13 LWG/SG-3 Issaquah:]
Discussion when around in circles for a while, until someone suggested the reference to 15.15 was wrong, and that the issue applied to the previous function in the WP, 15.14 File size [fs.op.file_size]. The NB Comment makes much more sense if it applies to file_size(), so the chair was directed to change the reference from 15.15 [fs.op.hard_lk_ct] to 15.14 [fs.op.file_size]. The intent that file_size() is only meaningful for regular_files. Beman to strike the the static_cast, changing it to "Otherwise an error is reported.".Proposed resolution:
Change 15.14 [fs.op.file_size]:
uintmax_t file_size(const path& p); uintmax_t file_size(const path& p, error_code& ec) noexcept;
Returns: If
exists(p) && is_regular_file(p)
, the size in bytes of the filep
resolves to, determined as if by the value of the POSIXstat
structure memberst_size
obtained as if by POSIXstat()
. Otherwise,an error is reported (7). The signature with argumentstatic_cast<uintmax_t>(-1)
ec
returnsstatic_cast<uintmax_t>(-1)
if an error occurs.Throws: As specified in Error reporting (7).
Section: X 6 [fs.filesystem.synopsis] Status: New Submitter: P.J. Plauger Opened: 2014-01-30 Last modified: 2014-04-18
View other active issues in 6 [fs.filesystem.synopsis].
View all other issues in 6 [fs.filesystem.synopsis].
View all issues with New status.
Discussion:
enum class directory_options has no summary.
Proposed resolution:
Change 6 [fs.filesystem.synopsis]:
enum class directory_options;{none,follow_directory_symlink,skip_permission_denied};
Add the following sub-section:
10.4 Enum class
directory_options
[enum.directory_options]The enum class type
directory_options
is a bitmask type (C++11 §17.5.2.1.3) that specifies bitmask constants used to identify directory traversal options.
Name Value Definition or notes none
0
follow_directory_symlink
1
Follow rather than skip directory symlinks. skip_permission_denied
2
Skip directories that would otherwise result in permission denied errors.
Section: X 6 [fs.filesystem.synopsis] Status: New Submitter: P.J. Plauger Opened: 2014-01-30 Last modified: 2014-05-24
View other active issues in 6 [fs.filesystem.synopsis].
View all other issues in 6 [fs.filesystem.synopsis].
View all issues with New status.
Discussion:
directory_options::skip_permission_denied is not used.
[2014-04-13 Beman: skip_permissions_denied not being used is a symptom of a more serious problem; two directory_itorator constructors are missing directory_options arguments and a description of how they are used. Proposed wording provided.]
Proposed resolution:
Change 13 [class.directory_iterator]:
directory_iterator() noexcept; explicit directory_iterator(const path& p, directory_options options = directory_options::none); directory_iterator(const path& p, directory_options options, error_code& ec) noexcept; directory_iterator(const directory_iterator&) = default; directory_iterator(directory_iterator&&) = default; ~directory_iterator();
Change 13.1 directory_iterator members [directory_iterator.members]:
explicit directory_iterator(const path& p, directory_options options = directory_options::none); directory_iteratorconst path& p, directory_options options, error_code& ec) noexcept;Effects: For the directory that
p
resolves to, constructs an iterator for the first element in a sequence ofdirectory_entry
elements representing the files in the directory, if any; otherwise the end iterator.However, if
options & directory_options::skip_permissions_denied != directory_options::none
and construction encounters an error indicating that permission to accessp
is denied, construct the end iterator and do not report an error.
Change 14.1 recursive_directory_iterator members [rec.dir.itr.members]:
explicit recursive_directory_iterator(const path& p, directory_options options = directory_options::none); recursive_directory_iterator(const path& p, directory_options options, error_code& ec) noexcept; recursive_directory_iterator(
const path& p, error_code& ec) noexcept;
Effects: Constructs a iterator representing the first entry in the directory
p
resolves to, if any; otherwise, the end iterator.However, if
options & directory_options::skip_permissions_denied != directory_options::none
and construction encounters an error indicating that permission to accessp
is denied, construct the end iterator and do not report an error.
Change 14.1 recursive_directory_iterator members [rec.dir.itr.members]:
recursive_directory_iterator& operator++(); recursive_directory_iterator& increment(error_code& ec);Requires:
*this != recursive_directory_iterator()
.Effects: As specified by C++11 § 24.1.1 Input iterators, except that:
- If there are no more entries at this depth, then if
depth()!= 0
iteration over the parent directory resumes; otherwise*this = recursive_directory_iterator()
.- Otherwise if
recursion_pending() && is_directory(this->status()) && (!is_symlink(this->symlink_status()) || (options() & directory_options::follow_directory_symlink) !=
then either directory0directory_options::none)(*this)->path()
is recursively iterated into or, ifoptions() & directory_options::skip_permissions_denied != directory_options::none
and an error indicating that permission to access directory(*this)->path()
is denied, then directory(*this)->path()
is treated as an empty directory and no error is reported.
Section: X 10.2 [enum.copy_options] Status: New Submitter: P.J. Plauger Opened: 2014-01-30 Last modified: 2014-05-24
View all other issues in 10.2 [enum.copy_options].
View all issues with New status.
Discussion:
copy_options::copy_symlinks is not used (should test it before calling copy_symlinks in copy).
[20 May 2014 Beman Dawes provides proposed wording.]
Proposed resolution:
Change 15.3 Copy [fs.op.copy]:
If
is_symlink(f)
, then:
- If
options & copy_options::skip_symlinks
, then return. Missing != copy_options::none fixed by issue 59- Otherwise if
!exists(t) && (options & copy_options::copy_symlinks) != copy_options::none
, thencopy_symlink(from, to, options)
.- Otherwise report an error as specified in Error reporting (7) .
Section: X 15.2 [fs.op.canonical], X 15.11 [fs.op.current_path], X 15.27 [fs.op.read_symlink], X 15.36 [fs.op.system_complete], X 15.37 [fs.op.temp_dir_path], X 15.38 [fs.op.unique_path], X 8.4 [path.member] Status: New Submitter: P.J. Plauger Opened: 2014-01-30 Last modified: 2014-05-23
View all issues with New status.
Discussion:
all functions with error_code arguments should be noexcept (see canonical, current_path, read_symlink, system_complete, temp_directory_path, unique_path, plus member functions).
[2014-02-03: Stephan T. Lavavej comments:]
The declaration and definition of "recursive_directory_iterator& increment(error_code& ec);" should almost certainly be marked noexcept.
[2014-02-08: Daniel comments]
All functions that return a path value such as canonical, current_path, read_symlink, system_complete, temp_directory_path, unique_path, or any member function returning a path value or basic_string value might legally throw an exception, if the allocator of the underlying string complains about insufficient memory. This is an anti-pattern for noexcept, because the exception-specification includes the return statement of a function and given the fact that the language currently does declare RVO as an optional action, we cannot rely on it.
The Standard is currently very careful not to specify functions as noexcept, if this case can happen, see e.g. std::locale::name(). To the contrary, enforcing them to be noexcept, would cause a similar problem as the unconditional noexcept specifier of the value-returning kill_dependency as denoted by LWG 2236. Basically this requirement conflicts with the section "Adopted Guidelines", second bullet of N3279.[Beman Dawes 2014-02-27]
Issues 37, 38, 41, and 49 are concerned with signatures which should or should not be noexcept. I will provide unified proposed wording for these issues, possibly in a separate paper.[21 May 2014 Beman Dawes reviewed all functions with error_code&
arguments,
and provided proposed wording for the one case found where the above guidelines were not met.
This was the case previously identified by Stephan T. Lavavej.
]
Proposed resolution:
Change 14 Class recursive_directory_iterator [class.rec.dir.itr]:
recursive_directory_iterator& increment(error_code& ec) noexcept;
Change 14.1 recursive_directory_iterator members [rec.dir.itr.members]:
recursive_directory_iterator& increment(error_code& ec) noexcept;
Section: X 12.3 [directory_entry.obs], X 15.12 [fs.op.exists], X 15.16 [fs.op.is_block_file], X 15.17 [fs.op.is_char_file], X 15.18 [fs.op.is_directory], X 15.19 [fs.op.is_empty], X 15.20 [fs.op.is_fifo], X 15.21 [fs.op.is_other], X 15.22 [fs.op.is_regular_file], X 15.23 [fs.op.is_socket], X 15.24 [fs.op.is_symlink], X 15.33 [fs.op.status], X 15.35 [fs.op.symlink_status], X 15.38 [fs.op.unique_path] Status: New Submitter: P.J. Plauger Opened: 2014-01-30 Last modified: 2014-05-23
View all other issues in 12.3 [directory_entry.obs].
View all issues with New status.
Discussion:
exists(const path&) should be noexcept (drop error_code version).
is_*(const path&) should be noexcept (drop error_code version).
status(const path&) should be noexcept (drop error_code version).
symlink_status(const path&) should be noexcept (drop error_code version).
file_status::status() should be noexcept (drop error_code version).
file_status::symlink_status() should be noexcept (drop error_code version).
unique_path(const path&) should be noexcept (drop error_code version).
[2014-02-08: Daniel comments]
unique_path(const path&) cannot be declared as noexcept, because it returns an object during whose construction a memory allocation request may fail, see the rationale provided in 37.
exists(const path&) and the is_*(const path&) functions cannot be noexcept, because they are specified in terms of status(const path&), which again may throw an exception, which is explicitly described in the Effects (filesystem_error), because the non-throwing function (status(const path&, error_code&)) may fail to satisfy the request. symlink_status(const path&) may throw an exception for similar reasons that status(const path&) could fail. The reference to file_status::status()/symlink_status() looks like a typo to me (there are no such functions in file_status), presumably directory_entry::status()/symlink_status() was meant. In this case I see no reason how these could be marked as noexcept, because these functions all may fail and may throw an exception. Based on this interpretation of the issue discussion I recommend to resolve this issue as NAD.[Beman Dawes 2014-02-27]
Issues 37, 38, 41, and 49 are concerned with signatures which should or should not be noexcept. I will provide unified proposed wording for these issues, possibly in a separate paper.Proposed resolution:
Section: X 12 [class.directory_entry] Status: New Submitter: P.J. Plauger Opened: 2014-01-30 Last modified: 2014-05-19
View other active issues in 12 [class.directory_entry].
View all other issues in 12 [class.directory_entry].
View all issues with New status.
Discussion:
class directory_entry should retain operator const path&() from V2.
[2014-05-19 Beman Dawes supplied proposed wording.]
Proposed resolution:
Change 12 Class directory_entry [class.directory_entry]:
// observers const path& path() const noexcept; operator const path&() const noexcept; file_status status() const; file_status status(error_code& ec) const noexcept; file_status symlink_status() const; file_status symlink_status(error_code& ec) const noexcept;
Change 12.3 directory_entry observers [directory_entry.obs]:
const path& path() const noexcept; operator const path&() const noexcept;Returns:
m_path
Section: X 13 [class.directory_iterator], X 14 [class.rec.dir.itr] Status: New Submitter: P.J. Plauger Opened: 2014-01-30 Last modified: 2014-05-23
View all other issues in 13 [class.directory_iterator].
View all issues with New status.
Discussion:
class directory_iterator move construct/assign should be noexcept.
class recursive_directory_iterator move construct/assign should be noexcept.
[Beman Dawes 2014-02-27]
Issues 37, 38, 41, and 49 are concerned with signatures which should or should not be noexcept. I will provide unified proposed wording for these issues, possibly in a separate paper.[Daniel Krügler 2014-02-28]
directory_iterator begin(directory_iterator iter) noexcept; directory_iterator end(const directory_iterator&) noexcept;are noexcept, but we have no guarantee that at least the move-constructor is noexcept:
directory_iterator(const directory_iterator&) = default; directory_iterator(directory_iterator&&) = default;This means that either the above noexcept specifications are not warranted or that at least the move-constructor of directory_iterator is required to be noexcept. The same applies to recursive_directory_iterator.
[21 May 2014 Beman Dawes provided proposed resolution wording.]
Proposed resolution:
Change 13 Class directory_iterator [class.directory_iterator]:
directory_iterator(directory_iterator&&) noexcept = default; ... directory_iterator& operator=(directory_iterator&&) noexcept = default;
Change 14 Class recursive_directory_iterator [class.rec.dir.itr]:
recursive_directory_iterator(recursive_directory_iterator&&) noexcept = default; ... recursive_directory_iterator& operator=(recursive_directory_iterator&&) noexcept = default;
Section: X 8 [class.path] Status: New Submitter: P.J. Plauger Opened: 2014-01-30 Last modified: 2014-04-18
View all other issues in 8 [class.path].
View all issues with New status.
Discussion:
class path should have defaulted constructors/destructor/assignments.
[2014-02-26 Beman Dawes comments]
Suggest NAD. Earlier versions did have defaulted constructors/destructor/assignments, but they were removed at the request of Alberto Ganesh Barbati (c++std-filesys January 8, 2013):Speaking of =default, we have to be careful not over-constrain the specification. I mean, if we just specify the intended meaning of those function with proper wording, the implementation is allowed to use =default in case it provides an equivalent behaviour, but if we put =default in the specification, the implementation is required to use it. However, we have to remember that "for exposition only" data members may not be an exhaustive list and that 17.5.2.3/2 allows implementations to provide an equivalent behaviour using different members for which "default" construction/copy/assignment may not be appropriate. =default is what we want for tuple, atomics, etc. It might be appropriate for simple types like file_status, but, for more complex types like path itself, I'd remove it and add proper wording.
Proposed resolution:
Section: X 15.7 [fs.op.create_directory] Status: New Submitter: P.J. Plauger Opened: 2014-01-30 Last modified: 2014-04-18
View all issues with New status.
Discussion:
create_directory should refer to perms::all instead of the Posix S_IRWXU|S_IRWXG|S_IRWXO.
[2014-02-28 Beman provided proposed wording.]
Proposed resolution:
Effects: Establishes the postcondition by attempting to create the
directory p
resolves to, as if by POSIX
mkdir()
with a second argument of S_IRWXU|S_IRWXG|S_IRWXO perms::all
. Creation
failure because p
resolves to an existing directory shall not be
treated as an error.
Section: X 8.4.6 [path.native.obs] Status: New Submitter: P.J. Plauger Opened: 2014-01-30 Last modified: 2014-04-18
View all issues with New status.
Discussion:
path::template<class charT>string() should promise to convert by the same rules as u16string for string<char16_t>, etc. and one-for-one otherwise.
What if charT is signed char (or even float)? I don't see where that choice is disallowed, so we should either disallow it or make it be something that is quasi-sensible.[2014-02-08 Daniel comments]
There are two relevant places in the wording that seem to clarify what is required here:
Most importantly, 5 [fs.req] says:
Throughout this Technical Specification, char, wchar_t, char16_t, and char32_t are collectively called encoded character types.
Template parameters named charT shall be one of the encoded character types. […] [Note: Use of an encoded character type implies an associated encoding. Since signed char and unsigned char have no implied encoding, they are not included as permitted types. — end note]
For both the mentioned string function template and the specific non-template functions (such as u16string()) the same Remarks element exists, that refers to character conversion:
Conversion, if any, is performed as specified by 8.2 [path.cvt].
The first quote excludes arbitrary types such as signed char or float as feasible template arguments. The second quote makes clear that both the function template and the non-template functions do normatively refer to the same wording in 8.2 [path.cvt].
Based on this interpretation of the issue discussion I recommend resolving it as NAD. In addition to that recommendation I recommend to rename the current usage of the symbol charT in this technical specification, because 5 [fs.req] assigns a very special meaning to the constraints on charT types that does not exist to this extend in the rest of the standard library. A similar approach is used in Clause 22, where a special symbol C is used for constrained character types (C++11 §22.3.1.1.1 [locale.category]):A template formal parameter with name C represents the set of types containing char, wchar_t, and any other implementation-defined character types that satisfy the requirements for a character on which any of the iostream components can be instantiated.
[2014-02-28 Beman provides proposed resolution wording]
Proposed resolution:
In the entire Working Paper, change each instance of "charT
" to "C
".
For example, in 5 [fs.req]:
Template parameters namedcharT
C
shall be one of the encoded character types.
Section: X 8.4.1 [path.construct], X 12 [class.directory_entry] Status: New Submitter: Stephan T. Lavavej Opened: 2014-02-03 Last modified: 2014-05-23
View all other issues in 8.4.1 [path.construct].
View all issues with New status.
Discussion:
path's move ctor is marked noexcept, but it contains a basic_string. Similarly, directory_entry's move ctor is marked noexcept, but it contains a path. This is affected by LWG 2319 "basic_string's move constructor should not be noexcept".
[Beman Dawes 2014-02-27]
Issues 37, 38, 41, and 49 are concerned with signatures which should or should not be noexcept. I will provide unified proposed wording for these issues, possibly in a separate paper.[21 May 2014 Beman Dawes provides wording. See LWG 2319 for rationale. ]
Proposed resolution:
Change 8 Class path [class.path]:Change 8.4.1 path constructors [path.construct]:path(path&& p)noexcept;
Change 12 Class directory_entry [class.directory_entry]:path(path&& p)noexcept;
directory_entry(directory_entry&&)noexcept= default;
Section: X 12 [class.directory_entry] Status: Open Submitter: Stephan T. Lavavej Opened: 2014-02-03 Last modified: 2014-04-18
View other active issues in 12 [class.directory_entry].
View all other issues in 12 [class.directory_entry].
View all issues with Open status.
Discussion:
12 [class.directory_entry] depicts directory_entry as having mutable m_status and m_symlink_status data members. This is problematic because of C++11's multithreading guarantees, which say that const member functions are simultaneously callable. As a result, mutable data members must be protected with synchronization, which was probably not considered during this design. The complexity and expense may be acceptable in directory_entry (since it can save filesystem queries, apparently) but it would be very very nice to have a note about this.
[2014-02-13 LWG/SG-3 discussed in Issaquah: Beman and STL will work together to better understand the concerns, and to formulate a solution. This is not a blocking issue for finishing the TS, but is a blocking issue for merging into the IS]
[2014-04-17 Beman provides proposed wording]
Proposed resolution:
No changes to 12 Class directory_entry [class.directory_entry]:
private: path m_path; // for exposition only mutable file_status m_status; // for exposition only; stat()-like mutable file_status m_symlink_status; // for exposition only; lstat()-like...
A
directory_entry
object stores apath object
, afile_status
object for non-symbolic link status, and afile_status
object for symbolic link status. Thefile_status
objects act as value caches.[Note: Because
status()
on a pathname may be a relatively expensive operation, some operating systems provide status information as a byproduct of directory iteration. Caching such status information can result in significant time savings. Cached and non-cached results may differ in the presence of file system races. —end note]
Change 12.3 directory_entry observers [directory_entry.obs]:
file_status status() const; file_status status(error_code& ec) const noexcept;Effects: As if,
if (!status_known(m_status)) { if (status_known(m_symlink_status) && !is_symlink(m_symlink_status)) { m_status = m_symlink_status; } else { m_status = status(m_path[, ec]); } }Returns:
m_status
Remarks: These functions shall not introduce a data race (C++std 17.6.5.9).
Throws: As specified in Error reporting (7).
file_status symlink_status() const; file_status symlink_status(error_code& ec) const noexcept;
Effects: As if,
if (!status_known(m_symlink_status)) { m_symlink_status = symlink_status(m_path[, ec]); }Returns:
m_symlink_status
Remarks: These functions shall not introduce a data race (C++std 17.6.5.9).
Throws: As specified in Error reporting (7).
Section: X all Status: New Submitter: Google Opened: 2014-01-20 Last modified: 2014-04-18
View all issues with New status.
Discussion:
We have two primary concerns with the interface as specified:
(a) its interface repeats the mistake of V7 Unix in 1979 by exposing access checking (and similarly file creation) independently from opening and mutating the file, and
(b) it provides no realistic means of testing a software library which uses the standard interface for accessing the filesystem under fault scenarios.
Due to the extent of (a), TOCTTOU [1] security vulnerabilities are guaranteed, if not during access checking[2], during other common operations such as temporary file creation[3].
Due to (b) it is impossible to portably test libraries using the proposed interface against critical correctness and security edge cases.
[1]: TOCTTOU: Time-of-check-to-time-of-use. Operating system integrity in OS/VS2
[2]: Fixing Races for Fun and Profit: How to use access(2)
[3]: Checking for Race Conditions in File Accesses
[Beman Dawes: 10 Feb 2014: Suggested response: NAD, Future]We share your concerns and look forward to receiving specific proposals to address them. Whether they will addressed by a revision of TS 18822 or a new TS will be decided as proposals progress through the committee process. See How To Submit a Proposal.
Proposed resolution:
Section: X 5 [fs.req] Status: New Submitter: Clark Nelson Opened: 2014-02-10 Last modified: 2014-04-08
View all issues with New status.
Discussion:
SD-6: SG10 Feature Test Recommendations recommends that each library header provide feature test macros. For Technical Specifications, the TS itself should specify recommended names for the feature test macros.[Beman Dawes 2014-02-28 provided the proposed resolution. Thanks to Vicente J. Botet Escriba, Richard Smith, and Clark Nelson for suggestions and corrections.]
Proposed resolution:
Add a new sub-section:
5.2 Feature test macros [fs.req.macros]
These macros allow users to determine which versions of this Technical Specification are supported by header
<experimental/filesystem>
.Header
<experimental/filesystem>
shall supply the following macro definitions:#define __cpp_lib_experimental_filesystem 201406 #define __cpp_lib_experimental_filesystem_v1 201406[Note: These macros follow WG21 SD-6, Feature-testing recommendations for C++.
The value of macro
__cpp_lib_experimental_filesystem
is yyyymm where yyyy is the year and mm the month when the version of the Technical Specification was completed.A macro in the form
__cpp_lib_experimental_filesystem_v
n is provided for each inner namespacev
n supplied by the implementation. The value of each macro__cpp_lib_experimental_filesystem_v
n is the same as the value of macro__cpp_lib_experimental_filesystem
for the corresponding version of the Technical Specification. — end note]
Section: X 2.1 [fs.conform.9945] Status: Review Submitter: LWG/SG-3 Opened: 2014-02-13 Last modified: 2014-04-08
View all other issues in 2.1 [fs.conform.9945].
View all issues with Review status.
Discussion:
§ 2.1 [fs.conform.9945] specifes "No diagnostic is required" for races. That prescription is used by the standard for the core language; it is not appropriate in library specifications. LWG/SG-3 wishes this be changed to undefined behavior.[Beman comments: The replacment wording is similar to that used by C++14 17.6.4.10]
Proposed resolution:
Change the following paragraph from § 2.1 [fs.conform.9945]Insert a new sub-section head before the modified paragraph:The behavior of functions described in this Technical Specification may differ from their specification in the presence of file system races ([fs.def.race]). No diagnostic is required.Behavior is undefined if calls to functions provided by this Technical Specification introduce a file system race (4.6 [fs.def.race]).
2.1 File system race behavior [fs.race.behavior]
Section: X 15.25 [fs.op.last_write_time] Status: New Submitter: LWG/SG-3 Opened: 2014-02-13 Last modified: 2014-05-20
View all other issues in 15.25 [fs.op.last_write_time].
View all issues with New status.
Discussion:
POSIX now says: "Since the utimbuf structure only contains time_t variables and is not accurate to fractions of a second, applications should use the utimensat() function instead of the obsolescent utime() function."
Suggested resolution: Rewrite the last_write_time setter description to utilize utimensat() or similar.
[20 May 2014 Beman Dawes supplies proposed wording. He comments:]
POSIX supplies two functions, futimens()
and utimensat()
,
as replacements for utime()
.
futimens()
is appropriate for the current TS.
utimensat()
will be appropriate for a future File System TS that adds the
functionality of the whole family of POSIX *at()
functions.
Proposed resolution:
Change 15.25 Last write time [fs.op.last_write_time]:
Effects: Sets the time of last data modification of the file resolved to by
p
tonew_time
, as if by POSIXstat()
followed by POSIXutime()
futimens()
.
Section: X 10 [fs.enum] Status: New Submitter: Daniel Krügler Opened: 2014-03-01 Last modified: 2014-05-24
View all issues with New status.
Discussion:
copy_options
is declared as enum class
type that is a bismask type, but the
specification repeatedly uses expressions that are invalid for scoped
enums, such as:
!(options)
because there is no contextual conversion to bool, not even the || operator in:
((options & copy_options::recursive) || !(options))
Affected are basically all formulations in the form:
"if options & copy_options::create_symlinks
[..]"
because all rely on contextual conversion to bool. The only other specifically
mention scoped enumeration in the standard that is also a bit mask type is the
launch
enum and
the wording there always uses forms such as:
"if policy & launch::deferred
is non-zero"
which better acknowledges the fact that the obtained values does not necessarily
undergo an implicit conversion.
I think the current wording in the file system spec. must be changed, especially for
invalid expressions of the form:
((options & copy_options::recursive) || !(options))
A similar problem arises in the usage of the bitmask type perms
for the
expression:
((prms & add_perms) && (prms & remove_perms))
The only way how to describe this with a scoped enum is the lengthier form
((prms & perms::add_perms) != perms::none && (prms & perms::remove_perms) !=
perms::none)
thus fixing several problems:
add_perms
and remove_perms
is incorrect[20 May 2014 Beman Dawes provides proposed wording. Fixing invalid C++ is editorial, but treating this as an issue ensures more people review the proposed changes.]
Proposed resolution:
Change 15.3 Copy [fs.op.copy]:
Before the first use of
f
andt
:
- If
(options & copy_options::create_symlinks) != copy_options::none || (options & copy_options::skip_symlinks) != copy_options::none
, thenauto f = symlink_status(from)
and if neededauto t = symlink_status(to)
.- Otherwise,
auto f = status(from)
and if neededauto t = status(to)
.Report an error as specified in Error reporting (7) if:
!exists(f)
, orequivalent(from, to)
, oris_other(f) || is_other(t)
, oris_directory(f) && is_regular_file(t)
.If
is_symlink(f)
, then:
- If
(options & copy_options::skip_symlinks) != copy_options::none
, then return.- Otherwise if
!exists(t)
, thencopy_symlink(from, to, options)
.- Otherwise report an error as specified in Error reporting (7).
Otherwise if
is_regular_file(f)
, then:
- If
(options & copy_options::directories_only) != copy_options::none
, then return.- Otherwise if
(options & copy_options::create_symlinks ) != copy_options::none
, then create a symbolic link to the source file.- Otherwise if
(options & copy_options::create_hard_links) != copy_options::none
, then create a hard link to the source file.- Otherwise if
is_directory(t)
, thencopy_file(from, to/from.filename(), options)
.- Otherwise,
copy_file(from, to, options)
.
Otherwise if
is_directory(f) && ((options & copy_options::recursive) != copy_options::none ||
then:!(options == copy_options::none))
- If
!exists(t)
, thencreate_directory(to, from)
.- Then, iterate over the files in
from
, as if byfor (directory_entry& x : directory_iterator(from))
, and for each iterationcopy(x.path(), to/x.path().filename(), options | copy_options::unspecified)
.
Change 15.4 Copy file [fs.op.copy_file]:
If
exists(to) &&
report a file already exists error as specified in Error reporting (7).
!(options & (copy_options::skip_existing | copy_options::overwrite_existing | copy_options::update_existing)) == copy_options::noneIf
!exists(to) || (options & copy_options::overwrite_existing) != copy_options::none || ((options & copy_options::update_existing) != copy_options::none && last_write_time(from) > last_write_time(to)) ||
copy the contents and attributes of the file!(options & (copy_options::skip_existing | copy_options::overwrite_existing | copy_options::update_existing)) == copy_options::nonefrom
resolves to the fileto
resolves to.
Change 15.26 Permissions [fs.op.permissions]:
Requires:
!((prms & perms::add_perms) != perms::none && (prms & perms::remove_perms) != perms::none)
.
Section: X 15.1 [fs.op.absolute] Status: New Submitter: Daniel Krügler Opened: 2014-02-28 Last modified: 2014-04-08
View all issues with New status.
Discussion:
The Throws element [fs.op.absolute] says:
"If
base.is_absolute()
is true, throws only if memory allocation fails."
We can strike:
"If
base.is_absolute()
is true," and the wording will still hold. Note that:
- None of the involved functions has requirements.
- In *every* case potentially memory allocation occurs, even for "
return p
", so this allocation can fail.
[02-03-2014 Beman Dawes comments and provides P/R]
The Throws element should follow the same form as similar Throws elements in the TS. There isn't enough special about this function to justify special wording and by referencing Error reporting (7) we ensure absolute() follows the overall policy for handling memory allocation failures.Proposed resolution:
[Change 15.1 [fs.op.absolute]:]
Throws:
IfAs specified in Error reporting (7).base.is_absolute()
is true, throws only if memory allocation fails.
Section: X 6 [fs.filesystem.synopsis] Status: New Submitter: Beman Dawes Opened: 2014-04-12 Last modified: 2014-05-23
View other active issues in 6 [fs.filesystem.synopsis].
View all other issues in 6 [fs.filesystem.synopsis].
View all issues with New status.
Discussion:
bool equivalent(const path& p1, const path& p2);
has always thrown a exception if neither file exists,
with rationale that if they don't exist, it isn't possible to tell
if two paths are equivalent. Dave Abrahams has reported that this
is counter-intuitive and hard to teach.
An alternative if neither path exists would be to return true if they are lexically equal (operator==), otherwise return false.
This was not a national body comment, and Dave is the only one I can recall ever complaining about the current behavior. On the other hand, any complaint from Dave deserves serious consideration.
Proposed resolution:
Section: X 5 Requirements [fs.req] Status: New Submitter: Daniel Krügler Opened: 2014-05-19 Last modified: 2014-05-19
View all issues with New status.
Discussion:
The SG3 WP refers in several places to a template parameter named "Allocator" but does not impose requirements on this type.
Proposed resolution:
Add the following to 5 Requirements [fs.req]:
Template parameters named
Allocator
shall meet the C++ Standard's library Allocator requirements (C++11 §17.6.3.5)
directory_entry
Section: X [fs.op.file_size] Status: New Submitter: Gor Nishanov Opened: 2014-05-22 Last modified: 2014-05-24
View all issues with New status.
Discussion:
On Windows, the FindFileData
structure, which is the underlying data type for directory_entry
, contains the file size as one of the fields.
Thus efficient enumeration of files and getting their sizes is possible without doing a separate query for the file size.
Proposed resolution:
In section 12 Class directory_entry
[class.directory_entry] add the
following observer declarations:
uintmax_t file_size(); uintmax_t file_size(error_code& ec) noexcept;
In section 12.3 directory_entry
observers [directory_entry.obs]
add the following:
uintmax_t file_size(); uintmax_t file_size(error_code& ec) noexcept;Returns: if
*this
contains a cached file size, return it. Otherwise returnfile_size(path())
orfile_size(path(), ec)
respectively.Throws: As specified in Error reporting (7).