Skip to content
Snippets Groups Projects
Commit b6807042 authored by George Nachman's avatar George Nachman
Browse files

Prevent statfs from hanging the app for more than half a second in the face of...

Prevent statfs from hanging the app for more than half a second in the face of broken network filesystems. Issue 6110
parent 87dff6eb
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -37,7 +37,8 @@
 
// Returns YES if the file exists on a local (non-network) filesystem.
- (BOOL)fileExistsAtPathLocally:(NSString *)filename
additionalNetworkPaths:(NSArray<NSString *> *)additionalNetworkpaths;
additionalNetworkPaths:(NSArray<NSString *> *)additionalNetworkpaths
timedOut:(BOOL *)timedOut;
 
- (BOOL)fileHasForbiddenPrefix:(NSString *)filename
additionalNetworkPaths:(NSArray<NSString *> *)additionalNetworkpaths;
Loading
Loading
Loading
Loading
@@ -227,17 +227,46 @@ NSString * const DirectoryLocationDomain = @"DirectoryLocationDomain";
}
 
- (BOOL)fileExistsAtPathLocally:(NSString *)filename
additionalNetworkPaths:(NSArray<NSString *> *)additionalNetworkPaths {
additionalNetworkPaths:(NSArray<NSString *> *)additionalNetworkPaths
timedOut:(BOOL *)timedOutPtr {
if ([self fileHasForbiddenPrefix:filename additionalNetworkPaths:additionalNetworkPaths]) {
return NO;
}
struct statfs buf;
int rc = statfs([filename UTF8String], &buf);
if (rc != 0 || (buf.f_flags & MNT_LOCAL)) {
return [self fileExistsAtPath:filename];
} else {
return NO;
static dispatch_queue_t statfsQueue;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
statfsQueue = dispatch_queue_create("com.iterm2.statfs", NULL);
});
// Do statfs in a background thread because it can hang when you're using certain network file systems.
__block BOOL ok = NO;
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
[filename retain];
dispatch_async(statfsQueue, ^{
struct statfs buf;
int rc = statfs([filename UTF8String], &buf);
if (rc != 0 || (buf.f_flags & MNT_LOCAL)) {
ok = [self fileExistsAtPath:filename];
} else {
ok = NO;
}
[filename release];
dispatch_group_leave(group);
});
// Wait up to half a second for the statfs to finish.
long timedOut = dispatch_group_wait(group,
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)));
dispatch_release(group);
if (timedOutPtr) {
*timedOutPtr = !!timedOut;
}
if (timedOut) {
DLog(@"Timed out doing statfs on %@", filename);
}
return timedOut ? NO : ok;
}
 
@end
Loading
Loading
@@ -48,7 +48,8 @@ extern NSString *const kSemanticHistoryWorkingDirectorySubstitutionKey;
- (NSString *)getFullPath:(NSString *)path
workingDirectory:(NSString *)workingDirectory
lineNumber:(NSString **)lineNumber
columnNumber:(NSString **)columnNumber;
columnNumber:(NSString **)columnNumber
timedOut:(BOOL *)timedOut;
 
// Opens the file at the relative |path| (which may include :lineNumber) in |workingDirectory|.
// The |substitutions| dictionary is used to expand \references in the command to run (gotten from
Loading
Loading
Loading
Loading
@@ -43,9 +43,10 @@ NSString *const kSemanticHistoryWorkingDirectorySubstitutionKey = @"semanticHist
@synthesize prefs = prefs_;
@synthesize delegate = delegate_;
 
- (BOOL)fileExistsAtPathLocally:(NSString *)path {
- (BOOL)fileExistsAtPathLocally:(NSString *)path timedOut:(BOOL *)timedOut {
return [self.fileManager fileExistsAtPathLocally:path
additionalNetworkPaths:[[iTermAdvancedSettingsModel pathsToIgnore] componentsSeparatedByString:@","]];
additionalNetworkPaths:[[iTermAdvancedSettingsModel pathsToIgnore] componentsSeparatedByString:@","]
timedOut:timedOut];
}
 
