fs.createReadStream(path[, options]) - What are those options? - node.js

According to Node's v6.10.2 API - options is an object or string with the following defaults:
{
flags: 'r',
encoding: null,
fd: null,
mode: 0o666,
autoClose: true
}
But I've seen highWaterMark property being used to set Buffer size. But API didn't put it on the option. So I'm wondering is there more options that API didn't write on the document. If so where I can find the full option list?
And API didn't talk about flags, So I would like to know what flags dose in this case and what's the difference between
flags: r
flags: w
flags: r+
I tried to find those answer but I didn't find any helpful information. I would really appreciate if somebody help me to understand this topic.
Thanks.

At the time of writing this answer the explanation in streams context still seem to be missing from the documentation, so it's unclear as to what options there can be for a readable stream. As far as I can tell the flags are most likely the same flags as specified for other fs operations like fs.open.
From the docs:
https://nodejs.org/api/fs.html#fs_fs_open_path_flags_mode_callback
r - Open file for reading. An exception occurs if the file does not exist.
r+ - Open file for reading and writing. An exception occurs if the file does not exist.
rs+ - Open file for reading and writing in synchronous mode. Instructs the operating system to bypass the local file system cache.
This is primarily useful for opening files on NFS mounts as it allows skipping the potentially stale local cache. It has a very real impact on I/O performance so using this flag is not recommended unless it is needed.
w - Open file for writing. The file is created (if it does not exist) or truncated (if it exists).
wx - Like 'w' but fails if path exists.
w+ - Open file for reading and writing. The file is created (if it does not exist) or truncated (if it exists).
wx+ - Like 'w+' but fails if path exists.
a - Open file for appending. The file is created if it does not exist.
ax - Like 'a' but fails if path exists.
a+ - Open file for reading and appending. The file is created if it does not exist.
ax+ - Like 'a+' but fails if path exists.

Related

what happens when calling ```touch .``` in linux?

this is a very specific question
I'm mainly interested in the open() system calls the happen when running touch ..
So I ran strace touch . and saw that opennat() is called three times.
but I'm not really understanding whats going on; as touch . does not print anything in the console and does not create a new file named "." since "." is a pointer to the current folder and can be seen by running ls -a so nothing is created since that name is already in use.
this is my assumption:
open() is called to check if the specified file name already exits, if a file descriptor is returned this means that the name is already in use and the operation is canceled.
please correct me if I'm wrong.
GNU touch prefers to use a file descriptor when touching files, since it's possible to write touch - > foo and expect the file foo to be touched. As a result, it always tries to open the specified path as a writable file, and if that's possible, it then uses that file descriptor to update the file timestamp.
In this case, it's not possible to open . for writing, so openat returns EISDIR. touch notices that it's a directory, so its call to its internal fdutimensat function gets an invalid file descriptor and falls back to using utimensat instead of futimens.
It isn't the case that the openat call is used to check that the file exists, but instead that using a file descriptor for many operations means that you don't have to deal with path resolution multiple times or handle symlinks, since all of those are resolved when the file descriptor is opened. This is why many long-lived programs choose to open a file descriptor to their current working directory, then change directories, and then use the file descriptor with fchdir to change back. Any pchanges to permissions after the program starts are not a problem.

How do I get the filename of an open std::fs::File in Rust?

I have an open std::fs::File, and I want to get it's filename, e.g. as a PathBuf. How do I do that?
The simple solution would be to just save the path used in the call to File::open. Unfortunately, this does not work for me. I am trying to write a program that reads log files, and the program that writes the logs keep changing the filenames as part of it's log rotation. So the file may very well have been renamed since it was opened. This is on Linux, so renaming open files is possible.
How do I get around this issue, and get the current filename of an open file?
On a typical Unix filesystem, a file may have multiple filenames at once, or even none at all. The file metadata is stored in an inode, which has a unique inode number, and this inode number can be linked from any number of directory entries. However, there are no reverse links from the inode back to the directory entries.
Given an open File object in Rust, you can get the inode number using the ino() method. If you know the directory the log file is in, you can use std::fs::read_dir() to iterate over all entries in that directory, and each entry will also have an ino() method, so you can find the one(s) matching your open file object. Of course this approach is subject to race conditions – the directory entry may already be gone again once you try to do anything with it.
On linux, files handles held by the current process can be found under /proc/self/fd. These look and act like symlinks to the original files (though I think they may technically be something else - perhaps someone who knows more can chip in).
You can therefore recover the (possibly changed) file name by constructing the correct path in /proc/self/fd using your file descriptor, and then following the symlink back to the filesystem.
This snippet shows the steps:
use std::fs::read_link;
use std::os::unix::io::AsRawFd;
use std::path::PathBuf;
// if f is your std::fs::File
// first construct the path to the symlink under /proc
let path_in_proc = PathBuf::from(format!("/proc/self/fd/{}", f.as_raw_fd()));
// ...and follow it back to the original file
let new_file_name = read_link(path_in_proc).unwrap();

