Archive for the 'Uncategorized' Category

Solved: "Cannot read from the source file or disk"

I’ve finally solved a problem that’s been bugging me for years. One of our file shares ended up with several undelete-able files. Attempting to delete them results in “Error Deleting File or Folder - Cannot delete file: Cannot read from the source file or disk“.

Even going to the file’s properties to check permissions presented a very blank properties dialog. And a CHKDSK didn’t sort thing out either.

It turns out the problem was: the filename ended with a dot, e.g. it was something like “C:\Temp\Stuff\Sales Agreement.“. As far as Windows is concerned this is an invalid file name: so although it gets reported in a directory listing, the standard Windows APIs for manipulating files subsequently deny its existence.

So how did this file get created in the first place? The answer: a Mac. The file was on a file share which had been accessed by a Mac user. Macs tend to write all sorts of metadata to extra “._DSStore” files and suchlike and had left this file behind.

So if Windows doesn’t appear to allow these file names, how did they get to be created? Well, it turns out that NTFS allows all sort of file name/path weirdness that Windows, or specifically the Win32 API, doesn’t allow. For example, NTFS actually allows file paths up to 32K but Windows restricts file paths to no more than 260 characters (MAX_PATH). I suppose this is all for DOS/Windows 9x backwards compatibility. As these files were being accessed over a file share I guess the usual Win32 checks are bypassed.

But thankfully you can get Win32 to ignore these checks by prefixing your file paths with \\?\, (ie. C:\Temp\SomeFile.txt becomes \\?\C:\Temp\SomeFile.txt) which I discovered after reading this blog post about long paths in .NET.

So at a command prompt I was able to delete the file using:

del "\\?\C:\Temp\Stuff\Sales Agreement."

Of course the corollary of this is that you could really annoy somebody by doing this:

echo Hi > "\\?\%USERPROFILE%\Desktop\Annoying file you can't delete."

But you wouldn’t do that would you?

Moving on from SVN_ASP_DOT_NET_HACK

I noticed that I was running TortoiseSVN in SVN_ASP_DOT_NET_HACK mode (where Subversion clients use ‘_svn’ instead of ‘.svn’ directories) unnecessarily as I don’t have silly old Visual Studio 2003 installed anymore which caused this mess in the first place.

The _svn directories work just as well as .svn, but nevertheless (due to mild OCD?), I created a batch script that ripped through my project directory renaming all ‘_svn’ directories to ‘.svn’, so I could remove the SVN_ASP_DOT_NET_HACK mode. It uses the wonderfully flexible FOR command drive the whole process. We don’t need no stinkin’ Powershell round these parts…

Save this script as something like “SvnRenameDirs.cmd” in the root of your projects folder:

:: Make script directory current
pushd "%~dp0"

:: Unhide, rename and re-hide svn dirs
for /r /d %%D in (*) do @if exist "%%D\_svn" (
   attrib -H "%%D\_svn"
   ren "%%D\_svn" ".svn"
   attrib +H "%%D\.svn"
)
popd

rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl,0,3

At the end click the Environment Variables button in the System Properties dialog and remove the SVN_ASP_DOT_NET_HACK environment variable and then log out and back in again (or restart explorer.exe and TSVNCache.exe).

System.Net.Mail: The specified string is not in the form required for a subject

Having your ASP.NET error handling routine, which sends you emails when an error occurs on your site, itself fail is annoying. Especially when you think you’ve made the code robust enough. Anyway the error handler for one site I work on was failing with “ArgumentException: The specified string is not in the form required for a subject“.

So what is exactly “the form required for a subject”? Googling for this error message returns a lot of junk and misinformed forum posts. It turns out that setting the Subject on a System.Net.Mail.Message internally calls MailBnfHelper.HasCROrLF (thank you Reflector) which does exactly what it says on the tin. Therefore one forum poster’s solution of subject.Replace("\r\n", " ") isn’t going to work when your have either a carriage return or line feed in there.

So, obviously, the solution is:

message.Subject = subject.Replace('\r', ' ').Replace('\n', ' ');

Personally, I think that the MailMessage should to this for you or at least Microsoft should document what actually constitutes a “form required for a subject” in MSDN or, even better, in the actual error message itself!

C# Extension Methods and IsNullOrEmpty

As Brad Wilson points out one of the nice features of C# 3.0’s extension methods is that they work on null instances. Indeed, why shouldn’t they? They’re just static methods that are invoked in a slightly different way. But this allows a subtle but very pleasing (to me this morning anyway) bit of syntactic sugar for the very commonly used String.IsNullOrEmpty() method.

So instead of:

if (string.IsNullOrEmpty(myString)) ...

you can have the more-readable:

if (myString.IsNullOrEmpty()) ...

by using:

public static class StringExtensions
{
   public static bool IsNullOrEmpty(this string str)
   {
      return string.IsNullOrEmpty(str);
   }
}

