In fs.writeFile([option]), how an "options parameter" generally work? - node.js

I was reading this document about Node.js file system, fs.writeFile(filename, data, [options], callback).
So I noticed that i have seen the [options] pretty often, but never used it for anything. Can someone give me an example? All the cases i had didn't use this option.

For anyone ending up here off a search looking for a flags reference, here it is:
Flag
Description
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 in synchronous mode.
rs+
Open file for reading and writing, asking the OS to open it synchronously. See notes for 'rs' about using this with caution.
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 the 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 the path exists.
a+
Open file for reading and appending. The file is created if it does not exist.
ax+
Like 'a+' but fails if the the path exists.

I'm guessing your interested in how an options parameter generally works in javascript.
As opposed to what the parameters are, which are stated in the docs:
options Object
encoding String | Null default = 'utf8'
mode Number default = 438 (aka 0666 in Octal)
flag String default = 'w'
Generally, the options parameter is an object, with properties that are the options you want to modify. So if you wanted to modify two of the options on fs.writeFile, you'd add each one as a property to options:
fs.writeFile(
"foo.txt",
"bar",
{
encoding: "base64",
flag: "a"
},
function(){ console.log("done!") }
)
And if you're confused as to what these three params are used for, the docs for fs.open have everything you need. It includes all the possibilities for flag, and a description for mode. The callback is called once the writeFile operation is complete.

fs.writeFile(filename,data,{flag: "wx"},function(err){
if(err) throw err
console.log('Date written to file, ',filename)
})
As you can see in the above code snippet, the third parameter is the options/flag. There are optional and used to indicate the behaviour of the file to be opened.
I have passed "wx" as option which indicates, file will open for writing and will be created if it doesn't exist. But it will fail if already exists.
By default "w" is passed as option.
For further reading on different options, here

These are the options.
encoding (string or NULL), default value is 'utf8'
mode (number), default value is 438 (aka 0666 in Octal)
flag (string), default value is 'w'

Related

Why os.Open returns nil error when opening a directory?

I've spend some time looking for an error in my code and it appeared that at one place I was trying to read contents of a directory like it was the file. Consider the following code:
import (
"fmt"
"os"
)
func init() {
file, err := os.Open("/tmp/")
fmt.Println(file, err) //err == nil here
var b []byte
n, err := file.Read(b)
fmt.Println(n, err) //err == "read /tmp/: is a directory"
}
I am wondering, why os.Open allows to 'open' a directory without an error if I cannot 'read' it anyway? The documentation says
Open opens the named file for reading. If successful, methods on the
returned file can be used for reading; the associated file descriptor
has mode O_RDONLY. If there is an error, it will be of type
*PathError. [reference]
If the 'directory' is a 'file' is disputable but for me it looks a bit misleading. Is there any usage for that behavior?
"Reading" has more meanings, one of which is reading the contents of a file.
Another meaning is if the file denotes a directory, you may read its content, which is the list of the files / subfolders in it, using File.Readdir() or File.Readdirnames(). This is perfectly valid for an opened file whose name denotes a directory.
Also you may do a lot more with an opened os.File even if it denotes a folder, e.g. call its File.Chdir() (exclusive for directories) or File.Chmod() methods, or get statistics about it using File.Stat(). I don't see why "opening" a folder should be disallowed. The wording in the doc may not be perfect (or it could be extended to mention this though).

Positional write to existing file [Linux, NodeJS]

I'm trying to edit an existing binary file using NodeJS.
My code goes something like this:
file = fs.createWriteStream("/path/to/existing/binary/file", {flags: "a"});
file.pos = 256;
file.write(new Buffer([0, 1, 2, 3, 4, 5]));
In OS X, this works as expected (The bytes at 256..261 get replaced with 0..5).
In linux however, the 5 bytes get appended to the end of file. This is also mentioned in the NodeJS API Reference:
On Linux, positional writes don't work when the file is opened in append mode. The kernel ignores the position argument and always appends the data to the end of the file.
How do I get around this?
Open with a mode of r+ instead of a. r+ is the portable way to say that you want to read and/or write to arbitrary positions in the file, and that the file should already exist.

Issue with filepath name, possible corrupt characters

