Drizzled Public API Documentation

CSPath.cc

00001 /* Copyright (C) 2008 PrimeBase Technologies GmbH, Germany
00002  *
00003  * PrimeBase Media Stream for MySQL
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
00018  *
00019  * Original author: Paul McCullagh
00020  * Continued development: Barry Leslie
00021  *
00022  * 2007-06-07
00023  *
00024  * CORE SYSTEM:
00025  * Basic file system path.
00026  *
00027  */
00028 
00029 #include "CSConfig.h"
00030 
00031 #include <string.h>
00032 #include <stdio.h>
00033 
00034 #include "CSStrUtil.h"
00035 #include "CSSys.h"
00036 #include "CSFile.h"
00037 #include "CSDirectory.h"
00038 #include "CSPath.h"
00039 #include "CSGlobal.h"
00040 
00041 /*
00042  * ---------------------------------------------------------------
00043  * CORE SYSTEM PATH
00044  */
00045 CSLock  CSPath::iRename_lock;
00046 
00047 CSPath *CSPath::iCWD = NULL;
00048 
00049 CSPath::~CSPath()
00050 {
00051   if (iPath)
00052     iPath->release();
00053 }
00054 
00055 CSFile *CSPath::try_CreateAndOpen(CSThread *self, int mode, bool retry)
00056 {
00057   volatile CSFile *fh = NULL;
00058   
00059   try_(a) {
00060     fh = openFile(mode | CSFile::CREATE); // success, do not try again.
00061   }
00062   catch_(a) {
00063     if (retry || !CSFile::isDirNotFound(&self->myException))
00064       throw_();
00065 
00066     /* Make sure the parent directory exists: */
00067     CSPath  *dir = CSPath::newPath(RETAIN(this), "..");
00068     push_(dir);
00069     dir->makePath();
00070     release_(dir);
00071 
00072   }
00073   cont_(a);
00074   return (CSFile *) fh; 
00075 }
00076 
00077 CSFile *CSPath::createFile(int mode)
00078 {
00079   CSFile  *file = NULL;
00080   bool  retry = false;
00081 
00082   enter_();
00083   while (file == NULL) {
00084     file = try_CreateAndOpen(self, mode, retry);
00085     retry = true;
00086   }
00087   return_(file);
00088 }
00089 
00090 /* Copy the contents of one file to another.
00091  * The destination need not exist.
00092  * If the destination exists, it will be
00093  * overwritten if 'overwrite' is true.
00094  */
00095 void CSPath::copyFile(CSPath *in_to_file, bool overwrite)
00096 {
00097   CSPath      *to_file = in_to_file;
00098   bool      is_dir;
00099   CSFile      *infile, *outfile;
00100 
00101   enter_();
00102   push_(in_to_file);
00103   
00104   if (to_file->exists(&is_dir)) {
00105     if (is_dir) {
00106       to_file = CSPath::newPath(RETAIN(in_to_file), getNameCString());
00107       push_(to_file);
00108       
00109       if (to_file->exists(&is_dir)) { 
00110         if (!overwrite)
00111           CSException::throwFileError(CS_CONTEXT, to_file->getCString(), EEXIST);
00112         to_file->remove();
00113       }
00114     }
00115     else if (!overwrite)
00116       CSException::throwFileError(CS_CONTEXT, to_file->getCString(), EEXIST);
00117   }
00118 
00119   infile = openFile(CSFile::READONLY);
00120   push_(infile);
00121 
00122   outfile = to_file->createFile(CSFile::TRUNCATE);
00123   push_(outfile);
00124   
00125   CSStream::pipe(outfile->getOutputStream(), infile->getInputStream());
00126   release_(outfile);
00127   release_(infile);
00128   
00129   if (to_file != in_to_file)
00130     release_(to_file);
00131     
00132   release_(in_to_file);
00133   exit_();
00134 }
00135 
00136 void CSPath::makePath()
00137 {
00138   CSPath  *path;
00139   bool  is_dir;
00140 
00141   enter_();
00142   if (iPath->length() <= 1)
00143     exit_();
00144 
00145   if (exists(&is_dir)) {
00146     if (!is_dir)
00147       CSException::throwFileError(CS_CONTEXT, iPath, EEXIST);
00148     exit_();
00149   }
00150 
00151   path = CSPath::newPath(RETAIN(this), "..");
00152   push_(path);
00153   
00154   path->makePath();
00155   makeDir();
00156   
00157   release_(path);
00158 
00159   exit_();
00160 }
00161 
00162 /* Copy the contents of one directory to another.
00163  * The destination must be a directory.
00164  * The new source directory will be copied to
00165  * a directory of the same name in the destination.
00166  */
00167 void CSPath::copyDir(CSPath *in_to_dir, bool overwrite)
00168 {
00169   CSPath    *to_dir = in_to_dir;
00170   bool    is_dir;
00171   CSDirectory *dir = NULL;
00172   CSPath    *path = NULL;
00173 
00174   enter_();
00175   push_(in_to_dir);
00176   
00177   if (to_dir->exists(&is_dir)) {
00178     if (!is_dir)
00179       CSException::throwFileError(CS_CONTEXT, to_dir->getCString(), ENOTDIR);
00180     /* Add the source directory name to the destination: */
00181     to_dir = CSPath::newPath(RETAIN(in_to_dir), getNameCString());
00182     push_(to_dir);
00183     
00184     if (to_dir->exists(&is_dir)) {
00185       if (!overwrite)
00186         CSException::throwFileError(CS_CONTEXT, to_dir->getCString(), EEXIST);
00187       to_dir->remove();
00188     }
00189   }
00190  
00191   /* Make the directory and copy the contents of the source
00192    * into it:
00193    */
00194   to_dir->makePath();
00195 
00196   dir = openDirectory();
00197   push_(dir);
00198   while (dir->next()) {
00199     self->interrupted();
00200     path = CSPath::newPath(RETAIN(this), dir->name());
00201     push_(path);
00202     if (dir->isFile())
00203       path->copyFile(RETAIN(to_dir), overwrite);
00204     else
00205       path->copyDir(RETAIN(to_dir), overwrite);
00206     release_(path);
00207   }
00208   release_(dir);
00209   
00210   if (to_dir != in_to_dir)
00211     release_(to_dir);
00212     
00213   release_(in_to_dir);
00214   
00215   exit_();
00216 }
00217 
00218 
00219 bool CSPath::isLink()
00220 {
00221   bool link;
00222   enter_();
00223 
00224   link = sys_isLink(iPath->getCString());
00225   
00226   return_(link);
00227 }
00228 
00229 bool CSPath::isEmpty()
00230 {
00231   CSDirectory *dir = NULL;
00232   bool    is_dir, result = true;
00233 
00234   enter_();
00235   if (!exists(&is_dir))
00236     return_(true);
00237 
00238   if (!is_dir)
00239     return_(false);
00240 
00241   dir = openDirectory();
00242   push_(dir);
00243   
00244   if (dir->next())
00245     result = false;
00246 
00247   release_(dir);
00248   return_(result);
00249 }
00250 
00251 void CSPath::emptyDir()
00252 {
00253   CSDirectory *dir;
00254   CSPath    *path = NULL;
00255   bool    is_dir;
00256 
00257   enter_();
00258   if (!exists(&is_dir))
00259     exit_();
00260 
00261   if (!is_dir)
00262     CSException::throwFileError(CS_CONTEXT, iPath, ENOTDIR);
00263 
00264   dir = openDirectory();
00265   push_(dir);
00266 
00267   while (dir->next()) {
00268     path = CSPath::newPath(RETAIN(this), dir->name());
00269     push_(path);
00270     if (dir->isFile())
00271       path->remove();
00272     else
00273       path->removeDir();
00274     release_(path);
00275   }
00276 
00277   release_(dir);
00278   exit_();
00279 }
00280 
00281 void CSPath::emptyPath()
00282 {
00283   CSDirectory *dir;
00284   CSPath    *path = NULL;
00285   bool    is_dir;
00286 
00287   enter_();
00288   if (!exists(&is_dir))
00289     exit_();
00290 
00291   if (!is_dir)
00292     CSException::throwFileError(CS_CONTEXT, iPath, ENOTDIR);
00293 
00294   dir = openDirectory();
00295   push_(dir);
00296 
00297   while (dir->next()) {
00298     path = CSPath::newPath(RETAIN(this), dir->name());
00299     push_(path);
00300     if (dir->isFile())
00301       path->remove();
00302     else
00303       path->emptyPath();
00304     release_(path);
00305   }
00306 
00307   release_(dir);
00308   exit_();
00309 }
00310 
00311 void CSPath::copyTo(CSPath *to_path, bool overwrite)
00312 {
00313   bool is_dir;
00314 
00315   enter_();
00316   push_(to_path);
00317   if (!exists(&is_dir))
00318     CSException::throwFileError(CS_CONTEXT, iPath, ENOENT);
00319 
00320   pop_(to_path);
00321   if (is_dir)
00322     /* The source is a directory. */
00323     copyDir(to_path, overwrite);
00324   else {
00325     /* The source is not a directory: */
00326     copyFile(to_path, overwrite);
00327   }
00328 
00329   exit_();
00330 }
00331 
00332 void CSPath::moveTo(CSPath *in_to_path)
00333 {
00334   CSPath  *to_path = NULL;
00335   bool  is_dir;
00336 
00337   enter_();
00338   push_(in_to_path);
00339   
00340   if (!exists(NULL))
00341     CSException::throwFileError(CS_CONTEXT, iPath, ENOENT);
00342 
00343   if (in_to_path->exists(&is_dir)) {
00344     if (is_dir) {
00345       to_path = CSPath::newPath(RETAIN(in_to_path), getNameCString());
00346       push_(to_path);
00347       if (to_path->exists(NULL))
00348         CSException::throwFileError(CS_CONTEXT, to_path->getCString(), EEXIST);
00349       pop_(to_path);
00350     }
00351     else
00352       CSException::throwFileError(CS_CONTEXT, to_path->getCString(), ENOTDIR);
00353   } else
00354     to_path = RETAIN(in_to_path);
00355     
00356   move(to_path);
00357 
00358   release_(in_to_path);
00359   exit_();
00360 }
00361 
00362 void CSPath::remove()
00363 {
00364   bool is_dir;
00365 
00366   if (exists(&is_dir)) {
00367     if (is_dir) {
00368       emptyDir();
00369       removeDir();
00370     }
00371     else
00372       removeFile();
00373   }
00374 }
00375 
00376 
00377 void CSPath::touch(bool create_path)
00378 {
00379   CSFile *file;
00380 
00381   enter_();
00382   if (create_path)
00383     file = createFile(CSFile::READONLY);
00384   else
00385     file = openFile(CSFile::READONLY | CSFile::CREATE);
00386   file->release();
00387   exit_();
00388 }
00389 
00390 CSString *CSPath::getString()
00391 { 
00392   return iPath;
00393 }
00394 
00395 const char *CSPath::getCString()
00396 {
00397   return iPath->getCString();
00398 }
00399 
00400 const char *CSPath::getNameCString()
00401 {
00402   const char *str = getCString();
00403   
00404   return cs_last_name_of_path(str);
00405 }
00406 
00407 off64_t CSPath::getSize(const char *path)
00408 {
00409   off64_t size;
00410 
00411   info(path, NULL, &size, NULL);
00412   return size;
00413 }
00414 
00415 off64_t CSPath::getSize()
00416 {
00417   off64_t size;
00418 
00419   info((bool *) NULL, &size, (CSTime *) NULL);
00420   return size;
00421 }
00422 
00423 bool CSPath::isDir()
00424 {
00425   bool  is_dir;
00426 
00427   info(&is_dir, (off64_t *) NULL, (CSTime *) NULL);
00428   return is_dir;
00429 }
00430 
00431 bool CSPath::exists(bool *is_dir)
00432 {
00433   if (!sys_exists(iPath->getCString()))
00434     return false;
00435     
00436   if (is_dir)
00437     *is_dir = isDir();
00438   return true;
00439 }
00440 
00441 void CSPath::info(const char *path, bool *is_dir, off64_t *size, CSTime *mod_time)
00442 {
00443   sys_stat(path, is_dir, size, mod_time);
00444   
00445 }
00446 
00447 void CSPath::info(bool *is_dir, off64_t *size, CSTime *mod_time)
00448 {
00449   info(iPath->getCString(), is_dir, size, mod_time);
00450 }
00451 
00452 CSFile *CSPath::openFile(int mode)
00453 {
00454   CSFile *file;
00455 
00456   enter_();
00457   file = CSFile::newFile(RETAIN(this));
00458   push_(file);
00459   file->open(mode);
00460   pop_(file);
00461   return_(file);
00462 }
00463 
00464 void CSPath::removeFile()
00465 {
00466   sys_removeFile(iPath->getCString());
00467 }
00468 
00469 void CSPath::makeDir()
00470 {
00471   char path[PATH_MAX];
00472 
00473   cs_strcpy(PATH_MAX, path, iPath->getCString());
00474   cs_remove_dir_char(path);
00475 
00476   sys_makeDir(path);
00477 }
00478 
00479 CSDirectory *CSPath::openDirectory()
00480 {
00481   CSDirectory *dir;
00482 
00483   enter_();
00484   dir = CSDirectory::newDirectory(RETAIN(this));
00485   push_(dir);
00486   dir->open();
00487   pop_(dir);
00488   return_(dir);
00489 }
00490 
00491 void CSPath::removeDir()
00492 {     
00493   emptyDir();
00494   sys_removeDir(iPath->getCString());
00495 }
00496 
00497 void CSPath::rename(const char *name)
00498 {
00499   char new_path[PATH_MAX];
00500   CSString *tmp_path, *old_path = iPath;
00501   
00502   enter_();
00503   
00504   cs_strcpy(PATH_MAX, new_path, iPath->getCString());
00505   cs_remove_last_name_of_path(new_path);
00506   cs_add_dir_char(PATH_MAX, new_path);
00507   cs_strcat(PATH_MAX, new_path, name);
00508   
00509   lock_(&iRename_lock); // protect against race condition when testing if the new name exists yet or not. 
00510   if (sys_exists(new_path))
00511     CSException::throwFileError(CS_CONTEXT, new_path, EEXIST);
00512   
00513   tmp_path = CSString::newString(new_path);
00514   push_(tmp_path);
00515   
00516   sys_rename(iPath->getCString(), new_path);
00517     
00518   pop_(tmp_path);
00519   unlock_(&iRename_lock);
00520   
00521   old_path = iPath;
00522   iPath = tmp_path;
00523   
00524   old_path->release();
00525   exit_();
00526 }
00527 
00528 void CSPath::move(CSPath *to_path)
00529 {
00530   enter_();
00531   push_(to_path);
00532   lock_(&iRename_lock); // protect against race condition when testing if the new name exists yet or not. 
00533   if (to_path->exists())
00534     CSException::throwFileError(CS_CONTEXT, to_path->getCString(), EEXIST);
00535     
00536   /* Cannot move from TD to non-TD: */
00537   sys_rename(iPath->getCString(), to_path->getCString());
00538   unlock_(&iRename_lock);
00539   release_(to_path);
00540   exit_();
00541 }
00542 
00543 CSPath *CSPath::getCWD()
00544 {
00545   char path[PATH_MAX];
00546 
00547   sys_getcwd(path, PATH_MAX);
00548   return newPath(path);
00549 }
00550 
00551 CSPath *CSPath::newPath(const char *path)
00552 {
00553   if (!path)
00554     CSException::throwAssertion(CS_CONTEXT, "Initial string may not be NULL");
00555   return newPath(CSString::newString(path));
00556 }
00557 
00558 CSPath *CSPath::newPath(CSString *path)
00559 {
00560   CSPath *p;
00561 
00562   enter_();
00563   push_(path);
00564   new_(p, CSPath());
00565 
00566   /* Adjust the path string so that it does not have
00567    * a terminating CS_DIR_CHAR:
00568    */
00569   if (path->endsWith(CS_DIR_DELIM) && path->length() > 1) {
00570     p->iPath = path->left(CS_DIR_DELIM, -1);
00571     path->release();
00572   }
00573   else
00574     p->iPath = path;
00575   pop_(path);
00576   return_(p);
00577 }
00578 
00579 CSPath *CSPath::newPath(CSPath *cwd, const char *path)
00580 {
00581   char abs_path[PATH_MAX];
00582 
00583   enter_();
00584   cs_make_absolute_path(PATH_MAX, abs_path, path, cwd->getCString());
00585   cwd->release();
00586   CSPath *p = newPath(abs_path);
00587   return_(p);
00588 }
00589 
00590 CSPath *CSPath::newPath(CSString *cwd, const char *path)
00591 {
00592   char abs_path[PATH_MAX];
00593 
00594   enter_();
00595   cs_make_absolute_path(PATH_MAX, abs_path, path, cwd->getCString());
00596   cwd->release();
00597   CSPath *p = newPath(abs_path);
00598   return_(p);
00599 }
00600 
00601 CSPath *CSPath::newPath(const char *cwd, CSString *path)
00602 {
00603   char abs_path[PATH_MAX];
00604 
00605   enter_();
00606   cs_make_absolute_path(PATH_MAX, abs_path, path->getCString(), cwd);
00607   path->release();
00608   CSPath *p = newPath(abs_path);
00609   return_(p);
00610 }
00611 
00612 CSPath *CSPath::newPath(const char *cwd, const char *path)
00613 {
00614   char abs_path[PATH_MAX];
00615 
00616   enter_();
00617   cs_make_absolute_path(PATH_MAX, abs_path, path, cwd);
00618   CSPath *p = newPath(abs_path);
00619   return_(p);
00620 }
00621