webengine/osswebengine/WebKit/Misc/WebNSFileManagerExtras.m
changeset 0 dd21522fd290
equal deleted inserted replaced
-1:000000000000 0:dd21522fd290
       
     1 /*
       
     2  * Copyright (C) 2005 Apple Computer, Inc.  All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  *
       
     8  * 1.  Redistributions of source code must retain the above copyright
       
     9  *     notice, this list of conditions and the following disclaimer. 
       
    10  * 2.  Redistributions in binary form must reproduce the above copyright
       
    11  *     notice, this list of conditions and the following disclaimer in the
       
    12  *     documentation and/or other materials provided with the distribution. 
       
    13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
       
    14  *     its contributors may be used to endorse or promote products derived
       
    15  *     from this software without specific prior written permission. 
       
    16  *
       
    17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
       
    18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
    19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
       
    20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
       
    21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
       
    22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
       
    23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
       
    24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
       
    26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    27  */
       
    28 
       
    29 #import <WebKit/WebNSFileManagerExtras.h>
       
    30 
       
    31 #import <JavaScriptCore/Assertions.h>
       
    32 #import <WebKit/WebKitNSStringExtras.h>
       
    33 
       
    34 #import <sys/mount.h>
       
    35 
       
    36 @implementation NSFileManager (WebNSFileManagerExtras)
       
    37 
       
    38 - (BOOL)_webkit_fileExistsAtPath:(NSString *)path isDirectory:(BOOL *)isDirectory traverseLink:(BOOL)flag
       
    39 {
       
    40     BOOL result;
       
    41     NSDictionary *attributes;
       
    42 
       
    43     result = NO;
       
    44     if (isDirectory) {
       
    45         *isDirectory = NO;
       
    46     }
       
    47 
       
    48     attributes = [self fileAttributesAtPath:path traverseLink:flag];
       
    49 
       
    50     if (attributes) {
       
    51         result = YES;
       
    52         if ([[attributes objectForKey:NSFileType] isEqualToString:NSFileTypeDirectory]) {
       
    53             if (isDirectory) {
       
    54                 *isDirectory = YES;
       
    55             }
       
    56         }
       
    57     }
       
    58 
       
    59     return result;
       
    60 }
       
    61 
       
    62 - (BOOL)_webkit_createIntermediateDirectoriesForPath:(NSString *)path attributes:(NSDictionary *)attributes
       
    63 {
       
    64     BOOL result;
       
    65     NSArray *pathComponents;
       
    66     BOOL isDir;
       
    67     unsigned count;
       
    68     unsigned i;
       
    69     NSString *checkPath;
       
    70     NSMutableString *subpath;
       
    71             
       
    72     if (!path || [path length] == 0 || ![path isAbsolutePath]) {
       
    73         return NO;
       
    74     }
       
    75 
       
    76     result = NO;  
       
    77 
       
    78     // check to see if the path to the file already exists        
       
    79     if ([self _webkit_fileExistsAtPath:[path stringByDeletingLastPathComponent] isDirectory:&isDir traverseLink:YES]) {
       
    80         if (isDir) {
       
    81             result = YES;
       
    82         }
       
    83         else {
       
    84             result = NO;
       
    85         }
       
    86     }
       
    87     else {
       
    88         // create the path to the file
       
    89         result = YES;  
       
    90 
       
    91         // assume that most of the path exists, look backwards until we find an existing subpath
       
    92         checkPath = path;
       
    93         while (![checkPath isEqualToString:@"/"]) {
       
    94             checkPath = [checkPath stringByDeletingLastPathComponent];
       
    95             if ([self _webkit_fileExistsAtPath:checkPath isDirectory:&isDir traverseLink:YES]) {
       
    96                 if (isDir) {
       
    97                     break;
       
    98                 }
       
    99                 else {
       
   100                     // found a leaf node, can't continue
       
   101                     result = NO;
       
   102                     break;
       
   103                 }
       
   104             }
       
   105         }
       
   106 
       
   107         if (result) {
       
   108             // now build up the path to the point where we found existing paths
       
   109             subpath = [[NSMutableString alloc] initWithCapacity:[path length]];
       
   110             pathComponents = [path componentsSeparatedByString:@"/"];    
       
   111             count = [pathComponents count];
       
   112             i = 0;
       
   113             while (i < count - 1 && ![subpath isEqualToString:checkPath]) {
       
   114                 if (i > 0) {
       
   115                     [subpath appendString:@"/"];
       
   116                 }
       
   117                 [subpath appendString:[pathComponents objectAtIndex:i]];  
       
   118                 i++;  
       
   119             }
       
   120             
       
   121             // now create the parts of the path that did not yet exist
       
   122             while (i < count - 1) {
       
   123                 if ([(NSString *)[pathComponents objectAtIndex:i] length] == 0) {
       
   124                     continue;
       
   125                 }
       
   126                 if (i > 0) {
       
   127                     [subpath appendString:@"/"];
       
   128                 }
       
   129                 [subpath appendString:[pathComponents objectAtIndex:i]];
       
   130                 
       
   131                 // does this directory exist?
       
   132                 if ([self _webkit_fileExistsAtPath:subpath isDirectory:&isDir traverseLink:YES]) {
       
   133                     if (!isDir) {
       
   134                         // ran into a leaf node of some sort
       
   135                         result = NO;
       
   136                         break;
       
   137                     }
       
   138                 }
       
   139                 else {
       
   140                     // subpath does not exist - create it
       
   141                     if (![self createDirectoryAtPath:subpath attributes:attributes]) {
       
   142                         // failed to create subpath
       
   143                         result = NO;
       
   144                         break;
       
   145                     }
       
   146                 }
       
   147                 i++; 
       
   148             }
       
   149             
       
   150             [subpath release];
       
   151         }
       
   152         
       
   153     }    
       
   154                             
       
   155     return result;
       
   156 }
       
   157 
       
   158 - (BOOL)_webkit_createDirectoryAtPathWithIntermediateDirectories:(NSString *)path attributes:(NSDictionary *)attributes
       
   159 {
       
   160     // Be really optimistic - assume that in the common case, the directory exists.
       
   161     BOOL isDirectory;
       
   162     if ([self fileExistsAtPath:path isDirectory:&isDirectory] && isDirectory) {
       
   163         return YES;
       
   164     }
       
   165 
       
   166     // Assume the next most common case is that the parent directory already exists
       
   167     if ([self createDirectoryAtPath:path attributes:attributes]) {
       
   168         return YES;
       
   169     }
       
   170 
       
   171     // Do it the hard way 
       
   172     return [self _webkit_createIntermediateDirectoriesForPath:path attributes:attributes] && [self createDirectoryAtPath:path attributes:attributes];
       
   173 }
       
   174 
       
   175 - (BOOL)_webkit_createFileAtPathWithIntermediateDirectories:(NSString *)path contents:(NSData *)contents attributes:(NSDictionary *)attributes directoryAttributes:(NSDictionary *)directoryAttributes
       
   176 {
       
   177     // Be optimistic - try just creating the file first, assuming intermediate directories exist. 
       
   178     if ([self createFileAtPath:path contents:contents attributes:attributes]) {
       
   179         return YES;
       
   180     }
       
   181 
       
   182     return ([self _webkit_createIntermediateDirectoriesForPath:path attributes:directoryAttributes] && [self createFileAtPath:path contents:contents attributes:attributes]);
       
   183 }
       
   184 
       
   185 - (BOOL)_webkit_removeFileOnlyAtPath:(NSString *)path
       
   186 {
       
   187     struct statfs buf;
       
   188     BOOL result = unlink([path fileSystemRepresentation]) == 0;
       
   189 
       
   190     // For mysterious reasons, MNT_DOVOLFS is the flag for "supports resource fork"
       
   191     if ((statfs([path fileSystemRepresentation], &buf) == 0) && !(buf.f_flags & MNT_DOVOLFS)) {
       
   192         NSString *lastPathComponent = [path lastPathComponent];
       
   193         if ([lastPathComponent length] != 0 && ![lastPathComponent isEqualToString:@"/"]) {
       
   194             NSString *resourcePath = [[path stringByDeletingLastPathComponent] stringByAppendingString:[@"._" stringByAppendingString:lastPathComponent]];
       
   195             if (unlink([resourcePath fileSystemRepresentation]) != 0) {
       
   196                 result = NO;
       
   197             }
       
   198         }
       
   199     }
       
   200 
       
   201     return result;
       
   202 }
       
   203 
       
   204 - (void)_webkit_backgroundRemoveFileAtPath:(NSString *)path
       
   205 {
       
   206     NSFileManager *manager;
       
   207     NSString *moveToSubpath;
       
   208     NSString *moveToPath;
       
   209     int i;
       
   210     
       
   211     manager = [NSFileManager defaultManager];
       
   212     
       
   213     i = 0;
       
   214     moveToSubpath = [path stringByDeletingLastPathComponent];
       
   215     do {
       
   216         moveToPath = [NSString stringWithFormat:@"%@/.tmp%d", moveToSubpath, i];
       
   217         i++;
       
   218     } while ([manager fileExistsAtPath:moveToPath]);
       
   219 
       
   220     if ([manager movePath:path toPath:moveToPath handler:nil]) {
       
   221         [NSThread detachNewThreadSelector:@selector(_performRemoveFileAtPath:) toTarget:self withObject:moveToPath];
       
   222     }
       
   223 
       
   224 }
       
   225 
       
   226 - (void)_webkit_backgroundRemoveLeftoverFiles:(NSString *)path
       
   227 {
       
   228     NSFileManager *manager;
       
   229     NSString *leftoverSubpath;
       
   230     NSString *leftoverPath;
       
   231     int i;
       
   232     
       
   233     manager = [NSFileManager defaultManager];
       
   234     leftoverSubpath = [path stringByDeletingLastPathComponent];
       
   235     
       
   236     i = 0;
       
   237     while (1) {
       
   238         leftoverPath = [NSString stringWithFormat:@"%@/.tmp%d", leftoverSubpath, i];
       
   239         if (![manager fileExistsAtPath:leftoverPath]) {
       
   240             break;
       
   241         }
       
   242         [NSThread detachNewThreadSelector:@selector(_performRemoveFileAtPath:) toTarget:self withObject:leftoverPath];
       
   243         i++;
       
   244     }
       
   245 }
       
   246 
       
   247 - (NSString *)_webkit_carbonPathForPath:(NSString *)posixPath
       
   248 {
       
   249     OSStatus error;
       
   250     FSRef ref, rootRef, parentRef;
       
   251     FSCatalogInfo info;
       
   252     NSMutableArray *carbonPathPieces;
       
   253     HFSUniStr255 nameString;
       
   254 
       
   255     // Make an FSRef.
       
   256     error = FSPathMakeRef((const UInt8 *)[posixPath fileSystemRepresentation], &ref, NULL);
       
   257     if (error != noErr) {
       
   258         return nil;
       
   259     }
       
   260 
       
   261     // Get volume refNum.
       
   262     error = FSGetCatalogInfo(&ref, kFSCatInfoVolume, &info, NULL, NULL, NULL);
       
   263     if (error != noErr) {
       
   264         return nil;
       
   265     }
       
   266 
       
   267     // Get root directory FSRef.
       
   268     error = FSGetVolumeInfo(info.volume, 0, NULL, kFSVolInfoNone, NULL, NULL, &rootRef);
       
   269     if (error != noErr) {
       
   270         return nil;
       
   271     }
       
   272 
       
   273     // Get the pieces of the path.
       
   274     carbonPathPieces = [NSMutableArray array];
       
   275     for (;;) {
       
   276         error = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, &nameString, NULL, &parentRef);
       
   277         if (error != noErr) {
       
   278             return nil;
       
   279         }
       
   280         [carbonPathPieces insertObject:[NSString stringWithCharacters:nameString.unicode length:nameString.length] atIndex:0];
       
   281         if (FSCompareFSRefs(&ref, &rootRef) == noErr) {
       
   282             break;
       
   283         }
       
   284         ref = parentRef;
       
   285     }
       
   286 
       
   287     // Volume names need trailing : character.
       
   288     if ([carbonPathPieces count] == 1) {
       
   289         [carbonPathPieces addObject:@""];
       
   290     }
       
   291 
       
   292     return [carbonPathPieces componentsJoinedByString:@":"];
       
   293 }
       
   294 
       
   295 - (NSString *)_webkit_startupVolumeName
       
   296 {
       
   297     NSString *path = [self _webkit_carbonPathForPath:@"/"];
       
   298     return [path substringToIndex:[path length]-1];
       
   299 }
       
   300 
       
   301 - (NSString *)_webkit_pathWithUniqueFilenameForPath:(NSString *)path
       
   302 {
       
   303     // "Fix" the filename of the path.
       
   304     NSString *filename = [[path lastPathComponent] _webkit_filenameByFixingIllegalCharacters];
       
   305     path = [[path stringByDeletingLastPathComponent] stringByAppendingPathComponent:filename];
       
   306 
       
   307     NSFileManager *fileManager = [NSFileManager defaultManager];
       
   308     if ([fileManager fileExistsAtPath:path]) {
       
   309         // Don't overwrite existing file by appending "-n", "-n.ext" or "-n.ext.ext" to the filename.
       
   310         NSString *extensions = nil;
       
   311         NSString *pathWithoutExtensions;
       
   312         NSString *lastPathComponent = [path lastPathComponent];
       
   313         NSRange periodRange = [lastPathComponent rangeOfString:@"."];
       
   314         
       
   315         if (periodRange.location == NSNotFound) {
       
   316             pathWithoutExtensions = path;
       
   317         } else {
       
   318             extensions = [lastPathComponent substringFromIndex:periodRange.location + 1];
       
   319             lastPathComponent = [lastPathComponent substringToIndex:periodRange.location];
       
   320             pathWithoutExtensions = [[path stringByDeletingLastPathComponent] stringByAppendingPathComponent:lastPathComponent];
       
   321         }
       
   322 
       
   323         NSString *pathWithAppendedNumber;
       
   324         unsigned i;
       
   325 
       
   326         for (i = 1; 1; i++) {
       
   327             pathWithAppendedNumber = [NSString stringWithFormat:@"%@-%d", pathWithoutExtensions, i];
       
   328             path = [extensions length] ? [pathWithAppendedNumber stringByAppendingPathExtension:extensions] : pathWithAppendedNumber;
       
   329             if (![fileManager fileExistsAtPath:path]) {
       
   330                 break;
       
   331             }
       
   332         }
       
   333     }
       
   334 
       
   335     return path;
       
   336 }
       
   337 
       
   338 @end