• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <WebCore/FoundationExtras.h>
32#import <WebKit/WebKitNSStringExtras.h>
33#import <WebKitSystemInterface.h>
34#import <wtf/Assertions.h>
35
36#import <pthread.h>
37#import <sys/mount.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    // Spawn a background thread for WKSetMetadataURL because this function will not return until mds has
175    // journaled the data we're're trying to set. Depending on what other I/O is going on, it can take some
176    // time.
177    pthread_t tid;
178    pthread_attr_t attr;
179    pthread_attr_init(&attr);
180    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
181
182    MetaDataInfo *info = malloc(sizeof(MetaDataInfo));
183
184    info->URLString = HardRetainWithNSRelease([URLString copy]);
185    info->referrer = HardRetainWithNSRelease([referrer copy]);
186    info->path = HardRetainWithNSRelease([path copy]);
187
188    pthread_create(&tid, &attr, setMetaData, info);
189    pthread_attr_destroy(&attr);
190}
191
192- (NSString *)_webkit_startupVolumeName
193{
194    NSString *path = [self _webkit_carbonPathForPath:@"/"];
195    return [path substringToIndex:[path length]-1];
196}
197
198- (NSString *)_webkit_pathWithUniqueFilenameForPath:(NSString *)path
199{
200    // "Fix" the filename of the path.
201    NSString *filename = [[path lastPathComponent] _webkit_filenameByFixingIllegalCharacters];
202    path = [[path stringByDeletingLastPathComponent] stringByAppendingPathComponent:filename];
203
204    NSFileManager *fileManager = [NSFileManager defaultManager];
205    if ([fileManager fileExistsAtPath:path]) {
206        // Don't overwrite existing file by appending "-n", "-n.ext" or "-n.ext.ext" to the filename.
207        NSString *extensions = nil;
208        NSString *pathWithoutExtensions;
209        NSString *lastPathComponent = [path lastPathComponent];
210        NSRange periodRange = [lastPathComponent rangeOfString:@"."];
211
212        if (periodRange.location == NSNotFound) {
213            pathWithoutExtensions = path;
214        } else {
215            extensions = [lastPathComponent substringFromIndex:periodRange.location + 1];
216            lastPathComponent = [lastPathComponent substringToIndex:periodRange.location];
217            pathWithoutExtensions = [[path stringByDeletingLastPathComponent] stringByAppendingPathComponent:lastPathComponent];
218        }
219
220        NSString *pathWithAppendedNumber;
221        unsigned i;
222
223        for (i = 1; 1; i++) {
224            pathWithAppendedNumber = [NSString stringWithFormat:@"%@-%d", pathWithoutExtensions, i];
225            path = [extensions length] ? [pathWithAppendedNumber stringByAppendingPathExtension:extensions] : pathWithAppendedNumber;
226            if (![fileManager fileExistsAtPath:path]) {
227                break;
228            }
229        }
230    }
231
232    return path;
233}
234
235@end
236
237
238#ifdef BUILDING_ON_TIGER
239@implementation NSFileManager (WebNSFileManagerTigerForwardCompatibility)
240
241- (NSArray *)contentsOfDirectoryAtPath:(NSString *)path error:(NSError **)error
242{
243    // We don't report errors via the NSError* output parameter, so ensure that the caller does not expect us to do so.
244    ASSERT_ARG(error, !error);
245
246    return [self directoryContentsAtPath:path];
247}
248
249- (NSString *)destinationOfSymbolicLinkAtPath:(NSString *)path error:(NSError **)error
250{
251    // We don't report errors via the NSError* output parameter, so ensure that the caller does not expect us to do so.
252    ASSERT_ARG(error, !error);
253
254    return [self pathContentOfSymbolicLinkAtPath:path];
255}
256
257- (NSDictionary *)attributesOfFileSystemForPath:(NSString *)path error:(NSError **)error
258{
259    // We don't report errors via the NSError* output parameter, so ensure that the caller does not expect us to do so.
260    ASSERT_ARG(error, !error);
261
262    return [self fileSystemAttributesAtPath:path];
263}
264
265- (NSDictionary *)attributesOfItemAtPath:(NSString *)path error:(NSError **)error
266{
267    // We don't report errors via the NSError* output parameter, so ensure that the caller does not expect us to do so.
268    ASSERT_ARG(error, !error);
269
270    return [self fileAttributesAtPath:path traverseLink:NO];
271}
272
273- (BOOL)moveItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error
274{
275    // The implementation of moveItemAtPath:toPath:error: interacts with the NSFileManager's delegate.
276    // We are not matching that behaviour at the moment, but it should not be a problem as any client
277    // expecting that would need to call setDelegate: first which will generate a compile-time warning,
278    // as that method is not available on Tiger.
279    return [self movePath:srcPath toPath:dstPath handler:nil];
280}
281
282- (BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error
283{
284    // The implementation of removeItemAtPath:error: interacts with the NSFileManager's delegate.
285    // We are not matching that behaviour at the moment, but it should not be a problem as any client
286    // expecting that would need to call setDelegate: first which will generate a compile-time warning,
287    // as that method is not available on Tiger.
288    return [self removeFileAtPath:path handler:nil];
289}
290
291@end
292#endif
293