Why nodejs can make hardlink with dircortory? [duplicate] - node.js

How do you create a hardlink (as opposed to a symlink or a Mac OS alias) in OS X that points to a directory? I already know the command "ln target destination" but that only works when the target is a file. I know that Mac OS, unlike other Unix environments, does allow hardlinking to folders (this is used for Time Machine, for example) but I don't know how to do it myself.

I agree that hard-linking folders/directories can cause problems if not careful, but they have a very definite advantage - Time Machine is a perfect example. Without them it simply would not be practical as the duplication of redundant versions of files would very quickly consume even the largest of disks.
Snow Leopard can create hard links to directories as long as you follow Amit Singh's six rules:
The file system must be journaled HFS+.
The parent directories of the source and destination must be different.
The source’s parent must not be the root directory.
The destination must not be in the root directory.
The destination must not be a descendent of the source.
The destination must not have any ancestor that’s a directory hard link.
So it's not correct at all that Snow Leopard has lost the ability to create hard links to
folders.
I just verified that link/unlink do work on Snow Leopard - as long as you follow the six
rules. I just tried it and it works fine on my Snow Leopard 10.6.6 system - tried it on the boot volume and on a separate USB external volume and it worked fine in both cases.
Here is the "hunlink.c" program:
#include <stdio.h>
#include <unistd.h>
int
main(int argc, char *argv[])
{
if (argc != 2)
return 1;
int ret = unlink(argv[1]);
if (ret != 0)
perror("unlink");
return ret;
}
gcc -o hunlink hunlink.c
So, be careful if you try it - remember to follow the rules and use hlink to create these hard links and use hunlink to remove the hard link afterwards. And don't forget to document
what you've done for later on or for someone else who might need to know this.
One other "gotcha" that I just learned about these "hard links" to folders. When you create them there is really a lot that happens "behind the curtain" of Mac OS X. One really important issue is that the folder you create the link to is really moved to a super-magical super-hidden folder called /.HFS+ Private Directory Data%000d/dir_xxx where xxx is the inode number of the "source_folder" - remember the format of the command is
hlink source_folder target_folder
So because of this, you have to be careful of not having any files open in the "source_folder" because if you do, they just got moved to the super-magical folder and you will likely have a problem if you try and save any changes to those files that were open in the "source_folder". This happened to me a couple of times until it dawned on me what was happening and the solution is pretty simple. I noticed that you couldn't do a "ls -la" command any longer without getting funny errors for all the folders/directories that were in the original "source_folder" but you could do a "ls" command and all looked well.
If you run "Verify disk" in the "Disk Utility" program, you will notice that it probably complains and gives a "Volume bitmap needs minor repair for orphaned blocks" which is what just happened with the creation of the super-magical folder and the movement of the "source_folder" to it.
If you do find yourself in this situation with "orphaned blocks", first save the changed files to some other temporary location not in the volume containing the "source_folder" tree, then use "Disk Utility" to unmount and remount the volume that contains the "source_folder" or just restart the computer. Then copy the files you saved to the temporary locations back to their original locations and you should be back in business. This is what worked for me, so can't guarantee this will work for you too. So it might be a good idea to try this out on a volume you have a good backup of just in case.
It seems so very weird that all this overhead occurs just for the simple task of creating a hard link to a folder. Does anyone have any idea why Mac OS X goes to all this effort for this hard link creation to folders? Does it have something to do with the fact that this is a "journaled" file system?
I discovered the info about the super-magical, super-hidden location by reading Amit Singh's explanation of his "hfsdebug" utility. If you want more details see his web site at Amit Singh's hfsdebug utility. It's a very interesting piece of software and will tell you lots of details about HFS+ file systems. It's free and I encourage you to download it and try it out. It's no longer supported but it still works on both Snow Leopard and Leopard - basically any HFS+ supported system. You can't really do any harm with it as it's a "read-only" tool - so it's great to use to look at some details of the filesystem.
One more issue about these "hard links to folders" - once you create one and the super-magical super-secret-hidden folder gets created, it's there for good. Even if you unlink the folder that caused it to be created in the first place, this magic folder stays around. Not sure why, but it definitely does. You can use "hfsdebug" to find this out if you wish to try it out. You can also use "hfsdebug" to find out how many of these "hard links to folders" exist on a drive. For these details refer to Amit's article on the "hfsdebug" utility.
He also has another newer utility that's supported but costs. It's called fileXray and costs $79 for one person on any number of computers in the same household for a personal non-business type license. It has an extensive 173-page User Guide that you can download to see what it can do before you purchase. Unfortunately there is no trial version, so read the manual and check out the web site for more details to see if it can help you out of a jam. Learn all the details about it at their web site - see fileXray web site for more info.
There are a couple of issues you should be aware of when using these hard links to folders. If the volume that they are created on is mounted to a remote client, there can be significant problems, depending on how they are mounted. If you use AFP to mount the volume to a remote client, there are big problems as any folder that currently has a hard link to it or has ever had one but later removed, will be unable to be used as all the lower level folders (but not files) will be inaccessible from either the Finder or a Terminal window. If you try to do a simple "ls -lR" command, it will fail and give you "ls: xxx: No such file or directory" error messages for all lower level folders. If you use a Finder window to traverse the directory tree of the remote volume, the folders that are in the folder that had or has a hard link to it will simply disappear without any error when you first click on the folder name.
These problems don't appear to occur (except for the error message) if you use NFS to mount the remote client (and assuming you had a NFS server on the system that has the volume as a local HFS+ filesystem). Details on how to use NFS to mount volumes are not provided here. I used a nice program from Dr. Marcel Bresink called "NFS Manager" to help with the NFS mounts on the server and client. You can get it from his web site - just search for "Bresink NFS Manager" in your favorite search engine, but he has a free trial version so you can try before you buy. It's not that big a deal if you want to learn how to do the NFS mounts, but the "NFS Manager" makes it pretty easy to set things up and to tweak all the different settings to help optimize it. He has several other neat Mac OS X utilities too that are very reasonably priced - one called "Hardware Monitor" that lets you monitor and graph all kinds of things like power usage, temperature of CPU, speed of fans and many many other variables for both the local and remote Mac systems over extended periods of time (from minutes to days). Definitely worth checking out if you are into handy utilities.
One thing I did notice is that NFS file transfers were about 20% slower than doing them via AFP, but your "mileage may vary", so no guarantees one way or the other, but I would rather have something that works even if I have to pay a 20% performance hit as compared to having nothing work at all.
Apple is aware of the problems with hard links and remote AFP filesystems, and they refer to it as an "implentation limitation" of the AFP client - I prefer to call it what it really appears to me to be - A BUG!!! I can only hope the next release of Mac OS X fixes the problem, as I really like having the ability to use hard links to folders when it makes sense.
These notes are my own personal opinion and I don't make any warranty about their correctness so use them at your own risk. Have a good backup before you play around with these "hard links to folders" just in case something unforeseen happens. But I hope you have fun if you do decide to look a bit more into this interesting aspect of Mac OS X.

