source: trunk/third/firefox/xpcom/obsolete/nsFileSpecBeOS.cpp @ 21695

Revision 21695, 17.5 KB checked in by rbasch, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21694, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* ***** BEGIN LICENSE BLOCK *****
3 * Version: NPL 1.1/GPL 2.0/LGPL 2.1
4 *
5 * The contents of this file are subject to the Netscape Public License
6 * Version 1.1 (the "License"); you may not use this file except in
7 * compliance with the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/NPL/
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.org code.
16 *
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.
21 *
22 * Contributor(s):
23 *
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * 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 NPL, 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 NPL, the GPL or the LGPL.
35 *
36 * ***** END LICENSE BLOCK ***** */
37 
38//    This file is included by nsFileSpec.cpp, and includes the Unix-specific
39//    implementations.
40
41#include <sys/stat.h>
42#include <sys/param.h>
43#include <errno.h>
44#include <dirent.h>
45#include <unistd.h>
46#include <stdlib.h>
47#include <limits.h>
48#include "nsError.h"
49#include "prio.h"   /* for PR_Rename */
50
51// BeOS specific headers
52#include <Entry.h>
53#include <Path.h>
54#include <Volume.h>
55
56//----------------------------------------------------------------------------------------
57void nsFileSpecHelpers::Canonify(nsSimpleCharString& ioPath, PRBool inMakeDirs)
58// Canonify, make absolute, and check whether directories exist
59//----------------------------------------------------------------------------------------
60{
61    if (ioPath.IsEmpty())
62        return;
63    if (inMakeDirs)
64    {
65        const mode_t mode = 0700;
66        nsFileSpecHelpers::MakeAllDirectories((const char*)ioPath, mode);
67    }
68    char buffer[MAXPATHLEN];
69    errno = 0;
70    *buffer = '\0';
71    BEntry e((const char *)ioPath, true);
72    BPath p;
73    e.GetPath(&p);
74    ioPath = p.Path();
75} // nsFileSpecHelpers::Canonify
76
77//----------------------------------------------------------------------------------------
78void nsFileSpec::SetLeafName(const char* inLeafName)
79//----------------------------------------------------------------------------------------
80{
81    mPath.LeafReplace('/', inLeafName);
82} // nsFileSpec::SetLeafName
83
84//----------------------------------------------------------------------------------------
85char* nsFileSpec::GetLeafName() const
86//----------------------------------------------------------------------------------------
87{
88    return mPath.GetLeaf('/');
89} // nsFileSpec::GetLeafName
90
91//----------------------------------------------------------------------------------------
92PRBool nsFileSpec::Exists() const
93//----------------------------------------------------------------------------------------
94{
95    struct stat st;
96    return !mPath.IsEmpty() && 0 == stat(mPath, &st);
97} // nsFileSpec::Exists
98
99//----------------------------------------------------------------------------------------
100void nsFileSpec::GetModDate(TimeStamp& outStamp) const
101//----------------------------------------------------------------------------------------
102{
103        struct stat st;
104    if (!mPath.IsEmpty() && stat(mPath, &st) == 0)
105        outStamp = st.st_mtime;
106    else
107        outStamp = 0;
108} // nsFileSpec::GetModDate
109
110//----------------------------------------------------------------------------------------
111PRUint32 nsFileSpec::GetFileSize() const
112//----------------------------------------------------------------------------------------
113{
114        struct stat st;
115    if (!mPath.IsEmpty() && stat(mPath, &st) == 0)
116        return (PRUint32)st.st_size;
117    return 0;
118} // nsFileSpec::GetFileSize
119
120//----------------------------------------------------------------------------------------
121PRBool nsFileSpec::IsFile() const
122//----------------------------------------------------------------------------------------
123{
124    struct stat st;
125    return !mPath.IsEmpty() && stat(mPath, &st) == 0 && S_ISREG(st.st_mode);
126} // nsFileSpec::IsFile
127
128//----------------------------------------------------------------------------------------
129PRBool nsFileSpec::IsDirectory() const
130//----------------------------------------------------------------------------------------
131{
132    struct stat st;
133    return !mPath.IsEmpty() && 0 == stat(mPath, &st) && S_ISDIR(st.st_mode);
134} // nsFileSpec::IsDirectory
135
136//----------------------------------------------------------------------------------------
137PRBool nsFileSpec::IsHidden() const
138//----------------------------------------------------------------------------------------
139{
140    PRBool hidden = PR_TRUE;
141    char *leafname = GetLeafName();
142    if (nsnull != leafname)
143    {
144        if ((!strcmp(leafname, ".")) || (!strcmp(leafname, "..")))
145        {
146            hidden = PR_FALSE;
147        }
148        nsCRT::free(leafname);
149    }
150    return hidden;
151} // nsFileSpec::IsHidden
152
153//----------------------------------------------------------------------------------------
154PRBool nsFileSpec::IsSymlink() const
155//----------------------------------------------------------------------------------------
156{
157    struct stat st;
158    if (!mPath.IsEmpty() && stat(mPath, &st) == 0 && S_ISLNK(st.st_mode))
159        return PR_TRUE;
160
161    return PR_FALSE;
162} // nsFileSpec::IsSymlink
163
164//----------------------------------------------------------------------------------------
165nsresult nsFileSpec::ResolveSymlink(PRBool& wasAliased)
166//----------------------------------------------------------------------------------------
167{
168    wasAliased = PR_FALSE;
169
170    char resolvedPath[MAXPATHLEN];
171    int charCount = readlink(mPath, (char*)&resolvedPath, MAXPATHLEN);
172    if (0 < charCount)
173    {
174        if (MAXPATHLEN > charCount)
175            resolvedPath[charCount] = '\0';
176       
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);
182                }
183                else {
184                        mPath = (char*)resolvedPath;
185                }
186
187                BEntry e((const char *)mPath, true);    // traverse symlink
188                BPath p;
189                status_t err;
190                err = e.GetPath(&p);
191                NS_ASSERTION(err == B_OK, "realpath failed");
192
193                const char* canonicalPath = p.Path();
194                if(err == B_OK)
195                        mPath = (char*)canonicalPath;
196                else
197                        return NS_ERROR_FAILURE;
198    }
199    return NS_OK;
200} // nsFileSpec::ResolveSymlink
201
202//----------------------------------------------------------------------------------------
203void nsFileSpec::GetParent(nsFileSpec& outSpec) const
204//----------------------------------------------------------------------------------------
205{
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, '/');
210    if (cp++)
211            outSpec.mPath.SetLength(cp - chars); // truncate.
212} // nsFileSpec::GetParent
213
214//----------------------------------------------------------------------------------------
215void nsFileSpec::operator += (const char* inRelativePath)
216//----------------------------------------------------------------------------------------
217{
218    if (!inRelativePath || mPath.IsEmpty())
219        return;
220   
221    char endChar = mPath[(int)(strlen(mPath) - 1)];
222    if (endChar == '/')
223        mPath += "x";
224    else
225        mPath += "/x";
226    SetLeafName(inRelativePath);
227} // nsFileSpec::operator +=
228
229//----------------------------------------------------------------------------------------
230void nsFileSpec::CreateDirectory(int mode)
231//----------------------------------------------------------------------------------------
232{
233    // Note that mPath is canonical!
234    if (mPath.IsEmpty())
235        return;
236    mkdir(mPath, mode);
237} // nsFileSpec::CreateDirectory
238
239//----------------------------------------------------------------------------------------
240void nsFileSpec::Delete(PRBool inRecursive) const
241// To check if this worked, call Exists() afterwards, see?
242//----------------------------------------------------------------------------------------
243{
244    if (IsDirectory())
245    {
246        if (inRecursive)
247        {
248            for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++)
249            {
250                nsFileSpec& child = (nsFileSpec&)i;
251                child.Delete(inRecursive);
252            }       
253        }
254        rmdir(mPath);
255    }
256    else if (!mPath.IsEmpty())
257        remove(mPath);
258} // nsFileSpec::Delete
259
260//----------------------------------------------------------------------------------------
261void nsFileSpec::RecursiveCopy(nsFileSpec newDir) const
262//----------------------------------------------------------------------------------------
263{
264    if (IsDirectory())
265    {
266                if (!(newDir.Exists()))
267                {
268                        newDir.CreateDirectory();
269                }
270
271                for (nsDirectoryIterator i(*this, PR_FALSE); i.Exists(); i++)
272                {
273                        nsFileSpec& child = (nsFileSpec&)i;
274
275                        if (child.IsDirectory())
276                        {
277                                nsFileSpec tmpDirSpec(newDir);
278
279                                char *leafname = child.GetLeafName();
280                                tmpDirSpec += leafname;
281                                nsCRT::free(leafname);
282
283                                child.RecursiveCopy(tmpDirSpec);
284                        }
285                        else
286                        {
287                                child.RecursiveCopy(newDir);
288                        }
289                }
290    }
291    else if (!mPath.IsEmpty())
292    {
293                nsFileSpec& filePath = (nsFileSpec&) *this;
294
295                if (!(newDir.Exists()))
296                {
297                        newDir.CreateDirectory();
298                }
299
300        filePath.CopyToDir(newDir);
301    }
302} // nsFileSpec::RecursiveCopy
303
304//----------------------------------------------------------------------------------------
305nsresult nsFileSpec::Truncate(PRInt32 offset) const
306//----------------------------------------------------------------------------------------
307{
308    char* Path = nsCRT::strdup(mPath);
309
310    int rv = truncate(Path, offset) ;
311
312    nsCRT::free(Path) ;
313
314    if(!rv)
315        return NS_OK ;
316    else
317        return NS_ERROR_FAILURE ;
318} // nsFileSpec::Truncate
319
320//----------------------------------------------------------------------------------------
321nsresult nsFileSpec::Rename(const char* inNewName)
322//----------------------------------------------------------------------------------------
323{
324    // This function should not be used to move a file on disk.
325    if (mPath.IsEmpty() || strchr(inNewName, '/'))
326        return NS_FILE_FAILURE;
327
328    char* oldPath = nsCRT::strdup(mPath);
329   
330    SetLeafName(inNewName);
331
332    if (PR_Rename(oldPath, mPath) != NS_OK)
333    {
334        // Could not rename, set back to the original.
335        mPath = oldPath;
336        return NS_FILE_FAILURE;
337    }
338   
339    nsCRT::free(oldPath);
340
341    return NS_OK;
342} // nsFileSpec::Rename
343
344//----------------------------------------------------------------------------------------
345static int CrudeFileCopy(const char* in, const char* out)
346//----------------------------------------------------------------------------------------
347{
348        struct stat in_stat;
349        int stat_result = -1;
350
351        char    buf [1024];
352        FILE    *ifp, *ofp;
353        int     rbytes, wbytes;
354
355        if (!in || !out)
356                return -1;
357
358        stat_result = stat (in, &in_stat);
359
360        ifp = fopen (in, "r");
361        if (!ifp)
362        {
363                return -1;
364        }
365
366        ofp = fopen (out, "w");
367        if (!ofp)
368        {
369                fclose (ifp);
370                return -1;
371        }
372
373        while ((rbytes = fread (buf, 1, sizeof(buf), ifp)) > 0)
374        {
375                while (rbytes > 0)
376                {
377                        if ( (wbytes = fwrite (buf, 1, rbytes, ofp)) < 0 )
378                        {
379                                fclose (ofp);
380                                fclose (ifp);
381                                unlink(out);
382                                return -1;
383                        }
384                        rbytes -= wbytes;
385                }
386        }
387        fclose (ofp);
388        fclose (ifp);
389
390        if (stat_result == 0)
391                chmod (out, in_stat.st_mode & 0777);
392
393        return 0;
394} // nsFileSpec::Rename
395
396//----------------------------------------------------------------------------------------
397nsresult nsFileSpec::CopyToDir(const nsFileSpec& inParentDirectory) const
398//----------------------------------------------------------------------------------------
399{
400    // We can only copy into a directory, and (for now) can not copy entire directories
401    nsresult result = NS_FILE_FAILURE;
402
403    if (inParentDirectory.IsDirectory() && (! IsDirectory() ) )
404    {
405        char *leafname = GetLeafName();
406        nsSimpleCharString destPath(inParentDirectory.GetCString());
407        destPath += "/";
408        destPath += leafname;
409        nsCRT::free(leafname);
410        result = NS_FILE_RESULT(CrudeFileCopy(GetCString(), destPath));
411    }
412    return result;
413} // nsFileSpec::CopyToDir
414
415//----------------------------------------------------------------------------------------
416nsresult nsFileSpec::MoveToDir(const nsFileSpec& inNewParentDirectory)
417//----------------------------------------------------------------------------------------
418{
419    // We can only copy into a directory, and (for now) can not copy entire directories
420    nsresult result = NS_FILE_FAILURE;
421
422    if (inNewParentDirectory.IsDirectory() && !IsDirectory())
423    {
424        char *leafname = GetLeafName();
425        nsSimpleCharString destPath(inNewParentDirectory.GetCString());
426        destPath += "/";
427        destPath += leafname;
428        nsCRT::free(leafname);
429
430        result = NS_FILE_RESULT(CrudeFileCopy(GetCString(), (const char*)destPath));
431        if (result == NS_OK)
432        {
433            // cast to fix const-ness
434                    ((nsFileSpec*)this)->Delete(PR_FALSE);
435       
436            *this = inNewParentDirectory + GetLeafName();
437        }
438    }
439    return result;
440}
441
442//----------------------------------------------------------------------------------------
443nsresult nsFileSpec::Execute(const char* inArgs ) const
444//----------------------------------------------------------------------------------------
445{
446    nsresult result = NS_FILE_FAILURE;
447   
448    if (!mPath.IsEmpty() && !IsDirectory())
449    {
450        nsSimpleCharString fileNameWithArgs = mPath + " " + inArgs;
451        result = NS_FILE_RESULT(system(fileNameWithArgs));
452    }
453
454    return result;
455
456} // nsFileSpec::Execute
457
458//----------------------------------------------------------------------------------------
459PRInt64 nsFileSpec::GetDiskSpaceAvailable() const
460//----------------------------------------------------------------------------------------
461{
462    char curdir [MAXPATHLEN];
463    if (!mPath || !*mPath)
464    {
465        (void) getcwd(curdir, MAXPATHLEN);
466        if (!curdir)
467            return ULONGLONG_MAX;  /* hope for the best as we did in cheddar */
468    }
469    else
470        sprintf(curdir, "%.200s", (const char*)mPath);
471
472    BEntry e(curdir);
473    if(e.InitCheck() != B_OK)
474        return ULONGLONG_MAX; /* hope for the best as we did in cheddar */
475    entry_ref ref;
476    e.GetRef(&ref);
477    BVolume v(ref.device);
478
479#ifdef DEBUG_DISK_SPACE
480    printf("DiskSpaceAvailable: %d bytes\n", space);
481#endif
482    return v.FreeBytes();
483} // nsFileSpec::GetDiskSpace()
484
485//========================================================================================
486//                                nsDirectoryIterator
487//========================================================================================
488
489//----------------------------------------------------------------------------------------
490nsDirectoryIterator::nsDirectoryIterator(
491    const nsFileSpec& inDirectory
492,   PRBool resolveSymlinks)
493//----------------------------------------------------------------------------------------
494    : mCurrent(inDirectory)
495    , mStarting(inDirectory)
496    , mExists(PR_FALSE)
497    , mDir(nsnull)
498    , mResoveSymLinks(resolveSymlinks)
499{
500    mStarting += "sysygy"; // save off the starting directory
501    mCurrent += "sysygy"; // prepare the path for SetLeafName
502    mDir = opendir((const char*)nsFilePath(inDirectory));
503    ++(*this);
504} // nsDirectoryIterator::nsDirectoryIterator
505
506//----------------------------------------------------------------------------------------
507nsDirectoryIterator::~nsDirectoryIterator()
508//----------------------------------------------------------------------------------------
509{
510    if (mDir)
511        closedir(mDir);
512} // nsDirectoryIterator::nsDirectoryIterator
513
514//----------------------------------------------------------------------------------------
515nsDirectoryIterator& nsDirectoryIterator::operator ++ ()
516//----------------------------------------------------------------------------------------
517{
518    mExists = PR_FALSE;
519    if (!mDir)
520        return *this;
521    char* dot    = ".";
522    char* dotdot = "..";
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);
528    if (entry)
529    {
530        mExists = PR_TRUE;
531        mCurrent = mStarting;           // restore mCurrent to be the starting directory.  ResolveSymlink() may have taken us to another directory
532        mCurrent.SetLeafName(entry->d_name);
533        if (mResoveSymLinks)
534        {   
535          PRBool ignore;
536          mCurrent.ResolveSymlink(ignore);
537        }
538    }
539    return *this;
540} // nsDirectoryIterator::operator ++
541
542//----------------------------------------------------------------------------------------
543nsDirectoryIterator& nsDirectoryIterator::operator -- ()
544//----------------------------------------------------------------------------------------
545{
546    return ++(*this); // can't do it backwards.
547} // nsDirectoryIterator::operator --
Note: See TracBrowser for help on using the repository browser.