It’s a very small thing but I like it.

Draytek Vigor 2800 reboot script

After years of great service, our Draytek Vigor 2800 seems to be having problems after running for a few days of allowing HTTPS in to our network, which is only solved by rebooting the router. For the life of me I can’t upgrade the firmware using either the TFTP or FTP approach. So giving up, I’ve adopted the brute force approach of scheduling a reboot every night. To do this I considered scripting the appropriate Telnet commands to the router, but that would involve some custom or third party code. (Telnet, being a duplex protocol means you can’t simply pipe commands to telnet.exe from a batch file, you have to use something like expect to script a Telnet session.)

The simplest, lowest-tech approach (and they’re always the best, right?) I found was merely to mimic the reboot page on the router web management UI with the following Windows Scripting Host script:

////// RebootRouter.js ////////
// Change these for your environment
var ROUTER_IP = "192.168.0.1";
var ROUTER_USER = "admin";
var ROUTER_PASSWORD = "pA55w0rd";

var http = new ActiveXObject("Microsoft.XMLHTTP");
http.open("POST", "http://" + ROUTER_IP
    + "/cgi-bin/reboot.cgi", false,
    + ROUTER_USER, ROUTER_PASSWORD);
http.setRequestHeader("Content-Type",
    "application/x-www-form-urlencoded");
http.send("sReboot=Current&submit=OK");

// For debugging/logging un-comment the following lines:
// WScript.Echo(http.status + " " + http.statusText);
// WScript.Echo(http.responseText);

Save this as RebootRouter.js, update the values accordingly and schedule for a appropriate time using Control Panel > Scheduled Tasks.

CTRL+TAB switching between document windows in Visual Studio

Visual Studio 2008 introduced a document switcher window that pops up when you do a CTRL+TAB. Nice idea, inspired by ALT+TAB application switching  but I find that the little previews it shows you are pretty useless. One code window looks like pretty much any other at that resolution. I prefer the previous behaviour of just immediately switching windows.

Sara Ford’s excellent series of Visual Studio tips prompted me to restore CTRL+TAB’s previous behaviour. You can do this by using the Keyboard binding page in Tools Options. In Tools > Options > Keyboard locate Window.NextDocumentWindowNav and remove the CTRL+TAB binding, then go to Window.NextDocumentWindow and assign CTRL+TAB there instead. Same drill for CTRL+SHIFT+TAB for Window.PreviousDocumentWindowNav and Window.PreviousDocumentWindow.

Sharing Google Picasa Libraries between users on the same computer

After a few years of using Adobe Photoshop Elements, last year we switched over to using Google’s free Picasa for organising our photo collection. Consecutive versions of Photoshop Elements were just getting slower and slower mainly it seemed due to waiting for the ‘kewl’ interface to redraw itself. Picasa is really slick and fast on our 2.8GHz Pentium 4 home PC. It can also upload our photos for printing to PhotoBox, and share them online using Google’s own Picasa Web Albums.

Photoshop Elements keeps all of your photo tags and collections in a ‘*.psa’ database file (which is actually Microsoft Access database). The useful thing we found about this was that we could share all our photo collection settings and tags between users. Picasa, on the other hand, stores its settings in hidden Picasa.ini files in your photo directories as well as in your local app settings user profile folder (buried in ‘Documents and Settings’ on Windows XP or the ‘Users’ folder on Vista). The problem with this is that you can’t share your Picasa library between users on the same machine as Picasa is hard-coded to look in the currently logged on user’s profile directory, and can’t be coaxed to look elsewhere, such as a shared location.

So to workaround this, you can take advantage of a feature of NTFS called junctions, which allow you to wire up one folder to another (or symbolic links, I’m not sure what the difference is, but the end result is the same). Windows Vista has a command-line tool called MKLINK which will create these. On Windows XP you will need to use the Sysinternals Junction command-line tool. Here’s what I did:

  1. Copy %LocalAppData%\Google\Picasa2 and Picasa2Albums to a shared location to which all users will have Modify access. (I chose C:\Users\Public\AppData\Local\Google on Vista, it’d be something like C:\Documents and Settings\Public on XP)
  2. Rename %LocalAppData%\Google\Picasa2 and Picasa2Albums e.g. “Picasa2.old” and “Picasa2Albums.old”
  3. Use MKLINK (Vista) or Junction (XP) to create a junction from
    %LocalAppData%\Google\Picasa2 to
    <SharedLocation>\Google\Picasa2
    and:
    %LocalAppData%\Google\Picasa2Albums to <SharedLocation>\Google\Picasa2Albums
  4. Repeat steps 2-3 for each user for whom you want to share the Picasa library

Of course this may break with a future version of Picasa, so proceed with caution and don’t blame me if it all goes horribly wrong.

Microsoft Search Server and FAST

