0

I have a small utility that keeps hitting PathTooLongException and I was instructed to output the file path for the error, with is fine... somewhat.

However I find myself not able to replicate the issue. I tried creating a file with a path that is bigger than the MAX_PATH, but my program handles it fine. I tried to increase the path size even more but Windows did not allow for this, and the kicker is that through CMD can't even go to the containing folder because I do hit PathTooLongException before that, yet my program handles it just fine, no exception thrown.

What's really weird is that although the exception is never thrown, the program simply ignores the file in question, this is the peace of code that can't seam to find it and does not throw an error.

string fileName;
DirectoryInfo di = new DirectoryInfo(strFolderPath);
IEnumerable<FileInfo> fileList = di.EnumerateFiles("*", SearchOption.AllDirectories);
foreach (FileInfo fi in fileList)
{
    fileName = fi.FullName.Remove(0, di.FullName.Length + 1);
}

I find myself in a weird situation, with no way to invoke the error, I am supposed to handle.

PS. I think I should mention that I can't use the deployment paths, because of various reasons.

Here is the full path, in theory:
C:\net\sync-test-1\G1244kljsdfglksdjflsdjlfkjajhalsjflkdsajkljsdflk\long_name_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItI\long_na.txt

Here is the same containing folder when I take it from windows address bar: C:\net\SYNC-T~1\G1244K~1\long_name_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItIs_YesItI

And this is the stack trace that the program sent out in deployment:

System.IO.PathTooLongException: The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.
   at System.IO.PathHelper.GetFullPathName()
   at System.IO.Path.NormalizePath(String path, Boolean fullCheck, Int32 maxPathLength, Boolean expandShortPaths)
   at System.Security.Util.StringExpressionSet.CanonicalizePath(String path, Boolean needFullPath)
   at System.Security.Util.StringExpressionSet.CreateListFromExpressions(String[] str, Boolean needFullPath)
   at System.Security.Permissions.FileIOPermission.AddPathList(FileIOPermissionAccess access, AccessControlActions control, String[] pathListOrig, Boolean checkForDuplicates, Boolean needFullPath, Boolean copyPathList)
   at System.IO.FileSystemInfo.get_FullName()
   at Neudesic.BlobDrop.BlobDrop.SyncContainer(BlobTask task)

So here is the source code for the SyncContainer():

// Sync local folder to container
private bool SyncContainer(BlobTask task)
{
    try
    {
        List<CloudBlob> blobList;
        Dictionary<string, CloudBlob> blobDict = new Dictionary<string,CloudBlob>();

        // Enumerate blobs in container.

        if (BlobHelper.ListBlobs(Container, out blobList))
        {
            // Put blob in a dictionary so we can easily look it up by name.
            foreach (CloudBlob blob in blobList)
            {
                blobDict.Add(blob.Name, blob);
            }

            // Enumerate the files in the watch folder - upload any files that do not yet have corresponding blobs in storage.
            string fileName;
            DirectoryInfo di = new DirectoryInfo(FolderPath);
            IEnumerable<FileInfo> fileList = di.EnumerateFiles("*", SearchOption.AllDirectories);
            foreach (FileInfo fi in fileList)
            {
                fileName = fi.FullName.Remove(0, di.FullName.Length + 1);
                if (!isPathSafe(fi.FullName))
                    continue;

                if (BlobHelper.doesTheBlobExist(fileName, Container))
                {
                    Info("  [" + Container + "\\" + fileName + "]: already in blob storage");
                }
                else
                {
                    Warning("  [" + Container + "\\" + fileName + "]: not found, adding upload task");

                    BlobQueue.Add(new BlobTask()
                    {
                        Action = "upload",
                        BlobName = fileName,
                        ContainerName = Container,
                        FilePath = fi.FullName,
                        RemainingRetryCount = MAX_RETRY_COUNT
                    });
                }
            }


            //checks the blob for all exess files in the blob and then removes them
            CloudBlobContainer container = BlobHelper.BlobClient.GetContainerReference(Container);
            BlobRequestOptions options = new BlobRequestOptions();
            options.UseFlatBlobListing = true;
            IEnumerable<IListBlobItem> blobs = container.ListBlobs(options);
            CloudBlob cbBlob;
            string mimeType;

            if (blobs.Count() > 0)
            {
                int containerLength = container.Name.Length + 2;
                foreach (IListBlobItem blob in blobs)
                {
                    if (blob is CloudBlob)
                    {
                        cbBlob = blob as CloudBlob;
                        fileName = cbBlob.Name;
                        string filePath = String.Concat(di.FullName, '\\', fileName);

                        mimeType = BlobHelper.getFileMimeTypeFromPath(filePath);
                        cbBlob.FetchAttributes();
                        // set cache-control header if necessary
                        if (cbBlob.Properties.CacheControl != BlobHelper.blobCacheHeader)
                        {
                            cbBlob.Properties.CacheControl = BlobHelper.blobCacheHeader;
                        }
                        if (cbBlob.Properties.ContentType != mimeType)
                        {
                            cbBlob.Properties.ContentType = mimeType;
                        }
                        cbBlob.SetProperties();

                        if (!File.Exists(filePath) || !isPathSafe(filePath))
                        {
                            Warning("  [" + Container + "\\" + fileName + "]: not found in system, but found in blob, adding deletion task");

                            BlobQueue.Add(new BlobTask()
                            {
                                Action = "delete",
                                BlobName = fileName,
                                ContainerName = Container,
                                FilePath = filePath
                            });
                        }
                    }
                }
            }

            return true;
        }
        return false;
    }
    catch (Exception ex)
    {
        if (ex is System.IO.PathTooLongException)
        {
            System.IO.PathTooLongException exeption = ex as PathTooLongException;
            Error(exeption.ToString());
        }
        else 
        {
            Error(ex.ToString());
        }

        return false;
    }
}


