Bug 376959, follow symlinks when doing Repack verification, r=preed
[mozilla-1.9.git] / xpcom / obsolete / nsFileSpecMac.cpp
blob8b8ea4a46fd206693cb573184112a3ebea1b1d37
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 // This file is included by nsFile.cp, and includes the Macintosh-specific
39 // implementations.
42 #include <string.h>
44 #include "prtypes.h"
45 #include "nscore.h"
47 #include "FullPath.h"
48 #include "FileCopy.h"
49 #include "MoreFilesExtras.h"
51 #include <Aliases.h>
52 #include <Folders.h>
53 #include <Math64.h>
54 #include <TextUtils.h>
55 #include <Processes.h>
56 #include <limits.h> // ULONG_MAX
58 #include "nsFileSpec.h"
59 #include "nsEscape.h"
60 #include "nsXPIDLString.h"
63 const unsigned char* kAliasHavenFolderName = "\pnsAliasHaven";
65 //========================================================================================
66 namespace MacFileHelpers
67 //========================================================================================
69 inline void PLstrcpy(Str255 dst, ConstStr255Param src)
71 memcpy(dst, src, 1 + src[0]);
74 void PLstrcpy(Str255 dst, const char* src, int inMaxLen=255);
75 void PLstrncpy(Str255 dst, const char* src, int inMaxLen);
77 void SwapSlashColon(char * s);
78 OSErr FSSpecFromUnixPath(
79 const char * unixPath,
80 FSSpec& ioSpec,
81 Boolean hexDecode,
82 Boolean resolveAlias,
83 Boolean allowPartial = false,
84 Boolean createDirs = false);
85 char* MacPathFromUnixPath(
86 const char* unixPath,
87 Boolean hexDecode);
88 char* EncodeMacPath(
89 char* inPath, // NOT const - gets clobbered
90 Boolean prependSlash,
91 Boolean doEscape );
92 OSErr FSSpecFromPathname(
93 const char* inPathNamePtr,
94 FSSpec& ioSpec,
95 Boolean inCreateDirs);
96 char* PathNameFromFSSpec(
97 const FSSpec& inSpec );
98 OSErr CreateFolderInFolder(
99 short refNum, // Parent directory/volume
100 long dirID,
101 ConstStr255Param folderName, // Name of the new folder
102 short& outRefNum, // Volume of the created folder
103 long& outDirID); //
105 // Some routines to support an "alias haven" directory. Aliases in this directory
106 // are never resolved. There is a ResolveAlias here that respects that. This is
107 // to support attaching of aliases in mail.
108 void EnsureAliasHaven();
109 void SetNoResolve(Boolean inResolve);
110 PRBool IsAliasSafe(const FSSpec& inSpec);
111 OSErr MakeAliasSafe(FSSpec& inOutSpec);
112 OSErr ResolveAliasFile(FSSpec& inOutSpec, Boolean& wasAliased);
114 Boolean sNoResolve = false;
115 long sAliasHavenDirID = 0;
116 short sAliasHavenVRefNum = 0;
117 } // namespace MacFileHelpers
119 //----------------------------------------------------------------------------------------
120 void MacFileHelpers::PLstrcpy(Str255 dst, const char* src, int inMax)
121 //----------------------------------------------------------------------------------------
123 int srcLength = strlen(src);
124 NS_ASSERTION(srcLength <= inMax, "Oops, string is too long!");
125 if (srcLength > inMax)
126 srcLength = inMax;
127 dst[0] = srcLength;
128 memcpy(&dst[1], src, srcLength);
131 //----------------------------------------------------------------------------------------
132 void MacFileHelpers::PLstrncpy(Str255 dst, const char* src, int inMax)
133 //----------------------------------------------------------------------------------------
135 int srcLength = strlen(src);
136 if (srcLength > inMax)
137 srcLength = inMax;
138 dst[0] = srcLength;
139 memcpy(&dst[1], src, srcLength);
142 //-----------------------------------
143 void MacFileHelpers::SwapSlashColon(char * s)
144 //-----------------------------------
147 while (*s)
149 if (*s == '/')
150 *s++ = ':';
151 else if (*s == ':')
152 *s++ = '/';
153 else
154 *s++;
156 } // MacFileHelpers::SwapSlashColon
158 //-----------------------------------
159 char* MacFileHelpers::EncodeMacPath(
160 char* inPath, // NOT const, gets clobbered
161 Boolean prependSlash,
162 Boolean doEscape )
163 // Transforms Macintosh style path into Unix one
164 // Method: Swap ':' and '/', hex escape the result
165 //-----------------------------------
167 if (inPath == nsnull)
168 return nsnull;
169 int pathSize = strlen(inPath);
171 // XP code sometimes chokes if there's a final slash in the unix path.
172 // Since correct mac paths to folders and volumes will end in ':', strip this
173 // first.
174 char* c = inPath + pathSize - 1;
175 if (*c == ':')
177 *c = 0;
178 pathSize--;
181 char * newPath = nsnull;
182 char * finalPath = nsnull;
184 if (prependSlash)
186 newPath = new char[pathSize + 2];
187 newPath[0] = ':'; // It will be converted to '/'
188 memcpy(&newPath[1], inPath, pathSize + 1);
190 else
192 newPath = new char[pathSize + 1];
193 strcpy(newPath, inPath);
195 if (newPath)
197 SwapSlashColon( newPath );
198 if (doEscape)
200 finalPath = nsEscape(newPath, url_Path);
201 delete [] newPath;
203 else
204 finalPath = newPath;
206 delete [] inPath;
207 return finalPath;
208 } // MacFileHelpers::EncodeMacPath
210 //----------------------------------------------------------------------------------------
211 inline void MacFileHelpers::SetNoResolve(Boolean inResolve)
212 //----------------------------------------------------------------------------------------
214 sNoResolve = inResolve;
215 } // MacFileHelpers::SetNoResolve
217 //----------------------------------------------------------------------------------------
218 OSErr MacFileHelpers::MakeAliasSafe(FSSpec& inOutSpec)
219 // Pass in the spec of an alias. This copies the file to the safe haven folder, and
220 // returns the spec of the copy to the caller
221 //----------------------------------------------------------------------------------------
223 EnsureAliasHaven();
224 nsFileSpec dstDirSpec(sAliasHavenVRefNum, sAliasHavenDirID, "\p");
226 // Make sure its name is unique
227 nsFileSpec havenSpec(sAliasHavenVRefNum, sAliasHavenDirID, "\pG'day");
228 if (havenSpec.Valid())
229 havenSpec.MakeUnique(inOutSpec.name);
230 // Copy the file into the haven directory
231 if (havenSpec.Valid())
233 OSErr err = ::FSpFileCopy(
234 &inOutSpec,
235 dstDirSpec,
236 havenSpec.GetLeafPName(),
237 nil, 0, true);
238 // Return the spec of the copy to the caller.
239 if (err != noErr)
240 return err;
241 inOutSpec = havenSpec;
243 return noErr;
244 } // MacFileHelpers::MakeAliasSafe
246 //----------------------------------------------------------------------------------------
247 char* MacFileHelpers::MacPathFromUnixPath(const char* unixPath, Boolean hexDecode)
248 //----------------------------------------------------------------------------------------
250 // Relying on the fact that the unix path is always longer than the mac path:
251 size_t len = strlen(unixPath);
252 char* result = new char[len + 2]; // ... but allow for the initial colon in a partial name
253 // REMEMBER: at the end we call SwapSlashColon, so bear that in mind when you see
254 // this code using '/' as a separator in what is supposed to be a Macintosh path!
255 if (result)
257 char* dst = result;
258 const char* src = unixPath;
259 if (*src == '/') // * full path
260 src++;
261 else if (strchr(src, '/') && *src != '.')
263 // * partial path, and not just a leaf name. The '.' test is there because
264 // the loop below will add sufficient colons in that case.
265 *dst++ = '/';
267 // Copy src to dst, but watch out for .. and .
268 char c = '/';
271 char cprev = c; // remember the previous char (initially /)
272 c = *src++;
273 if (c == '.' && cprev == '/')
275 char* dstSaved = dst;
276 // Special cases: "." and "..". Convert to ':' and '::'
277 *dst++ = '/'; // . becomes :
278 c = *src++;
279 if (c == '.')
281 *dst++ = '/'; // .. becomes ::
282 c = *src++;
284 if (c == '/')
286 // ../ becomes :: so just skip the slash
287 // ./ becomes : " " " " "
288 src++;
290 else if (c)
292 // Oh. A file called ".foo" or "..foo"
293 // Back up and just do the normal thing.
294 src -= (dst - dstSaved);
295 dst = dstSaved;
296 // Since c is not '/', we won't do this stuff on the
297 // next iteration.
299 continue;
301 else if (c == '/' && cprev == '/')
303 // Hmm. A 'run on' path with two slashes right next to each other.
304 // This is an illegal path, but, hey, we'll be tough and try to
305 // deal with it (especially since '::' has loaded semantics in
306 // a Mac path)
307 continue;
309 *dst++ = c;
310 } while (c);
311 if (hexDecode)
312 nsUnescape(result); // Hex Decode
313 MacFileHelpers::SwapSlashColon(result);
315 return result;
316 } // MacFileHelpers::MacPathFromUnixPath
318 //----------------------------------------------------------------------------------------
319 OSErr MacFileHelpers::FSSpecFromPathname(
320 const char* inPathNamePtr,
321 FSSpec& ioSpec, // used as in-parameter for a relative path.
322 Boolean inCreateDirs)
323 // FSSpecFromPathname reverses PathNameFromFSSpec.
324 // It returns a FSSpec given a c string which is a mac pathname.
325 //----------------------------------------------------------------------------------------
327 OSErr err;
328 // Simplify this routine to use FSMakeFSSpec if length < 255. Otherwise use the MoreFiles
329 // routine FSpLocationFromFullPath, which allocates memory, to handle longer pathnames.
331 short inVRefNum = ioSpec.vRefNum;
332 long inParID = ioSpec.parID;
334 size_t inLength = strlen(inPathNamePtr);
335 bool isRelative = (strchr(inPathNamePtr, ':') == 0 || *inPathNamePtr == ':');
336 #ifdef NS_DEBUG
337 // Attempt to catch people sending unix paths in to routines that expect native ones.
338 NS_ASSERTION(strchr(inPathNamePtr, '/') == 0,
339 "Possible unix path where native path is required");
340 #endif
341 if (inLength < 255)
343 Str255 pascalpath;
344 MacFileHelpers::PLstrcpy(pascalpath, inPathNamePtr);
345 if (isRelative)
346 err = ::FSMakeFSSpec(inVRefNum, inParID, pascalpath, &ioSpec);
347 else
348 err = ::FSMakeFSSpec(0, 0, pascalpath, &ioSpec);
350 else if (!isRelative)
351 err = FSpLocationFromFullPath(inLength, inPathNamePtr, &ioSpec);
352 else
353 err = bdNamErr;
355 if ((err == dirNFErr || err == bdNamErr) && inCreateDirs)
357 const char* path = inPathNamePtr;
358 if (isRelative)
360 ioSpec.vRefNum = inVRefNum;
361 ioSpec.parID = inParID;
363 else
365 ioSpec.vRefNum = 0;
366 ioSpec.parID = 0;
368 do {
369 // Locate the colon that terminates the node.
370 // But if we've a partial path (starting with a colon), find the second one.
371 const char* nextColon = strchr(path + (*path == ':'), ':');
372 // Well, if there are no more colons, point to the end of the string.
373 if (!nextColon)
374 nextColon = path + strlen(path);
376 // Make a pascal string out of this node. Include initial
377 // and final colon, if any!
378 Str255 ppath;
379 MacFileHelpers::PLstrncpy(ppath, path, nextColon - path + 1);
381 // Use this string as a relative path using the directory created
382 // on the previous round (or directory 0,0 on the first round).
383 err = ::FSMakeFSSpec(ioSpec.vRefNum, ioSpec.parID, ppath, &ioSpec);
385 // If this was the leaf node, then we are done.
386 if (!*nextColon)
387 break;
389 // Since there's more to go, we have to get the directory ID, which becomes
390 // the parID for the next round.
391 if (err == noErr)
393 // The directory (or perhaps a file) exists. Find its dirID.
394 long dirID;
395 Boolean isDirectory;
396 err = ::FSpGetDirectoryID(&ioSpec, &dirID, &isDirectory);
397 if (!isDirectory)
398 return dupFNErr; // oops! a file exists with that name.
399 if (err)
400 return err;
401 ioSpec.parID = dirID;
403 else if (err == fnfErr)
405 // If we got "file not found", then
406 // we need to create a directory.
407 err = ::FSpDirCreate(&ioSpec, smCurrentScript, &ioSpec.parID);
408 // For some reason, this usually returns fnfErr, even though it works.
409 if (err == fnfErr)
410 err = noErr;
412 if (err != noErr)
413 return err;
414 path = nextColon; // next round
415 } while (1);
417 return err;
418 } // MacFileHelpers::FSSpecFromPathname
420 //----------------------------------------------------------------------------------------
421 OSErr MacFileHelpers::CreateFolderInFolder(
422 short refNum, // Parent directory/volume
423 long dirID,
424 ConstStr255Param folderName, // Name of the new folder
425 short& outRefNum, // Volume of the created folder
426 long& outDirID) //
427 // Creates a folder named 'folderName' inside a folder.
428 // The errors returned are same as PBDirCreate
429 //----------------------------------------------------------------------------------------
431 HFileParam hpb;
432 hpb.ioVRefNum = refNum;
433 hpb.ioDirID = dirID;
434 hpb.ioNamePtr = (StringPtr)&folderName;
436 OSErr err = PBDirCreateSync((HParmBlkPtr)&hpb);
437 if (err == noErr)
439 outRefNum = hpb.ioVRefNum;
440 outDirID = hpb.ioDirID;
442 else
444 outRefNum = 0;
445 outDirID = 0;
447 return err;
448 } // MacFileHelpers::CreateFolderInFolder
450 //----------------------------------------------------------------------------------------
451 void MacFileHelpers::EnsureAliasHaven()
452 //----------------------------------------------------------------------------------------
454 // Alias Haven is a directory in which we never resolve aliases.
455 if (sAliasHavenVRefNum != 0)
456 return;
459 FSSpec temp;
460 if (FindFolder(0, kTemporaryFolderType, true, & temp.vRefNum, &temp.parID) == noErr)
462 CreateFolderInFolder(
463 temp.vRefNum, // Parent directory/volume
464 temp.parID,
465 kAliasHavenFolderName, // Name of the new folder
466 sAliasHavenVRefNum, // Volume of the created folder
467 sAliasHavenDirID);
469 } // MacFileHelpers::EnsureAliasHaven
471 //----------------------------------------------------------------------------------------
472 PRBool MacFileHelpers::IsAliasSafe(const FSSpec& inSpec)
473 // Returns true if the alias is in the alias haven directory, or if alias resolution
474 // has been turned off.
475 //----------------------------------------------------------------------------------------
477 return sNoResolve
478 || (inSpec.parID == sAliasHavenDirID && inSpec.vRefNum == sAliasHavenVRefNum);
479 } // MacFileHelpers::IsAliasSafe
481 //----------------------------------------------------------------------------------------
482 OSErr MacFileHelpers::ResolveAliasFile(FSSpec& inOutSpec, Boolean& wasAliased)
483 //----------------------------------------------------------------------------------------
485 wasAliased = false;
486 if (IsAliasSafe(inOutSpec))
487 return noErr;
488 Boolean dummy;
489 return ::ResolveAliasFile(&inOutSpec, TRUE, &dummy, &wasAliased);
490 } // MacFileHelpers::ResolveAliasFile
492 //-----------------------------------
493 OSErr MacFileHelpers::FSSpecFromUnixPath(
494 const char * unixPath,
495 FSSpec& ioSpec,
496 Boolean hexDecode,
497 Boolean resolveAlias,
498 Boolean allowPartial,
499 Boolean createDirs)
500 // File spec from URL. Reverses GetURLFromFileSpec
501 // Its input is only the <path> part of the URL
502 // JRM 97/01/08 changed this so that if it's a partial path (doesn't start with '/'),
503 // then it is combined with inOutSpec's vRefNum and parID to form a new spec.
504 //-----------------------------------
506 if (unixPath == nsnull)
507 return badFidErr;
508 char* macPath = MacPathFromUnixPath(unixPath, hexDecode);
509 if (!macPath)
510 return memFullErr;
512 OSErr err = noErr;
513 if (!allowPartial)
515 NS_ASSERTION(*unixPath == '/' /*full path*/, "Not a full Unix path!");
517 err = FSSpecFromPathname(macPath, ioSpec, createDirs);
518 if (err == fnfErr)
519 err = noErr;
520 Boolean dummy;
521 if (err == noErr && resolveAlias) // Added
522 err = MacFileHelpers::ResolveAliasFile(ioSpec, dummy);
523 delete [] macPath;
524 NS_ASSERTION(err==noErr||err==fnfErr||err==dirNFErr||err==nsvErr, "Not a path!");
525 return err;
526 } // MacFileHelpers::FSSpecFromLocalUnixPath
528 //-----------------------------------
529 char* MacFileHelpers::PathNameFromFSSpec( const FSSpec& inSpec )
530 // Returns a full pathname to the given file
531 // Returned value is allocated with new [], and must be freed with delete []
532 // For consistency and to work under OS X this creates an nsILocalFileMac and has it do the work.
533 //-----------------------------------
535 char* result = nil;
536 nsresult rv;
538 FSSpec nonConstSpec = inSpec;
539 nsCAutoString path;
540 nsCOMPtr<nsILocalFileMac> macFile;
542 rv = NS_NewLocalFileWithFSSpec(&nonConstSpec, PR_TRUE, getter_AddRefs(macFile));
543 if (NS_FAILED(rv)) return nsnull;
544 nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(macFile, &rv));
545 if (NS_FAILED(rv)) return nsnull;
546 rv = localFile->GetNativePath(path);
547 if (NS_FAILED(rv)) return nsnull;
548 PRInt32 strLen = path.Length();
549 result = new char [strLen + 1];
550 if (!result) return nsnull;
551 memcpy(result, path.get(), strLen);
552 result[ strLen ] = 0;
554 return result;
555 } // MacFileHelpers::PathNameFromFSSpec
558 #pragma mark -
560 //========================================================================================
561 // Macintosh nsFileSpec implementation
562 //========================================================================================
564 //----------------------------------------------------------------------------------------
565 nsFileSpec::nsFileSpec()
566 //----------------------------------------------------------------------------------------
568 // NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
569 Clear();
572 //----------------------------------------------------------------------------------------
573 nsFileSpec::nsFileSpec(const FSSpec& inSpec, PRBool resolveAlias)
574 //----------------------------------------------------------------------------------------
575 : mSpec(inSpec)
576 , mError(NS_OK)
578 // NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
579 if (resolveAlias)
581 PRBool dummy;
582 ResolveSymlink(dummy);
586 //----------------------------------------------------------------------------------------
587 void nsFileSpec::operator = (const FSSpec& inSpec)
588 //----------------------------------------------------------------------------------------
590 mSpec = inSpec;
591 mError = NS_OK;
594 //----------------------------------------------------------------------------------------
595 nsFileSpec::nsFileSpec(const nsFileSpec& inSpec)
596 //----------------------------------------------------------------------------------------
597 : mSpec(inSpec.mSpec)
598 , mError(inSpec.Error())
600 // NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
603 //----------------------------------------------------------------------------------------
604 nsFileSpec::nsFileSpec(const char* inNativePathString, PRBool inCreateDirs)
605 //----------------------------------------------------------------------------------------
607 // NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
608 Clear(); // this sets mError to NS_ERROR_NOT_INITIALIZED
610 if (inNativePathString)
612 mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromPathname(
613 inNativePathString, mSpec, inCreateDirs));
614 if (mError == NS_FILE_RESULT(fnfErr))
615 mError = NS_OK;
618 } // nsFileSpec::nsFileSpec
620 //----------------------------------------------------------------------------------------
621 nsFileSpec::nsFileSpec(const nsString& inNativePathString, PRBool inCreateDirs)
622 //----------------------------------------------------------------------------------------
624 // NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
625 Clear(); // this sets mError to NS_ERROR_NOT_INITIALIZED
627 mError = NS_FILE_RESULT(
628 MacFileHelpers::FSSpecFromPathname(
629 NS_LossyConvertUTF16toASCII(inNativePathString).get(),
630 mSpec, inCreateDirs));
631 if (mError == NS_FILE_RESULT(fnfErr))
632 mError = NS_OK;
634 } // nsFileSpec::nsFileSpec
636 //----------------------------------------------------------------------------------------
637 nsFileSpec::nsFileSpec(short vRefNum, long parID, ConstStr255Param fileName, PRBool resolveAlias)
638 //----------------------------------------------------------------------------------------
640 // NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
641 mError = NS_FILE_RESULT(::FSMakeFSSpec(vRefNum, parID, fileName, &mSpec));
642 if (mError == NS_FILE_RESULT(fnfErr))
643 mError = NS_OK;
645 if (resolveAlias)
647 PRBool dummy;
648 ResolveSymlink(dummy);
652 //----------------------------------------------------------------------------------------
653 nsFileSpec::nsFileSpec(const nsFilePath& inPath)
654 //----------------------------------------------------------------------------------------
656 // NS_ASSERTION(0, "nsFileSpec is unsupported - use nsIFile!");
657 *this = inPath.GetFileSpec();
660 //----------------------------------------------------------------------------------------
661 void nsFileSpec::operator = (const char* inString)
662 //----------------------------------------------------------------------------------------
664 Clear(); // this sets mError to NS_ERROR_NOT_INITIALIZED
666 if (inString)
668 mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromPathname(inString, mSpec, true));
669 if (mError == NS_FILE_RESULT(fnfErr))
670 mError = NS_OK;
673 } // nsFileSpec::operator =
675 //----------------------------------------------------------------------------------------
676 void nsFileSpec::operator = (const nsFileSpec& inSpec)
677 //----------------------------------------------------------------------------------------
679 mPath.SetToEmpty();
680 mSpec.vRefNum = inSpec.mSpec.vRefNum;
681 mSpec.parID = inSpec.mSpec.parID;
683 PRInt32 copySize = inSpec.mSpec.name[0] + 1;
684 if (copySize > sizeof(inSpec.mSpec.name))
685 copySize = sizeof(inSpec.mSpec.name);
686 memcpy(mSpec.name, inSpec.mSpec.name, copySize);
687 mError = inSpec.Error(); // note that the error is propagated
688 } // nsFileSpec::operator =
690 //----------------------------------------------------------------------------------------
691 void nsFileSpec::operator = (const nsFilePath& inPath)
692 //----------------------------------------------------------------------------------------
694 *this = inPath.GetFileSpec();
695 } // nsFileSpec::operator =
697 //----------------------------------------------------------------------------------------
698 inline void nsFileSpec::Clear()
699 //----------------------------------------------------------------------------------------
701 mPath.SetToEmpty();
702 mSpec.vRefNum = 0;
703 mSpec.parID = 0;
704 mSpec.name[0] = 0;
705 mError = NS_ERROR_NOT_INITIALIZED;
708 //----------------------------------------------------------------------------------------
709 PRBool nsFileSpec::Exists() const
710 //----------------------------------------------------------------------------------------
712 if (NS_FAILED(mError)) return PR_FALSE;
713 FSSpec temp;
714 return ::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, mSpec.name, &temp) == noErr;
715 } // nsFileSpec::Exists()
717 //----------------------------------------------------------------------------------------
718 void nsFileSpec::GetModDate(TimeStamp& outStamp) const
719 //----------------------------------------------------------------------------------------
721 CInfoPBRec pb;
722 if (GetCatInfo(pb) == noErr)
723 outStamp = ((DirInfo*)&pb)->ioDrMdDat; // The mod date is in the same spot for files and dirs.
724 else
725 outStamp = 0;
726 } // nsFileSpec::GetModDate
728 //----------------------------------------------------------------------------------------
729 PRUint32 nsFileSpec::GetFileSize() const
730 //----------------------------------------------------------------------------------------
732 CInfoPBRec pb;
733 if (noErr == GetCatInfo(pb))
734 return (PRUint32)((HFileInfo*)&pb)->ioFlLgLen;
735 return 0;
736 } // nsFileSpec::GetFileSize
738 //----------------------------------------------------------------------------------------
739 void nsFileSpec::SetLeafName(const char* inLeafName)
740 // In leaf name can actually be a partial path...
741 //----------------------------------------------------------------------------------------
743 NS_ASSERTION(inLeafName, "Attempt to set leaf name with a null string");
745 mPath.SetToEmpty();
747 if (inLeafName)
749 // what about long relative paths? Hmm? We don't have a routine for this anywhere.
750 Str255 partialPath;
751 MacFileHelpers::PLstrcpy(partialPath, inLeafName);
752 mError = NS_FILE_RESULT(
753 ::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, partialPath, &mSpec));
754 if (mError == NS_FILE_RESULT(fnfErr))
755 mError = NS_OK;
758 } // nsFileSpec::SetLeafName
760 //----------------------------------------------------------------------------------------
761 char* nsFileSpec::GetLeafName() const
762 // Result needs to be nsCRT::free()ed.
763 //----------------------------------------------------------------------------------------
765 char leaf[sizeof(mSpec.name)];
766 memcpy(leaf, &mSpec.name[1], mSpec.name[0]);
767 leaf[mSpec.name[0]] = '\0';
768 return nsCRT::strdup(leaf);
769 } // nsFileSpec::GetLeafName
771 //----------------------------------------------------------------------------------------
772 void nsFileSpec::MakeAliasSafe()
773 //----------------------------------------------------------------------------------------
775 mPath.SetToEmpty();
776 mError = NS_FILE_RESULT(MacFileHelpers::MakeAliasSafe(mSpec));
777 } // nsFileSpec::MakeAliasSafe
779 //----------------------------------------------------------------------------------------
780 void nsFileSpec::MakeUnique(ConstStr255Param inSuggestedLeafName)
781 //----------------------------------------------------------------------------------------
783 mPath.SetToEmpty();
784 if (inSuggestedLeafName[0] > 0)
785 MacFileHelpers::PLstrcpy(mSpec.name, inSuggestedLeafName);
787 MakeUnique();
788 } // nsFileSpec::MakeUnique
790 //----------------------------------------------------------------------------------------
791 PRBool nsFileSpec::IsFile() const
792 //----------------------------------------------------------------------------------------
794 long dirID;
795 Boolean isDirectory;
796 return (noErr == ::FSpGetDirectoryID(&mSpec, &dirID, &isDirectory) && !isDirectory);
797 } // nsFileSpec::IsFile
799 //----------------------------------------------------------------------------------------
800 PRBool nsFileSpec::IsDirectory() const
801 //----------------------------------------------------------------------------------------
803 long dirID;
804 Boolean isDirectory;
805 return (noErr == ::FSpGetDirectoryID(&mSpec, &dirID, &isDirectory) && isDirectory);
806 } // nsFileSpec::IsDirectory
808 //----------------------------------------------------------------------------------------
809 PRBool nsFileSpec::IsHidden() const
810 //----------------------------------------------------------------------------------------
812 CInfoPBRec cInfo;
813 PRBool hidden = PR_FALSE;
815 if (noErr == GetCatInfo(cInfo))
816 if (cInfo.hFileInfo.ioFlFndrInfo.fdFlags & kIsInvisible)
817 hidden = PR_TRUE;
819 return hidden;
820 } // nsFileSpec::IsHidden
822 //----------------------------------------------------------------------------------------
823 PRBool nsFileSpec::IsSymlink() const
824 //----------------------------------------------------------------------------------------
826 CInfoPBRec cInfo;
827 PRBool hidden = PR_FALSE;
829 if (noErr == GetCatInfo(cInfo))
830 if (cInfo.hFileInfo.ioFlFndrInfo.fdFlags & kIsAlias)
831 hidden = PR_TRUE;
833 return hidden;
834 } // nsFileSpec::IsSymlink
836 //----------------------------------------------------------------------------------------
837 nsresult nsFileSpec::ResolveSymlink(PRBool& wasAliased)
838 //----------------------------------------------------------------------------------------
840 Boolean wasAliased2; // Type conversion Boolean <--> PRBool
841 OSErr err = MacFileHelpers::ResolveAliasFile(mSpec, wasAliased2);
842 if (wasAliased2)
844 mError = NS_FILE_RESULT(err);
845 wasAliased = PR_TRUE;
847 else
848 wasAliased = PR_FALSE;
850 return mError;
851 } // nsFileSpec::ResolveSymlink
853 //----------------------------------------------------------------------------------------
854 void nsFileSpec::GetParent(nsFileSpec& outSpec) const
855 //----------------------------------------------------------------------------------------
857 if (NS_SUCCEEDED(mError))
858 outSpec.mError = NS_FILE_RESULT(::FSMakeFSSpec(mSpec.vRefNum, mSpec.parID, nsnull, outSpec));
859 } // nsFileSpec::GetParent
861 //----------------------------------------------------------------------------------------
862 void nsFileSpec::operator += (const char* inRelativePath)
863 //----------------------------------------------------------------------------------------
865 NS_ASSERTION(inRelativePath, "Attempt to append relative path with null path");
867 // Invalidate the path cache string, since we're changing ourselves.
868 mPath.SetToEmpty();
870 // if we are already bad, don't allow appendage
871 if (NS_FAILED(Error()))
873 NS_WARNING("trying to append to a bad nsFileSpec");
874 return;
877 // Find the dirID of the directory described by this spec
878 long dirID;
879 Boolean isDirectory;
880 mError = NS_FILE_RESULT(::FSpGetDirectoryID(&mSpec, &dirID, &isDirectory));
881 if (NS_FAILED(mError) || !isDirectory || !inRelativePath)
882 return;
883 // mSpec.vRefNum is already correct.
884 mSpec.parID = dirID;
886 // Next, determine if it is a UNIX or Mac style path. Now, Macintosh relative paths
887 // are either leaf names (in which the distinction between unix and macintosh
888 // relative paths disappears) or they start with a colon. If we find an initial colon,
889 // then assume it's a macintosh path.
890 // If it is a UNIX path (including just a leaf name), we will also look for ':' and
891 // assert if we find one.
892 if (*inRelativePath != ':')
894 // Looks like a UNIX path (including possibly just a leaf name)
895 NS_ASSERTION(strchr(inRelativePath, ':') == nsnull, "Can not determine path type");
896 // Convert unix path (which is unencoded) to a spec
897 mError = NS_FILE_RESULT(
898 MacFileHelpers::FSSpecFromUnixPath(inRelativePath, mSpec, false, false, true, true));
900 else
902 // We must be a mac path!
903 mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromPathname(inRelativePath, mSpec, true));
905 if (mError == NS_FILE_RESULT(fnfErr))
906 mError = NS_OK;
908 } // nsFileSpec::operator +=
910 //----------------------------------------------------------------------------------------
911 void nsFileSpec::CreateDirectory(int /* unix mode */)
912 //----------------------------------------------------------------------------------------
914 long ignoredDirID;
915 OSErr err = ::FSpDirCreate(&mSpec, smCurrentScript, &ignoredDirID);
916 // it's OK if the dir already exists
917 if (err != noErr && IsDirectory())
918 err = noErr;
920 mError = NS_FILE_RESULT(err);
922 } // nsFileSpec::CreateDirectory
924 //----------------------------------------------------------------------------------------
925 void nsFileSpec::Delete(PRBool inRecursive) const
926 //----------------------------------------------------------------------------------------
928 OSErr anErr;
930 nsresult& mutableError = const_cast<nsFileSpec*>(this)->mError;
931 if (inRecursive)
933 // MoreFilesExtras
934 anErr = ::DeleteDirectory(
935 mSpec.vRefNum,
936 mSpec.parID,
937 const_cast<unsigned char*>(mSpec.name));
939 else
940 anErr = ::FSpDelete(&mSpec);
942 if (anErr == fnfErr) // deleting a file that doesn't exist isn't an error!
943 anErr = noErr;
945 mutableError = NS_FILE_RESULT(anErr);
947 } // nsFileSpec::Delete
949 //----------------------------------------------------------------------------------------
950 void nsFileSpec::RecursiveCopy(nsFileSpec newDir) const
951 //----------------------------------------------------------------------------------------
953 if (IsDirectory())
955 if (!(newDir.Exists()))
957 newDir.CreateDirectory();
960 for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++)
962 nsFileSpec& child = (nsFileSpec&)i;
964 if (child.IsDirectory())
966 nsFileSpec tmpDirSpec(newDir);
968 char *leafname = child.GetLeafName();
969 tmpDirSpec += leafname;
970 nsCRT::free(leafname);
972 child.RecursiveCopy(tmpDirSpec);
974 else
976 child.RecursiveCopy(newDir);
980 else
982 nsFileSpec& filePath = (nsFileSpec&) *this;
984 if (!(newDir.Exists()))
986 newDir.CreateDirectory();
989 filePath.CopyToDir(newDir);
991 } // nsFileSpec::RecursiveCopy
993 //----------------------------------------------------------------------------------------
994 nsresult nsFileSpec::Truncate(PRInt32 aNewLength) const
995 //----------------------------------------------------------------------------------------
997 short refNum;
998 OSErr err;
1000 // First see if we have an internal error set
1001 if (NS_FAILED(mError))
1002 return mError;
1004 // Need to open the file to trunc
1005 if (::FSpOpenDF(&mSpec, fsWrPerm, &refNum) != noErr)
1006 return NS_FILE_FAILURE;
1008 err = ::SetEOF(refNum, aNewLength);
1010 // Close the file unless we got an error that it was already closed
1011 if (err != fnOpnErr)
1012 (void)::FSClose(refNum);
1014 if (err != noErr)
1015 return NS_FILE_FAILURE;
1017 return NS_OK;
1018 } // nsFileSpec::Truncate
1020 //----------------------------------------------------------------------------------------
1021 nsresult nsFileSpec::Rename(const char* inNewName)
1022 //----------------------------------------------------------------------------------------
1024 NS_ASSERTION(inNewName, "Attempt to rename with null new name");
1026 if (strchr(inNewName, '/'))
1027 return NS_FILE_FAILURE; // no relative paths here!
1029 Str255 pName;
1030 MacFileHelpers::PLstrcpy(pName, inNewName);
1031 if (::FSpRename(&mSpec, pName) != noErr)
1032 return NS_FILE_FAILURE;
1033 SetLeafName(inNewName);
1034 return NS_OK;
1035 } // nsFileSpec::Rename
1037 //----------------------------------------------------------------------------------------
1038 nsresult nsFileSpec::CopyToDir(const nsFileSpec& newParentDir) const
1039 //----------------------------------------------------------------------------------------
1041 // We can only copy into a directory, and (for now) can not copy entire directories
1043 if (!newParentDir.IsDirectory() || (IsDirectory() ) )
1044 return NS_FILE_FAILURE;
1046 nsresult rv = NS_FILE_RESULT(::FSpFileCopy(&mSpec,
1047 &newParentDir.mSpec,
1048 const_cast<StringPtr>(GetLeafPName()),
1049 nsnull,
1051 true));
1053 return rv;
1055 } // nsFileSpec::CopyToDir
1057 //----------------------------------------------------------------------------------------
1058 nsresult nsFileSpec::MoveToDir(const nsFileSpec& newParentDir)
1059 //----------------------------------------------------------------------------------------
1061 // We can only move into a directory
1063 if (!newParentDir.IsDirectory())
1064 return NS_FILE_FAILURE;
1066 nsresult result = NS_FILE_RESULT(::FSpMoveRenameCompat(&mSpec,
1067 &newParentDir.mSpec,
1068 const_cast<StringPtr>(GetLeafPName())));
1070 if ( NS_SUCCEEDED(result) )
1072 char* leafName = GetLeafName();
1073 *this = newParentDir + leafName;
1074 nsCRT::free(leafName);
1076 return result;
1077 } // nsFileSpec::MoveToDir
1079 //----------------------------------------------------------------------------------------
1080 nsresult nsFileSpec::Execute(const char* /*args - how can this be cross-platform? problem! */ ) const
1081 //----------------------------------------------------------------------------------------
1083 if (IsDirectory())
1084 return NS_FILE_FAILURE;
1086 LaunchParamBlockRec launchThis;
1087 launchThis.launchAppSpec = const_cast<FSSpec*>(&mSpec);
1088 launchThis.launchAppParameters = nsnull; // args;
1089 /* launch the thing */
1090 launchThis.launchBlockID = extendedBlock;
1091 launchThis.launchEPBLength = extendedBlockLen;
1092 launchThis.launchFileFlags = nsnull;
1093 launchThis.launchControlFlags = launchContinue + launchNoFileFlags + launchUseMinimum;
1094 launchThis.launchControlFlags += launchDontSwitch;
1096 nsresult result = NS_FILE_RESULT(::LaunchApplication(&launchThis));
1097 return result;
1099 } // nsFileSpec::Execute
1101 //----------------------------------------------------------------------------------------
1102 OSErr nsFileSpec::GetCatInfo(CInfoPBRec& outInfo) const
1103 //----------------------------------------------------------------------------------------
1105 DirInfo *dipb=(DirInfo *)&outInfo;
1106 dipb->ioCompletion = nsnull;
1107 dipb->ioFDirIndex = 0; // use dirID and name
1108 dipb->ioVRefNum = mSpec.vRefNum;
1109 dipb->ioDrDirID = mSpec.parID;
1110 dipb->ioNamePtr = const_cast<nsFileSpec*>(this)->mSpec.name;
1111 return PBGetCatInfoSync(&outInfo);
1112 } // nsFileSpec::GetCatInfo()
1114 //----------------------------------------------------------------------------------------
1115 OSErr nsFileSpec::SetFileTypeAndCreator(OSType type, OSType creator)
1116 //----------------------------------------------------------------------------------------
1118 FInfo info;
1119 OSErr err = ::FSpGetFInfo(&mSpec, &info);
1120 if (err != noErr)
1121 return err;
1122 info.fdType = type;
1123 info.fdCreator = creator;
1124 err = ::FSpSetFInfo(&mSpec, &info);
1125 return err;
1128 //----------------------------------------------------------------------------------------
1129 OSErr nsFileSpec::GetFileTypeAndCreator(OSType* type, OSType* creator)
1130 //----------------------------------------------------------------------------------------
1132 FInfo info;
1133 OSErr err = ::FSpGetFInfo(&mSpec, &info);
1134 if (err != noErr)
1135 return err;
1136 *type = info.fdType;
1137 *creator = info.fdCreator;
1138 return noErr;
1141 //----------------------------------------------------------------------------------------
1142 PRInt64 nsFileSpec::GetDiskSpaceAvailable() const
1143 //----------------------------------------------------------------------------------------
1145 PRInt64 space64Bits;
1147 LL_I2L(space64Bits , LONG_MAX);
1149 XVolumeParam pb;
1150 pb.ioCompletion = nsnull;
1151 pb.ioVolIndex = 0;
1152 pb.ioNamePtr = nsnull;
1153 pb.ioVRefNum = mSpec.vRefNum;
1155 // PBXGetVolInfoSync works on HFS+ volumes too!
1156 OSErr err = ::PBXGetVolInfoSync(&pb);
1158 if (err == noErr)
1160 #ifdef HAVE_LONG_LONG
1161 space64Bits = pb.ioVFreeBytes;
1162 #else
1163 const UnsignedWide& freeBytes = UInt64ToUnsignedWide(pb.ioVFreeBytes);
1164 space64Bits.lo = freeBytes.lo;
1165 space64Bits.hi = freeBytes.hi;
1166 #endif
1169 return space64Bits;
1170 } // nsFileSpec::GetDiskSpace()
1172 //----------------------------------------------------------------------------------------
1173 const char* nsFileSpec::GetCString() const
1174 // This is the only conversion to const char* that is provided, and it allows the
1175 // path to be "passed" to NSPR file routines. This practice is VERY EVIL and should only
1176 // be used to support legacy code. Using it guarantees bugs on Macintosh. The string is
1177 // cached and freed by the nsFileSpec destructor, so do not delete (or free) it.
1178 //----------------------------------------------------------------------------------------
1180 if (mPath.IsEmpty())
1182 char* path = MacFileHelpers::PathNameFromFSSpec(mSpec);
1183 if (path != NULL) {
1184 const_cast<nsFileSpec*>(this)->mPath = path; // operator =() copies the string!!!
1185 delete[] path;
1186 } else {
1187 const_cast<nsFileSpec*>(this)->mError = NS_ERROR_OUT_OF_MEMORY;
1190 return mPath;
1193 #pragma mark -
1195 //========================================================================================
1196 // Macintosh nsFilePath implementation
1197 //========================================================================================
1199 //----------------------------------------------------------------------------------------
1200 static void AssignFromPath(nsFilePath& ioPath, const char* inString, PRBool inCreateDirs)
1201 //----------------------------------------------------------------------------------------
1203 NS_ASSERTION(inString, "AssignFromPath called with null inString");
1204 NS_ASSERTION(strstr(inString, kFileURLPrefix) != inString, "URL passed as path");
1206 FSSpec spec;
1207 spec.vRefNum = 0;
1208 spec.parID = 0;
1209 spec.name[0] = 0;
1210 MacFileHelpers::FSSpecFromUnixPath(
1211 inString,
1212 spec,
1213 false,
1214 true, // resolve alias
1215 true,
1216 inCreateDirs);
1217 // Now we have a spec,
1218 // Invoke operator = (const nsFileSpec&) to do the rest.
1219 // Why didn't we just say mPath = inString to get the path? Well, we want it to be
1220 // canonical and absolute.
1221 ioPath = spec;
1224 //----------------------------------------------------------------------------------------
1225 nsFilePath::nsFilePath(const char* inString, PRBool inCreateDirs)
1226 //----------------------------------------------------------------------------------------
1228 AssignFromPath(*this, inString, inCreateDirs);
1229 } //nsFilePath::nsFilePath
1231 //----------------------------------------------------------------------------------------
1232 nsFilePath::nsFilePath(const nsString& inString, PRBool inCreateDirs)
1233 //----------------------------------------------------------------------------------------
1235 AssignFromPath(*this, NS_LossyConvertUTF16toASCII(inString).get(),
1236 inCreateDirs);
1239 //----------------------------------------------------------------------------------------
1240 void nsFilePath::operator = (const char* inString)
1241 //----------------------------------------------------------------------------------------
1243 AssignFromPath(*this, inString, PR_FALSE);
1246 //----------------------------------------------------------------------------------------
1247 nsFilePath::nsFilePath(const nsFileSpec& inSpec)
1248 //----------------------------------------------------------------------------------------
1250 *this = inSpec;
1253 //----------------------------------------------------------------------------------------
1254 nsFilePath::nsFilePath(const nsFileURL& inOther)
1255 //----------------------------------------------------------------------------------------
1257 *this = inOther;
1260 //----------------------------------------------------------------------------------------
1261 void nsFilePath::operator = (const nsFileSpec& inSpec)
1262 //----------------------------------------------------------------------------------------
1264 char * path = MacFileHelpers::PathNameFromFSSpec(inSpec);
1265 path = MacFileHelpers::EncodeMacPath(path, true, false);
1266 mPath = path;
1267 nsCRT::free(path);
1268 mFileSpec = inSpec;
1269 } // nsFilePath::operator =
1271 //----------------------------------------------------------------------------------------
1272 void nsFilePath::operator = (const nsFileURL& inOther)
1273 //----------------------------------------------------------------------------------------
1275 char * path = MacFileHelpers::PathNameFromFSSpec(inOther.mFileSpec);
1276 path = MacFileHelpers::EncodeMacPath(path, true, false);
1277 mPath = path;
1278 nsCRT::free(path);
1279 mFileSpec = inOther.GetFileSpec();
1282 #pragma mark -
1284 //========================================================================================
1285 // nsFileURL implementation
1286 //========================================================================================
1288 //----------------------------------------------------------------------------------------
1289 nsFileURL::nsFileURL(const char* inString, PRBool inCreateDirs)
1290 //----------------------------------------------------------------------------------------
1291 : mURL(inString)
1293 NS_ASSERTION(inString, "nsFileURL constructed with null inString");
1294 NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!");
1295 mFileSpec.mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromUnixPath(
1296 inString + kFileURLPrefixLength,
1297 mFileSpec.mSpec,
1298 true, // need to decode
1299 false, // resolve alias
1300 false, // must be a full path
1301 inCreateDirs));
1302 if (mFileSpec.mError == NS_FILE_RESULT(fnfErr))
1303 mFileSpec.mError = NS_OK;
1304 } // nsFileURL::nsFileURL
1306 //----------------------------------------------------------------------------------------
1307 nsFileURL::nsFileURL(const nsString& inString, PRBool inCreateDirs)
1308 //----------------------------------------------------------------------------------------
1309 : mURL(nsnull)
1311 NS_LossyConvertUTF16toASCII cstring(inString);
1312 mURL = cstring.get();
1313 NS_ASSERTION(strstr(cstring.get(), kFileURLPrefix) == cstring.get(),
1314 "Not a URL!");
1315 mFileSpec.mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromUnixPath(
1316 cstring.get() + kFileURLPrefixLength,
1317 mFileSpec.mSpec,
1318 true, // need to decode
1319 false, // resolve alias
1320 false, // must be a full path
1321 inCreateDirs));
1322 if (mFileSpec.mError == NS_FILE_RESULT(fnfErr))
1323 mFileSpec.mError = NS_OK;
1324 } // nsFileURL::nsFileURL
1326 //----------------------------------------------------------------------------------------
1327 nsFileURL::nsFileURL(const nsFilePath& inOther)
1328 //----------------------------------------------------------------------------------------
1330 *this = inOther.GetFileSpec();
1331 } // nsFileURL::nsFileURL
1333 //----------------------------------------------------------------------------------------
1334 nsFileURL::nsFileURL(const nsFileSpec& inOther)
1335 //----------------------------------------------------------------------------------------
1337 *this = inOther;
1338 } // nsFileURL::nsFileURL
1340 //----------------------------------------------------------------------------------------
1341 void nsFileURL::operator = (const nsFilePath& inOther)
1342 //----------------------------------------------------------------------------------------
1344 *this = inOther.GetFileSpec();
1345 } // nsFileURL::operator =
1347 //----------------------------------------------------------------------------------------
1348 void nsFileURL::operator = (const nsFileSpec& inOther)
1349 //----------------------------------------------------------------------------------------
1351 mFileSpec = inOther;
1352 char* path = MacFileHelpers::PathNameFromFSSpec( mFileSpec );
1353 char* encodedPath = MacFileHelpers::EncodeMacPath(path, true, true);
1354 nsSimpleCharString encodedURL(kFileURLPrefix);
1355 encodedURL += encodedPath;
1356 nsCRT::free(encodedPath);
1357 mURL = encodedURL;
1358 if (encodedURL[encodedURL.Length() - 1] != '/' && inOther.IsDirectory())
1359 mURL += "/";
1360 } // nsFileURL::operator =
1362 //----------------------------------------------------------------------------------------
1363 void nsFileURL::operator = (const char* inString)
1364 //----------------------------------------------------------------------------------------
1366 NS_ASSERTION(inString, "nsFileURL operator= constructed with null inString");
1368 mURL = inString;
1369 NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!");
1370 mFileSpec.mError = NS_FILE_RESULT(MacFileHelpers::FSSpecFromUnixPath(
1371 inString + kFileURLPrefixLength,
1372 mFileSpec.mSpec,
1373 true, // need to decode
1374 true, // resolve alias
1375 false, // must be a full path
1376 false)); // don't create dirs.
1377 if (mFileSpec.mError == NS_FILE_RESULT(fnfErr))
1378 mFileSpec.mError = NS_OK;
1379 } // nsFileURL::operator =
1381 #pragma mark -
1383 //========================================================================================
1384 // nsDirectoryIterator
1385 //========================================================================================
1387 //----------------------------------------------------------------------------------------
1388 nsDirectoryIterator::nsDirectoryIterator(
1389 const nsFileSpec& inDirectory
1390 , PRBool resolveSymLinks)
1391 //----------------------------------------------------------------------------------------
1392 : mCurrent(inDirectory)
1393 , mExists(false)
1394 , mResoveSymLinks(resolveSymLinks)
1395 , mIndex(-1)
1397 CInfoPBRec pb;
1398 OSErr err = inDirectory.GetCatInfo(pb);
1400 // test that we have got a directory back, not a file
1401 DirInfo* dipb = (DirInfo*)&pb;
1402 if (err != noErr || !( dipb->ioFlAttrib & 0x0010))
1403 return;
1404 // Sorry about this, there seems to be a bug in CWPro 4:
1405 FSSpec& currentSpec = mCurrent.nsFileSpec::operator FSSpec&();
1406 mVRefNum = currentSpec.vRefNum;
1407 mParID = dipb->ioDrDirID;
1408 mMaxIndex = pb.dirInfo.ioDrNmFls;
1409 mIndex = 0; // ready to increment
1410 ++(*this); // the pre-increment operator
1412 } // nsDirectoryIterator::nsDirectoryIterator
1414 //----------------------------------------------------------------------------------------
1415 OSErr nsDirectoryIterator::SetToIndex()
1416 //----------------------------------------------------------------------------------------
1418 CInfoPBRec cipb;
1419 DirInfo *dipb=(DirInfo *)&cipb;
1420 Str255 objectName;
1421 dipb->ioCompletion = nsnull;
1422 dipb->ioFDirIndex = mIndex;
1423 // Sorry about this, there seems to be a bug in CWPro 4:
1424 FSSpec& currentSpec = mCurrent.nsFileSpec::operator FSSpec&();
1425 dipb->ioVRefNum = mVRefNum; /* Might need to use vRefNum, not sure*/
1426 dipb->ioDrDirID = mParID;
1427 dipb->ioNamePtr = objectName;
1428 OSErr err = PBGetCatInfoSync(&cipb);
1429 FSSpec temp;
1430 if (err == noErr)
1431 err = FSMakeFSSpec(mVRefNum, mParID, objectName, &temp);
1432 mCurrent = temp; // use the operator: it clears the string cache.
1433 mExists = err == noErr;
1435 if (mExists && mResoveSymLinks)
1437 PRBool ignore;
1438 mCurrent.ResolveSymlink(ignore);
1440 return err;
1441 } // nsDirectoryIterator::SetToIndex()
1443 //----------------------------------------------------------------------------------------
1444 nsDirectoryIterator& nsDirectoryIterator::operator -- ()
1445 //----------------------------------------------------------------------------------------
1447 mExists = false;
1448 while (--mIndex > 0)
1450 OSErr err = SetToIndex();
1451 if (err == noErr)
1452 break;
1454 return *this;
1455 } // nsDirectoryIterator::operator --
1457 //----------------------------------------------------------------------------------------
1458 nsDirectoryIterator& nsDirectoryIterator::operator ++ ()
1459 //----------------------------------------------------------------------------------------
1461 mExists = false;
1462 if (mIndex >= 0) // probably trying to use a file as a directory!
1463 while (++mIndex <= mMaxIndex)
1465 OSErr err = SetToIndex();
1466 if (err == noErr)
1467 break;
1469 return *this;
1470 } // nsDirectoryIterator::operator ++