You can't do it directly in BASH then. However... I found an article here that discusses how to do it indirectly: http://www.mactech.com/articles/mactech/Vol.23/23.11/ExploringLeopardwithDTrace/index.html by compiling a simple little C program:
#include <unistd.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
if (argc != 3) return 1;
int ret = link(argv[1], argv[2]);
if (ret != 0) perror("link");
return ret;
}
...and build in Terminal.app with:
$ gcc -o hlink hlink.c -Wall

Piffle. On 10.5, it tells you in the man page for ln:
-d, -F, --directory
allow the superuser to attempt to hard link directories (note:
will probably fail due to system restrictions, even for the
superuser)
So yes:
sudo ln -d existing_dir new_hard_link
Give it your password, and you're not done yet. You didn't document it, did you? You must document hard linked directories; even if it's a single user machine.
Deleting is a different story: if you go about it the usual way to delete directories, you'll delete the contents. So you must "unlink" the directory:
unlink new_hard_link
There. Hope you don't wreck your filesystem!

Cross-posting this great tool which neatly solves the problem, originally posted by Sam:
To install Hardlink, ensure you've installed homebrew, then run:
brew install hardlink-osx
Once installed, create a hard link with:
hln [source] [destination]
I also noticed that unlink command does not work on snow leopard, so I added an option to unlink:
hln -u destination
Code is available on Github for those who are interested: https://github.com/selkhateeb/hardlink

