/core/externals/update-engine/Core/Support/ksurl-main.m

http://macfuse.googlecode.com/ · Objective C · 192 lines · 104 code · 36 blank · 52 comment · 23 complexity · 712606fa3b57ba21e2e08b20beb3a517 MD5 · raw file

  1. // Copyright 2008 Google Inc.
  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. #import "KSURLNotification.h"
  15. #import <unistd.h>
  16. #import <pwd.h>
  17. #import <Foundation/Foundation.h>
  18. // We use NSLog here to avoid the dependency on non-default frameworks.
  19. // DownloadDelegate
  20. //
  21. // The delegate for NSURLDownload. It sets some internal flags when a
  22. // download finishes to indicate whether the download finished
  23. // successfully. It also accepts progress information from the
  24. // NSURLDownload and may send distributed notifications to announce progress.
  25. @interface DownloadDelegate : NSObject {
  26. @private
  27. BOOL done_;
  28. BOOL success_;
  29. NSInteger expectedSize_; // expected total size
  30. NSInteger downloadProgress_; // how far we've gotten (bytes)
  31. float lastAnnouncedProgress_; // last progress value we announced (0.0-1.0)
  32. NSString *path_; // dest path (used for notification)
  33. }
  34. // Designated initializer. |expectedSize| is the expected download size.
  35. // If expectedSize is 0, we do not send download progress.
  36. - (id)initWithSize:(NSInteger)expectedSize path:(NSString *)path;
  37. // Returns YES if the download has finished, NO otherwise.
  38. - (BOOL)isDone;
  39. // Returns YES if the download completed successfully, NO otherwise.
  40. - (BOOL)wasSuccess;
  41. @end
  42. @implementation DownloadDelegate
  43. - (id)initWithSize:(NSInteger)expectedSize path:(NSString *)path {
  44. if ((self = [super init])) {
  45. expectedSize_ = expectedSize;
  46. path_ = [path copy];
  47. }
  48. return self;
  49. }
  50. - (void)dealloc {
  51. [path_ release];
  52. [super dealloc];
  53. }
  54. - (BOOL)isDone {
  55. return done_;
  56. }
  57. - (BOOL)wasSuccess {
  58. return success_;
  59. }
  60. - (void)download:(NSURLDownload *)download didFailWithError:(NSError *)error {
  61. NSLog(@"Download (%@) failed with error - %@ %@",
  62. download, [error localizedDescription],
  63. [[error userInfo] objectForKey:NSErrorFailingURLStringKey]);
  64. done_ = YES;
  65. success_ = NO;
  66. }
  67. - (void)downloadDidFinish:(NSURLDownload *)download {
  68. done_ = YES;
  69. success_ = YES;
  70. }
  71. - (void)download:(NSURLDownload *)download didReceiveDataOfLength:(NSUInteger)length {
  72. downloadProgress_ += (NSInteger)length;
  73. // Don't announce a progress unless we have some chance of being useful.
  74. if (path_ && (expectedSize_ != 0)) {
  75. float progress = (float)downloadProgress_ / (float)expectedSize_;
  76. // Throttle progress a little.
  77. // Don't announce progress greater than 1.0.
  78. if ((progress > (lastAnnouncedProgress_ + 0.01)) &&
  79. (progress <= 1.0)) {
  80. [[NSDistributedNotificationCenter defaultCenter]
  81. postNotificationName:KSURLProgressNotification
  82. object:path_
  83. userInfo:[NSDictionary
  84. dictionaryWithObject:[NSNumber numberWithFloat:progress]
  85. forKey:KSURLProgressKey]];
  86. lastAnnouncedProgress_ = progress;
  87. }
  88. }
  89. }
  90. @end
  91. // A command-line URL fetcher (ksurl, like "curl"). It requires the following
  92. // two command-line arguments:
  93. // -url <url> the URL to be downloaded (e.g. http://www.google.com)
  94. // -path <path> the local path where the downloaded file should be stored
  95. // An optional argument is:
  96. // -size <size> the expected download size (implicitly turns on
  97. // progress notifications). Progress is sent via a
  98. // distributed notification named
  99. // KSURLProgressNotification whose object is <path>
  100. // (from above). The userInfo is a dictionary with
  101. // Key=KSURLProgressKey, value is an float (0.0-1.0)
  102. // encoded in an NSNumber.
  103. //
  104. // We do not provide a help screen because this command is not a "public" API
  105. // and it would only increase our file size and encourage its use.
  106. //
  107. // We use this command instead of a simple curl for a couple reasons. One is
  108. // that using Apple's Foundation networking APIs gets us proxy support at
  109. // virtually no cost. The other reason is that this command will change UID to
  110. // a non-root user if invoked from a root process. This helps ensure that root
  111. // processes do not do network transactions.
  112. int main(void) {
  113. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  114. int rc = EXIT_FAILURE;
  115. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  116. NSString *urlString = [defaults stringForKey:@"url"];
  117. if (urlString == nil) goto bail;
  118. NSURL *url = [NSURL URLWithString:urlString];
  119. if (url == nil) goto bail;
  120. NSString *path = [defaults stringForKey:@"path"];
  121. if (path == nil) goto bail;
  122. NSString *size = [defaults stringForKey:@"size"];
  123. NSInteger downloadSize = [size intValue]; // may be 0
  124. // If we're running as root, change uid and group id to "nobody"
  125. if (geteuid() == 0 || getuid() == 0) {
  126. // COV_NF_START
  127. setgid(-2); // nobody
  128. setuid(-2); // nobody
  129. if (geteuid() == 0 || getuid() == 0 || getgid() == 0) {
  130. NSLog(@"Failed to change uid to -2");
  131. goto bail;
  132. }
  133. //COV_NF_END
  134. }
  135. NSURLRequest *request = nil;
  136. request = [NSURLRequest requestWithURL:url
  137. cachePolicy:NSURLRequestReloadIgnoringCacheData
  138. timeoutInterval:60];
  139. DownloadDelegate *delegate = [[[DownloadDelegate alloc]
  140. initWithSize:downloadSize
  141. path:path] autorelease];
  142. NSURLDownload *download =
  143. [[[NSURLDownload alloc] initWithRequest:request
  144. delegate:delegate] autorelease];
  145. [download setDestination:path allowOverwrite:YES];
  146. // Wait for the download to complete.
  147. while (![delegate isDone]) {
  148. NSDate *spin = [NSDate dateWithTimeIntervalSinceNow:1];
  149. [[NSRunLoop currentRunLoop] runUntilDate:spin];
  150. }
  151. if ([delegate wasSuccess])
  152. rc = EXIT_SUCCESS;
  153. bail:
  154. [pool release];
  155. return rc;
  156. }