| 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 |
|---|
| 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 | * Mike Shaver <shaver@mozilla.org> |
|---|
| 25 | * Christopher Blizzard <blizzard@mozilla.org> |
|---|
| 26 | * Jason Eager <jce2@po.cwru.edu> |
|---|
| 27 | * Stuart Parmenter <pavlov@netscape.com> |
|---|
| 28 | * Brendan Eich <brendan@mozilla.org> |
|---|
| 29 | * Pete Collins <petejc@mozdev.org> |
|---|
| 30 | * Paul Ashford <arougthopher@lizardland.net> |
|---|
| 31 | * Fredrik Holmqvist <thesuckiestemail@yahoo.se> |
|---|
| 32 | * |
|---|
| 33 | * Alternatively, the contents of this file may be used under the terms of |
|---|
| 34 | * either of the GNU General Public License Version 2 or later (the "GPL"), |
|---|
| 35 | * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), |
|---|
| 36 | * in which case the provisions of the GPL or the LGPL are applicable instead |
|---|
| 37 | * of those above. If you wish to allow use of your version of this file only |
|---|
| 38 | * under the terms of either the GPL or the LGPL, and not to allow others to |
|---|
| 39 | * use your version of this file under the terms of the MPL, indicate your |
|---|
| 40 | * decision by deleting the provisions above and replace them with the notice |
|---|
| 41 | * and other provisions required by the GPL or the LGPL. If you do not delete |
|---|
| 42 | * the provisions above, a recipient may use your version of this file under |
|---|
| 43 | * the terms of any one of the MPL, the GPL or the LGPL. |
|---|
| 44 | * |
|---|
| 45 | * ***** END LICENSE BLOCK ***** */ |
|---|
| 46 | |
|---|
| 47 | /** |
|---|
| 48 | * Implementation of nsIFile for ``Unixy'' systems. |
|---|
| 49 | */ |
|---|
| 50 | |
|---|
| 51 | // We're going to need some autoconf loving, I can just tell. |
|---|
| 52 | #include <sys/types.h> |
|---|
| 53 | #include <sys/stat.h> |
|---|
| 54 | #include <unistd.h> |
|---|
| 55 | #include <fcntl.h> |
|---|
| 56 | #include <errno.h> |
|---|
| 57 | #include <utime.h> |
|---|
| 58 | #include <dirent.h> |
|---|
| 59 | #include <ctype.h> |
|---|
| 60 | #include <locale.h> |
|---|
| 61 | #ifdef XP_BEOS |
|---|
| 62 | #include <Path.h> |
|---|
| 63 | #include <Entry.h> |
|---|
| 64 | #include <Roster.h> |
|---|
| 65 | #endif |
|---|
| 66 | #if defined(VMS) |
|---|
| 67 | #include <fabdef.h> |
|---|
| 68 | #endif |
|---|
| 69 | |
|---|
| 70 | #include "nsDirectoryServiceDefs.h" |
|---|
| 71 | #include "nsCRT.h" |
|---|
| 72 | #include "nsCOMPtr.h" |
|---|
| 73 | #include "nsMemory.h" |
|---|
| 74 | #include "nsIFile.h" |
|---|
| 75 | #include "nsString.h" |
|---|
| 76 | #include "nsReadableUtils.h" |
|---|
| 77 | #include "nsLocalFile.h" |
|---|
| 78 | #include "nsIComponentManager.h" |
|---|
| 79 | #include "nsXPIDLString.h" |
|---|
| 80 | #include "prproces.h" |
|---|
| 81 | #include "nsIDirectoryEnumerator.h" |
|---|
| 82 | #include "nsISimpleEnumerator.h" |
|---|
| 83 | #include "nsITimelineService.h" |
|---|
| 84 | |
|---|
| 85 | #ifdef MOZ_WIDGET_GTK2 |
|---|
| 86 | #include "nsIGnomeVFSService.h" |
|---|
| 87 | #endif |
|---|
| 88 | |
|---|
| 89 | #include "nsNativeCharsetUtils.h" |
|---|
| 90 | #include "nsTraceRefcntImpl.h" |
|---|
| 91 | |
|---|
| 92 | // On some platforms file/directory name comparisons need to |
|---|
| 93 | // be case-blind. |
|---|
| 94 | #if defined(VMS) |
|---|
| 95 | #define FILE_STRCMP strcasecmp |
|---|
| 96 | #define FILE_STRNCMP strncasecmp |
|---|
| 97 | #else |
|---|
| 98 | #define FILE_STRCMP strcmp |
|---|
| 99 | #define FILE_STRNCMP strncmp |
|---|
| 100 | #endif |
|---|
| 101 | |
|---|
| 102 | #define VALIDATE_STAT_CACHE() \ |
|---|
| 103 | PR_BEGIN_MACRO \ |
|---|
| 104 | if (!mHaveCachedStat) { \ |
|---|
| 105 | FillStatCache(); \ |
|---|
| 106 | if (!mHaveCachedStat) \ |
|---|
| 107 | return NSRESULT_FOR_ERRNO(); \ |
|---|
| 108 | } \ |
|---|
| 109 | PR_END_MACRO |
|---|
| 110 | |
|---|
| 111 | #define CHECK_mPath() \ |
|---|
| 112 | PR_BEGIN_MACRO \ |
|---|
| 113 | if (mPath.IsEmpty()) \ |
|---|
| 114 | return NS_ERROR_NOT_INITIALIZED; \ |
|---|
| 115 | PR_END_MACRO |
|---|
| 116 | |
|---|
| 117 | /* directory enumerator */ |
|---|
| 118 | class NS_COM |
|---|
| 119 | nsDirEnumeratorUnix : public nsISimpleEnumerator, |
|---|
| 120 | public nsIDirectoryEnumerator |
|---|
| 121 | { |
|---|
| 122 | public: |
|---|
| 123 | nsDirEnumeratorUnix(); |
|---|
| 124 | |
|---|
| 125 | // nsISupports interface |
|---|
| 126 | NS_DECL_ISUPPORTS |
|---|
| 127 | |
|---|
| 128 | // nsISimpleEnumerator interface |
|---|
| 129 | NS_DECL_NSISIMPLEENUMERATOR |
|---|
| 130 | |
|---|
| 131 | // nsIDirectoryEnumerator interface |
|---|
| 132 | NS_DECL_NSIDIRECTORYENUMERATOR |
|---|
| 133 | |
|---|
| 134 | NS_IMETHOD Init(nsLocalFile *parent, PRBool ignored); |
|---|
| 135 | |
|---|
| 136 | private: |
|---|
| 137 | ~nsDirEnumeratorUnix(); |
|---|
| 138 | |
|---|
| 139 | protected: |
|---|
| 140 | NS_IMETHOD GetNextEntry(); |
|---|
| 141 | |
|---|
| 142 | DIR *mDir; |
|---|
| 143 | struct dirent *mEntry; |
|---|
| 144 | nsCString mParentPath; |
|---|
| 145 | }; |
|---|
| 146 | |
|---|
| 147 | nsDirEnumeratorUnix::nsDirEnumeratorUnix() : |
|---|
| 148 | mDir(nsnull), |
|---|
| 149 | mEntry(nsnull) |
|---|
| 150 | { |
|---|
| 151 | } |
|---|
| 152 | |
|---|
| 153 | nsDirEnumeratorUnix::~nsDirEnumeratorUnix() |
|---|
| 154 | { |
|---|
| 155 | Close(); |
|---|
| 156 | } |
|---|
| 157 | |
|---|
| 158 | NS_IMPL_ISUPPORTS2(nsDirEnumeratorUnix, nsISimpleEnumerator, nsIDirectoryEnumerator) |
|---|
| 159 | |
|---|
| 160 | NS_IMETHODIMP |
|---|
| 161 | nsDirEnumeratorUnix::Init(nsLocalFile *parent, PRBool resolveSymlinks /*ignored*/) |
|---|
| 162 | { |
|---|
| 163 | nsCAutoString dirPath; |
|---|
| 164 | if (NS_FAILED(parent->GetNativePath(dirPath)) || |
|---|
| 165 | dirPath.IsEmpty()) { |
|---|
| 166 | return NS_ERROR_FILE_INVALID_PATH; |
|---|
| 167 | } |
|---|
| 168 | |
|---|
| 169 | if (NS_FAILED(parent->GetNativePath(mParentPath))) |
|---|
| 170 | return NS_ERROR_FAILURE; |
|---|
| 171 | |
|---|
| 172 | mDir = opendir(dirPath.get()); |
|---|
| 173 | if (!mDir) |
|---|
| 174 | return NSRESULT_FOR_ERRNO(); |
|---|
| 175 | return GetNextEntry(); |
|---|
| 176 | } |
|---|
| 177 | |
|---|
| 178 | NS_IMETHODIMP |
|---|
| 179 | nsDirEnumeratorUnix::HasMoreElements(PRBool *result) |
|---|
| 180 | { |
|---|
| 181 | *result = mDir && mEntry; |
|---|
| 182 | if (!*result) |
|---|
| 183 | Close(); |
|---|
| 184 | return NS_OK; |
|---|
| 185 | } |
|---|
| 186 | |
|---|
| 187 | NS_IMETHODIMP |
|---|
| 188 | nsDirEnumeratorUnix::GetNext(nsISupports **_retval) |
|---|
| 189 | { |
|---|
| 190 | nsCOMPtr<nsIFile> file; |
|---|
| 191 | nsresult rv = GetNextFile(getter_AddRefs(file)); |
|---|
| 192 | if (NS_FAILED(rv)) |
|---|
| 193 | return rv; |
|---|
| 194 | NS_IF_ADDREF(*_retval = file); |
|---|
| 195 | return NS_OK; |
|---|
| 196 | } |
|---|
| 197 | |
|---|
| 198 | NS_IMETHODIMP |
|---|
| 199 | nsDirEnumeratorUnix::GetNextEntry() |
|---|
| 200 | { |
|---|
| 201 | do { |
|---|
| 202 | errno = 0; |
|---|
| 203 | mEntry = readdir(mDir); |
|---|
| 204 | |
|---|
| 205 | // end of dir or error |
|---|
| 206 | if (!mEntry) |
|---|
| 207 | return NSRESULT_FOR_ERRNO(); |
|---|
| 208 | |
|---|
| 209 | // keep going past "." and ".." |
|---|
| 210 | } while (mEntry->d_name[0] == '.' && |
|---|
| 211 | (mEntry->d_name[1] == '\0' || // .\0 |
|---|
| 212 | (mEntry->d_name[1] == '.' && |
|---|
| 213 | mEntry->d_name[2] == '\0'))); // ..\0 |
|---|
| 214 | return NS_OK; |
|---|
| 215 | } |
|---|
| 216 | |
|---|
| 217 | NS_IMETHODIMP |
|---|
| 218 | nsDirEnumeratorUnix::GetNextFile(nsIFile **_retval) |
|---|
| 219 | { |
|---|
| 220 | nsresult rv; |
|---|
| 221 | if (!mDir || !mEntry) { |
|---|
| 222 | *_retval = nsnull; |
|---|
| 223 | return NS_OK; |
|---|
| 224 | } |
|---|
| 225 | |
|---|
| 226 | nsCOMPtr<nsILocalFile> file = new nsLocalFile(); |
|---|
| 227 | if (!file) |
|---|
| 228 | return NS_ERROR_OUT_OF_MEMORY; |
|---|
| 229 | |
|---|
| 230 | if (NS_FAILED(rv = file->InitWithNativePath(mParentPath)) || |
|---|
| 231 | NS_FAILED(rv = file->AppendNative(nsDependentCString(mEntry->d_name)))) |
|---|
| 232 | return rv; |
|---|
| 233 | |
|---|
| 234 | *_retval = file; |
|---|
| 235 | NS_ADDREF(*_retval); |
|---|
| 236 | return GetNextEntry(); |
|---|
| 237 | } |
|---|
| 238 | |
|---|
| 239 | NS_IMETHODIMP |
|---|
| 240 | nsDirEnumeratorUnix::Close() |
|---|
| 241 | { |
|---|
| 242 | if (mDir) { |
|---|
| 243 | closedir(mDir); |
|---|
| 244 | mDir = nsnull; |
|---|
| 245 | } |
|---|
| 246 | return NS_OK; |
|---|
| 247 | } |
|---|
| 248 | |
|---|
| 249 | nsLocalFile::nsLocalFile() : |
|---|
| 250 | mHaveCachedStat(PR_FALSE) |
|---|
| 251 | { |
|---|
| 252 | } |
|---|
| 253 | |
|---|
| 254 | nsLocalFile::nsLocalFile(const nsLocalFile& other) |
|---|
| 255 | : mPath(other.mPath) |
|---|
| 256 | , mHaveCachedStat(PR_FALSE) |
|---|
| 257 | { |
|---|
| 258 | } |
|---|
| 259 | |
|---|
| 260 | NS_IMPL_THREADSAFE_ISUPPORTS3(nsLocalFile, |
|---|
| 261 | nsIFile, |
|---|
| 262 | nsILocalFile, |
|---|
| 263 | nsIHashable) |
|---|
| 264 | |
|---|
| 265 | nsresult |
|---|
| 266 | nsLocalFile::nsLocalFileConstructor(nsISupports *outer, |
|---|
| 267 | const nsIID &aIID, |
|---|
| 268 | void **aInstancePtr) |
|---|
| 269 | { |
|---|
| 270 | NS_ENSURE_ARG_POINTER(aInstancePtr); |
|---|
| 271 | NS_ENSURE_NO_AGGREGATION(outer); |
|---|
| 272 | |
|---|
| 273 | *aInstancePtr = nsnull; |
|---|
| 274 | |
|---|
| 275 | nsCOMPtr<nsIFile> inst = new nsLocalFile(); |
|---|
| 276 | if (!inst) |
|---|
| 277 | return NS_ERROR_OUT_OF_MEMORY; |
|---|
| 278 | return inst->QueryInterface(aIID, aInstancePtr); |
|---|
| 279 | } |
|---|
| 280 | |
|---|
| 281 | nsresult |
|---|
| 282 | nsLocalFile::FillStatCache() { |
|---|
| 283 | if (stat(mPath.get(), &mCachedStat) == -1) { |
|---|
| 284 | // try lstat it may be a symlink |
|---|
| 285 | if (lstat(mPath.get(), &mCachedStat) == -1) { |
|---|
| 286 | return NSRESULT_FOR_ERRNO(); |
|---|
| 287 | } |
|---|
| 288 | } |
|---|
| 289 | mHaveCachedStat = PR_TRUE; |
|---|
| 290 | return NS_OK; |
|---|
| 291 | } |
|---|
| 292 | |
|---|
| 293 | NS_IMETHODIMP |
|---|
| 294 | nsLocalFile::Clone(nsIFile **file) |
|---|
| 295 | { |
|---|
| 296 | // Just copy-construct ourselves |
|---|
| 297 | *file = new nsLocalFile(*this); |
|---|
| 298 | if (!*file) |
|---|
| 299 | return NS_ERROR_OUT_OF_MEMORY; |
|---|
| 300 | |
|---|
| 301 | NS_ADDREF(*file); |
|---|
| 302 | |
|---|
| 303 | return NS_OK; |
|---|
| 304 | } |
|---|
| 305 | |
|---|
| 306 | NS_IMETHODIMP |
|---|
| 307 | nsLocalFile::InitWithNativePath(const nsACString &filePath) |
|---|
| 308 | { |
|---|
| 309 | if (Substring(filePath, 0, 2).EqualsLiteral("~/")) { |
|---|
| 310 | nsCOMPtr<nsIFile> homeDir; |
|---|
| 311 | nsCAutoString homePath; |
|---|
| 312 | if (NS_FAILED(NS_GetSpecialDirectory(NS_OS_HOME_DIR, |
|---|
| 313 | getter_AddRefs(homeDir))) || |
|---|
| 314 | NS_FAILED(homeDir->GetNativePath(homePath))) { |
|---|
| 315 | return NS_ERROR_FAILURE; |
|---|
| 316 | } |
|---|
| 317 | |
|---|
| 318 | mPath = homePath + Substring(filePath, 1, filePath.Length() - 1); |
|---|
| 319 | } else { |
|---|
| 320 | if (filePath.IsEmpty() || filePath.First() != '/') |
|---|
| 321 | return NS_ERROR_FILE_UNRECOGNIZED_PATH; |
|---|
| 322 | mPath = filePath; |
|---|
| 323 | } |
|---|
| 324 | |
|---|
| 325 | // trim off trailing slashes |
|---|
| 326 | ssize_t len = mPath.Length(); |
|---|
| 327 | while ((len > 1) && (mPath[len - 1] == '/')) |
|---|
| 328 | --len; |
|---|
| 329 | mPath.SetLength(len); |
|---|
| 330 | |
|---|
| 331 | InvalidateCache(); |
|---|
| 332 | return NS_OK; |
|---|
| 333 | } |
|---|
| 334 | |
|---|
| 335 | NS_IMETHODIMP |
|---|
| 336 | nsLocalFile::CreateAllAncestors(PRUint32 permissions) |
|---|
| 337 | { |
|---|
| 338 | // <jband> I promise to play nice |
|---|
| 339 | char *buffer = mPath.BeginWriting(), |
|---|
| 340 | *slashp = buffer; |
|---|
| 341 | |
|---|
| 342 | #ifdef DEBUG_NSIFILE |
|---|
| 343 | fprintf(stderr, "nsIFile: before: %s\n", buffer); |
|---|
| 344 | #endif |
|---|
| 345 | |
|---|
| 346 | while ((slashp = strchr(slashp + 1, '/'))) { |
|---|
| 347 | /* |
|---|
| 348 | * Sequences of '/' are equivalent to a single '/'. |
|---|
| 349 | */ |
|---|
| 350 | if (slashp[1] == '/') |
|---|
| 351 | continue; |
|---|
| 352 | |
|---|
| 353 | /* |
|---|
| 354 | * If the path has a trailing slash, don't make the last component, |
|---|
| 355 | * because we'll get EEXIST in Create when we try to build the final |
|---|
| 356 | * component again, and it's easier to condition the logic here than |
|---|
| 357 | * there. |
|---|
| 358 | */ |
|---|
| 359 | if (slashp[1] == '\0') |
|---|
| 360 | break; |
|---|
| 361 | |
|---|
| 362 | /* Temporarily NUL-terminate here */ |
|---|
| 363 | *slashp = '\0'; |
|---|
| 364 | #ifdef DEBUG_NSIFILE |
|---|
| 365 | fprintf(stderr, "nsIFile: mkdir(\"%s\")\n", buffer); |
|---|
| 366 | #endif |
|---|
| 367 | int mkdir_result = mkdir(buffer, permissions); |
|---|
| 368 | int mkdir_errno = errno; |
|---|
| 369 | if (mkdir_result == -1) { |
|---|
| 370 | /* |
|---|
| 371 | * Always set |errno| to EEXIST if the dir already exists |
|---|
| 372 | * (we have to do this here since the errno value is not consistent |
|---|
| 373 | * in all cases - various reasons like different platform, |
|---|
| 374 | * automounter-controlled dir, etc. can affect it (see bug 125489 |
|---|
| 375 | * for details)). |
|---|
| 376 | */ |
|---|
| 377 | if (access(buffer, F_OK) == 0) { |
|---|
| 378 | mkdir_errno = EEXIST; |
|---|
| 379 | } |
|---|
| 380 | } |
|---|
| 381 | |
|---|
| 382 | /* Put the / back before we (maybe) return */ |
|---|
| 383 | *slashp = '/'; |
|---|
| 384 | |
|---|
| 385 | /* |
|---|
| 386 | * We could get EEXIST for an existing file -- not directory -- |
|---|
| 387 | * with the name of one of our ancestors, but that's OK: we'll get |
|---|
| 388 | * ENOTDIR when we try to make the next component in the path, |
|---|
| 389 | * either here on back in Create, and error out appropriately. |
|---|
| 390 | */ |
|---|
| 391 | if (mkdir_result == -1 && mkdir_errno != EEXIST) |
|---|
| 392 | return nsresultForErrno(mkdir_errno); |
|---|
| 393 | } |
|---|
| 394 | |
|---|
| 395 | #ifdef DEBUG_NSIFILE |
|---|
| 396 | fprintf(stderr, "nsIFile: after: %s\n", buffer); |
|---|
| 397 | #endif |
|---|
| 398 | |
|---|
| 399 | return NS_OK; |
|---|
| 400 | } |
|---|
| 401 | |
|---|
| 402 | NS_IMETHODIMP |
|---|
| 403 | nsLocalFile::OpenNSPRFileDesc(PRInt32 flags, PRInt32 mode, PRFileDesc **_retval) |
|---|
| 404 | { |
|---|
| 405 | *_retval = PR_Open(mPath.get(), flags, mode); |
|---|
| 406 | if (! *_retval) |
|---|
| 407 | return NS_ErrorAccordingToNSPR(); |
|---|
| 408 | |
|---|
| 409 | return NS_OK; |
|---|
| 410 | } |
|---|
| 411 | |
|---|
| 412 | NS_IMETHODIMP |
|---|
| 413 | nsLocalFile::OpenANSIFileDesc(const char *mode, FILE **_retval) |
|---|
| 414 | { |
|---|
| 415 | *_retval = fopen(mPath.get(), mode); |
|---|
| 416 | if (! *_retval) |
|---|
| 417 | return NS_ERROR_FAILURE; |
|---|
| 418 | |
|---|
| 419 | return NS_OK; |
|---|
| 420 | } |
|---|
| 421 | |
|---|
| 422 | static int |
|---|
| 423 | do_create(const char *path, PRIntn flags, mode_t mode, PRFileDesc **_retval) |
|---|
| 424 | { |
|---|
| 425 | *_retval = PR_Open(path, flags, mode); |
|---|
| 426 | return *_retval ? 0 : -1; |
|---|
| 427 | } |
|---|
| 428 | |
|---|
| 429 | static int |
|---|
| 430 | do_mkdir(const char *path, PRIntn flags, mode_t mode, PRFileDesc **_retval) |
|---|
| 431 | { |
|---|
| 432 | *_retval = nsnull; |
|---|
| 433 | return mkdir(path, mode); |
|---|
| 434 | } |
|---|
| 435 | |
|---|
| 436 | nsresult |
|---|
| 437 | nsLocalFile::CreateAndKeepOpen(PRUint32 type, PRIntn flags, |
|---|
| 438 | PRUint32 permissions, PRFileDesc **_retval) |
|---|
| 439 | { |
|---|
| 440 | if (type != NORMAL_FILE_TYPE && type != DIRECTORY_TYPE) |
|---|
| 441 | return NS_ERROR_FILE_UNKNOWN_TYPE; |
|---|
| 442 | |
|---|
| 443 | int result; |
|---|
| 444 | int (*createFunc)(const char *, PRIntn, mode_t, PRFileDesc **) = |
|---|
| 445 | (type == NORMAL_FILE_TYPE) ? do_create : do_mkdir; |
|---|
| 446 | |
|---|
| 447 | result = createFunc(mPath.get(), flags, permissions, _retval); |
|---|
| 448 | if (result == -1 && errno == ENOENT) { |
|---|
| 449 | /* |
|---|
| 450 | * If we failed because of missing ancestor components, try to create |
|---|
| 451 | * them and then retry the original creation. |
|---|
| 452 | * |
|---|
| 453 | * Ancestor directories get the same permissions as the file we're |
|---|
| 454 | * creating, with the X bit set for each of (user,group,other) with |
|---|
| 455 | * an R bit in the original permissions. If you want to do anything |
|---|
| 456 | * fancy like setgid or sticky bits, do it by hand. |
|---|
| 457 | */ |
|---|
| 458 | int dirperm = permissions; |
|---|
| 459 | if (permissions & S_IRUSR) |
|---|
| 460 | dirperm |= S_IXUSR; |
|---|
| 461 | if (permissions & S_IRGRP) |
|---|
| 462 | dirperm |= S_IXGRP; |
|---|
| 463 | if (permissions & S_IROTH) |
|---|
| 464 | dirperm |= S_IXOTH; |
|---|
| 465 | |
|---|
| 466 | #ifdef DEBUG_NSIFILE |
|---|
| 467 | fprintf(stderr, "nsIFile: perm = %o, dirperm = %o\n", permissions, |
|---|
| 468 | dirperm); |
|---|
| 469 | #endif |
|---|
| 470 | |
|---|
| 471 | if (NS_FAILED(CreateAllAncestors(dirperm))) |
|---|
| 472 | return NS_ERROR_FAILURE; |
|---|
| 473 | |
|---|
| 474 | #ifdef DEBUG_NSIFILE |
|---|
| 475 | fprintf(stderr, "nsIFile: Create(\"%s\") again\n", mPath.get()); |
|---|
| 476 | #endif |
|---|
| 477 | result = createFunc(mPath.get(), flags, permissions, _retval); |
|---|
| 478 | } |
|---|
| 479 | return NSRESULT_FOR_RETURN(result); |
|---|
| 480 | } |
|---|
| 481 | |
|---|
| 482 | NS_IMETHODIMP |
|---|
| 483 | nsLocalFile::Create(PRUint32 type, PRUint32 permissions) |
|---|
| 484 | { |
|---|
| 485 | PRFileDesc *junk = nsnull; |
|---|
| 486 | nsresult rv = CreateAndKeepOpen(type, |
|---|
| 487 | PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE | |
|---|
| 488 | PR_EXCL, |
|---|
| 489 | permissions, |
|---|
| 490 | &junk); |
|---|
| 491 | if (junk) |
|---|
| 492 | PR_Close(junk); |
|---|
| 493 | return rv; |
|---|
| 494 | } |
|---|
| 495 | |
|---|
| 496 | NS_IMETHODIMP |
|---|
| 497 | nsLocalFile::AppendNative(const nsACString &fragment) |
|---|
| 498 | { |
|---|
| 499 | if (fragment.IsEmpty()) |
|---|
| 500 | return NS_OK; |
|---|
| 501 | |
|---|
| 502 | // only one component of path can be appended |
|---|
| 503 | nsACString::const_iterator begin, end; |
|---|
| 504 | if (FindCharInReadable('/', fragment.BeginReading(begin), |
|---|
| 505 | fragment.EndReading(end))) |
|---|
| 506 | return NS_ERROR_FILE_UNRECOGNIZED_PATH; |
|---|
| 507 | |
|---|
| 508 | return AppendRelativeNativePath(fragment); |
|---|
| 509 | } |
|---|
| 510 | |
|---|
| 511 | NS_IMETHODIMP |
|---|
| 512 | nsLocalFile::AppendRelativeNativePath(const nsACString &fragment) |
|---|
| 513 | { |
|---|
| 514 | if (fragment.IsEmpty()) |
|---|
| 515 | return NS_OK; |
|---|
| 516 | |
|---|
| 517 | // No leading '/' |
|---|
| 518 | if (fragment.First() == '/') |
|---|
| 519 | return NS_ERROR_FILE_UNRECOGNIZED_PATH; |
|---|
| 520 | |
|---|
| 521 | if (mPath.EqualsLiteral("/")) |
|---|
| 522 | mPath.Append(fragment); |
|---|
| 523 | else |
|---|
| 524 | mPath.Append(NS_LITERAL_CSTRING("/") + fragment); |
|---|
| 525 | |
|---|
| 526 | InvalidateCache(); |
|---|
| 527 | return NS_OK; |
|---|
| 528 | } |
|---|
| 529 | |
|---|
| 530 | NS_IMETHODIMP |
|---|
| 531 | nsLocalFile::Normalize() |
|---|
| 532 | { |
|---|
| 533 | char resolved_path[PATH_MAX] = ""; |
|---|
| 534 | char *resolved_path_ptr = nsnull; |
|---|
| 535 | |
|---|
| 536 | #ifdef XP_BEOS |
|---|
| 537 | BEntry be_e(mPath.get(), true); |
|---|
| 538 | BPath be_p; |
|---|
| 539 | status_t err; |
|---|
| 540 | if ((err = be_e.GetPath(&be_p)) == B_OK) { |
|---|
| 541 | resolved_path_ptr = (char *)be_p.Path(); |
|---|
| 542 | PL_strncpyz(resolved_path, resolved_path_ptr, PATH_MAX - 1); |
|---|
| 543 | } |
|---|
| 544 | #else |
|---|
| 545 | resolved_path_ptr = realpath(mPath.get(), resolved_path); |
|---|
| 546 | #endif |
|---|
| 547 | // if there is an error, the return is null. |
|---|
| 548 | if (!resolved_path_ptr) |
|---|
| 549 | return NSRESULT_FOR_ERRNO(); |
|---|
| 550 | |
|---|
| 551 | mPath = resolved_path; |
|---|
| 552 | return NS_OK; |
|---|
| 553 | } |
|---|
| 554 | |
|---|
| 555 | void |
|---|
| 556 | nsLocalFile::LocateNativeLeafName(nsACString::const_iterator &begin, |
|---|
| 557 | nsACString::const_iterator &end) |
|---|
| 558 | { |
|---|
| 559 | // XXX perhaps we should cache this?? |
|---|
| 560 | |
|---|
| 561 | mPath.BeginReading(begin); |
|---|
| 562 | mPath.EndReading(end); |
|---|
| 563 | |
|---|
| 564 | nsACString::const_iterator it = end; |
|---|
| 565 | nsACString::const_iterator stop = begin; |
|---|
| 566 | --stop; |
|---|
| 567 | while (--it != stop) { |
|---|
| 568 | if (*it == '/') { |
|---|
| 569 | begin = ++it; |
|---|
| 570 | return; |
|---|
| 571 | } |
|---|
| 572 | } |
|---|
| 573 | // else, the entire path is the leaf name (which means this |
|---|
| 574 | // isn't an absolute path... unexpected??) |
|---|
| 575 | } |
|---|
| 576 | |
|---|
| 577 | NS_IMETHODIMP |
|---|
| 578 | nsLocalFile::GetNativeLeafName(nsACString &aLeafName) |
|---|
| 579 | { |
|---|
| 580 | nsACString::const_iterator begin, end; |
|---|
| 581 | LocateNativeLeafName(begin, end); |
|---|
| 582 | aLeafName = Substring(begin, end); |
|---|
| 583 | return NS_OK; |
|---|
| 584 | } |
|---|
| 585 | |
|---|
| 586 | NS_IMETHODIMP |
|---|
| 587 | nsLocalFile::SetNativeLeafName(const nsACString &aLeafName) |
|---|
| 588 | { |
|---|
| 589 | nsACString::const_iterator begin, end; |
|---|
| 590 | LocateNativeLeafName(begin, end); |
|---|
| 591 | mPath.Replace(begin.get() - mPath.get(), Distance(begin, end), aLeafName); |
|---|
| 592 | InvalidateCache(); |
|---|
| 593 | return NS_OK; |
|---|
| 594 | } |
|---|
| 595 | |
|---|
| 596 | NS_IMETHODIMP |
|---|
| 597 | nsLocalFile::GetNativePath(nsACString &_retval) |
|---|
| 598 | { |
|---|
| 599 | _retval = mPath; |
|---|
| 600 | return NS_OK; |
|---|
| 601 | } |
|---|
| 602 | |
|---|
| 603 | nsresult |
|---|
| 604 | nsLocalFile::GetNativeTargetPathName(nsIFile *newParent, |
|---|
| 605 | const nsACString &newName, |
|---|
| 606 | nsACString &_retval) |
|---|
| 607 | { |
|---|
| 608 | nsresult rv; |
|---|
| 609 | nsCOMPtr<nsIFile> oldParent; |
|---|
| 610 | |
|---|
| 611 | if (!newParent) { |
|---|
| 612 | if (NS_FAILED(rv = GetParent(getter_AddRefs(oldParent)))) |
|---|
| 613 | return rv; |
|---|
| 614 | newParent = oldParent.get(); |
|---|
| 615 | } else { |
|---|
| 616 | // check to see if our target directory exists |
|---|
| 617 | PRBool targetExists; |
|---|
| 618 | if (NS_FAILED(rv = newParent->Exists(&targetExists))) |
|---|
| 619 | return rv; |
|---|
| 620 | |
|---|
| 621 | if (!targetExists) { |
|---|
| 622 | // XXX create the new directory with some permissions |
|---|
| 623 | rv = newParent->Create(DIRECTORY_TYPE, 0755); |
|---|
| 624 | if (NS_FAILED(rv)) |
|---|
| 625 | return rv; |
|---|
| 626 | } else { |
|---|
| 627 | // make sure that the target is actually a directory |
|---|
| 628 | PRBool targetIsDirectory; |
|---|
| 629 | if (NS_FAILED(rv = newParent->IsDirectory(&targetIsDirectory))) |
|---|
| 630 | return rv; |
|---|
| 631 | if (!targetIsDirectory) |
|---|
| 632 | return NS_ERROR_FILE_DESTINATION_NOT_DIR; |
|---|
| 633 | } |
|---|
| 634 | } |
|---|
| 635 | |
|---|
| 636 | nsACString::const_iterator nameBegin, nameEnd; |
|---|
| 637 | if (!newName.IsEmpty()) { |
|---|
| 638 | newName.BeginReading(nameBegin); |
|---|
| 639 | newName.EndReading(nameEnd); |
|---|
| 640 | } |
|---|
| 641 | else |
|---|
| 642 | LocateNativeLeafName(nameBegin, nameEnd); |
|---|
| 643 | |
|---|
| 644 | nsCAutoString dirName; |
|---|
| 645 | if (NS_FAILED(rv = newParent->GetNativePath(dirName))) |
|---|
| 646 | return rv; |
|---|
| 647 | |
|---|
| 648 | _retval = dirName |
|---|
| 649 | + NS_LITERAL_CSTRING("/") |
|---|
| 650 | + Substring(nameBegin, nameEnd); |
|---|
| 651 | return NS_OK; |
|---|
| 652 | } |
|---|
| 653 | |
|---|
| 654 | nsresult |
|---|
| 655 | nsLocalFile::CopyDirectoryTo(nsIFile *newParent) |
|---|
| 656 | { |
|---|
| 657 | nsresult rv; |
|---|
| 658 | /* |
|---|
| 659 | * dirCheck is used for various boolean test results such as from Equals, |
|---|
| 660 | * Exists, isDir, etc. |
|---|
| 661 | */ |
|---|
| 662 | PRBool dirCheck, isSymlink; |
|---|
| 663 | PRUint32 oldPerms; |
|---|
| 664 | |
|---|
| 665 | if (NS_FAILED(rv = IsDirectory(&dirCheck))) |
|---|
| 666 | return rv; |
|---|
| 667 | if (!dirCheck) |
|---|
| 668 | return CopyToNative(newParent, EmptyCString()); |
|---|
| 669 | |
|---|
| 670 | if (NS_FAILED(rv = Equals(newParent, &dirCheck))) |
|---|
| 671 | return rv; |
|---|
| 672 | if (dirCheck) { |
|---|
| 673 | // can't copy dir to itself |
|---|
| 674 | return NS_ERROR_INVALID_ARG; |
|---|
| 675 | } |
|---|
| 676 | |
|---|
| 677 | if (NS_FAILED(rv = newParent->Exists(&dirCheck))) |
|---|
| 678 | return rv; |
|---|
| 679 | // get the dirs old permissions |
|---|
| 680 | if (NS_FAILED(rv = GetPermissions(&oldPerms))) |
|---|
| 681 | return rv; |
|---|
| 682 | if (!dirCheck) { |
|---|
| 683 | if (NS_FAILED(rv = newParent->Create(DIRECTORY_TYPE, oldPerms))) |
|---|
| 684 | return rv; |
|---|
| 685 | } else { // dir exists lets try to use leaf |
|---|
| 686 | nsCAutoString leafName; |
|---|
| 687 | if (NS_FAILED(rv = GetNativeLeafName(leafName))) |
|---|
| 688 | return rv; |
|---|
| 689 | if (NS_FAILED(rv = newParent->AppendNative(leafName))) |
|---|
| 690 | return rv; |
|---|
| 691 | if (NS_FAILED(rv = newParent->Exists(&dirCheck))) |
|---|
| 692 | return rv; |
|---|
| 693 | if (dirCheck) |
|---|
| 694 | return NS_ERROR_FILE_ALREADY_EXISTS; // dest exists |
|---|
| 695 | if (NS_FAILED(rv = newParent->Create(DIRECTORY_TYPE, oldPerms))) |
|---|
| 696 | return rv; |
|---|
| 697 | } |
|---|
| 698 | |
|---|
| 699 | nsCOMPtr<nsISimpleEnumerator> dirIterator; |
|---|
| 700 | if (NS_FAILED(rv = GetDirectoryEntries(getter_AddRefs(dirIterator)))) |
|---|
| 701 | return rv; |
|---|
| 702 | |
|---|
| 703 | PRBool hasMore = PR_FALSE; |
|---|
| 704 | while (dirIterator->HasMoreElements(&hasMore), hasMore) { |
|---|
| 705 | nsCOMPtr<nsIFile> entry; |
|---|
| 706 | rv = dirIterator->GetNext((nsISupports**)getter_AddRefs(entry)); |
|---|
| 707 | if (NS_FAILED(rv)) |
|---|
| 708 | continue; |
|---|
| 709 | if (NS_FAILED(rv = entry->IsSymlink(&isSymlink))) |
|---|
| 710 | return rv; |
|---|
| 711 | if (NS_FAILED(rv = entry->IsDirectory(&dirCheck))) |
|---|
| 712 | return rv; |
|---|
| 713 | if (dirCheck && !isSymlink) { |
|---|
| 714 | nsCOMPtr<nsIFile> destClone; |
|---|
| 715 | rv = newParent->Clone(getter_AddRefs(destClone)); |
|---|
| 716 | if (NS_SUCCEEDED(rv)) { |
|---|
| 717 | nsCOMPtr<nsILocalFile> newDir(do_QueryInterface(destClone)); |
|---|
| 718 | if (NS_FAILED(rv = entry->CopyToNative(newDir, EmptyCString()))) { |
|---|
| 719 | #ifdef DEBUG |
|---|
| 720 | nsresult rv2; |
|---|
| 721 | nsCAutoString pathName; |
|---|
| 722 | if (NS_FAILED(rv2 = entry->GetNativePath(pathName))) |
|---|
| 723 | return rv2; |
|---|
| 724 | printf("Operation not supported: %s\n", pathName.get()); |
|---|
| 725 | #endif |
|---|
| 726 | if (rv == NS_ERROR_OUT_OF_MEMORY) |
|---|
| 727 | return rv; |
|---|
| 728 | continue; |
|---|
| 729 | } |
|---|
| 730 | } |
|---|
| 731 | } else { |
|---|
| 732 | if (NS_FAILED(rv = entry->CopyToNative(newParent, EmptyCString()))) { |
|---|
| 733 | #ifdef DEBUG |
|---|
| 734 | nsresult rv2; |
|---|
| 735 | nsCAutoString pathName; |
|---|
| 736 | if (NS_FAILED(rv2 = entry->GetNativePath(pathName))) |
|---|
| 737 | return rv2; |
|---|
| 738 | printf("Operation not supported: %s\n", pathName.get()); |
|---|
| 739 | #endif |
|---|
| 740 | if (rv == NS_ERROR_OUT_OF_MEMORY) |
|---|
| 741 | return rv; |
|---|
| 742 | continue; |
|---|
| 743 | } |
|---|
| 744 | } |
|---|
| 745 | } |
|---|
| 746 | return NS_OK; |
|---|
| 747 | } |
|---|
| 748 | |
|---|
| 749 | NS_IMETHODIMP |
|---|
| 750 | nsLocalFile::CopyToNative(nsIFile *newParent, const nsACString &newName) |
|---|
| 751 | { |
|---|
| 752 | nsresult rv; |
|---|
| 753 | // check to make sure that this has been initialized properly |
|---|
| 754 | CHECK_mPath(); |
|---|
| 755 | |
|---|
| 756 | // we copy the parent here so 'newParent' remains immutable |
|---|
| 757 | nsCOMPtr <nsIFile> workParent; |
|---|
| 758 | if (newParent) { |
|---|
| 759 | if (NS_FAILED(rv = newParent->Clone(getter_AddRefs(workParent)))) |
|---|
| 760 | return rv; |
|---|
| 761 | } else { |
|---|
| 762 | if (NS_FAILED(rv = GetParent(getter_AddRefs(workParent)))) |
|---|
| 763 | return rv; |
|---|
| 764 | } |
|---|
| 765 | |
|---|
| 766 | // check to see if we are a directory or if we are a file |
|---|
| 767 | PRBool isDirectory; |
|---|
| 768 | if (NS_FAILED(rv = IsDirectory(&isDirectory))) |
|---|
| 769 | return rv; |
|---|
| 770 | |
|---|
| 771 | nsCAutoString newPathName; |
|---|
| 772 | if (isDirectory) { |
|---|
| 773 | if (!newName.IsEmpty()) { |
|---|
| 774 | if (NS_FAILED(rv = workParent->AppendNative(newName))) |
|---|
| 775 | return rv; |
|---|
| 776 | } else { |
|---|
| 777 | if (NS_FAILED(rv = GetNativeLeafName(newPathName))) |
|---|
| 778 | return rv; |
|---|
| 779 | if (NS_FAILED(rv = workParent->AppendNative(newPathName))) |
|---|
| 780 | return rv; |
|---|
| 781 | } |
|---|
| 782 | if (NS_FAILED(rv = CopyDirectoryTo(workParent))) |
|---|
| 783 | return rv; |
|---|
| 784 | } else { |
|---|
| 785 | rv = GetNativeTargetPathName(workParent, newName, newPathName); |
|---|
| 786 | if (NS_FAILED(rv)) |
|---|
| 787 | return rv; |
|---|
| 788 | |
|---|
| 789 | #ifdef DEBUG_blizzard |
|---|
| 790 | printf("nsLocalFile::CopyTo() %s -> %s\n", mPath.get(), newPathName.get()); |
|---|
| 791 | #endif |
|---|
| 792 | |
|---|
| 793 | // actually create the file. |
|---|
| 794 | nsLocalFile *newFile = new nsLocalFile(); |
|---|
| 795 | if (!newFile) |
|---|
| 796 | return NS_ERROR_OUT_OF_MEMORY; |
|---|
| 797 | |
|---|
| 798 | nsCOMPtr<nsILocalFile> fileRef(newFile); // release on exit |
|---|
| 799 | |
|---|
| 800 | rv = newFile->InitWithNativePath(newPathName); |
|---|
| 801 | if (NS_FAILED(rv)) |
|---|
| 802 | return rv; |
|---|
| 803 | |
|---|
| 804 | // get the old permissions |
|---|
| 805 | PRUint32 myPerms; |
|---|
| 806 | GetPermissions(&myPerms); |
|---|
| 807 | |
|---|
| 808 | // Create the new file with the old file's permissions, even if write |
|---|
| 809 | // permission is missing. We can't create with write permission and |
|---|
| 810 | // then change back to myPerm on all filesystems (FAT on Linux, e.g.). |
|---|
| 811 | // But we can write to a read-only file on all Unix filesystems if we |
|---|
| 812 | // open it successfully for writing. |
|---|
| 813 | |
|---|
| 814 | PRFileDesc *newFD; |
|---|
| 815 | rv = newFile->CreateAndKeepOpen(NORMAL_FILE_TYPE, |
|---|
| 816 | PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE, |
|---|
| 817 | myPerms, |
|---|
| 818 | &newFD); |
|---|
| 819 | if (NS_FAILED(rv)) |
|---|
| 820 | return rv; |
|---|
| 821 | |
|---|
| 822 | // open the old file, too |
|---|
| 823 | PRBool specialFile; |
|---|
| 824 | if (NS_FAILED(rv = IsSpecial(&specialFile))) { |
|---|
| 825 | PR_Close(newFD); |
|---|
| 826 | return rv; |
|---|
| 827 | } |
|---|
| 828 | if (specialFile) { |
|---|
| 829 | #ifdef DEBUG |
|---|
| 830 | printf("Operation not supported: %s\n", mPath.get()); |
|---|
| 831 | #endif |
|---|
| 832 | // make sure to clean up properly |
|---|
| 833 | PR_Close(newFD); |
|---|
| 834 | return NS_OK; |
|---|
| 835 | } |
|---|
| 836 | |
|---|
| 837 | PRFileDesc *oldFD; |
|---|
| 838 | rv = OpenNSPRFileDesc(PR_RDONLY, myPerms, &oldFD); |
|---|
| 839 | if (NS_FAILED(rv)) { |
|---|
| 840 | // make sure to clean up properly |
|---|
| 841 | PR_Close(newFD); |
|---|
| 842 | return rv; |
|---|
| 843 | } |
|---|
| 844 | |
|---|
| 845 | #ifdef DEBUG_blizzard |
|---|
| 846 | PRInt32 totalRead = 0; |
|---|
| 847 | PRInt32 totalWritten = 0; |
|---|
| 848 | #endif |
|---|
| 849 | char buf[BUFSIZ]; |
|---|
| 850 | PRInt32 bytesRead; |
|---|
| 851 | |
|---|
| 852 | while ((bytesRead = PR_Read(oldFD, buf, BUFSIZ)) > 0) { |
|---|
| 853 | #ifdef DEBUG_blizzard |
|---|
| 854 | totalRead += bytesRead; |
|---|
| 855 | #endif |
|---|
| 856 | |
|---|
| 857 | // PR_Write promises never to do a short write |
|---|
| 858 | PRInt32 bytesWritten = PR_Write(newFD, buf, bytesRead); |
|---|
| 859 | if (bytesWritten < 0) { |
|---|
| 860 | bytesRead = -1; |
|---|
| 861 | break; |
|---|
| 862 | } |
|---|
| 863 | NS_ASSERTION(bytesWritten == bytesRead, "short PR_Write?"); |
|---|
| 864 | |
|---|
| 865 | #ifdef DEBUG_blizzard |
|---|
| 866 | totalWritten += bytesWritten; |
|---|
| 867 | #endif |
|---|
| 868 | } |
|---|
| 869 | |
|---|
| 870 | #ifdef DEBUG_blizzard |
|---|
| 871 | printf("read %d bytes, wrote %d bytes\n", |
|---|
| 872 | totalRead, totalWritten); |
|---|
| 873 | #endif |
|---|
| 874 | |
|---|
| 875 | // close the files |
|---|
| 876 | PR_Close(newFD); |
|---|
| 877 | PR_Close(oldFD); |
|---|
| 878 | |
|---|
| 879 | // check for read (or write) error after cleaning up |
|---|
| 880 | if (bytesRead < 0) |
|---|
| 881 | return NS_ERROR_OUT_OF_MEMORY; |
|---|
| 882 | } |
|---|
| 883 | return rv; |
|---|
| 884 | } |
|---|
| 885 | |
|---|
| 886 | NS_IMETHODIMP |
|---|
| 887 | nsLocalFile::CopyToFollowingLinksNative(nsIFile *newParent, const nsACString &newName) |
|---|
| 888 | { |
|---|
| 889 | return CopyToNative(newParent, newName); |
|---|
| 890 | } |
|---|
| 891 | |
|---|
| 892 | NS_IMETHODIMP |
|---|
| 893 | nsLocalFile::MoveToNative(nsIFile *newParent, const nsACString &newName) |
|---|
| 894 | { |
|---|
| 895 | nsresult rv; |
|---|
| 896 | |
|---|
| 897 | // check to make sure that this has been initialized properly |
|---|
| 898 | CHECK_mPath(); |
|---|
| 899 | |
|---|
| 900 | // check to make sure that we have a new parent |
|---|
| 901 | nsCAutoString newPathName; |
|---|
| 902 | rv = GetNativeTargetPathName(newParent, newName, newPathName); |
|---|
| 903 | if (NS_FAILED(rv)) |
|---|
| 904 | return rv; |
|---|
| 905 | |
|---|
| 906 | // try for atomic rename, falling back to copy/delete |
|---|
| 907 | if (rename(mPath.get(), newPathName.get()) < 0) { |
|---|
| 908 | #ifdef VMS |
|---|
| 909 | if (errno == EXDEV || errno == ENXIO) { |
|---|
| 910 | #else |
|---|
| 911 | if (errno == EXDEV) { |
|---|
| 912 | #endif |
|---|
| 913 | rv = CopyToNative(newParent, newName); |
|---|
| 914 | if (NS_SUCCEEDED(rv)) |
|---|
| 915 | rv = Remove(PR_TRUE); |
|---|
| 916 | } else { |
|---|
| 917 | rv = NSRESULT_FOR_ERRNO(); |
|---|
| 918 | } |
|---|
| 919 | } |
|---|
| 920 | return rv; |
|---|
| 921 | } |
|---|
| 922 | |
|---|
| 923 | NS_IMETHODIMP |
|---|
| 924 | nsLocalFile::Remove(PRBool recursive) |
|---|
| 925 | { |
|---|
| 926 | CHECK_mPath(); |
|---|
| 927 | |
|---|
| 928 | VALIDATE_STAT_CACHE(); |
|---|
| 929 | PRBool isSymLink, isDir; |
|---|
| 930 | |
|---|
| 931 | nsresult rv = IsSymlink(&isSymLink); |
|---|
| 932 | if (NS_FAILED(rv)) |
|---|
| 933 | return rv; |
|---|
| 934 | |
|---|
| 935 | if (!recursive && isSymLink) |
|---|
| 936 | return NSRESULT_FOR_RETURN(unlink(mPath.get())); |
|---|
| 937 | |
|---|
| 938 | isDir = S_ISDIR(mCachedStat.st_mode); |
|---|
| 939 | InvalidateCache(); |
|---|
| 940 | if (isDir) { |
|---|
| 941 | if (recursive) { |
|---|
| 942 | nsDirEnumeratorUnix *dir = new nsDirEnumeratorUnix(); |
|---|
| 943 | if (!dir) |
|---|
| 944 | return NS_ERROR_OUT_OF_MEMORY; |
|---|
| 945 | |
|---|
| 946 | nsCOMPtr<nsISimpleEnumerator> dirRef(dir); // release on exit |
|---|
| 947 | |
|---|
| 948 | rv = dir->Init(this, PR_FALSE); |
|---|
| 949 | if (NS_FAILED(rv)) |
|---|
| 950 | return rv; |
|---|
| 951 | |
|---|
| 952 | PRBool more; |
|---|
| 953 | while (dir->HasMoreElements(&more), more) { |
|---|
| 954 | nsCOMPtr<nsISupports> item; |
|---|
| 955 | rv = dir->GetNext(getter_AddRefs(item)); |
|---|
| 956 | if (NS_FAILED(rv)) |
|---|
| 957 | return NS_ERROR_FAILURE; |
|---|
| 958 | |
|---|
| 959 | nsCOMPtr<nsIFile> file = do_QueryInterface(item, &rv); |
|---|
| 960 | if (NS_FAILED(rv)) |
|---|
| 961 | return NS_ERROR_FAILURE; |
|---|
| 962 | if (NS_FAILED(rv = file->Remove(recursive))) |
|---|
| 963 | return rv; |
|---|
| 964 | } |
|---|
| 965 | } |
|---|
| 966 | |
|---|
| 967 | if (rmdir(mPath.get()) == -1) |
|---|
| 968 | return NSRESULT_FOR_ERRNO(); |
|---|
| 969 | } else { |
|---|
| 970 | if (unlink(mPath.get()) == -1) |
|---|
| 971 | return NSRESULT_FOR_ERRNO(); |
|---|
| 972 | } |
|---|
| 973 | |
|---|
| 974 | return NS_OK; |
|---|
| 975 | } |
|---|
| 976 | |
|---|
| 977 | NS_IMETHODIMP |
|---|
| 978 | nsLocalFile::GetLastModifiedTime(PRInt64 *aLastModTime) |
|---|
| 979 | { |
|---|
| 980 | CHECK_mPath(); |
|---|
| 981 | NS_ENSURE_ARG(aLastModTime); |
|---|
| 982 | |
|---|
| 983 | PRFileInfo64 info; |
|---|
| 984 | if (PR_GetFileInfo64(mPath.get(), &info) != PR_SUCCESS) |
|---|
| 985 | return NSRESULT_FOR_ERRNO(); |
|---|
| 986 | |
|---|
| 987 | // PRTime is a 64 bit value |
|---|
| 988 | // microseconds -> milliseconds |
|---|
| 989 | PRInt64 usecPerMsec; |
|---|
| 990 | LL_I2L(usecPerMsec, PR_USEC_PER_MSEC); |
|---|
| 991 | LL_DIV(*aLastModTime, info.modifyTime, usecPerMsec); |
|---|
| 992 | return NS_OK; |
|---|
| 993 | } |
|---|
| 994 | |
|---|
| 995 | NS_IMETHODIMP |
|---|
| 996 | nsLocalFile::SetLastModifiedTime(PRInt64 aLastModTime) |
|---|
| 997 | { |
|---|
| 998 | CHECK_mPath(); |
|---|
| 999 | |
|---|
| 1000 | int result; |
|---|
| 1001 | if (! LL_IS_ZERO(aLastModTime)) { |
|---|
| 1002 | VALIDATE_STAT_CACHE(); |
|---|
| 1003 | struct utimbuf ut; |
|---|
| 1004 | ut.actime = mCachedStat.st_atime; |
|---|
| 1005 | |
|---|
| 1006 | // convert milliseconds to seconds since the unix epoch |
|---|
| 1007 | double dTime; |
|---|
| 1008 | LL_L2D(dTime, aLastModTime); |
|---|
| 1009 | ut.modtime = (time_t) (dTime / PR_MSEC_PER_SEC); |
|---|
| 1010 | result = utime(mPath.get(), &ut); |
|---|
| 1011 | } else { |
|---|
| 1012 | result = utime(mPath.get(), nsnull); |
|---|
| 1013 | } |
|---|
| 1014 | InvalidateCache(); |
|---|
| 1015 | return NSRESULT_FOR_RETURN(result); |
|---|
| 1016 | } |
|---|
| 1017 | |
|---|
| 1018 | NS_IMETHODIMP |
|---|
| 1019 | nsLocalFile::GetLastModifiedTimeOfLink(PRInt64 *aLastModTimeOfLink) |
|---|
| 1020 | { |
|---|
| 1021 | CHECK_mPath(); |
|---|
| 1022 | NS_ENSURE_ARG(aLastModTimeOfLink); |
|---|
| 1023 | |
|---|
| 1024 | struct stat sbuf; |
|---|
| 1025 | if (lstat(mPath.get(), &sbuf) == -1) |
|---|
| 1026 | return NSRESULT_FOR_ERRNO(); |
|---|
| 1027 | LL_I2L(*aLastModTimeOfLink, (PRInt32)sbuf.st_mtime); |
|---|
| 1028 | |
|---|
| 1029 | // lstat returns st_mtime in seconds |
|---|
| 1030 | PRInt64 msecPerSec; |
|---|
| 1031 | LL_I2L(msecPerSec, PR_MSEC_PER_SEC); |
|---|
| 1032 | LL_MUL(*aLastModTimeOfLink, *aLastModTimeOfLink, msecPerSec); |
|---|
| 1033 | |
|---|
| 1034 | return NS_OK; |
|---|
| 1035 | } |
|---|
| 1036 | |
|---|
| 1037 | /* |
|---|
| 1038 | * utime(2) may or may not dereference symlinks, joy. |
|---|
| 1039 | */ |
|---|
| 1040 | NS_IMETHODIMP |
|---|
| 1041 | nsLocalFile::SetLastModifiedTimeOfLink(PRInt64 aLastModTimeOfLink) |
|---|
| 1042 | { |
|---|
| 1043 | return SetLastModifiedTime(aLastModTimeOfLink); |
|---|
| 1044 | } |
|---|
| 1045 | |
|---|
| 1046 | /* |
|---|
| 1047 | * Only send back permissions bits: maybe we want to send back the whole |
|---|
| 1048 | * mode_t to permit checks against other file types? |
|---|
| 1049 | */ |
|---|
| 1050 | |
|---|
| 1051 | #define NORMALIZE_PERMS(mode) ((mode)& (S_IRWXU | S_IRWXG | S_IRWXO)) |
|---|
| 1052 | |
|---|
| 1053 | NS_IMETHODIMP |
|---|
| 1054 | nsLocalFile::GetPermissions(PRUint32 *aPermissions) |
|---|
| 1055 | { |
|---|
| 1056 | NS_ENSURE_ARG(aPermissions); |
|---|
| 1057 | VALIDATE_STAT_CACHE(); |
|---|
| 1058 | *aPermissions = NORMALIZE_PERMS(mCachedStat.st_mode); |
|---|
| 1059 | return NS_OK; |
|---|
| 1060 | } |
|---|
| 1061 | |
|---|
| 1062 | NS_IMETHODIMP |
|---|
| 1063 | nsLocalFile::GetPermissionsOfLink(PRUint32 *aPermissionsOfLink) |
|---|
| 1064 | { |
|---|
| 1065 | CHECK_mPath(); |
|---|
| 1066 | NS_ENSURE_ARG(aPermissionsOfLink); |
|---|
| 1067 | |
|---|
| 1068 | struct stat sbuf; |
|---|
| 1069 | if (lstat(mPath.get(), &sbuf) == -1) |
|---|
| 1070 | return NSRESULT_FOR_ERRNO(); |
|---|
| 1071 | *aPermissionsOfLink = NORMALIZE_PERMS(sbuf.st_mode); |
|---|
| 1072 | return NS_OK; |
|---|
| 1073 | } |
|---|
| 1074 | |
|---|
| 1075 | NS_IMETHODIMP |
|---|
| 1076 | nsLocalFile::SetPermissions(PRUint32 aPermissions) |
|---|
| 1077 | { |
|---|
| 1078 | CHECK_mPath(); |
|---|
| 1079 | |
|---|
| 1080 | InvalidateCache(); |
|---|
| 1081 | |
|---|
| 1082 | /* |
|---|
| 1083 | * Race condition here: we should use fchmod instead, there's no way to |
|---|
| 1084 | * guarantee the name still refers to the same file. |
|---|
| 1085 | */ |
|---|
| 1086 | if (chmod(mPath.get(), aPermissions) < 0) |
|---|
| 1087 | return NSRESULT_FOR_ERRNO(); |
|---|
| 1088 | return NS_OK; |
|---|
| 1089 | } |
|---|
| 1090 | |
|---|
| 1091 | NS_IMETHODIMP |
|---|
| 1092 | nsLocalFile::SetPermissionsOfLink(PRUint32 aPermissions) |
|---|
| 1093 | { |
|---|
| 1094 | return SetPermissions(aPermissions); |
|---|
| 1095 | } |
|---|
| 1096 | |
|---|
| 1097 | NS_IMETHODIMP |
|---|
| 1098 | nsLocalFile::GetFileSize(PRInt64 *aFileSize) |
|---|
| 1099 | { |
|---|
| 1100 | NS_ENSURE_ARG_POINTER(aFileSize); |
|---|
| 1101 | *aFileSize = LL_ZERO; |
|---|
| 1102 | VALIDATE_STAT_CACHE(); |
|---|
| 1103 | |
|---|
| 1104 | #if defined(VMS) |
|---|
| 1105 | /* Only two record formats can report correct file content size */ |
|---|
| 1106 | if ((mCachedStat.st_fab_rfm != FAB$C_STMLF) && |
|---|
| 1107 | (mCachedStat.st_fab_rfm != FAB$C_STMCR)) { |
|---|
| 1108 | return NS_ERROR_FAILURE; |
|---|
| 1109 | } |
|---|
| 1110 | #endif |
|---|
| 1111 | |
|---|
| 1112 | /* XXX autoconf for and use stat64 if available */ |
|---|
| 1113 | if (!S_ISDIR(mCachedStat.st_mode)) { |
|---|
| 1114 | LL_UI2L(*aFileSize, (PRUint32)mCachedStat.st_size); |
|---|
| 1115 | } |
|---|
| 1116 | return NS_OK; |
|---|
| 1117 | } |
|---|
| 1118 | |
|---|
| 1119 | NS_IMETHODIMP |
|---|
| 1120 | nsLocalFile::SetFileSize(PRInt64 aFileSize) |
|---|
| 1121 | { |
|---|
| 1122 | CHECK_mPath(); |
|---|
| 1123 | |
|---|
| 1124 | PRInt32 size; |
|---|
| 1125 | LL_L2I(size, aFileSize); |
|---|
| 1126 | /* XXX truncate64? */ |
|---|
| 1127 | InvalidateCache(); |
|---|
| 1128 | if (truncate(mPath.get(), (off_t)size) == -1) |
|---|
| 1129 | return NSRESULT_FOR_ERRNO(); |
|---|
| 1130 | return NS_OK; |
|---|
| 1131 | } |
|---|
| 1132 | |
|---|
| 1133 | NS_IMETHODIMP |
|---|
| 1134 | nsLocalFile::GetFileSizeOfLink(PRInt64 *aFileSize) |
|---|
| 1135 | { |
|---|
| 1136 | CHECK_mPath(); |
|---|
| 1137 | NS_ENSURE_ARG(aFileSize); |
|---|
| 1138 | |
|---|
| 1139 | struct stat sbuf; |
|---|
| 1140 | if (lstat(mPath.get(), &sbuf) == -1) |
|---|
| 1141 | return NSRESULT_FOR_ERRNO(); |
|---|
| 1142 | /* XXX autoconf for and use lstat64 if available */ |
|---|
| 1143 | LL_UI2L(*aFileSize, (PRUint32)sbuf.st_size); |
|---|
| 1144 | return NS_OK; |
|---|
| 1145 | } |
|---|
| 1146 | |
|---|
| 1147 | NS_IMETHODIMP |
|---|
| 1148 | nsLocalFile::GetDiskSpaceAvailable(PRInt64 *aDiskSpaceAvailable) |
|---|
| 1149 | { |
|---|
| 1150 | NS_ENSURE_ARG_POINTER(aDiskSpaceAvailable); |
|---|
| 1151 | |
|---|
| 1152 | // These systems have the operations necessary to check disk space. |
|---|
| 1153 | |
|---|
| 1154 | #if defined(HAVE_SYS_STATFS_H) || defined(HAVE_SYS_STATVFS_H) |
|---|
| 1155 | |
|---|
| 1156 | // check to make sure that mPath is properly initialized |
|---|
| 1157 | CHECK_mPath(); |
|---|
| 1158 | |
|---|
| 1159 | struct STATFS fs_buf; |
|---|
| 1160 | |
|---|
| 1161 | /* |
|---|
| 1162 | * Members of the STATFS struct that you should know about: |
|---|
| 1163 | * f_bsize = block size on disk. |
|---|
| 1164 | * f_bavail = number of free blocks available to a non-superuser. |
|---|
| 1165 | * f_bfree = number of total free blocks in file system. |
|---|
| 1166 | */ |
|---|
| 1167 | |
|---|
| 1168 | if (STATFS(mPath.get(), &fs_buf) < 0) { |
|---|
| 1169 | // The call to STATFS failed. |
|---|
| 1170 | #ifdef DEBUG |
|---|
| 1171 | printf("ERROR: GetDiskSpaceAvailable: STATFS call FAILED. \n"); |
|---|
| 1172 | #endif |
|---|
| 1173 | return NS_ERROR_FAILURE; |
|---|
| 1174 | } |
|---|
| 1175 | #ifdef DEBUG_DISK_SPACE |
|---|
| 1176 | printf("DiskSpaceAvailable: %d bytes\n", |
|---|
| 1177 | fs_buf.f_bsize * (fs_buf.f_bavail - 1)); |
|---|
| 1178 | #endif |
|---|
| 1179 | |
|---|
| 1180 | /* |
|---|
| 1181 | * The number of bytes free == The number of free blocks available to |
|---|
| 1182 | * a non-superuser, minus one as a fudge factor, multiplied by the size |
|---|
| 1183 | * of the aforementioned blocks. |
|---|
| 1184 | */ |
|---|
| 1185 | PRInt64 bsize, bavail; |
|---|
| 1186 | |
|---|
| 1187 | LL_I2L(bsize, fs_buf.f_bsize); |
|---|
| 1188 | LL_I2L(bavail, fs_buf.f_bavail - 1); |
|---|
| 1189 | LL_MUL(*aDiskSpaceAvailable, bsize, bavail); |
|---|
| 1190 | return NS_OK; |
|---|
| 1191 | |
|---|
| 1192 | #else |
|---|
| 1193 | /* |
|---|
| 1194 | * This platform doesn't have statfs or statvfs. I'm sure that there's |
|---|
| 1195 | * a way to check for free disk space on platforms that don't have statfs |
|---|
| 1196 | * (I'm SURE they have df, for example). |
|---|
| 1197 | * |
|---|
| 1198 | * Until we figure out how to do that, lets be honest and say that this |
|---|
| 1199 | * command isn't implemented properly for these platforms yet. |
|---|
| 1200 | */ |
|---|
| 1201 | #ifdef DEBUG |
|---|
| 1202 | printf("ERROR: GetDiskSpaceAvailable: Not implemented for plaforms without statfs.\n"); |
|---|
| 1203 | #endif |
|---|
| 1204 | return NS_ERROR_NOT_IMPLEMENTED; |
|---|
| 1205 | |
|---|
| 1206 | #endif /* HAVE_SYS_STATFS_H or HAVE_SYS_STATVFS_H */ |
|---|
| 1207 | |
|---|
| 1208 | } |
|---|
| 1209 | |
|---|
| 1210 | NS_IMETHODIMP |
|---|
| 1211 | nsLocalFile::GetParent(nsIFile **aParent) |
|---|
| 1212 | { |
|---|
| 1213 | CHECK_mPath(); |
|---|
| 1214 | NS_ENSURE_ARG_POINTER(aParent); |
|---|
| 1215 | *aParent = nsnull; |
|---|
| 1216 | |
|---|
| 1217 | // if '/' we are at the top of the volume, return null |
|---|
| 1218 | if (mPath.Equals("/")) |
|---|
| 1219 | return NS_OK; |
|---|
| 1220 | |
|---|
| 1221 | // <brendan, after jband> I promise to play nice |
|---|
| 1222 | char *buffer = mPath.BeginWriting(), |
|---|
| 1223 | *slashp = buffer; |
|---|
| 1224 | |
|---|
| 1225 | // find the last significant slash in buffer |
|---|
| 1226 | slashp = strrchr(buffer, '/'); |
|---|
| 1227 | NS_ASSERTION(slashp, "non-canonical mPath?"); |
|---|
| 1228 | if (!slashp) |
|---|
| 1229 | return NS_ERROR_FILE_INVALID_PATH; |
|---|
| 1230 | |
|---|
| 1231 | // for the case where we are at '/' |
|---|
| 1232 | if (slashp == buffer) |
|---|
| 1233 | slashp++; |
|---|
| 1234 | |
|---|
| 1235 | // temporarily terminate buffer at the last significant slash |
|---|
| 1236 | char c = *slashp; |
|---|
| 1237 | *slashp = '\0'; |
|---|
| 1238 | |
|---|
| 1239 | nsCOMPtr<nsILocalFile> localFile; |
|---|
| 1240 | nsresult rv = NS_NewNativeLocalFile(nsDependentCString(buffer), PR_TRUE, |
|---|
| 1241 | getter_AddRefs(localFile)); |
|---|
| 1242 | |
|---|
| 1243 | // make buffer whole again |
|---|
| 1244 | *slashp = c; |
|---|
| 1245 | |
|---|
| 1246 | if (NS_SUCCEEDED(rv) && localFile) |
|---|
| 1247 | rv = CallQueryInterface(localFile, aParent); |
|---|
| 1248 | return rv; |
|---|
| 1249 | } |
|---|
| 1250 | |
|---|
| 1251 | /* |
|---|
| 1252 | * The results of Exists, isWritable and isReadable are not cached. |
|---|
| 1253 | */ |
|---|
| 1254 | |
|---|
| 1255 | |
|---|
| 1256 | #if defined(XP_BEOS) || defined(SOLARIS) |
|---|
| 1257 | // access() is buggy in BeOS POSIX implementation, at least for BFS, using stat() instead |
|---|
| 1258 | // see bug 169506, https://bugzilla.mozilla.org/show_bug.cgi?id=169506 |
|---|
| 1259 | // access() problem also exists in Solaris POSIX implementation |
|---|
| 1260 | // see bug 351595, https://bugzilla.mozilla.org/show_bug.cgi?id=351595 |
|---|
| 1261 | NS_IMETHODIMP |
|---|
| 1262 | nsLocalFile::Exists(PRBool *_retval) |
|---|
| 1263 | { |
|---|
| 1264 | CHECK_mPath(); |
|---|
| 1265 | NS_ENSURE_ARG_POINTER(_retval); |
|---|
| 1266 | struct stat buf; |
|---|
| 1267 | |
|---|
| 1268 | *_retval = (stat(mPath.get(), &buf) == 0); |
|---|
| 1269 | return NS_OK; |
|---|
| 1270 | } |
|---|
| 1271 | |
|---|
| 1272 | NS_IMETHODIMP |
|---|
| 1273 | nsLocalFile::IsWritable(PRBool *_retval) |
|---|
| 1274 | { |
|---|
| 1275 | CHECK_mPath(); |
|---|
| 1276 | NS_ENSURE_ARG_POINTER(_retval); |
|---|
| 1277 | struct stat buf; |
|---|
| 1278 | |
|---|
| 1279 | *_retval = (stat(mPath.get(), &buf) == 0); |
|---|
| 1280 | if (*_retval || errno == EACCES) { |
|---|
| 1281 | *_retval = *_retval && (buf.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH )); |
|---|
| 1282 | return NS_OK; |
|---|
| 1283 | } |
|---|
| 1284 | return NSRESULT_FOR_ERRNO(); |
|---|
| 1285 | } |
|---|
| 1286 | |
|---|
| 1287 | NS_IMETHODIMP |
|---|
| 1288 | nsLocalFile::IsReadable(PRBool *_retval) |
|---|
| 1289 | { |
|---|
| 1290 | CHECK_mPath(); |
|---|
| 1291 | NS_ENSURE_ARG_POINTER(_retval); |
|---|
| 1292 | struct stat buf; |
|---|
| 1293 | |
|---|
| 1294 | *_retval = (stat(mPath.get(), &buf) == 0); |
|---|
| 1295 | if (*_retval || errno == EACCES) { |
|---|
| 1296 | *_retval = *_retval && (buf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH )); |
|---|
| 1297 | return NS_OK; |
|---|
| 1298 | } |
|---|
| 1299 | return NSRESULT_FOR_ERRNO(); |
|---|
| 1300 | } |
|---|
| 1301 | |
|---|
| 1302 | NS_IMETHODIMP |
|---|
| 1303 | nsLocalFile::IsExecutable(PRBool *_retval) |
|---|
| 1304 | { |
|---|
| 1305 | CHECK_mPath(); |
|---|
| 1306 | NS_ENSURE_ARG_POINTER(_retval); |
|---|
| 1307 | struct stat buf; |
|---|
| 1308 | |
|---|
| 1309 | *_retval = (stat(mPath.get(), &buf) == 0); |
|---|
| 1310 | if (*_retval || errno == EACCES) { |
|---|
| 1311 | *_retval = *_retval && (buf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH )); |
|---|
| 1312 | return NS_OK; |
|---|
| 1313 | } |
|---|
| 1314 | return NSRESULT_FOR_ERRNO(); |
|---|
| 1315 | } |
|---|
| 1316 | #else |
|---|
| 1317 | |
|---|
| 1318 | NS_IMETHODIMP |
|---|
| 1319 | nsLocalFile::Exists(PRBool *_retval) |
|---|
| 1320 | { |
|---|
| 1321 | CHECK_mPath(); |
|---|
| 1322 | NS_ENSURE_ARG_POINTER(_retval); |
|---|
| 1323 | |
|---|
| 1324 | *_retval = (access(mPath.get(), F_OK) == 0); |
|---|
| 1325 | return NS_OK; |
|---|
| 1326 | } |
|---|
| 1327 | |
|---|
| 1328 | |
|---|
| 1329 | NS_IMETHODIMP |
|---|
| 1330 | nsLocalFile::IsWritable(PRBool *_retval) |
|---|
| 1331 | { |
|---|
| 1332 | CHECK_mPath(); |
|---|
| 1333 | NS_ENSURE_ARG_POINTER(_retval); |
|---|
| 1334 | |
|---|
| 1335 | *_retval = (access(mPath.get(), W_OK) == 0); |
|---|
| 1336 | if (*_retval || errno == EACCES) |
|---|
| 1337 | return NS_OK; |
|---|
| 1338 | return NSRESULT_FOR_ERRNO(); |
|---|
| 1339 | } |
|---|
| 1340 | |
|---|
| 1341 | NS_IMETHODIMP |
|---|
| 1342 | nsLocalFile::IsReadable(PRBool *_retval) |
|---|
| 1343 | { |
|---|
| 1344 | CHECK_mPath(); |
|---|
| 1345 | NS_ENSURE_ARG_POINTER(_retval); |
|---|
| 1346 | |
|---|
| 1347 | *_retval = (access(mPath.get(), R_OK) == 0); |
|---|
| 1348 | if (*_retval || errno == EACCES) |
|---|
| 1349 | return NS_OK; |
|---|
| 1350 | return NSRESULT_FOR_ERRNO(); |
|---|
| 1351 | } |
|---|
| 1352 | |
|---|
| 1353 | NS_IMETHODIMP |
|---|
| 1354 | nsLocalFile::IsExecutable(PRBool *_retval) |
|---|
| 1355 | { |
|---|
| 1356 | CHECK_mPath(); |
|---|
| 1357 | NS_ENSURE_ARG_POINTER(_retval); |
|---|
| 1358 | |
|---|
| 1359 | *_retval = (access(mPath.get(), X_OK) == 0); |
|---|
| 1360 | if (*_retval || errno == EACCES) |
|---|
| 1361 | return NS_OK; |
|---|
| 1362 | return NSRESULT_FOR_ERRNO(); |
|---|
| 1363 | } |
|---|
| 1364 | #endif |
|---|
| 1365 | NS_IMETHODIMP |
|---|
| 1366 | nsLocalFile::IsDirectory(PRBool *_retval) |
|---|
| 1367 | { |
|---|
| 1368 | NS_ENSURE_ARG_POINTER(_retval); |
|---|
| 1369 | *_retval = PR_FALSE; |
|---|
| 1370 | VALIDATE_STAT_CACHE(); |
|---|
| 1371 | *_retval = S_ISDIR(mCachedStat.st_mode); |
|---|
| 1372 | return NS_OK; |
|---|
| 1373 | } |
|---|
| 1374 | |
|---|
| 1375 | NS_IMETHODIMP |
|---|
| 1376 | nsLocalFile::IsFile(PRBool *_retval) |
|---|
| 1377 | { |
|---|
| 1378 | NS_ENSURE_ARG_POINTER(_retval); |
|---|
| 1379 | *_retval = PR_FALSE; |
|---|
| 1380 | VALIDATE_STAT_CACHE(); |
|---|
| 1381 | *_retval = S_ISREG(mCachedStat.st_mode); |
|---|
| 1382 | return NS_OK; |
|---|
| 1383 | } |
|---|
| 1384 | |
|---|
| 1385 | NS_IMETHODIMP |
|---|
| 1386 | nsLocalFile::IsHidden(PRBool *_retval) |
|---|
| 1387 | { |
|---|
| 1388 | NS_ENSURE_ARG_POINTER(_retval); |
|---|
| 1389 | nsACString::const_iterator begin, end; |
|---|
| 1390 | LocateNativeLeafName(begin, end); |
|---|
| 1391 | *_retval = (*begin == '.'); |
|---|
| 1392 | return NS_OK; |
|---|
| 1393 | } |
|---|
| 1394 | |
|---|
| 1395 | NS_IMETHODIMP |
|---|
| 1396 | nsLocalFile::IsSymlink(PRBool *_retval) |
|---|
| 1397 | { |
|---|
| 1398 | NS_ENSURE_ARG_POINTER(_retval); |
|---|
| 1399 | CHECK_mPath(); |
|---|
| 1400 | |
|---|
| 1401 | struct stat symStat; |
|---|
| 1402 | lstat(mPath.get(), &symStat); |
|---|
| 1403 | *_retval=S_ISLNK(symStat.st_mode); |
|---|
| 1404 | return NS_OK; |
|---|
| 1405 | } |
|---|
| 1406 | |
|---|
| 1407 | NS_IMETHODIMP |
|---|
| 1408 | nsLocalFile::IsSpecial(PRBool *_retval) |
|---|
| 1409 | { |
|---|
| 1410 | NS_ENSURE_ARG_POINTER(_retval); |
|---|
| 1411 | VALIDATE_STAT_CACHE(); |
|---|
| 1412 | *_retval = S_ISCHR(mCachedStat.st_mode) || |
|---|
| 1413 | S_ISBLK(mCachedStat.st_mode) || |
|---|
| 1414 | #ifdef S_ISSOCK |
|---|
| 1415 | S_ISSOCK(mCachedStat.st_mode) || |
|---|
| 1416 | #endif |
|---|
| 1417 | S_ISFIFO(mCachedStat.st_mode); |
|---|
| 1418 | |
|---|
| 1419 | return NS_OK; |
|---|
| 1420 | } |
|---|
| 1421 | |
|---|
| 1422 | NS_IMETHODIMP |
|---|
| 1423 | nsLocalFile::Equals(nsIFile *inFile, PRBool *_retval) |
|---|
| 1424 | { |
|---|
| 1425 | NS_ENSURE_ARG(inFile); |
|---|
| 1426 | NS_ENSURE_ARG_POINTER(_retval); |
|---|
| 1427 | *_retval = PR_FALSE; |
|---|
| 1428 | |
|---|
| 1429 | nsresult rv; |
|---|
| 1430 | nsCAutoString inPath; |
|---|
| 1431 | |
|---|
| 1432 | if (NS_FAILED(rv = inFile->GetNativePath(inPath))) |
|---|
| 1433 | return rv; |
|---|
| 1434 | |
|---|
| 1435 | *_retval = !FILE_STRCMP(inPath.get(), mPath.get()); |
|---|
| 1436 | return NS_OK; |
|---|
| 1437 | } |
|---|
| 1438 | |
|---|
| 1439 | NS_IMETHODIMP |
|---|
| 1440 | nsLocalFile::Contains(nsIFile *inFile, PRBool recur, PRBool *_retval) |
|---|
| 1441 | { |
|---|
| 1442 | CHECK_mPath(); |
|---|
| 1443 | NS_ENSURE_ARG(inFile); |
|---|
| 1444 | NS_ENSURE_ARG_POINTER(_retval); |
|---|
| 1445 | |
|---|
| 1446 | nsCAutoString inPath; |
|---|
| 1447 | nsresult rv; |
|---|
| 1448 | |
|---|
| 1449 | if (NS_FAILED(rv = inFile->GetNativePath(inPath))) |
|---|
| 1450 | return rv; |
|---|
| 1451 | |
|---|
| 1452 | *_retval = PR_FALSE; |
|---|
| 1453 | |
|---|
| 1454 | ssize_t len = mPath.Length(); |
|---|
| 1455 | if (FILE_STRNCMP(mPath.get(), inPath.get(), len) == 0) { |
|---|
| 1456 | // Now make sure that the |inFile|'s path has a separator at len, |
|---|
| 1457 | // which implies that it has more components after len. |
|---|
| 1458 | if (inPath[len] == '/') |
|---|
| 1459 | *_retval = PR_TRUE; |
|---|
| 1460 | } |
|---|
| 1461 | |
|---|
| 1462 | return NS_OK; |
|---|
| 1463 | } |
|---|
| 1464 | |
|---|
| 1465 | NS_IMETHODIMP |
|---|
| 1466 | nsLocalFile::GetNativeTarget(nsACString &_retval) |
|---|
| 1467 | { |
|---|
| 1468 | CHECK_mPath(); |
|---|
| 1469 | _retval.Truncate(); |
|---|
| 1470 | |
|---|
| 1471 | struct stat symStat; |
|---|
| 1472 | lstat(mPath.get(), &symStat); |
|---|
| 1473 | if (!S_ISLNK(symStat.st_mode)) |
|---|
| 1474 | return NS_ERROR_FILE_INVALID_PATH; |
|---|
| 1475 | |
|---|
| 1476 | PRInt64 targetSize64; |
|---|
| 1477 | if (NS_FAILED(GetFileSizeOfLink(&targetSize64))) |
|---|
| 1478 | return NS_ERROR_FAILURE; |
|---|
| 1479 | |
|---|
| 1480 | PRInt32 size; |
|---|
| 1481 | LL_L2I(size, targetSize64); |
|---|
| 1482 | char *target = (char *)nsMemory::Alloc(size + 1); |
|---|
| 1483 | if (!target) |
|---|
| 1484 | return NS_ERROR_OUT_OF_MEMORY; |
|---|
| 1485 | |
|---|
| 1486 | if (readlink(mPath.get(), target, (size_t)size) < 0) { |
|---|
| 1487 | nsMemory::Free(target); |
|---|
| 1488 | return NSRESULT_FOR_ERRNO(); |
|---|
| 1489 | } |
|---|
| 1490 | target[size] = '\0'; |
|---|
| 1491 | |
|---|
| 1492 | nsresult rv; |
|---|
| 1493 | PRBool isSymlink; |
|---|
| 1494 | nsCOMPtr<nsIFile> self(this); |
|---|
| 1495 | nsCOMPtr<nsIFile> parent; |
|---|
| 1496 | while (NS_SUCCEEDED(rv = self->GetParent(getter_AddRefs(parent)))) { |
|---|
| 1497 | NS_ASSERTION(parent != nsnull, "no parent?!"); |
|---|
| 1498 | |
|---|
| 1499 | if (target[0] != '/') { |
|---|
| 1500 | nsCOMPtr<nsILocalFile> localFile(do_QueryInterface(parent, &rv)); |
|---|
| 1501 | if (NS_FAILED(rv)) |
|---|
| 1502 | break; |
|---|
| 1503 | if (NS_FAILED(rv = localFile->AppendRelativeNativePath(nsDependentCString(target)))) |
|---|
| 1504 | break; |
|---|
| 1505 | if (NS_FAILED(rv = localFile->GetNativePath(_retval))) |
|---|
| 1506 | break; |
|---|
| 1507 | if (NS_FAILED(rv = parent->IsSymlink(&isSymlink))) |
|---|
| 1508 | break; |
|---|
| 1509 | self = parent; |
|---|
| 1510 | } else { |
|---|
| 1511 | nsCOMPtr<nsILocalFile> localFile; |
|---|
| 1512 | rv = NS_NewNativeLocalFile(nsDependentCString(target), PR_TRUE, |
|---|
| 1513 | getter_AddRefs(localFile)); |
|---|
| 1514 | if (NS_FAILED(rv)) |
|---|
| 1515 | break; |
|---|
| 1516 | if (NS_FAILED(rv = localFile->IsSymlink(&isSymlink))) |
|---|
| 1517 | break; |
|---|
| 1518 | _retval = target; // XXX can we avoid this buffer copy? |
|---|
| 1519 | self = do_QueryInterface(localFile); |
|---|
| 1520 | } |
|---|
| 1521 | if (NS_FAILED(rv) || !isSymlink) |
|---|
| 1522 | break; |
|---|
| 1523 | |
|---|
| 1524 | const nsPromiseFlatCString &flatRetval = PromiseFlatCString(_retval); |
|---|
| 1525 | |
|---|
| 1526 | // strip off any and all trailing '/' |
|---|
| 1527 | PRInt32 len = strlen(target); |
|---|
| 1528 | while (target[len-1] == '/' && len > 1) |
|---|
| 1529 | target[--len] = '\0'; |
|---|
| 1530 | if (lstat(flatRetval.get(), &symStat) < 0) { |
|---|
| 1531 | rv = NSRESULT_FOR_ERRNO(); |
|---|
| 1532 | break; |
|---|
| 1533 | } |
|---|
| 1534 | if (!S_ISLNK(symStat.st_mode)) { |
|---|
| 1535 | rv = NS_ERROR_FILE_INVALID_PATH; |
|---|
| 1536 | break; |
|---|
| 1537 | } |
|---|
| 1538 | size = symStat.st_size; |
|---|
| 1539 | if (readlink(flatRetval.get(), target, size) < 0) { |
|---|
| 1540 | rv = NSRESULT_FOR_ERRNO(); |
|---|
| 1541 | break; |
|---|
| 1542 | } |
|---|
| 1543 | target[size] = '\0'; |
|---|
| 1544 | |
|---|
| 1545 | _retval.Truncate(); |
|---|
| 1546 | } |
|---|
| 1547 | |
|---|
| 1548 | nsMemory::Free(target); |
|---|
| 1549 | |
|---|
| 1550 | if (NS_FAILED(rv)) |
|---|
| 1551 | _retval.Truncate(); |
|---|
| 1552 | return rv; |
|---|
| 1553 | } |
|---|
| 1554 | |
|---|
| 1555 | /* attribute PRBool followLinks; */ |
|---|
| 1556 | NS_IMETHODIMP |
|---|
| 1557 | nsLocalFile::GetFollowLinks(PRBool *aFollowLinks) |
|---|
| 1558 | { |
|---|
| 1559 | *aFollowLinks = PR_TRUE; |
|---|
| 1560 | return NS_OK; |
|---|
| 1561 | } |
|---|
| 1562 | |
|---|
| 1563 | NS_IMETHODIMP |
|---|
| 1564 | nsLocalFile::SetFollowLinks(PRBool aFollowLinks) |
|---|
| 1565 | { |
|---|
| 1566 | return NS_OK; |
|---|
| 1567 | } |
|---|
| 1568 | |
|---|
| 1569 | NS_IMETHODIMP |
|---|
| 1570 | nsLocalFile::GetDirectoryEntries(nsISimpleEnumerator **entries) |
|---|
| 1571 | { |
|---|
| 1572 | nsDirEnumeratorUnix *dir = new nsDirEnumeratorUnix(); |
|---|
| 1573 | if (!dir) |
|---|
| 1574 | return NS_ERROR_OUT_OF_MEMORY; |
|---|
| 1575 | |
|---|
| 1576 | NS_ADDREF(dir); |
|---|
| 1577 | nsresult rv = dir->Init(this, PR_FALSE); |
|---|
| 1578 | if (NS_FAILED(rv)) { |
|---|
| 1579 | *entries = nsnull; |
|---|
| 1580 | NS_RELEASE(dir); |
|---|
| 1581 | } else { |
|---|
| 1582 | *entries = dir; // transfer reference |
|---|
| 1583 | } |
|---|
| 1584 | |
|---|
| 1585 | return rv; |
|---|
| 1586 | } |
|---|
| 1587 | |
|---|
| 1588 | NS_IMETHODIMP |
|---|
| 1589 | nsLocalFile::Load(PRLibrary **_retval) |
|---|
| 1590 | { |
|---|
| 1591 | CHECK_mPath(); |
|---|
| 1592 | NS_ENSURE_ARG_POINTER(_retval); |
|---|
| 1593 | |
|---|
| 1594 | NS_TIMELINE_START_TIMER("PR_LoadLibrary"); |
|---|
| 1595 | |
|---|
| 1596 | #ifdef NS_BUILD_REFCNT_LOGGING |
|---|
| 1597 | nsTraceRefcntImpl::SetActivityIsLegal(PR_FALSE); |
|---|
| 1598 | #endif |
|---|
| 1599 | |
|---|
| 1600 | *_retval = PR_LoadLibrary(mPath.get()); |
|---|
| 1601 | |
|---|
| 1602 | #ifdef NS_BUILD_REFCNT_LOGGING |
|---|
| 1603 | nsTraceRefcntImpl::SetActivityIsLegal(PR_TRUE); |
|---|
| 1604 | #endif |
|---|
| 1605 | |
|---|
| 1606 | NS_TIMELINE_STOP_TIMER("PR_LoadLibrary"); |
|---|
| 1607 | NS_TIMELINE_MARK_TIMER1("PR_LoadLibrary", mPath.get()); |
|---|
| 1608 | |
|---|
| 1609 | if (!*_retval) |
|---|
| 1610 | return NS_ERROR_FAILURE; |
|---|
| 1611 | return NS_OK; |
|---|
| 1612 | } |
|---|
| 1613 | |
|---|
| 1614 | NS_IMETHODIMP |
|---|
| 1615 | nsLocalFile::GetPersistentDescriptor(nsACString &aPersistentDescriptor) |
|---|
| 1616 | { |
|---|
| 1617 | return GetNativePath(aPersistentDescriptor); |
|---|
| 1618 | } |
|---|
| 1619 | |
|---|
| 1620 | NS_IMETHODIMP |
|---|
| 1621 | nsLocalFile::SetPersistentDescriptor(const nsACString &aPersistentDescriptor) |
|---|
| 1622 | { |
|---|
| 1623 | return InitWithNativePath(aPersistentDescriptor); |
|---|
| 1624 | } |
|---|
| 1625 | |
|---|
| 1626 | #ifdef XP_BEOS |
|---|
| 1627 | NS_IMETHODIMP |
|---|
| 1628 | nsLocalFile::Reveal() |
|---|
| 1629 | { |
|---|
| 1630 | BPath bPath(mPath.get()); |
|---|
| 1631 | PRBool isDirectory; |
|---|
| 1632 | if (NS_FAILED(IsDirectory(&isDirectory))) |
|---|
| 1633 | return NS_ERROR_FAILURE; |
|---|
| 1634 | |
|---|
| 1635 | if(!isDirectory) |
|---|
| 1636 | bPath.GetParent(&bPath); |
|---|
| 1637 | entry_ref ref; |
|---|
| 1638 | get_ref_for_path(bPath.Path(),&ref); |
|---|
| 1639 | BMessage message(B_REFS_RECEIVED); |
|---|
| 1640 | message.AddRef("refs",&ref); |
|---|
| 1641 | BMessenger messenger("application/x-vnd.Be-TRAK"); |
|---|
| 1642 | messenger.SendMessage(&message); |
|---|
| 1643 | return NS_OK; |
|---|
| 1644 | } |
|---|
| 1645 | |
|---|
| 1646 | NS_IMETHODIMP |
|---|
| 1647 | nsLocalFile::Launch() |
|---|
| 1648 | { |
|---|
| 1649 | entry_ref ref; |
|---|
| 1650 | get_ref_for_path (mPath.get(), &ref); |
|---|
| 1651 | be_roster->Launch (&ref); |
|---|
| 1652 | |
|---|
| 1653 | return NS_OK; |
|---|
| 1654 | } |
|---|
| 1655 | #else |
|---|
| 1656 | NS_IMETHODIMP |
|---|
| 1657 | nsLocalFile::Reveal() |
|---|
| 1658 | { |
|---|
| 1659 | #ifdef MOZ_WIDGET_GTK2 |
|---|
| 1660 | nsCOMPtr<nsIGnomeVFSService> vfs = do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID); |
|---|
| 1661 | if (!vfs) |
|---|
| 1662 | return NS_ERROR_FAILURE; |
|---|
| 1663 | |
|---|
| 1664 | PRBool isDirectory; |
|---|
| 1665 | if (NS_FAILED(IsDirectory(&isDirectory))) |
|---|
| 1666 | return NS_ERROR_FAILURE; |
|---|
| 1667 | |
|---|
| 1668 | if (isDirectory) { |
|---|
| 1669 | return vfs->ShowURIForInput(mPath); |
|---|
| 1670 | } else { |
|---|
| 1671 | nsCOMPtr<nsIFile> parentDir; |
|---|
| 1672 | nsCAutoString dirPath; |
|---|
| 1673 | if (NS_FAILED(GetParent(getter_AddRefs(parentDir)))) |
|---|
| 1674 | return NS_ERROR_FAILURE; |
|---|
| 1675 | if (NS_FAILED(parentDir->GetNativePath(dirPath))) |
|---|
| 1676 | return NS_ERROR_FAILURE; |
|---|
| 1677 | |
|---|
| 1678 | return vfs->ShowURIForInput(dirPath); |
|---|
| 1679 | } |
|---|
| 1680 | #else |
|---|
| 1681 | return NS_ERROR_FAILURE; |
|---|
| 1682 | #endif |
|---|
| 1683 | } |
|---|
| 1684 | |
|---|
| 1685 | NS_IMETHODIMP |
|---|
| 1686 | nsLocalFile::Launch() |
|---|
| 1687 | { |
|---|
| 1688 | #ifdef MOZ_WIDGET_GTK2 |
|---|
| 1689 | nsCOMPtr<nsIGnomeVFSService> vfs = do_GetService(NS_GNOMEVFSSERVICE_CONTRACTID); |
|---|
| 1690 | if (!vfs) |
|---|
| 1691 | return NS_ERROR_FAILURE; |
|---|
| 1692 | |
|---|
| 1693 | return vfs->ShowURIForInput(mPath); |
|---|
| 1694 | #else |
|---|
| 1695 | return NS_ERROR_FAILURE; |
|---|
| 1696 | #endif |
|---|
| 1697 | } |
|---|
| 1698 | #endif |
|---|
| 1699 | |
|---|
| 1700 | nsresult |
|---|
| 1701 | NS_NewNativeLocalFile(const nsACString &path, PRBool followSymlinks, nsILocalFile **result) |
|---|
| 1702 | { |
|---|
| 1703 | nsLocalFile *file = new nsLocalFile(); |
|---|
| 1704 | if (!file) |
|---|
| 1705 | return NS_ERROR_OUT_OF_MEMORY; |
|---|
| 1706 | NS_ADDREF(file); |
|---|
| 1707 | |
|---|
| 1708 | if (!path.IsEmpty()) { |
|---|
| 1709 | nsresult rv = file->InitWithNativePath(path); |
|---|
| 1710 | if (NS_FAILED(rv)) { |
|---|
| 1711 | NS_RELEASE(file); |
|---|
| 1712 | return rv; |
|---|
| 1713 | } |
|---|
| 1714 | } |
|---|
| 1715 | *result = file; |
|---|
| 1716 | return NS_OK; |
|---|
| 1717 | } |
|---|
| 1718 | |
|---|
| 1719 | //----------------------------------------------------------------------------- |
|---|
| 1720 | // unicode support |
|---|
| 1721 | //----------------------------------------------------------------------------- |
|---|
| 1722 | |
|---|
| 1723 | #define SET_UCS(func, ucsArg) \ |
|---|
| 1724 | { \ |
|---|
| 1725 | nsCAutoString buf; \ |
|---|
| 1726 | nsresult rv = NS_CopyUnicodeToNative(ucsArg, buf); \ |
|---|
| 1727 | if (NS_FAILED(rv)) \ |
|---|
| 1728 | return rv; \ |
|---|
| 1729 | return (func)(buf); \ |
|---|
| 1730 | } |
|---|
| 1731 | |
|---|
| 1732 | #define GET_UCS(func, ucsArg) \ |
|---|
| 1733 | { \ |
|---|
| 1734 | nsCAutoString buf; \ |
|---|
| 1735 | nsresult rv = (func)(buf); \ |
|---|
| 1736 | if (NS_FAILED(rv)) return rv; \ |
|---|
| 1737 | return NS_CopyNativeToUnicode(buf, ucsArg); \ |
|---|
| 1738 | } |
|---|
| 1739 | |
|---|
| 1740 | #define SET_UCS_2ARGS_2(func, opaqueArg, ucsArg) \ |
|---|
| 1741 | { \ |
|---|
| 1742 | nsCAutoString buf; \ |
|---|
| 1743 | nsresult rv = NS_CopyUnicodeToNative(ucsArg, buf); \ |
|---|
| 1744 | if (NS_FAILED(rv)) \ |
|---|
| 1745 | return rv; \ |
|---|
| 1746 | return (func)(opaqueArg, buf); \ |
|---|
| 1747 | } |
|---|
| 1748 | |
|---|
| 1749 | // Unicode interface Wrapper |
|---|
| 1750 | nsresult |
|---|
| 1751 | nsLocalFile::InitWithPath(const nsAString &filePath) |
|---|
| 1752 | { |
|---|
| 1753 | SET_UCS(InitWithNativePath, filePath); |
|---|
| 1754 | } |
|---|
| 1755 | nsresult |
|---|
| 1756 | nsLocalFile::Append(const nsAString &node) |
|---|
| 1757 | { |
|---|
| 1758 | SET_UCS(AppendNative, node); |
|---|
| 1759 | } |
|---|
| 1760 | nsresult |
|---|
| 1761 | nsLocalFile::AppendRelativePath(const nsAString &node) |
|---|
| 1762 | { |
|---|
| 1763 | SET_UCS(AppendRelativeNativePath, node); |
|---|
| 1764 | } |
|---|
| 1765 | nsresult |
|---|
| 1766 | nsLocalFile::GetLeafName(nsAString &aLeafName) |
|---|
| 1767 | { |
|---|
| 1768 | GET_UCS(GetNativeLeafName, aLeafName); |
|---|
| 1769 | } |
|---|
| 1770 | nsresult |
|---|
| 1771 | nsLocalFile::SetLeafName(const nsAString &aLeafName) |
|---|
| 1772 | { |
|---|
| 1773 | SET_UCS(SetNativeLeafName, aLeafName); |
|---|
| 1774 | } |
|---|
| 1775 | nsresult |
|---|
| 1776 | nsLocalFile::GetPath(nsAString &_retval) |
|---|
| 1777 | { |
|---|
| 1778 | return NS_CopyNativeToUnicode(mPath, _retval); |
|---|
| 1779 | } |
|---|
| 1780 | nsresult |
|---|
| 1781 | nsLocalFile::CopyTo(nsIFile *newParentDir, const nsAString &newName) |
|---|
| 1782 | { |
|---|
| 1783 | SET_UCS_2ARGS_2(CopyToNative , newParentDir, newName); |
|---|
| 1784 | } |
|---|
| 1785 | nsresult |
|---|
| 1786 | nsLocalFile::CopyToFollowingLinks(nsIFile *newParentDir, const nsAString &newName) |
|---|
| 1787 | { |
|---|
| 1788 | SET_UCS_2ARGS_2(CopyToFollowingLinksNative , newParentDir, newName); |
|---|
| 1789 | } |
|---|
| 1790 | nsresult |
|---|
| 1791 | nsLocalFile::MoveTo(nsIFile *newParentDir, const nsAString &newName) |
|---|
| 1792 | { |
|---|
| 1793 | SET_UCS_2ARGS_2(MoveToNative, newParentDir, newName); |
|---|
| 1794 | } |
|---|
| 1795 | nsresult |
|---|
| 1796 | nsLocalFile::GetTarget(nsAString &_retval) |
|---|
| 1797 | { |
|---|
| 1798 | GET_UCS(GetNativeTarget, _retval); |
|---|
| 1799 | } |
|---|
| 1800 | |
|---|
| 1801 | // nsIHashable |
|---|
| 1802 | |
|---|
| 1803 | NS_IMETHODIMP |
|---|
| 1804 | nsLocalFile::Equals(nsIHashable* aOther, PRBool *aResult) |
|---|
| 1805 | { |
|---|
| 1806 | nsCOMPtr<nsIFile> otherFile(do_QueryInterface(aOther)); |
|---|
| 1807 | if (!otherFile) { |
|---|
| 1808 | *aResult = PR_FALSE; |
|---|
| 1809 | return NS_OK; |
|---|
| 1810 | } |
|---|
| 1811 | |
|---|
| 1812 | return Equals(otherFile, aResult); |
|---|
| 1813 | } |
|---|
| 1814 | |
|---|
| 1815 | NS_IMETHODIMP |
|---|
| 1816 | nsLocalFile::GetHashCode(PRUint32 *aResult) |
|---|
| 1817 | { |
|---|
| 1818 | *aResult = nsCRT::HashCode(mPath.get()); |
|---|
| 1819 | return NS_OK; |
|---|
| 1820 | } |
|---|
| 1821 | |
|---|
| 1822 | nsresult |
|---|
| 1823 | NS_NewLocalFile(const nsAString &path, PRBool followLinks, nsILocalFile* *result) |
|---|
| 1824 | { |
|---|
| 1825 | nsCAutoString buf; |
|---|
| 1826 | nsresult rv = NS_CopyUnicodeToNative(path, buf); |
|---|
| 1827 | if (NS_FAILED(rv)) |
|---|
| 1828 | return rv; |
|---|
| 1829 | return NS_NewNativeLocalFile(buf, followLinks, result); |
|---|
| 1830 | } |
|---|
| 1831 | |
|---|
| 1832 | //----------------------------------------------------------------------------- |
|---|
| 1833 | // global init/shutdown |
|---|
| 1834 | //----------------------------------------------------------------------------- |
|---|
| 1835 | |
|---|
| 1836 | void |
|---|
| 1837 | nsLocalFile::GlobalInit() |
|---|
| 1838 | { |
|---|
| 1839 | } |
|---|
| 1840 | |
|---|
| 1841 | void |
|---|
| 1842 | nsLocalFile::GlobalShutdown() |
|---|
| 1843 | { |
|---|
| 1844 | } |
|---|