Microsoft have a new server product: Search Server 2008. Well I say “new” but it seems to be based the same technology they’ve been pushing since the days of Site Server, on which I spent most of the late 1990’s travelling the world doing training and consulting. The same technology is used in Index Server, SQL Server Full Text Search, SharePoint, and even Windows Desktop Search.

It’s a workmanlike search technology, but I think people are so used to Google being so effective on the Internet that when they come to search their intranet using these technologies they come up short. You have to do a bit more wading through useless hits before you find what you’re looking for. In fact it’s a bit like going back the bad old days of AltaVista, et al before Google revolutionised search with PageRank.

This begs the question how good any intranet search solution could be (including Google’s own Search Appliance) on a intranet that consists of file shares and SharePoint document libraries containing mostly Word documents, Excel spreadsheets, etc, with nary a hyperlink in sight. How would you get something like PageRank, which relies on incoming links to help rank content, working with a “corpus” (in search parlance) such as this?

So, Microsoft have now pretty much admitted that their search technology needs some work, because they’ve just shelled out $1.2 billion for FAST,a Norwegian search technology company. Or should that be “bailed out” as FAST seem to have had some financial difficulties recently? It’ll be interesting to see if FAST’s technology, when they integrate it, is more effective than Microsoft’s current offerings.

WCF JSON Serialization is flawed

I’m working on a little internal app that involves some AJAX-y callbacks to the server for data. The data is returned in JSON format for easy consumption by the client side code and is being generated with very un-sexy Response.Writes, whose output looks something like this:

{
   "jbloggs" :
   {
      fullName : "Fred Bloggs",
      title : "Chief Burger Flipper",
      tel : "512"
   },
   "jdoe" :
   {
      fullName : "Jane Doe",
      title : "Assistant Burger Flipper",
      tel : "587"
   },
   ...
}

This works nicely as a information can be looked up on the client in JavaScript like so:

var person = peopleJson["jbloggs"];
alert(person.fullName);

Dead easy. JavaScript objects are just dictionaries/hash tables.

Now I was aware that Windows Communication Foundation (WCF) services can now do JSON serialization in .NET 3.5, so I thought I’d swap out my low-tech Response.Writes for a WCF Service that would let me come up with structures in my server-side code that would be serialized automatically to JSON. But I found that the the way WCF (which ultimately uses DataContractJsonSerializer) serializes Dictionaries is a bit lame. This is what it came up with:

[
   {
      "Key":"jbloggs",
      "Value":
      {
         fullName : "Joe Bloggs",
         title : "Chief Burger Flipper",
         tel : "512"
      }
   },
   {
      "Key":"jdoe",
      "Value":
      {
         fullName : "John Doe",
         title : "Assistant Burger Flipper",
         tel : "587"
      }
   },
   ...
]

Odd. Dictionaries are serialised as arrays of objects whose members consist of a Key and Value. So in order to look up an entry I’d have to do a linear search through this array. I mean, you would have thought the fact there is dictionary functionality built-in to the JavaScript Object prototype (in fact, fundamental to JavaScript) - that it would be the sensible format to use rather than the Key/Value format. I just can’t quite see why Microsoft thought that this Key/Value format was necessary as it’s such a pain to consume on the client.

Looks like my low-tech Response.Writes are going to get a stay of execution for the time being.

SQL Server database space usage

Ever wanted to know what the biggest table in your database is, and what the other space hogs are? There is the sp_spaceused system stored procedure that either shows headline stats for the database as a whole, or those for a particular table. Annoyingly it doesn’t tell you which table is taking up all the space relative to all the others. If you have SQL Server SP2 installed then it ups SQL Management Studio

So, here’s a T-SQL batch that shows all the space taken up by tables in the current database. The main column to look at is “Total size”, which is a sum of the Data size, Index size and Unused columns.

SET NOCOUNT ON
DBCC UPDATEUSAGE(0)
CREATE TABLE #spaceused
(
    Name nvarchar(255),
    Rows int,
    [Total size] varchar(50),
    [Data size] varchar(50),
    [Index size] varchar(50),
    Unused varchar(50)
)
DECLARE @table_name nvarchar(255) 

DECLARE tables_cursor CURSOR LOCAL FORWARD_ONLY FOR
    SELECT name FROM sysobjects WHERE type='U'
OPEN tables_cursor
FETCH NEXT FROM tables_cursor INTO @table_name
WHILE @@FETCH_STATUS = 0
BEGIN
    INSERT INTO #spaceused EXEC sp_spaceused @table_name
    FETCH NEXT FROM tables_cursor INTO @table_name
END

SELECT * FROM #spaceused
    ORDER BY CONVERT(int, LEFT([Total size],
                     CHARINDEX(' KB', [Total size]))) DESC 

DROP TABLE #spaceused
CLOSE tables_cursor
DEALLOCATE tables_cursor

Of note is the very useful INSERT INTO table EXEC proc technique for capturing the output of a stored proc.

The script works on SQL Server 2000 and 2005 (and possibly later).

Next Page »