1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
---|
2 | /* ***** BEGIN LICENSE BLOCK *****
|
---|
3 | * Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
---|
4 | *
|
---|
5 | * The contents of this file are subject to the Mozilla Public License Version
|
---|
6 | * 1.1 (the "License"); you may not use this file except in compliance with
|
---|
7 | * the License. You may obtain a copy of the License at
|
---|
8 | * http://www.mozilla.org/MPL/
|
---|
9 | *
|
---|
10 | * Software distributed under the License is distributed on an "AS IS" basis,
|
---|
11 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
---|
12 | * for the specific language governing rights and limitations under the
|
---|
13 | * License.
|
---|
14 | *
|
---|
15 | * The Original Code is Mozilla Communicator client code, released
|
---|
16 | * March 31, 1998.
|
---|
17 | *
|
---|
18 | * The Initial Developer of the Original Code is
|
---|
19 | * Netscape Communications Corporation.
|
---|
20 | * Portions created by the Initial Developer are Copyright (C) 1998-1999
|
---|
21 | * the Initial Developer. All Rights Reserved.
|
---|
22 | *
|
---|
23 | * Contributor(s):
|
---|
24 | * Steve Dagley <[email protected]>
|
---|
25 | * John R. McMullen
|
---|
26 | *
|
---|
27 | * Alternatively, the contents of this file may be used under the terms of
|
---|
28 | * either of the GNU General Public License Version 2 or later (the "GPL"),
|
---|
29 | * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
---|
30 | * in which case the provisions of the GPL or the LGPL are applicable instead
|
---|
31 | * of those above. If you wish to allow use of your version of this file only
|
---|
32 | * under the terms of either the GPL or the LGPL, and not to allow others to
|
---|
33 | * use your version of this file under the terms of the MPL, indicate your
|
---|
34 | * decision by deleting the provisions above and replace them with the notice
|
---|
35 | * and other provisions required by the GPL or the LGPL. If you do not delete
|
---|
36 | * the provisions above, a recipient may use your version of this file under
|
---|
37 | * the terms of any one of the MPL, the GPL or the LGPL.
|
---|
38 | *
|
---|
39 | * ***** END LICENSE BLOCK ***** */
|
---|
40 |
|
---|
41 |
|
---|
42 | #include "nsCOMPtr.h"
|
---|
43 | #include "nsMemory.h"
|
---|
44 | #include "nsXPIDLString.h"
|
---|
45 |
|
---|
46 | #include "nsLocalFile.h"
|
---|
47 | #include "nsNativeCharsetUtils.h"
|
---|
48 | #include "nsISimpleEnumerator.h"
|
---|
49 | #include "nsIComponentManager.h"
|
---|
50 | #include "nsIInternetConfigService.h"
|
---|
51 | #include "nsIMIMEInfo.h"
|
---|
52 | #include "prtypes.h"
|
---|
53 | #include "prerror.h"
|
---|
54 |
|
---|
55 | #include "nsReadableUtils.h"
|
---|
56 | #include "nsITimelineService.h"
|
---|
57 |
|
---|
58 | #ifdef XP_MACOSX
|
---|
59 | #include "nsXPIDLString.h"
|
---|
60 |
|
---|
61 | #include "private/pprio.h"
|
---|
62 | #else
|
---|
63 | #include "pprio.h" // Include this rather than prio.h so we get def of PR_ImportFile
|
---|
64 | #endif
|
---|
65 | #include "prmem.h"
|
---|
66 | #include "plbase64.h"
|
---|
67 |
|
---|
68 | #include "FullPath.h"
|
---|
69 | #include "FileCopy.h"
|
---|
70 | #include "MoreFilesExtras.h"
|
---|
71 | #include "DirectoryCopy.h"
|
---|
72 | #include <Script.h>
|
---|
73 | #include <Processes.h>
|
---|
74 | #include <StringCompare.h>
|
---|
75 | #include <Resources.h>
|
---|
76 |
|
---|
77 | #include <AppleEvents.h>
|
---|
78 | #include <AEDataModel.h>
|
---|
79 | #include <AERegistry.h>
|
---|
80 | #include <Gestalt.h>
|
---|
81 |
|
---|
82 | #include <Math64.h>
|
---|
83 | #include <Aliases.h>
|
---|
84 | #include <Folders.h>
|
---|
85 | #include <Gestalt.h>
|
---|
86 | #include "macDirectoryCopy.h"
|
---|
87 |
|
---|
88 | #include <limits.h>
|
---|
89 |
|
---|
90 | // Stupid @#$% header looks like its got extern mojo but it doesn't really
|
---|
91 | extern "C"
|
---|
92 | {
|
---|
93 | #ifndef XP_MACOSX
|
---|
94 | // BADPINK - this MSL header doesn't exist under macosx :-(
|
---|
95 | #include <FSp_fopen.h>
|
---|
96 | #endif
|
---|
97 | }
|
---|
98 |
|
---|
99 | #if TARGET_CARBON
|
---|
100 | #include <CodeFragments.h> // Needed for definition of kUnresolvedCFragSymbolAddress
|
---|
101 | #include <LaunchServices.h>
|
---|
102 | #endif
|
---|
103 |
|
---|
104 | #pragma mark [Constants]
|
---|
105 |
|
---|
106 | const OSType kDefaultCreator = 'MOSS';
|
---|
107 |
|
---|
108 | #pragma mark -
|
---|
109 | #pragma mark [nsPathParser]
|
---|
110 |
|
---|
111 | class nsPathParser
|
---|
112 | {
|
---|
113 | public:
|
---|
114 | nsPathParser(const nsACString &path);
|
---|
115 |
|
---|
116 | ~nsPathParser()
|
---|
117 | {
|
---|
118 | if (mAllocatedBuffer)
|
---|
119 | nsMemory::Free(mAllocatedBuffer);
|
---|
120 | }
|
---|
121 |
|
---|
122 | const char* First()
|
---|
123 | {
|
---|
124 | return nsCRT::strtok(mBuffer, ":", &mNewString);
|
---|
125 | }
|
---|
126 | const char* Next()
|
---|
127 | {
|
---|
128 | return nsCRT::strtok(mNewString, ":", &mNewString);
|
---|
129 | }
|
---|
130 | const char* Remainder()
|
---|
131 | {
|
---|
132 | return mNewString;
|
---|
133 | }
|
---|
134 |
|
---|
135 | private:
|
---|
136 | char mAutoBuffer[512];
|
---|
137 | char *mAllocatedBuffer;
|
---|
138 | char *mBuffer, *mNewString;
|
---|
139 | };
|
---|
140 |
|
---|
141 | nsPathParser::nsPathParser(const nsACString &inPath) :
|
---|
142 | mAllocatedBuffer(nsnull), mNewString(nsnull)
|
---|
143 | {
|
---|
144 | PRUint32 inPathLen = inPath.Length();
|
---|
145 | if (inPathLen >= sizeof(mAutoBuffer)) {
|
---|
146 | mAllocatedBuffer = (char *)nsMemory::Alloc(inPathLen + 1);
|
---|
147 | mBuffer = mAllocatedBuffer;
|
---|
148 | }
|
---|
149 | else
|
---|
150 | mBuffer = mAutoBuffer;
|
---|
151 |
|
---|
152 | // copy inPath into mBuffer
|
---|
153 | nsACString::const_iterator start, end;
|
---|
154 | inPath.BeginReading(start);
|
---|
155 | inPath.EndReading(end);
|
---|
156 |
|
---|
157 | PRUint32 size, offset = 0;
|
---|
158 | for ( ; start != end; start.advance(size)) {
|
---|
159 | const char* buf = start.get();
|
---|
160 | size = start.size_forward();
|
---|
161 | memcpy(mBuffer + offset, buf, size);
|
---|
162 | offset += size;
|
---|
163 | }
|
---|
164 | mBuffer[offset] = '\0';
|
---|
165 | }
|
---|
166 |
|
---|
167 | #pragma mark -
|
---|
168 | #pragma mark [static util funcs]
|
---|
169 |
|
---|
170 | static inline void ClearFSSpec(FSSpec& aSpec)
|
---|
171 | {
|
---|
172 | aSpec.vRefNum = 0;
|
---|
173 | aSpec.parID = 0;
|
---|
174 | aSpec.name[0] = 0;
|
---|
175 | }
|
---|
176 |
|
---|
177 |
|
---|
178 | // Simple func to map Mac OS errors into nsresults
|
---|
179 | static nsresult MacErrorMapper(OSErr inErr)
|
---|
180 | {
|
---|
181 | nsresult outErr;
|
---|
182 |
|
---|
183 | switch (inErr)
|
---|
184 | {
|
---|
185 | case noErr:
|
---|
186 | outErr = NS_OK;
|
---|
187 | break;
|
---|
188 |
|
---|
189 | case fnfErr:
|
---|
190 | outErr = NS_ERROR_FILE_NOT_FOUND;
|
---|
191 | break;
|
---|
192 |
|
---|
193 | case dupFNErr:
|
---|
194 | outErr = NS_ERROR_FILE_ALREADY_EXISTS;
|
---|
195 | break;
|
---|
196 |
|
---|
197 | case dskFulErr:
|
---|
198 | outErr = NS_ERROR_FILE_DISK_FULL;
|
---|
199 | break;
|
---|
200 |
|
---|
201 | case fLckdErr:
|
---|
202 | outErr = NS_ERROR_FILE_IS_LOCKED;
|
---|
203 | break;
|
---|
204 |
|
---|
205 | // Can't find good map for some
|
---|
206 | case bdNamErr:
|
---|
207 | outErr = NS_ERROR_FAILURE;
|
---|
208 | break;
|
---|
209 |
|
---|
210 | default:
|
---|
211 | outErr = NS_ERROR_FAILURE;
|
---|
212 | break;
|
---|
213 | }
|
---|
214 | return outErr;
|
---|
215 | }
|
---|
216 |
|
---|
217 |
|
---|
218 |
|
---|
219 | /*----------------------------------------------------------------------------
|
---|
220 | IsEqualFSSpec
|
---|
221 |
|
---|
222 | Compare two canonical FSSpec records.
|
---|
223 |
|
---|
224 | Entry: file1 = pointer to first FSSpec record.
|
---|
225 | file2 = pointer to second FSSpec record.
|
---|
226 |
|
---|
227 | Exit: function result = true if the FSSpec records are equal.
|
---|
228 | ----------------------------------------------------------------------------*/
|
---|
229 |
|
---|
230 | static PRBool IsEqualFSSpec(const FSSpec& file1, const FSSpec& file2)
|
---|
231 | {
|
---|
232 | return
|
---|
233 | file1.vRefNum == file2.vRefNum &&
|
---|
234 | file1.parID == file2.parID &&
|
---|
235 | EqualString(file1.name, file2.name, false, true);
|
---|
236 | }
|
---|
237 |
|
---|
238 |
|
---|
239 | /*----------------------------------------------------------------------------
|
---|
240 | GetParentFolderSpec
|
---|
241 |
|
---|
242 | Given an FSSpec to a (possibly non-existent) file, get an FSSpec for its
|
---|
243 | parent directory.
|
---|
244 |
|
---|
245 | ----------------------------------------------------------------------------*/
|
---|
246 |
|
---|
247 | static OSErr GetParentFolderSpec(const FSSpec& fileSpec, FSSpec& parentDirSpec)
|
---|
248 | {
|
---|
249 | CInfoPBRec pBlock = {0};
|
---|
250 | OSErr err = noErr;
|
---|
251 |
|
---|
252 | parentDirSpec.name[0] = 0;
|
---|
253 |
|
---|
254 | pBlock.dirInfo.ioVRefNum = fileSpec.vRefNum;
|
---|
255 | pBlock.dirInfo.ioDrDirID = fileSpec.parID;
|
---|
256 | pBlock.dirInfo.ioNamePtr = (StringPtr)parentDirSpec.name;
|
---|
257 | pBlock.dirInfo.ioFDirIndex = -1; //get info on parID
|
---|
258 | err = PBGetCatInfoSync(&pBlock);
|
---|
259 | if (err != noErr) return err;
|
---|
260 |
|
---|
261 | parentDirSpec.vRefNum = fileSpec.vRefNum;
|
---|
262 | parentDirSpec.parID = pBlock.dirInfo.ioDrParID;
|
---|
263 |
|
---|
264 | return err;
|
---|
265 | }
|
---|
266 |
|
---|
267 |
|
---|
268 | /*----------------------------------------------------------------------------
|
---|
269 | VolHasDesktopDB
|
---|
270 |
|
---|
271 | Check to see if a volume supports the new desktop database.
|
---|
272 |
|
---|
273 | Entry: vRefNum = vol ref num of volumn
|
---|
274 |
|
---|
275 | Exit: function result = error code.
|
---|
276 | *hasDesktop = true if volume has the new desktop database.
|
---|
277 | ----------------------------------------------------------------------------*/
|
---|
278 |
|
---|
279 | static OSErr VolHasDesktopDB (short vRefNum, Boolean *hasDesktop)
|
---|
280 | {
|
---|
281 | HParamBlockRec pb;
|
---|
282 | GetVolParmsInfoBuffer info;
|
---|
283 | OSErr err = noErr;
|
---|
284 |
|
---|
285 | pb.ioParam.ioCompletion = nil;
|
---|
286 | pb.ioParam.ioNamePtr = nil;
|
---|
287 | pb.ioParam.ioVRefNum = vRefNum;
|
---|
288 | pb.ioParam.ioBuffer = (Ptr)&info;
|
---|
289 | pb.ioParam.ioReqCount = sizeof(info);
|
---|
290 | err = PBHGetVolParmsSync(&pb);
|
---|
291 | *hasDesktop = err == noErr && (info.vMAttrib & (1L << bHasDesktopMgr)) != 0;
|
---|
292 | return err;
|
---|
293 | }
|
---|
294 |
|
---|
295 |
|
---|
296 | /*----------------------------------------------------------------------------
|
---|
297 | GetLastModDateTime
|
---|
298 |
|
---|
299 | Get the last mod date and time of a file.
|
---|
300 |
|
---|
301 | Entry: fSpec = pointer to file spec.
|
---|
302 |
|
---|
303 | Exit: function result = error code.
|
---|
304 | *lastModDateTime = last mod date and time.
|
---|
305 | ----------------------------------------------------------------------------*/
|
---|
306 |
|
---|
307 | static OSErr GetLastModDateTime(const FSSpec *fSpec, unsigned long *lastModDateTime)
|
---|
308 | {
|
---|
309 | CInfoPBRec pBlock;
|
---|
310 | OSErr err = noErr;
|
---|
311 |
|
---|
312 | pBlock.hFileInfo.ioNamePtr = (StringPtr)fSpec->name;
|
---|
313 | pBlock.hFileInfo.ioVRefNum = fSpec->vRefNum;
|
---|
314 | pBlock.hFileInfo.ioFDirIndex = 0;
|
---|
315 | pBlock.hFileInfo.ioDirID = fSpec->parID;
|
---|
316 | err = PBGetCatInfoSync(&pBlock);
|
---|
317 | if (err != noErr) return err;
|
---|
318 | *lastModDateTime = pBlock.hFileInfo.ioFlMdDat;
|
---|
319 | return noErr;
|
---|
320 | }
|
---|
321 |
|
---|
322 |
|
---|
323 | /*----------------------------------------------------------------------------
|
---|
324 | FindAppOnVolume
|
---|
325 |
|
---|
326 | Find an application on a volume.
|
---|
327 |
|
---|
328 | Entry: sig = application signature.
|
---|
329 | vRefNum = vol ref num
|
---|
330 |
|
---|
331 | Exit: function result = error code
|
---|
332 | = afpItemNotFound if app not found on vol.
|
---|
333 | *file = file spec for application on volume.
|
---|
334 | ----------------------------------------------------------------------------*/
|
---|
335 |
|
---|
336 | static OSErr FindAppOnVolume (OSType sig, short vRefNum, FSSpec *file)
|
---|
337 | {
|
---|
338 | DTPBRec pb;
|
---|
339 | OSErr err = noErr;
|
---|
340 | short ioDTRefNum, i;
|
---|
341 | FInfo fInfo;
|
---|
342 | FSSpec candidate;
|
---|
343 | unsigned long lastModDateTime, maxLastModDateTime;
|
---|
344 |
|
---|
345 | memset(&pb, 0, sizeof(DTPBRec));
|
---|
346 | pb.ioCompletion = nil;
|
---|
347 | pb.ioVRefNum = vRefNum;
|
---|
348 | pb.ioNamePtr = nil;
|
---|
349 | err = PBDTGetPath(&pb);
|
---|
350 | if (err != noErr) return err;
|
---|
351 | ioDTRefNum = pb.ioDTRefNum;
|
---|
352 |
|
---|
353 | memset(&pb, 0, sizeof(DTPBRec));
|
---|
354 | pb.ioCompletion = nil;
|
---|
355 | pb.ioIndex = 0;
|
---|
356 | pb.ioFileCreator = sig;
|
---|
357 | pb.ioNamePtr = file->name;
|
---|
358 | pb.ioDTRefNum = ioDTRefNum;
|
---|
359 | err = PBDTGetAPPLSync(&pb);
|
---|
360 |
|
---|
361 | if (err == fnfErr || err == paramErr) return afpItemNotFound;
|
---|
362 | if (err != noErr) return err;
|
---|
363 |
|
---|
364 | file->vRefNum = vRefNum;
|
---|
365 | file->parID = pb.ioAPPLParID;
|
---|
366 |
|
---|
367 | err = FSpGetFInfo(file, &fInfo);
|
---|
368 | if (err == noErr) return noErr;
|
---|
369 |
|
---|
370 | i = 1;
|
---|
371 | maxLastModDateTime = 0;
|
---|
372 | while (true)
|
---|
373 | {
|
---|
374 | memset(&pb, 0, sizeof(DTPBRec));
|
---|
375 | pb.ioCompletion = nil;
|
---|
376 | pb.ioIndex = i;
|
---|
377 | pb.ioFileCreator = sig;
|
---|
378 | pb.ioNamePtr = candidate.name;
|
---|
379 | pb.ioDTRefNum = ioDTRefNum;
|
---|
380 | err = PBDTGetAPPLSync(&pb);
|
---|
381 | if (err != noErr) break;
|
---|
382 | candidate.vRefNum = vRefNum;
|
---|
383 | candidate.parID = pb.ioAPPLParID;
|
---|
384 | err = GetLastModDateTime(file, &lastModDateTime);
|
---|
385 | if (err == noErr) {
|
---|
386 | if (lastModDateTime > maxLastModDateTime) {
|
---|
387 | maxLastModDateTime = lastModDateTime;
|
---|
388 | *file = candidate;
|
---|
389 | }
|
---|
390 | }
|
---|
391 | i++;
|
---|
392 | }
|
---|
393 |
|
---|
394 | return maxLastModDateTime > 0 ? noErr : afpItemNotFound;
|
---|
395 | }
|
---|
396 |
|
---|
397 |
|
---|
398 | /*----------------------------------------------------------------------------
|
---|
399 | GetIndVolume
|
---|
400 |
|
---|
401 | Get a volume reference number by volume index.
|
---|
402 |
|
---|
403 | Entry: index = volume index
|
---|
404 |
|
---|
405 | Exit: function result = error code.
|
---|
406 | *vRefNum = vol ref num of indexed volume.
|
---|
407 | ----------------------------------------------------------------------------*/
|
---|
408 |
|
---|
409 | static OSErr GetIndVolume(short index, short *vRefNum)
|
---|
410 | {
|
---|
411 | HParamBlockRec pb;
|
---|
412 | Str63 volumeName;
|
---|
413 | OSErr err = noErr;
|
---|
414 |
|
---|
415 | pb.volumeParam.ioCompletion = nil;
|
---|
416 | pb.volumeParam.ioNamePtr = volumeName;
|
---|
417 | pb.volumeParam.ioVolIndex = index;
|
---|
418 |
|
---|
419 | err = PBHGetVInfoSync(&pb);
|
---|
420 |
|
---|
421 | *vRefNum = pb.volumeParam.ioVRefNum;
|
---|
422 | return err;
|
---|
423 | }
|
---|
424 |
|
---|
425 |
|
---|
426 | // Private NSPR functions
|
---|
427 | static unsigned long gJanuaryFirst1970Seconds = 0;
|
---|
428 | /*
|
---|
429 | * The geographic location and time zone information of a Mac
|
---|
430 | * are stored in extended parameter RAM. The ReadLocation
|
---|
431 | * produdure uses the geographic location record, MachineLocation,
|
---|
432 | * to read the geographic location and time zone information in
|
---|
433 | * extended parameter RAM.
|
---|
434 | *
|
---|
435 | * Because serial port and SLIP conflict with ReadXPram calls,
|
---|
436 | * we cache the call here.
|
---|
437 | *
|
---|
438 | * Caveat: this caching will give the wrong result if a session
|
---|
439 | * extend across the DST changeover time.
|
---|
440 | */
|
---|
441 |
|
---|
442 | static void MyReadLocation(MachineLocation *loc)
|
---|
443 | {
|
---|
444 | static MachineLocation storedLoc;
|
---|
445 | static Boolean didReadLocation = false;
|
---|
446 |
|
---|
447 | if (!didReadLocation) {
|
---|
448 | ReadLocation(&storedLoc);
|
---|
449 | didReadLocation = true;
|
---|
450 | }
|
---|
451 | *loc = storedLoc;
|
---|
452 | }
|
---|
453 |
|
---|
454 | static long GMTDelta(void)
|
---|
455 | {
|
---|
456 | MachineLocation loc;
|
---|
457 | long gmtDelta;
|
---|
458 |
|
---|
459 | MyReadLocation(&loc);
|
---|
460 | gmtDelta = loc.u.gmtDelta & 0x00ffffff;
|
---|
461 | if (gmtDelta & 0x00800000) { /* test sign extend bit */
|
---|
462 | gmtDelta |= 0xff000000;
|
---|
463 | }
|
---|
464 | return gmtDelta;
|
---|
465 | }
|
---|
466 |
|
---|
467 | static void MacintoshInitializeTime(void)
|
---|
468 | {
|
---|
469 | /*
|
---|
470 | * The NSPR epoch is midnight, Jan. 1, 1970 GMT.
|
---|
471 | *
|
---|
472 | * At midnight Jan. 1, 1970 GMT, the local time was
|
---|
473 | * midnight Jan. 1, 1970 + GMTDelta().
|
---|
474 | *
|
---|
475 | * Midnight Jan. 1, 1970 is 86400 * (365 * (1970 - 1904) + 17)
|
---|
476 | * = 2082844800 seconds since the Mac epoch.
|
---|
477 | * (There were 17 leap years from 1904 to 1970.)
|
---|
478 | *
|
---|
479 | * So the NSPR epoch is 2082844800 + GMTDelta() seconds since
|
---|
480 | * the Mac epoch. Whew! :-)
|
---|
481 | */
|
---|
482 | gJanuaryFirst1970Seconds = 2082844800 + GMTDelta();
|
---|
483 | }
|
---|
484 |
|
---|
485 | static nsresult ConvertMacTimeToMilliseconds( PRInt64* aLastModifiedTime, PRUint32 timestamp )
|
---|
486 | {
|
---|
487 | if ( gJanuaryFirst1970Seconds == 0)
|
---|
488 | MacintoshInitializeTime();
|
---|
489 | timestamp -= gJanuaryFirst1970Seconds;
|
---|
490 | PRTime usecPerSec, dateInMicroSeconds;
|
---|
491 | LL_I2L(dateInMicroSeconds, timestamp);
|
---|
492 | LL_I2L(usecPerSec, PR_MSEC_PER_SEC);
|
---|
493 | LL_MUL(*aLastModifiedTime, usecPerSec, dateInMicroSeconds);
|
---|
494 | return NS_OK;
|
---|
495 | }
|
---|
496 |
|
---|
497 | static nsresult ConvertMillisecondsToMacTime(PRInt64 aTime, PRUint32 *aOutMacTime)
|
---|
498 | {
|
---|
499 | NS_ENSURE_ARG( aOutMacTime );
|
---|
500 |
|
---|
501 | PRTime usecPerSec, dateInSeconds;
|
---|
502 | dateInSeconds = LL_ZERO;
|
---|
503 |
|
---|
504 | LL_I2L(usecPerSec, PR_MSEC_PER_SEC);
|
---|
505 | LL_DIV(dateInSeconds, aTime, usecPerSec); // dateInSeconds = aTime/1,000
|
---|
506 | LL_L2UI(*aOutMacTime, dateInSeconds);
|
---|
507 | *aOutMacTime += 2082844800; // date + Mac epoch
|
---|
508 |
|
---|
509 | return NS_OK;
|
---|
510 | }
|
---|
511 |
|
---|
512 | static void myPLstrcpy(Str255 dst, const char* src)
|
---|
513 | {
|
---|
514 | int srcLength = strlen(src);
|
---|
515 | NS_ASSERTION(srcLength <= 255, "Oops, Str255 can't hold >255 chars");
|
---|
516 | if (srcLength > 255)
|
---|
517 | srcLength = 255;
|
---|
518 | dst[0] = srcLength;
|
---|
519 | memcpy(&dst[1], src, srcLength);
|
---|
520 | }
|
---|
521 |
|
---|
522 | static void myPLstrncpy(Str255 dst, const char* src, int inMax)
|
---|
523 | {
|
---|
524 | int srcLength = strlen(src);
|
---|
525 | if (srcLength > inMax)
|
---|
526 | srcLength = inMax;
|
---|
527 | dst[0] = srcLength;
|
---|
528 | memcpy(&dst[1], src, srcLength);
|
---|
529 | }
|
---|
530 |
|
---|
531 | /*
|
---|
532 | NS_TruncNodeName
|
---|
533 |
|
---|
534 | Utility routine to do a mid-trunc on a potential file name so that it is
|
---|
535 | no longer than 31 characters. Until we move to the HFS+ APIs we need this
|
---|
536 | to come up with legal Mac file names.
|
---|
537 |
|
---|
538 | Entry: aNode = initial file name
|
---|
539 | outBuf = scratch buffer for the truncated name (MUST be >= 32 characters)
|
---|
540 |
|
---|
541 | Exit: function result = pointer to truncated name. Will be either aNode or outBuf.
|
---|
542 |
|
---|
543 | */
|
---|
544 | const char* NS_TruncNodeName(const char *aNode, char *outBuf)
|
---|
545 | {
|
---|
546 | PRUint32 nodeLen;
|
---|
547 | if ((nodeLen = strlen(aNode)) > 31)
|
---|
548 | {
|
---|
549 | static PRBool sInitialized = PR_FALSE;
|
---|
550 | static CharByteTable sTable;
|
---|
551 | // Init to "..." in case we fail to get the ellipsis token
|
---|
552 | static char sEllipsisTokenStr[4] = { '.', '.', '.', 0 };
|
---|
553 | static PRUint8 sEllipsisTokenLen = 3;
|
---|
554 |
|
---|
555 | if (!sInitialized)
|
---|
556 | {
|
---|
557 | // Entries in the table are:
|
---|
558 | // 0 == 1 byte char
|
---|
559 | // 1 == 2 byte char
|
---|
560 | FillParseTable(sTable, smSystemScript);
|
---|
561 |
|
---|
562 | Handle itl4ResHandle = nsnull;
|
---|
563 | long offset, len;
|
---|
564 | ::GetIntlResourceTable(smSystemScript, smUnTokenTable, &itl4ResHandle, &offset, &len);
|
---|
565 | if (itl4ResHandle)
|
---|
566 | {
|
---|
567 | UntokenTable *untokenTableRec = (UntokenTable *)(*itl4ResHandle + offset);
|
---|
568 | if (untokenTableRec->lastToken >= tokenEllipsis)
|
---|
569 | {
|
---|
570 | offset += untokenTableRec->index[tokenEllipsis];
|
---|
571 | char *tokenStr = (*itl4ResHandle + offset);
|
---|
572 | sEllipsisTokenLen = tokenStr[0];
|
---|
573 | memcpy(sEllipsisTokenStr, &tokenStr[1], sEllipsisTokenLen);
|
---|
574 | }
|
---|
575 | ::ReleaseResource(itl4ResHandle);
|
---|
576 | }
|
---|
577 | sInitialized = PR_TRUE;
|
---|
578 | }
|
---|
579 |
|
---|
580 | PRInt32 halfLen = (31 - sEllipsisTokenLen) / 2;
|
---|
581 | PRInt32 charSize = 0, srcPos, destPos;
|
---|
582 | for (srcPos = 0; srcPos + charSize <= halfLen; srcPos += charSize)
|
---|
583 | charSize = sTable[aNode[srcPos]] ? 2 : 1;
|
---|
584 |
|
---|
585 | memcpy(outBuf, aNode, srcPos);
|
---|
586 | memcpy(outBuf + srcPos, sEllipsisTokenStr, sEllipsisTokenLen);
|
---|
587 | destPos = srcPos + sEllipsisTokenLen;
|
---|
588 |
|
---|
589 | for (; srcPos < nodeLen - halfLen; srcPos += charSize)
|
---|
590 | charSize = sTable[aNode[srcPos]] ? 2 : 1;
|
---|
591 |
|
---|
592 | memcpy(outBuf + destPos, aNode + srcPos, nodeLen - srcPos);
|
---|
593 | destPos += (nodeLen - srcPos);
|
---|
594 | outBuf[destPos] = '\0';
|
---|
595 | return outBuf;
|
---|
596 | }
|
---|
597 | return aNode;
|
---|
598 | }
|
---|
599 |
|
---|
600 | /**
|
---|
601 | * HFSPlusGetRawPath returns the path for an FSSpec as a unicode string.
|
---|
602 | *
|
---|
603 | * The reason for this routine instead of just calling FSRefMakePath is
|
---|
604 | * (1) inSpec does not have to exist
|
---|
605 | * (2) FSRefMakePath uses '/' as the separator under OSX and ':' under OS9
|
---|
606 | */
|
---|
607 | static OSErr HFSPlusGetRawPath(const FSSpec& inSpec, nsAString& outStr)
|
---|
608 | {
|
---|
609 | OSErr err;
|
---|
610 | nsAutoString ucPathString;
|
---|
611 |
|
---|
612 | outStr.Truncate(0);
|
---|
613 |
|
---|
614 | FSRef nodeRef;
|
---|
615 | FSCatalogInfo catalogInfo;
|
---|
616 | catalogInfo.parentDirID = 0;
|
---|
617 | err = ::FSpMakeFSRef(&inSpec, &nodeRef);
|
---|
618 |
|
---|
619 | if (err == fnfErr) {
|
---|
620 | FSSpec parentDirSpec;
|
---|
621 | err = GetParentFolderSpec(inSpec, parentDirSpec);
|
---|
622 | if (err == noErr) {
|
---|
623 | const char *startPtr = (const char*)&inSpec.name[1];
|
---|
624 | NS_CopyNativeToUnicode(Substring(startPtr, startPtr + PRUint32(inSpec.name[0])), outStr);
|
---|
625 | err = ::FSpMakeFSRef(&parentDirSpec, &nodeRef);
|
---|
626 | }
|
---|
627 | }
|
---|
628 |
|
---|
629 | while (err == noErr && catalogInfo.parentDirID != fsRtParID) {
|
---|
630 | HFSUniStr255 nodeName;
|
---|
631 | FSRef parentRef;
|
---|
632 | err = ::FSGetCatalogInfo(&nodeRef,
|
---|
633 | kFSCatInfoNodeFlags + kFSCatInfoParentDirID,
|
---|
634 | &catalogInfo,
|
---|
635 | &nodeName,
|
---|
636 | nsnull,
|
---|
637 | &parentRef);
|
---|
638 | if (err == noErr)
|
---|
639 | {
|
---|
640 | if (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask)
|
---|
641 | nodeName.unicode[nodeName.length++] = PRUnichar(':');
|
---|
642 | const PRUnichar* nodeNameUni = (const PRUnichar*) nodeName.unicode;
|
---|
643 | outStr.Insert(Substring(nodeNameUni, nodeNameUni + nodeName.length), 0);
|
---|
644 | nodeRef = parentRef;
|
---|
645 | }
|
---|
646 | }
|
---|
647 | return err;
|
---|
648 | }
|
---|
649 |
|
---|
650 |
|
---|
651 | // The R**co FSSpec resolver -
|
---|
652 | // it slices, it dices, it juliannes fries and it even creates FSSpecs out of whatever you feed it
|
---|
653 | // This function will take a path and a starting FSSpec and generate a FSSpec to represent
|
---|
654 | // the target of the two. If the intial FSSpec is null the path alone will be resolved
|
---|
655 | static OSErr ResolvePathAndSpec(const char * filePath, FSSpec *inSpec, PRBool createDirs, FSSpec *outSpec)
|
---|
656 | {
|
---|
657 | OSErr err = noErr;
|
---|
658 | size_t inLength = strlen(filePath);
|
---|
659 | Boolean isRelative = (filePath && inSpec);
|
---|
660 | FSSpec tempSpec;
|
---|
661 | Str255 ppath;
|
---|
662 | Boolean isDirectory;
|
---|
663 |
|
---|
664 | if (isRelative && inSpec)
|
---|
665 | {
|
---|
666 | outSpec->vRefNum = inSpec->vRefNum;
|
---|
667 | outSpec->parID = inSpec->parID;
|
---|
668 |
|
---|
669 | if (inSpec->name[0] != 0)
|
---|
670 | {
|
---|
671 | long theDirID;
|
---|
672 |
|
---|
673 | err = FSpGetDirectoryID(inSpec, &theDirID, &isDirectory);
|
---|
674 |
|
---|
675 | if (err == noErr && isDirectory)
|
---|
676 | outSpec->parID = theDirID;
|
---|
677 | else if (err == fnfErr && createDirs)
|
---|
678 | {
|
---|
679 | err = FSpDirCreate(inSpec, smCurrentScript, &theDirID);
|
---|
680 | if (err == noErr)
|
---|
681 | outSpec->parID = theDirID;
|
---|
682 | else if (err == fnfErr)
|
---|
683 | err = dirNFErr;
|
---|
684 | }
|
---|
685 | }
|
---|
686 | }
|
---|
687 | else
|
---|
688 | {
|
---|
689 | outSpec->vRefNum = 0;
|
---|
690 | outSpec->parID = 0;
|
---|
691 | }
|
---|
692 |
|
---|
693 | if (err)
|
---|
694 | return err;
|
---|
695 |
|
---|
696 | // Try making an FSSpec from the path
|
---|
697 | if (inLength < 255)
|
---|
698 | {
|
---|
699 | // Use tempSpec as dest because if FSMakeFSSpec returns dirNFErr, it
|
---|
700 | // will reset the dest spec and we'll lose what we determined above.
|
---|
701 |
|
---|
702 | myPLstrcpy(ppath, filePath);
|
---|
703 | err = ::FSMakeFSSpec(outSpec->vRefNum, outSpec->parID, ppath, &tempSpec);
|
---|
704 | if (err == noErr || err == fnfErr)
|
---|
705 | *outSpec = tempSpec;
|
---|
706 | }
|
---|
707 | else if (!isRelative)
|
---|
708 | {
|
---|
709 | err = ::FSpLocationFromFullPath(inLength, filePath, outSpec);
|
---|
710 | }
|
---|
711 | else
|
---|
712 | { // If the path is relative and >255 characters we need to manually walk the
|
---|
713 | // path appending each node to the initial FSSpec so to reach that code we
|
---|
714 | // set the err to bdNamErr and fall into the code below
|
---|
715 | err = bdNamErr;
|
---|
716 | }
|
---|
717 |
|
---|
718 | // If we successfully created a spec then leave
|
---|
719 | if (err == noErr)
|
---|
720 | return err;
|
---|
721 |
|
---|
722 | // We get here when the directory hierarchy needs to be created or we're resolving
|
---|
723 | // a relative path >255 characters long
|
---|
724 | if (err == dirNFErr || err == bdNamErr)
|
---|
725 | {
|
---|
726 | const char* path = filePath;
|
---|
727 |
|
---|
728 | if (!isRelative) // If path is relative, we still need vRefNum & parID.
|
---|
729 | {
|
---|
730 | outSpec->vRefNum = 0;
|
---|
731 | outSpec->parID = 0;
|
---|
732 | }
|
---|
733 |
|
---|
734 | do
|
---|
735 | {
|
---|
736 | // Locate the colon that terminates the node.
|
---|
737 | // But if we've a partial path (starting with a colon), find the second one.
|
---|
738 | const char* nextColon = strchr(path + (*path == ':'), ':');
|
---|
739 | // Well, if there are no more colons, point to the end of the string.
|
---|
740 | if (!nextColon)
|
---|
741 | nextColon = path + strlen(path);
|
---|
742 |
|
---|
743 | // Make a pascal string out of this node. Include initial
|
---|
744 | // and final colon, if any!
|
---|
745 | myPLstrncpy(ppath, path, nextColon - path + 1);
|
---|
746 |
|
---|
747 | // Use this string as a relative path using the directory created
|
---|
748 | // on the previous round (or directory 0,0 on the first round).
|
---|
749 | err = ::FSMakeFSSpec(outSpec->vRefNum, outSpec->parID, ppath, outSpec);
|
---|
750 |
|
---|
751 | // If this was the leaf node, then we are done.
|
---|
752 | if (!*nextColon)
|
---|
753 | break;
|
---|
754 |
|
---|
755 | // Since there's more to go, we have to get the directory ID, which becomes
|
---|
756 | // the parID for the next round.
|
---|
757 | if (err == noErr)
|
---|
758 | {
|
---|
759 | // The directory (or perhaps a file) exists. Find its dirID.
|
---|
760 | long dirID;
|
---|
761 | err = ::FSpGetDirectoryID(outSpec, &dirID, &isDirectory);
|
---|
762 | if (!isDirectory)
|
---|
763 | err = dupFNErr; // oops! a file exists with that name.
|
---|
764 | if (err != noErr)
|
---|
765 | break; // bail if we've got an error
|
---|
766 | outSpec->parID = dirID;
|
---|
767 | }
|
---|
768 | else if ((err == fnfErr) && createDirs)
|
---|
769 | {
|
---|
770 | // If we got "file not found" and we're allowed to create directories
|
---|
771 | // then we need to create one
|
---|
772 | err = ::FSpDirCreate(outSpec, smCurrentScript, &outSpec->parID);
|
---|
773 | // For some reason, this usually returns fnfErr, even though it works.
|
---|
774 | if (err == fnfErr)
|
---|
775 | err = noErr;
|
---|
776 | }
|
---|
777 | if (err != noErr)
|
---|
778 | break;
|
---|
779 | path = nextColon; // next round
|
---|
780 | } while (true);
|
---|
781 | }
|
---|
782 |
|
---|
783 | return err;
|
---|
784 | }
|
---|
785 |
|
---|
786 |
|
---|
787 | #pragma mark -
|
---|
788 | #pragma mark [StFollowLinksState]
|
---|
789 | class StFollowLinksState
|
---|
790 | {
|
---|
791 | public:
|
---|
792 | StFollowLinksState(nsILocalFile *aFile) :
|
---|
793 | mFile(aFile)
|
---|
794 | {
|
---|
795 | NS_ASSERTION(mFile, "StFollowLinksState passed a NULL file.");
|
---|
796 | if (mFile)
|
---|
797 | mFile->GetFollowLinks(&mSavedState);
|
---|
798 | }
|
---|
799 |
|
---|
800 | StFollowLinksState(nsILocalFile *aFile, PRBool followLinksState) :
|
---|
801 | mFile(aFile)
|
---|
802 | {
|
---|
803 | NS_ASSERTION(mFile, "StFollowLinksState passed a NULL file.");
|
---|
804 | if (mFile) {
|
---|
805 | mFile->GetFollowLinks(&mSavedState);
|
---|
806 | mFile->SetFollowLinks(followLinksState);
|
---|
807 | }
|
---|
808 | }
|
---|
809 |
|
---|
810 | ~StFollowLinksState()
|
---|
811 | {
|
---|
812 | if (mFile)
|
---|
813 | mFile->SetFollowLinks(mSavedState);
|
---|
814 | }
|
---|
815 |
|
---|
816 | private:
|
---|
817 | nsCOMPtr<nsILocalFile> mFile;
|
---|
818 | PRBool mSavedState;
|
---|
819 | };
|
---|
820 |
|
---|
821 | #pragma mark -
|
---|
822 | #pragma mark [nsDirEnumerator]
|
---|
823 | class nsDirEnumerator : public nsISimpleEnumerator
|
---|
824 | {
|
---|
825 | public:
|
---|
826 |
|
---|
827 | NS_DECL_ISUPPORTS
|
---|
828 |
|
---|
829 | nsDirEnumerator()
|
---|
830 | {
|
---|
831 | }
|
---|
832 |
|
---|
833 | nsresult Init(nsILocalFileMac* parent)
|
---|
834 | {
|
---|
835 | NS_ENSURE_ARG(parent);
|
---|
836 | nsresult rv;
|
---|
837 | FSSpec fileSpec;
|
---|
838 |
|
---|
839 | rv = parent->GetFSSpec(&fileSpec);
|
---|
840 | if (NS_FAILED(rv))
|
---|
841 | return rv;
|
---|
842 |
|
---|
843 | OSErr err;
|
---|
844 | Boolean isDirectory;
|
---|
845 |
|
---|
846 | err = ::FSpGetDirectoryID(&fileSpec, &mDirID, &isDirectory);
|
---|
847 | if (err || !isDirectory)
|
---|
848 | return NS_ERROR_FILE_NOT_DIRECTORY;
|
---|
849 |
|
---|
850 | mCatInfo.hFileInfo.ioNamePtr = mItemName;
|
---|
851 | mCatInfo.hFileInfo.ioVRefNum = fileSpec.vRefNum;
|
---|
852 | mItemIndex = 1;
|
---|
853 |
|
---|
854 | return NS_OK;
|
---|
855 | }
|
---|
856 |
|
---|
857 | NS_IMETHOD HasMoreElements(PRBool *result)
|
---|
858 | {
|
---|
859 | nsresult rv = NS_OK;
|
---|
860 | if (mNext == nsnull)
|
---|
861 | {
|
---|
862 | mItemName[0] = 0;
|
---|
863 | mCatInfo.dirInfo.ioFDirIndex = mItemIndex;
|
---|
864 | mCatInfo.dirInfo.ioDrDirID = mDirID;
|
---|
865 |
|
---|
866 | OSErr err = ::PBGetCatInfoSync(&mCatInfo);
|
---|
867 | if (err == fnfErr)
|
---|
868 | {
|
---|
869 | // end of dir entries
|
---|
870 | *result = PR_FALSE;
|
---|
871 | return NS_OK;
|
---|
872 | }
|
---|
873 |
|
---|
874 | // Make a new nsILocalFile for the new element
|
---|
875 | FSSpec tempSpec;
|
---|
876 | tempSpec.vRefNum = mCatInfo.hFileInfo.ioVRefNum;
|
---|
877 | tempSpec.parID = mDirID;
|
---|
878 | ::BlockMoveData(mItemName, tempSpec.name, mItemName[0] + 1);
|
---|
879 |
|
---|
880 | rv = NS_NewLocalFileWithFSSpec(&tempSpec, PR_TRUE, getter_AddRefs(mNext));
|
---|
881 | if (NS_FAILED(rv))
|
---|
882 | return rv;
|
---|
883 | }
|
---|
884 | *result = mNext != nsnull;
|
---|
885 | return NS_OK;
|
---|
886 | }
|
---|
887 |
|
---|
888 | NS_IMETHOD GetNext(nsISupports **result)
|
---|
889 | {
|
---|
890 | NS_ENSURE_ARG_POINTER(result);
|
---|
891 | *result = nsnull;
|
---|
892 |
|
---|
893 | nsresult rv;
|
---|
894 | PRBool hasMore;
|
---|
895 | rv = HasMoreElements(&hasMore);
|
---|
896 | if (NS_FAILED(rv)) return rv;
|
---|
897 |
|
---|
898 | *result = mNext; // might return nsnull
|
---|
899 | NS_IF_ADDREF(*result);
|
---|
900 |
|
---|
901 | mNext = nsnull;
|
---|
902 | ++mItemIndex;
|
---|
903 | return NS_OK;
|
---|
904 | }
|
---|
905 |
|
---|
906 | private:
|
---|
907 | ~nsDirEnumerator() {}
|
---|
908 |
|
---|
909 | protected:
|
---|
910 | nsCOMPtr<nsILocalFileMac> mNext;
|
---|
911 |
|
---|
912 | CInfoPBRec mCatInfo;
|
---|
913 | short mItemIndex;
|
---|
914 | long mDirID;
|
---|
915 | Str63 mItemName;
|
---|
916 | };
|
---|
917 |
|
---|
918 | NS_IMPL_ISUPPORTS1(nsDirEnumerator, nsISimpleEnumerator)
|
---|
919 |
|
---|
920 | #pragma mark -
|
---|
921 |
|
---|
922 | OSType nsLocalFile::sCurrentProcessSignature = 0;
|
---|
923 | PRBool nsLocalFile::sHasHFSPlusAPIs = PR_FALSE;
|
---|
924 | PRBool nsLocalFile::sRunningOSX = PR_FALSE;
|
---|
925 |
|
---|
926 | #pragma mark [CTOR/DTOR]
|
---|
927 | nsLocalFile::nsLocalFile() :
|
---|
928 | mFollowLinks(PR_TRUE),
|
---|
929 | mFollowLinksDirty(PR_TRUE),
|
---|
930 | mSpecDirty(PR_TRUE),
|
---|
931 | mCatInfoDirty(PR_TRUE),
|
---|
932 | mType('TEXT'),
|
---|
933 | mCreator(kDefaultCreator)
|
---|
934 | {
|
---|
935 | ClearFSSpec(mSpec);
|
---|
936 | ClearFSSpec(mTargetSpec);
|
---|
937 |
|
---|
938 | InitClassStatics();
|
---|
939 | if (sCurrentProcessSignature != 0)
|
---|
940 | mCreator = sCurrentProcessSignature;
|
---|
941 | }
|
---|
942 |
|
---|
943 | nsLocalFile::nsLocalFile(const nsLocalFile& srcFile)
|
---|
944 | {
|
---|
945 | *this = srcFile;
|
---|
946 | }
|
---|
947 |
|
---|
948 | nsLocalFile::nsLocalFile(const FSSpec& aSpec, const nsACString& aAppendedPath) :
|
---|
949 | mFollowLinks(PR_TRUE),
|
---|
950 | mFollowLinksDirty(PR_TRUE),
|
---|
951 | mSpecDirty(PR_TRUE),
|
---|
952 | mSpec(aSpec),
|
---|
953 | mAppendedPath(aAppendedPath),
|
---|
954 | mCatInfoDirty(PR_TRUE),
|
---|
955 | mType('TEXT'),
|
---|
956 | mCreator(kDefaultCreator)
|
---|
957 | {
|
---|
958 | ClearFSSpec(mTargetSpec);
|
---|
959 |
|
---|
960 | InitClassStatics();
|
---|
961 | if (sCurrentProcessSignature != 0)
|
---|
962 | mCreator = sCurrentProcessSignature;
|
---|
963 | }
|
---|
964 |
|
---|
965 | nsLocalFile& nsLocalFile::operator=(const nsLocalFile& rhs)
|
---|
966 | {
|
---|
967 | mFollowLinks = rhs.mFollowLinks;
|
---|
968 | mFollowLinksDirty = rhs.mFollowLinksDirty;
|
---|
969 | mSpecDirty = rhs.mSpecDirty;
|
---|
970 | mSpec = rhs.mSpec;
|
---|
971 | mAppendedPath = rhs.mAppendedPath;
|
---|
972 | mTargetSpec = rhs.mTargetSpec;
|
---|
973 | mCatInfoDirty = rhs.mCatInfoDirty;
|
---|
974 | mType = rhs.mType;
|
---|
975 | mCreator = rhs.mCreator;
|
---|
976 |
|
---|
977 | if (!rhs.mCatInfoDirty)
|
---|
978 | mCachedCatInfo = rhs.mCachedCatInfo;
|
---|
979 |
|
---|
980 | return *this;
|
---|
981 | }
|
---|
982 |
|
---|
983 | #pragma mark -
|
---|
984 | #pragma mark [nsISupports interface implementation]
|
---|
985 |
|
---|
986 | NS_IMPL_THREADSAFE_ISUPPORTS3(nsLocalFile,
|
---|
987 | nsILocalFileMac,
|
---|
988 | nsILocalFile,
|
---|
989 | nsIFile)
|
---|
990 |
|
---|
991 | NS_METHOD
|
---|
992 | nsLocalFile::nsLocalFileConstructor(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr)
|
---|
993 | {
|
---|
994 | NS_ENSURE_ARG_POINTER(aInstancePtr);
|
---|
995 | NS_ENSURE_NO_AGGREGATION(outer);
|
---|
996 |
|
---|
997 | nsLocalFile* inst = new nsLocalFile();
|
---|
998 | if (inst == NULL)
|
---|
999 | return NS_ERROR_OUT_OF_MEMORY;
|
---|
1000 |
|
---|
1001 | nsresult rv = inst->QueryInterface(aIID, aInstancePtr);
|
---|
1002 | if (NS_FAILED(rv))
|
---|
1003 | {
|
---|
1004 | delete inst;
|
---|
1005 | return rv;
|
---|
1006 | }
|
---|
1007 | return NS_OK;
|
---|
1008 | }
|
---|
1009 |
|
---|
1010 | // This function resets any cached information about the file.
|
---|
1011 | void
|
---|
1012 | nsLocalFile::MakeDirty()
|
---|
1013 | {
|
---|
1014 | mSpecDirty = PR_TRUE;
|
---|
1015 | mFollowLinksDirty = PR_TRUE;
|
---|
1016 | mCatInfoDirty = PR_TRUE;
|
---|
1017 |
|
---|
1018 | ClearFSSpec(mTargetSpec);
|
---|
1019 | }
|
---|
1020 |
|
---|
1021 |
|
---|
1022 | /* attribute PRBool followLinks; */
|
---|
1023 | NS_IMETHODIMP
|
---|
1024 | nsLocalFile::GetFollowLinks(PRBool *aFollowLinks)
|
---|
1025 | {
|
---|
1026 | NS_ENSURE_ARG_POINTER(aFollowLinks);
|
---|
1027 | *aFollowLinks = mFollowLinks;
|
---|
1028 | return NS_OK;
|
---|
1029 | }
|
---|
1030 |
|
---|
1031 | NS_IMETHODIMP
|
---|
1032 | nsLocalFile::SetFollowLinks(PRBool aFollowLinks)
|
---|
1033 | {
|
---|
1034 | if (aFollowLinks != mFollowLinks)
|
---|
1035 | {
|
---|
1036 | mFollowLinks = aFollowLinks;
|
---|
1037 | mFollowLinksDirty = PR_TRUE;
|
---|
1038 | }
|
---|
1039 | return NS_OK;
|
---|
1040 | }
|
---|
1041 |
|
---|
1042 | NS_IMETHODIMP
|
---|
1043 | nsLocalFile::ResolveAndStat()
|
---|
1044 | {
|
---|
1045 | OSErr err = noErr;
|
---|
1046 | FSSpec resolvedSpec;
|
---|
1047 |
|
---|
1048 | // fnfErr means target spec is valid but doesn't exist.
|
---|
1049 | // If the end result is fnfErr, we're cleanly resolved.
|
---|
1050 |
|
---|
1051 | if (mSpecDirty)
|
---|
1052 | {
|
---|
1053 | if (mAppendedPath.Length())
|
---|
1054 | {
|
---|
1055 | err = ResolvePathAndSpec(mAppendedPath.get(), &mSpec, PR_FALSE, &resolvedSpec);
|
---|
1056 | if (err == noErr)
|
---|
1057 | mAppendedPath.Truncate(0);
|
---|
1058 | }
|
---|
1059 | else
|
---|
1060 | err = ::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, mSpec.name, &resolvedSpec);
|
---|
1061 | if (err == noErr)
|
---|
1062 | {
|
---|
1063 | mSpec = resolvedSpec;
|
---|
1064 | mSpecDirty = PR_FALSE;
|
---|
1065 | }
|
---|
1066 | mFollowLinksDirty = PR_TRUE;
|
---|
1067 | }
|
---|
1068 | if (mFollowLinksDirty && (err == noErr))
|
---|
1069 | {
|
---|
1070 | if (mFollowLinks)
|
---|
1071 | {
|
---|
1072 | // Resolve the alias to the original file.
|
---|
1073 | resolvedSpec = mSpec;
|
---|
1074 | Boolean resolvedWasFolder, resolvedWasAlias;
|
---|
1075 | err = ::ResolveAliasFile(&resolvedSpec, TRUE, &resolvedWasFolder, &resolvedWasAlias);
|
---|
1076 | if (err == noErr || err == fnfErr) {
|
---|
1077 | err = noErr;
|
---|
1078 | mTargetSpec = resolvedSpec;
|
---|
1079 | mFollowLinksDirty = PR_FALSE;
|
---|
1080 | }
|
---|
1081 | }
|
---|
1082 | else
|
---|
1083 | {
|
---|
1084 | mTargetSpec = mSpec;
|
---|
1085 | mFollowLinksDirty = PR_FALSE;
|
---|
1086 | }
|
---|
1087 | mCatInfoDirty = PR_TRUE;
|
---|
1088 | }
|
---|
1089 |
|
---|
1090 | return (MacErrorMapper(err));
|
---|
1091 | }
|
---|
1092 |
|
---|
1093 |
|
---|
1094 | NS_IMETHODIMP
|
---|
1095 | nsLocalFile::Clone(nsIFile **file)
|
---|
1096 | {
|
---|
1097 | // Just copy-construct ourselves
|
---|
1098 | *file = new nsLocalFile(*this);
|
---|
1099 | if (!*file)
|
---|
1100 | return NS_ERROR_OUT_OF_MEMORY;
|
---|
1101 |
|
---|
1102 | NS_ADDREF(*file);
|
---|
1103 |
|
---|
1104 | return NS_OK;
|
---|
1105 | }
|
---|
1106 |
|
---|
1107 | NS_IMETHODIMP
|
---|
1108 | nsLocalFile::InitWithNativePath(const nsACString &filePath)
|
---|
1109 | {
|
---|
1110 | // The incoming path must be a FULL path
|
---|
1111 |
|
---|
1112 | if (filePath.IsEmpty())
|
---|
1113 | return NS_ERROR_INVALID_ARG;
|
---|
1114 |
|
---|
1115 | MakeDirty();
|
---|
1116 |
|
---|
1117 | // If it starts with a colon, it's invalid
|
---|
1118 | if (filePath.First() == ':')
|
---|
1119 | return NS_ERROR_FILE_UNRECOGNIZED_PATH;
|
---|
1120 |
|
---|
1121 | nsPathParser parser(filePath);
|
---|
1122 | OSErr err;
|
---|
1123 | Str255 pascalNode;
|
---|
1124 | FSSpec nodeSpec;
|
---|
1125 |
|
---|
1126 | const char *root = parser.First();
|
---|
1127 | if (root == nsnull)
|
---|
1128 | return NS_ERROR_FILE_UNRECOGNIZED_PATH;
|
---|
1129 |
|
---|
1130 | // The first component must be an existing volume
|
---|
1131 | myPLstrcpy(pascalNode, root);
|
---|
1132 | pascalNode[++pascalNode[0]] = ':';
|
---|
1133 | err = ::FSMakeFSSpec(0, 0, pascalNode, &nodeSpec);
|
---|
1134 | if (err)
|
---|
1135 | return NS_ERROR_FILE_UNRECOGNIZED_PATH;
|
---|
1136 |
|
---|
1137 | // Build as much of a spec as possible from the rest of the path
|
---|
1138 | // What doesn't exist will be left over in mAppendedPath
|
---|
1139 | const char *nextNode;
|
---|
1140 | while ((nextNode = parser.Next()) != nsnull) {
|
---|
1141 | long dirID;
|
---|
1142 | Boolean isDir;
|
---|
1143 | err = ::FSpGetDirectoryID(&nodeSpec, &dirID, &isDir);
|
---|
1144 | if (err || !isDir)
|
---|
1145 | break;
|
---|
1146 | myPLstrcpy(pascalNode, nextNode);
|
---|
1147 | err = ::FSMakeFSSpec(nodeSpec.vRefNum, dirID, pascalNode, &nodeSpec);
|
---|
1148 | if (err == fnfErr)
|
---|
1149 | break;
|
---|
1150 | }
|
---|
1151 | mSpec = nodeSpec;
|
---|
1152 | mAppendedPath = parser.Remainder();
|
---|
1153 |
|
---|
1154 | return NS_OK;
|
---|
1155 | }
|
---|
1156 |
|
---|
1157 | NS_IMETHODIMP
|
---|
1158 | nsLocalFile::InitWithPath(const nsAString &filePath)
|
---|
1159 | {
|
---|
1160 | nsresult rv;
|
---|
1161 | nsCAutoString fsStr;
|
---|
1162 |
|
---|
1163 | if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(filePath, fsStr)))
|
---|
1164 | rv = InitWithNativePath(fsStr);
|
---|
1165 |
|
---|
1166 | return rv;
|
---|
1167 | }
|
---|
1168 |
|
---|
1169 | NS_IMETHODIMP
|
---|
1170 | nsLocalFile::InitWithFile(nsILocalFile *aFile)
|
---|
1171 | {
|
---|
1172 | NS_ENSURE_ARG(aFile);
|
---|
1173 | nsLocalFile *asLocalFile = dynamic_cast<nsLocalFile*>(aFile);
|
---|
1174 | if (!asLocalFile)
|
---|
1175 | return NS_ERROR_NO_INTERFACE; // Well, sort of.
|
---|
1176 | *this = *asLocalFile;
|
---|
1177 | return NS_OK;
|
---|
1178 | }
|
---|
1179 |
|
---|
1180 | NS_IMETHODIMP
|
---|
1181 | nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval)
|
---|
1182 | {
|
---|
1183 | // Macintosh doesn't really have mode bits, just drop them
|
---|
1184 | #pragma unused (mode)
|
---|
1185 |
|
---|
1186 | NS_ENSURE_ARG(_retval);
|
---|
1187 |
|
---|
1188 | nsresult rv = NS_OK;
|
---|
1189 | FSSpec spec;
|
---|
1190 | OSErr err = noErr;
|
---|
1191 |
|
---|
1192 | rv = ResolveAndStat();
|
---|
1193 | if (rv == NS_ERROR_FILE_NOT_FOUND && (flags & PR_CREATE_FILE))
|
---|
1194 | rv = NS_OK;
|
---|
1195 |
|
---|
1196 | if (flags & PR_CREATE_FILE) {
|
---|
1197 | rv = Create(nsIFile::NORMAL_FILE_TYPE, 0);
|
---|
1198 | /* If opening with the PR_EXCL flag the existence of the file prior to opening is an error */
|
---|
1199 | if ((flags & PR_EXCL) && (rv == NS_ERROR_FILE_ALREADY_EXISTS))
|
---|
1200 | return rv;
|
---|
1201 | }
|
---|
1202 |
|
---|
1203 | rv = GetFSSpec(&spec);
|
---|
1204 | if (NS_FAILED(rv))
|
---|
1205 | return rv;
|
---|
1206 |
|
---|
1207 | SInt8 perm;
|
---|
1208 | if (flags & PR_RDWR)
|
---|
1209 | perm = fsRdWrPerm;
|
---|
1210 | else if (flags & PR_WRONLY)
|
---|
1211 | perm = fsWrPerm;
|
---|
1212 | else
|
---|
1213 | perm = fsRdPerm;
|
---|
1214 |
|
---|
1215 | short refnum;
|
---|
1216 | err = ::FSpOpenDF(&spec, perm, &refnum);
|
---|
1217 |
|
---|
1218 | if (err == noErr && (flags & PR_TRUNCATE))
|
---|
1219 | err = ::SetEOF(refnum, 0);
|
---|
1220 | if (err == noErr && (flags & PR_APPEND))
|
---|
1221 | err = ::SetFPos(refnum, fsFromLEOF, 0);
|
---|
1222 | if (err != noErr)
|
---|
1223 | return MacErrorMapper(err);
|
---|
1224 |
|
---|
1225 | if ((*_retval = PR_ImportFile(refnum)) == 0)
|
---|
1226 | return NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_FILES,(PR_GetError() & 0xFFFF));
|
---|
1227 |
|
---|
1228 | return NS_OK;
|
---|
1229 | }
|
---|
1230 |
|
---|
1231 | NS_IMETHODIMP
|
---|
1232 | nsLocalFile::OpenANSIFileDesc(const char *mode, FILE * *_retval)
|
---|
1233 | {
|
---|
1234 | NS_ENSURE_ARG(mode);
|
---|
1235 | NS_ENSURE_ARG_POINTER(_retval);
|
---|
1236 |
|
---|
1237 | nsresult rv;
|
---|
1238 | FSSpec spec;
|
---|
1239 |
|
---|
1240 | rv = ResolveAndStat();
|
---|
1241 | if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND)
|
---|
1242 | return rv;
|
---|
1243 |
|
---|
1244 | if (mode[0] == 'w' || mode[0] == 'a') // Create if it doesn't exist
|
---|
1245 | {
|
---|
1246 | if (rv == NS_ERROR_FILE_NOT_FOUND) {
|
---|
1247 | mType = (mode[1] == 'b') ? 'BiNA' : 'TEXT';
|
---|
1248 | rv = Create(nsIFile::NORMAL_FILE_TYPE, 0);
|
---|
1249 | if (NS_FAILED(rv))
|
---|
1250 | return rv;
|
---|
1251 | }
|
---|
1252 | }
|
---|
1253 |
|
---|
1254 | rv = GetFSSpec(&spec);
|
---|
1255 | if (NS_FAILED(rv))
|
---|
1256 | return rv;
|
---|
1257 |
|
---|
1258 | #ifdef MACOSX
|
---|
1259 | // FSp_fopen() doesn't exist under macosx :-(
|
---|
1260 | nsXPIDLCString ourPath;
|
---|
1261 | rv = GetPath(getter_Copies(ourPath));
|
---|
1262 | if (NS_FAILED(rv))
|
---|
1263 | return rv;
|
---|
1264 | *_retval = fopen(ourPath, mode);
|
---|
1265 | #else
|
---|
1266 | *_retval = FSp_fopen(&spec, mode);
|
---|
1267 | #endif
|
---|
1268 |
|
---|
1269 | if (*_retval)
|
---|
1270 | return NS_OK;
|
---|
1271 |
|
---|
1272 | return NS_ERROR_FAILURE;
|
---|
1273 | }
|
---|
1274 |
|
---|
1275 |
|
---|
1276 | NS_IMETHODIMP
|
---|
1277 | nsLocalFile::Create(PRUint32 type, PRUint32 attributes)
|
---|
1278 | {
|
---|
1279 | OSErr err;
|
---|
1280 |
|
---|
1281 | if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE)
|
---|
1282 | return NS_ERROR_FILE_UNKNOWN_TYPE;
|
---|
1283 |
|
---|
1284 | FSSpec newSpec;
|
---|
1285 |
|
---|
1286 | if (mAppendedPath.Length())
|
---|
1287 | { // We've got an FSSpec and an appended path so pass 'em both to ResolvePathAndSpec
|
---|
1288 | err = ResolvePathAndSpec(mAppendedPath.get(), &mSpec, PR_TRUE, &newSpec);
|
---|
1289 | }
|
---|
1290 | else
|
---|
1291 | {
|
---|
1292 | err = ::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, mSpec.name, &newSpec);
|
---|
1293 | }
|
---|
1294 |
|
---|
1295 | if (err != noErr && err != fnfErr)
|
---|
1296 | return (MacErrorMapper(err));
|
---|
1297 |
|
---|
1298 | switch (type)
|
---|
1299 | {
|
---|
1300 | case NORMAL_FILE_TYPE:
|
---|
1301 | SetOSTypeAndCreatorFromExtension();
|
---|
1302 | err = ::FSpCreate(&newSpec, mCreator, mType, smCurrentScript);
|
---|
1303 | break;
|
---|
1304 |
|
---|
1305 | case DIRECTORY_TYPE:
|
---|
1306 | {
|
---|
1307 | long newDirID;
|
---|
1308 | err = ::FSpDirCreate(&newSpec, smCurrentScript, &newDirID);
|
---|
1309 | // For some reason, this usually returns fnfErr, even though it works.
|
---|
1310 | if (err == fnfErr)
|
---|
1311 | err = noErr;
|
---|
1312 | }
|
---|
1313 | break;
|
---|
1314 |
|
---|
1315 | default:
|
---|
1316 | return NS_ERROR_FILE_UNKNOWN_TYPE;
|
---|
1317 | break;
|
---|
1318 | }
|
---|
1319 |
|
---|
1320 | if (err == noErr)
|
---|
1321 | {
|
---|
1322 | mSpec = mTargetSpec = newSpec;
|
---|
1323 | mAppendedPath.Truncate(0);
|
---|
1324 | }
|
---|
1325 |
|
---|
1326 | return (MacErrorMapper(err));
|
---|
1327 | }
|
---|
1328 |
|
---|
1329 | NS_IMETHODIMP
|
---|
1330 | nsLocalFile::AppendNative(const nsACString &aNode)
|
---|
1331 | {
|
---|
1332 | if (aNode.IsEmpty())
|
---|
1333 | return NS_OK;
|
---|
1334 |
|
---|
1335 | nsACString::const_iterator start, end;
|
---|
1336 | aNode.BeginReading(start);
|
---|
1337 | aNode.EndReading(end);
|
---|
1338 | if (FindCharInReadable(':', start, end))
|
---|
1339 | return NS_ERROR_FILE_UNRECOGNIZED_PATH;
|
---|
1340 |
|
---|
1341 | MakeDirty();
|
---|
1342 |
|
---|
1343 | char truncBuffer[32];
|
---|
1344 | const char *node = NS_TruncNodeName(PromiseFlatCString(aNode).get(), truncBuffer);
|
---|
1345 |
|
---|
1346 | if (!mAppendedPath.Length())
|
---|
1347 | {
|
---|
1348 | OSErr err;
|
---|
1349 | Boolean resolvedWasFolder, resolvedWasAlias;
|
---|
1350 | err = ::ResolveAliasFile(&mSpec, TRUE, &resolvedWasFolder, &resolvedWasAlias);
|
---|
1351 | if (err == noErr)
|
---|
1352 | {
|
---|
1353 | long dirID;
|
---|
1354 | Boolean isDir;
|
---|
1355 |
|
---|
1356 | if (!resolvedWasFolder)
|
---|
1357 | return NS_ERROR_FILE_NOT_DIRECTORY;
|
---|
1358 | if ((err = ::FSpGetDirectoryID(&mSpec, &dirID, &isDir)) != noErr)
|
---|
1359 | return MacErrorMapper(err);
|
---|
1360 |
|
---|
1361 | FSSpec childSpec;
|
---|
1362 | Str255 pascalNode;
|
---|
1363 | myPLstrcpy(pascalNode, node);
|
---|
1364 | err = ::FSMakeFSSpec(mSpec.vRefNum, dirID, pascalNode, &childSpec);
|
---|
1365 | if (err && err != fnfErr)
|
---|
1366 | return MacErrorMapper(err);
|
---|
1367 | mSpec = childSpec;
|
---|
1368 | }
|
---|
1369 | else if (err == fnfErr)
|
---|
1370 | mAppendedPath.Assign(node);
|
---|
1371 | else
|
---|
1372 | return MacErrorMapper(err);
|
---|
1373 | }
|
---|
1374 | else
|
---|
1375 | {
|
---|
1376 | if (mAppendedPath.First() != ':')
|
---|
1377 | mAppendedPath.Insert(':', 0);
|
---|
1378 | mAppendedPath.Append(":");
|
---|
1379 | mAppendedPath.Append(node);
|
---|
1380 | }
|
---|
1381 |
|
---|
1382 | return NS_OK;
|
---|
1383 | }
|
---|
1384 |
|
---|
1385 | NS_IMETHODIMP
|
---|
1386 | nsLocalFile::Append(const nsAString &node)
|
---|
1387 | {
|
---|
1388 | nsresult rv;
|
---|
1389 | nsCAutoString fsStr;
|
---|
1390 |
|
---|
1391 | if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(node, fsStr)))
|
---|
1392 | rv = AppendNative(fsStr);
|
---|
1393 |
|
---|
1394 | return rv;
|
---|
1395 | }
|
---|
1396 |
|
---|
1397 | NS_IMETHODIMP
|
---|
1398 | nsLocalFile::AppendRelativeNativePath(const nsACString &relPath)
|
---|
1399 | {
|
---|
1400 | if (relPath.IsEmpty())
|
---|
1401 | return NS_ERROR_INVALID_ARG;
|
---|
1402 |
|
---|
1403 | nsresult rv;
|
---|
1404 | nsPathParser parser(relPath);
|
---|
1405 | const char* node = parser.First();
|
---|
1406 |
|
---|
1407 | while (node)
|
---|
1408 | {
|
---|
1409 | if (NS_FAILED(rv = AppendNative(nsDependentCString(node))))
|
---|
1410 | return rv;
|
---|
1411 | node = parser.Next();
|
---|
1412 | }
|
---|
1413 |
|
---|
1414 | return NS_OK;
|
---|
1415 | }
|
---|
1416 |
|
---|
1417 | NS_IMETHODIMP
|
---|
1418 | nsLocalFile::AppendRelativePath(const nsAString &relPath)
|
---|
1419 | {
|
---|
1420 | nsresult rv;
|
---|
1421 | nsCAutoString fsStr;
|
---|
1422 |
|
---|
1423 | if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(relPath, fsStr)))
|
---|
1424 | rv = AppendRelativeNativePath(fsStr);
|
---|
1425 |
|
---|
1426 | return rv;
|
---|
1427 | }
|
---|
1428 |
|
---|
1429 | NS_IMETHODIMP
|
---|
1430 | nsLocalFile::GetNativeLeafName(nsACString &aLeafName)
|
---|
1431 | {
|
---|
1432 | aLeafName.Truncate();
|
---|
1433 |
|
---|
1434 | // See if we've had a path appended
|
---|
1435 | if (mAppendedPath.Length())
|
---|
1436 | {
|
---|
1437 | const char* temp = mAppendedPath.get();
|
---|
1438 | if (temp == nsnull)
|
---|
1439 | return NS_ERROR_FILE_UNRECOGNIZED_PATH;
|
---|
1440 |
|
---|
1441 | const char* leaf = strrchr(temp, ':');
|
---|
1442 |
|
---|
1443 | // if the working path is just a node without any directory delimeters.
|
---|
1444 | if (leaf == nsnull)
|
---|
1445 | leaf = temp;
|
---|
1446 | else
|
---|
1447 | leaf++;
|
---|
1448 |
|
---|
1449 | aLeafName = leaf;
|
---|
1450 | }
|
---|
1451 | else
|
---|
1452 | {
|
---|
1453 | // We don't have an appended path so grab the leaf name from the FSSpec
|
---|
1454 | // Convert the Pascal string to a C string
|
---|
1455 | PRInt32 len = mSpec.name[0];
|
---|
1456 | char* leafName = (char *)malloc(len + 1);
|
---|
1457 | if (!leafName) return NS_ERROR_OUT_OF_MEMORY;
|
---|
1458 | ::BlockMoveData(&mSpec.name[1], leafName, len);
|
---|
1459 | leafName[len] = '\0';
|
---|
1460 | aLeafName = leafName;
|
---|
1461 | free(leafName);
|
---|
1462 | }
|
---|
1463 |
|
---|
1464 | return NS_OK;
|
---|
1465 | }
|
---|
1466 |
|
---|
1467 | NS_IMETHODIMP
|
---|
1468 | nsLocalFile::GetLeafName(nsAString &aLeafName)
|
---|
1469 | {
|
---|
1470 | nsresult rv;
|
---|
1471 | nsCAutoString fsStr;
|
---|
1472 |
|
---|
1473 | if (NS_SUCCEEDED(rv = GetNativeLeafName(fsStr)))
|
---|
1474 | rv = NS_CopyNativeToUnicode(fsStr, aLeafName);
|
---|
1475 | return rv;
|
---|
1476 | }
|
---|
1477 |
|
---|
1478 | NS_IMETHODIMP
|
---|
1479 | nsLocalFile::SetNativeLeafName(const nsACString &aLeafName)
|
---|
1480 | {
|
---|
1481 | if (aLeafName.IsEmpty())
|
---|
1482 | return NS_ERROR_INVALID_ARG;
|
---|
1483 |
|
---|
1484 | MakeDirty();
|
---|
1485 |
|
---|
1486 | char truncBuffer[32];
|
---|
1487 | const char *leafName = NS_TruncNodeName(PromiseFlatCString(aLeafName).get(), truncBuffer);
|
---|
1488 |
|
---|
1489 | if (mAppendedPath.Length())
|
---|
1490 | { // Lop off the end of the appended path and replace it with the new leaf name
|
---|
1491 | PRInt32 offset = mAppendedPath.RFindChar(':');
|
---|
1492 | if (offset || ((!offset) && (1 < mAppendedPath.Length())))
|
---|
1493 | {
|
---|
1494 | mAppendedPath.Truncate(offset + 1);
|
---|
1495 | }
|
---|
1496 | mAppendedPath.Append(leafName);
|
---|
1497 | }
|
---|
1498 | else
|
---|
1499 | {
|
---|
1500 | // We don't have an appended path so directly modify the FSSpec
|
---|
1501 | myPLstrcpy(mSpec.name, leafName);
|
---|
1502 | }
|
---|
1503 |
|
---|
1504 | return NS_OK;
|
---|
1505 | }
|
---|
1506 |
|
---|
1507 | NS_IMETHODIMP
|
---|
1508 | nsLocalFile::SetLeafName(const nsAString &aLeafName)
|
---|
1509 | {
|
---|
1510 | nsresult rv;
|
---|
1511 | nsCAutoString fsStr;
|
---|
1512 |
|
---|
1513 | if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(aLeafName, fsStr)))
|
---|
1514 | rv = SetNativeLeafName(fsStr);
|
---|
1515 |
|
---|
1516 | return rv;
|
---|
1517 | }
|
---|
1518 |
|
---|
1519 | NS_IMETHODIMP
|
---|
1520 | nsLocalFile::GetNativePath(nsACString &_retval)
|
---|
1521 | {
|
---|
1522 | _retval.Truncate();
|
---|
1523 |
|
---|
1524 | nsCAutoString fsCharSetPathStr;
|
---|
1525 |
|
---|
1526 | #if TARGET_CARBON
|
---|
1527 | if (sHasHFSPlusAPIs) // should always be true under Carbon, but in case...
|
---|
1528 | {
|
---|
1529 | OSErr err;
|
---|
1530 | nsresult rv;
|
---|
1531 | nsAutoString ucPathString;
|
---|
1532 |
|
---|
1533 | if ((err = HFSPlusGetRawPath(mSpec, ucPathString)) != noErr)
|
---|
1534 | return MacErrorMapper(err);
|
---|
1535 | rv = NS_CopyUnicodeToNative(ucPathString, fsCharSetPathStr);
|
---|
1536 | if (NS_FAILED(rv))
|
---|
1537 | return rv;
|
---|
1538 | }
|
---|
1539 | else
|
---|
1540 | #endif
|
---|
1541 | {
|
---|
1542 | // Now would be a good time to call the code that makes an FSSpec into a path
|
---|
1543 | short fullPathLen;
|
---|
1544 | Handle fullPathHandle;
|
---|
1545 | (void)::FSpGetFullPath(&mSpec, &fullPathLen, &fullPathHandle);
|
---|
1546 | if (!fullPathHandle)
|
---|
1547 | return NS_ERROR_OUT_OF_MEMORY;
|
---|
1548 |
|
---|
1549 | ::HLock(fullPathHandle);
|
---|
1550 | fsCharSetPathStr.Assign(*fullPathHandle, fullPathLen);
|
---|
1551 | ::DisposeHandle(fullPathHandle);
|
---|
1552 | }
|
---|
1553 |
|
---|
1554 | // We need to make sure that even if we have a path to a
|
---|
1555 | // directory we don't return the trailing colon. It breaks
|
---|
1556 | // the component manager. (Bugzilla bug #26102)
|
---|
1557 | if (fsCharSetPathStr.Last() == ':')
|
---|
1558 | fsCharSetPathStr.Truncate(fsCharSetPathStr.Length() - 1);
|
---|
1559 |
|
---|
1560 | // Now, tack on mAppendedPath. It never ends in a colon.
|
---|
1561 | if (mAppendedPath.Length())
|
---|
1562 | {
|
---|
1563 | if (mAppendedPath.First() != ':')
|
---|
1564 | fsCharSetPathStr.Append(":");
|
---|
1565 | fsCharSetPathStr.Append(mAppendedPath);
|
---|
1566 | }
|
---|
1567 |
|
---|
1568 | _retval = fsCharSetPathStr;
|
---|
1569 | return NS_OK;
|
---|
1570 | }
|
---|
1571 |
|
---|
1572 | NS_IMETHODIMP
|
---|
1573 | nsLocalFile::GetPath(nsAString &_retval)
|
---|
1574 | {
|
---|
1575 | nsresult rv = NS_OK;
|
---|
1576 |
|
---|
1577 | #if TARGET_CARBON
|
---|
1578 | if (sHasHFSPlusAPIs) // should always be true under Carbon, but in case...
|
---|
1579 | {
|
---|
1580 | OSErr err;
|
---|
1581 | nsAutoString ucPathString;
|
---|
1582 |
|
---|
1583 | if ((err = HFSPlusGetRawPath(mSpec, ucPathString)) != noErr)
|
---|
1584 | return MacErrorMapper(err);
|
---|
1585 |
|
---|
1586 | // We need to make sure that even if we have a path to a
|
---|
1587 | // directory we don't return the trailing colon. It breaks
|
---|
1588 | // the component manager. (Bugzilla bug #26102)
|
---|
1589 | if (ucPathString.Last() == PRUnichar(':'))
|
---|
1590 | ucPathString.Truncate(ucPathString.Length() - 1);
|
---|
1591 |
|
---|
1592 | // Now, tack on mAppendedPath. It never ends in a colon.
|
---|
1593 | if (mAppendedPath.Length())
|
---|
1594 | {
|
---|
1595 | nsAutoString ucAppendage;
|
---|
1596 | if (mAppendedPath.First() != ':')
|
---|
1597 | ucPathString.Append(PRUnichar(':'));
|
---|
1598 | rv = NS_CopyNativeToUnicode(mAppendedPath, ucAppendage);
|
---|
1599 | if (NS_FAILED(rv))
|
---|
1600 | return rv;
|
---|
1601 | ucPathString.Append(ucAppendage);
|
---|
1602 | }
|
---|
1603 |
|
---|
1604 | _retval = ucPathString;
|
---|
1605 | }
|
---|
1606 | else
|
---|
1607 | #endif
|
---|
1608 | {
|
---|
1609 | nsCAutoString fsStr;
|
---|
1610 |
|
---|
1611 | if (NS_SUCCEEDED(rv = GetNativePath(fsStr))) {
|
---|
1612 | rv = NS_CopyNativeToUnicode(fsStr, _retval);
|
---|
1613 | }
|
---|
1614 | }
|
---|
1615 | return rv;
|
---|
1616 | }
|
---|
1617 |
|
---|
1618 | nsresult nsLocalFile::MoveCopy( nsIFile* newParentDir, const nsACString &newName, PRBool isCopy, PRBool followLinks )
|
---|
1619 | {
|
---|
1620 | OSErr macErr;
|
---|
1621 | FSSpec srcSpec;
|
---|
1622 | Str255 newPascalName;
|
---|
1623 | nsresult rv;
|
---|
1624 |
|
---|
1625 | StFollowLinksState srcFollowState(this, followLinks);
|
---|
1626 | rv = GetFSSpec(&srcSpec);
|
---|
1627 | if ( NS_FAILED( rv ) )
|
---|
1628 | return rv;
|
---|
1629 |
|
---|
1630 | // If newParentDir == nsnull, it's a simple rename
|
---|
1631 | if ( !newParentDir )
|
---|
1632 | {
|
---|
1633 | myPLstrncpy( newPascalName, PromiseFlatCString(newName).get(), 255 );
|
---|
1634 | macErr = ::FSpRename( &srcSpec, newPascalName );
|
---|
1635 | return MacErrorMapper( macErr );
|
---|
1636 | }
|
---|
1637 |
|
---|
1638 | nsCOMPtr<nsILocalFileMac> destDir(do_QueryInterface( newParentDir ));
|
---|
1639 | StFollowLinksState destFollowState(destDir, followLinks);
|
---|
1640 | FSSpec destSpec;
|
---|
1641 | rv = destDir->GetFSSpec(&destSpec);
|
---|
1642 | if ( NS_FAILED( rv ) )
|
---|
1643 | return rv;
|
---|
1644 |
|
---|
1645 | long dirID;
|
---|
1646 | Boolean isDirectory;
|
---|
1647 | macErr = ::FSpGetDirectoryID(&destSpec, &dirID, &isDirectory);
|
---|
1648 | if ( macErr || !isDirectory )
|
---|
1649 | return NS_ERROR_FILE_DESTINATION_NOT_DIR;
|
---|
1650 |
|
---|
1651 | if ( !newName.IsEmpty() )
|
---|
1652 | myPLstrncpy( newPascalName, PromiseFlatCString(newName).get(), 255);
|
---|
1653 | else
|
---|
1654 | memcpy(newPascalName, srcSpec.name, srcSpec.name[0] + 1);
|
---|
1655 | if ( isCopy )
|
---|
1656 | {
|
---|
1657 | macErr = ::FSpGetDirectoryID(&srcSpec, &dirID, &isDirectory);
|
---|
1658 | if (macErr == noErr)
|
---|
1659 | {
|
---|
1660 | const PRInt32 kCopyBufferSize = (1024 * 512); // allocate our own buffer to speed file copies. Bug #103202
|
---|
1661 | OSErr tempErr;
|
---|
1662 | Handle copyBufferHand = ::TempNewHandle(kCopyBufferSize, &tempErr);
|
---|
1663 | void* copyBuffer = nsnull;
|
---|
1664 | PRInt32 copyBufferSize = 0;
|
---|
1665 |
|
---|
1666 | // it's OK if the allocated failed; FSpFileCopy will just fall back on its own internal 16k buffer
|
---|
1667 | if (copyBufferHand)
|
---|
1668 | {
|
---|
1669 | ::HLock(copyBufferHand);
|
---|
1670 | copyBuffer = *copyBufferHand;
|
---|
1671 | copyBufferSize = kCopyBufferSize;
|
---|
1672 | }
|
---|
1673 |
|
---|
1674 | if ( isDirectory )
|
---|
1675 | macErr = MacFSpDirectoryCopyRename( &srcSpec, &destSpec, newPascalName, copyBuffer, copyBufferSize, true, NULL );
|
---|
1676 | else
|
---|
1677 | macErr = ::FSpFileCopy( &srcSpec, &destSpec, newPascalName, copyBuffer, copyBufferSize, true );
|
---|
1678 |
|
---|
1679 | if (copyBufferHand)
|
---|
1680 | ::DisposeHandle(copyBufferHand);
|
---|
1681 | }
|
---|
1682 | }
|
---|
1683 | else
|
---|
1684 | {
|
---|
1685 | macErr= ::FSpMoveRenameCompat(&srcSpec, &destSpec, newPascalName);
|
---|
1686 | if ( macErr == diffVolErr)
|
---|
1687 | {
|
---|
1688 | // On a different Volume so go for Copy and then delete
|
---|
1689 | rv = CopyToNative( newParentDir, newName );
|
---|
1690 | if ( NS_FAILED ( rv ) )
|
---|
1691 | return rv;
|
---|
1692 | return Remove( PR_TRUE );
|
---|
1693 | }
|
---|
1694 | }
|
---|
1695 | return MacErrorMapper( macErr );
|
---|
1696 | }
|
---|
1697 |
|
---|
1698 | NS_IMETHODIMP
|
---|
1699 | nsLocalFile::CopyToNative(nsIFile *newParentDir, const nsACString &newName)
|
---|
1700 | {
|
---|
1701 | return MoveCopy( newParentDir, newName, PR_TRUE, PR_FALSE );
|
---|
1702 | }
|
---|
1703 |
|
---|
1704 | NS_IMETHODIMP
|
---|
1705 | nsLocalFile::CopyTo(nsIFile *newParentDir, const nsAString &newName)
|
---|
1706 | {
|
---|
1707 | if (newName.IsEmpty())
|
---|
1708 | return CopyToNative(newParentDir, nsCString());
|
---|
1709 |
|
---|
1710 | nsresult rv;
|
---|
1711 | nsCAutoString fsStr;
|
---|
1712 | if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(newName, fsStr)))
|
---|
1713 | rv = CopyToNative(newParentDir, fsStr);
|
---|
1714 | return rv;
|
---|
1715 | }
|
---|
1716 |
|
---|
1717 | NS_IMETHODIMP
|
---|
1718 | nsLocalFile::CopyToFollowingLinksNative(nsIFile *newParentDir, const nsACString &newName)
|
---|
1719 | {
|
---|
1720 | return MoveCopy( newParentDir, newName, PR_TRUE, PR_TRUE );
|
---|
1721 | }
|
---|
1722 |
|
---|
1723 | NS_IMETHODIMP
|
---|
1724 | nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const nsAString &newName)
|
---|
1725 | {
|
---|
1726 | if (newName.IsEmpty())
|
---|
1727 | return CopyToFollowingLinksNative(newParentDir, nsCString());
|
---|
1728 |
|
---|
1729 | nsresult rv;
|
---|
1730 | nsCAutoString fsStr;
|
---|
1731 | if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(newName, fsStr)))
|
---|
1732 | rv = CopyToFollowingLinksNative(newParentDir, fsStr);
|
---|
1733 | return rv;
|
---|
1734 | }
|
---|
1735 |
|
---|
1736 | NS_IMETHODIMP
|
---|
1737 | nsLocalFile::MoveToNative(nsIFile *newParentDir, const nsACString &newName)
|
---|
1738 | {
|
---|
1739 | return MoveCopy( newParentDir, newName, PR_FALSE, PR_FALSE );
|
---|
1740 | }
|
---|
1741 |
|
---|
1742 | NS_IMETHODIMP
|
---|
1743 | nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString &newName)
|
---|
1744 | {
|
---|
1745 | if (newName.IsEmpty())
|
---|
1746 | return MoveToNative(newParentDir, nsCString());
|
---|
1747 |
|
---|
1748 | nsresult rv;
|
---|
1749 | nsCAutoString fsStr;
|
---|
1750 | if (NS_SUCCEEDED(rv = NS_CopyUnicodeToNative(newName, fsStr)))
|
---|
1751 | rv = MoveToNative(newParentDir, fsStr);
|
---|
1752 | return rv;
|
---|
1753 | }
|
---|
1754 |
|
---|
1755 | NS_IMETHODIMP
|
---|
1756 | nsLocalFile::Load(PRLibrary * *_retval)
|
---|
1757 | {
|
---|
1758 | PRBool isFile;
|
---|
1759 | nsresult rv = IsFile(&isFile);
|
---|
1760 |
|
---|
1761 | if (NS_FAILED(rv))
|
---|
1762 | return rv;
|
---|
1763 |
|
---|
1764 | if (! isFile)
|
---|
1765 | return NS_ERROR_FILE_IS_DIRECTORY;
|
---|
1766 |
|
---|
1767 | NS_TIMELINE_START_TIMER("PR_LoadLibrary");
|
---|
1768 |
|
---|
1769 | #if !TARGET_CARBON
|
---|
1770 | // This call to SystemTask is here to give the OS time to grow its
|
---|
1771 | // FCB (file control block) list, which it seems to be unable to
|
---|
1772 | // do unless we yield some time to the OS. See bugs 64978 & 70543
|
---|
1773 | // for the whole story.
|
---|
1774 | ::SystemTask();
|
---|
1775 | #endif
|
---|
1776 |
|
---|
1777 | // Use the new PR_LoadLibraryWithFlags which allows us to use a FSSpec
|
---|
1778 | PRLibSpec libSpec;
|
---|
1779 | libSpec.type = PR_LibSpec_MacIndexedFragment;
|
---|
1780 | libSpec.value.mac_indexed_fragment.fsspec = &mTargetSpec;
|
---|
1781 | libSpec.value.mac_indexed_fragment.index = 0;
|
---|
1782 | *_retval = PR_LoadLibraryWithFlags(libSpec, 0);
|
---|
1783 |
|
---|
1784 | NS_TIMELINE_STOP_TIMER("PR_LoadLibrary");
|
---|
1785 | NS_TIMELINE_MARK_TIMER("PR_LoadLibrary");
|
---|
1786 |
|
---|
1787 | if (*_retval)
|
---|
1788 | return NS_OK;
|
---|
1789 |
|
---|
1790 | return NS_ERROR_NULL_POINTER;
|
---|
1791 | }
|
---|
1792 |
|
---|
1793 | NS_IMETHODIMP
|
---|
1794 | nsLocalFile::Remove(PRBool recursive)
|
---|
1795 | {
|
---|
1796 | OSErr err;
|
---|
1797 | nsresult rv;
|
---|
1798 | FSSpec specToDelete;
|
---|
1799 | PRBool isDir;
|
---|
1800 |
|
---|
1801 | StFollowLinksState(this, PR_FALSE);
|
---|
1802 |
|
---|
1803 | rv = IsDirectory(&isDir); // Calls ResolveAndStat()
|
---|
1804 | if (NS_FAILED(rv))
|
---|
1805 | return rv;
|
---|
1806 | rv = GetFSSpec(&specToDelete);
|
---|
1807 | if (NS_FAILED(rv))
|
---|
1808 | return rv;
|
---|
1809 |
|
---|
1810 | if (isDir && recursive)
|
---|
1811 | err = ::DeleteDirectory( specToDelete.vRefNum, specToDelete.parID, specToDelete.name );
|
---|
1812 | else
|
---|
1813 | err = ::HDelete( specToDelete.vRefNum, specToDelete.parID, specToDelete.name );
|
---|
1814 |
|
---|
1815 | return MacErrorMapper( err );
|
---|
1816 | }
|
---|
1817 |
|
---|
1818 | NS_IMETHODIMP
|
---|
1819 | nsLocalFile::GetLastModifiedTime(PRInt64 *aLastModifiedTime)
|
---|
1820 | {
|
---|
1821 | NS_ENSURE_ARG(aLastModifiedTime);
|
---|
1822 | *aLastModifiedTime = 0;
|
---|
1823 |
|
---|
1824 | nsresult rv = ResolveAndStat();
|
---|
1825 | if ( NS_FAILED( rv ) )
|
---|
1826 | return rv;
|
---|
1827 | rv = UpdateCachedCatInfo(PR_TRUE);
|
---|
1828 | if ( NS_FAILED( rv ) )
|
---|
1829 | return rv;
|
---|
1830 |
|
---|
1831 | // The mod date is in the same spot for files and dirs.
|
---|
1832 | return ConvertMacTimeToMilliseconds( aLastModifiedTime, mCachedCatInfo.hFileInfo.ioFlMdDat );
|
---|
1833 | }
|
---|
1834 |
|
---|
1835 | NS_IMETHODIMP
|
---|
1836 | nsLocalFile::SetLastModifiedTime(PRInt64 aLastModifiedTime)
|
---|
1837 | {
|
---|
1838 | nsresult rv = ResolveAndStat();
|
---|
1839 | if ( NS_FAILED(rv) )
|
---|
1840 | return rv;
|
---|
1841 |
|
---|
1842 | PRUint32 macTime = 0;
|
---|
1843 | OSErr err = noErr;
|
---|
1844 |
|
---|
1845 | ConvertMillisecondsToMacTime(aLastModifiedTime, &macTime);
|
---|
1846 |
|
---|
1847 | if (NS_SUCCEEDED(rv = UpdateCachedCatInfo(PR_TRUE)))
|
---|
1848 | {
|
---|
1849 | if (mCachedCatInfo.hFileInfo.ioFlAttrib & ioDirMask)
|
---|
1850 | {
|
---|
1851 | mCachedCatInfo.dirInfo.ioDrMdDat = macTime;
|
---|
1852 | mCachedCatInfo.dirInfo.ioDrParID = mFollowLinks ? mTargetSpec.parID : mSpec.parID;
|
---|
1853 | }
|
---|
1854 | else
|
---|
1855 | {
|
---|
1856 | mCachedCatInfo.hFileInfo.ioFlMdDat = macTime;
|
---|
1857 | mCachedCatInfo.hFileInfo.ioDirID = mFollowLinks ? mTargetSpec.parID : mSpec.parID;
|
---|
1858 | }
|
---|
1859 |
|
---|
1860 | err = ::PBSetCatInfoSync(&mCachedCatInfo);
|
---|
1861 | if (err != noErr)
|
---|
1862 | return MacErrorMapper(err);
|
---|
1863 | }
|
---|
1864 |
|
---|
1865 | return rv;
|
---|
1866 | }
|
---|
1867 |
|
---|
1868 | NS_IMETHODIMP
|
---|
1869 | nsLocalFile::GetLastModifiedTimeOfLink(PRInt64 *aLastModifiedTime)
|
---|
1870 | {
|
---|
1871 | NS_ENSURE_ARG(aLastModifiedTime);
|
---|
1872 |
|
---|
1873 | nsresult rv;
|
---|
1874 | PRBool isLink;
|
---|
1875 |
|
---|
1876 | rv = IsSymlink(&isLink);
|
---|
1877 | if (NS_FAILED(rv))
|
---|
1878 | return rv;
|
---|
1879 | if (!isLink)
|
---|
1880 | return NS_ERROR_FAILURE;
|
---|
1881 |
|
---|
1882 | StFollowLinksState followState(this, PR_FALSE);
|
---|
1883 | return GetLastModifiedTime(aLastModifiedTime);
|
---|
1884 | }
|
---|
1885 |
|
---|
1886 | NS_IMETHODIMP
|
---|
1887 | nsLocalFile::SetLastModifiedTimeOfLink(PRInt64 aLastModifiedTime)
|
---|
1888 | {
|
---|
1889 | nsresult rv;
|
---|
1890 | PRBool isLink;
|
---|
1891 |
|
---|
1892 | rv = IsSymlink(&isLink);
|
---|
1893 | if (NS_FAILED(rv))
|
---|
1894 | return rv;
|
---|
1895 | if (!isLink)
|
---|
1896 | return NS_ERROR_FAILURE;
|
---|
1897 |
|
---|
1898 | StFollowLinksState followState(this, PR_FALSE);
|
---|
1899 | return SetLastModifiedTime(aLastModifiedTime);
|
---|
1900 | }
|
---|
1901 |
|
---|
1902 |
|
---|
1903 | NS_IMETHODIMP
|
---|
1904 | nsLocalFile::GetFileSize(PRInt64 *aFileSize)
|
---|
1905 | {
|
---|
1906 | NS_ENSURE_ARG(aFileSize);
|
---|
1907 | nsresult rv;
|
---|
1908 |
|
---|
1909 | *aFileSize = LL_Zero();
|
---|
1910 |
|
---|
1911 | if (NS_SUCCEEDED(rv = ResolveAndStat()) && NS_SUCCEEDED(rv = UpdateCachedCatInfo(PR_TRUE)))
|
---|
1912 | {
|
---|
1913 | if (!(mCachedCatInfo.hFileInfo.ioFlAttrib & ioDirMask))
|
---|
1914 | {
|
---|
1915 | long dataSize = mCachedCatInfo.hFileInfo.ioFlLgLen;
|
---|
1916 | long resSize = mCachedCatInfo.hFileInfo.ioFlRLgLen;
|
---|
1917 |
|
---|
1918 | // For now we've only got 32 bits of file size info
|
---|
1919 | PRInt64 dataInt64 = LL_Zero();
|
---|
1920 | PRInt64 resInt64 = LL_Zero();
|
---|
1921 |
|
---|
1922 | // WARNING!!!!!!
|
---|
1923 | //
|
---|
1924 | // For now we do NOT add the data and resource fork sizes as there are several
|
---|
1925 | // assumptions in the code (notably in form submit) that only the data fork is
|
---|
1926 | // used.
|
---|
1927 | // LL_I2L(resInt64, resSize);
|
---|
1928 |
|
---|
1929 | LL_I2L(dataInt64, dataSize);
|
---|
1930 |
|
---|
1931 | LL_ADD((*aFileSize), dataInt64, resInt64);
|
---|
1932 | }
|
---|
1933 | // leave size at zero for dirs
|
---|
1934 | }
|
---|
1935 |
|
---|
1936 | return rv;
|
---|
1937 | }
|
---|
1938 |
|
---|
1939 |
|
---|
1940 | NS_IMETHODIMP
|
---|
1941 | nsLocalFile::SetFileSize(PRInt64 aFileSize)
|
---|
1942 | {
|
---|
1943 | nsresult rv = ResolveAndStat();
|
---|
1944 | if (NS_FAILED(rv))
|
---|
1945 | return rv;
|
---|
1946 |
|
---|
1947 | short refNum;
|
---|
1948 | OSErr err;
|
---|
1949 | PRInt32 aNewLength;
|
---|
1950 |
|
---|
1951 | LL_L2I(aNewLength, aFileSize);
|
---|
1952 |
|
---|
1953 | // Need to open the file to set the size
|
---|
1954 | if (::FSpOpenDF(&mTargetSpec, fsWrPerm, &refNum) != noErr)
|
---|
1955 | return NS_ERROR_FILE_ACCESS_DENIED;
|
---|
1956 |
|
---|
1957 | err = ::SetEOF(refNum, aNewLength);
|
---|
1958 |
|
---|
1959 | // Close the file unless we got an error that it was already closed
|
---|
1960 | if (err != fnOpnErr)
|
---|
1961 | (void)::FSClose(refNum);
|
---|
1962 |
|
---|
1963 | if (err != noErr)
|
---|
1964 | return MacErrorMapper(err);
|
---|
1965 |
|
---|
1966 | return MacErrorMapper(err);
|
---|
1967 | }
|
---|
1968 |
|
---|
1969 | NS_IMETHODIMP
|
---|
1970 | nsLocalFile::GetFileSizeOfLink(PRInt64 *aFileSize)
|
---|
1971 | {
|
---|
1972 | NS_ENSURE_ARG(aFileSize);
|
---|
1973 |
|
---|
1974 | StFollowLinksState followState(this, PR_FALSE);
|
---|
1975 | return GetFileSize(aFileSize);
|
---|
1976 | }
|
---|
1977 |
|
---|
1978 | NS_IMETHODIMP
|
---|
1979 | nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable)
|
---|
1980 | {
|
---|
1981 | NS_ENSURE_ARG(aDiskSpaceAvailable);
|
---|
1982 |
|
---|
1983 | PRInt64 space64Bits;
|
---|
1984 |
|
---|
1985 | LL_I2L(space64Bits , LONG_MAX);
|
---|
1986 |
|
---|
1987 | nsresult rv = ResolveAndStat();
|
---|
1988 | if (NS_FAILED(rv))
|
---|
1989 | return rv;
|
---|
1990 |
|
---|
1991 | XVolumeParam pb;
|
---|
1992 | pb.ioCompletion = nsnull;
|
---|
1993 | pb.ioVolIndex = 0;
|
---|
1994 | pb.ioNamePtr = nsnull;
|
---|
1995 | pb.ioVRefNum = mFollowLinks ? mTargetSpec.vRefNum : mSpec.vRefNum;
|
---|
1996 |
|
---|
1997 | // we should check if this call is available
|
---|
1998 | OSErr err = ::PBXGetVolInfoSync(&pb);
|
---|
1999 |
|
---|
2000 | if (err == noErr)
|
---|
2001 | {
|
---|
2002 | const UnsignedWide& freeBytes = UInt64ToUnsignedWide(pb.ioVFreeBytes);
|
---|
2003 | #ifdef HAVE_LONG_LONG
|
---|
2004 | space64Bits = UnsignedWideToUInt64(freeBytes);
|
---|
2005 | #else
|
---|
2006 | space64Bits.lo = freeBytes.lo;
|
---|
2007 | space64Bits.hi = freeBytes.hi;
|
---|
2008 | #endif
|
---|
2009 | }
|
---|
2010 |
|
---|
2011 | *aDiskSpaceAvailable = space64Bits;
|
---|
2012 |
|
---|
2013 | return NS_OK;
|
---|
2014 | }
|
---|
2015 |
|
---|
2016 | NS_IMETHODIMP
|
---|
2017 | nsLocalFile::GetParent(nsIFile * *aParent)
|
---|
2018 | {
|
---|
2019 | NS_ENSURE_ARG_POINTER(aParent);
|
---|
2020 | *aParent = nsnull;
|
---|
2021 |
|
---|
2022 | nsresult rv = NS_OK;
|
---|
2023 | PRInt32 offset;
|
---|
2024 |
|
---|
2025 | nsCOMPtr<nsILocalFileMac> localFile;
|
---|
2026 | PRInt32 appendedLen = mAppendedPath.Length();
|
---|
2027 | OSErr err;
|
---|
2028 |
|
---|
2029 | if (!appendedLen || (appendedLen == 1 && mAppendedPath.CharAt(0) == ':'))
|
---|
2030 | {
|
---|
2031 | rv = ResolveAndStat();
|
---|
2032 | //if the file does not exist, does not mean that the parent does not.
|
---|
2033 | if (NS_FAILED(rv) && rv != NS_ERROR_FILE_NOT_FOUND)
|
---|
2034 | return rv;
|
---|
2035 |
|
---|
2036 | CInfoPBRec pBlock = {0};
|
---|
2037 | FSSpec parentFolderSpec;
|
---|
2038 | parentFolderSpec.name[0] = 0;
|
---|
2039 |
|
---|
2040 | pBlock.dirInfo.ioVRefNum = mSpec.vRefNum;
|
---|
2041 | pBlock.dirInfo.ioDrDirID = mSpec.parID;
|
---|
2042 | pBlock.dirInfo.ioNamePtr = (StringPtr)parentFolderSpec.name;
|
---|
2043 | pBlock.dirInfo.ioFDirIndex = -1; //get info on parID
|
---|
2044 | err = PBGetCatInfoSync(&pBlock);
|
---|
2045 | if (err != noErr)
|
---|
2046 | return MacErrorMapper(err);
|
---|
2047 | parentFolderSpec.vRefNum = mSpec.vRefNum;
|
---|
2048 | parentFolderSpec.parID = pBlock.dirInfo.ioDrParID;
|
---|
2049 |
|
---|
2050 | localFile = new nsLocalFile;
|
---|
2051 | if (!localFile)
|
---|
2052 | return NS_ERROR_OUT_OF_MEMORY;
|
---|
2053 | rv = localFile->InitWithFSSpec(&parentFolderSpec);
|
---|
2054 | if (NS_FAILED(rv))
|
---|
2055 | return rv;
|
---|
2056 | }
|
---|
2057 | else
|
---|
2058 | {
|
---|
2059 | // trim off the last component of the appended path
|
---|
2060 | // construct a new file from our spec + trimmed path
|
---|
2061 |
|
---|
2062 | nsCAutoString parentAppendage(mAppendedPath);
|
---|
2063 |
|
---|
2064 | if (parentAppendage.Last() == ':')
|
---|
2065 | parentAppendage.Truncate(appendedLen - 1);
|
---|
2066 | if ((offset = parentAppendage.RFindChar(':')) != -1)
|
---|
2067 | parentAppendage.Truncate(offset);
|
---|
2068 | else
|
---|
2069 | parentAppendage.Truncate(0);
|
---|
2070 |
|
---|
2071 | localFile = new nsLocalFile(mSpec, parentAppendage);
|
---|
2072 | if (!localFile)
|
---|
2073 | return NS_ERROR_OUT_OF_MEMORY;
|
---|
2074 | }
|
---|
2075 | *aParent = localFile;
|
---|
2076 | NS_ADDREF(*aParent);
|
---|
2077 |
|
---|
2078 | return rv;
|
---|
2079 | }
|
---|
2080 |
|
---|
2081 |
|
---|
2082 | NS_IMETHODIMP
|
---|
2083 | nsLocalFile::Exists(PRBool *_retval)
|
---|
2084 | {
|
---|
2085 | NS_ENSURE_ARG(_retval);
|
---|
2086 | *_retval = PR_FALSE;
|
---|
2087 |
|
---|
2088 | nsresult rv = ResolveAndStat();
|
---|
2089 | if (NS_SUCCEEDED(rv)) {
|
---|
2090 | if (NS_SUCCEEDED(UpdateCachedCatInfo(PR_TRUE)))
|
---|
2091 | *_retval = PR_TRUE;
|
---|
2092 | }
|
---|
2093 |
|
---|
2094 | return NS_OK;
|
---|
2095 | }
|
---|
2096 |
|
---|
2097 | NS_IMETHODIMP
|
---|
2098 | nsLocalFile::IsPackage(PRBool *outIsPackage)
|
---|
2099 | {
|
---|
2100 | NS_ENSURE_ARG(outIsPackage);
|
---|
2101 | *outIsPackage = PR_FALSE;
|
---|
2102 |
|
---|
2103 | // Note: IsDirectory() calls ResolveAndStat() & UpdateCachedCatInfo
|
---|
2104 | PRBool isDir;
|
---|
2105 | nsresult rv = IsDirectory(&isDir);
|
---|
2106 | if (NS_FAILED(rv)) return rv;
|
---|
2107 |
|
---|
2108 | *outIsPackage = ((mCachedCatInfo.dirInfo.ioFlAttrib & kioFlAttribDirMask) &&
|
---|
2109 | (mCachedCatInfo.dirInfo.ioDrUsrWds.frFlags & kHasBundle));
|
---|
2110 |
|
---|
2111 | if ((!*outIsPackage) && isDir)
|
---|
2112 | {
|
---|
2113 | // Believe it or not, folders ending with ".app" are also considered
|
---|
2114 | // to be packages, even if the top-level folder doesn't have bundle set
|
---|
2115 | nsCAutoString name;
|
---|
2116 | if (NS_SUCCEEDED(rv = GetNativeLeafName(name)))
|
---|
2117 | {
|
---|
2118 | const char *extPtr = strrchr(name.get(), '.');
|
---|
2119 | if (extPtr)
|
---|
2120 | {
|
---|
2121 | if (!nsCRT::strcasecmp(extPtr, ".app"))
|
---|
2122 | {
|
---|
2123 | *outIsPackage = PR_TRUE;
|
---|
2124 | }
|
---|
2125 | }
|
---|
2126 | }
|
---|
2127 | }
|
---|
2128 |
|
---|
2129 | return NS_OK;
|
---|
2130 | }
|
---|
2131 |
|
---|
2132 | NS_IMETHODIMP
|
---|
2133 | nsLocalFile::IsWritable(PRBool *outIsWritable)
|
---|
2134 | {
|
---|
2135 | NS_ENSURE_ARG(outIsWritable);
|
---|
2136 | *outIsWritable = PR_TRUE;
|
---|
2137 |
|
---|
2138 | nsresult rv = ResolveAndStat();
|
---|
2139 | if (NS_FAILED(rv)) return rv;
|
---|
2140 |
|
---|
2141 | rv = UpdateCachedCatInfo(PR_TRUE);
|
---|
2142 | if (NS_FAILED(rv)) return rv;
|
---|
2143 |
|
---|
2144 | *outIsWritable = !(mCachedCatInfo.hFileInfo.ioFlAttrib & kioFlAttribLockedMask);
|
---|
2145 | return NS_OK;
|
---|
2146 | }
|
---|
2147 |
|
---|
2148 | NS_IMETHODIMP
|
---|
2149 | nsLocalFile::IsReadable(PRBool *_retval)
|
---|
2150 | {
|
---|
2151 | NS_ENSURE_ARG(_retval);
|
---|
2152 |
|
---|
2153 | // is it ever not readable on Mac?
|
---|
2154 | *_retval = PR_TRUE;
|
---|
2155 | return NS_OK;
|
---|
2156 | }
|
---|
2157 |
|
---|
2158 |
|
---|
2159 | NS_IMETHODIMP
|
---|
2160 | nsLocalFile::IsExecutable(PRBool *outIsExecutable)
|
---|
2161 | {
|
---|
2162 | NS_ENSURE_ARG(outIsExecutable);
|
---|
2163 | *outIsExecutable = PR_FALSE; // Assume failure
|
---|
2164 |
|
---|
2165 | nsresult rv = ResolveAndStat();
|
---|
2166 | if (NS_FAILED(rv)) return rv;
|
---|
2167 |
|
---|
2168 | #if TARGET_CARBON
|
---|
2169 | // If we're running under OS X ask LaunchServices if we're executable
|
---|
2170 | if (sRunningOSX)
|
---|
2171 | {
|
---|
2172 | if ( (UInt32)LSCopyItemInfoForRef != (UInt32)kUnresolvedCFragSymbolAddress )
|
---|
2173 | {
|
---|
2174 | FSRef theRef;
|
---|
2175 | LSRequestedInfo theInfoRequest = kLSRequestAllInfo;
|
---|
2176 | LSItemInfoRecord theInfo;
|
---|
2177 |
|
---|
2178 | if (::FSpMakeFSRef(&mTargetSpec, &theRef) == noErr)
|
---|
2179 | {
|
---|
2180 | if (::LSCopyItemInfoForRef(&theRef, theInfoRequest, &theInfo) == noErr)
|
---|
2181 | {
|
---|
2182 | if ((theInfo.flags & kLSItemInfoIsApplication) != 0)
|
---|
2183 | *outIsExecutable = PR_TRUE;
|
---|
2184 | }
|
---|
2185 | }
|
---|
2186 | }
|
---|
2187 | }
|
---|
2188 | else
|
---|
2189 | #endif
|
---|
2190 | {
|
---|
2191 | OSType fileType;
|
---|
2192 | rv = GetFileType(&fileType);
|
---|
2193 | if (NS_FAILED(rv)) return rv;
|
---|
2194 |
|
---|
2195 | *outIsExecutable = (fileType == 'APPL' || fileType == 'appe' || fileType == 'FNDR');
|
---|
2196 | }
|
---|
2197 |
|
---|
2198 | return NS_OK;
|
---|
2199 | }
|
---|
2200 |
|
---|
2201 |
|
---|
2202 | NS_IMETHODIMP
|
---|
2203 | nsLocalFile::IsDirectory(PRBool *outIsDir)
|
---|
2204 | {
|
---|
2205 | NS_ENSURE_ARG(outIsDir);
|
---|
2206 | *outIsDir = PR_FALSE;
|
---|
2207 |
|
---|
2208 | nsresult rv = ResolveAndStat();
|
---|
2209 | if (NS_FAILED(rv)) return rv;
|
---|
2210 |
|
---|
2211 | rv = UpdateCachedCatInfo(PR_FALSE);
|
---|
2212 | if (NS_FAILED(rv)) return rv;
|
---|
2213 |
|
---|
2214 | *outIsDir = (mCachedCatInfo.hFileInfo.ioFlAttrib & ioDirMask) != 0;
|
---|
2215 | return NS_OK;
|
---|
2216 | }
|
---|
2217 |
|
---|
2218 | NS_IMETHODIMP
|
---|
2219 | nsLocalFile::IsFile(PRBool *outIsFile)
|
---|
2220 | {
|
---|
2221 | NS_ENSURE_ARG(outIsFile);
|
---|
2222 | *outIsFile = PR_FALSE;
|
---|
2223 |
|
---|
2224 | nsresult rv = ResolveAndStat();
|
---|
2225 | if (NS_FAILED(rv)) return rv;
|
---|
2226 |
|
---|
2227 | rv = UpdateCachedCatInfo(PR_FALSE);
|
---|
2228 | if (NS_FAILED(rv)) return rv;
|
---|
2229 |
|
---|
2230 | *outIsFile = (mCachedCatInfo.hFileInfo.ioFlAttrib & ioDirMask) == 0;
|
---|
2231 | return NS_OK;
|
---|
2232 | }
|
---|
2233 |
|
---|
2234 | NS_IMETHODIMP
|
---|
2235 | nsLocalFile::IsHidden(PRBool *_retval)
|
---|
2236 | {
|
---|
2237 | NS_ENSURE_ARG(_retval);
|
---|
2238 | *_retval = PR_FALSE;
|
---|
2239 |
|
---|
2240 | nsresult rv = ResolveAndStat();
|
---|
2241 | if (NS_FAILED(rv)) return rv;
|
---|
2242 |
|
---|
2243 | rv = UpdateCachedCatInfo(PR_FALSE);
|
---|
2244 | if (NS_FAILED(rv)) return rv;
|
---|
2245 |
|
---|
2246 | *_retval = (mCachedCatInfo.hFileInfo.ioFlFndrInfo.fdFlags & kIsInvisible) != 0;
|
---|
2247 |
|
---|
2248 | if (sRunningOSX)
|
---|
2249 | {
|
---|
2250 | // on Mac OS X, also follow Unix "convention" where files
|
---|
2251 | // beginning with a period are considered to be hidden
|
---|
2252 | nsCAutoString name;
|
---|
2253 | if (NS_SUCCEEDED(rv = GetNativeLeafName(name)))
|
---|
2254 | {
|
---|
2255 | if (name.First() == '.')
|
---|
2256 | {
|
---|
2257 | *_retval = PR_TRUE;
|
---|
2258 | }
|
---|
2259 | }
|
---|
2260 | }
|
---|
2261 |
|
---|
2262 | return NS_OK;
|
---|
2263 | }
|
---|
2264 |
|
---|
2265 | NS_IMETHODIMP
|
---|
2266 | nsLocalFile::IsSymlink(PRBool *_retval)
|
---|
2267 | {
|
---|
2268 | NS_ENSURE_ARG(_retval);
|
---|
2269 | *_retval = PR_FALSE;
|
---|
2270 |
|
---|
2271 | nsresult rv = ResolveAndStat();
|
---|
2272 | if (NS_FAILED(rv)) return rv;
|
---|
2273 |
|
---|
2274 | Boolean isAlias, isFolder;
|
---|
2275 | if (::IsAliasFile(&mSpec, &isAlias, &isFolder) == noErr)
|
---|
2276 | *_retval = isAlias;
|
---|
2277 | return NS_OK;
|
---|
2278 | }
|
---|
2279 |
|
---|
2280 | NS_IMETHODIMP
|
---|
2281 | nsLocalFile::Equals(nsIFile *inFile, PRBool *_retval)
|
---|
2282 | {
|
---|
2283 | NS_ENSURE_ARG(inFile);
|
---|
2284 | NS_ENSURE_ARG(_retval);
|
---|
2285 | *_retval = PR_FALSE;
|
---|
2286 |
|
---|
2287 | // Building paths is expensive. If we can get the FSSpecs of
|
---|
2288 | // both (they or their parents exist) just compare the specs.
|
---|
2289 | nsCOMPtr<nsILocalFileMac> inMacFile(do_QueryInterface(inFile));
|
---|
2290 | FSSpec fileSpec, inFileSpec;
|
---|
2291 | if (NS_SUCCEEDED(GetFSSpec(&fileSpec)) && inMacFile && NS_SUCCEEDED(inMacFile->GetFSSpec(&inFileSpec)))
|
---|
2292 | *_retval = IsEqualFSSpec(fileSpec, inFileSpec);
|
---|
2293 | else
|
---|
2294 | {
|
---|
2295 | nsCAutoString filePath;
|
---|
2296 | GetNativePath(filePath);
|
---|
2297 |
|
---|
2298 | nsXPIDLCString inFilePath;
|
---|
2299 | inFile->GetNativePath(inFilePath);
|
---|
2300 |
|
---|
2301 | if (nsCRT::strcasecmp(inFilePath.get(), filePath.get()) == 0)
|
---|
2302 | *_retval = PR_TRUE;
|
---|
2303 | }
|
---|
2304 | return NS_OK;
|
---|
2305 | }
|
---|
2306 |
|
---|
2307 | NS_IMETHODIMP
|
---|
2308 | nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *outContains)
|
---|
2309 | {
|
---|
2310 | /* Note here that we make no attempt to deal with the problem
|
---|
2311 | of folder aliases. Doing a 'Contains' test and dealing with
|
---|
2312 | folder aliases is Hard. Think about it.
|
---|
2313 | */
|
---|
2314 | *outContains = PR_FALSE;
|
---|
2315 |
|
---|
2316 | PRBool isDir;
|
---|
2317 | nsresult rv = IsDirectory(&isDir); // need to cache this
|
---|
2318 | if (NS_FAILED(rv)) return rv;
|
---|
2319 | if (!isDir) return NS_OK; // must be a dir to contain someone
|
---|
2320 |
|
---|
2321 | nsCOMPtr<nsILocalFileMac> macFile(do_QueryInterface(inFile));
|
---|
2322 | if (!macFile) return NS_OK; // trying to compare non-local with local file
|
---|
2323 |
|
---|
2324 | FSSpec mySpec = mSpec;
|
---|
2325 | FSSpec compareSpec;
|
---|
2326 |
|
---|
2327 | // NOTE: we're not resolving inFile if it was an alias
|
---|
2328 | StFollowLinksState followState(macFile, PR_FALSE);
|
---|
2329 | rv = macFile->GetFSSpec(&compareSpec);
|
---|
2330 | if (NS_FAILED(rv)) return rv;
|
---|
2331 |
|
---|
2332 | // if they are on different volumes, bail
|
---|
2333 | if (mSpec.vRefNum != compareSpec.vRefNum)
|
---|
2334 | return NS_OK;
|
---|
2335 |
|
---|
2336 | // if recur == true, test every parent, otherwise just test the first one
|
---|
2337 | // (yes, recur does not get set in this loop)
|
---|
2338 | OSErr err = noErr;
|
---|
2339 | do
|
---|
2340 | {
|
---|
2341 | FSSpec parentFolderSpec;
|
---|
2342 | err = GetParentFolderSpec(compareSpec, parentFolderSpec);
|
---|
2343 | if (err != noErr) break; // we reached the top
|
---|
2344 |
|
---|
2345 | if (IsEqualFSSpec(parentFolderSpec, mySpec))
|
---|
2346 | {
|
---|
2347 | *outContains = PR_TRUE;
|
---|
2348 | break;
|
---|
2349 | }
|
---|
2350 |
|
---|
2351 | compareSpec = parentFolderSpec;
|
---|
2352 | } while (recur);
|
---|
2353 |
|
---|
2354 | return NS_OK;
|
---|
2355 | }
|
---|
2356 |
|
---|
2357 |
|
---|
2358 |
|
---|
2359 | NS_IMETHODIMP
|
---|
2360 | nsLocalFile::GetNativeTarget(nsACString &_retval)
|
---|
2361 | {
|
---|
2362 | _retval.Truncate();
|
---|
2363 |
|
---|
2364 | PRBool symLink;
|
---|
2365 |
|
---|
2366 | nsresult rv = IsSymlink(&symLink);
|
---|
2367 | if (NS_FAILED(rv))
|
---|
2368 | return rv;
|
---|
2369 |
|
---|
2370 | if (!symLink)
|
---|
2371 | return NS_ERROR_FILE_INVALID_PATH;
|
---|
2372 |
|
---|
2373 | StFollowLinksState followState(this, PR_TRUE);
|
---|
2374 | return GetNativePath(_retval);
|
---|
2375 | }
|
---|
2376 |
|
---|
2377 | NS_IMETHODIMP
|
---|
2378 | nsLocalFile::GetTarget(nsAString &_retval)
|
---|
2379 | {
|
---|
2380 | nsresult rv;
|
---|
2381 | nsCAutoString fsStr;
|
---|
2382 |
|
---|
2383 | if (NS_SUCCEEDED(rv = GetNativeTarget(fsStr))) {
|
---|
2384 | rv = NS_CopyNativeToUnicode(fsStr, _retval);
|
---|
2385 | }
|
---|
2386 | return rv;
|
---|
2387 | }
|
---|
2388 |
|
---|
2389 | NS_IMETHODIMP
|
---|
2390 | nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator * *entries)
|
---|
2391 | {
|
---|
2392 | nsresult rv;
|
---|
2393 |
|
---|
2394 | *entries = nsnull;
|
---|
2395 |
|
---|
2396 | PRBool isDir;
|
---|
2397 | rv = IsDirectory(&isDir);
|
---|
2398 | if (NS_FAILED(rv))
|
---|
2399 | return rv;
|
---|
2400 | if (!isDir)
|
---|
2401 | return NS_ERROR_FILE_NOT_DIRECTORY;
|
---|
2402 |
|
---|
2403 | nsDirEnumerator* dirEnum = new nsDirEnumerator();
|
---|
2404 | if (dirEnum == nsnull)
|
---|
2405 | return NS_ERROR_OUT_OF_MEMORY;
|
---|
2406 | NS_ADDREF(dirEnum);
|
---|
2407 | rv = dirEnum->Init(this);
|
---|
2408 | if (NS_FAILED(rv))
|
---|
2409 | {
|
---|
2410 | NS_RELEASE(dirEnum);
|
---|
2411 | return rv;
|
---|
2412 | }
|
---|
2413 |
|
---|
2414 | *entries = dirEnum;
|
---|
2415 | return NS_OK;
|
---|
2416 | }
|
---|
2417 |
|
---|
2418 | NS_IMETHODIMP
|
---|
2419 | nsLocalFile::GetPersistentDescriptor(nsACString &aPersistentDescriptor)
|
---|
2420 | {
|
---|
2421 | aPersistentDescriptor.Truncate();
|
---|
2422 |
|
---|
2423 | nsresult rv = ResolveAndStat();
|
---|
2424 | if ( NS_FAILED( rv ) )
|
---|
2425 | return rv;
|
---|
2426 |
|
---|
2427 | AliasHandle aliasH;
|
---|
2428 | OSErr err = ::NewAlias(nil, &mTargetSpec, &aliasH);
|
---|
2429 | if (err != noErr)
|
---|
2430 | return MacErrorMapper(err);
|
---|
2431 |
|
---|
2432 | PRUint32 bytes = ::GetHandleSize((Handle) aliasH);
|
---|
2433 | HLock((Handle) aliasH);
|
---|
2434 | char* buf = PL_Base64Encode((const char*)*aliasH, bytes, nsnull); // Passing nsnull for dest makes NULL-term string
|
---|
2435 | ::DisposeHandle((Handle) aliasH);
|
---|
2436 | NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY);
|
---|
2437 |
|
---|
2438 | aPersistentDescriptor = buf;
|
---|
2439 | PR_Free(buf);
|
---|
2440 |
|
---|
2441 | return NS_OK;
|
---|
2442 | }
|
---|
2443 |
|
---|
2444 | NS_IMETHODIMP
|
---|
2445 | nsLocalFile::SetPersistentDescriptor(const nsACString &aPersistentDescriptor)
|
---|
2446 | {
|
---|
2447 | if (aPersistentDescriptor.IsEmpty())
|
---|
2448 | return NS_ERROR_INVALID_ARG;
|
---|
2449 |
|
---|
2450 | nsresult rv = NS_OK;
|
---|
2451 |
|
---|
2452 | PRUint32 dataSize = aPersistentDescriptor.Length();
|
---|
2453 | char* decodedData = PL_Base64Decode(PromiseFlatCString(aPersistentDescriptor).get(), dataSize, nsnull);
|
---|
2454 | // Cast to an alias record and resolve.
|
---|
2455 | AliasHandle aliasH = nsnull;
|
---|
2456 | if (::PtrToHand(decodedData, &(Handle)aliasH, (dataSize * 3) / 4) != noErr)
|
---|
2457 | rv = NS_ERROR_OUT_OF_MEMORY;
|
---|
2458 | PR_Free(decodedData);
|
---|
2459 | NS_ENSURE_SUCCESS(rv, rv);
|
---|
2460 |
|
---|
2461 | Boolean changed;
|
---|
2462 | FSSpec resolvedSpec;
|
---|
2463 | OSErr err;
|
---|
2464 | err = ::ResolveAlias(nsnull, aliasH, &resolvedSpec, &changed);
|
---|
2465 | if (err == fnfErr) // resolvedSpec is valid in this case
|
---|
2466 | err = noErr;
|
---|
2467 | rv = MacErrorMapper(err);
|
---|
2468 | DisposeHandle((Handle) aliasH);
|
---|
2469 | NS_ENSURE_SUCCESS(rv, rv);
|
---|
2470 |
|
---|
2471 | return InitWithFSSpec(&resolvedSpec);
|
---|
2472 | }
|
---|
2473 |
|
---|
2474 | #pragma mark -
|
---|
2475 |
|
---|
2476 | // a stack-based, exception safe class for an AEDesc
|
---|
2477 |
|
---|
2478 | #pragma mark
|
---|
2479 | class StAEDesc: public AEDesc
|
---|
2480 | {
|
---|
2481 | public:
|
---|
2482 | StAEDesc()
|
---|
2483 | {
|
---|
2484 | descriptorType = typeNull;
|
---|
2485 | dataHandle = nil;
|
---|
2486 | }
|
---|
2487 |
|
---|
2488 | ~StAEDesc()
|
---|
2489 | {
|
---|
2490 | ::AEDisposeDesc(this);
|
---|
2491 | }
|
---|
2492 |
|
---|
2493 | void Clear()
|
---|
2494 | {
|
---|
2495 | ::AEDisposeDesc(this);
|
---|
2496 | descriptorType = typeNull;
|
---|
2497 | dataHandle = nil;
|
---|
2498 | }
|
---|
2499 |
|
---|
2500 | private:
|
---|
2501 | // disallow copies and assigns
|
---|
2502 | StAEDesc(const StAEDesc& rhs); // copy constructor
|
---|
2503 | StAEDesc& operator= (const StAEDesc&rhs); // throws OSErrs
|
---|
2504 |
|
---|
2505 | };
|
---|
2506 |
|
---|
2507 | #pragma mark -
|
---|
2508 | #pragma mark [Utility methods]
|
---|
2509 |
|
---|
2510 |
|
---|
2511 | nsresult nsLocalFile::UpdateCachedCatInfo(PRBool forceUpdate)
|
---|
2512 | {
|
---|
2513 | if (!mCatInfoDirty && !forceUpdate)
|
---|
2514 | return NS_OK;
|
---|
2515 |
|
---|
2516 | FSSpec spectoUse = mFollowLinks ? mTargetSpec : mSpec;
|
---|
2517 | mCachedCatInfo.hFileInfo.ioCompletion = nsnull;
|
---|
2518 | mCachedCatInfo.hFileInfo.ioFDirIndex = 0; // use dirID and name
|
---|
2519 | mCachedCatInfo.hFileInfo.ioVRefNum = spectoUse.vRefNum;
|
---|
2520 | mCachedCatInfo.hFileInfo.ioDirID = spectoUse.parID;
|
---|
2521 | mCachedCatInfo.hFileInfo.ioNamePtr = spectoUse.name;
|
---|
2522 |
|
---|
2523 | OSErr err = ::PBGetCatInfoSync(&mCachedCatInfo);
|
---|
2524 | if (err == noErr)
|
---|
2525 | {
|
---|
2526 | mCatInfoDirty = PR_FALSE;
|
---|
2527 | return NS_OK;
|
---|
2528 | }
|
---|
2529 | return MacErrorMapper(err);
|
---|
2530 | }
|
---|
2531 |
|
---|
2532 |
|
---|
2533 | nsresult nsLocalFile::FindRunningAppBySignature (OSType aAppSig, FSSpec& outSpec, ProcessSerialNumber& outPsn)
|
---|
2534 | {
|
---|
2535 | ProcessInfoRec info;
|
---|
2536 | FSSpec tempFSSpec;
|
---|
2537 | OSErr err = noErr;
|
---|
2538 |
|
---|
2539 | outPsn.highLongOfPSN = 0;
|
---|
2540 | outPsn.lowLongOfPSN = kNoProcess;
|
---|
2541 |
|
---|
2542 | while (PR_TRUE)
|
---|
2543 | {
|
---|
2544 | err = ::GetNextProcess(&outPsn);
|
---|
2545 | if (err == procNotFound) break;
|
---|
2546 | if (err != noErr) return NS_ERROR_FAILURE;
|
---|
2547 | info.processInfoLength = sizeof(ProcessInfoRec);
|
---|
2548 | info.processName = nil;
|
---|
2549 | info.processAppSpec = &tempFSSpec;
|
---|
2550 | err = ::GetProcessInformation(&outPsn, &info);
|
---|
2551 | if (err != noErr) return NS_ERROR_FAILURE;
|
---|
2552 |
|
---|
2553 | if (info.processSignature == aAppSig)
|
---|
2554 | {
|
---|
2555 | outSpec = tempFSSpec;
|
---|
2556 | return NS_OK;
|
---|
2557 | }
|
---|
2558 | }
|
---|
2559 |
|
---|
2560 | return NS_ERROR_FILE_NOT_FOUND; // really process not found
|
---|
2561 | }
|
---|
2562 |
|
---|
2563 |
|
---|
2564 | nsresult nsLocalFile::FindRunningAppByFSSpec(const FSSpec& appSpec, ProcessSerialNumber& outPsn)
|
---|
2565 | {
|
---|
2566 | ProcessInfoRec info;
|
---|
2567 | FSSpec tempFSSpec;
|
---|
2568 | OSErr err = noErr;
|
---|
2569 |
|
---|
2570 | outPsn.highLongOfPSN = 0;
|
---|
2571 | outPsn.lowLongOfPSN = kNoProcess;
|
---|
2572 |
|
---|
2573 | while (PR_TRUE)
|
---|
2574 | {
|
---|
2575 | err = ::GetNextProcess(&outPsn);
|
---|
2576 | if (err == procNotFound) break;
|
---|
2577 | if (err != noErr) return NS_ERROR_FAILURE;
|
---|
2578 | info.processInfoLength = sizeof(ProcessInfoRec);
|
---|
2579 | info.processName = nil;
|
---|
2580 | info.processAppSpec = &tempFSSpec;
|
---|
2581 | err = ::GetProcessInformation(&outPsn, &info);
|
---|
2582 | if (err != noErr) return NS_ERROR_FAILURE;
|
---|
2583 |
|
---|
2584 | if (IsEqualFSSpec(appSpec, *info.processAppSpec))
|
---|
2585 | {
|
---|
2586 | return NS_OK;
|
---|
2587 | }
|
---|
2588 | }
|
---|
2589 |
|
---|
2590 | return NS_ERROR_FILE_NOT_FOUND; // really process not found
|
---|
2591 | }
|
---|
2592 |
|
---|
2593 |
|
---|
2594 | nsresult nsLocalFile::FindAppOnLocalVolumes(OSType sig, FSSpec &outSpec)
|
---|
2595 | {
|
---|
2596 | OSErr err;
|
---|
2597 |
|
---|
2598 | // get the system volume
|
---|
2599 | long systemFolderDirID;
|
---|
2600 | short sysVRefNum;
|
---|
2601 | err = FindFolder(kOnSystemDisk, kSystemFolderType, false, &sysVRefNum, &systemFolderDirID);
|
---|
2602 | if (err != noErr) return NS_ERROR_FAILURE;
|
---|
2603 |
|
---|
2604 | short vRefNum = sysVRefNum;
|
---|
2605 | short index = 0;
|
---|
2606 |
|
---|
2607 | while (true)
|
---|
2608 | {
|
---|
2609 | if (index == 0 || vRefNum != sysVRefNum)
|
---|
2610 | {
|
---|
2611 | // should we avoid AppleShare volumes?
|
---|
2612 |
|
---|
2613 | Boolean hasDesktopDB;
|
---|
2614 | err = VolHasDesktopDB(vRefNum, &hasDesktopDB);
|
---|
2615 | if (err != noErr) return err;
|
---|
2616 | if (hasDesktopDB)
|
---|
2617 | {
|
---|
2618 | err = FindAppOnVolume(sig, vRefNum, &outSpec);
|
---|
2619 | if (err != afpItemNotFound) return err;
|
---|
2620 | }
|
---|
2621 | }
|
---|
2622 | index++;
|
---|
2623 | err = GetIndVolume(index, &vRefNum);
|
---|
2624 | if (err == nsvErr) return fnfErr;
|
---|
2625 | if (err != noErr) return err;
|
---|
2626 | }
|
---|
2627 |
|
---|
2628 | return NS_OK;
|
---|
2629 | }
|
---|
2630 |
|
---|
2631 | #define aeSelectionKeyword 'fsel'
|
---|
2632 | #define kAEOpenSelection 'sope'
|
---|
2633 | #define kAERevealSelection 'srev'
|
---|
2634 | #define kFinderType 'FNDR'
|
---|
2635 |
|
---|
2636 | NS_IMETHODIMP nsLocalFile::Launch()
|
---|
2637 | {
|
---|
2638 | AppleEvent aeEvent = {0, nil};
|
---|
2639 | AppleEvent aeReply = {0, nil};
|
---|
2640 | StAEDesc aeDirDesc, listElem, myAddressDesc, fileList;
|
---|
2641 | FSSpec dirSpec, appSpec;
|
---|
2642 | AliasHandle DirAlias, FileAlias;
|
---|
2643 | OSErr errorResult = noErr;
|
---|
2644 | ProcessSerialNumber process;
|
---|
2645 |
|
---|
2646 | // for launching a file, we'll use mTargetSpec (which is both a resolved spec and a resolved alias)
|
---|
2647 | ResolveAndStat();
|
---|
2648 |
|
---|
2649 | #if TARGET_CARBON
|
---|
2650 | if (sRunningOSX)
|
---|
2651 | { // We're running under Mac OS X, LaunchServices here we come
|
---|
2652 |
|
---|
2653 | // First we make sure the LaunchServices routine we want is implemented
|
---|
2654 | if ( (UInt32)LSOpenFSRef != (UInt32)kUnresolvedCFragSymbolAddress )
|
---|
2655 | {
|
---|
2656 | FSRef theRef;
|
---|
2657 | if (::FSpMakeFSRef(&mTargetSpec, &theRef) == noErr)
|
---|
2658 | {
|
---|
2659 | (void)::LSOpenFSRef(&theRef, NULL);
|
---|
2660 | }
|
---|
2661 | }
|
---|
2662 | }
|
---|
2663 | else
|
---|
2664 | #endif
|
---|
2665 | { // We're running under Mac OS 8.x/9.x, use the Finder Luke
|
---|
2666 | nsresult rv = FindRunningAppBySignature ('MACS', appSpec, process);
|
---|
2667 | if (NS_SUCCEEDED(rv))
|
---|
2668 | {
|
---|
2669 | errorResult = AECreateDesc(typeProcessSerialNumber, (Ptr)&process, sizeof(process), &myAddressDesc);
|
---|
2670 | if (errorResult == noErr)
|
---|
2671 | {
|
---|
2672 | /* Create the FinderEvent */
|
---|
2673 | errorResult = AECreateAppleEvent(kFinderType, kAEOpenSelection, &myAddressDesc, kAutoGenerateReturnID, kAnyTransactionID,
|
---|
2674 | &aeEvent);
|
---|
2675 | if (errorResult == noErr)
|
---|
2676 | {
|
---|
2677 | errorResult = FSMakeFSSpec(mTargetSpec.vRefNum, mTargetSpec.parID, nil, &dirSpec);
|
---|
2678 | NewAlias(nil, &dirSpec, &DirAlias);
|
---|
2679 | /* Create alias for file */
|
---|
2680 | NewAlias(nil, &mTargetSpec, &FileAlias);
|
---|
2681 |
|
---|
2682 | /* Create the file list */
|
---|
2683 | errorResult = AECreateList(nil, 0, false, &fileList);
|
---|
2684 | /* create the folder descriptor */
|
---|
2685 | HLock((Handle)DirAlias);
|
---|
2686 | errorResult = AECreateDesc(typeAlias, (Ptr)*DirAlias, GetHandleSize((Handle)DirAlias), &aeDirDesc);
|
---|
2687 | HUnlock((Handle)DirAlias);
|
---|
2688 | if (errorResult == noErr)
|
---|
2689 | {
|
---|
2690 | errorResult = AEPutParamDesc(&aeEvent, keyDirectObject, &aeDirDesc);
|
---|
2691 | if ( errorResult == noErr)
|
---|
2692 | {
|
---|
2693 | /* create the file descriptor and add to aliasList */
|
---|
2694 | HLock((Handle)FileAlias);
|
---|
2695 | errorResult = AECreateDesc(typeAlias, (Ptr)*FileAlias, GetHandleSize((Handle)FileAlias), &listElem);
|
---|
2696 | HLock((Handle)FileAlias);
|
---|
2697 | if (errorResult == noErr)
|
---|
2698 | {
|
---|
2699 | errorResult = AEPutDesc(&fileList, 0, &listElem);
|
---|
2700 | if (errorResult == noErr)
|
---|
2701 | {
|
---|
2702 | /* Add the file alias list to the event */
|
---|
2703 | errorResult = AEPutParamDesc(&aeEvent, aeSelectionKeyword, &fileList);
|
---|
2704 | if (errorResult == noErr)
|
---|
2705 | AESend(&aeEvent, &aeReply, kAEWaitReply + kAENeverInteract
|
---|
2706 | + kAECanSwitchLayer, kAEHighPriority, kAEDefaultTimeout, nil, nil);
|
---|
2707 | }
|
---|
2708 | }
|
---|
2709 | }
|
---|
2710 | }
|
---|
2711 | }
|
---|
2712 | }
|
---|
2713 | }
|
---|
2714 | }
|
---|
2715 |
|
---|
2716 | return NS_OK;
|
---|
2717 | }
|
---|
2718 |
|
---|
2719 | NS_IMETHODIMP nsLocalFile::Reveal()
|
---|
2720 | {
|
---|
2721 | FSSpec specToReveal;
|
---|
2722 | AppleEvent aeEvent = {0, nil};
|
---|
2723 | AppleEvent aeReply = {0, nil};
|
---|
2724 | StAEDesc aeDirDesc, listElem, myAddressDesc, fileList;
|
---|
2725 | OSErr errorResult = noErr;
|
---|
2726 | ProcessSerialNumber process;
|
---|
2727 | FSSpec appSpec;
|
---|
2728 |
|
---|
2729 | nsresult rv = ResolveAndStat();
|
---|
2730 | if (NS_FAILED(rv))
|
---|
2731 | return rv;
|
---|
2732 | rv = GetFSSpec(&specToReveal); // Pay attention to followLinks
|
---|
2733 | if (NS_FAILED(rv))
|
---|
2734 | return rv;
|
---|
2735 |
|
---|
2736 | rv = FindRunningAppBySignature ('MACS', appSpec, process);
|
---|
2737 | if (NS_SUCCEEDED(rv))
|
---|
2738 | {
|
---|
2739 | errorResult = AECreateDesc(typeProcessSerialNumber, (Ptr)&process, sizeof(process), &myAddressDesc);
|
---|
2740 | if (errorResult == noErr)
|
---|
2741 | {
|
---|
2742 | /* Create the FinderEvent */
|
---|
2743 | #if TARGET_CARBON
|
---|
2744 | // The Finder under OS X uses a different event to reveal
|
---|
2745 | if (sRunningOSX)
|
---|
2746 | errorResult = AECreateAppleEvent(kAEMiscStandards, kAEMakeObjectsVisible, &myAddressDesc, kAutoGenerateReturnID, kAnyTransactionID,
|
---|
2747 | &aeEvent);
|
---|
2748 | else
|
---|
2749 | #endif
|
---|
2750 | errorResult = AECreateAppleEvent(kFinderType, kAERevealSelection, &myAddressDesc, kAutoGenerateReturnID, kAnyTransactionID,
|
---|
2751 | &aeEvent);
|
---|
2752 | if (errorResult == noErr)
|
---|
2753 | {
|
---|
2754 | /* Create the file list */
|
---|
2755 | errorResult = AECreateList(nil, 0, false, &fileList);
|
---|
2756 | if (errorResult == noErr)
|
---|
2757 | {
|
---|
2758 | errorResult = AEPutPtr(&fileList, 0, typeFSS, &specToReveal, sizeof(FSSpec));
|
---|
2759 |
|
---|
2760 | if (errorResult == noErr)
|
---|
2761 | {
|
---|
2762 | #if TARGET_CARBON
|
---|
2763 | // When we're sending the event under OS X the FSSpec must be a keyDirectObject
|
---|
2764 | if (sRunningOSX)
|
---|
2765 | errorResult = AEPutParamDesc(&aeEvent, keyDirectObject, &fileList);
|
---|
2766 | else
|
---|
2767 | #endif
|
---|
2768 | errorResult = AEPutParamDesc(&aeEvent,keySelection, &fileList);
|
---|
2769 |
|
---|
2770 | if (errorResult == noErr)
|
---|
2771 | {
|
---|
2772 | errorResult = AESend(&aeEvent, &aeReply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, nil, nil);
|
---|
2773 | if (errorResult == noErr)
|
---|
2774 | SetFrontProcess(&process);
|
---|
2775 | }
|
---|
2776 | }
|
---|
2777 | }
|
---|
2778 | }
|
---|
2779 | }
|
---|
2780 | }
|
---|
2781 |
|
---|
2782 | return NS_OK;
|
---|
2783 | }
|
---|
2784 |
|
---|
2785 | nsresult nsLocalFile::MyLaunchAppWithDoc(const FSSpec& appSpec, const FSSpec* aDocToLoad, PRBool aLaunchInBackground)
|
---|
2786 | {
|
---|
2787 | ProcessSerialNumber thePSN = {0};
|
---|
2788 | StAEDesc target;
|
---|
2789 | StAEDesc docDesc;
|
---|
2790 | StAEDesc launchDesc;
|
---|
2791 | StAEDesc docList;
|
---|
2792 | AppleEvent theEvent = {0, nil};
|
---|
2793 | AppleEvent theReply = {0, nil};
|
---|
2794 | OSErr err = noErr;
|
---|
2795 | Boolean autoParamValue = false;
|
---|
2796 | Boolean running = false;
|
---|
2797 | nsresult rv = NS_OK;
|
---|
2798 |
|
---|
2799 | #if TARGET_CARBON
|
---|
2800 | if (sRunningOSX)
|
---|
2801 | { // Under Mac OS X we'll use LaunchServices
|
---|
2802 |
|
---|
2803 | // First we make sure the LaunchServices routine we want is implemented
|
---|
2804 | if ( (UInt32)LSOpenFromRefSpec != (UInt32)kUnresolvedCFragSymbolAddress )
|
---|
2805 | {
|
---|
2806 | FSRef appRef;
|
---|
2807 | FSRef docRef;
|
---|
2808 | LSLaunchFlags theLaunchFlags = kLSLaunchDefaults;
|
---|
2809 | LSLaunchFSRefSpec thelaunchSpec;
|
---|
2810 |
|
---|
2811 | if (::FSpMakeFSRef(&appSpec, &appRef) != noErr)
|
---|
2812 | return NS_ERROR_FAILURE;
|
---|
2813 |
|
---|
2814 | if (aDocToLoad)
|
---|
2815 | if (::FSpMakeFSRef(aDocToLoad, &docRef) != noErr)
|
---|
2816 | return NS_ERROR_FAILURE;
|
---|
2817 |
|
---|
2818 | if (aLaunchInBackground)
|
---|
2819 | theLaunchFlags |= kLSLaunchDontSwitch;
|
---|
2820 |
|
---|
2821 | memset(&thelaunchSpec, 0, sizeof(LSLaunchFSRefSpec));
|
---|
2822 |
|
---|
2823 | thelaunchSpec.appRef = &appRef;
|
---|
2824 | if (aDocToLoad)
|
---|
2825 | {
|
---|
2826 | thelaunchSpec.numDocs = 1;
|
---|
2827 | thelaunchSpec.itemRefs = &docRef;
|
---|
2828 | }
|
---|
2829 | thelaunchSpec.launchFlags = theLaunchFlags;
|
---|
2830 |
|
---|
2831 | err = ::LSOpenFromRefSpec(&thelaunchSpec, NULL);
|
---|
2832 | NS_ASSERTION((err != noErr), "Error calling LSOpenFromRefSpec");
|
---|
2833 | if (err != noErr) return NS_ERROR_FAILURE;
|
---|
2834 | }
|
---|
2835 | }
|
---|
2836 | else
|
---|
2837 | #endif
|
---|
2838 | { // The old fashioned way for Mac OS 8.x/9.x
|
---|
2839 | rv = FindRunningAppByFSSpec(appSpec, thePSN);
|
---|
2840 | running = NS_SUCCEEDED(rv);
|
---|
2841 |
|
---|
2842 | err = AECreateDesc(typeProcessSerialNumber, &thePSN, sizeof(thePSN), &target);
|
---|
2843 | if (err != noErr) return NS_ERROR_FAILURE;
|
---|
2844 |
|
---|
2845 | err = AECreateAppleEvent(kCoreEventClass, aDocToLoad ? kAEOpenDocuments : kAEOpenApplication, &target,
|
---|
2846 | kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
|
---|
2847 | if (err != noErr) return NS_ERROR_FAILURE;
|
---|
2848 |
|
---|
2849 | if (aDocToLoad)
|
---|
2850 | {
|
---|
2851 | err = AECreateList(nil, 0, false, &docList);
|
---|
2852 | if (err != noErr) return NS_ERROR_FAILURE;
|
---|
2853 |
|
---|
2854 | err = AECreateDesc(typeFSS, aDocToLoad, sizeof(FSSpec), &docDesc);
|
---|
2855 | if (err != noErr) return NS_ERROR_FAILURE;
|
---|
2856 |
|
---|
2857 | err = AEPutDesc(&docList, 0, &docDesc);
|
---|
2858 | if (err != noErr) return NS_ERROR_FAILURE;
|
---|
2859 |
|
---|
2860 | err = AEPutParamDesc(&theEvent, keyDirectObject, &docList);
|
---|
2861 | if (err != noErr) return NS_ERROR_FAILURE;
|
---|
2862 | }
|
---|
2863 |
|
---|
2864 | if (running)
|
---|
2865 | {
|
---|
2866 | err = AESend(&theEvent, &theReply, kAENoReply, kAENormalPriority, kNoTimeOut, nil, nil);
|
---|
2867 | if (err != noErr) return NS_ERROR_FAILURE;
|
---|
2868 |
|
---|
2869 | if (!aLaunchInBackground)
|
---|
2870 | {
|
---|
2871 | err = ::SetFrontProcess(&thePSN);
|
---|
2872 | if (err != noErr) return NS_ERROR_FAILURE;
|
---|
2873 | }
|
---|
2874 | }
|
---|
2875 | else
|
---|
2876 | {
|
---|
2877 | LaunchParamBlockRec launchThis = {0};
|
---|
2878 | PRUint16 launchControlFlags = (launchContinue | launchNoFileFlags);
|
---|
2879 | if (aLaunchInBackground)
|
---|
2880 | launchControlFlags |= launchDontSwitch;
|
---|
2881 |
|
---|
2882 | err = AECoerceDesc(&theEvent, typeAppParameters, &launchDesc);
|
---|
2883 | if (err != noErr) return NS_ERROR_FAILURE;
|
---|
2884 |
|
---|
2885 | launchThis.launchAppSpec = (FSSpecPtr)&appSpec;
|
---|
2886 | #if TARGET_CARBON && ACCESSOR_CALLS_ARE_FUNCTIONS
|
---|
2887 | ::AEGetDescData(&launchDesc, &launchThis.launchAppParameters, sizeof(launchThis.launchAppParameters));
|
---|
2888 | #else
|
---|
2889 | // no need to lock this handle.
|
---|
2890 | launchThis.launchAppParameters = (AppParametersPtr) *(launchDesc.dataHandle);
|
---|
2891 | #endif
|
---|
2892 | launchThis.launchBlockID = extendedBlock;
|
---|
2893 | launchThis.launchEPBLength = extendedBlockLen;
|
---|
2894 | launchThis.launchFileFlags = 0;
|
---|
2895 | launchThis.launchControlFlags = launchControlFlags;
|
---|
2896 | err = ::LaunchApplication(&launchThis);
|
---|
2897 | if (err != noErr) return NS_ERROR_FAILURE;
|
---|
2898 |
|
---|
2899 | // let's be nice and wait until it's running
|
---|
2900 | const PRUint32 kMaxTimeToWait = 60; // wait 1 sec max
|
---|
2901 | PRUint32 endTicks = ::TickCount() + kMaxTimeToWait;
|
---|
2902 |
|
---|
2903 | PRBool foundApp = PR_FALSE;
|
---|
2904 |
|
---|
2905 | do
|
---|
2906 | {
|
---|
2907 | EventRecord theEvent;
|
---|
2908 | (void)WaitNextEvent(nullEvent, &theEvent, 1, NULL);
|
---|
2909 |
|
---|
2910 | ProcessSerialNumber psn;
|
---|
2911 | foundApp = NS_SUCCEEDED(FindRunningAppByFSSpec(appSpec, psn));
|
---|
2912 |
|
---|
2913 | } while (!foundApp && (::TickCount() <= endTicks));
|
---|
2914 |
|
---|
2915 | NS_ASSERTION(foundApp, "Failed to find app after launching it");
|
---|
2916 | }
|
---|
2917 |
|
---|
2918 | if (theEvent.dataHandle != nil) AEDisposeDesc(&theEvent);
|
---|
2919 | if (theReply.dataHandle != nil) AEDisposeDesc(&theReply);
|
---|
2920 | }
|
---|
2921 |
|
---|
2922 | return NS_OK;
|
---|
2923 | }
|
---|
2924 |
|
---|
2925 |
|
---|
2926 | #pragma mark -
|
---|
2927 | #pragma mark [Methods that will not be implemented on Mac]
|
---|
2928 |
|
---|
2929 | NS_IMETHODIMP
|
---|
2930 | nsLocalFile::Normalize()
|
---|
2931 | {
|
---|
2932 | return NS_ERROR_NOT_IMPLEMENTED;
|
---|
2933 | }
|
---|
2934 |
|
---|
2935 | NS_IMETHODIMP
|
---|
2936 | nsLocalFile::GetPermissions(PRUint32 *aPermissions)
|
---|
2937 | {
|
---|
2938 | return NS_ERROR_NOT_IMPLEMENTED;
|
---|
2939 | }
|
---|
2940 |
|
---|
2941 | NS_IMETHODIMP
|
---|
2942 | nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissionsOfLink)
|
---|
2943 | {
|
---|
2944 | return NS_ERROR_NOT_IMPLEMENTED;
|
---|
2945 | }
|
---|
2946 |
|
---|
2947 |
|
---|
2948 | NS_IMETHODIMP
|
---|
2949 | nsLocalFile::SetPermissions(PRUint32 aPermissions)
|
---|
2950 | {
|
---|
2951 | return NS_ERROR_NOT_IMPLEMENTED;
|
---|
2952 | }
|
---|
2953 |
|
---|
2954 | NS_IMETHODIMP
|
---|
2955 | nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissions)
|
---|
2956 | {
|
---|
2957 | return NS_ERROR_NOT_IMPLEMENTED;
|
---|
2958 | }
|
---|
2959 |
|
---|
2960 | NS_IMETHODIMP
|
---|
2961 | nsLocalFile::IsSpecial(PRBool *_retval)
|
---|
2962 | {
|
---|
2963 | return NS_ERROR_NOT_IMPLEMENTED;
|
---|
2964 | }
|
---|
2965 |
|
---|
2966 | #pragma mark -
|
---|
2967 | #pragma mark [nsILocalFileMac]
|
---|
2968 | // Implementation of Mac specific finctions from nsILocalFileMac
|
---|
2969 |
|
---|
2970 |
|
---|
2971 | NS_IMETHODIMP nsLocalFile::InitWithCFURL(CFURLRef aCFURL)
|
---|
2972 | {
|
---|
2973 | nsresult rv = NS_ERROR_FAILURE;
|
---|
2974 |
|
---|
2975 | #if TARGET_CARBON
|
---|
2976 | NS_ENSURE_ARG(aCFURL);
|
---|
2977 |
|
---|
2978 | // CFURLGetFSRef can only succeed if the entire path exists.
|
---|
2979 | FSRef fsRef;
|
---|
2980 | if (::CFURLGetFSRef(aCFURL, &fsRef) == PR_TRUE)
|
---|
2981 | rv = InitWithFSRef(&fsRef);
|
---|
2982 | else
|
---|
2983 | {
|
---|
2984 | CFURLRef parentURL = ::CFURLCreateCopyDeletingLastPathComponent(NULL, aCFURL);
|
---|
2985 | if (!parentURL)
|
---|
2986 | return NS_ERROR_FAILURE;
|
---|
2987 |
|
---|
2988 | // Get the FSRef from the parent and the FSSpec from that
|
---|
2989 | FSRef parentFSRef;
|
---|
2990 | FSSpec parentFSSpec;
|
---|
2991 | if ((::CFURLGetFSRef(parentURL, &parentFSRef) == PR_TRUE) &&
|
---|
2992 | (::FSGetCatalogInfo(&parentFSRef, kFSCatInfoNone,
|
---|
2993 | nsnull, nsnull, &parentFSSpec, nsnull) == noErr))
|
---|
2994 | {
|
---|
2995 | // Get the leaf name of the file and turn it into a string HFS can use.
|
---|
2996 | CFStringRef fileNameRef = ::CFURLCopyLastPathComponent(aCFURL);
|
---|
2997 | if (fileNameRef)
|
---|
2998 | {
|
---|
2999 | TextEncoding theEncoding;
|
---|
3000 | if (::UpgradeScriptInfoToTextEncoding(smSystemScript,
|
---|
3001 | kTextLanguageDontCare,
|
---|
3002 | kTextRegionDontCare,
|
---|
3003 | NULL,
|
---|
3004 | &theEncoding) != noErr)
|
---|
3005 | theEncoding = kTextEncodingMacRoman;
|
---|
3006 |
|
---|
3007 | char origName[256];
|
---|
3008 | char truncBuf[32];
|
---|
3009 | if (::CFStringGetCString(fileNameRef, origName, sizeof(origName), theEncoding))
|
---|
3010 | {
|
---|
3011 | MakeDirty();
|
---|
3012 | mSpec = parentFSSpec;
|
---|
3013 | mAppendedPath = NS_TruncNodeName(origName, truncBuf);
|
---|
3014 | rv = NS_OK;
|
---|
3015 | }
|
---|
3016 | ::CFRelease(fileNameRef);
|
---|
3017 | }
|
---|
3018 | }
|
---|
3019 | ::CFRelease(parentURL);
|
---|
3020 | }
|
---|
3021 | #endif
|
---|
3022 |
|
---|
3023 | return rv;
|
---|
3024 | }
|
---|
3025 |
|
---|
3026 |
|
---|
3027 | NS_IMETHODIMP nsLocalFile::InitWithFSRef(const FSRef * aFSRef)
|
---|
3028 | {
|
---|
3029 | nsresult rv = NS_ERROR_FAILURE;
|
---|
3030 |
|
---|
3031 | #if TARGET_CARBON
|
---|
3032 | NS_ENSURE_ARG(aFSRef);
|
---|
3033 |
|
---|
3034 | FSSpec fsSpec;
|
---|
3035 | OSErr err = ::FSGetCatalogInfo(aFSRef, kFSCatInfoNone, nsnull,
|
---|
3036 | nsnull, &fsSpec, nsnull);
|
---|
3037 | if (err == noErr)
|
---|
3038 | rv = InitWithFSSpec(&fsSpec);
|
---|
3039 | else
|
---|
3040 | rv = MacErrorMapper(err);
|
---|
3041 | #endif
|
---|
3042 |
|
---|
3043 | return rv;
|
---|
3044 | }
|
---|
3045 |
|
---|
3046 |
|
---|
3047 | NS_IMETHODIMP nsLocalFile::InitWithFSSpec(const FSSpec *fileSpec)
|
---|
3048 | {
|
---|
3049 | MakeDirty();
|
---|
3050 | mSpec = *fileSpec;
|
---|
3051 | mTargetSpec = *fileSpec;
|
---|
3052 | mAppendedPath = "";
|
---|
3053 | return NS_OK;
|
---|
3054 | }
|
---|
3055 |
|
---|
3056 |
|
---|
3057 | NS_IMETHODIMP nsLocalFile::InitToAppWithCreatorCode(OSType aAppCreator)
|
---|
3058 | {
|
---|
3059 | FSSpec appSpec;
|
---|
3060 | ProcessSerialNumber psn;
|
---|
3061 |
|
---|
3062 | #if TARGET_CARBON
|
---|
3063 | if (sRunningOSX)
|
---|
3064 | { // If we're running under OS X use LaunchServices to determine the app
|
---|
3065 | // corresponding to the creator code
|
---|
3066 | if ( (UInt32)LSFindApplicationForInfo != (UInt32)kUnresolvedCFragSymbolAddress )
|
---|
3067 | {
|
---|
3068 | FSRef theRef;
|
---|
3069 | if (::LSFindApplicationForInfo(aAppCreator, NULL, NULL, &theRef, NULL) == noErr)
|
---|
3070 | {
|
---|
3071 | FSCatalogInfoBitmap whichInfo = kFSCatInfoNone;
|
---|
3072 |
|
---|
3073 | if (::FSGetCatalogInfo(&theRef, whichInfo, NULL, NULL, &appSpec, NULL) == noErr)
|
---|
3074 | return InitWithFSSpec(&appSpec);
|
---|
3075 | }
|
---|
3076 |
|
---|
3077 | // If we get here we didn't find an app
|
---|
3078 | return NS_ERROR_FILE_NOT_FOUND;
|
---|
3079 | }
|
---|
3080 | }
|
---|
3081 | #endif
|
---|
3082 |
|
---|
3083 | // is the app running?
|
---|
3084 | nsresult rv = FindRunningAppBySignature(aAppCreator, appSpec, psn);
|
---|
3085 | if (rv == NS_ERROR_FILE_NOT_FOUND)
|
---|
3086 | {
|
---|
3087 | // we have to look on disk
|
---|
3088 | rv = FindAppOnLocalVolumes(aAppCreator, appSpec);
|
---|
3089 | if (NS_FAILED(rv)) return rv;
|
---|
3090 | }
|
---|
3091 | else if (NS_FAILED(rv))
|
---|
3092 | return rv;
|
---|
3093 |
|
---|
3094 | // init with the spec here
|
---|
3095 | return InitWithFSSpec(&appSpec);
|
---|
3096 | }
|
---|
3097 |
|
---|
3098 | NS_IMETHODIMP nsLocalFile::GetCFURL(CFURLRef *_retval)
|
---|
3099 | {
|
---|
3100 | nsresult rv = NS_ERROR_FAILURE;
|
---|
3101 |
|
---|
3102 | #if TARGET_CARBON
|
---|
3103 | NS_ENSURE_ARG_POINTER(_retval);
|
---|
3104 | *_retval = nsnull;
|
---|
3105 |
|
---|
3106 | PRBool exists;
|
---|
3107 | if (NS_SUCCEEDED(Exists(&exists)) && exists)
|
---|
3108 | {
|
---|
3109 | FSRef fsRef;
|
---|
3110 | FSSpec fsSpec = mFollowLinks ? mTargetSpec : mSpec;
|
---|
3111 | if (::FSpMakeFSRef(&fsSpec, &fsRef) == noErr)
|
---|
3112 | {
|
---|
3113 | *_retval = ::CFURLCreateFromFSRef(NULL, &fsRef);
|
---|
3114 | if (*_retval)
|
---|
3115 | return NS_OK;
|
---|
3116 | }
|
---|
3117 | }
|
---|
3118 | else
|
---|
3119 | {
|
---|
3120 | nsCAutoString tempPath;
|
---|
3121 | if (NS_SUCCEEDED(GetNativePath(tempPath)))
|
---|
3122 | {
|
---|
3123 | CFStringRef pathStrRef = ::CFStringCreateWithCString(NULL, tempPath.get(), kCFStringEncodingMacRoman);
|
---|
3124 | if (!pathStrRef)
|
---|
3125 | return NS_ERROR_FAILURE;
|
---|
3126 | *_retval = ::CFURLCreateWithFileSystemPath(NULL, pathStrRef, kCFURLHFSPathStyle, false);
|
---|
3127 | ::CFRelease(pathStrRef);
|
---|
3128 | if (*_retval)
|
---|
3129 | return NS_OK;
|
---|
3130 | }
|
---|
3131 | }
|
---|
3132 | #endif
|
---|
3133 |
|
---|
3134 | return rv;
|
---|
3135 | }
|
---|
3136 |
|
---|
3137 | NS_IMETHODIMP nsLocalFile::GetFSRef(FSRef *_retval)
|
---|
3138 | {
|
---|
3139 | nsresult rv = NS_ERROR_FAILURE;
|
---|
3140 |
|
---|
3141 | #if TARGET_CARBON
|
---|
3142 | NS_ENSURE_ARG_POINTER(_retval);
|
---|
3143 |
|
---|
3144 | FSSpec fsSpec;
|
---|
3145 | rv = GetFSSpec(&fsSpec);
|
---|
3146 | if (NS_SUCCEEDED(rv))
|
---|
3147 | rv = MacErrorMapper(::FSpMakeFSRef(&fsSpec, _retval));
|
---|
3148 | #endif
|
---|
3149 |
|
---|
3150 | return rv;
|
---|
3151 | }
|
---|
3152 |
|
---|
3153 | NS_IMETHODIMP nsLocalFile::GetFSSpec(FSSpec *fileSpec)
|
---|
3154 | {
|
---|
3155 | NS_ENSURE_ARG(fileSpec);
|
---|
3156 | nsresult rv = ResolveAndStat();
|
---|
3157 | if (rv == NS_ERROR_FILE_NOT_FOUND)
|
---|
3158 | rv = NS_OK;
|
---|
3159 | if (NS_SUCCEEDED(rv))
|
---|
3160 | *fileSpec = mFollowLinks ? mTargetSpec : mSpec;
|
---|
3161 |
|
---|
3162 | return NS_OK;
|
---|
3163 | }
|
---|
3164 |
|
---|
3165 | NS_IMETHODIMP nsLocalFile::GetFileType(OSType *aFileType)
|
---|
3166 | {
|
---|
3167 | NS_ENSURE_ARG(aFileType);
|
---|
3168 |
|
---|
3169 | FSSpec fileSpec;
|
---|
3170 | (void)GetFSSpec(&fileSpec);
|
---|
3171 |
|
---|
3172 | FInfo info;
|
---|
3173 | OSErr err = ::FSpGetFInfo(&fileSpec, &info);
|
---|
3174 | if (err != noErr)
|
---|
3175 | {
|
---|
3176 | *aFileType = mType;
|
---|
3177 | return NS_ERROR_FILE_NOT_FOUND;
|
---|
3178 | }
|
---|
3179 |
|
---|
3180 | *aFileType = info.fdType;
|
---|
3181 |
|
---|
3182 | return NS_OK;
|
---|
3183 | }
|
---|
3184 |
|
---|
3185 | NS_IMETHODIMP nsLocalFile::SetFileType(OSType aFileType)
|
---|
3186 | {
|
---|
3187 | mType = aFileType;
|
---|
3188 |
|
---|
3189 | FSSpec fileSpec;
|
---|
3190 | (void)GetFSSpec(&fileSpec);
|
---|
3191 |
|
---|
3192 | FInfo info;
|
---|
3193 | OSErr err = ::FSpGetFInfo(&fileSpec, &info);
|
---|
3194 | if (err != noErr)
|
---|
3195 | return NS_ERROR_FILE_NOT_FOUND;
|
---|
3196 |
|
---|
3197 | info.fdType = aFileType;
|
---|
3198 | err = ::FSpSetFInfo(&fileSpec, &info);
|
---|
3199 | if (err != noErr)
|
---|
3200 | return NS_ERROR_FILE_ACCESS_DENIED;
|
---|
3201 |
|
---|
3202 | return NS_OK;
|
---|
3203 | }
|
---|
3204 |
|
---|
3205 | NS_IMETHODIMP nsLocalFile::GetFileCreator(OSType *aCreator)
|
---|
3206 | {
|
---|
3207 | NS_ENSURE_ARG(aCreator);
|
---|
3208 |
|
---|
3209 | FSSpec fileSpec;
|
---|
3210 | (void)GetFSSpec(&fileSpec);
|
---|
3211 |
|
---|
3212 | FInfo info;
|
---|
3213 | OSErr err = ::FSpGetFInfo(&fileSpec, &info);
|
---|
3214 | if (err != noErr)
|
---|
3215 | {
|
---|
3216 | *aCreator = mCreator;
|
---|
3217 | return NS_ERROR_FILE_NOT_FOUND;
|
---|
3218 | }
|
---|
3219 |
|
---|
3220 | *aCreator = info.fdCreator;
|
---|
3221 |
|
---|
3222 | return NS_OK;
|
---|
3223 | }
|
---|
3224 |
|
---|
3225 | NS_IMETHODIMP nsLocalFile::SetFileCreator(OSType aCreator)
|
---|
3226 | {
|
---|
3227 | if (aCreator == CURRENT_PROCESS_CREATOR)
|
---|
3228 | aCreator = sCurrentProcessSignature;
|
---|
3229 |
|
---|
3230 | mCreator = aCreator;
|
---|
3231 |
|
---|
3232 | FSSpec fileSpec;
|
---|
3233 | (void)GetFSSpec(&fileSpec);
|
---|
3234 |
|
---|
3235 | FInfo info;
|
---|
3236 | OSErr err = ::FSpGetFInfo(&fileSpec, &info);
|
---|
3237 | if (err != noErr)
|
---|
3238 | return NS_ERROR_FILE_NOT_FOUND;
|
---|
3239 |
|
---|
3240 | info.fdCreator = aCreator;
|
---|
3241 | err = ::FSpSetFInfo(&fileSpec, &info);
|
---|
3242 | if (err != noErr)
|
---|
3243 | return NS_ERROR_FILE_ACCESS_DENIED;
|
---|
3244 |
|
---|
3245 | return NS_OK;
|
---|
3246 | }
|
---|
3247 |
|
---|
3248 | NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromExtension(const char *aExtension)
|
---|
3249 | {
|
---|
3250 | NS_ENSURE_ARG(aExtension);
|
---|
3251 | return SetOSTypeAndCreatorFromExtension(aExtension);
|
---|
3252 | }
|
---|
3253 |
|
---|
3254 | NS_IMETHODIMP nsLocalFile::SetFileTypeAndCreatorFromMIMEType(const char *aMIMEType)
|
---|
3255 | {
|
---|
3256 | NS_ENSURE_ARG(aMIMEType);
|
---|
3257 |
|
---|
3258 | nsresult rv;
|
---|
3259 | nsCOMPtr<nsIInternetConfigService> icService(do_GetService
|
---|
3260 | (NS_INTERNETCONFIGSERVICE_CONTRACTID, &rv));
|
---|
3261 |
|
---|
3262 | if (NS_SUCCEEDED(rv))
|
---|
3263 | {
|
---|
3264 | nsCOMPtr<nsIMIMEInfo> mimeInfo;
|
---|
3265 | PRUint32 fileType = 'TEXT';
|
---|
3266 | PRUint32 fileCreator = nsILocalFileMac::CURRENT_PROCESS_CREATOR;
|
---|
3267 |
|
---|
3268 | rv = icService->FillInMIMEInfo(aMIMEType,
|
---|
3269 | nsnull, getter_AddRefs(mimeInfo));
|
---|
3270 | if (NS_SUCCEEDED(rv))
|
---|
3271 | rv = mimeInfo->GetMacType(&fileType);
|
---|
3272 | if (NS_SUCCEEDED(rv))
|
---|
3273 | rv = mimeInfo->GetMacCreator(&fileCreator);
|
---|
3274 | if (NS_SUCCEEDED(rv))
|
---|
3275 | rv = SetFileType(fileType);
|
---|
3276 | if (NS_SUCCEEDED(rv))
|
---|
3277 | rv = SetFileCreator(fileCreator);
|
---|
3278 | }
|
---|
3279 |
|
---|
3280 | return rv;
|
---|
3281 | }
|
---|
3282 |
|
---|
3283 | NS_IMETHODIMP
|
---|
3284 | nsLocalFile::GetFileSizeWithResFork(PRInt64 *aFileSize)
|
---|
3285 | {
|
---|
3286 | NS_ENSURE_ARG(aFileSize);
|
---|
3287 |
|
---|
3288 | *aFileSize = LL_Zero();
|
---|
3289 |
|
---|
3290 | ResolveAndStat();
|
---|
3291 |
|
---|
3292 | long dataSize = 0;
|
---|
3293 | long resSize = 0;
|
---|
3294 |
|
---|
3295 | OSErr err = FSpGetFileSize(&mTargetSpec, &dataSize, &resSize);
|
---|
3296 |
|
---|
3297 | if (err != noErr)
|
---|
3298 | return MacErrorMapper(err);
|
---|
3299 |
|
---|
3300 | // For now we've only got 32 bits of file size info
|
---|
3301 | PRInt64 dataInt64 = LL_Zero();
|
---|
3302 | PRInt64 resInt64 = LL_Zero();
|
---|
3303 |
|
---|
3304 | // Combine the size of the resource and data forks
|
---|
3305 | LL_I2L(resInt64, resSize);
|
---|
3306 | LL_I2L(dataInt64, dataSize);
|
---|
3307 | LL_ADD((*aFileSize), dataInt64, resInt64);
|
---|
3308 |
|
---|
3309 | return NS_OK;
|
---|
3310 | }
|
---|
3311 |
|
---|
3312 |
|
---|
3313 | // this nsLocalFile points to the app. We want to launch it, optionally with the document.
|
---|
3314 | NS_IMETHODIMP
|
---|
3315 | nsLocalFile::LaunchWithDoc(nsILocalFile* aDocToLoad, PRBool aLaunchInBackground)
|
---|
3316 | {
|
---|
3317 | // are we launchable?
|
---|
3318 | PRBool isExecutable;
|
---|
3319 | nsresult rv = IsExecutable(&isExecutable);
|
---|
3320 | if (NS_FAILED(rv)) return rv;
|
---|
3321 | if (!isExecutable) return NS_ERROR_FILE_EXECUTION_FAILED;
|
---|
3322 |
|
---|
3323 | FSSpec docSpec;
|
---|
3324 | FSSpecPtr docSpecPtr = nsnull;
|
---|
3325 |
|
---|
3326 | nsCOMPtr<nsILocalFileMac> macDoc = do_QueryInterface(aDocToLoad);
|
---|
3327 | if (macDoc)
|
---|
3328 | {
|
---|
3329 | rv = macDoc->GetFSSpec(&docSpec); // XXX GetTargetFSSpec
|
---|
3330 | if (NS_FAILED(rv)) return rv;
|
---|
3331 |
|
---|
3332 | docSpecPtr = &docSpec;
|
---|
3333 | }
|
---|
3334 |
|
---|
3335 | FSSpec appSpec;
|
---|
3336 | rv = GetFSSpec(&appSpec); // XXX GetResolvedFSSpec
|
---|
3337 | if (NS_FAILED(rv)) return rv;
|
---|
3338 |
|
---|
3339 | rv = MyLaunchAppWithDoc(appSpec, docSpecPtr, aLaunchInBackground);
|
---|
3340 | return rv;
|
---|
3341 | }
|
---|
3342 |
|
---|
3343 |
|
---|
3344 | NS_IMETHODIMP
|
---|
3345 | nsLocalFile::OpenDocWithApp(nsILocalFile* aAppToOpenWith, PRBool aLaunchInBackground)
|
---|
3346 | {
|
---|
3347 | // if aAppToOpenWith is nil, we have to find the app from the creator code
|
---|
3348 | // of the document
|
---|
3349 | nsresult rv = NS_OK;
|
---|
3350 |
|
---|
3351 | FSSpec appSpec;
|
---|
3352 |
|
---|
3353 | if (aAppToOpenWith)
|
---|
3354 | {
|
---|
3355 | nsCOMPtr<nsILocalFileMac> appFileMac = do_QueryInterface(aAppToOpenWith, &rv);
|
---|
3356 | if (!appFileMac) return rv;
|
---|
3357 |
|
---|
3358 | rv = appFileMac->GetFSSpec(&appSpec); // XXX GetTargetFSSpec
|
---|
3359 | if (NS_FAILED(rv)) return rv;
|
---|
3360 |
|
---|
3361 | // is it launchable?
|
---|
3362 | PRBool isExecutable;
|
---|
3363 | rv = aAppToOpenWith->IsExecutable(&isExecutable);
|
---|
3364 | if (NS_FAILED(rv)) return rv;
|
---|
3365 | if (!isExecutable) return NS_ERROR_FILE_EXECUTION_FAILED;
|
---|
3366 | }
|
---|
3367 | else
|
---|
3368 | {
|
---|
3369 | // look for one
|
---|
3370 | OSType fileCreator;
|
---|
3371 | rv = GetFileCreator(&fileCreator);
|
---|
3372 | if (NS_FAILED(rv)) return rv;
|
---|
3373 |
|
---|
3374 | // just make one on the stack
|
---|
3375 | nsLocalFile localAppFile;
|
---|
3376 | rv = localAppFile.InitToAppWithCreatorCode(fileCreator);
|
---|
3377 | if (NS_FAILED(rv)) return rv;
|
---|
3378 |
|
---|
3379 | rv = localAppFile.GetFSSpec(&appSpec); // GetTargetFSSpec
|
---|
3380 | if (NS_FAILED(rv)) return rv;
|
---|
3381 | }
|
---|
3382 |
|
---|
3383 | FSSpec docSpec;
|
---|
3384 | rv = GetFSSpec(&docSpec); // XXX GetResolvedFSSpec
|
---|
3385 | if (NS_FAILED(rv)) return rv;
|
---|
3386 |
|
---|
3387 | rv = MyLaunchAppWithDoc(appSpec, &docSpec, aLaunchInBackground);
|
---|
3388 | return rv;
|
---|
3389 | }
|
---|
3390 |
|
---|
3391 | nsresult nsLocalFile::SetOSTypeAndCreatorFromExtension(const char* extension)
|
---|
3392 | {
|
---|
3393 | nsresult rv;
|
---|
3394 |
|
---|
3395 | nsCAutoString localExtBuf;
|
---|
3396 | const char *extPtr;
|
---|
3397 |
|
---|
3398 | if (!extension)
|
---|
3399 | {
|
---|
3400 | rv = GetNativeLeafName(localExtBuf);
|
---|
3401 | extPtr = strrchr(localExtBuf.get(), '.');
|
---|
3402 | if (!extPtr)
|
---|
3403 | return NS_ERROR_FAILURE;
|
---|
3404 | ++extPtr;
|
---|
3405 | }
|
---|
3406 | else
|
---|
3407 | {
|
---|
3408 | extPtr = extension;
|
---|
3409 | if (*extPtr == '.')
|
---|
3410 | ++extPtr;
|
---|
3411 | }
|
---|
3412 |
|
---|
3413 | nsCOMPtr<nsIInternetConfigService> icService =
|
---|
3414 | do_GetService(NS_INTERNETCONFIGSERVICE_CONTRACTID, &rv);
|
---|
3415 | if (NS_SUCCEEDED(rv))
|
---|
3416 | {
|
---|
3417 | nsCOMPtr<nsIMIMEInfo> mimeInfo;
|
---|
3418 | rv = icService->GetMIMEInfoFromExtension(extPtr, getter_AddRefs(mimeInfo));
|
---|
3419 | if (NS_SUCCEEDED(rv))
|
---|
3420 | {
|
---|
3421 | PRUint32 osType;
|
---|
3422 | rv = mimeInfo->GetMacType(&osType);
|
---|
3423 | if (NS_SUCCEEDED(rv))
|
---|
3424 | mType = osType;
|
---|
3425 | PRBool skip;
|
---|
3426 | rv = ExtensionIsOnExceptionList(extPtr, &skip);
|
---|
3427 | if (NS_SUCCEEDED(rv) && !skip)
|
---|
3428 | {
|
---|
3429 | rv = mimeInfo->GetMacCreator(&osType);
|
---|
3430 | if (NS_SUCCEEDED(rv))
|
---|
3431 | mCreator = osType;
|
---|
3432 | }
|
---|
3433 | }
|
---|
3434 | }
|
---|
3435 | return rv;
|
---|
3436 | }
|
---|
3437 |
|
---|
3438 | nsresult nsLocalFile::ExtensionIsOnExceptionList(const char *extension, PRBool *onList)
|
---|
3439 | {
|
---|
3440 | // Probably want to make a global list somewhere in the future
|
---|
3441 | // for now, just check for "html" and "htm"
|
---|
3442 |
|
---|
3443 | *onList = PR_FALSE;
|
---|
3444 |
|
---|
3445 | if (!nsCRT::strcasecmp(extension, "html") ||
|
---|
3446 | !nsCRT::strcasecmp(extension, "htm"))
|
---|
3447 | *onList = PR_TRUE;
|
---|
3448 | return NS_OK;
|
---|
3449 | }
|
---|
3450 |
|
---|
3451 |
|
---|
3452 | void nsLocalFile::InitClassStatics()
|
---|
3453 | {
|
---|
3454 | OSErr err;
|
---|
3455 |
|
---|
3456 |
|
---|
3457 | if (sCurrentProcessSignature == 0)
|
---|
3458 | {
|
---|
3459 | ProcessSerialNumber psn;
|
---|
3460 | ProcessInfoRec info;
|
---|
3461 |
|
---|
3462 | psn.highLongOfPSN = 0;
|
---|
3463 | psn.lowLongOfPSN = kCurrentProcess;
|
---|
3464 |
|
---|
3465 | info.processInfoLength = sizeof(ProcessInfoRec);
|
---|
3466 | info.processName = nil;
|
---|
3467 | info.processAppSpec = nil;
|
---|
3468 | err = ::GetProcessInformation(&psn, &info);
|
---|
3469 | if (err == noErr)
|
---|
3470 | sCurrentProcessSignature = info.processSignature;
|
---|
3471 | // Try again next time if error
|
---|
3472 | }
|
---|
3473 |
|
---|
3474 | static PRBool didHFSPlusCheck = PR_FALSE;
|
---|
3475 | if (!didHFSPlusCheck)
|
---|
3476 | {
|
---|
3477 | long response;
|
---|
3478 | err = ::Gestalt(gestaltFSAttr, &response);
|
---|
3479 | sHasHFSPlusAPIs = (err == noErr && (response & (1 << gestaltHasHFSPlusAPIs)) != 0);
|
---|
3480 | didHFSPlusCheck = PR_TRUE;
|
---|
3481 | }
|
---|
3482 |
|
---|
3483 | static PRBool didOSXCheck = PR_FALSE;
|
---|
3484 | if (!didOSXCheck)
|
---|
3485 | {
|
---|
3486 | long version;
|
---|
3487 | sRunningOSX = (::Gestalt(gestaltSystemVersion, &version) == noErr && version >= 0x00001000);
|
---|
3488 | didOSXCheck = PR_TRUE;
|
---|
3489 | }
|
---|
3490 | }
|
---|
3491 |
|
---|
3492 |
|
---|
3493 | #pragma mark -
|
---|
3494 |
|
---|
3495 | // Handy dandy utility create routine for something or the other
|
---|
3496 | nsresult
|
---|
3497 | NS_NewNativeLocalFile(const nsACString &path, PRBool followLinks, nsILocalFile* *result)
|
---|
3498 | {
|
---|
3499 | nsLocalFile* file = new nsLocalFile();
|
---|
3500 | if (file == nsnull)
|
---|
3501 | return NS_ERROR_OUT_OF_MEMORY;
|
---|
3502 | NS_ADDREF(file);
|
---|
3503 |
|
---|
3504 | file->SetFollowLinks(followLinks);
|
---|
3505 |
|
---|
3506 | if (!path.IsEmpty()) {
|
---|
3507 | nsresult rv = file->InitWithNativePath(path);
|
---|
3508 | if (NS_FAILED(rv)) {
|
---|
3509 | NS_RELEASE(file);
|
---|
3510 | return rv;
|
---|
3511 | }
|
---|
3512 | }
|
---|
3513 | *result = file;
|
---|
3514 | return NS_OK;
|
---|
3515 | }
|
---|
3516 |
|
---|
3517 | nsresult
|
---|
3518 | NS_NewLocalFile(const nsAString &path, PRBool followLinks, nsILocalFile* *result)
|
---|
3519 | {
|
---|
3520 | nsCAutoString fsCharSetStr;
|
---|
3521 | nsresult rv = NS_CopyUnicodeToNative(path, fsCharSetStr);
|
---|
3522 | if (NS_FAILED(rv))
|
---|
3523 | return rv;
|
---|
3524 | return NS_NewNativeLocalFile(fsCharSetStr, followLinks, result);
|
---|
3525 | }
|
---|
3526 |
|
---|
3527 | nsresult
|
---|
3528 | NS_NewLocalFileWithFSSpec(const FSSpec* inSpec, PRBool followLinks, nsILocalFileMac* *result)
|
---|
3529 | {
|
---|
3530 | nsLocalFile* file = new nsLocalFile();
|
---|
3531 | if (file == nsnull)
|
---|
3532 | return NS_ERROR_OUT_OF_MEMORY;
|
---|
3533 | NS_ADDREF(file);
|
---|
3534 |
|
---|
3535 | file->SetFollowLinks(followLinks);
|
---|
3536 |
|
---|
3537 | nsresult rv = file->InitWithFSSpec(inSpec);
|
---|
3538 | if (NS_FAILED(rv)) {
|
---|
3539 | NS_RELEASE(file);
|
---|
3540 | return rv;
|
---|
3541 | }
|
---|
3542 | *result = file;
|
---|
3543 | return NS_OK;
|
---|
3544 | }
|
---|
3545 |
|
---|
3546 | void
|
---|
3547 | nsLocalFile::GlobalInit()
|
---|
3548 | {
|
---|
3549 | }
|
---|
3550 |
|
---|
3551 | void
|
---|
3552 | nsLocalFile::GlobalShutdown()
|
---|
3553 | {
|
---|
3554 | }
|
---|