- (BOOL)fileHasForbiddenPrefix:(NSString *)path {
Loading
Loading
@@ -56,7 +57,8 @@ NSString *const kSemanticHistoryWorkingDirectorySubstitutionKey = @"semanticHist
- (NSString *)getFullPath:(NSString *)path
workingDirectory:(NSString *)workingDirectory
lineNumber:(NSString **)lineNumber
columnNumber:(NSString **)columnNumber {
columnNumber:(NSString **)columnNumber
timedOut:(BOOL *)timedOut {
DLog(@"Check if %@ is a valid path in %@", path, workingDirectory);
NSString *origPath = path;
// TODO(chendo): Move regex, define capture semantics in config file/prefs
Loading
Loading
@@ -104,7 +106,7 @@ NSString *const kSemanticHistoryWorkingDirectorySubstitutionKey = @"semanticHist
// be stat()ed, although they were always stat()ed because of unintentional
// disk access in the old code.
 
if ([self fileExistsAtPathLocally:path]) {
if ([self fileExistsAtPathLocally:path timedOut:timedOut]) {
DLog(@" YES: A file exists at %@", path);
NSURL *url = [NSURL fileURLWithPath:path];
 
Loading
Loading
@@ -117,6 +119,9 @@ NSString *const kSemanticHistoryWorkingDirectorySubstitutionKey = @"semanticHist
return nil;
}
return path;
} else if (*timedOut) {
DLog(@" NO: timed out");
return nil;
}
 
// If path doesn't exist and it starts with "a/" or "b/" (from `diff`).
Loading
Loading
@@ -130,7 +135,8 @@ NSString *const kSemanticHistoryWorkingDirectorySubstitutionKey = @"semanticHist
return [self getFullPath:origPath
workingDirectory:workingDirectory
lineNumber:lineNumber
columnNumber:columnNumber];
columnNumber:columnNumber
timedOut:timedOut];
}
 
DLog(@" NO: no valid path found");
Loading
Loading
@@ -331,7 +337,11 @@ NSString *const kSemanticHistoryWorkingDirectorySubstitutionKey = @"semanticHist
 
BOOL isRawAction = [prefs_[kSemanticHistoryActionKey] isEqualToString:kSemanticHistoryRawCommandAction];
if (!isRawAction) {
path = [self getFullPath:path workingDirectory:workingDirectory lineNumber:&lineNumber columnNumber:&columnNumber];
BOOL timedOut;
path = [self getFullPath:path workingDirectory:workingDirectory
lineNumber:&lineNumber
columnNumber:&columnNumber
timedOut:&timedOut];
DLog(@"Not a raw action. New path is %@, line number is %@", path, lineNumber);
}
 
Loading
Loading
@@ -444,7 +454,8 @@ NSString *const kSemanticHistoryWorkingDirectorySubstitutionKey = @"semanticHist
charsTakenFromPrefix:(int *)charsTakenFromPrefixPtr
charsTakenFromSuffix:(int *)suffixChars
trimWhitespace:(BOOL)trimWhitespace {
BOOL workingDirectoryIsOk = [self fileExistsAtPathLocally:workingDirectory];
BOOL timedOut;
BOOL workingDirectoryIsOk = [self fileExistsAtPathLocally:workingDirectory timedOut:&timedOut];
if (!workingDirectoryIsOk) {
DLog(@"Working directory %@ is a network share or doesn't exist. Not using it for context.",
workingDirectory);
Loading
Loading
@@ -507,7 +518,16 @@ NSString *const kSemanticHistoryWorkingDirectorySubstitutionKey = @"semanticHist
for (NSString *modifiedPossiblePath in [self pathsFromPath:trimmedPath byRemovingBadSuffixes:questionableSuffixes]) {
BOOL exists = NO;
if (workingDirectoryIsOk || [modifiedPossiblePath hasPrefix:@"/"]) {
exists = ([self getFullPath:modifiedPossiblePath workingDirectory:workingDirectory lineNumber:NULL columnNumber:NULL] != nil);
BOOL timedOut = NO;
exists = ([self getFullPath:modifiedPossiblePath
workingDirectory:workingDirectory
lineNumber:NULL
columnNumber:NULL
timedOut:&timedOut] != nil);
if (timedOut) {
DLog(@"Timed out checking path %@ in %@", modifiedPossiblePath, workingDirectory);
return nil;
}
}
if (exists) {
if (charsTakenFromPrefixPtr) {
Loading
Loading
Loading
Loading
@@ -196,10 +196,12 @@
range.columnWindow = extractor.logicalWindow;
action.range = range;
 
BOOL timedOut;
action.fullPath = [semanticHistoryController getFullPath:filename
workingDirectory:workingDirectory
lineNumber:NULL
columnNumber:NULL];
columnNumber:NULL
timedOut:&timedOut];
action.workingDirectory = workingDirectory;
return action;
}
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment