1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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
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.
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 nsFileSpec.cpp, and includes the Unix-specific
42 #include <sys/param.h>
49 #include "prio.h" /* for PR_Rename */
51 // BeOS specific headers
56 //----------------------------------------------------------------------------------------
57 void nsFileSpecHelpers::Canonify(nsSimpleCharString
& ioPath
, PRBool inMakeDirs
)
58 // Canonify, make absolute, and check whether directories exist
59 //----------------------------------------------------------------------------------------
65 const mode_t mode
= 0700;
66 nsFileSpecHelpers::MakeAllDirectories((const char*)ioPath
, mode
);
68 char buffer
[MAXPATHLEN
];
71 BEntry
e((const char *)ioPath
, true);
75 } // nsFileSpecHelpers::Canonify
77 //----------------------------------------------------------------------------------------
78 void nsFileSpec::SetLeafName(const char* inLeafName
)
79 //----------------------------------------------------------------------------------------
81 mPath
.LeafReplace('/', inLeafName
);
82 } // nsFileSpec::SetLeafName
84 //----------------------------------------------------------------------------------------
85 char* nsFileSpec::GetLeafName() const
86 //----------------------------------------------------------------------------------------
88 return mPath
.GetLeaf('/');
89 } // nsFileSpec::GetLeafName
91 //----------------------------------------------------------------------------------------
92 PRBool
nsFileSpec::Exists() const
93 //----------------------------------------------------------------------------------------
96 return !mPath
.IsEmpty() && 0 == stat(mPath
, &st
);
97 } // nsFileSpec::Exists
99 //----------------------------------------------------------------------------------------
100 void nsFileSpec::GetModDate(TimeStamp
& outStamp
) const
101 //----------------------------------------------------------------------------------------
104 if (!mPath
.IsEmpty() && stat(mPath
, &st
) == 0)
105 outStamp
= st
.st_mtime
;
108 } // nsFileSpec::GetModDate
110 //----------------------------------------------------------------------------------------
111 PRUint32
nsFileSpec::GetFileSize() const
112 //----------------------------------------------------------------------------------------
115 if (!mPath
.IsEmpty() && stat(mPath
, &st
) == 0)
116 return (PRUint32
)st
.st_size
;
118 } // nsFileSpec::GetFileSize
120 //----------------------------------------------------------------------------------------
121 PRBool
nsFileSpec::IsFile() const
122 //----------------------------------------------------------------------------------------
125 return !mPath
.IsEmpty() && stat(mPath
, &st
) == 0 && S_ISREG(st
.st_mode
);
126 } // nsFileSpec::IsFile
128 //----------------------------------------------------------------------------------------
129 PRBool
nsFileSpec::IsDirectory() const
130 //----------------------------------------------------------------------------------------
133 return !mPath
.IsEmpty() && 0 == stat(mPath
, &st
) && S_ISDIR(st
.st_mode
);
134 } // nsFileSpec::IsDirectory
136 //----------------------------------------------------------------------------------------
137 PRBool
nsFileSpec::IsHidden() const
138 //----------------------------------------------------------------------------------------
140 PRBool hidden
= PR_TRUE
;
141 char *leafname
= GetLeafName();
142 if (nsnull
!= leafname
)
144 if ((!strcmp(leafname
, ".")) || (!strcmp(leafname
, "..")))
148 nsCRT::free(leafname
);
151 } // nsFileSpec::IsHidden
153 //----------------------------------------------------------------------------------------
154 PRBool
nsFileSpec::IsSymlink() const
155 //----------------------------------------------------------------------------------------
158 if (!mPath
.IsEmpty() && stat(mPath
, &st
) == 0 && S_ISLNK(st
.st_mode
))
162 } // nsFileSpec::IsSymlink
164 //----------------------------------------------------------------------------------------
165 nsresult
nsFileSpec::ResolveSymlink(PRBool
& wasAliased
)
166 //----------------------------------------------------------------------------------------
168 wasAliased
= PR_FALSE
;
170 char resolvedPath
[MAXPATHLEN
];
171 int charCount
= readlink(mPath
, (char*)&resolvedPath
, MAXPATHLEN
);
174 if (MAXPATHLEN
> charCount
)
175 resolvedPath
[charCount
] = '\0';
177 wasAliased
= PR_TRUE
;
178 /* if it's not an absolute path,
179 replace the leaf with what got resolved */
180 if (resolvedPath
[0] != '/') {
181 SetLeafName(resolvedPath
);
184 mPath
= (char*)resolvedPath
;
187 BEntry
e((const char *)mPath
, true); // traverse symlink
191 NS_ASSERTION(err
== B_OK
, "realpath failed");
193 const char* canonicalPath
= p
.Path();
195 mPath
= (char*)canonicalPath
;
197 return NS_ERROR_FAILURE
;
200 } // nsFileSpec::ResolveSymlink
202 //----------------------------------------------------------------------------------------
203 void nsFileSpec::GetParent(nsFileSpec
& outSpec
) const
204 //----------------------------------------------------------------------------------------
206 outSpec
.mPath
= mPath
;
207 char* chars
= (char*)outSpec
.mPath
;
208 chars
[outSpec
.mPath
.Length() - 1] = '\0'; // avoid trailing separator, if any
209 char* cp
= strrchr(chars
, '/');
211 outSpec
.mPath
.SetLength(cp
- chars
); // truncate.
212 } // nsFileSpec::GetParent
214 //----------------------------------------------------------------------------------------
215 void nsFileSpec::operator += (const char* inRelativePath
)
216 //----------------------------------------------------------------------------------------
218 if (!inRelativePath
|| mPath
.IsEmpty())
221 char endChar
= mPath
[(int)(strlen(mPath
) - 1)];
226 SetLeafName(inRelativePath
);
227 } // nsFileSpec::operator +=
229 //----------------------------------------------------------------------------------------
230 void nsFileSpec::CreateDirectory(int mode
)
231 //----------------------------------------------------------------------------------------
233 // Note that mPath is canonical!
237 } // nsFileSpec::CreateDirectory
239 //----------------------------------------------------------------------------------------
240 void nsFileSpec::Delete(PRBool inRecursive
) const
241 // To check if this worked, call Exists() afterwards, see?
242 //----------------------------------------------------------------------------------------
248 for (nsDirectoryIterator
i(*this, PR_FALSE
); i
.Exists(); i
++)
250 nsFileSpec
& child
= (nsFileSpec
&)i
;
251 child
.Delete(inRecursive
);
256 else if (!mPath
.IsEmpty())
258 } // nsFileSpec::Delete
260 //----------------------------------------------------------------------------------------
261 void nsFileSpec::RecursiveCopy(nsFileSpec newDir
) const
262 //----------------------------------------------------------------------------------------
266 if (!(newDir
.Exists()))
268 newDir
.CreateDirectory();
271 for (nsDirectoryIterator
i(*this, PR_FALSE
); i
.Exists(); i
++)
273 nsFileSpec
& child
= (nsFileSpec
&)i
;
275 if (child
.IsDirectory())
277 nsFileSpec
tmpDirSpec(newDir
);
279 char *leafname
= child
.GetLeafName();
280 tmpDirSpec
+= leafname
;
281 nsCRT::free(leafname
);
283 child
.RecursiveCopy(tmpDirSpec
);
287 child
.RecursiveCopy(newDir
);
291 else if (!mPath
.IsEmpty())
293 nsFileSpec
& filePath
= (nsFileSpec
&) *this;
295 if (!(newDir
.Exists()))
297 newDir
.CreateDirectory();
300 filePath
.CopyToDir(newDir
);
302 } // nsFileSpec::RecursiveCopy
304 //----------------------------------------------------------------------------------------
305 nsresult
nsFileSpec::Truncate(PRInt32 offset
) const
306 //----------------------------------------------------------------------------------------
308 char* Path
= nsCRT::strdup(mPath
);
310 int rv
= truncate(Path
, offset
) ;
317 return NS_ERROR_FAILURE
;
318 } // nsFileSpec::Truncate
320 //----------------------------------------------------------------------------------------
321 nsresult
nsFileSpec::Rename(const char* inNewName
)
322 //----------------------------------------------------------------------------------------
324 // This function should not be used to move a file on disk.
325 if (mPath
.IsEmpty() || strchr(inNewName
, '/'))
326 return NS_FILE_FAILURE
;
328 char* oldPath
= nsCRT::strdup(mPath
);
330 SetLeafName(inNewName
);
332 if (PR_Rename(oldPath
, mPath
) != NS_OK
)
334 // Could not rename, set back to the original.
336 return NS_FILE_FAILURE
;
339 nsCRT::free(oldPath
);
342 } // nsFileSpec::Rename
344 //----------------------------------------------------------------------------------------
345 static int CrudeFileCopy(const char* in
, const char* out
)
346 //----------------------------------------------------------------------------------------
349 int stat_result
= -1;
358 stat_result
= stat (in
, &in_stat
);
360 ifp
= fopen (in
, "r");
366 ofp
= fopen (out
, "w");
373 while ((rbytes
= fread (buf
, 1, sizeof(buf
), ifp
)) > 0)
377 if ( (wbytes
= fwrite (buf
, 1, rbytes
, ofp
)) < 0 )
390 if (stat_result
== 0)
391 chmod (out
, in_stat
.st_mode
& 0777);
394 } // nsFileSpec::Rename
396 //----------------------------------------------------------------------------------------
397 nsresult
nsFileSpec::CopyToDir(const nsFileSpec
& inParentDirectory
) const
398 //----------------------------------------------------------------------------------------
400 // We can only copy into a directory, and (for now) can not copy entire directories
401 nsresult result
= NS_FILE_FAILURE
;
403 if (inParentDirectory
.IsDirectory() && (! IsDirectory() ) )
405 char *leafname
= GetLeafName();
406 nsSimpleCharString
destPath(inParentDirectory
.GetCString());
408 destPath
+= leafname
;
409 nsCRT::free(leafname
);
410 result
= NS_FILE_RESULT(CrudeFileCopy(GetCString(), destPath
));
413 } // nsFileSpec::CopyToDir
415 //----------------------------------------------------------------------------------------
416 nsresult
nsFileSpec::MoveToDir(const nsFileSpec
& inNewParentDirectory
)
417 //----------------------------------------------------------------------------------------
419 // We can only copy into a directory, and (for now) can not copy entire directories
420 nsresult result
= NS_FILE_FAILURE
;
422 if (inNewParentDirectory
.IsDirectory() && !IsDirectory())
424 char *leafname
= GetLeafName();
425 nsSimpleCharString
destPath(inNewParentDirectory
.GetCString());
427 destPath
+= leafname
;
428 nsCRT::free(leafname
);
430 result
= NS_FILE_RESULT(CrudeFileCopy(GetCString(), (const char*)destPath
));
433 // cast to fix const-ness
434 ((nsFileSpec
*)this)->Delete(PR_FALSE
);
436 *this = inNewParentDirectory
+ GetLeafName();
442 //----------------------------------------------------------------------------------------
443 nsresult
nsFileSpec::Execute(const char* inArgs
) const
444 //----------------------------------------------------------------------------------------
446 nsresult result
= NS_FILE_FAILURE
;
448 if (!mPath
.IsEmpty() && !IsDirectory())
450 nsSimpleCharString fileNameWithArgs
= mPath
+ " " + inArgs
;
451 result
= NS_FILE_RESULT(system(fileNameWithArgs
));
456 } // nsFileSpec::Execute
458 //----------------------------------------------------------------------------------------
459 PRInt64
nsFileSpec::GetDiskSpaceAvailable() const
460 //----------------------------------------------------------------------------------------
462 char curdir
[MAXPATHLEN
];
463 if (!mPath
|| !*mPath
)
465 (void) getcwd(curdir
, MAXPATHLEN
);
467 return ULONGLONG_MAX
; /* hope for the best as we did in cheddar */
470 sprintf(curdir
, "%.200s", (const char*)mPath
);
473 if(e
.InitCheck() != B_OK
)
474 return ULONGLONG_MAX
; /* hope for the best as we did in cheddar */
477 BVolume
v(ref
.device
);
479 #ifdef DEBUG_DISK_SPACE
480 printf("DiskSpaceAvailable: %d bytes\n", space
);
482 return v
.FreeBytes();
483 } // nsFileSpec::GetDiskSpace()
485 //========================================================================================
486 // nsDirectoryIterator
487 //========================================================================================
489 //----------------------------------------------------------------------------------------
490 nsDirectoryIterator::nsDirectoryIterator(
491 const nsFileSpec
& inDirectory
492 , PRBool resolveSymlinks
)
493 //----------------------------------------------------------------------------------------
494 : mCurrent(inDirectory
)
495 , mStarting(inDirectory
)
498 , mResoveSymLinks(resolveSymlinks
)
500 mStarting
+= "sysygy"; // save off the starting directory
501 mCurrent
+= "sysygy"; // prepare the path for SetLeafName
502 mDir
= opendir((const char*)nsFilePath(inDirectory
));
504 } // nsDirectoryIterator::nsDirectoryIterator
506 //----------------------------------------------------------------------------------------
507 nsDirectoryIterator::~nsDirectoryIterator()
508 //----------------------------------------------------------------------------------------
512 } // nsDirectoryIterator::nsDirectoryIterator
514 //----------------------------------------------------------------------------------------
515 nsDirectoryIterator
& nsDirectoryIterator::operator ++ ()
516 //----------------------------------------------------------------------------------------
523 struct dirent
* entry
= readdir(mDir
);
524 if (entry
&& strcmp(entry
->d_name
, dot
) == 0)
525 entry
= readdir(mDir
);
526 if (entry
&& strcmp(entry
->d_name
, dotdot
) == 0)
527 entry
= readdir(mDir
);
531 mCurrent
= mStarting
; // restore mCurrent to be the starting directory. ResolveSymlink() may have taken us to another directory
532 mCurrent
.SetLeafName(entry
->d_name
);
536 mCurrent
.ResolveSymlink(ignore
);
540 } // nsDirectoryIterator::operator ++
542 //----------------------------------------------------------------------------------------
543 nsDirectoryIterator
& nsDirectoryIterator::operator -- ()
544 //----------------------------------------------------------------------------------------
546 return ++(*this); // can't do it backwards.
547 } // nsDirectoryIterator::operator --