static void parse_node_namespace(syntree_t st) { str_it_t i, e; i = syntree_position(st); e = str_end(syntree_str(st)); p_skip_spaces(i, e); syntree_seek(st, i); parse_node_name(st); if(err()) return; i = syntree_position(st); p_skip_spaces(i,e); if(i==e ? 1 : *i!='[') goto error; i++; while(i<e) { p_skip_spaces(i, e); if(i==e) goto error; if(*i==']') { syntree_seek(st, i+1); return; } syntree_seek(st, i); xcss_parse(st); if(err()) return; i = syntree_position(st); if(i==e) goto error; } error: syntree_seek(st, i); err_set(e_xcss_syntax); return; }
static void parse_node_class_parent(syntree_t st) { str_it_t i, e; syntree_named_start(st, XCSS_NODE_CLASS_PARENT); i = syntree_position(st); e = str_end(syntree_str(st)); p_skip_spaces(i, e); if(i==e ? 1 : *i!='(') goto error; i++; syntree_seek(st, i); parse_node_class_name(st); while(!err()) { i = syntree_position(st); p_skip_spaces(i, e); if(i==e) goto error; if(*i==')') { syntree_seek(st, i+1); syntree_named_end(st); return; } else if(*i==',') { i++; p_skip_spaces(i, e); syntree_seek(st,i); parse_node_class_name(st); } else goto error; } error: syntree_seek(st, i); err_set(e_xcss_syntax); return; }
static void parse_node_class_name(syntree_t st) { syntree_named_start(st, XCSS_NODE_CLASS_NAME); if(err()) return; else { str_it_t i, e, j; i = syntree_position(st); e = str_end(syntree_str(st)); while(1) { p_skip(i, e, isclass_name_char(*i)); if(i==e) goto error; j = i; p_skip_spaces(j, e); if(j==e) goto error; if(!isclass_name_char(*j)) break; i = j; } if(i!=e) { syntree_seek(st, i); syntree_named_end(st); return; } error: syntree_seek(st, i); err_set(e_xcss_syntax); return; } }
static void parse_node_comment(syntree_t st) { str_it_t i, e; i = syntree_position(st); e = str_end(syntree_str(st)); p_skip_spaces(i, e); if((e-i)>=2 ? i[0]!='/' || i[1]!='*' : 1) { err_set(e_xcss_syntax); return; } i+=2; for(; i<e; i++) { if((e-i)>=2 ? i[0]=='*' && i[1]=='/' : 0) { syntree_seek(st, i+2); return; } } err_set(e_xcss_syntax); }
static void parse_node_include(syntree_t st) { str_it_t i, j, e; static char include_str[] = "include"; i = syntree_position(st); e = str_end(syntree_str(st)); p_skip_spaces(i, e); if((e-i)<7) goto error; for(j=include_str; *j; j++, *i++) if(*i!=*j) goto error; p_skip_spaces(i, e); if((e-i)<5) goto error; p_skip_spaces(i, e); if(*i!='(') goto error; i++; p_skip_spaces(i, e); if(*i!='"') goto error; i++; syntree_seek(st, i); syntree_named_start(st, XCSS_NODE_INCLUDE_NAME); if(err()) return; p_skip(i, e, (isgraph(*i) && *i!=':' && *i!='"') || *i==' '); syntree_seek(st,i); syntree_named_end(st); if(err()) return; if(i==e) goto error; if(*i!='"') goto error; i++; p_skip_spaces(i, e); if(i==e) goto error; if(*i!=')') goto error; i++; if(i==e) goto error; p_skip_spaces(i, e); if(i==e) goto error; if(*i!=';') goto error; syntree_seek(st, i+1); return; error: syntree_seek(st, i); err_set(e_xcss_syntax); return; }
static void parse_node_class(syntree_t st) { str_it_t i, e; i = syntree_position(st); e = str_end(syntree_str(st)); p_skip_spaces(i, e); syntree_seek(st, i); parse_node_class_name(st); if(err()) return; i = syntree_position(st); p_skip_spaces(i,e); if(i==e) goto error; if(*i=='(') { parse_node_class_parent(st); if(err()) return; i = syntree_position(st); p_skip_spaces(i,e); if(i==e) goto error; } if(*i=='{') { i++; while(i<e) { p_skip_spaces(i, e); if(i==e) goto error; syntree_seek(st, i); if(*i=='/') parse_node_comment(st); else if(*i=='}') { syntree_seek(st, i+1); return; } else { syntree_named_start(st, XCSS_NODE_RULE); if(err()) return; parse_node_rule(st); if(err()) return; syntree_named_end(st); if(err()) return; } i = syntree_position(st); } } error: syntree_seek(st, i); err_set(e_xcss_syntax); return; }
static void parse_node_value(syntree_t st) { str_it_t i, e; i = syntree_position(st); e = str_end(syntree_str(st)); syntree_named_start(st, XCSS_NODE_VALUE); if(err()) return; while(i<e ? *i!=';' : 0) { if((e-i)>=2 ? i[0]=='$' && i[1]=='{' : 0) { syntree_seek(st, i+2); parse_node_name(st); i = syntree_position(st); if(i<e ? *i!='}' : 1) { err_set(e_xcss_syntax); return; } i++; syntree_seek(st, i); } else { syntree_named_start(st, XCSS_NODE_TEXT); if(err()) return; while(i<e && *i!=';') { i++; if((e-i)>=2 ? i[0]=='$' && i[1]=='{' : 0) break; } syntree_seek(st, i); syntree_named_end(st); } } if(i==e) { err_set(e_xcss_syntax); } else { syntree_seek(st, i+1); syntree_named_end(st); } }
static void parse_node_name(syntree_t st) { syntree_named_start(st, XCSS_NODE_NAME); if(err()) return; else { str_it_t i, e; i = syntree_position(st); e = str_end(syntree_str(st)); p_skip(i, e, isalnum(*i) || (*i=='_') || (*i=='-')); if(i==e) { err_set(e_xcss_syntax); } else { syntree_seek(st, i); syntree_named_end(st); } } }
static void xcss_parse(syntree_t res) { xcss_node_type_t nd_type; str_it_t e = str_end(syntree_str(res)); if(nd_type = get_node_type(syntree_position(res), e)) { syntree_named_start(res, nd_type); if(err()) return; switch(nd_type) { case XCSS_NODE_RULE: parse_node_rule(res); break; case XCSS_NODE_NAMESPACE: parse_node_namespace(res); break; case XCSS_NODE_CLASS: parse_node_class(res); break; case XCSS_NODE_COMMENT: parse_node_comment(res); break; case XCSS_NODE_INCLUDE: parse_node_include(res); break; default: { assert(0); /* Invalid node type*/ } } if(err()) return; syntree_named_end(res); } else { str_it_t i = syntree_position(res); str_it_t e = str_end(syntree_str(res)); p_skip_spaces(i, e); syntree_seek(res, i); if(i!=e) { err_set(e_xcss_syntax); return; } } return; }
static void parse_node_rule(syntree_t st) { str_it_t i, e; i = syntree_position(st); e = str_end(syntree_str(st)); p_skip_spaces(i,e); syntree_seek(st, i); parse_node_name(st); if(err()) return; i = syntree_position(st); p_skip_spaces(i,e); if(i==e ? 1 : (*i)!=':') { err_set(e_xcss_syntax); return; } i++; p_skip_spaces(i,e); syntree_seek(st, i); parse_node_value(st); return; }
void requester_thaw(int *num_vols, void *mountpints, ErrorSet *errset) { COMPointer<IVssAsync> pAsync; if (!vss_ctx.hEventThaw) { /* * In this case, DoSnapshotSet is aborted or not started, * and no volumes must be frozen. We return without an error. */ *num_vols = 0; return; } /* Tell the provider that the snapshot is finished. */ SetEvent(vss_ctx.hEventThaw); assert(vss_ctx.pVssbc); assert(vss_ctx.pAsyncSnapshot); HRESULT hr = WaitForAsync(vss_ctx.pAsyncSnapshot); switch (hr) { case VSS_S_ASYNC_FINISHED: hr = vss_ctx.pVssbc->BackupComplete(pAsync.replace()); if (SUCCEEDED(hr)) { hr = WaitForAsync(pAsync); } if (FAILED(hr)) { err_set(errset, hr, "failed to complete backup"); } break; case (HRESULT)VSS_E_OBJECT_NOT_FOUND: /* * On Windows earlier than 2008 SP2 which does not support * VSS_VOLSNAP_ATTR_NO_AUTORECOVERY context, the final commit is not * skipped and VSS is aborted by VSS_E_OBJECT_NOT_FOUND. However, as * the system had been frozen until fsfreeze-thaw command was issued, * we ignore this error. */ vss_ctx.pVssbc->AbortBackup(); break; case VSS_E_UNEXPECTED_PROVIDER_ERROR: if (WaitForSingleObject(vss_ctx.hEventTimeout, 0) != WAIT_OBJECT_0) { err_set(errset, hr, "unexpected error in VSS provider"); break; } /* fall through if hEventTimeout is signaled */ case (HRESULT)VSS_E_HOLD_WRITES_TIMEOUT: err_set(errset, hr, "couldn't hold writes: " "fsfreeze is limited up to 10 seconds"); break; default: err_set(errset, hr, "failed to do snapshot set"); } if (err_is_set(errset)) { vss_ctx.pVssbc->AbortBackup(); } *num_vols = vss_ctx.cFrozenVols; requester_cleanup(); CoUninitialize(); StopService(); }
void requester_freeze(int *num_vols, void *mountpoints, ErrorSet *errset) { COMPointer<IVssAsync> pAsync; HANDLE volume; HRESULT hr; LONG ctx; GUID guidSnapshotSet = GUID_NULL; SECURITY_DESCRIPTOR sd; SECURITY_ATTRIBUTES sa; WCHAR short_volume_name[64], *display_name = short_volume_name; DWORD wait_status; int num_fixed_drives = 0, i; int num_mount_points = 0; if (vss_ctx.pVssbc) { /* already frozen */ *num_vols = 0; return; } CoInitialize(NULL); /* Allow unrestricted access to events */ InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = &sd; sa.bInheritHandle = FALSE; vss_ctx.hEventFrozen = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_FROZEN); if (!vss_ctx.hEventFrozen) { err_set(errset, GetLastError(), "failed to create event %s", EVENT_NAME_FROZEN); goto out; } vss_ctx.hEventThaw = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_THAW); if (!vss_ctx.hEventThaw) { err_set(errset, GetLastError(), "failed to create event %s", EVENT_NAME_THAW); goto out; } vss_ctx.hEventTimeout = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_TIMEOUT); if (!vss_ctx.hEventTimeout) { err_set(errset, GetLastError(), "failed to create event %s", EVENT_NAME_TIMEOUT); goto out; } assert(pCreateVssBackupComponents != NULL); hr = pCreateVssBackupComponents(&vss_ctx.pVssbc); if (FAILED(hr)) { err_set(errset, hr, "failed to create VSS backup components"); goto out; } hr = vss_ctx.pVssbc->InitializeForBackup(); if (FAILED(hr)) { err_set(errset, hr, "failed to initialize for backup"); goto out; } hr = vss_ctx.pVssbc->SetBackupState(true, true, VSS_BT_FULL, false); if (FAILED(hr)) { err_set(errset, hr, "failed to set backup state"); goto out; } /* * Currently writable snapshots are not supported. * To prevent the final commit (which requires to write to snapshots), * ATTR_NO_AUTORECOVERY and ATTR_TRANSPORTABLE are specified here. */ ctx = VSS_CTX_APP_ROLLBACK | VSS_VOLSNAP_ATTR_TRANSPORTABLE | VSS_VOLSNAP_ATTR_NO_AUTORECOVERY | VSS_VOLSNAP_ATTR_TXF_RECOVERY; hr = vss_ctx.pVssbc->SetContext(ctx); if (hr == (HRESULT)VSS_E_UNSUPPORTED_CONTEXT) { /* Non-server version of Windows doesn't support ATTR_TRANSPORTABLE */ ctx &= ~VSS_VOLSNAP_ATTR_TRANSPORTABLE; hr = vss_ctx.pVssbc->SetContext(ctx); } if (FAILED(hr)) { err_set(errset, hr, "failed to set backup context"); goto out; } hr = vss_ctx.pVssbc->GatherWriterMetadata(pAsync.replace()); if (SUCCEEDED(hr)) { hr = WaitForAsync(pAsync); } if (FAILED(hr)) { err_set(errset, hr, "failed to gather writer metadata"); goto out; } AddComponents(errset); if (err_is_set(errset)) { goto out; } hr = vss_ctx.pVssbc->StartSnapshotSet(&guidSnapshotSet); if (FAILED(hr)) { err_set(errset, hr, "failed to start snapshot set"); goto out; } if (mountpoints) { PWCHAR volume_name_wchar; for (volList *list = (volList *)mountpoints; list; list = list->next) { size_t len = strlen(list->value) + 1; size_t converted = 0; VSS_ID pid; volume_name_wchar = new wchar_t[len]; mbstowcs_s(&converted, volume_name_wchar, len, list->value, _TRUNCATE); hr = vss_ctx.pVssbc->AddToSnapshotSet(volume_name_wchar, g_gProviderId, &pid); if (FAILED(hr)) { err_set(errset, hr, "failed to add %S to snapshot set", volume_name_wchar); delete volume_name_wchar; goto out; } num_mount_points++; delete volume_name_wchar; } if (num_mount_points == 0) { /* If there is no valid mount points, just exit. */ goto out; } } if (!mountpoints) { volume = FindFirstVolumeW(short_volume_name, sizeof(short_volume_name)); if (volume == INVALID_HANDLE_VALUE) { err_set(errset, hr, "failed to find first volume"); goto out; } for (;;) { if (GetDriveTypeW(short_volume_name) == DRIVE_FIXED) { VSS_ID pid; hr = vss_ctx.pVssbc->AddToSnapshotSet(short_volume_name, g_gProviderId, &pid); if (FAILED(hr)) { WCHAR volume_path_name[PATH_MAX]; if (GetVolumePathNamesForVolumeNameW( short_volume_name, volume_path_name, sizeof(volume_path_name), NULL) && *volume_path_name) { display_name = volume_path_name; } err_set(errset, hr, "failed to add %S to snapshot set", display_name); FindVolumeClose(volume); goto out; } num_fixed_drives++; } if (!FindNextVolumeW(volume, short_volume_name, sizeof(short_volume_name))) { FindVolumeClose(volume); break; } } if (num_fixed_drives == 0) { goto out; /* If there is no fixed drive, just exit. */ } } hr = vss_ctx.pVssbc->PrepareForBackup(pAsync.replace()); if (SUCCEEDED(hr)) { hr = WaitForAsync(pAsync); } if (FAILED(hr)) { err_set(errset, hr, "failed to prepare for backup"); goto out; } hr = vss_ctx.pVssbc->GatherWriterStatus(pAsync.replace()); if (SUCCEEDED(hr)) { hr = WaitForAsync(pAsync); } if (FAILED(hr)) { err_set(errset, hr, "failed to gather writer status"); goto out; } /* * Start VSS quiescing operations. * CQGAVssProvider::CommitSnapshots will kick vss_ctx.hEventFrozen * after the applications and filesystems are frozen. */ hr = vss_ctx.pVssbc->DoSnapshotSet(&vss_ctx.pAsyncSnapshot); if (FAILED(hr)) { err_set(errset, hr, "failed to do snapshot set"); goto out; } /* Need to call QueryStatus several times to make VSS provider progress */ for (i = 0; i < VSS_TIMEOUT_FREEZE_MSEC/VSS_TIMEOUT_EVENT_MSEC; i++) { HRESULT hr2 = vss_ctx.pAsyncSnapshot->QueryStatus(&hr, NULL); if (FAILED(hr2)) { err_set(errset, hr, "failed to do snapshot set"); goto out; } if (hr != VSS_S_ASYNC_PENDING) { err_set(errset, E_FAIL, "DoSnapshotSet exited without Frozen event"); goto out; } wait_status = WaitForSingleObject(vss_ctx.hEventFrozen, VSS_TIMEOUT_EVENT_MSEC); if (wait_status != WAIT_TIMEOUT) { break; } } if (wait_status == WAIT_TIMEOUT) { err_set(errset, E_FAIL, "timeout when try to receive Frozen event from VSS provider"); /* If we are here, VSS had timeout. * Don't call AbortBackup, just return directly. */ goto out1; } if (wait_status != WAIT_OBJECT_0) { err_set(errset, E_FAIL, "couldn't receive Frozen event from VSS provider"); goto out; } if (mountpoints) { *num_vols = vss_ctx.cFrozenVols = num_mount_points; } else { *num_vols = vss_ctx.cFrozenVols = num_fixed_drives; } return; out: if (vss_ctx.pVssbc) { vss_ctx.pVssbc->AbortBackup(); } out1: requester_cleanup(); CoUninitialize(); }
static void AddComponents(ErrorSet *errset) { unsigned int cWriters, i; VSS_ID id, idInstance, idWriter; BSTR bstrWriterName = NULL; VSS_USAGE_TYPE usage; VSS_SOURCE_TYPE source; unsigned int cComponents, c1, c2, j; COMPointer<IVssExamineWriterMetadata> pMetadata; COMPointer<IVssWMComponent> pComponent; PVSSCOMPONENTINFO info; HRESULT hr; hr = vss_ctx.pVssbc->GetWriterMetadataCount(&cWriters); if (FAILED(hr)) { err_set(errset, hr, "failed to get writer metadata count"); goto out; } for (i = 0; i < cWriters; i++) { hr = vss_ctx.pVssbc->GetWriterMetadata(i, &id, pMetadata.replace()); if (FAILED(hr)) { err_set(errset, hr, "failed to get writer metadata of %d/%d", i, cWriters); goto out; } hr = pMetadata->GetIdentity(&idInstance, &idWriter, &bstrWriterName, &usage, &source); if (FAILED(hr)) { err_set(errset, hr, "failed to get identity of writer %d/%d", i, cWriters); goto out; } hr = pMetadata->GetFileCounts(&c1, &c2, &cComponents); if (FAILED(hr)) { err_set(errset, hr, "failed to get file counts of %S", bstrWriterName); goto out; } for (j = 0; j < cComponents; j++) { hr = pMetadata->GetComponent(j, pComponent.replace()); if (FAILED(hr)) { err_set(errset, hr, "failed to get component %d/%d of %S", j, cComponents, bstrWriterName); goto out; } hr = pComponent->GetComponentInfo(&info); if (FAILED(hr)) { err_set(errset, hr, "failed to get component info %d/%d of %S", j, cComponents, bstrWriterName); goto out; } if (info->bSelectable) { hr = vss_ctx.pVssbc->AddComponent(idInstance, idWriter, info->type, info->bstrLogicalPath, info->bstrComponentName); if (FAILED(hr)) { err_set(errset, hr, "failed to add component %S(%S)", info->bstrComponentName, bstrWriterName); goto out; } } SysFreeString(bstrWriterName); bstrWriterName = NULL; pComponent->FreeComponentInfo(info); info = NULL; } } out: if (bstrWriterName) { SysFreeString(bstrWriterName); } if (pComponent && info) { pComponent->FreeComponentInfo(info); } }