int impl_fuse_context::move_file(LPCWSTR file_name, LPCWSTR new_file_name, BOOL replace_existing, PDOKAN_FILE_INFO dokan_file_info) { if (!ops_.rename || !ops_.getattr) return -EINVAL; std::string name=unixify(wchar_to_utf8_cstr(file_name)); std::string new_name=unixify(wchar_to_utf8_cstr(new_file_name)); struct FUSE_STAT stbuf={0}; if (ops_.getattr(new_name.c_str(),&stbuf)!=-ENOENT) { //Cannot delete directory if ((stbuf.st_mode&S_IFDIR)==0 && ops_.unlink) { if (replace_existing) { CHECKED(ops_.unlink(new_name.c_str())); } else { return -EEXIST; } } } return ops_.rename(name.c_str(),new_name.c_str()); }
int impl_fuse_context::move_file(LPCWSTR file_name, LPCWSTR new_file_name, BOOL replace_existing, PDOKAN_FILE_INFO dokan_file_info) { if (!ops_.rename || !ops_.getattr) return -EINVAL; std::string name = unixify(wchar_to_utf8_cstr(file_name)); std::string new_name = unixify(wchar_to_utf8_cstr(new_file_name)); struct FUSE_STAT stbuf = {0}; if (ops_.getattr(new_name.c_str(), &stbuf) != -ENOENT) { if (!replace_existing) return -EEXIST; // Cannot delete directory if ((stbuf.st_mode & S_IFDIR) != 0) return -EISDIR; if (!ops_.unlink) return -EINVAL; CHECKED(ops_.unlink(new_name.c_str())); } // this can happen cause DeleteFile in Windows can return success even if // file is still in the file system if (ops_.getattr(new_name.c_str(), &stbuf) != -ENOENT) { return -EEXIST; } CHECKED(ops_.rename(name.c_str(), new_name.c_str())); file_locks.renamed_file(name, new_name); return 0; }
int impl_fuse_context::set_file_time(PCWSTR file_name, const FILETIME *creation_time, const FILETIME *last_access_time, const FILETIME *last_write_time, PDOKAN_FILE_INFO dokan_file_info) { if (!ops_.utimens && !ops_.utime && !ops_.win_set_times) return -EINVAL; if (ops_.win_set_times) { std::string fname = unixify(wchar_to_utf8_cstr(file_name)); CHECKED(check_and_resolve(&fname)); impl_file_handle *hndl = reinterpret_cast<impl_file_handle *>(dokan_file_info->Context); if (!hndl) return ops_.win_set_times(fname.c_str(), NULL, creation_time, last_access_time, last_write_time); if (hndl->is_dir()) return -EACCES; fuse_file_info finfo(hndl->make_finfo()); return ops_.win_set_times(fname.c_str(), &finfo, creation_time, last_access_time, last_write_time); } if (!ops_.getattr) return -EINVAL; std::string fname = unixify(wchar_to_utf8_cstr(file_name)); CHECKED(check_and_resolve(&fname)); struct FUSE_STAT st = {0}; CHECKED(ops_.getattr(fname.c_str(), &st)); if (ops_.utimens) { struct timespec tv[2] = {0}; // TODO: support nanosecond resolution // Access time CHECKED(helper_set_time_struct(last_access_time, st.st_atim.tv_sec, &(tv[0].tv_sec))); // Modification time CHECKED(helper_set_time_struct(last_write_time, st.st_mtim.tv_sec, &(tv[1].tv_sec))); return ops_.utimens(fname.c_str(), tv); } else { struct utimbuf ut = {0}; // Access time CHECKED(helper_set_time_struct(last_access_time, st.st_atim.tv_sec, &(ut.actime))); // Modification time CHECKED(helper_set_time_struct(last_write_time, st.st_mtim.tv_sec, &(ut.modtime))); return ops_.utime(fname.c_str(), &ut); } }
win_error impl_fuse_context::create_file(LPCWSTR file_name, DWORD access_mode, DWORD share_mode, DWORD creation_disposition, DWORD flags_and_attributes, PDOKAN_FILE_INFO dokan_file_info) { std::string fname=unixify(wchar_to_utf8_cstr(file_name)); dokan_file_info->Context=0; if (!ops_.getattr) return -EINVAL; struct FUSE_STAT stbuf={0}; //Check if the target file/directory exists if (ops_.getattr(fname.c_str(),&stbuf)<0) { //Nope. if (dokan_file_info->IsDirectory) return -EINVAL; //We can't create directories using CreateFile return do_create_file(file_name, creation_disposition, share_mode, access_mode, dokan_file_info); } else { if (S_ISLNK(stbuf.st_mode)) { //Get link's target CHECKED(resolve_symlink(fname,&fname)); CHECKED(ops_.getattr(fname.c_str(),&stbuf)); } if ((stbuf.st_mode&S_IFDIR)==S_IFDIR) { //Existing directory //TODO: add access control dokan_file_info->IsDirectory=TRUE; return do_open_dir(file_name,dokan_file_info); } else { //Existing file //Check if we'll be able to truncate or delete the opened file //TODO: race condition here? if (creation_disposition==CREATE_ALWAYS) { if (!ops_.unlink) return -EINVAL; CHECKED(ops_.unlink(fname.c_str())); //Delete file //And create it! return do_create_file(file_name,creation_disposition, share_mode, access_mode,dokan_file_info); } else if (creation_disposition==TRUNCATE_EXISTING) { if (!ops_.truncate) return -EINVAL; CHECKED(ops_.truncate(fname.c_str(),0)); } else if (creation_disposition==CREATE_NEW) { return win_error(ERROR_FILE_EXISTS, true); } return do_open_file(file_name, share_mode, access_mode, dokan_file_info); } } }
int impl_fuse_context::do_create_file(LPCWSTR FileName, DWORD Disposition, DWORD share_mode, DWORD Flags, PDOKAN_FILE_INFO DokanFileInfo) { std::string fname=unixify(wchar_to_utf8_cstr(FileName)); //Create file? if (Disposition!=CREATE_NEW && Disposition!=CREATE_ALWAYS && Disposition!=OPEN_ALWAYS) return -ENOENT; //No, we're trying to open an existing file! if (!ops_.create) { //Use mknod+open. if (!ops_.mknod || !ops_.open) return -EINVAL; CHECKED(ops_.mknod(fname.c_str(),filemask_,0)); return do_open_file(FileName, share_mode, Flags, DokanFileInfo); } std::auto_ptr<impl_file_handle> file; CHECKED(file_locks.get_file(fname,false,Flags,share_mode,file)); fuse_file_info finfo={0}; finfo.flags=O_CREAT | O_EXCL | convert_flags(Flags); //TODO: these flags should be OK for new files? CHECKED(ops_.create(fname.c_str(),filemask_,&finfo)); DokanFileInfo->Context=reinterpret_cast<ULONG64>(file.release()); return 0; }
void Drive::Umount(HWND) { // check mounted CheckMounted(); // if (GetDriveType(mnt) == DRIVE_NO_ROOT_DIR) // mounted = false; if (!mounted) throw truntime_error(_T("Cannot unmount a not mounted drive")); // unmount fuse_unmount(wchar_to_utf8_cstr(mnt).c_str(), NULL); if (subProcess) { // attach console to allow sending ctrl-c AttachConsole(subProcess->pid); // disable ctrl-c to not exit this process SetConsoleCtrlHandler(HandlerRoutine, TRUE); if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT, subProcess->pid) && !GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, subProcess->pid)) TerminateProcess(subProcess->hProcess, 0); // force exit if (WaitForSingleObject(subProcess->hProcess, 2000) == WAIT_TIMEOUT) TerminateProcess(subProcess->hProcess, 0); // close the console FreeConsole(); SetConsoleCtrlHandler(HandlerRoutine, FALSE); } CheckMounted(); }
int impl_fuse_context::set_file_time(PCWSTR file_name, const FILETIME* creation_time, const FILETIME* last_access_time, const FILETIME* last_write_time, PDOKAN_FILE_INFO dokan_file_info) { if (!ops_.utimens && !ops_.utime) return -EINVAL; if (!ops_.getattr) return -EINVAL; std::string fname=unixify(wchar_to_utf8_cstr(file_name)); CHECKED(check_and_resolve(&fname)); struct FUSE_STAT st={0}; CHECKED(ops_.getattr(fname.c_str(),&st)); if (ops_.utimens) { struct timespec tv[2]={{0,},}; //TODO: support nanosecond resolution //Access time CHECKED(helper_set_time_struct(last_access_time,st.st_atime,&(tv[0].tv_sec))); //Modification time CHECKED(helper_set_time_struct(last_write_time,st.st_mtime,&(tv[1].tv_sec))); return ops_.utimens(fname.c_str(),tv); } else { struct utimbuf ut={0}; //Access time CHECKED(helper_set_time_struct(last_access_time,st.st_atime,&(ut.actime))); //Modification time CHECKED(helper_set_time_struct(last_write_time,st.st_mtime,&(ut.modtime))); return ops_.utime(fname.c_str(),&ut); } }
int impl_fuse_context::get_file_information( LPCWSTR file_name, LPBY_HANDLE_FILE_INFORMATION handle_file_information, PDOKAN_FILE_INFO dokan_file_info) { std::string fname = unixify(wchar_to_utf8_cstr(file_name)); if (!ops_.getattr) return -EINVAL; struct FUSE_STAT st = {0}; CHECKED(ops_.getattr(fname.c_str(), &st)); if (S_ISLNK(st.st_mode)) { std::string resolved; CHECKED(resolve_symlink(fname, &resolved)); CHECKED(ops_.getattr(resolved.c_str(), &st)); } handle_file_information->nNumberOfLinks = st.st_nlink; if ((st.st_mode & S_IFDIR) == S_IFDIR) dokan_file_info->IsDirectory = TRUE; convertStatlikeBuf(&st, fname, handle_file_information); uint32_t attrs = 0xFFFFFFFFu; if (ops_.win_get_attributes) attrs = ops_.win_get_attributes(fname.c_str()); if (attrs != 0xFFFFFFFFu) handle_file_information->dwFileAttributes = attrs; return 0; }
int impl_fuse_context::open_directory(LPCWSTR file_name, PDOKAN_FILE_INFO dokan_file_info) { std::string fname=unixify(wchar_to_utf8_cstr(file_name)); if (ops_.opendir) return do_open_dir(file_name,dokan_file_info); //We don't have opendir(), so the most we can do is make sure //that the target is indeed a directory struct FUSE_STAT st={0}; CHECKED(ops_.getattr(fname.c_str(),&st)); if (S_ISLNK(st.st_mode)) { std::string resolved; CHECKED(resolve_symlink(fname,&resolved)); CHECKED(ops_.getattr(resolved.c_str(),&st)); } //Not a directory if ((st.st_mode&S_IFDIR)!=S_IFDIR) return -ENOTDIR; dokan_file_info->Context=(ULONG64)NULL; //Do not want to attach anything return 0; //Use readdir here? }
static void OpenOrCreate(HWND hwnd) { static bool openAlreadyOpened = false; if (openAlreadyOpened) return; class Unique { public: Unique() { openAlreadyOpened = true; } ~Unique() { openAlreadyOpened = false; } } unique; std::tstring dir = GetExistingDirectory(hwnd, _T("Select a folder which contains or will contain encrypted data."), _T("Select Crypt Folder")); if (dir.empty()) return; // if directory is already configured add and try to mount boost::shared_ptr<EncFSConfig> config(new EncFSConfig); if (readConfig(slashTerminate(wchar_to_utf8_cstr(dir.c_str())), config) != Config_None) { char drive = SelectFreeDrive(hwnd); if (drive) { Drives::drive_t dr(Drives::Add(dir, drive)); if (dr) dr->Mount(hwnd); } return; } // TODO check directory is empty, warning if continue // "You are initializing a crypted directory with a no-empty directory. Is this expected?" OptionsData data; data.rootDir = dir; if (DialogBoxParam(hInst, (LPCTSTR) IDD_OPTIONS, hwnd, (DLGPROC) OptionsDlgProc, (LPARAM) &data) != IDOK) return; // add configuration and add new drive createConfig(slashTerminate(wchar_to_utf8_cstr(dir.c_str())), data.paranoia, false, wchar_to_utf8_cstr(data.password).c_str(), true); Drives::drive_t dr(Drives::Add(dir, data.drive)); if (dr) dr->Mount(hwnd); }
int impl_fuse_context::do_delete_file(LPCWSTR file_name, PDOKAN_FILE_INFO dokan_file_info) { if (!ops_.unlink) return -EINVAL; // Note: we do not try to resolve symlink target std::string fname = unixify(wchar_to_utf8_cstr(file_name)); return ops_.unlink(fname.c_str()); }
int impl_fuse_context::create_directory(LPCWSTR file_name, PDOKAN_FILE_INFO dokan_file_info) { std::string fname = unixify(wchar_to_utf8_cstr(file_name)); if (!ops_.mkdir) return -EINVAL; return ops_.mkdir(fname.c_str(), dirmask_); }
int impl_fuse_context::delete_file(LPCWSTR file_name, PDOKAN_FILE_INFO dokan_file_info) { std::string fname = unixify(wchar_to_utf8_cstr(file_name)); if (!ops_.getattr) return -EINVAL; struct FUSE_STAT stbuf = {0}; return ops_.getattr(fname.c_str(), &stbuf); }
int impl_fuse_context::do_open_dir(LPCWSTR FileName, PDOKAN_FILE_INFO DokanFileInfo) { if (ops_.opendir) { fuse_file_info finfo={0}; std::string fname=unixify(wchar_to_utf8_cstr(FileName)); CHECKED(ops_.opendir(fname.c_str(),&finfo)); DokanFileInfo->Context=reinterpret_cast<ULONG64>(new impl_file_handle(fname,true,&finfo)); return 0; } DokanFileInfo->Context=0; return 0; }
int impl_fuse_context::walk_directory(void *buf, const char *name, const struct FUSE_STAT *stbuf, FUSE_OFF_T off) { walk_data *wd=(walk_data*)buf; WIN32_FIND_DATAW find_data={0}; utf8_to_wchar_buf(name,find_data.cFileName,MAX_PATH); // fix name if wrong encoding if (!find_data.cFileName[0]) { struct FUSE_STAT stbuf={0}; utf8_to_wchar_buf_old(name,find_data.cFileName,MAX_PATH); std::string new_name = wchar_to_utf8_cstr(find_data.cFileName); if (wd->ctx->ops_.getattr && wd->ctx->ops_.rename && new_name.length() && wd->ctx->ops_.getattr(new_name.c_str(),&stbuf) == -ENOENT) wd->ctx->ops_.rename(name, new_name.c_str()); } memset(find_data.cAlternateFileName, 0, sizeof(find_data.cAlternateFileName)); struct FUSE_STAT stat={0}; if (stbuf!=NULL) stat=*stbuf; else { //No stat buffer - use 'getattr'. //TODO: fill directory params here!!! if (strcmp(name,".")==0 || strcmp(name,"..")==0) //Special entries stat.st_mode|=S_IFDIR; else CHECKED(wd->ctx->ops_.getattr((wd->dirname+name).c_str(),&stat)); } if (S_ISLNK(stat.st_mode)) { std::string resolved; CHECKED(wd->ctx->resolve_symlink(wd->dirname+name,&resolved)); CHECKED(wd->ctx->ops_.getattr(resolved.c_str(),&stat)); } convertStatlikeBuf(&stat,name,&find_data); uint32_t attrs = 0xFFFFFFFFu; if (wd->ctx->ops_.win_get_attributes) attrs = wd->ctx->ops_.win_get_attributes((wd->dirname+name).c_str()); if (attrs != 0xFFFFFFFFu) find_data.dwFileAttributes = attrs; return wd->delegate(&find_data,wd->DokanFileInfo); }
int impl_fuse_context::do_open_file(LPCWSTR FileName, DWORD Flags, PDOKAN_FILE_INFO DokanFileInfo) { if (!ops_.open) return -EINVAL; std::string fname=unixify(wchar_to_utf8_cstr(FileName)); CHECKED(check_and_resolve(&fname)); fuse_file_info finfo={0}; //if ((ShareMode & FILE_SHARE_READ) || (ShareMode & FILE_SHARE_DELETE)) //TODO: add sharing support? finfo.flags=convert_flags(Flags); CHECKED(ops_.open(fname.c_str(),&finfo)); DokanFileInfo->Context=reinterpret_cast<ULONG64>(new impl_file_handle(fname,false,&finfo)); return 0; }
int impl_fuse_context::set_file_attributes(LPCWSTR file_name, DWORD file_attributes, PDOKAN_FILE_INFO dokan_file_info) { // This method is unlikely to be implemented since we do not support // advanced properties // TODO: maybe use extended properties of underlying FS? // Just return 'success' since returning -EINVAL interferes with modification // time // setting from FAR Manager. if (ops_.win_set_attributes) { std::string fname = unixify(wchar_to_utf8_cstr(file_name)); CHECKED(check_and_resolve(&fname)); return ops_.win_set_attributes(fname.c_str(), file_attributes); } return 0; }
int impl_fuse_context::set_end_of_file(LPCWSTR file_name, LONGLONG byte_offset, PDOKAN_FILE_INFO dokan_file_info) { FUSE_OFF_T off; CHECKED(cast_from_longlong(byte_offset, &off)); std::string fname = unixify(wchar_to_utf8_cstr(file_name)); CHECKED(check_and_resolve(&fname)); impl_file_handle *hndl = reinterpret_cast<impl_file_handle *>(dokan_file_info->Context); if (hndl && ops_.ftruncate) { fuse_file_info finfo(hndl->make_finfo()); return ops_.ftruncate(hndl->get_name().c_str(), off, &finfo); } if (!ops_.truncate) return -EINVAL; return ops_.truncate(fname.c_str(), off); }
int impl_fuse_context::find_files(LPCWSTR file_name, PFillFindData fill_find_data, PDOKAN_FILE_INFO dokan_file_info) { if ((!ops_.readdir && !ops_.getdir) || !ops_.getattr) return -EINVAL; std::string fname = unixify(wchar_to_utf8_cstr(file_name)); CHECKED(check_and_resolve(&fname)); walk_data wd; wd.ctx = this; wd.dirname = fname; if (*fname.rbegin() != '/') wd.dirname.append("/"); wd.delegate = fill_find_data; wd.DokanFileInfo = dokan_file_info; if (ops_.readdir) { impl_file_handle *hndl = reinterpret_cast<impl_file_handle *>(dokan_file_info->Context); if (hndl != NULL) { fuse_file_info finfo(hndl->make_finfo()); return ops_.readdir(fname.c_str(), &wd, &walk_directory, 0, &finfo); } else return ops_.readdir(fname.c_str(), &wd, &walk_directory, 0, NULL); } else { CHECKED( ops_.getdir(fname.c_str(), (fuse_dirh_t)&wd, &walk_directory_getdir)); // Convert returned data The getdir_data array will be filled during // getdir() call. // We emulate FUSE behavior and do not pass information directly to Dokan // in walk_directory_getdir callback. This can cause excessive network // traffic // in sshfs because it populates stat buffer cache AFTER calling our // callback. // See: cache.c file, function cache_dirfill() in SSHFS 2.2 for (std::vector<std::string>::const_iterator f = wd.getdir_data.begin(); f != wd.getdir_data.end(); ++f) CHECKED(walk_directory(&wd, f->c_str(), 0, 0)); } return 0; }
int impl_fuse_context::do_open_file(LPCWSTR FileName, DWORD share_mode, DWORD Flags, PDOKAN_FILE_INFO DokanFileInfo) { if (!ops_.open) return -EINVAL; std::string fname=unixify(wchar_to_utf8_cstr(FileName)); CHECKED(check_and_resolve(&fname)); std::auto_ptr<impl_file_handle> file; CHECKED(file_locks.get_file(fname,false,Flags,share_mode,file)); fuse_file_info finfo={0}; finfo.flags=convert_flags(Flags); CHECKED(ops_.open(fname.c_str(),&finfo)); file->set_finfo(finfo); DokanFileInfo->Context=reinterpret_cast<ULONG64>(file.release()); return 0; }
int impl_fuse_context::do_open_dir(LPCWSTR FileName, PDOKAN_FILE_INFO DokanFileInfo) { if (ops_.opendir) { std::string fname=unixify(wchar_to_utf8_cstr(FileName)); std::auto_ptr<impl_file_handle> file; // TODO access_mode CHECKED(file_locks.get_file(fname,true,0,FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,file)); fuse_file_info finfo={0}; CHECKED(ops_.opendir(fname.c_str(),&finfo)); file->set_finfo(finfo); DokanFileInfo->Context=reinterpret_cast<ULONG64>(file.release()); return 0; } DokanFileInfo->Context=0; return 0; }
int impl_fuse_context::do_create_file(LPCWSTR FileName, DWORD Disposition, DWORD share_mode, DWORD Flags, PDOKAN_FILE_INFO DokanFileInfo) // Kernel mappsings: // Disposition = CreateDisposition // Flags = DesiredAccess // share_mode = ShareAccess { std::string fname = unixify(wchar_to_utf8_cstr(FileName)); // Create file? if (Disposition != FILE_CREATE && Disposition != FILE_SUPERSEDE && Disposition != FILE_OPEN_IF && Disposition != FILE_OVERWRITE_IF) { SetLastError(ERROR_FILE_NOT_FOUND); return -ENOENT; // No, we're trying to open an existing file! } if (!ops_.create) { // Use mknod+open. if (!ops_.mknod || !ops_.open) return -EINVAL; CHECKED(ops_.mknod(fname.c_str(), filemask_, 0)); return do_open_file(FileName, share_mode, Flags, DokanFileInfo); } std::unique_ptr<impl_file_handle> file; CHECKED(file_locks.get_file(fname, false, Flags, share_mode, file)); fuse_file_info finfo = {0}; finfo.flags = O_CREAT | O_EXCL | convert_flags(Flags); // TODO: these flags should be OK for new files? CHECKED(ops_.create(fname.c_str(), filemask_, &finfo)); file->set_finfo(finfo); DokanFileInfo->Context = reinterpret_cast<ULONG64>(file.release()); return 0; }
int impl_fuse_context::do_delete_directory(LPCWSTR file_name, PDOKAN_FILE_INFO dokan_file_info) { std::string fname = unixify(wchar_to_utf8_cstr(file_name)); if (!ops_.rmdir || !ops_.getattr) return -EINVAL; // Make sure directory is NOT opened // TODO: potential race here - Unix filesystems typically allow // to delete open files and directories. impl_file_handle *hndl = reinterpret_cast<impl_file_handle *>(dokan_file_info->Context); if (hndl) return -EBUSY; // A special case: symlinks are deleted by unlink, not rmdir struct FUSE_STAT stbuf = {0}; CHECKED(ops_.getattr(fname.c_str(), &stbuf)); if (S_ISLNK(stbuf.st_mode) && ops_.unlink) return ops_.unlink(fname.c_str()); // Ok, try to rmdir it. return ops_.rmdir(fname.c_str()); }
void Drive::Mount(HWND hwnd) { // check drive empty or require a new drive while (GetDriveType(mnt) != DRIVE_NO_ROOT_DIR) { char drive = SelectFreeDrive(hwnd); if (!drive) return; _stprintf(mnt, _T("%c:\\"), drive); Save(); } // check directory existence if (!isDirectory(wchar_to_utf8_cstr(dir.c_str()).c_str())) { if (YesNo(hwnd, _T("Directory does not exists. Remove from list?"))) Drives::Delete(shared_from_this()); return; } // TODO check configuration still exists ?? ... no can cause recursion problem // search if executable is present TCHAR executable[MAX_PATH]; if (!SearchPath(NULL, _T("encfs.exe"), NULL, LENGTH(executable), executable, NULL)) throw truntime_error(_T("Unable to find encfs.exe file")); // ask a password to mount TCHAR pass[128+2]; if (!GetPassword(hwnd, pass, LENGTH(pass)-2)) return; _tcscat(pass, _T("\r\n")); // mount using a sort of popen TCHAR cmd[2048]; _sntprintf(cmd, LENGTH(cmd), _T("\"%s\" -S \"%s\" %c:"), executable, dir.c_str(), mnt[0]); boost::shared_ptr<SubProcessInformations> proc(new SubProcessInformations); proc->creationFlags = CREATE_NEW_PROCESS_GROUP|CREATE_NO_WINDOW; if (!CreateSubProcess(cmd, proc.get())) { DWORD err = GetLastError(); memset(pass, 0, sizeof(pass)); _sntprintf(cmd, LENGTH(cmd), _T("Error: %s (%u)"), proc->errorPart, (unsigned) err); throw truntime_error(cmd); } subProcess = proc; // send the password std::string pwd = wchar_to_utf8_cstr(pass); DWORD written; WriteFile(proc->hIn, pwd.c_str(), pwd.length(), &written, NULL); CloseHandle(proc->hIn); // close input so sub process does not any more proc->hIn = NULL; memset(pass, 0, sizeof(pass)); memset((char*) pwd.c_str(), 0, pwd.length()); mounted = false; // wait for mount, read error and give feedback for (unsigned n = 0; n < 5*10; ++n) { // drive appeared if (GetDriveType(mnt) != DRIVE_NO_ROOT_DIR) { if (Drives::autoShow) Show(hwnd); break; } // process terminated DWORD readed; char output[2048]; switch (WaitForSingleObject(subProcess->hProcess, 200)) { case WAIT_OBJECT_0: case WAIT_ABANDONED: if (ReadFile(proc->hOut, output, sizeof(output)-1, &readed, NULL)) { output[readed] = 0; utf8_to_wchar_buf(output, cmd, LENGTH(cmd)); } else { _stprintf(cmd, _T("Unknown error mounting drive %c:"), mnt[0]); } subProcess.reset(); throw truntime_error(cmd); } } if (subProcess) mounted = true; Save(); // save for resume }