Left: | ||
Right: |
OLD | NEW |
---|---|
1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
2 """ZIP-based storage. | 2 """ZIP-based storage. |
3 | 3 |
4 The ZIP-based storage can be described as a collection of storage files | 4 The ZIP-based storage can be described as a collection of storage files |
5 (named streams) bundled in a single ZIP archive file. | 5 (named streams) bundled in a single ZIP archive file. |
6 | 6 |
7 There are multiple types of streams: | 7 There are multiple types of streams: |
8 * error_data.# | 8 * error_data.# |
9 The error data streams contain the serialized error objects. | 9 The error data streams contain the serialized error objects. |
10 * error_index.# | 10 * error_index.# |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
111 event tag objects. | 111 event tag objects. |
112 * plaso_timestamps.# | 112 * plaso_timestamps.# |
113 The event timestamps streams contain the timestamp of the serialized | 113 The event timestamps streams contain the timestamp of the serialized |
114 events. | 114 events. |
115 """ | 115 """ |
116 | 116 |
117 import heapq | 117 import heapq |
118 import io | 118 import io |
119 import logging | 119 import logging |
120 import os | 120 import os |
121 import shutil | |
122 import tempfile | 121 import tempfile |
123 import time | 122 import time |
124 import warnings | 123 import warnings |
125 import zipfile | 124 import zipfile |
126 | 125 |
127 try: | 126 try: |
128 import ConfigParser as configparser | 127 import ConfigParser as configparser |
129 except ImportError: | 128 except ImportError: |
130 import configparser # pylint: disable=import-error | 129 import configparser # pylint: disable=import-error |
131 | 130 |
(...skipping 640 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
772 storage_metadata.storage_type = self._GetConfigValue( | 771 storage_metadata.storage_type = self._GetConfigValue( |
773 config_parser, section_name, u'storage_type') | 772 config_parser, section_name, u'storage_type') |
774 | 773 |
775 if not storage_metadata.storage_type: | 774 if not storage_metadata.storage_type: |
776 storage_metadata.storage_type = definitions.STORAGE_TYPE_SESSION | 775 storage_metadata.storage_type = definitions.STORAGE_TYPE_SESSION |
777 | 776 |
778 return storage_metadata | 777 return storage_metadata |
779 | 778 |
780 | 779 |
781 class ZIPStorageFile(interface.BaseFileStorage): | 780 class ZIPStorageFile(interface.BaseFileStorage): |
782 """Class that defines the ZIP-based storage file. | 781 """ZIP-based storage file. |
783 | 782 |
784 Attributes: | 783 Attributes: |
785 format_version (int): storage format version. | 784 format_version (int): storage format version. |
786 serialization_format (str): serialization format. | 785 serialization_format (str): serialization format. |
787 storage_type (str): storage type. | 786 storage_type (str): storage type. |
788 """ | 787 """ |
789 | 788 |
790 NEXT_AVAILABLE_ENTRY = -1 | 789 NEXT_AVAILABLE_ENTRY = -1 |
791 | 790 |
792 # The format version. | 791 # The format version. |
(...skipping 2042 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2835 """Initializes a storage reader. | 2834 """Initializes a storage reader. |
2836 | 2835 |
2837 Args: | 2836 Args: |
2838 path (str): path to the input file. | 2837 path (str): path to the input file. |
2839 """ | 2838 """ |
2840 super(ZIPStorageFileReader, self).__init__(path) | 2839 super(ZIPStorageFileReader, self).__init__(path) |
2841 self._storage_file = ZIPStorageFile() | 2840 self._storage_file = ZIPStorageFile() |
2842 self._storage_file.Open(path=path) | 2841 self._storage_file.Open(path=path) |
2843 | 2842 |
2844 | 2843 |
2845 class ZIPStorageFileWriter(interface.StorageWriter): | 2844 class ZIPStorageFileWriter(interface.FileStorageWriter): |
2846 """Class that implements the ZIP-based storage file writer.""" | 2845 """Class that implements the ZIP-based storage file writer.""" |
2847 | 2846 |
2848 def __init__( | 2847 def __init__( |
2849 self, session, output_file, buffer_size=0, | 2848 self, session, output_file, buffer_size=0, |
2850 storage_type=definitions.STORAGE_TYPE_SESSION, task=None): | 2849 storage_type=definitions.STORAGE_TYPE_SESSION, task=None): |
2851 """Initializes a storage writer. | 2850 """Initializes a storage writer. |
2852 | 2851 |
2853 Args: | 2852 Args: |
2854 session (Session): session the storage changes are part of. | 2853 session (Session): session the storage changes are part of. |
2855 output_file (str): path to the output file. | 2854 output_file (str): path to the output file. |
2856 buffer_size (Optional[int]): estimated size of a protobuf file. | 2855 buffer_size (Optional[int]): estimated size of a protobuf file. |
2857 storage_type (Optional[str]): storage type. | 2856 storage_type (Optional[str]): storage type. |
2858 task(Optional[Task]): task. | 2857 task(Optional[Task]): task. |
2859 """ | 2858 """ |
2860 super(ZIPStorageFileWriter, self).__init__( | 2859 super(ZIPStorageFileWriter, self).__init__( |
2861 session, storage_type=storage_type, task=task) | 2860 session, output_file, storage_type=storage_type, task=task) |
2862 self._buffer_size = buffer_size | 2861 self._buffer_size = buffer_size |
2863 self._merge_task_storage_path = u'' | |
2864 self._output_file = output_file | |
2865 self._storage_file = None | |
2866 self._serializers_profiler = None | |
2867 self._task_storage_path = None | |
2868 | 2862 |
2869 def _UpdateCounters(self, event): | 2863 def _CreateStorageFile(self): |
2870 """Updates the counters. | 2864 """Creates a storage file. |
2865 | |
2866 Returns: | |
2867 BaseFileStorage: storage file. | |
2868 """ | |
2869 if self._storage_type == definitions.STORAGE_TYPE_TASK: | |
2870 return gzip_file.GZIPStorageFile(storage_type=self._storage_type) | |
2871 | |
2872 return ZIPStorageFile( | |
2873 maximum_buffer_size=self._buffer_size, | |
2874 storage_type=self._storage_type) | |
2875 | |
2876 def _CreateTaskStorageMergeReader(self, path): | |
2877 """Creates a task storage merge reader. | |
2871 | 2878 |
2872 Args: | 2879 Args: |
2873 event: an event (instance of EventObject). | 2880 path (str): path of the task storage file that should be merged. |
onager
2017/03/29 12:52:03
-of +to
Joachim Metz
2017/04/08 18:11:31
Done.
| |
2881 | |
2882 Returns: | |
2883 StorageMergeReader: storage merge reader. | |
2874 """ | 2884 """ |
2875 self._session.parsers_counter[u'total'] += 1 | 2885 return gzip_file.GZIPStorageMergeReader(self, path) |
2876 | 2886 |
2877 # Here we want the name of the parser or plugin not the parser chain. | 2887 def _CreateTaskStorageWriter(self, path, task): |
2878 parser_name = getattr(event, u'parser', u'') | 2888 """Creates a task storage writer. |
2879 _, _, parser_name = parser_name.rpartition(u'/') | |
2880 if not parser_name: | |
2881 parser_name = u'N/A' | |
2882 self._session.parsers_counter[parser_name] += 1 | |
2883 | |
2884 def AddAnalysisReport(self, analysis_report): | |
2885 """Adds an analysis report. | |
2886 | 2889 |
2887 Args: | 2890 Args: |
2888 analysis_report: an analysis report object (instance of AnalysisReport). | 2891 path (str): path of the storage file. |
onager
2017/03/29 12:52:03
-of +to
Joachim Metz
2017/04/08 18:11:31
Done.
| |
2889 | |
2890 Raises: | |
2891 IOError: when the storage writer is closed. | |
2892 """ | |
2893 if not self._storage_file: | |
2894 raise IOError(u'Unable to write to closed storage writer.') | |
2895 | |
2896 self._storage_file.AddAnalysisReport(analysis_report) | |
2897 | |
2898 report_identifier = analysis_report.plugin_name | |
2899 self._session.analysis_reports_counter[u'total'] += 1 | |
2900 self._session.analysis_reports_counter[report_identifier] += 1 | |
2901 self.number_of_analysis_reports += 1 | |
2902 | |
2903 def AddError(self, error): | |
2904 """Adds an error. | |
2905 | |
2906 Args: | |
2907 error: an error object (instance of AnalysisError or ExtractionError). | |
2908 | |
2909 Raises: | |
2910 IOError: when the storage writer is closed. | |
2911 """ | |
2912 if not self._storage_file: | |
2913 raise IOError(u'Unable to write to closed storage writer.') | |
2914 | |
2915 self._storage_file.AddError(error) | |
2916 self.number_of_errors += 1 | |
2917 | |
2918 def AddEvent(self, event): | |
2919 """Adds an event. | |
2920 | |
2921 Args: | |
2922 event: an event (instance of EventObject). | |
2923 | |
2924 Raises: | |
2925 IOError: when the storage writer is closed. | |
2926 """ | |
2927 if not self._storage_file: | |
2928 raise IOError(u'Unable to write to closed storage writer.') | |
2929 | |
2930 self._storage_file.AddEvent(event) | |
2931 self.number_of_events += 1 | |
2932 | |
2933 self._UpdateCounters(event) | |
2934 | |
2935 def AddEventSource(self, event_source): | |
2936 """Adds an event source. | |
2937 | |
2938 Args: | |
2939 event_source: an event source object (instance of EventSource). | |
2940 | |
2941 Raises: | |
2942 IOError: when the storage writer is closed. | |
2943 """ | |
2944 if not self._storage_file: | |
2945 raise IOError(u'Unable to write to closed storage writer.') | |
2946 | |
2947 self._storage_file.AddEventSource(event_source) | |
2948 self.number_of_event_sources += 1 | |
2949 | |
2950 def AddEventTag(self, event_tag): | |
2951 """Adds an event tag. | |
2952 | |
2953 Args: | |
2954 event_tag: an event tag object (instance of EventTag). | |
2955 | |
2956 Raises: | |
2957 IOError: when the storage writer is closed. | |
2958 """ | |
2959 if not self._storage_file: | |
2960 raise IOError(u'Unable to write to closed storage writer.') | |
2961 | |
2962 self._storage_file.AddEventTag(event_tag) | |
2963 | |
2964 self._session.event_labels_counter[u'total'] += 1 | |
2965 for label in event_tag.labels: | |
2966 self._session.event_labels_counter[label] += 1 | |
2967 self.number_of_event_tags += 1 | |
2968 | |
2969 def CheckTaskReadyForMerge(self, task): | |
2970 """Checks if a task is ready for merging with this session storage. | |
2971 | |
2972 Args: | |
2973 task (Task): task. | 2892 task (Task): task. |
2974 | 2893 |
2975 Returns: | 2894 Returns: |
2976 bool: True if the task is ready to be merged. | 2895 StorageWriter: storage writer. |
2977 | |
2978 Raises: | |
2979 IOError: if the storage type is not supported or | |
2980 if the temporary path for the task storage does not exist. | |
2981 """ | 2896 """ |
2982 if self._storage_type != definitions.STORAGE_TYPE_SESSION: | |
2983 raise IOError(u'Unsupported storage type.') | |
2984 | |
2985 if not self._merge_task_storage_path: | |
2986 raise IOError(u'Missing merge task storage path.') | |
2987 | |
2988 storage_file_path = os.path.join( | |
2989 self._merge_task_storage_path, u'{0:s}.plaso'.format(task.identifier)) | |
2990 | |
2991 try: | |
2992 stat_info = os.stat(storage_file_path) | |
2993 except (IOError, OSError): | |
2994 return False | |
2995 | |
2996 task.storage_file_size = stat_info.st_size | |
2997 return True | |
2998 | |
2999 def Close(self): | |
3000 """Closes the storage writer. | |
3001 | |
3002 Raises: | |
3003 IOError: when the storage writer is closed. | |
3004 """ | |
3005 if not self._storage_file: | |
3006 raise IOError(u'Unable to write to closed storage writer.') | |
3007 | |
3008 self._storage_file.Close() | |
3009 self._storage_file = None | |
3010 | |
3011 def CreateTaskStorage(self, task): | |
3012 """Creates a task storage. | |
3013 | |
3014 The task storage is used to store attributes created by the task. | |
3015 | |
3016 Args: | |
3017 task(Task): task. | |
3018 | |
3019 Returns: | |
3020 StorageWriter: storage writer. | |
3021 | |
3022 Raises: | |
3023 IOError: if the storage type is not supported or | |
3024 if the temporary path for the task storage does not exist. | |
3025 """ | |
3026 if self._storage_type != definitions.STORAGE_TYPE_SESSION: | |
3027 raise IOError(u'Unsupported storage type.') | |
3028 | |
3029 if not self._task_storage_path: | |
3030 raise IOError(u'Missing task storage path.') | |
3031 | |
3032 storage_file_path = os.path.join( | |
3033 self._task_storage_path, u'{0:s}.plaso'.format(task.identifier)) | |
3034 | |
3035 return ZIPStorageFileWriter( | 2897 return ZIPStorageFileWriter( |
3036 self._session, storage_file_path, buffer_size=self._buffer_size, | 2898 self._session, path, buffer_size=self._buffer_size, |
3037 storage_type=definitions.STORAGE_TYPE_TASK, task=task) | 2899 storage_type=definitions.STORAGE_TYPE_TASK, task=task) |
3038 | |
3039 def GetEvents(self, time_range=None): | |
3040 """Retrieves the events in increasing chronological order. | |
3041 | |
3042 Args: | |
3043 time_range (Optional[TimeRange]): time range used to filter events | |
3044 that fall in a specific period. | |
3045 | |
3046 Returns: | |
3047 generator(EventObject): event generator. | |
3048 | |
3049 Raises: | |
3050 IOError: when the storage writer is closed. | |
3051 """ | |
3052 if not self._storage_file: | |
3053 raise IOError(u'Unable to read from closed storage writer.') | |
3054 | |
3055 return self._storage_file.GetEvents(time_range=time_range) | |
3056 | |
3057 def GetFirstWrittenEventSource(self): | |
3058 """Retrieves the first event source that was written after open. | |
3059 | |
3060 Using GetFirstWrittenEventSource and GetNextWrittenEventSource newly | |
3061 added event sources can be retrieved in order of addition. | |
3062 | |
3063 Returns: | |
3064 EventSource: event source or None if there are no newly written ones. | |
3065 | |
3066 Raises: | |
3067 IOError: when the storage writer is closed. | |
3068 """ | |
3069 if not self._storage_file: | |
3070 raise IOError(u'Unable to read from closed storage writer.') | |
3071 | |
3072 event_source = self._storage_file.GetEventSourceByIndex( | |
3073 self._first_written_event_source_index) | |
3074 | |
3075 if event_source: | |
3076 self._written_event_source_index = ( | |
3077 self._first_written_event_source_index + 1) | |
3078 return event_source | |
3079 | |
3080 def GetNextWrittenEventSource(self): | |
3081 """Retrieves the next event source that was written after open. | |
3082 | |
3083 Returns: | |
3084 EventSource: event source or None if there are no newly written ones. | |
3085 | |
3086 Raises: | |
3087 IOError: when the storage writer is closed. | |
3088 """ | |
3089 if not self._storage_file: | |
3090 raise IOError(u'Unable to read from closed storage writer.') | |
3091 | |
3092 event_source = self._storage_file.GetEventSourceByIndex( | |
3093 self._written_event_source_index) | |
3094 if event_source: | |
3095 self._written_event_source_index += 1 | |
3096 return event_source | |
3097 | |
3098 def Open(self): | |
3099 """Opens the storage writer. | |
3100 | |
3101 Raises: | |
3102 IOError: if the storage writer is already opened. | |
3103 """ | |
3104 if self._storage_file: | |
3105 raise IOError(u'Storage writer already opened.') | |
3106 | |
3107 if self._storage_type == definitions.STORAGE_TYPE_TASK: | |
3108 self._storage_file = gzip_file.GZIPStorageFile( | |
3109 storage_type=self._storage_type) | |
3110 else: | |
3111 self._storage_file = ZIPStorageFile( | |
3112 maximum_buffer_size=self._buffer_size, | |
3113 storage_type=self._storage_type) | |
3114 | |
3115 if self._serializers_profiler: | |
3116 self._storage_file.SetSerializersProfiler(self._serializers_profiler) | |
3117 | |
3118 self._storage_file.Open(path=self._output_file, read_only=False) | |
3119 | |
3120 self._first_written_event_source_index = ( | |
3121 self._storage_file.GetNumberOfEventSources()) | |
3122 self._written_event_source_index = self._first_written_event_source_index | |
3123 | |
3124 def PrepareMergeTaskStorage(self, task): | |
3125 """Prepares a task storage for merging. | |
3126 | |
3127 Args: | |
3128 task (Task): unique identifier of the task. | |
3129 | |
3130 Raises: | |
3131 IOError: if the storage type is not supported or | |
3132 if the temporary path for the task storage does not exist. | |
3133 """ | |
3134 if self._storage_type != definitions.STORAGE_TYPE_SESSION: | |
3135 raise IOError(u'Unsupported storage type.') | |
3136 | |
3137 if not self._task_storage_path: | |
3138 raise IOError(u'Missing task storage path.') | |
3139 | |
3140 storage_file_path = os.path.join( | |
3141 self._task_storage_path, u'{0:s}.plaso'.format(task.identifier)) | |
3142 | |
3143 merge_storage_file_path = os.path.join( | |
3144 self._merge_task_storage_path, u'{0:s}.plaso'.format(task.identifier)) | |
3145 | |
3146 try: | |
3147 os.rename(storage_file_path, merge_storage_file_path) | |
3148 except OSError as exception: | |
3149 raise IOError(( | |
3150 u'Unable to rename task storage file: {0:s} with error: ' | |
3151 u'{1:s}').format(storage_file_path, exception)) | |
3152 | |
3153 def ReadPreprocessingInformation(self, knowledge_base): | |
3154 """Reads preprocessing information. | |
3155 | |
3156 The preprocessing information contains the system configuration which | |
3157 contains information about various system specific configuration data, | |
3158 for example the user accounts. | |
3159 | |
3160 Args: | |
3161 knowledge_base (KnowledgeBase): is used to store the preprocessing | |
3162 information. | |
3163 | |
3164 Raises: | |
3165 IOError: when the storage writer is closed. | |
3166 """ | |
3167 if not self._storage_file: | |
3168 raise IOError(u'Unable to read from closed storage writer.') | |
3169 | |
3170 return self._storage_file.ReadPreprocessingInformation(knowledge_base) | |
3171 | |
3172 def SetSerializersProfiler(self, serializers_profiler): | |
3173 """Sets the serializers profiler. | |
3174 | |
3175 Args: | |
3176 serializers_profiler (SerializersProfiler): serializers profile. | |
3177 """ | |
3178 self._serializers_profiler = serializers_profiler | |
3179 if self._storage_file: | |
3180 self._storage_file.SetSerializersProfiler(serializers_profiler) | |
3181 | |
3182 def StartMergeTaskStorage(self, task): | |
3183 """Starts a merge of a task storage with the session storage. | |
3184 | |
3185 Args: | |
3186 task (Task): task. | |
3187 | |
3188 Returns: | |
3189 StorageMergeReader: storage merge reader of the task storage. | |
3190 | |
3191 Raises: | |
3192 IOError: if the storage file cannot be opened or | |
3193 if the storage type is not supported or | |
3194 if the temporary path for the task storage does not exist or | |
3195 if the temporary path for the task storage doe not refers to a file. | |
3196 """ | |
3197 if self._storage_type != definitions.STORAGE_TYPE_SESSION: | |
3198 raise IOError(u'Unsupported storage type.') | |
3199 | |
3200 if not self._merge_task_storage_path: | |
3201 raise IOError(u'Missing merge task storage path.') | |
3202 | |
3203 storage_file_path = os.path.join( | |
3204 self._merge_task_storage_path, u'{0:s}.plaso'.format(task.identifier)) | |
3205 | |
3206 if not os.path.isfile(storage_file_path): | |
3207 raise IOError(u'Merge task storage path is not a file.') | |
3208 | |
3209 return gzip_file.GZIPStorageMergeReader(self, storage_file_path) | |
3210 | |
3211 def StartTaskStorage(self): | |
3212 """Creates a temporary path for the task storage. | |
3213 | |
3214 Raises: | |
3215 IOError: if the storage type is not supported or | |
3216 if the temporary path for the task storage already exists. | |
3217 """ | |
3218 if self._storage_type != definitions.STORAGE_TYPE_SESSION: | |
3219 raise IOError(u'Unsupported storage type.') | |
3220 | |
3221 if self._task_storage_path: | |
3222 raise IOError(u'Task storage path already exists.') | |
3223 | |
3224 output_directory = os.path.dirname(self._output_file) | |
3225 self._task_storage_path = tempfile.mkdtemp(dir=output_directory) | |
3226 | |
3227 self._merge_task_storage_path = os.path.join( | |
3228 self._task_storage_path, u'merge') | |
3229 os.mkdir(self._merge_task_storage_path) | |
3230 | |
3231 def StopTaskStorage(self, abort=False): | |
3232 """Removes the temporary path for the task storage. | |
3233 | |
3234 Args: | |
3235 abort (bool): True to indicated the stop is issued on abort. | |
3236 | |
3237 Raises: | |
3238 IOError: if the storage type is not supported or | |
3239 if the temporary path for the task storage does not exist. | |
3240 """ | |
3241 if self._storage_type != definitions.STORAGE_TYPE_SESSION: | |
3242 raise IOError(u'Unsupported storage type.') | |
3243 | |
3244 if not self._task_storage_path: | |
3245 raise IOError(u'Missing task storage path.') | |
3246 | |
3247 if os.path.isdir(self._merge_task_storage_path): | |
3248 if abort: | |
3249 shutil.rmtree(self._merge_task_storage_path) | |
3250 else: | |
3251 os.rmdir(self._merge_task_storage_path) | |
3252 | |
3253 if os.path.isdir(self._task_storage_path): | |
3254 if abort: | |
3255 shutil.rmtree(self._task_storage_path) | |
3256 else: | |
3257 os.rmdir(self._task_storage_path) | |
3258 | |
3259 self._merge_task_storage_path = None | |
3260 self._task_storage_path = None | |
3261 | |
3262 def WritePreprocessingInformation(self, knowledge_base): | |
3263 """Writes preprocessing information. | |
3264 | |
3265 Args: | |
3266 knowledge_base (KnowledgeBase): contains the preprocessing information. | |
3267 | |
3268 Raises: | |
3269 IOError: if the storage type does not support writing preprocessing | |
3270 information or when the storage writer is closed. | |
3271 """ | |
3272 if not self._storage_file: | |
3273 raise IOError(u'Unable to write to closed storage writer.') | |
3274 | |
3275 if self._storage_type != definitions.STORAGE_TYPE_SESSION: | |
3276 raise IOError(u'Preprocessing information not supported by storage type.') | |
3277 | |
3278 self._storage_file.WritePreprocessingInformation(knowledge_base) | |
3279 | |
3280 def WriteSessionCompletion(self, aborted=False): | |
3281 """Writes session completion information. | |
3282 | |
3283 Args: | |
3284 aborted (Optional[bool]): True if the session was aborted. | |
3285 | |
3286 Raises: | |
3287 IOError: if the storage type is not supported or | |
3288 when the storage writer is closed. | |
3289 """ | |
3290 if not self._storage_file: | |
3291 raise IOError(u'Unable to write to closed storage writer.') | |
3292 | |
3293 if self._storage_type != definitions.STORAGE_TYPE_SESSION: | |
3294 raise IOError(u'Unsupported storage type.') | |
3295 | |
3296 self._session.aborted = aborted | |
3297 session_completion = self._session.CreateSessionCompletion() | |
3298 self._storage_file.WriteSessionCompletion(session_completion) | |
3299 | |
3300 def WriteSessionStart(self): | |
3301 """Writes session start information. | |
3302 | |
3303 Raises: | |
3304 IOError: if the storage type is not supported or | |
3305 when the storage writer is closed. | |
3306 """ | |
3307 if not self._storage_file: | |
3308 raise IOError(u'Unable to write to closed storage writer.') | |
3309 | |
3310 if self._storage_type != definitions.STORAGE_TYPE_SESSION: | |
3311 raise IOError(u'Unsupported storage type.') | |
3312 | |
3313 session_start = self._session.CreateSessionStart() | |
3314 self._storage_file.WriteSessionStart(session_start) | |
3315 | |
3316 def WriteTaskCompletion(self, aborted=False): | |
3317 """Writes task completion information. | |
3318 | |
3319 Args: | |
3320 aborted (Optional[bool]): True if the session was aborted. | |
3321 | |
3322 Raises: | |
3323 IOError: if the storage type is not supported or | |
3324 when the storage writer is closed. | |
3325 """ | |
3326 if not self._storage_file: | |
3327 raise IOError(u'Unable to write to closed storage writer.') | |
3328 | |
3329 if self._storage_type != definitions.STORAGE_TYPE_TASK: | |
3330 raise IOError(u'Unsupported storage type.') | |
3331 | |
3332 self._task.aborted = aborted | |
3333 task_completion = self._task.CreateTaskCompletion() | |
3334 self._storage_file.WriteTaskCompletion(task_completion) | |
3335 | |
3336 def WriteTaskStart(self): | |
3337 """Writes task start information. | |
3338 | |
3339 Raises: | |
3340 IOError: if the storage type is not supported or | |
3341 when the storage writer is closed. | |
3342 """ | |
3343 if not self._storage_file: | |
3344 raise IOError(u'Unable to write to closed storage writer.') | |
3345 | |
3346 if self._storage_type != definitions.STORAGE_TYPE_TASK: | |
3347 raise IOError(u'Unsupported storage type.') | |
3348 | |
3349 task_start = self._task.CreateTaskStart() | |
3350 self._storage_file.WriteTaskStart(task_start) | |
OLD | NEW |