static void MountVolumeSpecialAndUpload(string volumeName, string guidPath, ProgramConfig config) { if (Directory.CreateDirectory($".\\{volumeName}") != null) { Native.SetVolumeMountPoint($".\\{volumeName}\\", guidPath); if (IsVolumeMountPointForUploadValid($".\\{volumeName}\\")) { try { HandleVolumeMountForUpload($".\\{volumeName}\\", config); } catch (Exception ex) { // Get out and turn it off so we do not overheat the device // from continual processing through an infinite cycle of reading // and erroring. Console.WriteLine("HandleVolumeMountForUpload Exception:"); Console.WriteLine(ex.ToString()); Console.WriteLine(ex.StackTrace); Console.WriteLine("Ejecting the device."); } // https://msdn.microsoft.com/en-us/library/aa363216(VS.85).aspx const uint GENERIC_READ = 0x80000000; const uint GENERIC_WRITE = 0x40000000; const int FILE_SHARE_READ = 0x1; const int FILE_SHARE_WRITE = 0x2; const int FSCTL_LOCK_VOLUME = 0x00090018; const int FSCTL_DISMOUNT_VOLUME = 0x00090020; const int IOCTL_STORAGE_EJECT_MEDIA = 0x2D4808; const int IOCTL_STORAGE_MEDIA_REMOVAL = 0x002D4804; https: //msdn.microsoft.com/en-us/library/windows/desktop/aa365461(v=vs.85).aspx var devicePath = new StringBuilder(256); var guidOnly = guidPath.Substring(4); guidOnly = guidOnly.Substring(0, guidOnly.Length - 1); // Note: Microsoft's historic naming reasons lead to decreased ability to recognize the needed API functions // unless I have been doing WIN32 development for the past 40 years. Native.QueryDosDevice(guidOnly, devicePath, 256); Native.DeleteVolumeMountPoint($".\\{volumeName}\\"); var neededDeviceString = devicePath.ToString(); neededDeviceString = neededDeviceString.Substring(neededDeviceString.LastIndexOf('\\') + 1); var f = Native.CreateFile( $"\\\\.\\{neededDeviceString}", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, IntPtr.Zero, 0x3, 0x40000000, IntPtr.Zero ); uint bytesReturned; int tryCount = 0; while (!Native.DeviceIoControl(f, FSCTL_LOCK_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero)) { Console.WriteLine("Trying to lock the volume."); Thread.Sleep(1000); tryCount++; if (tryCount > 30) { break; } } Native.DeviceIoControl(f, FSCTL_DISMOUNT_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero); byte[] buf = new byte[1]; uint retVal; buf[0] = 1; Native.DeviceIoControl(f, IOCTL_STORAGE_MEDIA_REMOVAL, buf, 1, IntPtr.Zero, 0, out retVal, IntPtr.Zero); Native.DeviceIoControl(f, IOCTL_STORAGE_EJECT_MEDIA, IntPtr.Zero, 0, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero); } else { Native.DeleteVolumeMountPoint($".\\{volumeName}\\"); } } }
static bool HandleVolumeMountForUpload(string path, ProgramConfig config) { Console.WriteLine($"HandleVolumeMountForUpload: handling volume at path {path} for upload"); if (!IsVolumeMountPointForUploadValid(path)) { Console.WriteLine($"HandleVolumeMountForUpload: mount point for volume failed inner validity check"); return(false); } var configText = File.ReadAllText($"{path}MISC\\settings.json"); var configParsed = JsonConvert.DeserializeObject <JObject>(configText); var serialNumber = configParsed["info"]["serial-number"].ToObject <string>(); var creds = new ServerCredentials() { serverUrl = config.dbUrl, }; var serverConfig = ServerUtility.GetConfiguration(creds, serialNumber, configText); if (IsBC300ConfigTheSame(configText, serverConfig.deviceConfig)) { File.WriteAllText($"{path}MISC\\settings.json", serverConfig.deviceConfig); } var serverReportedUserId = serverConfig.userId; // Scan for data files. foreach (var sdir in Directory.EnumerateDirectories($"{path}DCIM\\")) { foreach (var sfile in Directory.EnumerateFiles(sdir)) { var baseName = Path.GetFileNameWithoutExtension(sfile); var baseParts = baseName.Split('_'); if (baseParts.Length < 3) { continue; } var fullPath = sfile; var dataSize = new FileInfo(fullPath).Length; var dataType = Path.GetExtension(sfile).Substring(1).ToLower(); var dateString = baseParts[2].Substring(0, 8); var dateDay = dateString.Substring(2, 2); var dateMonth = dateString.Substring(0, 2); var dateYear = dateString.Substring(4, 4); dateString = $"{dateYear}-{dateMonth}-{dateDay}"; var timeString = baseParts[2].Substring(8, 6); var dataStream = File.OpenRead(fullPath); Console.WriteLine($"Uploading {fullPath}"); var uploadTask = MDACS.API.Database.UploadAsync( config.authUrl, config.dbUrl, config.username, config.password, dataSize, dataType, dateString, serialNumber, timeString, serverReportedUserId, dataStream ); Console.WriteLine("Waiting..."); uploadTask.Wait(); Console.WriteLine("Done upload.."); var uploadResult = uploadTask.Result; dataStream.Close(); if (uploadResult.success && uploadResult.security_id.Length != 0) { Console.WriteLine("Upload success"); File.Delete(fullPath); } else { Console.WriteLine("Upload failure"); } } } // Would be nice to be able to run a chkdsk /F command on the volume just to help over time correct some issues. /*var processInfo = new ProcessStartInfo() * { * FileName = "chkdsk.exe", * Arguments = $"{path} /f /r /x", * }; * * var chkdskProcess = Process.Start(processInfo); * chkdskProcess.StandardInput.WriteLine("Y"); * chkdskProcess.StandardInput.WriteLine("Y"); * chkdskProcess.StandardInput.WriteLine("Y"); * chkdskProcess.WaitForExit(1000 * 60 * 5); */ return(true); }