Perl and html, CGI on Linux.
Issue with file path name, being passed in a form field, to a CGI on server.
The issue is with the Linux file path, not the PC side.
I am using 2 programs,
1) program written years ago, dynamic html generated in a perl program, and presented to the user as a form. I modified by inserting the needed code to allow a the user to select a file from their PC, to be placed on the Linux machine.
Because this program already knew the filepath, needed on the linux side, I pass this filepath in a hidden form field, to program 2.
2) CGI program on Linux side, to run when form on (1) is posted.
Strange issue.
The filepath that I pass, has a very strange issue.
I can extract it using
my $filepath = $query->param("serverfpath");
The above does populate $filepath with what looks like exactly the correct path.
But it fails, and not in a way that takes me to the file open error block, but such that the call to the CGI script gives an error.
However, if I populate $filepath with EXACTLY the same string, via hard coding it, it works, and my file successfully uploads.
For example:
$fpath1 = $query->param("serverfpath");
$fpath2 = "/opt/webhost/ims/DOCURVC/data"
A comparison of $fpath1 and $fpath2 reveals that they are exactly equal.
A length check of $fpath1 and $fpath2 reveals that they are exactly the same length.
I have tried many methods of cleaning the data in $fpath1.
I chomp it.
I remove any non standard characters.
$fpath1 =~ s/[^A-Za-z0-9\-\.\/]//g;
and this:
my $safe_filepath_characters = "a-zA-Z0-9_.-/";
$fpath1 =~ s/[^$safe_filepath_characters]//g;
But no matter what I do, using $fpath1 causes an error, using $fpath2 works.
What could be wrong with the data in the $fpath1, that would cause it to successfully compare to $fpath2, yet not be equal, visually look exactly equal, show as having the exact same length, but not work the same?
For the below file open block.
$upload_dir = $fpath1
causes complete failure of CGI to load, as if it can not find the CGI (which I know is sometimes caused by syntax error in the CGI script).
$uplaod_dir = $fpath2
I get a successful file upload
$uplaod_dir = ""
The call to the cgi does not fail, it executes the else block of the below if, as expected.
here is the file open block:
if (open ( UPLOADFILE, ">$upload_dir/$filename" ))
{
binmode UPLOADFILE;
while ( <$upload_filehandle> )
{
print UPLOADFILE;
}
close UPLOADFILE;
$msgstr="Done with Upload: upload_dir=$upload_dir filename=$filename";
}
else
{
$msgstr="ERROR opening for upload: upload_dir=$upload_dir filename=$filename";
}
What other tests should I be performing on $fpath1, to find out why it does not work the same as its hard-coded equivalent $fpath2
I did try character replacement, a single character at a time, from $fpath2 to $fpath1.
Even doing this with a single character, caused $fpath1 to have the same error as $fpath2, although the character looked exactly the same.
Is your CGI perhaps running perl with the -T (taint mode) switch (e.g., #!/usr/bin/perl -T)? If so, any value coming from untrusted sources (such as user input, URIs, and form fields) is not allowed to be used in system operations, such as open, until it has been untainted by using a regex capture. Note that using s/// to modify it in-place will not untaint the value.
$fpath1 =~ /^([A-Za-z0-9\-\.\/]*)$/;
$fpath1 = $1;
die "Illegal character in fpath1" unless defined $fpath1;
should work if taint mode is your issue.
But it fails, and not in a way that takes me to the file open error block, but such that the call to the CGI script gives an error.
Premature end of script headers? Try running the CGI from the command line:
perl your_upload_script.cgi serverfpath=/opt/webhost/ims/DOCURVC/data

How can I detect that a file descriptor was redefined to a new filehandle?

In this code:
open my $fh1,'>','file1';
my $fh1_desc=fileno $fh1;
close $fh1;
open my $fh2,'>','file2';
open my $fh1_,'>&=',$fh1_desc;
if (fileno $fh1_ == fileno $fh2 ) {
print "\$fh1_ and \$fh2 are dups\n";
}
After that $fh1_ and $fh2 point to the same file. How can I detect that the redefinition of file descriptor?
This is "dummy code"! The real case is:
When I pass the file descriptor to a different thread how can I know that it wasn't redefined?
Once you've closed a file handle, the numerical descriptor is meaningless, and will usually just be re-used by the next open, as you've shown. My suggestion is that when you close a file, you make sure to set any handles you may have to 'undef' so you don't fool yourself into thinking they are still valid.
But I may have misunderstood your problem - you didn't supply very much detail.

How to get the name of a file acting as stdin/stdout?

I'm having the following problem. I want to write a program in Fortran90 which I want to be able to call like this:
./program.x < main.in > main.out
Additionally to "main.out" (whose name I can set when calling the program), secondary outputs have to be written and I wanted them to have a similar name to either "main.in" or "main.out" (they are not actually called "main"); however, when I use:
INQUIRE(UNIT=5,NAME=sInputName)
The content of sInputName becomes "Stdin" instead of the name of the file. Is there some way to obtain the name of files that are linked to stdin/stdout when the program is called??
Unfortunately the point of i/o redirection is that you're program doesn't have to know what the input/output files are. On unix based systems you cannot look at the command line arguments as the < main.in > main.out are actually processed by the shell which uses these files to set up standard input and output before your program is invoked.
You have to remember that sometimes the standard input and output will not even be files, as they could be a terminal or a pipe. e.g.
./generate_input | ./program.x | less
So one solution is to redesign your program so that the output file is an explicit argument.
./program.x --out=main.out
That way your program knows the filename. The cost is that your program is now responsible for openning (and maybe creating) the file.
That said, on linux systems you can actually find yout where your standard file handles are pointing from the special /proc filesystem. There will be symbolic links in place for each file descriptor
/proc/<process_id>/fd/0 -> standard_input
/proc/<process_id>/fd/1 -> standard_output
/proc/<process_id>/fd/2 -> standard_error
Sorry, I don't know fortran, but a psudeo code way of checking the output file could be:
out_name = realLink( "/proc/"+getpid()+"/fd/1" )
if( isNormalFile( out_name ) )
...
Keep in mind what I said earlier, there is no garauntee this will actually be a normal file. It could be a terminal device, a pipe, a network socket, whatever... Also, I do not know what other operating systems this works on other than redhat/centos linux, so it may not be that portable. More a diagnostic tool.
Maybe the intrinsic subroutines get_command and/or get_command_argument can be of help. They were introduced in fortran 2003, and either return the full command line which was used to invoke the program, or the specified argument.

Resources