Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
// Copyright 2019 Google
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
 
15
#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h"
16
 
17
#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h"
18
#import "Crashlytics/Crashlytics/Components/FIRCLSCrashedMarkerFile.h"
19
#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h"
20
#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h"
21
 
22
NSString *const FIRCLSCacheDirectoryName = @"com.crashlytics.data";
23
NSString *const FIRCLSCacheVersion = @"v5";
24
NSString *const FIRCLSMetricKitDiagnosticPath = @"/MetricKit/Diagnostics/";
25
 
26
@interface FIRCLSFileManager () {
27
  NSString *_rootPath;
28
  NSString *_cachesPath;
29
}
30
@property(nonatomic) BOOL crashFileMarkerExists;
31
 
32
@end
33
 
34
@implementation FIRCLSFileManager
35
 
36
- (instancetype)init {
37
  self = [super init];
38
  if (!self) {
39
    return nil;
40
  }
41
 
42
  _underlyingFileManager = [NSFileManager defaultManager];
43
 
44
  NSString *path =
45
      [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
46
  _cachesPath = [path copy];
47
  path = [path stringByAppendingPathComponent:FIRCLSCacheDirectoryName];
48
  path = [path stringByAppendingPathComponent:[self pathNamespace]];
49
  _rootPath = [path copy];
50
 
51
  _crashFileMarkerExists = NO;
52
  return self;
53
}
54
 
55
#pragma mark - Core API
56
 
57
- (BOOL)fileExistsAtPath:(NSString *)path {
58
  return [_underlyingFileManager fileExistsAtPath:path];
59
}
60
 
61
- (BOOL)createFileAtPath:(NSString *)path
62
                contents:(nullable NSData *)data
63
              attributes:(nullable NSDictionary<NSFileAttributeKey, id> *)attr {
64
  return [_underlyingFileManager createFileAtPath:path contents:data attributes:attr];
65
}
66
 
67
- (BOOL)createDirectoryAtPath:(NSString *)path {
68
  NSDictionary *attributes;
69
  NSError *error;
70
 
71
  attributes = @{NSFilePosixPermissions : [NSNumber numberWithShort:0755]};
72
  error = nil;
73
 
74
  if (![[self underlyingFileManager] createDirectoryAtPath:path
75
                               withIntermediateDirectories:YES
76
                                                attributes:attributes
77
                                                     error:&error]) {
78
    FIRCLSErrorLog(@"Unable to create directory %@", error);
79
    return NO;
80
  }
81
 
82
  return YES;
83
}
84
 
85
- (BOOL)removeItemAtPath:(NSString *)path {
86
  NSError *error;
87
 
88
  error = nil;
89
  if (![[self underlyingFileManager] removeItemAtPath:path error:&error] || !path) {
90
    FIRCLSErrorLog(@"Failed to remove file %@: %@", path, error);
91
 
92
    return NO;
93
  }
94
 
95
  return YES;
96
}
97
 
98
- (BOOL)removeContentsOfDirectoryAtPath:(NSString *)path {
99
  __block BOOL success = YES;
100
 
101
  // only return true if we were able to remove every item in the directory (or it was empty)
102
 
103
  [self enumerateFilesInDirectory:path
104
                       usingBlock:^(NSString *filePath, NSString *extension) {
105
                         success = [self removeItemAtPath:filePath] && success;
106
                       }];
107
 
108
  return success;
109
}
110
 
111
- (BOOL)moveItemAtPath:(NSString *)path toDirectory:(NSString *)destDir {
112
  NSString *destPath;
113
  NSError *error;
114
 
115
  destPath = [destDir stringByAppendingPathComponent:[path lastPathComponent]];
116
  error = nil;
117
 
118
  if (!path || !destPath) {
119
    FIRCLSErrorLog(@"Failed to move file, inputs invalid");
120
 
121
    return NO;
122
  }
123
 
124
  if (![[self underlyingFileManager] moveItemAtPath:path toPath:destPath error:&error]) {
125
    FIRCLSErrorLog(@"Failed to move file: %@", error);
126
 
127
    return NO;
128
  }
129
 
130
  return YES;
131
}
132
 
133
- (BOOL)didCrashOnPreviousExecution {
134
  static dispatch_once_t checkCrashFileMarketExistsOnceToken;
135
  dispatch_once(&checkCrashFileMarketExistsOnceToken, ^{
136
    NSString *crashedMarkerFileName = [NSString stringWithUTF8String:FIRCLSCrashedMarkerFileName];
137
    NSString *crashedMarkerFileFullPath =
138
        [[self rootPath] stringByAppendingPathComponent:crashedMarkerFileName];
139
    self.crashFileMarkerExists = [self fileExistsAtPath:crashedMarkerFileFullPath];
140
  });
141
  return self.crashFileMarkerExists;
142
}
143
 
144
- (BOOL)metricKitDiagnosticFileExists {
145
  NSArray *contentsOfMetricKitDirectory = [self
146
      contentsOfDirectory:[_cachesPath stringByAppendingString:FIRCLSMetricKitDiagnosticPath]];
147
  return ([contentsOfMetricKitDirectory count] > 0);
148
}
149
 
150
- (void)createEmptyMetricKitFile:(NSString *)reportPath {
151
  NSString *metricKitFile =
152
      [reportPath stringByAppendingPathComponent:FIRCLSMetricKitFatalReportFile];
153
  [self createFileAtPath:metricKitFile contents:nil attributes:nil];
154
}
155
 
156
- (void)enumerateFilesInDirectory:(NSString *)directory
157
                       usingBlock:(void (^)(NSString *filePath, NSString *extension))block {
158
  for (NSString *path in [[self underlyingFileManager] contentsOfDirectoryAtPath:directory
159
                                                                           error:nil]) {
160
    NSString *extension;
161
    NSString *fullPath;
162
 
163
    // Skip files that start with a dot.  This is important, because if you try to move a .DS_Store
164
    // file, it will fail if the target directory also has a .DS_Store file in it.  Plus, its
165
    // wasteful, because we don't care about dot files.
166
    if ([path hasPrefix:@"."]) {
167
      continue;
168
    }
169
 
170
    extension = [path pathExtension];
171
    fullPath = [directory stringByAppendingPathComponent:path];
172
    if (block) {
173
      block(fullPath, extension);
174
    }
175
  }
176
}
177
 
178
- (NSNumber *)fileSizeAtPath:(NSString *)path {
179
  NSError *error = nil;
180
  NSDictionary *attrs = [[self underlyingFileManager] attributesOfItemAtPath:path error:&error];
181
 
182
  if (!attrs) {
183
    FIRCLSErrorLog(@"Unable to read file size: %@", error);
184
    return nil;
185
  }
186
 
187
  return [attrs objectForKey:NSFileSize];
188
}
189
 
190
- (NSArray *)contentsOfDirectory:(NSString *)path {
191
  NSMutableArray *array = [NSMutableArray array];
192
 
193
  [self enumerateFilesInDirectory:path
194
                       usingBlock:^(NSString *filePath, NSString *extension) {
195
                         [array addObject:filePath];
196
                       }];
197
 
198
  return [array copy];
199
}
200
 
201
#pragma - Properties
202
- (NSString *)pathNamespace {
203
  return FIRCLSApplicationGetBundleIdentifier();
204
}
205
 
206
- (NSString *)versionedPath {
207
  return [[self rootPath] stringByAppendingPathComponent:FIRCLSCacheVersion];
208
}
209
 
210
#pragma - Settings Paths
211
 
212
// This path should be different than the structurePath because the
213
// settings download operations will delete the settings directory,
214
// which would delete crash reports if these were the same
215
- (NSString *)settingsDirectoryPath {
216
  return [[self versionedPath] stringByAppendingPathComponent:@"settings"];
217
}
218
 
219
- (NSString *)settingsFilePath {
220
  return [[self settingsDirectoryPath] stringByAppendingPathComponent:@"settings.json"];
221
}
222
 
223
- (NSString *)settingsCacheKeyPath {
224
  return [[self settingsDirectoryPath] stringByAppendingPathComponent:@"cache-key.json"];
225
}
226
 
227
#pragma - Report Paths
228
- (NSString *)structurePath {
229
  return [[self versionedPath] stringByAppendingPathComponent:@"reports"];
230
}
231
 
232
- (NSString *)activePath {
233
  return [[self structurePath] stringByAppendingPathComponent:@"active"];
234
}
235
 
236
- (NSString *)pendingPath {
237
  return [[self structurePath] stringByAppendingPathComponent:@"pending"];
238
}
239
 
240
- (NSString *)processingPath {
241
  return [[self structurePath] stringByAppendingPathComponent:@"processing"];
242
}
243
 
244
- (NSString *)preparedPath {
245
  return [[self structurePath] stringByAppendingPathComponent:@"prepared"];
246
}
247
 
248
- (NSArray *)activePathContents {
249
  return [self contentsOfDirectory:[self activePath]];
250
}
251
 
252
- (NSArray *)preparedPathContents {
253
  return [self contentsOfDirectory:[self preparedPath]];
254
}
255
 
256
- (NSArray *)processingPathContents {
257
  return [self contentsOfDirectory:[self processingPath]];
258
}
259
 
260
#pragma mark - Logic
261
- (BOOL)createReportDirectories {
262
  if (![self createDirectoryAtPath:[self activePath]]) {
263
    return NO;
264
  }
265
 
266
  if (![self createDirectoryAtPath:[self processingPath]]) {
267
    return NO;
268
  }
269
 
270
  if (![self createDirectoryAtPath:[self preparedPath]]) {
271
    return NO;
272
  }
273
 
274
  return YES;
275
}
276
 
277
- (NSString *)setupNewPathForExecutionIdentifier:(NSString *)identifier {
278
  NSString *path = [[self activePath] stringByAppendingPathComponent:identifier];
279
 
280
  if (![self createDirectoryAtPath:path]) {
281
    return nil;
282
  }
283
 
284
  return path;
285
}
286
 
287
- (BOOL)moveItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error {
288
  return [self.underlyingFileManager moveItemAtPath:srcPath toPath:dstPath error:error];
289
}
290
 
291
// Wrapper over NSData so the method can be mocked for unit tests
292
- (NSData *)dataWithContentsOfFile:(NSString *)path {
293
  return [NSData dataWithContentsOfFile:path];
294
}
295
 
296
@end