Yes it's supported by the kernel and the filesystem, but since it's not intended for general usage it's not exposed to the shell.
You could probably work out which APIs Time Machine uses and wrap them in a commandline tool, but it'd be better to take the hint and steer well-clear.

The OSX version of ln cannot do it, but, as mentioned in the other answer by rich, it is possible with the GNU version of ln which is available in homebrew as gln as part of the coreutils formula. man gln lists the -d option with the OSX-specific warning provided in rich's answer. In other words, it does not work in all cases. What exactly determines whether it works or not does not seem to be documented anywhere.
As a prerequisite, install coreutils:
brew install coreutils
Now you can do:
sudo gln -d /original_folder /mirror_folder
IMPORTANT: To remove the hard link you must use gunlink:
sudo gunlink /mirror_folder
❗️❗️❗️ Using rm or Finder will also delete the original folder.
FYI: The coreutils homebrew formula provides the GNU-compatible versions of generic unix tools. Use brew list coreutils to see the full list.

As of 2018 no longer possible. APFS (introduced in MacOS High Sierra 10.13) is not compatible with directory hardlinks. See https://github.com/selkhateeb/hardlink/issues/31

My case was that I found out that from a windows virtual machine, I cannot follow symlinks. (i wanted to test some HTML pages in Internet Explorer). And my directory structure had symlinks for CSS and images folders.
My workaround to solve the problem was a different approach than the other answers implied. I used rsync to create a copy of the folder. Rsync can resolve the symlinks and copy the linked files in stead.
This solved my problem without using hard links to directories. And it's actually an easy solution if you're just working on a small set of files.
rsync -av --copy-dirlinks --delete ../htmlguide ~/src/

From the article linked to, you'll get that error if you try to create the hard link in the same directory as the original. You have to create it somewhere else.

In Linux you can use bind mount to simulate hard linking directories. Not sure about OSX
sudo mount --bind /some/existing_real_contents /else/dummy_but_existing_directory
sudo umount /else/dummy_but_existing_directory

