2016-06-30 14 views
1

最近、私たちの運用環境で異常な動作が発生しています。私は、次のしている :.NET 4.5 File.Copy OKですが、ファイルが存在しません

try { 
    var sourcePath = ... // my source path 
    var destinationPath = ... // guess what? You're right, my destination path 

    File.Copy(sourcePath, destinationPath); 
    Log.Debug(string.Format("Image {0} copied successfully", imagename)); 
} 
catch(Exception e) { 
    // exception handling 
} 

両方のソースと宛先パスは、ネットワーク共有上のファイルの数が多い(> 500K)と他の(仮想)マシン上のフォルダです。 上記のコードは過去2日間、最後の行(イメージがコピーされたことを示す行)を記録しますが、コピー先フォルダをチェックインすると、コピー先のファイルは存在しません。

I/OエラーのFile.Copyが例外を発生させるので、このことが私を怒らせると思っていました。 そのフォルダにファイルを書き込む他のコード部分が正しく動作していることに注意してください。また、すべてのファイル名が一意であることに注意してください(簡潔さのためにビジネスコードは含まれていません)。例外がスローされるか、ファイルが少なくとも上書きされると思います。

誰も同じ問題に直面しましたか?考えられる原因?どんな解決策ですか?

EDIT 2016年7月1日15時12分(GMT + 0200)

[OK]を、人々は、どうやらファイルは、まったく単純に明らかに理由もなく...すべてで削除されていない彼らの後それらはコピーされ、クライアント接続ユーザーから読み取り+書き込みモードで開いたままになります。 これは、私のコンピュータ上で、デバッグモードでリーダーアプリケーションを実行しようとしていて、私が最近知ったファイルの一つを開こうとしているのを発見しました。 ファイルが他の人によって開かれたという例外がありました。それは私にとっては奇妙に思えました。 リモートサーバー(ファイルを保存しているサーバー)の[コンピュータの管理]を開き、[共有フォルダ]、[ファイルを開く]の順に選択すると、そのファイルが読み書きモードで開いていることがわかりました。ファイルはその仕事をするために偽装しています。 また、同じ条件で、他の多くの他のファイルの一束はどこに読書モードで開いています。 私は共有フォルダ>セッションでも、偽装されたユーザーのセッションの長い天文リストであり、すべてが長いアイドル時間を持つことがわかりました。 偽装はファイルのコピーにのみ使用されてから廃棄されるため、私はそれを期待してはいけませんか?

私はファイルコピー中にユーザーを偽装する方法に問題があり、宛先フォルダの多数のファイルにリンクされている可能性があります。 これを確認します。

のEND EDIT

おかげで、

クラウディオ・ヴァレリオ

+1

たぶん誰か/それらがコピーされます後に何かがファイルを削除するのですか? –

+0

こんにちはマッテオ、コメントに感謝します。 悲しいことがありません、 dのコード行はありませんその特定のフォルダからのelete、誰もWindowsエクスプローラ経由で私と私の同僚(FTPアクセスなし)を介してアクセスすることはできません。 –

+2

あなたの 'destinationPath'は、あるケースではあなたが思うものではないかもしれません。おそらくあなたもそれを記録すべきです。 –

答えて

0

は、私が思うに、解決策を見つけました。 私の問題は、宛先フォルダに対する書き込み権限を持つユーザーを偽装するために使用されたコードでした。 (私の守備では、すべてこのプロジェクトは、以前のソフトウェア会社から継承されており、そしてそれはかなり大規模なので、すべてに目を維持することは容易ではありません)

偽装プロセスがIDisposableを

を実装したクラスに包まれました。 このクラスは、この方法を使用している
public class Impersonator : 
    IDisposable 
{ 
    public Impersonator() 
    { 
     string userName = // get username from config 
     string password = // get password from config 
     string domainName = // get domain from config 
     ImpersonateValidUser(userName, domainName, password); 
    } 

    public void Dispose() 
    { 
     UndoImpersonation(); 
    } 

    [DllImport("advapi32.dll", SetLastError = true)] 
    private static extern int LogonUser(
     string lpszUserName, 
     string lpszDomain, 
     string lpszPassword, 
     int dwLogonType, 
     int dwLogonProvider, 
     ref IntPtr phToken); 

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern int DuplicateToken(
     IntPtr hToken, 
     int impersonationLevel, 
     ref IntPtr hNewToken); 

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern bool RevertToSelf(); 

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)] 
    private static extern bool CloseHandle(
     IntPtr handle); 

    private const int LOGON32_LOGON_INTERACTIVE = 2; 
    private const int LOGON32_PROVIDER_DEFAULT = 0; 

    private void ImpersonateValidUser(
     string userName, 
     string domain, 
     string password) 
    { 
     WindowsIdentity tempWindowsIdentity = null; 
     IntPtr token = IntPtr.Zero; 
     IntPtr tokenDuplicate = IntPtr.Zero; 

     try 
     { 
      if (RevertToSelf()) 
      { 
       if (LogonUser(
        userName, 
        domain, 
        password, 
        LOGON32_LOGON_INTERACTIVE, 
        LOGON32_PROVIDER_DEFAULT, 
        ref token) != 0) 
       { 
        if (DuplicateToken(token, 2, ref tokenDuplicate) != 0) 
        { 
         tempWindowsIdentity = new WindowsIdentity(tokenDuplicate); 
         impersonationContext = tempWindowsIdentity.Impersonate(); 
        } 
        else 
        { 
         throw new Win32Exception(Marshal.GetLastWin32Error()); 
        } 
       } 
       else 
       { 
        throw new Win32Exception(Marshal.GetLastWin32Error()); 
       } 
      } 
      else 
      { 
       throw new Win32Exception(Marshal.GetLastWin32Error()); 
      } 
     } 
     finally 
     { 
      if (token != IntPtr.Zero) 
      { 
       CloseHandle(token); 
      } 
      if (tokenDuplicate != IntPtr.Zero) 
      { 
       CloseHandle(tokenDuplicate); 
      } 
     } 
    } 

    private void UndoImpersonation() 
    { 
     if (impersonationContext != null) 
     { 
      impersonationContext.Undo(); 
     } 
    } 

    private WindowsImpersonationContext impersonationContext = null; 

} 

