<?xml version="1.0" encoding="UTF-8"?><!-- generator="wordpress.com" -->
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	>

<channel>
	<title>symlink &amp;laquo; WordPress.com Tag Feed</title>
	<link>http://en.wordpress.com/tag/symlink/</link>
	<description>Feed of posts on WordPress.com tagged "symlink"</description>
	<pubDate>Tue, 01 Dec 2009 14:14:00 +0000</pubDate>

	<generator>http://en.wordpress.com/tags/</generator>
	<language>en</language>

<item>
<title><![CDATA[Random Notes &ndash; Creating Symlinks with LN]]></title>
<link>http://jasonk2600.wordpress.com/2009/11/25/random-note-creating-symlinks-with-ln/</link>
<pubDate>Wed, 25 Nov 2009 12:09:00 +0000</pubDate>
<dc:creator>jasonk2600</dc:creator>
<guid>http://jasonk2600.wordpress.com/2009/11/25/random-note-creating-symlinks-with-ln/</guid>
<description><![CDATA[A symlink is simply a pointer to a file or directory.&#160; Symlinks are used in Linux, *BSD, and UN]]></description>
<content:encoded><![CDATA[A symlink is simply a pointer to a file or directory.&#160; Symlinks are used in Linux, *BSD, and UN]]></content:encoded>
</item>
<item>
<title><![CDATA[Sync Skype Chat History on Multiple Machines With Dropbox]]></title>
<link>http://raanan.com/2009/06/22/sync-skype-on-multiple-machines-with-dropbox/</link>
<pubDate>Mon, 22 Jun 2009 17:44:50 +0000</pubDate>
<dc:creator>Raanan Bar-Cohen</dc:creator>
<guid>http://raanan.com/2009/06/22/sync-skype-on-multiple-machines-with-dropbox/</guid>
<description><![CDATA[Skype is awesome. We use it a ton here at Automattic, and it&#8217;s my main communication service f]]></description>
<content:encoded><![CDATA[<div class='snap_preview'><p>Skype is awesome.  We use it a <a href="http://raanan.com/2009/06/12/working-automattic-style/">ton here at Automattic</a>, and it&#8217;s my main communication service for staying in touch with friends and family who are spread out all over the world.  It&#8217;s also still the best text IM client out there.   And now with the <a href="http://www.skype.com/download/skype/iphone/">iPhone app</a>, I can make int&#8217;l calls on mobile without thinking about it.</p>
<p>The one issue though I&#8217;ve had lately, is that I rely on Skype so much, that when I use a second machine I find myself looking through Skype chat history for a link or reference, only to realize that it&#8217;s stored locally on another machine.</p>
<p>In my quest to find an <a href="http://raanan.com/2009/05/13/mozy-backup-review/">ideal backup solution</a>, I&#8217;ve been testing <a href="https://www.getdropbox.com/">Dropbox</a> which allows you to sync files between multiple machines.  So I took a crack at trying to get my Skype chat history to sync.  A quick google search brought up <a href="http://blog.andreaolivato.net/open-source/sync-skype-chronologies-using-dropbox.html">this post</a> which I followed:<br />
<code><br />
Step 1) Quit the Skype application on all machines<br />
Step 2) Move the "main" Skype chat history files to the Dropbox directory:<br />
"mv ~/Library/Application\ Support/Skype ~/Dropbox/"<br />
Step 3) Create a symlink from the original folder to the Dropbox folder:<br />
"ln -s ~/Dropbox/Skype/ ~/Library/Application\ Support/Skype"<br />
Step 4) On your secondary machines, remove the /Library/Application\ Support/Skype folder, and just insert the symlink:<br />
"ln -s ~/Dropbox/Skype/ ~/Library/Application\ Support/Skype"<br />
</code><br />
And it works !  One issue to be aware of: If you are logged-in and running Skype on multiple machines at once, you can get file conflicts and Dropbox will create secondary files &#8211; which kills the whole sync idea.  So for this to work, you need to quit Skype before you plan on using it on another machine &#8212; which isn&#8217;t a bad idea anyway since leaving it open just means missed messages.</p>
<p>And lastly, I posted some of this to the Dropbox forum and one member there recommended a slightly different method where: &#8220;The original stays where it is. Without moving it, one creates a symlink. Its symlink goes into the Drobox folder.&#8221;  I tried that method early on, and at least with Skype, the chat history kept getting written locally and never updating the Dropbox folder.</p>
<p>So for now this is working nicely for me.  I do wonder if in the future Skype would ever offer up a secure way to store chat history with them.  I also did see mention of a new service that tackles this issue for IM history in general called <a href="http://www.im-history.com/">im-hisotry.com</a> &#8212; looks interesting but haven&#8217;t tested so far as it&#8217;s Windows and Linux only.</p>
<p>For anyone thinking of trying the symlink method, as with anything like this, please backup your files before attempting this, as <a href="http://www.urbandictionary.com/define.php?term=YMMV">YMMV</a>.</p>
</div>]]></content:encoded>
</item>
<item>
<title><![CDATA[C: Múltiplos programas no mesmo binário]]></title>
<link>http://codare.net/2009/06/10/c-multiplos-programas-no-mesmo-binario/</link>
<pubDate>Wed, 10 Jun 2009 12:00:06 +0000</pubDate>
<dc:creator>Thiago Santos</dc:creator>
<guid>http://codare.net/2009/06/10/c-multiplos-programas-no-mesmo-binario/</guid>
<description><![CDATA[Um mesmo aplicativo pode se comportar de forma diferente dependendo da forma como é invocado. No exe]]></description>
<content:encoded><![CDATA[<div class='snap_preview'><p>Um mesmo aplicativo pode se comportar de forma diferente dependendo da forma como é invocado. No exemplo a seguir, o mesmo programa é usado para calcular a raiz quadrada e potência de dois de um dado argumento.</p>
<pre>#include &#60;libgen.h&#62;
#include &#60;math.h&#62;
#include &#60;stdio.h&#62;
#include &#60;stdlib.h&#62;
#include &#60;string.h&#62;

int main(int argc, char **argv)
{
    double res;
    char *program = basename(argv[0]);

    if (argc != 2)
        return 1;

    if (!strcmp(program, "sqrt")) {
        res = sqrt(atof(argv[1]));
        printf("%f\n", res);
        return 0;
    }

    if (!strcmp(program, "pow2")) {
        res = pow(atof(argv[1]), 2);
        printf("%f\n", res);
        return 0;
    }

    printf("Invalid program: %s\n", program);

    return 1;
}</pre>
<p>O truque consiste em analisar o primeiro argumento que corresponde ao caminho do binário do programa. No exemplo, decidimos qual ação tomar comparando o nome do programa com &#8220;sqrt&#8221; e &#8220;pow2&#8243;. Para não fazer múltiplas cópias do binário gerado, fazemos links simbólicos.</p>
<pre>$ gcc -Wall -lm -o test test.c
$ ln -s test sqrt
$ ln -s test pow2

$ ./test 5
Invalid program: test

$ ./pow2 5
25.000000

$ ./sqrt 5
2.236068</pre>
<p>A técnica é extensamente utilizada no <a href="http://www.busybox.net/">BusyBox</a> e pode facilmente ser implementada em qualquer outra linguagem de programação.</p>
</div>]]></content:encoded>
</item>
<item>
<title><![CDATA[How to store your music on a NAS or network share and access it with iTunes on a Mac]]></title>
<link>http://blog.davenicoll.com/2009/01/23/how-to-store-your-music-on-a-nas-or-network-share-and-access-it-with-itunes-on-a-mac/</link>
<pubDate>Fri, 23 Jan 2009 21:30:38 +0000</pubDate>
<dc:creator>Dave</dc:creator>
<guid>http://blog.davenicoll.com/2009/01/23/how-to-store-your-music-on-a-nas-or-network-share-and-access-it-with-itunes-on-a-mac/</guid>
<description><![CDATA[I store all my music on an external hard disk which is connected to Windows Server 2003 in a cupboar]]></description>
<content:encoded><![CDATA[<div class='snap_preview'><p><img class="alignnone size-full wp-image-282" title="Album art" src="http://grimfandango.wordpress.com/files/2009/01/album-art.jpg" alt="Album art" width="500" height="344" /></p>
<p>I store all my music on an external hard disk which is connected to Windows Server 2003 in a cupboard hidden away. This means my music doesn&#8217;t clutter up the hard disk on my MBP and it can be shared to other devices like my Xbox, without having my laptop on. Accessing the server from Windows XP or Vista was fairly straightforward &#8211; I&#8217;d just map a drive and iTunes was happy. Unfortunately, persistent mapped drives on Mac OS X 10.5.6 (or earlier) isn&#8217;t really a feature, so I&#8217;d just plug the external hard disk into my Mac via USB.</p>
<p>I needed a way to get my Windows iTunes database onto my Mac, and a way of mounting a persistent network share for iTunes, and a convenient way to add new music to the networked folder and iTunes. (Oh, and I kinda like things being in the <em>right</em> place &#8211; you know, documents in the Documents folder, music in the Music folder &#8211; so we&#8217;ll be creating a symbolic link to make our music appear as though it&#8217;s in ~/Music/iTunes/iTunes Music. Clever, eh?) So, without further ado, here&#8217;s what we&#8217;ll be doing -</p>
<ol>
<li>Setting up a shared folder for your music</li>
<li>Create a symbolic link (&#38; mounted drive) to the network share</li>
<li>Creating a crontab entry to keep the network share mounted (alive)</li>
<li>Modifying the location of your music files in the iTunes database</li>
</ol>
<p><!--more--></p>
<h2>1. Setting up a shared folder for your music</h2>
<p>If you&#8217;ve got a NAS you should go into its admin area and create a file share, call it Music or something useful. Depending on what NAS you have, you&#8217;ll be able to specify a username and password for the shared folder, or for the entire NAS. Either way, note the username and password to access the share &#8211; we&#8217;ll need them later.</p>
<p>If you&#8217;re using an hard disk (internal or external) on a server, go into Computer Manager &#124; Local Users and Groups &#8211; and create a new user. For security reasons, this user will only have access to your music. I created the user &#8220;music&#8221;, but you can use whatever. Note down the username and password. Still in the Computer Management window, go to Shared Folders &#124; Shares in the tree, then Action menu New Share. Create a new shared folder for your music folder, and add the user you just created to the permissions &#8211; give them Full Access (read, write, modify).</p>
<p>It&#8217;s probably a good idea to test accessing the share from your Mac. In Finder, go to the Go menu, and click Connect To Server. In the server address box, type <strong>smb://192.168.0.2/Music</strong> (change the IP address to your NAS or server, and the folder from Music to whatever share name you used). Click Connect, and you should be prompted for a username and password &#8211; use the details of the user you just created.</p>
<h2>2. Create a symbolic link (&#38; mounted drive) to the network share</h2>
<p>Quit iTunes if it&#8217;s running.</p>
<p>Here&#8217;s the command we&#8217;ll be using to create the symbolic link &#8211; this will place a drive icon on the desktop for the mounted network share, and when you go to your ~/Music/iTunes/iTunes Music folder, it&#8217;ll actually be the networked folder.</p>
<pre><strong>/sbin/mount -o nodev,nosuid -t smbfs '//username:password@192.168.0.2/Music' '/Users/YourName/Music/iTunes/iTunes Music'</strong></pre>
<p>And a explanation -</p>
<ul>
<li><strong>/sbin/mount</strong> is the utility which mounts drives and shares</li>
<li><strong>-o nodev,nosuid</strong> parameters are necessary to create a symbolic link (symlink)</li>
<li><strong>-t smbfs</strong> specifies we&#8217;re connecting to a Samba (SMB) network share</li>
<li><strong>username</strong> is the name of the user you created on your NAS or server</li>
<li><strong>password</strong> is the password you specified for that user</li>
<li><strong>192.168.0.2</strong> is the IP address of your NAS or server</li>
<li><strong>/Music</strong> is the shared folder name</li>
<li><strong>/Users/YourName/Music/iTunes/iTunes Music</strong> is the folder we&#8217;re going to make as a symbolic link. You should change YourName to your Mac username</li>
</ul>
<p>We need this command to work properly before we move on, so it would be a good idea to open a Terminal window and try it out. <strong>If you already have a /Users/YourName/Music/iTunes/iTunes Music folder, you should move the contents out of it for now and delete the folder.</strong> Alternatively, if you want to use a different folder, go ahead &#8211; just make sure it&#8217;s empty before you execute the command.</p>
<p>Ok, so if you&#8217;ve got a Music disk mounted on the desktop, proceed to the next step!</p>
<p>It&#8217;s a bit wasteful to blindly execute this command every 10 minutes, so we&#8217;ll put it in a script with a couple of checks. So, open your text editor and copy and paste this code snippet (you&#8217;ll need to change the parts in bold):</p>
<pre>if [ -d '/Users/<strong>YourName</strong>/Music/iTunes/iTunes Music/<strong>ChangeThis</strong>' ]; then
    exit
else
    /sbin/ping -c 1 -t 5 <strong>192.168.0.2</strong> &#38;&#62;/dev/null
    if [ $? -eq 0 ]
    then
        /sbin/mount -o nodev,nosuid -t smbfs '//<strong>username:password@192.168.0.2/Music</strong>' '/Users/<strong>YourName</strong>/Music/iTunes/iTunes Music'
    fi
fi</pre>
<p>What does this do? Well, firstly it checks to see if the drive is already mounted by looking for the folder <strong>/Users/YourName/Music/iTunes/iTunes Music/ChangeThis</strong> &#8211; and if so, exists. <strong>Note:</strong> ChangeThis needs to be a folder on your mounted drive.  If you change the script to check for the existance of <strong>/Users/YourName/Music/iTunes/iTunes Music/</strong>, the system will always find it even when disconnected.</p>
<p>Next it&#8217;ll ping the IP address of your server and if it gets a response, it&#8217;ll try to mount the share. If it doesn&#8217;t get a reply &#8211; probably because you&#8217;re on a different network or not connected &#8211; it&#8217;ll exit. This prevents needlessly sending login attempts across your network.</p>
<p>Ok, save your script in ~/Library/Scripts &#8211; call it <strong>MountMusic.command</strong> or something you can remember.</p>
<h2>3. Creating a crontab entry to keep the network share mounted</h2>
<p>In a nutshell, a crontab is a set of commands which can be run at set intervals &#8211; perfect for refreshing our mounted network share, and especially handy for mounting the drive shortly after you&#8217;ve logged in or woken your Mac from sleep. Editing the crontab isn&#8217;t difficult but it can be fiddly. I use a great little utility called <a href="http://www.macupdate.com/info.php/id/7486">CronniX</a> which I&#8217;ll be using for this tutorial.</p>
<p>Now the thing is with cron is that when it does something, it likes to send you an email about it. And left unchecked, it can create a whopping great big mail file. And we don&#8217;t want that, do we! In CronniX go the Edit menu, and click Env. Variables. &#8211; add a new environment variable &#8220;MAILTO&#8221; (sans quotes). For the MAILTO value, type double quotes (&#8220;&#8221;).</p>
<p>I run the mount command (above) every 10 minutes. If the network share has already been mounted, that&#8217;s fine, otherwise it&#8217;ll mount it again. If there&#8217;s no network share to mount &#8211; maybe you&#8217;re at work or school &#8211; it&#8217;ll fail silently. Using CronniX, create the following entries -</p>
<p><strong><code>Min  Hour  Mday  Month  Wday  Command</code></strong><br />
<code>0    *      *      *       *     ~/Library/Scripts/MountMusic.command</code><br />
<code>10     *          *          *            *</code><code> </code><code>~/Library/Scripts/MountMusic.command</code><br />
<code>20      *          *          *            *</code><code> </code><code>~/Library/Scripts/MountMusic.command</code><br />
<code>30      *     *          *            *</code><code> </code><code>~/Library/Scripts/MountMusic.command</code><br />
<code>40      *          *          *            *</code><code> </code><code>~/Library/Scripts/MountMusic.command</code><br />
<code>50      *          *          *            *</code><code> </code><code>~/Library/Scripts/MountMusic.command</code></p>
<p>So you&#8217;ve created 6 entries, set to run at 0, 10, 20, 30, 40 and 50 minutes past the hour, and it&#8217;ll be running your mount command. Once you&#8217;ve done that, click Save in the main CronniX window.</p>
<p>Chances are you still have the Music disk mounted on your desktop from before &#8211; right click on it, and Eject it (or drag it onto the recycle bin). If you wait until your clock shows 0, 10, 20, 30, 40 or 50 minutes (i.e. 10:40), a few seconds later the Music disk should reappear on your desktop &#8211; if it does, move on&#8230;</p>
<h2>4. Modifying the location of your music files in the iTunes database</h2>
<p>I have a fairly substantial music collection, all nicely tagged and with genres, ratings and play counts &#8211; which I don&#8217;t want to lose. If you don&#8217;t care about this extra info, you can pretty much skip most of this step.</p>
<p>I&#8217;ve searched high and low for an AppleScript or app to go through my iTunes database and mass change the location of my music files, but let me tell you &#8211; there is NOTHING that does it without serious effort. There are a few alternative techniques, but they don&#8217;t preserve your folder structure or meta data. So, we&#8217;ll be using the &#8220;corrupt iTunes database&#8221; method&#8230;</p>
<p>Go to your iTunes folder (~/Music/iTunes/) and in there you should find two files &#8211; iTunes Library (or iTunes Library.itl from the PC) and iTunes Music Library.xml. Rename the iTunes Library file to something else and create a file with the same name in TextEdit. Next, open iTunes Music Library.xml in TextEdit (or whatever text editor your prefer) and not too far down,  you&#8217;ll see something like this -</p>
<p><code>file://localhost/Volumes/MyDisk/Music/Albums/Band/Track.mp3</code></p>
<p>You need to search and replace the /Volumes/MyDisk part so you end up with something like -</p>
<p><code>file://localhost/Users/YourName/Music/Albums/Band/Track.mp3</code></p>
<p>Save the file and start iTunes. You should see iTunes recreating your library from the XML file &#8211; this may take some time. Fingers crossed, iTunes will eventually open and your music library should be intact!</p>
<p>Done <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
</div>]]></content:encoded>
</item>
<item>
<title><![CDATA[Linux Link "Operation Not Permitted"?]]></title>
<link>http://amandakerik.wordpress.com/2009/01/08/linux-link-operation-not-permitted/</link>
<pubDate>Thu, 08 Jan 2009 13:27:03 +0000</pubDate>
<dc:creator>amandakerik</dc:creator>
<guid>http://amandakerik.wordpress.com/2009/01/08/linux-link-operation-not-permitted/</guid>
<description><![CDATA[I ran into an interesting snag today: one of my favourite games (Widelands) is installed on my secon]]></description>
<content:encoded><![CDATA[<div class='snap_preview'><p>I ran into an interesting snag today: one of my favourite games (Widelands) is installed on my second hard drive but has a save game folder in my home folder.<br />
I didn&#8217;t like this (my home folder&#8217;s big enough as it is) so I tried to create a folder in Widelands&#8217; folder and then make a (sym)link to it from my home folder.</p>
<p>Operation not Permitted.</p>
<p>No explanation why (that needs to be changed), but a quick Google search found the problem:</p>
<p>My Widelands install (and therefore the temp directory I was going to use for the saved games) is on a FAT formatted drive.</p>
<p>FAT (in whatever incarnation you have &#8211; NTFS, FAT32, whatever) doesn&#8217;t do (sym)links.</p>
<p>So&#8230; short of making the partition the game was on a different format (and wiping it in the meantime)&#8230; I moved my Widelands install to my ext3 partition.</p>
<p>Linked and off we go! Easy, once you know the problem.</p>
</div>]]></content:encoded>
</item>
<item>
<title><![CDATA[helping to destroy ratio P2P peering one step at a time]]></title>
<link>http://himself.wordpress.com/2008/12/31/helping-to-destroy-ratio-p2p-peering-one-step-at-a-time/</link>
<pubDate>Thu, 01 Jan 2009 07:26:38 +0000</pubDate>
<dc:creator>Sagacious Himself</dc:creator>
<guid>http://himself.wordpress.com/2008/12/31/helping-to-destroy-ratio-p2p-peering-one-step-at-a-time/</guid>
<description><![CDATA[helping to destroy ratio P2P peering one step at a time How do I create multiple large files that co]]></description>
<content:encoded><![CDATA[<div class='snap_preview'><p><a href="http://himself.wordpress.com/2008/12/31/helping-to-destroy-ratio-p2p-peering-one-step-at-a-time/">helping to destroy ratio P2P peering one step at a time</a></p>
<blockquote><p>How do I create multiple large files that consume no extra diskspace?</p></blockquote>
<p>Create multiple <a href="http://schinagl.priv.at/nt/hardlinkshellext/hardlinkshellext.html?love=SagaciousHimself" target="_blank">Hardlink</a>s to one or more files.  Change the names of the Hardlinks to suit.</p>
<p><span style="font-family:mceinline;">.</span></p>
<p> <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' /> </p>
<p>[ <a href="http://himself.wordpress.com/?from=theif" target="_blank">Himself</a> ]</p>
</div>]]></content:encoded>
</item>
<item>
<title><![CDATA[Conoscere e usare i Collegamenti: Symbolic link e Hard link]]></title>
<link>http://hackgeek.wordpress.com/2008/11/19/conescere-e-usare-i-collegamenti-symbolic-link-e-hard-link/</link>
<pubDate>Wed, 19 Nov 2008 14:35:48 +0000</pubDate>
<dc:creator>hackgeek</dc:creator>
<guid>http://hackgeek.wordpress.com/2008/11/19/conescere-e-usare-i-collegamenti-symbolic-link-e-hard-link/</guid>
<description><![CDATA[Oggi voglio parlarvi di uno strumento che ci permette di rendere il file system e la gestione di fil]]></description>
<content:encoded><![CDATA[<div class='snap_preview'><p><a href="http://hackgeek.wordpress.com/files/2008/11/linux.jpg"><img class="alignright size-full wp-image-448" title="linux" src="http://hackgeek.wordpress.com/files/2008/11/linux.jpg" alt="linux" width="250" height="175" /></a>Oggi voglio parlarvi di uno strumento che ci permette di rendere il <a href="../2008/11/03/lorganizzazione-delle-directory-ed-il-filesystem-hierarchy-standard/">file system</a> e la gestione di file e directory molto più flessibile,sto parlando dei <strong>Collegamenti</strong>.</p>
<p><strong><a title="Collegamenti Linux" href="http://www.hackgeek.it/conescere-e-usare-i-collegamenti-symbolic-link-e-hard-link/" target="_blank">Continua sul Nuovo Blog&#8230;</a></strong></p>
<p style="margin-bottom:0;"> </p>
<p style="margin-bottom:0;"> </p>
</div>]]></content:encoded>
</item>
<item>
<title><![CDATA[Symbolische Links richtig anlegen]]></title>
<link>http://codecocktail.wordpress.com/2008/11/01/symbolische-links-richtig-anlegen/</link>
<pubDate>Sat, 01 Nov 2008 20:03:05 +0000</pubDate>
<dc:creator>charlysan</dc:creator>
<guid>http://codecocktail.wordpress.com/2008/11/01/symbolische-links-richtig-anlegen/</guid>
<description><![CDATA[Schon zum zweiten Mal habe ich mir heute den Kopf darüber zerbrochen was ich falsch mache beim Symli]]></description>
<content:encoded><![CDATA[<div class='snap_preview'><p>Schon zum zweiten Mal habe ich mir heute den Kopf darüber zerbrochen was ich falsch mache beim Symlink anlegen. In der Theorie geht es so:</p>
<p><strong>ln -s original_datei symlink_quelle</strong></p>
<p>Doch ich bekomme ständig leere Symlinks und damit Fehler wie:</p>
<p><em>chmod: kann nicht auf der freihängenden symbolischen Verknüpfung &#8220;Testdatei&#8221; arbeiten</em></p>
<p>Die Lösung:</p>
<p>Die Pfade müssen absolut nicht relativ angegeben werden (besonders wenn man das bei der Original Datei nicht tut gibt das Probleme), das kann man dann zum Beispiel mit &#8216;<em>pwd</em>&#8216; erreichen (pwd gibt den aktuellen  Pfad zurück).</p>
<p><strong>ln -s &#8216;pwd&#8217;/OriginalDatei /home/user/files/SymLink</strong></p>
<p>Die Anführungsstriche müssen übrigens Backticks sein.</p>
<p><em><br />
</em></p>
</div>]]></content:encoded>
</item>
<item>
<title><![CDATA[Mount remote filesystem over SSH with SSHFS]]></title>
<link>http://firmit.wordpress.com/2008/07/07/mount-remote-filesystem-over-ssh-with-sshfs/</link>
<pubDate>Mon, 07 Jul 2008 09:55:18 +0000</pubDate>
<dc:creator>firmit</dc:creator>
<guid>http://firmit.wordpress.com/2008/07/07/mount-remote-filesystem-over-ssh-with-sshfs/</guid>
<description><![CDATA[Using SSH is somewhat not easy for a newbie. To copy files over SSH, you need long commands. So, why]]></description>
<content:encoded><![CDATA[<div class='snap_preview'><p>Using SSH is somewhat not easy for a newbie. To copy files over SSH, you need long commands. So, why not just mount the remote filesystem on your local computer!</p>
<p>Fuse is a part of the latest kernel, so you don&#8217;t need to install fuse-utils (if you&#8217;re not sure if you have fuse, run <strong>lsmod &#124; grep fuse.</strong>) So &#8211; install sshfs:</p>
<blockquote><p>sudo aptitude install sshfs</p></blockquote>
<p>You need permission to use the fuse function &#8211; so add yourself to the groups:</p>
<blockquote><p>sudo usermod -a -G fuse username</p></blockquote>
<p>Now &#8211; create a directory where you want the remote filesystem (make sure you are the owner of the directory). I choose /media/directory</p>
<blockquote><p>cd /media<br />
sudo mkdir ext_sys<br />
sudo chown myusername:myusergroup ext_sys</p></blockquote>
<p>Now &#8211; you mount the system (I use /media/ext_sys as mount point)</p>
<blockquote><p>sshfs remote_username@remote_ip: /media/ext_sys</p></blockquote>
<p>To unmount, run</p>
<blockquote><p>fusermount -u /media/ext_sys</p></blockquote>
<p>Got to love Linux! I had a problem with my usb-stick &#8211; but ssh popped into my head &#8211; and voila! You learn something everyday <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><strong>Updated:</strong></p>
<p>You can allow the option to follow symlinks by adding &#8216; -o follow-symlinks&#8217;</p>
<blockquote><p>sshfs -o follow-symlinks user@server: /mnt/point</p></blockquote>
</div>]]></content:encoded>
</item>
<item>
<title><![CDATA[Symlinks under Windows using SBCL -- #'truename &amp; ASDF]]></title>
<link>http://brainrack.wordpress.com/2008/05/29/symlinks-under-windows-using-sbcl-truename-asdf/</link>
<pubDate>Thu, 29 May 2008 20:13:19 +0000</pubDate>
<dc:creator>brainrack</dc:creator>
<guid>http://brainrack.wordpress.com/2008/05/29/symlinks-under-windows-using-sbcl-truename-asdf/</guid>
<description><![CDATA[This post applies to running Steel Bank Common Lisp version 1.0.16 &#8211; 1.0.17.14 on Windows Vist]]></description>
<content:encoded><![CDATA[<div class='snap_preview'><blockquote><p>This post applies to running Steel Bank Common Lisp version 1.0.16 &#8211; 1.0.17.14 on Windows Vista. It may apply to later or earlier versions of SBCL, but I cannot directly attest to that. It may apply to certain functionality under Windows XP, but I cannot attest to that either.</p>
<p><span style="color:#339966;">[Update 07 June 2008]  I have made a few modifications to the attached code in order to:<br />
</span><span style="font-size:x-small;"><span style="color:#339966;">- place (D. Lichteblau&#8217;s) support for SHORTCUT files in a separate function PARSE-WINDOWS-SHORTCUT (to ensure stream-read-invariance wrt TRUENAME);<br />
</span><span style="color:#339966;">- add a redefinition for FILE-WRITE-DATE to mimic Unix behavior under Windows;<br />
</span><span style="color:#339966;">- add behavior so that TRUENAME of a recursive or dangling link returns the pathname of the link, and does not signal an error;<br />
</span><span style="color:#339966;">- add support for symbolic links containing relative pathnames;<br />
</span><span style="color:#339966;">- add support for symbolic links to different disks/volumes.</span></span></p></blockquote>
<p>With reference to:</p>
<p><a href="http://robert.zubek.net/blog/2008/04/09/sbcl-emacs-windows-vista/">http://robert.zubek.net/blog/2008/04/09/sbcl-emacs-windows-vista/</a><br />
<a href="http://sbcl-internals.cliki.net/Build%20on%20Windows">http://sbcl-internals.cliki.net/Build%20on%20Windows</a><br />
<a href="http://www.sbcl.org/">http://www.sbcl.org/</a><br />
<a href="http://brainrack.wordpress.com/2008/05/29/running-sbcl-on-windows/">http://brainrack.wordpress.com/2008/05/29/running-sbcl-on-windows/</a><br />
<a href="http://brainrack.wordpress.com/2008/05/28/broken-and-ill-documented-api-for-windows-mount-points/">http://brainrack.wordpress.com/2008/05/28/broken-and-ill-documented-api-for-windows-mount-points/</a></p>
<h2>Broken #&#8217;truename and annoying ASDF under Windows using SBCL</h2>
<p>The CLtL2 specification requires #&#8217;truename to return the &#8220;canonical&#8221; pathname of a file.  Most lisps interpret this to mean that when a pathname refers to a link, the link should be followed in order to return the pathname under which the file actually resides.  Indeed, this is the way the UNIX implementation of SBCL functions with regard to #&#8217;truename.  However, the Windows implementation of SBCL does not function the same as the UNIX implementation: (truename pathspec) will not follow links under Windows.</p>
<p>Complaining about this would be a petty bit of specs-manship were it not for the fact that the standard system definition facility ASDF relies on following links in order to function as designed.  I find the intended behavior of ASDF to be elegant and convenient and so I set out to restore the ANSI functionality of #&#8217;truename under SBCL Windows.</p>
<p>[This issue has a history: see Stephan Lang's <a href="http://marc.info/?l=sbcl-devel&#38;m=117357216708358&#38;w=2"><span style="text-decoration:underline;"><span style="font-size:x-small;color:#0000ff;">http://marc.info/?l=sbcl-devel&#38;m=117357216708358&#38;w=2</span></span></a><span style="font-size:x-small;">; David Lichteblau's <a href="http://www.lichteblau.com/blubba/shortcut/asdf.lisp">http://www.lichteblau.com/blubba/shortcut/asdf.lisp</a>; and a discussion initiated by Nikodemus Siivola at <a href="http://article.gmane.org/gmane.lisp.cclan.general/740">http://article.gmane.org/gmane.lisp.cclan.general/740</a>.]</span></p>
<p>Fixing the problem required me to delve deeply into some very dark recesses of the Microsoft Windows API, as well as SBCL&#8217;s FFI.  Along the way I encountered all the usual abominations one must deal with when trying to program in Microsoftland: incorrect documentation, broken functions, vague and underspecified behaviors, inconsistent functionality between related functions, bizarre designs, Hungarian variable notation, and generally rococo APIs seemingly still implemented in a pre-1980 version of &#8216;C&#8217; and modified from a cribbed copy of CPM.  Some details are <a href="http://brainrack.wordpress.com/2008/05/28/broken-and-ill-documented-api-for-windows-mount-points/">here</a>.  I feel most highly-privileged to have encountered the rare and wonderful &#8216;dammit-the-documentation-changed-while-I-was-reading-it!&#8217; experience at <a href="http://msdn.microsoft.com/en-us/library/ms791514.aspx">http://msdn.microsoft.com/en-us/library/ms791514.aspx</a>.</p>
<p>My plaints should not be taken to slight the abominations in SBCL&#8217;s FFI, however, for they are truly ghastly and profound.  (Try to figure out exactly how c-strings and (* char)&#8217;s are handled sometime!)</p>
<p>Nonetheless, I have a working version of</p>
<p>(LINKED-TRUENAME filespec) &#8212; if the last part of the path of /filespec/ points to a link, return a pathname in which the link is resolved, else return the usual truename.</p>
<p>I have tested this function to verify that it works on file symlinks, directory symlinks, and mount points (aka junctions) as produced by mklink, mklink /D, mklink /J, mountvol, and the Disk Manager.</p>
<p>I don&#8217;t know if the fix will ever make it into the SBCL distribution.  I&#8217;m not sure I want to jump through all the hoops necessary.  In the meantime, it works for me, and hopefully for you.</p>
<p>Here&#8217;s the source:</p>
<pre>;;;
;;;
;;; Code for following symlinks under Windows Vista
;;; Redefined truename so truename returns pathname of linked file
;;; This functionality is necessary for running asdf as it is designed
;;; - Neil Haven, June 2008
;;;
;;; For Microsoft reparse-points handling see:
;;; http://blog.kalmbach-software.de/2008/02/28/howto-correctly-read-reparse-data-in-vista/
;;;
;;; For Windows .lnk file handling see:
;;; "Jesse Hager: The Windows Shortcut File Format."
;;; http://www.wotsit.org/list.asp?fc=13
;;; Some code excerpted from David Lichteblau's modifications to asdf.lisp
;;; http://www.lichteblau.com/blubba/shortcut/asdf.lisp
;;;

(defpackage #:winlinks
    (:nicknames #:wl)
  (:documentation "Package for redefining truename so it follows links.")
  (:use #:cl #:sb-alien #:sb-ext)
  (:shadow #:truename #:file-write-date)
  (:export #:override-truename #:override-file-write-date
           #:parse-windows-shortcut))

(in-package #:wl)

#&#124;
To create a mount point under Vista use mklink /J ...
To create a symbolic file link use mklink ...
To create a directory link use mklink ...
&#124;#

#&#124;
typedef struct _REPARSE_DATA_BUFFER {
  ULONG  ReparseTag;
  USHORT  ReparseDataLength;
  USHORT  Reserved;
  union {
    struct {
      USHORT  SubstituteNameOffset;
      USHORT  SubstituteNameLength;
      USHORT  PrintNameOffset;
      USHORT  PrintNameLength;
      ULONG   Flags; // it seems that the docu is missing this entry (at least 2008-03-07)
      WCHAR  PathBuffer[1];
      } SymbolicLinkReparseBuffer;
    struct {
      USHORT  SubstituteNameOffset;
      USHORT  SubstituteNameLength;
      USHORT  PrintNameOffset;
      USHORT  PrintNameLength;
      WCHAR  PathBuffer[1];
      } MountPointReparseBuffer;
    struct {
      UCHAR  DataBuffer[1];
    } GenericReparseBuffer;
  };
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;

#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE  ( 16 * 1024 )

//
// The reparse tags are a DWORD. The 32 bits are laid out as follows:
//
//   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
//   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
//  +-+-+-+-+-----------------------+-------------------------------+
//  &#124;M&#124;R&#124;N&#124;R&#124;     Reserved bits     &#124;       Reparse Tag Value       &#124;
//  +-+-+-+-+-----------------------+-------------------------------+
//
// M is the Microsoft bit. When set to 1, it denotes a tag owned by Microsoft.
//   All ISVs must use a tag with a 0 in this position.
//   Note: If a Microsoft tag is used by non-Microsoft software, the
//   behavior is not defined.
//
// R is reserved.  Must be zero for non-Microsoft tags.
//
// N is name surrogate. When set to 1, the file represents another named
//   entity in the system.
//

&#124;#

(defun override-truename (&#38;optional (package *package*))
  "replace definition of truename in /package/ "
  (shadowing-import 'wl::truename package))

(defun override-file-write-date (&#38;optional (package *package*))
  "replace definition of file-write-date in /package/ "
  (shadowing-import 'wl::file-write-date package))

(defun wchar-string-&#62;lisp-string (wstring &#38;optional (length -1))
  "
  Arguments: /wstring/ is a pointer to a zero-terminated
    array of wchars (unsigned shorts)
    /length/, if supplied, truncates the translation after
    /length/ number of characters if a zero-termination is not
    encountered before that
  Semantics: translates /wstring/ to a lisp string.  If
    /wstring/ is a null pointer, returns nil
  Returns: a lisp string or nil.
  "
  (declare (type (alien (* unsigned-short)) wstring)
           (type integer length))
  (when (null-alien wstring)
    (return-from wchar-string-&#62;lisp-string nil))
  ;; calculate the length
  (when (minusp length)
    (do ((index 0 (incf index)))
        ((= (deref wstring index) 0) (setq length index))))
  (do* ((index 0 (incf index))
        (wchar (deref wstring index) (deref wstring index))
        (lisp-string (make-array length :element-type 'character)))
       ((= index length) lisp-string)
    (declare (type integer index)
             (type (unsigned-byte 16) wchar)
             (type string lisp-string))
    (setf (aref lisp-string index) (code-char wchar))))

(defun lisp-string-&#62;wchar-string (string)
  "
  Semantics: converts the lisp /string/ into an alien pointer to
    a zero-terminated array of wide (16-bit) chars.  Any
    characters in /string/ with a unicode code point
    &#62; #xFFFF are given a representation as #xFFFD -- the
    standard unicode Replacement Character
  Returns: Two values: an alien pointer to a zero-terminated array of
    16-bit chars suitable for passing to a Windows API;
    and the length of the string
  "
  (let* ((size (length string))
         (wchar-string (make-alien (unsigned 16) (1+ size)))
         (unicode 0)
         (wchar 0))
    (declare (type integer size unicode)
             (type (unsigned-byte 16) wchar))
    (dotimes (index size)
      (setq unicode (char-code (elt string index)))
      (when (&#62; unicode #xFFFF) (setq unicode #xFFFD)) ; coerce to 16-bits
      (setq wchar (coerce unicode '(unsigned-byte 16)))
      (setf (deref wchar-string index) wchar))
    (setf (deref wchar-string size) 0)
    (return-from lisp-string-&#62;wchar-string
      (values wchar-string size))))

(defun lisp-string-&#62;char-string (string)
  "
  Semantics: converts the lisp /string/ into an alien pointer to
    a zero-terminated array of 8-bit chars.  Any
    characters in /string/ with a unicode code point
    &#62; #xFF are given a representation as #x1A -- the
    standard unicode Substitute control
  Returns: Two values: an alien pointer to a zero-terminated array of
    8-bit chars suitable for passing to a Windows API;
    and the length of the string
  "
  (let* ((size (length string))
         (char-string (make-alien (unsigned <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_cool.gif' alt='8)' class='wp-smiley' /> (1+ size)))
         (unicode 0)
         (char 0))
    (declare (type integer size unicode)
             (type (unsigned-byte <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_cool.gif' alt='8)' class='wp-smiley' /> char))
    (dotimes (index size)
      (setq unicode (char-code (elt string index)))
      (when (&#62; unicode #xFF) (setq unicode #x1A)) ; coerce to 8-bits
      (setq char (coerce unicode '(unsigned-byte 8)))
      (setf (deref char-string index) char))
    (setf (deref char-string size) 0)
    (return-from lisp-string-&#62;char-string
      (values char-string size))))

(define-alien-type nil
    (struct SymbolicLinkStructure
            (substitute-name-offset unsigned-short) ; 2 bytes
            (substitute-name-length unsigned-short) ; 2 bytes
            (print-name-offset unsigned-short) ; 2 bytes
            (print-name-length unsigned-short) ; 2 bytes
            (flags unsigned-long)       ; 4 bytes
            (path-buffer (array unsigned-short 246)))) ; 492 bytes

(define-alien-type nil
    (struct MountPointStructure
            (substitute-name-offset unsigned-short) ; 2 bytes
            (substitute-name-length unsigned-short) ; 2 bytes
            (print-name-offset unsigned-short) ; 2 bytes
            (print-name-length unsigned-short) ; 2 bytes
            (path-buffer (array unsigned-short 248)))) ; 496 bytes

(define-alien-type nil
    (struct GenericReparseStructure
            (data-buffer (array char 504)))) ; 504 bytes

(define-alien-type nil
    (union ReparseUnion
           (symbolic-link-structure (struct SymbolicLinkStructure))
           (mount-point-structure (struct MountPointStructure))
           (generic-reparse-structure (struct GenericReparseStructure))))

(define-alien-type nil
    (struct ReparseStructure
            (reparse-tag unsigned-long) ; 4 bytes
            (length unsigned-short)     ; 2 bytes
            (reserved unsigned-short)   ; 2 bytes
            (reparse-union (union ReparseUnion)))) ; 504 bytes

(defmacro reparse-tag-p (reparse-tag)
  "Is /reparse-tag/ a legal Microsoft reparse tag?"
  ;(declare (type (unsigned-byte 32) reparse-tag))
  `(= #x80000000 (logand ,reparse-tag #x80000000)))

(defmacro name-surrogate-p (reparse-tag)
  "Is the /reparse-tag/ from a surrogate for another file?"
  ;(declare (type (unsigned-byte 32) reparse-tag))
  `(= #x20000000 (logand ,reparse-tag #x20000000)))

(defmacro mount-point-p (reparse-tag)
  "Is the /reparse-tag/ a Microsoft mount point?"
  ;(declare (type (unsigned-byte 32)) reparse-tag)
  `(= #xA0000003 (logand ,reparse-tag #xA0000003)))

(defmacro symlink-p (reparse-tag)
  "Is the /reparse-tag/ a Microsoft symlink?"
  ;(declare (type (unsigned-byte 32)) reparse-tag)
  `(= #xA000000C (logand ,reparse-tag #xA000000C)))

#&#124;
HANDLE WINAPI CreateFile(
  __in      LPCTSTR lpFileName,
  __in      DWORD dwDesiredAccess,
  __in      DWORD dwShareMode,
  __in_opt  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  __in      DWORD dwCreationDisposition,
  __in      DWORD dwFlagsAndAttributes,
  __in_opt  HANDLE hTemplateFile
);

BOOL WINAPI DeviceIoControl(
  __in         HANDLE hDevice,
  __in         DWORD dwIoControlCode,
  __in_opt     LPVOID lpInBuffer,
  __in         DWORD nInBufferSize,
  __out_opt    LPVOID lpOutBuffer,
  __in         DWORD nOutBufferSize,
  __out_opt    LPDWORD lpBytesReturned,
  __inout_opt  LPOVERLAPPED lpOverlapped
);
&#124;#

(load-shared-object "Kernel32")

(declaim (inline CreateFileA))

(declaim (inline CloseHandle))

(declaim (inline DeviceIoControl))

(declaim (inline GetVolumeNameForVolumeMountPointA))

(define-alien-routine ("GetVolumeNameForVolumeMountPointA" GetVolumeNameForVolumeMountPointA) int
  (mount-point (* unsigned-char))
  (volume-name (* unsigned-char))
  (buffer-length unsigned-int))

(define-alien-routine ("CreateFileA" CreateFileA) int
  (filename (* unsigned-char))
  (access unsigned-int)
  (sharemode unsigned-int)
  (security unsigned-int)
  (create unsigned-int)
  (flags unsigned-int)
  (template unsigned-int))

(define-alien-routine ("CloseHandle" CloseHandle) int
  (device int))

(define-alien-routine ("DeviceIoControl" DeviceIoControl) int
  (device unsigned-int)
  (control unsigned-int)
  (inBuffer (* t))
  (inSize unsigned-int)
  (outBuffer (* (struct ReparseStructure)))
  (outSize unsigned-int)
  (bytesReturned (* unsigned-int))
  (overlapped (* t)))

(defun get-link-handle (filespec)
  "returns -1 on failure, otherwise returns handle for /filespec/"
  (let ((filename (lisp-string-&#62;char-string (namestring filespec))))
    ;; for the interpretation of the magic numbers, see the kalmbach reference
    (CreateFileA filename #x8 #x7 #x0 #x3 #x02200000 #x0)))

(defun get-volume-name (mount-point)
  "
  Semantics: returns lisp string for underlying volume name of mount point
    If there is no underlying volume name, return /mount-point/
  Arguments: /mount-point/ is a string pathname designator
  Returns: lisp string in form \\\\?\\Volume{GUID}\\ if /mount-point/ exists
    else returns original /mount-point/
  "
  ;; GetVolumePathNamesForVolumeName, does not seem to work for me.
  ;; So this is a tedious bit of kludgy sequential search.
  (let ((volume-name (make-alien unsigned-char 64)) ; Microsoft doco says the max length is 50
        (result 0))
    (declare (type integer result))
    ;; read the low-level volume name given a normal path
    (setq result
          (GetVolumeNameForVolumeMountPointA (lisp-string-&#62;char-string mount-point) volume-name 64))
    (when (zerop result)
      ;; if the call fails, the path isn't a mount point
      (return-from get-volume-name mount-point))
    ;; now create a lisp string from the character array
    (let ((volume (make-string 64)))
      (declare (type string volume))
      (dotimes (i 64)
        (let ((c (deref volume-name i)))
          (when (zerop c)
            ;; hit end of array, so truncate the string
            (setq volume (subseq volume 0 i))
            (return))
          (setf (char volume i) (code-char c))))
      volume)))

(defun volume-name-&#62;disk-name (volume-name)
  "
  Semantics: returns disk-name for low-level volume name
  Arguments: /volume-name/ is a low-level volume name
    of the form \\??\\Volume{GUID}\\
  Returns: lisp string in form X:\\ where X is the disk name.
    or /volume-name/ if there is no associated disk
  "
  (dotimes (disk 26 volume-name)
    (let* ((disk-name (concatenate 'string (string (code-char (+ disk (char-code #\A)))) ":\\"))
           (disk-volume-name (get-volume-name disk-name)))
      (when (and (&#62;= (length volume-name) (length disk-volume-name) 4)
                 (equalp (subseq disk-volume-name 4) (subseq volume-name 4)))
        (return-from volume-name-&#62;disk-name disk-name)))))

(defun mount-point-&#62;disk-name (pathspec)
  "
  Semantics: Converts the mount point /pathspec/ into the name of the disk
    it points to.
  Arguments: /pathspec/ is the pathspec of a mount point
  Returns: the namestring of the disk pointed to by /pathspec/
  Error Conditions: signals
  "
  (let ((volume-name (get-volume-name (namestring (cl::truename pathspec)))))
    (volume-name-&#62;disk-name volume-name)))

(defun extract-path-from-mount-point (reparseStructure)
  "internal function for getting a path from a mount point"
  (declare (type (alien (struct ReparseStructure)) reparseStructure))
  ;; get the union fron the reparse structure
  (with-alien
      ((reparseUnion (union ReparseUnion) (slot reparseStructure 'reparse-union)))
    ;; get the mount-point from the union
    (with-alien
        ((mount-point (struct MountPointStructure) (slot reparseUnion 'mount-point-structure)))
      ;; get the string buffer from the mount-point
      (with-alien ((buffer (array unsigned-short 248) (slot mount-point 'path-buffer))
                   (sname-offset unsigned-short (slot mount-point 'substitute-name-offset))
                   (sname-length unsigned-short (slot mount-point 'substitute-name-length)))
        ;; adjust for size of wchar
        (setq sname-offset (/ sname-offset 2)) ; offset is returned in bytes
        (setq sname-length (/ sname-length 2)) ; length is returned in bytes
        ;; get the lisp equivalent
        (let ((sname-string
               (wchar-string-&#62;lisp-string (addr (deref buffer sname-offset)) sname-length)))
          ;; sname-string has form \??\Volume{GUID}\
          ;; OR sname-string has form \??\X:\ -- it all depends...
          (if (&#62; (length sname-string) (length "\\??\\X:\\"))
              ;; we have to do this the hard way
              (volume-name-&#62;disk-name sname-string)
              ;; otherwise don't forget to lop off the \??\ part...
              (subseq sname-string 4)))))))

(defun extract-path-from-symlink (reparseStructure)
  "internal function for getting a path from a symlink"
  ;; get the union from the structure
  (with-alien
      ((reparseUnion (union ReparseUnion) (slot reparseStructure 'reparse-union)))
    ;; get the symlink from the union
    (with-alien
        ((symlink (struct SymbolicLinkStructure) (slot reparseUnion 'symbolic-link-structure)))
      ;; get the string buffer from the symlink
      (with-alien ((buffer (array unsigned-short 246) (slot symlink 'path-buffer)))
        (let ((sname-offset (slot symlink 'substitute-name-offset))
              (pname-offset (slot symlink 'print-name-offset))
              (sname-length (slot symlink 'substitute-name-length))
              (pname-length (slot symlink 'print-name-length)))
          (declare (type integer sname-offset pname-offset sname-length pname-length))
          ;; adjust for size of wchar
          (setq sname-offset (/ sname-offset 2)) ; offset is returned in bytes
          (setq pname-offset (/ pname-offset 2))
          (setq sname-length (/ sname-length 2)) ; length is returned in bytes
          (setq pname-length (/ pname-length 2))
          ;; convert the alien pointer to a lisp string
          (with-alien
              ((sname (* unsigned-short) (addr (deref buffer sname-offset))))
              ;; (pname (* short) (addr (deref buffer pname-offset))))
            (let ((slink (wchar-string-&#62;lisp-string sname sname-length))
                  (indicator-length (length "\\??\\")))
              ;; if linking another device, we need to strip a \\??\\ from the front...
              (if (and (&#62;= (length slink) indicator-length)
                       (equal "\\??\\" (subseq slink 0 indicator-length)))
                  (subseq slink indicator-length)
                  slink))))))))

;;;; Windows shortcut support.  Based on:

;;; Jesse Hager: The Windows Shortcut File Format.
;;; http://www.wotsit.org/list.asp?fc=13
;;; Taken from David Lichteblau's modifications to asdf.lisp
;;; http://www.lichteblau.com/blubba/shortcut/asdf.lisp

;;; For the meaning of the magic numbers, see the Hager reference
(defparameter *link-initial-dword* 76)
(defparameter *link-guid* #(1 20 2 0 0 0 0 0 192 0 0 0 0 0 0 70))

(defun read-null-terminated-string (s)
  (with-output-to-string (out)
    (loop
        for code = (read-byte s)
        until (zerop code)
        do (write-char (code-char code) out))))

(defun read-little-endian (s &#38;optional (bytes 4))
  (let ((result 0))
    (loop
        for i from 0 below bytes
        do
        (setf result (logior result (ash (read-byte s) (* 8 i)))))
    result))

(defun parse-file-location-info (s)
  (let ((start (file-position s))
        (total-length (read-little-endian s))
        (end-of-header (read-little-endian s))
        (fli-flags (read-little-endian s))
        (local-volume-offset (read-little-endian s))
        (local-offset (read-little-endian s))
        (network-volume-offset (read-little-endian s))
        (remaining-offset (read-little-endian s)))
    (declare (ignore total-length end-of-header local-volume-offset))
    (unless (zerop fli-flags)
      (cond
        ((logbitp 0 fli-flags)
         (file-position s (+ start local-offset)))
        ((logbitp 1 fli-flags)
         (file-position s (+ start
                             network-volume-offset
                             #x14))))
      (concatenate 'string
                   (read-null-terminated-string s)
                   (progn
                     (file-position s (+ start remaining-offset))
                     (read-null-terminated-string s))))))

(defun windows-link-p (filespec)
  "Is /filespec/ a Windows .lnk shortcut file?"
  ;; must end in .lnk
  (when (not (equalp (pathname-type filespec) "LNK"))
    (return-from windows-link-p nil))
  ;; needs to have the correct header
  (with-open-file (s filespec :element-type '(unsigned-byte 8))
    (handler-case
        (and (= (read-little-endian s) *link-initial-dword*)
             (let ((header (make-array (length *link-guid*))))
               (read-sequence header s)
               (equalp header *link-guid*)))
      (end-of-file () nil))))

(defun parse-windows-shortcut (pathname)
  (with-open-file (s pathname :element-type '(unsigned-byte 8))
    (handler-case
        (when (and (= (read-little-endian s) *link-initial-dword*)
                   (let ((header (make-array (length *link-guid*))))
                     (read-sequence header s)
                     (equalp header *link-guid*)))
          (let ((flags (read-little-endian s)))
            (file-position s 76)        ;skip rest of header
            (when (logbitp 0 flags)
              ;; skip shell item id list
              (let ((length (read-little-endian s 2)))
                (file-position s (+ length (file-position s)))))
            (cond
              ((logbitp 1 flags)
               (parse-file-location-info s))
              (t
               (when (logbitp 2 flags)
                 ;; skip description string
                 (let ((length (read-little-endian s 2)))
                   (file-position s (+ length (file-position s)))))
               (when (logbitp 3 flags)
                 ;; finally, our pathname
                 (let* ((length (read-little-endian s 2))
                        (buffer (make-array length)))
                   (read-sequence buffer s)
                   (map 'string #'code-char buffer)))))))
      (end-of-file ()
                   nil))))

(define-condition symlink-error (error) ())

(defun truename-aux (filespec &#38;optional (depth 0))
  ;; RECURSIVE INVARIANT: /filespec/ is an absolute path, not relative
  ;; always returns an absolute pathname
  (when (&#62; (incf depth) 16)
    ;; poor man's recursion detection...
    (error 'symlink-error))
  ;(when (windows-link-p filespec)
  ;  (return-from truename-aux (truename-aux (parse-windows-shortcut (namestring filespec)) depth)))
  (let ((handle (get-link-handle filespec)))
    (declare (type integer handle))
    ;; check for failure
    (when (eq handle -1)
      ;; generally, this means we can't find the file
      (error 'symlink-error))
    (with-alien ((reparseStructure (struct ReparseStructure))
                 (bytes-returned unsigned-int))
      ;; see kalmbach to interpret the constants here...
      (let ((result (DeviceIoControl handle #x900A8 nil #x0
                                     (addr reparseStructure)
                                     #x200 (addr bytes-returned) nil)))
        (declare (type integer result))
        ;; done with handle
        (CloseHandle handle)
        ;; check for failure, meaning device is not a link
        (when (zerop result)
          ;; we are done
          (return-from truename-aux filespec))
        (let ((tag (slot reparseStructure 'reparse-tag)))
          (cond
            ((not (reparse-tag-p tag))
             filespec)
            ((symlink-p tag)
             (let* ((sympath (extract-path-from-symlink reparseStructure))
                    (dirlist (pathname-directory sympath)))
               (case (car dirlist)
                 (:ABSOLUTE
                  ;; an :absolute directory can be used as is
                  (truename-aux sympath depth))
                 (otherwise
                  ;; a :relative directory must be merged with the base directory before continuing
                  (let ((merged-path (merge-pathnames sympath (directory-namestring filespec))))
                    (setq merged-path (sb-impl::simplify-win32-namestring (namestring merged-path)))
                    (truename-aux merged-path depth))))))
            ((mount-point-p tag)
             (pathname (extract-path-from-mount-point reparseStructure)))
            (t
             filespec)))))))

(defun truename (filespec)
  #.(concatenate 'string
                 (documentation 'cl::truename 'function)
  "

Under Windows, the TRUENAME of a symlink that does not
exist or of a recursive symlink, or a symlink more than
16 levels deep, is the name of the symlink.

  ")
  (let ((original-path (cl::truename filespec)))
    (handler-case
        (cl::truename (truename-aux original-path))
      (symlink-error () original-path)
      (file-error () original-path))))

(defun file-write-date (pathspec)
  #.(documentation 'cl::file-write-date 'function)
  (cl::file-write-date (truename pathspec)))</pre>
<p> </p>
</div>]]></content:encoded>
</item>
<item>
<title><![CDATA[How to create symbolic links in NTFS file system without Resource Kit?]]></title>
<link>http://narawen.wordpress.com/2008/05/26/how-to-create-symbolic-links-in-ntfs-file-system-without-resource-kit/</link>
<pubDate>Mon, 26 May 2008 22:02:10 +0000</pubDate>
<dc:creator>Michał Krawczyk</dc:creator>
<guid>http://narawen.wordpress.com/2008/05/26/how-to-create-symbolic-links-in-ntfs-file-system-without-resource-kit/</guid>
<description><![CDATA[Today I searched for the method to create symbolic link in NTFS file system and found that there are]]></description>
<content:encoded><![CDATA[<div class='snap_preview'><p>Today I searched for the method to create symbolic link in NTFS file system and found that there are no system built-in commands to do the job. <a href="http://support.microsoft.com/kb/205524/en-us" target="_blank">The tools</a> are provided in Resource Kit only.</p>
<p>Fortunatelly unbeatable <a href="http://technet.microsoft.com/en-us/sysinternals/default.aspx" target="_blank">SysInternals</a> have handy command line utility for it. It is called Junction and available for download from here: <a href="http://www.microsoft.com/technet/sysinternals/fileanddisk/junction.mspx">http://www.microsoft.com/technet/sysinternals/fileanddisk/junction.mspx</a>.</p>
<p> </p>
</div>]]></content:encoded>
</item>
<item>
<title><![CDATA[DVD Library on Extenders How-To]]></title>
<link>http://noocyte.wordpress.com/2008/04/25/dvd-library-on-extenders-how-to/</link>
<pubDate>Fri, 25 Apr 2008 06:26:32 +0000</pubDate>
<dc:creator>noocyte</dc:creator>
<guid>http://noocyte.wordpress.com/2008/04/25/dvd-library-on-extenders-how-to/</guid>
<description><![CDATA[DVD Library on Extenders How-To Somebody figured out how to use symbolic links and a playlist to mak]]></description>
<content:encoded><![CDATA[<div class='snap_preview'><p><strong>DVD Library on Extenders How-To</strong></p>
<p>Somebody figured out how to use symbolic links and a playlist to make it possible to rip all your dvds and then play them back on an extender. Sweet! <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><a title="How-to" href="http://www.htpcug.org/Default.aspx?tabid=168">DVD Library on Extenders How-To</a></p>
</div>]]></content:encoded>
</item>
<item>
<title><![CDATA[Random Linux Fact #2]]></title>
<link>http://gayhacker.wordpress.com/2008/02/08/changing-the-target-of-a-symbolic-link-in-linux/</link>
<pubDate>Fri, 08 Feb 2008 10:02:02 +0000</pubDate>
<dc:creator>Hexadecimal</dc:creator>
<guid>http://gayhacker.wordpress.com/2008/02/08/changing-the-target-of-a-symbolic-link-in-linux/</guid>
<description><![CDATA[Changing the Target of a Symbolic Link I thought I might as well post this one, too, after posting h]]></description>
<content:encoded><![CDATA[<div class='snap_preview'><p align="center"><big><strong>Changing the Target of a Symbolic Link</strong></big></p>
<p>I thought I might as well post this one, too, after posting how to read a symbolic link.  This one isn&#8217;t so obvious, though.  It forces the target to be changed on an existing link.</p>
<p><code>ln -s -n -f /new/target/path /existing/link</code></p>
</div>]]></content:encoded>
</item>
<item>
<title><![CDATA[Tipos de Arquivos em Sistemas Unix-like]]></title>
<link>http://localdomain.wordpress.com/2008/02/05/tipos-de-arquivos-em-sistemas-unix-like/</link>
<pubDate>Tue, 05 Feb 2008 20:45:37 +0000</pubDate>
<dc:creator>ThigU</dc:creator>
<guid>http://localdomain.wordpress.com/2008/02/05/tipos-de-arquivos-em-sistemas-unix-like/</guid>
<description><![CDATA[Olá pessoal! Faz um tempo que não escrevo aqui no blog sobre algum assunto relacionado a segurança o]]></description>
<content:encoded><![CDATA[Olá pessoal! Faz um tempo que não escrevo aqui no blog sobre algum assunto relacionado a segurança o]]></content:encoded>
</item>
<item>
<title><![CDATA[Random Linux Fact #1]]></title>
<link>http://gayhacker.wordpress.com/2007/12/18/how-to-find-the-target-of-a-symbolic-link-in-linux/</link>
<pubDate>Tue, 18 Dec 2007 06:23:15 +0000</pubDate>
<dc:creator>Hexadecimal</dc:creator>
<guid>http://gayhacker.wordpress.com/2007/12/18/how-to-find-the-target-of-a-symbolic-link-in-linux/</guid>
<description><![CDATA[How to Find the Target of a Symbolic Link It took me like twenty minutes to find this simple command]]></description>
<content:encoded><![CDATA[<div class='snap_preview'><p align="center"><strong><big>How to Find the Target of a Symbolic Link</big></strong></p>
<p>It took me like twenty minutes to find this simple command on google:</p>
<p><code>readlink /path/to/link</code></p>
<p> <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
</div>]]></content:encoded>
</item>
<item>
<title><![CDATA[How to create and remove a soft link, symlink or symbolic link]]></title>
<link>http://freethegnu.wordpress.com/2007/11/15/how-to-create-and-remove-a-soft-link-symlink-or-symbolic-link/</link>
<pubDate>Thu, 15 Nov 2007 22:42:05 +0000</pubDate>
<dc:creator>Pedro Carvalho</dc:creator>
<guid>http://freethegnu.wordpress.com/2007/11/15/how-to-create-and-remove-a-soft-link-symlink-or-symbolic-link/</guid>
<description><![CDATA[A soft link, or more common, a symlink, is link a shortcut to the targeted file or directory. So whe]]></description>
<content:encoded><![CDATA[<div class='snap_preview'><p>A soft link, or more common, a <a href="http://en.wikipedia.org/wiki/Symbolic_link" target="_blank">symlink</a>, is link a shortcut to the targeted file or directory. So when is removed the original target stays present.  This is the opposite of a <a href="http://en.wikipedia.org/wiki/Hard_link" target="_blank">hard link</a> which is a reference to the target and so, if the hard link is removed, so is the target.</p>
<p>A symlink can be created like:<!--more--></p>
<p><code>ln -s /path/ linkname</code></p>
<p>from the ln man pages:</p>
<blockquote><p> ln [OPTION]&#8230; [-T] TARGET LINK_NAME   (1st form)</p>
<p>-s, &#8211;symbolic<br />
make symbolic links instead of hard links</p></blockquote>
<p>to remove a symlink</p>
<p><code>rm linkname</code></p>
<p>What is important here is to note that the command doesn&#8217;t have the trailing slash<br />
<code><br />
$ rm linkname/</code><br />
will output the error:<br />
<code>rm: cannot remove `linkname/': Is a directory</code></p>
<p><code>$ rmdir linkname/</code><br />
will output:<br />
<code>rmdir: linkname/: Not a directory</code></p>
<p>So it&#8217;s a directory or not??  i guess different tools have different ways of looking at this. Isn&#8217;t GNU/Linux great?! <img src='http://s.wordpress.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
</div>]]></content:encoded>
</item>
<item>
<title><![CDATA[Whew!]]></title>
<link>http://blog.theburrowfamily.net/2007/11/08/whew/</link>
<pubDate>Fri, 09 Nov 2007 06:24:03 +0000</pubDate>
<dc:creator>Dave</dc:creator>
<guid>http://blog.theburrowfamily.net/2007/11/08/whew/</guid>
<description><![CDATA[I almost missed today. It&#8217;s been a busy day.  I&#8217;ve got two big tests tomorrow, one on Mo]]></description>
<content:encoded><![CDATA[I almost missed today. It&#8217;s been a busy day.  I&#8217;ve got two big tests tomorrow, one on Mo]]></content:encoded>
</item>

</channel>
</rss>