private bool isPathSafe(string path)
{
    //checks to see if the file is hidden or not, if so do not upload
    if ((File.GetAttributes(path) & FileAttributes.Hidden) == FileAttributes.Hidden)
        return false;

    //Checks to see if any of the folders in the path are hidden
    FileInfo fi = new FileInfo(path);
    if (isAnyPathDirHidden(fi.Directory))
        return false;

    //check to see if the file is one of the exception files, if so do not upload.
    return !Regex.IsMatch(path, regexFileExeption, RegexOptions.IgnoreCase | RegexOptions.Singleline);
}

/// <summary>
/// Checks to see if any of the folder's path folders are hidden or not.
/// </summary>
/// <param name="dir">The DirectoryInfo for the currently checked folder</param>
/// <returns>TRUE if the folder is hidden and FALSE if not</returns>
private bool isAnyPathDirHidden(DirectoryInfo dir)
{
    if (dir.Parent == null)
        return false;
    if ((File.GetAttributes(dir.FullName) & FileAttributes.Hidden) == FileAttributes.Hidden)
        return true;
    return isAnyPathDirHidden(dir.Parent);
}

// Upload a local file as a blob.
// Result: 0=success, 1=failed, retry scheduled, 2=failed

private int UploadBlob(BlobTask task)
{
    try
    {
        if (!File.Exists(task.FilePath))
        {
            Warning("   [" + task.BlobName + "]: file not found");
            return 2;
        }

        if (IsFileInUse(task.FilePath))
        {
            Warning("   [" + task.BlobName + "]: file in use");
            task.RemainingRetryCount--;
            if (task.RemainingRetryCount > 0)
            {
                Thread.Sleep(RETRY_SLEEP_INTERVAL);
                lock (BlobQueue)
                {
                    BlobQueue.Add(task);
                }
                return 1;
            }
            return 2;
        }

        if (BlobHelper.PutFileToBlob(task.FilePath, task.ContainerName, task.BlobName))
        {
            return 0;
        }
        else
        {
            return 1;
        }
    }

    // Failed to upload due to a storage service problem.

    catch(StorageException ex)
    {
        Error(ex.ToString());
        Warning("   [" + task.BlobName + "]: storage error");
        task.RemainingRetryCount--;
        if (task.RemainingRetryCount > 0)
        {
            Thread.Sleep(RETRY_SLEEP_INTERVAL);
            lock (BlobQueue)
            {
                BlobQueue.Add(task);
            }
            return 1;
        }
        return 2;
    }

    // Failed to upload due to a file access problem.

    catch (IOException ex)
    {
        Error(ex.ToString());
        Warning("   [" + task.BlobName + "]: could not access file");
        task.RemainingRetryCount--;
        if (task.RemainingRetryCount > 0)
        {
            Thread.Sleep(RETRY_SLEEP_INTERVAL);
            lock (BlobQueue)
            {
                BlobQueue.Add(task);
            }
            return 1;
        }
        return 2;
    }
    catch (Exception ex)
    {
        Error(ex.ToString());
        return 2;
    }
}