This can also be done with built-in Perl (from Terminal) without compiling anything. My specific use case is for Google Drive (which doesn't support symbolic links), so the examples below reflect the use case.
To link your "Documents" folder to Google Drive so it's synced:
perl -e 'link "/Users/me/Documents", "/Users/me/Google Drive/Documents"'
To remove the link to your "Documents" folder from Google Drive:
sudo perl -U -e 'unlink "/Users/me/Google Drive/Documents"'
You need "root" to unlink (see "unlink" perldoc).

Another solution is to use bindfs https://code.google.com/p/bindfs/ which is installable via port:
sudo port install bindfs
sudo bindfs ~/source_dir ~/target_dir

The short answer is you can't. :) (except possibly as root, when it would be more accurate to say you shouldn't.)
Unixes only allow a set number of links to directories - ".." from within all its children and "." from within itself. Anything else is potentially a recipe for a very confused directory tree. This is/was apparently a design decision by Ken Thompson.
(Having said that, apparently Apple's Time Machine does do this :) )

in case there is no sub folder, you can try
ln folder_path/*.* target_folder
it worked for me on OSX 10.9

Related

How to avoid cmake to read in its "system cache" $HOME/.cmake/

When I run cmake with some projects such as caffe or gflags, it writes some information at the system level. Specifically, on a linux system, it generates some directories such as $HOME/.cmake/Caffe and $HOME/.cmake/gflags
My problem is that this information is hereafter used for any project I compile. As a consequence, the programs referenced in $HOME/.cmake are (partially) found, even if I do not want it (as far as I am concerned, I define external variables to control with external programs cmake is allowed to consider for a given compilation).
y current solution is to delete the directory $HOME/.cmake when needed (i.e before compiling my new program). I consider to add a rm -rf $HOME/.cmake in .bashrc but this not fully satisfactory (nor sophisticated!). Could anyone propose a better solution ?
NB: the expression "system cache" in the question is probably wrong. I would be grateful to get a better term. Thank you for any feedback on this (actually, if I knew the correct expression, I may have already found the solution on the web...)
Edit:
Once you know the "system cache" is actually the User Package Registry the answer is easy. See below...
The directory $HOME/.cmake is the User Package Registry. To avoid find_package() to search in this directory, use option NO_CMAKE_PACKAGE_REGISTRY. See point 6 of its documentation:
https://cmake.org/cmake/help/v3.0/command/find_package.html

rsync does not sync uppercase/ lowercase in filenames. How can I make it sync caps?

We are using shell scripts to deploy applications through the different servers (DTAP). The only problem is that when caps are changed these are not synced.
For example:
aboutcontroller.php > AboutController.php
We are using the following rync command.
rsync -avz git/folder/ public_html/folder/
Does anyone know how to tackle this issue?
The issue is not likely rsync itself, but the case-insensitivity of either the source or destination filesystem (or both). When rsync says "give me the contents of file foo", and the file system responds with the contents of FOO instead, because it for whatever reason thinks that case insensitivity is a "good thing", there's not much that rsync can do to accomplish the "right thing". This will be an issue on common file systems used by Windows and Mac platforms, but not so much on Unix/Linux (except where they support Windows/Mac file systems as well).
Linux does take this into account. However if you feed it Foo.h today but then your case insensitive file system sends it foo.h tomorrow (with different contents you'll end up with two file (foo.h and Foo.h) on Linux and you'll confuse everybody.

TortoiseSVN update/cleanup error between Linux repository and Windows XP

For no reason that I can see, I can no longer run a TortoiseSVN Update on a development directory on my portable Windows XP Professional SP3 machine, getting the error:
Previous operation has not finished; run 'cleanup' if it was interrupted
Please execute the 'Cleanup' command.
If I try running cleanup, I get another error,
cannot process the following paths: cannot move $ROOT_DIR/.svn/tmp/tmp-... to $ROOT_DIR/path/where/thing/should/go: no such file or directory
I have verified that both files exist, and actually from CMD.EXE prompt I am able to issue a MOVE with those two filenames and have it work correctly. It's no use because next time SVN tries to repeat the operation itself after creating a different tmp file name, and while CMD succeeded, SVN fails.
UPDATE: the path lengths are in both cases well below PATH_MAX, target file system is NTFS, and permissions are OK. Maybe I'll now try with FileMon to see whatever TortoiseSVN is really up to.
I tried downgrading TortoiseSVN but to no avail. Other repositories work OK between the same machines.
TortoiseSVN 1.7.9, Build 23248 - 32 Bit , 2012/08/30 18:25:37
Subversion 1.7.6,
apr 1.4.6
apr-utils 1.3.12
neon 0.29.6
OpenSSL 1.0.1c 10 May 2012
zlib 1.2.7
Both server (OpenSuSE Linux 12.2) and client now run the latest version of SVN.
On Windows, I also cannot seem to get any more informative logs or information (I'm not very skilled with TortoiseSVN, I have always used the Linux command line version).
I might delete the local copy and run a checkout, but it's about 2 GB of data, and I'm on a slow connection, so it is really more of a "fly physically to server location and hook a copper Ethernet to the local network there" alternative. I'm reserving that as a sort of last ditch, nuclear option; I'd really rather understand what the problem is, for I fear it might happen again.
UPDATE
I've tried to delete remotely the subdirectory involved, committing the deletion on the server; deleting the subdirectory locally, and emptying the .svn/tmp subdirectory where I found sixteen tmp files, all copies of the one PNG causing problems.
I am still not able to perform any SVN subcommand, getting "Run cleanup!" error; on cleanup; I get a failed attempt to copy a tmpfile to the never-sufficiently-damned .PNG file, which no longer exists anywhere, into a directory that no longer exists anywhere.
I tried recreating the directory locally (but not the file!), no changes.
With FileMon, I traced the source PNG to 8e4c2389cf9d85c8b8ee54d49ea053c752a38187.svn-base in .svn/pristine subdirectory, tried removing it and got SVN complaining. I tried copying it to its intended destination (so that the file-as-it-should-be and the file-as-it-is are identical), no joy.
UPDATE
Well, this is weird. I decided to track everything that TortoiseSVN is doing using FileMon. I could see it checking the wc.db and search the item, checking for it in .svn/pristine (and finding it), copying it (unnecessarily if you ask me...) in .svn/tmp, and finally checking $DESTINATION_FILE (with correct case) using Windows Open() API. And getting PATH NOT FOUND. Yet the file is there, I can see it (and the name is less than 8.3 characters). And why PATH not found and not FILE not found?
Okay, it all boiled down to a directory that had been created remotely with a name ending with space. The file in itself was OK; the directory where it stood was not.
When updating, apparently, the directory got created but the name was shortened by Windows to exclude the final space.
To add to the difficulty of diagnosing, while TortoiseSVN did tell me what the problem was, it did so in the dialog box where the Arial font made the space in \path\to\your \file not clearly recognizable (it was, once I knew where to look, and compared that slash with the others. This one stood a little farther from the letter at its left).
Lesson learned: check really carefully the dialog file name, character by character (note to self: find a way of having it in Courier New if at all possible).
You may have two files in the repository that differ only in case. That's a problem on Windows. See this FAQ for details.

let ./configure find library files in specific directory

I'm currently installing R software on a shared space across several servers. After installation I found that when I login on different servers, R is not guaranteed to run due to the missing of some library files on different machines.
Here is what I'm trying to do: since the installation of R is machine-dependent, I'd like to put all missing library files like libtermcap.so.2, libg2c.so.1, etc, to a single directory on the shared space, so that when I run ./configure, it will also search for this directory. Since this directory is shared, the installation could become machine-independent, so I won't need to add missing files on each server.
Is there an option to achieve this when I run ./configure? Thanks.
Assuming you have copied the library files to /shared/lib/ and the header files to /shared/include/, you can run
./configure LDFLAGS=-L/shared/lib CPPFLAGS=-I/shared/include ...other options...
Note, however, that you are bound to run into trouble at run time, when you have to convince your installation to use the shared libraries from the right directory, especially in case someone decides to upgrade the default version on the respective host. That whole business is platform and installation dependent. I think if your hosts are not at least mostly identical, you ought to install your software (R) locally in a way suitable to the respective system.
Peter's answer is correct (+1), and please take special note of his suggestion to install locally. Using the local package management system and auto updating on each box is (in the long run) a much easier solution than trying to get compatible binaries/libraries on a shared drive. To simplify using Peter's solution, note that you can place the appropriate arguments in /shared/share/config.site. For example:
$ cat > /shared/share/config.site << EOF
: ${LDFLAGS=-L/shared/lib}
: ${CPPFLAGS=-I/share/include}
EOF
Whenever you run configure with --prefix=/shared, the config.site file will be read and defaults will be set.

linux script, standard directory locations

I am trying to write a bash script to do a task, I have done pretty well so far, and have it working to an extent, but I want to set it up so it's distributable to other people, and will be opening it up as open source, so I want to start doing things the "conventional" way. Unfortunately I'm not all that sure what the conventional way is.
Ideally I want a link to an in depth online resource that discusses this and surrounding topics in depth, but I'm having difficulty finding keywords that will locate this on google.
At the start of my script I set a bunch of global variables that store the names of the dirs that it will be accessing, this means that I can modify the dir's quickly, but this is programming shortcuts, not user shortcuts, I can't tell the users that they have to fiddle with this stuff. Also, I need for individual users' settings not to get wiped out on every upgrade.
Questions:
Name of settings folder: ~/.foo/ -- this is well and good, but how do I keep my working copy and my development copy separate? tweek the reference in the source of the dev version?
If my program needs to maintain and update library of data (gps tracklog data in this case) where should this directory be? the user will need to access some of this data, but it's mostly for internal use. I personally work in cygwin, and I like to keep this data on separate drive, so the path is wierd, I suspect many users could find this. for a default however I'm thinking ~/gpsdata/ -- would this be normal, or should I hard code a system that ask the user at first run where to put it, and stores this in the settings folder? whatever happens I'm going ot have to store the directory reference in a file in the settings folder.
The program needs a data "inbox" that is a folder that the user can dump files, then run the script to process these files. I was thinking ~/gpsdata/in/ ?? though there will always be an option to add a file or folder to the command line to use that as well (it processed files all locations listed, including the "inbox")
Where should the script its self go? it's already smart enough that it can create all of it's ancillary/settings files (once I figure out the "correct" directory) if run with "./foo --setup" I could shove it in /usr/bin/ or /bin or ~/.foo/bin (and add that to the path) what's normal?
I need to store login details for a web service that it will connect to (using curl -u if it matters) plan on including a setting whereby it asks for a username and password every execution, but it currently stores it plane text in a file in ~/.foo/ -- I know, this is not good. The webservice (osm.org) does support oauth, but I have no idea how to get curl to use it -- getting curl to speak to the service in the first place was a hack. Is there a simple way to do a really basic encryption on a file like this to deter idiots armed with notepad?
Sorry for the list of questions, I believe they are closely related enough for a single post. This is all stuff that stabbing at, but would like clarification/confirmation over.
Name of settings folder: ~/.foo/ -- this is well and good, but how do I keep my working copy and my development copy separate?
Have a default of ~/.foo, and an option (for example --config-directory) that you can use to override the default while developing.
If my program needs to maintain and update library of data (gps tracklog data in this case) where should this directory be?
If your script is running under a normal user account, this will have to be somewhere in the user's home directory; elsewhere, you'll have no write permissions. Perhaps ~/.foo/tracklog or something? Again, add a command line option, and also an option in the configuration file, to override this.
I'm not a fan of your ~/gpsdata default; I don't want my home directory cluttered with all sorts of directories that programs created without my consent. You see this happen on Windows a lot, and it's really annoying. (Saved games in My Documents? Get out of here!)
The program needs a data "inbox" that is a folder that the user can dump files, then run the script to process these files. I was thinking ~/gpsdata/in/ ?
As stated above, I'd prefer ~/.foo/inbox. Also with command-line option and configuration file option to change this.
But do you really need an inbox? If the user needs to run the script manually over some files, it might be better just to accept those file names on the command line. They could just be processed wherever, without having to move them to a "magic" location.
Where should the script its self go?
This is usually up to the packaging system of the particular OS you're running on. When installing from source, /usr/local/bin is a sensible default that won't interfere with package managers.
Is there a simple way to do a really basic encryption on a file like this to deter idiots armed with notepad?
Yes, there is. But it's better not to, because it creates a false sense of security. Without a master password or something, secure storage is not possible! Pidgin, for example, explicitly stores passwords in plain text, so that users won't make any false assumptions about their passwords being stored "securely". So it's best just to store them in plain text, complain if the file is world-readable, and add a clear note to the manual to warn the user what's going on.
Bottom line: don't try to reinvent the wheel. There have been thousands of scripts and programs that faced the same issues; most of them ended up adopting the same conventions, and for good reasons. Look at what they do, and mimic them instead of reinventing the wheel.
You can start with the Filesystem Hierarchy Standard. I'm not sure how well followed it is, but it does provide some guidance. In general, I try to use the following:
$HOME/.foo/ is used for user-specific settings - it is hidden
$PREFIX/etc/foo/ is for system-wide configuration
$PREFIX/foo/bin/ is for system-wide binaries
sym-links from $PREFIX/foo/bin are added to $PREFIX/bin/ for ease of use
$PREFIX/foo/var/ is where variable data would live - this is where your input spools and log files would live
$PREFIX should default to /opt/foo even though almost everyone seems to plop stuff in /usr/local by default (thanks GNU!). If someone wants to install the package in their home directory, then substitute $HOME for $PREFIX. At least that is my take on how this should all work.

Resources