LD_PRELOAD with file functions

I have a rather peculiar file format to work with:
Every line begins with the checksum of its content, followed by a new-line-character.
It looks like this:
[CHECKSUM OF LINE_1][LINE_1]\n
[CHECKSUM OF LINE_2][LINE_2]\n
[CHECKSUM OF LINE_3][LINE_3]\n
...
My goal: To allow any application to work with these files like they would work with any other text file - unaware of the additional checksums at the beginning of each line.
Since I work on a linux machine with debian wheezy (kernel 3.18.26) I want to use the LD_PRELOAD-mechanism to override the relevant file functions.
I have seen something like this with zlibc on https://zlibc.linux.lu/index.html - with an explanation of how it works ( https://zlibc.linux.lu/zlibc.html#SEC8 ).
But I dont get it. They only replace the file-opening functions. No read. No write. no fseek. Nothing. So how does it work?
Or - which functions would I have to intercept to handle every read or write operation on this file and handle them accordingly?
I didn't exactly check how it works but the reason seems to be quite simple.
Possible implementation:
zlibc open:
uncompress file you wanted to open to some temporary file
open this temporary file instead of yours
zlibc close:
Compress temporary file
Override original file
In this case you don't need to override read/write/etc because you can use original ones.
In your case you have two possible solutions:
open, that make a copy of your file with striped checksums. close that calculates checksums and override original file
read and write that are able to skip/calculate checksums.
Ad 2.
From What is the difference between read() and fread()?:
fread() is part of the C library, and provides buffered reads. It is
usually implemented by calling read() in order to fill its buffer
In this case I believe that overriding open and close will be less error prone because you can safely reuse original read, write, fread, fseek etc.

Open file by inode

Is it possible to open a file knowing its inode?
ls -i /tmp/test/test.txt
529965 /tmp/test/test.txt
I can provide path, inode (above 529965) and I am looking to get in return a file descriptor.
This is not possible because it would open a loophole in the access control rules. Whether you can open a file depends not only on its own access permission bits, but on the permission bits of every containing directory. (For instance, in your example, if test.txt were mode 644 but the containing directory test were mode 700, then only root and the owner of test could open test.txt.) Inode numbers only identify the file, not the containing directories (it's possible for a file to be in more than one directory; read up on "hard links") so the kernel cannot perform a complete set of access control checks with only an inode number.
(Some Unix implementations have offered nonstandard root-only APIs to open a file by inode number, bypassing some of the access-control rules, but if current Linux has such an API, I don't know about it.)
Not exactly what you are asking, but (as hinted by zwol) both Linux and NetBSD/FreeBSD provide the ability to open files using previously created “handles”: These are inode-like persistent names that identify a file on a file system.
On *BSD (getfh and fhopen) using this is as simple as:
#include <sys/param.h>
#include <sys/mount.h>
fhandle_t file_handle;
getfh("<file_path>", &file_handle); // Or `getfhat` for the *at-style API
// … possibly save handle as bytes somewhere and recreate it some time later …
int fd = fhopen(&file_handle, O_RDWR);
The last call requiring the caller to be root however.
The Linux name_to_handle_at and open_by_handle_at system calls are similar, but a lot more explicit and require the caller to keep track of the relevant file system mount IDs/UUIDs themselves, so I'll humbly link to the detailed example in the manpage instead. Beware, that the example is not complete if you are looking to persist the handles across reboots; one has to convert the received mount ID to a persistent filesystem identifier, such as a filesystem UUID, and convert that back to a mount ID later on. In essence they do the same however. And just like on *BSD using the later system call requires elevated privileges (CAP_DAC_READ_SEARCH to be exact).

NFS CREATE File (overwrite) = zero size?

Im implementing NFS and almoste done but the RFC section 3.3.8 says this in its description:
mode
One of UNCHECKED, GUARDED, and EXCLUSIVE. UNCHECKED
means that the file should be created without checking
for the existence of a duplicate file in the same
directory. In this case, how.obj_attributes is a sattr3
describing the initial attributes for the file. GUARDED
specifies that the server should check for the presence
of a duplicate file before performing the create and
should fail the request with NFS3ERR_EXIST if a
duplicate file exists. If the file does not exist, the
request is performed as described for UNCHECKED.
EXCLUSIVE specifies that the server is to follow
exclusive creation semantics, using the verifier to
ensure exclusive creation of the target. No attributes
may be provided in this case, since the server may use
the target file metadata to store the createverf3
verifier.
so the question if UNCHECKED is the mode should i just set the length of the file to Zero or should i let the file be as it is? and if its a directory should i remove all the content?
I believe the idea of CREATE with UNCHECKED is to apply the semantics of good old Unix system call creat -- so, truncation of a file's existing contents (if any) is implied. However I cannot find this specified all that clearly in the docs (!).
Trying to CREATE an existing directory is an error in any case -- there's a separate MKDIR for that (in NFS 3, the same applies to special files, with MKNOD -- CREATE is now for regular, normal, plain good old files only!-)

Resources