using(new Impersonator()) 
{ 
    // do stuff with files in here 
} 

マイ疑わしい偽装ユーザーのハンドラを閉じて、何とか、それは窓が目で開いているファイルを処理する方法に何かを破るということでした私の場合のように、ネットワーク共有を介して偽装されたユーザーになる可能性があります。共有ファイルを読み取り+書き込みモードで開いたままにしておくと、他のプロセス/ユーザーは開けません。

次のようにIは偽装クラス修飾:

public class Impersonator : 
    IDisposable 
{ 
    public Impersonator() 
    { 
     string userName = // get username from config 
     string password = // get password from config 
     string domainName = // get domain from config 
     ImpersonateValidUser(userName, domainName, password); 
    } 

    public void Dispose() 
    { 
     UndoImpersonation(); 
     impersonationContext.Dispose(); 
    } 

    [DllImport("advapi32.dll", SetLastError = true)] 
    private static extern int LogonUser(
     string lpszUserName, 
     string lpszDomain, 
     string lpszPassword, 
     int dwLogonType, 
     int dwLogonProvider, 
     ref IntPtr phToken); 

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern int DuplicateToken(
     IntPtr hToken, 
     int impersonationLevel, 
     ref IntPtr hNewToken); 

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern bool RevertToSelf(); 

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)] 
    private static extern bool CloseHandle(
     IntPtr handle); 

    private const int LOGON32_LOGON_INTERACTIVE = 2; 
    private const int LOGON32_PROVIDER_DEFAULT = 0; 

    private void ImpersonateValidUser(
     string userName, 
     string domain, 
     string password) 
    { 
     WindowsIdentity tempWindowsIdentity = null; 
     token = IntPtr.Zero; 
     tokenDuplicate = IntPtr.Zero; 

     try 
     { 
      if (RevertToSelf()) 
      { 
       if (LogonUser(
        userName, 
        domain, 
        password, 
        LOGON32_LOGON_INTERACTIVE, 
        LOGON32_PROVIDER_DEFAULT, 
        ref token) != 0) 
       { 
        if (DuplicateToken(token, 2, ref tokenDuplicate) != 0) 
        { 
         tempWindowsIdentity = new WindowsIdentity(tokenDuplicate); 
         impersonationContext = tempWindowsIdentity.Impersonate(); 
        } 
        else 
        { 
         throw new Win32Exception(Marshal.GetLastWin32Error()); 
        } 
       } 
       else 
       { 
        throw new Win32Exception(Marshal.GetLastWin32Error()); 
       } 
      } 
      else 
      { 
       throw new Win32Exception(Marshal.GetLastWin32Error()); 
      } 
     } 
     finally 
     { 
     } 
    } 

    private void UndoImpersonation() 
    { 
     try 
     { 
      if (impersonationContext != null) 
      { 
       impersonationContext.Undo(); 
      } 
     } 
     finally 
     { 
      if (token != IntPtr.Zero) 
      { 
       CloseHandle(token); 
      } 
      if (tokenDuplicate != IntPtr.Zero) 
      { 
       CloseHandle(tokenDuplicate); 
      } 
     } 
    } 

    private WindowsImpersonationContext impersonationContext = null; 
    private IntPtr token; 
    private IntPtr tokenDuplicate; 

} 

を基本的に私はUndoImpersonation方法で閉鎖ハンドラを移動。また、明示的に処理されていないimpersonationContextを残すことについても疑問がありました。私はImpersonatorクラスのDisposeメソッドにそれを配置しました。

私はこのアップデートをプロダクションに投入して以来、私はこのコードで他に何の問題もなく、他の共有ファイルは宛先サーバ上で読み込み+書き込みモードでオープンしていませんでした。 最適な解決策ではないかもしれません(コンピュータ管理>共有フォルダ>セッションではセッションが一杯ですが、これは今のところシステムに害を及ぼさないようです)。

コメント、この状況について、私は読みくださいになります。

おかげで、

クラウディオ

関連する問題