Named Streams in Linux Strawman MRW-1 1. Named streams are functionality which exists on Microsoft Windows and Apple MacOS. A file or a directory may optionally have independently allocated data associated with it. We should decide if pipes, sockets, special devices or symlinks may have streams. My inclination is that this is not permitted, but it might be particularly interesting in the case of pipes ... 2. There exists userspace which would benefit from having named streams. It is a frequent request from GNOME; it is implemented in UDF and NTFS and the functionality was carried forward into ReFS [1] 3. Implementing this functionality in Linux requires several pieces: Userspace API, VFS plumbing, and Filesystem implementation. The first two need to define how named streams interact with other parts of the API. 3.1. Userspace API. 3.1.1. openat() To access a named stream, we need to be able to get a file descriptor for it. The new openat() syscall seems like the best way to accompish this; specify a file descriptor, a new AT_NAMED_STREAM flag and a filename, and the last component of the filename will be treated as the name of the stream within the object. This permits us to distinguish between a named stream on a directory and a file within a directory. 3.1.2. fstat() st_ino will be different for different names. st_dev may be different. st_mode will match the object for files, even if it is changed after creation. For directories, it will match except that execute permission will be removed and S_IFMT will be S_ISREG (do we want to define a new S_ISSTRM?). st_nlink will be 1. st_uid and st_gid will match. It will have its own st_atime/st_mtime/st_ctime. Accessing a stream will not update its parent's atime/mtime/ctime. 3.1.2. mmap(), read(), write(), close(), splice(), sendfile(), fallocate(), ftruncate(), dup(), dup2(), dup3(), utimensat(), futimens(), select(), poll(), lseek(), fcntl(): F_DUPFD, F_GETFD, F_GETFL, F_SETFL, F_SETLK, F_SETLKW, F_GETLK, F_GETOWN, F_SETOWN, F_GETSIG, F_SETSIG, F_SETLEASE, F_GETLEASE) These system calls work as expected 3.1.3. linkat(), symlinkat(), mknodat(), mkdirat(), These system calls will return -EPERM. 3.1.4. renameat() If olddirfd + oldpath refers to a stream then newdirfd + newpath must refer to a stream within the same parent object. If that stream exists, it is removed. If olddirfd + oldpath does not refer to a stream, then newdirfd + newpath must not refer to a stream. The two file specifications must resolve to the same parent object. It is possible to use renameat() to rename a stream within an object, but not to move a stream from one object to another. If newpath refers to an existing named stream, it is removed. 3.1.5. unlinkat() This is how you remove an individual named stream 3.1.6. unlink() Unlinking a file with named streams removes all named streams from that file and then unlinks the file. Open streams will continue to exist in the filesystem until they are closed, just as unlinked files do. 3.1.7. link(), rename() Renaming or linking to a file with named streams continues to work. I do not see any problem with these operations. [1] ReFS limits each stream to 128kB. It would be interesting to know why this limitation exists.