// Delete a blob.

private bool DeleteBlob(BlobTask task)
{
    bool ret;
    if (BlobHelper.doesTheBlobExist(task.BlobName, Container))
    {
        ret = DeleteSingleBlob(task.ContainerName, task.BlobName);
    }
    else
    {
        //checks to see if the deletion task is a folder
        //the way it is checked if the virtual folder exists is to check for all subitems (even in subfolders) and then removed all found-
        ret = true;

        CloudBlobContainer container = BlobHelper.BlobClient.GetContainerReference(Container);
        CloudBlobDirectory test = container.GetDirectoryReference(task.BlobName);
        BlobRequestOptions options = new BlobRequestOptions();
        options.UseFlatBlobListing = true;
        IEnumerable<IListBlobItem> blobs = test.ListBlobs(options);
        if (blobs.Count() > 0)
        {
            foreach (IListBlobItem blob in blobs)
            {
                if (blob is CloudBlob)
                {
                    if (!DeleteSingleBlob(task.ContainerName, (blob as CloudBlob).Name))
                    {
                        ret = false;
                    }
                }
            }
        }
    }

    return ret;
}


private bool DeleteSingleBlob(string containerName, string blobName)
{
    try
    {
        return BlobHelper.DeleteBlob(containerName, blobName);
    }
    catch (Exception ex)
    {
        Error(ex.ToString());
        return false;
    }
}
Idra
  • 5,777
  • 4
  • 22
  • 33
  • Do you have the stack trace from the exception? – Yuval Itzchakov Jun 01 '14 at 16:40
  • Is that length greater than 260 chars? I think 260 is the limit. – Sriram Sakthivel Jun 01 '14 at 16:42
  • @SriramSakthivel Yes it should be 260, this is why it is weird I am not getting it with a path of 305. – Idra Jun 01 '14 at 16:57
  • @YuvalItzchakov I added in the trace I got from the deployed utility + the test path I am using and failing to invoke it. – Idra Jun 01 '14 at 16:59
  • Could you show `Neudesic.BlobDrop.BlobDrop.SyncContainer(BlobTask task)`? – Yuval Itzchakov Jun 01 '14 at 17:27
  • @YuvalItzchakov I added in the code... excuse the mess, it is a quick utility that is based off another project. In general you should keep in mind that this is a Azure blob and file system synchronizer. – Idra Jun 01 '14 at 17:40
  • Are installed .NET versions on the development/deployment machines the same? Are their Windows versions same (including x86/x64)? – wasyl Jun 01 '14 at 17:44
  • @wasyl The .NET versions should be the same 4.0, but it is deployed on a x64 Windows Web 2008 R2, while my computer is a x84 Win 7 Pro. However the question is how can I invoke the PathTooLongException in my computer? – Idra Jun 01 '14 at 17:52
  • @Idra and what are file systems in use? Btw to invoke this exception `throw new PathTooLongException()` would probably be enough ;) I'm poking around to see if it's possible for your program to throw this on your machine though, because there are two limits for paths - 260 chars and 32k – wasyl Jun 01 '14 at 17:59
  • @Idra afaik Windows Vista added partial support for long paths. Check out [this hotfix](http://support.microsoft.com/kb/2891362) maybe? – wasyl Jun 01 '14 at 18:01
  • @wasyl unfortunatelly I can't simply throw it and develop it that way, because I need to be able to get the path name of the file. If I simply throw it, then there won't be any file info attached to it or am I missing something basic? – Idra Jun 01 '14 at 18:03
  • @wasyl thank you for this, but the problem is not in the long paths, we will simply restructure it as needed, but to do that we need to know were the problem is, this is why the path is needed in the first place. – Idra Jun 01 '14 at 18:09
  • @wasyl sorry forgot to check the file systems before, they are both NTFS – Idra Jun 01 '14 at 18:20
  • @Idra, sorry, I'm dropping this topic, couldn't find anything and I don't have time to dig deeper. My guess is this is difference in how OS's implement or handle IO parts of Win32 API. You can also check [this link about long paths in .NET](http://blogs.msdn.com/b/bclteam/archive/2007/02/13/long-paths-in-net-part-1-of-3-kim-hamilton.aspx) – wasyl Jun 01 '14 at 19:20

0 Answers0