PageRenderTime 50ms CodeModel.GetById 18ms app.highlight 29ms RepoModel.GetById 1ms app.codeStats 0ms

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