• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple 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 "WebKitNSStringExtras.h"
32#import "WebNSURLExtras.h"
33#import <WebCore/FoundationExtras.h>
34#import <WebKitSystemInterface.h>
35#import <pthread.h>
36#import <sys/mount.h>
37#import <JavaScriptCore/Assertions.h>
38
39@implementation NSFileManager (WebNSFileManagerExtras)
40
41- (BOOL)_webkit_removeFileOnlyAtPath:(NSString *)path
42{
43    struct statfs buf;
44    BOOL result = unlink([path fileSystemRepresentation]) == 0;
45
46    // For mysterious reasons, MNT_DOVOLFS is the flag for "supports resource fork"
47    if ((statfs([path fileSystemRepresentation], &buf) == 0) && !(buf.f_flags & MNT_DOVOLFS)) {
48        NSString *lastPathComponent = [path lastPathComponent];
49        if ([lastPathComponent length] != 0 && ![lastPathComponent isEqualToString:@"/"]) {
50            NSString *resourcePath = [[path stringByDeletingLastPathComponent] stringByAppendingString:[@"._" stringByAppendingString:lastPathComponent]];
51            if (unlink([resourcePath fileSystemRepresentation]) != 0) {
52                result = NO;
53            }
54        }
55    }
56
57    return result;
58}
59
60- (void)_webkit_backgroundRemoveFileAtPath:(NSString *)path
61{
62    NSFileManager *manager;
63    NSString *moveToSubpath;
64    NSString *moveToPath;
65    int i;
66
67    manager = [NSFileManager defaultManager];
68
69    i = 0;
70    moveToSubpath = [path stringByDeletingLastPathComponent];
71    do {
72        moveToPath = [NSString stringWithFormat:@"%@/.tmp%d", moveToSubpath, i];
73        i++;
74    } while ([manager fileExistsAtPath:moveToPath]);
75
76    if ([manager moveItemAtPath:path toPath:moveToPath error:NULL])
77        [NSThread detachNewThreadSelector:@selector(_performRemoveFileAtPath:) toTarget:self withObject:moveToPath];
78}
79
80- (void)_webkit_backgroundRemoveLeftoverFiles:(NSString *)path
81{
82    NSFileManager *manager;
83    NSString *leftoverSubpath;
84    NSString *leftoverPath;
85    int i;
86
87    manager = [NSFileManager defaultManager];
88    leftoverSubpath = [path stringByDeletingLastPathComponent];
89
90    i = 0;
91    while (1) {
92        leftoverPath = [NSString stringWithFormat:@"%@/.tmp%d", leftoverSubpath, i];
93        if (![manager fileExistsAtPath:leftoverPath]) {
94            break;
95        }
96        [NSThread detachNewThreadSelector:@selector(_performRemoveFileAtPath:) toTarget:self withObject:leftoverPath];
97        i++;
98    }
99}
100
101- (NSString *)_webkit_carbonPathForPath:(NSString *)posixPath
102{
103    OSStatus error;
104    FSRef ref, rootRef, parentRef;
105    FSCatalogInfo info;
106    NSMutableArray *carbonPathPieces;
107    HFSUniStr255 nameString;
108
109    // Make an FSRef.
110    error = FSPathMakeRef((const UInt8 *)[posixPath fileSystemRepresentation], &ref, NULL);
111    if (error != noErr) {
112        return nil;
113    }
114
115    // Get volume refNum.
116    error = FSGetCatalogInfo(&ref, kFSCatInfoVolume, &info, NULL, NULL, NULL);
117    if (error != noErr) {
118        return nil;
119    }
120
121    // Get root directory FSRef.
122    error = FSGetVolumeInfo(info.volume, 0, NULL, kFSVolInfoNone, NULL, NULL, &rootRef);
123    if (error != noErr) {
124        return nil;
125    }
126
127    // Get the pieces of the path.
128    carbonPathPieces = [NSMutableArray array];
129    for (;;) {
130        error = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, &nameString, NULL, &parentRef);
131        if (error != noErr) {
132            return nil;
133        }
134        [carbonPathPieces insertObject:[NSString stringWithCharacters:nameString.unicode length:nameString.length] atIndex:0];
135        if (FSCompareFSRefs(&ref, &rootRef) == noErr) {
136            break;
137        }
138        ref = parentRef;
139    }
140
141    // Volume names need trailing : character.
142    if ([carbonPathPieces count] == 1) {
143        [carbonPathPieces addObject:@""];
144    }
145
146    return [carbonPathPieces componentsJoinedByString:@":"];
147}
148
149typedef struct MetaDataInfo
150{
151    NSString *URLString;
152    NSString *referrer;
153    NSString *path;
154} MetaDataInfo;
155
156static void *setMetaData(void* context)
157{
158    MetaDataInfo *info = (MetaDataInfo *)context;
159    WKSetMetadataURL(info->URLString, info->referrer, info->path);
160
161    HardRelease(info->URLString);
162    HardRelease(info->referrer);
163    HardRelease(info->path);
164
165    free(info);
166    return 0;
167}
168
169- (void)_webkit_setMetadataURL:(NSString *)URLString referrer:(NSString *)referrer atPath:(NSString *)path
170{
171    ASSERT(URLString);
172    ASSERT(path);
173
174    NSURL *URL = [NSURL _web_URLWithUserTypedString:URLString];
175    if (URL)
176        URLString = [[URL _web_URLByRemovingUserInfo] _web_userVisibleString];
177
178    // Spawn a background thread for WKSetMetadataURL because this function will not return until mds has
179    // journaled the data we're're trying to set. Depending on what other I/O is going on, it can take some
180    // time.
181    pthread_t tid;
182    pthread_attr_t attr;
183    pthread_attr_init(&attr);
184    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
185
186    MetaDataInfo *info = malloc(sizeof(MetaDataInfo));
187
188    info->URLString = HardRetainWithNSRelease([URLString copy]);
189    info->referrer = HardRetainWithNSRelease([referrer copy]);
190    info->path = HardRetainWithNSRelease([path copy]);
191
192    pthread_create(&tid, &attr, setMetaData, info);
193    pthread_attr_destroy(&attr);
194}
195
196- (NSString *)_webkit_startupVolumeName
197{
198    NSString *path = [self _webkit_carbonPathForPath:@"/"];
199    return [path substringToIndex:[path length]-1];
200}
201
202- (NSString *)_webkit_pathWithUniqueFilenameForPath:(NSString *)path
203{
204    // "Fix" the filename of the path.
205    NSString *filename = [[path lastPathComponent] _webkit_filenameByFixingIllegalCharacters];
206    path = [[path stringByDeletingLastPathComponent] stringByAppendingPathComponent:filename];
207
208    NSFileManager *fileManager = [NSFileManager defaultManager];
209    if ([fileManager fileExistsAtPath:path]) {
210        // Don't overwrite existing file by appending "-n", "-n.ext" or "-n.ext.ext" to the filename.
211        NSString *extensions = nil;
212        NSString *pathWithoutExtensions;
213        NSString *lastPathComponent = [path lastPathComponent];
214        NSRange periodRange = [lastPathComponent rangeOfString:@"."];
215
216        if (periodRange.location == NSNotFound) {
217            pathWithoutExtensions = path;
218        } else {
219            extensions = [lastPathComponent substringFromIndex:periodRange.location + 1];
220            lastPathComponent = [lastPathComponent substringToIndex:periodRange.location];
221            pathWithoutExtensions = [[path stringByDeletingLastPathComponent] stringByAppendingPathComponent:lastPathComponent];
222        }
223
224        NSString *pathWithAppendedNumber;
225        unsigned i;
226
227        for (i = 1; 1; i++) {
228            pathWithAppendedNumber = [NSString stringWithFormat:@"%@-%d", pathWithoutExtensions, i];
229            path = [extensions length] ? [pathWithAppendedNumber stringByAppendingPathExtension:extensions] : pathWithAppendedNumber;
230            if (![fileManager fileExistsAtPath:path]) {
231                break;
232            }
233        }
234    }
235
236    return path;
237}
238
239@end
240
241
242#ifdef BUILDING_ON_TIGER
243@implementation NSFileManager (WebNSFileManagerTigerForwardCompatibility)
244
245- (NSArray *)contentsOfDirectoryAtPath:(NSString *)path error:(NSError **)error
246{
247    // We don't report errors via the NSError* output parameter, so ensure that the caller does not expect us to do so.
248    ASSERT_ARG(error, !error);
249
250    return [self directoryContentsAtPath:path];
251}
252
253- (NSString *)destinationOfSymbolicLinkAtPath:(NSString *)path error:(NSError **)error
254{
255    // We don't report errors via the NSError* output parameter, so ensure that the caller does not expect us to do so.
256    ASSERT_ARG(error, !error);
257
258    return [self pathContentOfSymbolicLinkAtPath:path];
259}
260
261- (NSDictionary *)attributesOfFileSystemForPath:(NSString *)path error:(NSError **)error
262{
263    // We don't report errors via the NSError* output parameter, so ensure that the caller does not expect us to do so.
264    ASSERT_ARG(error, !error);
265
266    return [self fileSystemAttributesAtPath:path];
267}
268
269- (NSDictionary *)attributesOfItemAtPath:(NSString *)path error:(NSError **)error
270{
271    // We don't report errors via the NSError* output parameter, so ensure that the caller does not expect us to do so.
272    ASSERT_ARG(error, !error);
273
274    return [self fileAttributesAtPath:path traverseLink:NO];
275}
276
277- (BOOL)moveItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error
278{
279    // The implementation of moveItemAtPath:toPath:error: interacts with the NSFileManager's delegate.
280    // We are not matching that behaviour at the moment, but it should not be a problem as any client
281    // expecting that would need to call setDelegate: first which will generate a compile-time warning,
282    // as that method is not available on Tiger.
283    return [self movePath:srcPath toPath:dstPath handler:nil];
284}
285
286- (BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error
287{
288    // The implementation of removeItemAtPath:error: interacts with the NSFileManager's delegate.
289    // We are not matching that behaviour at the moment, but it should not be a problem as any client
290    // expecting that would need to call setDelegate: first which will generate a compile-time warning,
291    // as that method is not available on Tiger.
292    return [self removeFileAtPath:path handler:nil];
293}
294
295@end
296#endif
297