"Fossies" - the Fresh Open Source Software Archive

Member "opengroupware-5.5rc3/DocumentAPI/OGoDatabaseProject/SkyProjectFileManager+Internals.m" (5 Dec 2015, 28831 Bytes) of package /linux/privat/opengroupware-5.5rc3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Matlab source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "SkyProjectFileManager+Internals.m": 5.5rc2_vs_5.5rc3.

    1 /*
    2   Copyright (C) 2000-2005 SKYRIX Software AG
    3 
    4   This file is part of OpenGroupware.org.
    5 
    6   OGo is free software; you can redistribute it and/or modify it under
    7   the terms of the GNU Lesser General Public License as published by the
    8   Free Software Foundation; either version 2, or (at your option) any
    9   later version.
   10 
   11   OGo is distributed in the hope that it will be useful, but WITHOUT ANY
   12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
   14   License for more details.
   15 
   16   You should have received a copy of the GNU Lesser General Public
   17   License along with OGo; see the file COPYING.  If not, write to the
   18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
   19   02111-1307, USA.
   20 */
   21 
   22 #include <OGoDatabaseProject/SkyProjectFileManager.h>
   23 #include <OGoDatabaseProject/SkyProjectFileManagerCache.h>
   24 #include <OGoProject/SkyContentHandler.h>
   25 
   26 @class NSString, NSMutableArray, NSArray, EOGenericRecord, NGHashMap;
   27 @class EOAdaptorChannel;
   28 
   29 static NSDictionary *er_dict(int _i) {
   30   return [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:_i]
   31                        forKey:@"errorNumber"];
   32 }
   33 
   34 @interface SkyProjectFileManager(DeleteDocument)
   35 - (BOOL)prepareDeletionOf:(NSDictionary *)_dict;
   36 - (BOOL)deleteVersions:(NSDictionary *)_attrs
   37   filesToRemove:(NSMutableArray *)_array;
   38 - (BOOL)deleteDocumentEditing:(NSDictionary *)_attrs
   39   filesToRemove:(NSMutableArray *)_array;
   40 - (BOOL)deleteDoc:(NSDictionary *)_attrs;
   41 - (BOOL)reallyDeleteFile:(NSDictionary *)_attrs;
   42 - (void)removeAllFiles:(NSArray *)_files;
   43 @end
   44 
   45 @interface SkyProjectFileManager(ErrorHandling_Internals)
   46 - (void)_initializeErrorDict;
   47 - (BOOL)_buildErrorWithSource:(NSString *)_src dest:(NSString *)_dest
   48   msg:(int)_msgId handler:(id)_handler cmd:(SEL)_sel;
   49 - (NSDictionary *)errorDict;
   50 - (BOOL)_buildErrorWithSource:(NSString *)_src dest:(NSString *)_dest
   51   msg:(int)_msgId handler:(id)_handler cmd:(SEL)_sel doFlush:(BOOL)_cache
   52   doRollback:(BOOL)_doRollback;
   53 @end /* SkyProjectFileManager(ErrorHandling+Internals) */
   54 
   55 @interface SkyProjectFileManager(Locking_Internals)
   56 - (NSArray *)allVersionAttributesAtPath:(NSString *)_path;
   57 @end /* SkyProjectFileManager(Locking_Internals) */
   58 
   59 @interface SkyProjectFileManager(Internals)
   60 - (void)_checkCWDFor:(NSString *)_source;
   61 - (id)_project;
   62 - (NSString *)_defaultCompleteProjectDocumentNamespace;
   63 - (NSArray *)subDirectoryNamesForPath:(NSString *)_path;
   64 - (NSString *)_makeAbsolute:(NSString *)_path;
   65 - (void)_subpathsAtPath:(NSString *)_path array:(NSMutableArray *)_array;
   66 - (BOOL)_copyPath:(NSString*)_src toPath:(NSString*)_dest handler:(id)_handler;
   67 
   68 - (BOOL)moveDir:(EOGenericRecord *)_srcGen
   69   toPath:(EOGenericRecord *)_destGen
   70   name:(NSString *)_dirName
   71   extension:(NSString *)_dirExt
   72   handler:(id)_handler;
   73 
   74 - (BOOL)moveDir:(EOGenericRecord *)_srcGen
   75   toPath:(EOGenericRecord *)_destGen
   76   name:(NSString *)_dirName
   77   extension:(NSString *)_dirExt
   78   handler:(id)_handler
   79   doFlush:(BOOL)_doFlush;
   80 
   81 - (BOOL)moveLink:(EOGenericRecord *)_srcGen
   82   toPath:(EOGenericRecord *)_destGen
   83   name:(NSString *)_linkName
   84   extension:(NSString *)_linkExt
   85   handler:(id)_handler;
   86 
   87 - (BOOL)moveLink:(EOGenericRecord *)_srcGen
   88   toPath:(EOGenericRecord *)_destGen
   89   name:(NSString *)_linkName
   90   extension:(NSString *)_linkExt
   91   handler:(id)_handler
   92   doFlush:(BOOL)_doFlush;
   93 
   94 - (BOOL)moveFile:(EOGenericRecord *)_srcGen
   95   toPath:(EOGenericRecord *)_destGen
   96   name:(NSString *)_fileName
   97   extension:(NSString *)_fileExt
   98   handler:(id)_handler;
   99 
  100 - (BOOL)moveFile:(EOGenericRecord *)_srcGen
  101   toPath:(EOGenericRecord *)_destGen
  102   name:(NSString *)_fileName
  103   extension:(NSString *)_fileExt
  104   handler:(id)_handler
  105   doFlush:(BOOL)_doFlush;
  106 
  107 @end /* SkyProjectFileManager(Internals) */
  108 
  109 @interface SkyProjectFileManagerCache(Internals)
  110 - (NGHashMap *)parent2ChildDirectoriesCache;
  111 - (EOAdaptorChannel *)beginTransaction;
  112 - (void)commitTransaction;
  113 - (void)rollbackTransaction;
  114 @end /* SkyProjectFileManagerCache(Internals) */
  115 
  116 @interface SkyProjectFileManager(Removing)
  117 - (BOOL)_removeFileAttrs:(NSArray *)_paths handler:(id)_handler
  118   failed:(BOOL*)failed_;
  119 - (BOOL)_removeFiles:(NSArray *)_fileAttrs handler:(id)_handler
  120   failed:(BOOL*)failed_;
  121 - (BOOL)_removeDirs:(NSArray *)_dirAttr handler:(id)_handler failed:(BOOL*)failed_;
  122 @end
  123 
  124 #include <OGoDatabaseProject/SkyProjectFileManagerCache.h>
  125 #include "common.h"
  126 
  127 @implementation SkyProjectFileManager(Internals)
  128 
  129 static NSNumber *yesNum = nil, *noNum = nil;
  130 static inline NSNumber *boolNum(BOOL value) {
  131   if (value) {
  132     if (yesNum == nil)
  133       yesNum = [[NSNumber numberWithBool:YES] retain];
  134     return yesNum;
  135   }
  136   else {
  137     if (noNum == nil)
  138       noNum = [[NSNumber numberWithBool:NO] retain];
  139     return noNum;
  140   }
  141 }
  142 
  143 - (void)_checkCWDFor:(NSString *)_source {
  144   if ([self->cwd isEqualToString: @"/"]) 
  145     return;
  146   if (![self->cwd hasPrefix:_source])
  147     return;
  148   
  149   ASSIGN(self->cwd, @"/");
  150 }
  151 
  152 - (id)_project {
  153   return [self->cache project];
  154 }
  155 
  156 - (NSString *)_defaultCompleteProjectDocumentNamespace {
  157   return @"{http://www.skyrix.com/namespaces/project-document}";
  158 }
  159 
  160 - (NSArray *)subDirectoryNamesForPath:(NSString *)_path {
  161   return [[self->cache parent2ChildDirectoriesCache] objectsForKey:_path];
  162 }
  163 
  164 - (NSString *)_makeAbsolute:(NSString *)_path {
  165   static Class NSStringClass = Nil;
  166   NSString *version;
  167   NSString *path;
  168   NSArray  *pathComponents;
  169   
  170 #if LIB_FOUNDATION_LIBRARY
  171   // TODO: hh asks: why is that?!
  172   _path = [_path stringByTrimmingWhiteSpaces];
  173 #else
  174   if (![_path isNotNull])
  175     return nil;
  176 #endif
  177   
  178   if (NSStringClass == Nil)
  179     NSStringClass = [NSString class];
  180   
  181   if (_path == nil) {
  182     NSLog(@"WARNING[%s]: missing path argument.", __PRETTY_FUNCTION__);
  183     return nil;
  184   }
  185   if (![_path isKindOfClass:NSStringClass])
  186     return nil;
  187   
  188   if ((version = [_path pathVersion]))
  189     _path = [_path stringByDeletingPathVersion];
  190   
  191   _path = ([_path isAbsolutePath] || ![_path isNotNull])
  192     ? _path
  193     : [[self currentDirectoryPath] stringByAppendingPathComponent:_path];
  194   
  195   if ([_path length] == 0)
  196     return @"/";
  197   
  198   while ([_path hasSuffix:@"/"]) {
  199     _path = [_path substringToIndex:([_path length] - 1)];
  200   }
  201   pathComponents = [_path pathComponents];
  202   
  203   if ([_path rangeOfString:@"."].length > 0) { /* skip '.' and '..' entries */
  204     int cnt = 0;
  205 
  206     if ((cnt = [pathComponents count]) > 0) {
  207       int i          = 0;
  208       int pnCnt      = 0;
  209       id  *pathNames = NULL;
  210 
  211       pathNames          = calloc(cnt + 1, sizeof(id));
  212       pathNames[pnCnt++] = @"/"; /* absolute path */
  213 
  214       for (i = 1; i < cnt; i++) {
  215         NSString *name = nil;
  216 
  217         name = [pathComponents objectAtIndex:i];
  218         if ([name isEqualToString:@"."] || ![name length])
  219         //        if ([name isEqualToString:@"."])        
  220           continue;
  221         if ([name isEqualToString:@".."]) {
  222           if (pnCnt > 1) /* first is '/' */
  223             pnCnt--;
  224           continue;
  225         }
  226         pathNames[pnCnt++] = name;
  227       }
  228       pathComponents = [NSArray arrayWithObjects:pathNames count:pnCnt];
  229       if (pathNames) free(pathNames); pathNames = NULL;
  230     }
  231     else
  232       return @"/";
  233   }
  234   if ([pathComponents count] == 0)
  235     return @"/";
  236   
  237   path = [NSString pathWithComponents:pathComponents];
  238   if (version)
  239     path = [path stringByAppendingPathVersion:version];
  240   
  241   return path;
  242 }
  243 
  244 - (BOOL)moveDir:(EOGenericRecord *)_srcGen
  245   toPath:(EOGenericRecord *)_destGen
  246   name:(NSString *)_dirName
  247   extension:(NSString *)_dirExt
  248   handler:(id)_handler
  249   doFlush:(BOOL)_doFlush
  250 {
  251   int ec;
  252 
  253   if (_dirName == nil) 
  254     _dirName = (id)[NSNull null];
  255 
  256   if (![_dirExt isNotNull])
  257     _dirExt = (id)[NSNull null];
  258   else if (![_dirExt length])
  259     _dirExt = (id)[NSNull null];
  260 
  261   if (_doFlush)
  262     [self flush];
  263   
  264   NS_DURING {
  265     ec = 0;
  266     [[self context] runCommand:@"doc::set-folder",
  267          @"object",   _srcGen,
  268          @"title",    _dirName,
  269          @"fileType", _dirExt,
  270          @"folder",   _destGen, nil];
  271   }
  272   NS_HANDLER {
  273     [self setLastException:localException];
  274     ec = 13;
  275   }
  276   NS_ENDHANDLER;
  277   if (ec) {
  278     return [self _buildErrorWithSource:nil dest:nil msg:ec handler:_handler
  279                  cmd:_cmd];
  280   }
  281   return YES;
  282 }
  283 
  284 - (BOOL)moveDir:(EOGenericRecord *)_srcGen
  285   toPath:(EOGenericRecord *)_destGen
  286   name:(NSString *)_dirName
  287   extension:(NSString *)_dirExt
  288   handler:(id)_handler
  289 {
  290   return [self moveDir:_srcGen toPath:_destGen name:_dirName
  291                extension:_dirExt handler:_handler doFlush:YES];
  292 }
  293 
  294 - (BOOL)moveLink:(EOGenericRecord *)_srcGen
  295   toPath:(EOGenericRecord *)_destGen
  296   name:(NSString *)_linkName
  297   extension:(NSString *)_linkExt
  298   handler:(id)_handler
  299   doFlush:(BOOL)_doFlush
  300 {
  301   int ec;
  302   
  303   if (_linkName == nil) 
  304     _linkName = (id)[NSNull null];
  305 
  306   if (![_linkExt isNotNull])
  307     _linkExt = (id)[NSNull null];
  308   else if (![_linkExt length])
  309     _linkExt = (id)[NSNull null];
  310 
  311   if (_doFlush)  
  312     [self flush];
  313   
  314   NS_DURING {
  315     ec = 0;
  316     [[self context] runCommand:@"doc::set-object-link",
  317          @"object",   _srcGen,
  318          @"title",    _linkName,
  319          @"fileType", _linkExt,
  320          @"folder",   _destGen, nil];
  321   }
  322   NS_HANDLER {
  323     ec = 14;
  324     [self setLastException:localException];
  325   }
  326   NS_ENDHANDLER;
  327   if (ec)
  328     return [self _buildErrorWithSource:nil dest:nil msg:ec handler:_handler
  329                  cmd:_cmd];
  330   return YES;
  331 }
  332 
  333 - (BOOL)moveLink:(EOGenericRecord *)_srcGen
  334   toPath:(EOGenericRecord *)_destGen
  335   name:(NSString *)_linkName
  336   extension:(NSString *)_linkExt
  337   handler:(id)_handler
  338 {
  339   return [self moveLink:_srcGen toPath:_destGen name:_linkName extension:_linkExt
  340                handler:_handler doFlush:YES];
  341 }
  342 
  343 - (BOOL)moveFile:(EOGenericRecord *)_srcGen
  344   toPath:(EOGenericRecord *)_destGen
  345   name:(NSString *)_fileName
  346   extension:(NSString *)_fileExt
  347   handler:(id)_handler
  348   doFlush:(BOOL)_doFlush
  349 {
  350   int      ec;
  351   BOOL     checkin;
  352   NSString *title, *ext;
  353   id       doc;
  354 
  355   title = [SkyProjectFileManager formatTitle:[_srcGen valueForKey:@"title"]];
  356 
  357   if (![title isNotNull])
  358     title = (id)[NSNull null];
  359 
  360   ext = [_srcGen valueForKey:@"fileType"];
  361 
  362   if (![ext isNotNull])
  363     ext = (id)[NSNull null];
  364   else if (![ext length])
  365     ext = (id)[NSNull null];
  366     
  367   if (![_fileName isNotNull]) 
  368     _fileName = (id)[NSNull null];
  369 
  370   if (_fileExt == nil || [_fileExt length] == 0)
  371     return [self _buildErrorWithSource:nil dest:nil msg:15
  372                  handler:_handler cmd:_cmd];
  373 
  374   if (_doFlush)
  375     [self flush];
  376   
  377   checkin = NO;
  378   doc     = nil;
  379   if (![_fileName isEqual:title] || ![_fileExt isEqual:ext]) {
  380     if ([[_srcGen valueForKey:@"status"] isEqualToString:@"released"]) {
  381       /* now checkout */
  382       checkin = YES;
  383 
  384       NS_DURING {
  385         ec      = 0;
  386         doc     = [[self context] runCommand:@"doc::checkout",
  387                        @"object", _srcGen, nil];
  388         _srcGen = [doc valueForKey:@"toDocumentEditing"];
  389       }
  390       NS_HANDLER {
  391         ec = 16;
  392         [self setLastException:localException];
  393       }
  394       NS_ENDHANDLER;
  395       if (ec)
  396         return [self _buildErrorWithSource:nil dest:nil msg:ec handler:_handler
  397                      cmd:_cmd];
  398     }
  399     NS_DURING {
  400       ec      = 0;
  401       if ([_srcGen isNotNull])
  402         _srcGen = [[self context] runCommand:@"doc::set",
  403                                   @"object", _srcGen,
  404                                   @"title", _fileName,
  405                                   @"fileType", _fileExt, nil];
  406       else
  407         ec = 4;
  408     }
  409     NS_HANDLER {
  410       ec = 17; 
  411       [self setLastException:localException];
  412     }
  413     NS_ENDHANDLER;
  414     if (ec)
  415       return [self _buildErrorWithSource:nil dest:nil msg:ec handler:_handler
  416                    cmd:_cmd];
  417   
  418     if (checkin) {
  419       NS_DURING {
  420         ec = 0;
  421         if ([doc isNotNull])
  422           [[self context] runCommand:@"doc::release", @"object", doc, nil];
  423         else
  424           ec = 4;
  425       }
  426       NS_HANDLER {
  427         ec = 18;
  428         [self setLastException:localException];
  429       }
  430       NS_ENDHANDLER;
  431       if (ec)
  432         return [self _buildErrorWithSource:nil dest:nil msg:ec handler:_handler
  433                      cmd:_cmd];
  434     }
  435   }
  436   if (doc == nil) {
  437     doc = (![[_srcGen entityName] isEqualToString:@"Doc"])
  438       ? [_srcGen valueForKey:@"toDoc"]
  439       : (id)_srcGen;
  440   }
  441   
  442   if (![[doc valueForKey:@"parentDocumentId"]
  443             isEqual:[_destGen valueForKey:@"documentId"]]) {
  444     NS_DURING {
  445       ec = 0;
  446       if ([doc isNotNull]) 
  447         [[self context] runCommand:@"doc::move", @"object", doc,
  448                         @"folder", _destGen, nil];
  449       else
  450         ec = 4;
  451     }
  452     NS_HANDLER {
  453       ec = 19;
  454       [self setLastException:localException];
  455     }
  456     NS_ENDHANDLER;
  457     if (ec)
  458       return [self _buildErrorWithSource:nil dest:nil msg:ec handler:_handler
  459                    cmd:_cmd];
  460   }
  461   return YES;
  462 }
  463 
  464 - (BOOL)moveFile:(EOGenericRecord *)_srcGen
  465   toPath:(EOGenericRecord *)_destGen
  466   name:(NSString *)_fileName
  467   extension:(NSString *)_fileExt
  468   handler:(id)_handler
  469 {
  470   return [self moveFile:_srcGen toPath:_destGen name:_fileName extension:_fileExt
  471                handler:_handler doFlush:YES];
  472 }
  473 
  474 - (void)_subpathsAtPath:(NSString *)_path
  475   array:(NSMutableArray *)_array
  476 {
  477   NSDictionary *attrs;
  478 
  479   if (_array == nil) {
  480     NSLog(@"ERROR[%s] internal inconsistency ...", __PRETTY_FUNCTION__);
  481     return;
  482   }
  483   attrs  = [self fileAttributesAtPath:_path traverseLink:NO];
  484   
  485   if ([[attrs objectForKey:NSFileType] isEqualToString:NSFileTypeDirectory]) {
  486     NSEnumerator *enumerator;
  487     NSDictionary *obj;
  488 
  489     enumerator = [[self->cache childAttributesAtPath:_path manager:self]
  490                                objectEnumerator];
  491 
  492     while ((obj = [enumerator nextObject])) {
  493       NSString *path;
  494 
  495       path = [obj objectForKey:NSFilePath];
  496       [_array addObject:path];
  497       if ([[obj objectForKey:NSFileType] isEqualToString:NSFileTypeDirectory])
  498         [self _subpathsAtPath:path array:_array];
  499     }
  500   }
  501 }
  502 
  503 /* got absolute paths */
  504 - (BOOL)_copyPath:(NSString*)_src
  505   toPath:(NSString*)_dest
  506   handler:(id)_handler
  507 {
  508   BOOL         srcIsFolder;
  509   NSDictionary *attrs;
  510   NSEnumerator *enumerator;
  511   NSArray      *contents;
  512 
  513   srcIsFolder = NO;
  514   if (![self fileExistsAtPath:_src isDirectory:&srcIsFolder]) {
  515     return [self _buildErrorWithSource:_src dest:_dest msg:4 handler:_handler
  516                  cmd:_cmd];
  517   }
  518   if (!srcIsFolder) {
  519     return [self _buildErrorWithSource:_src dest:_dest msg:32 handler:_handler
  520                  cmd:_cmd];
  521   }
  522   if (!(_dest = [self _makeAbsolute:_dest])) {
  523     return [self _buildErrorWithSource:_dest dest:nil msg:20 handler:_handler
  524                  cmd:_cmd];
  525   }
  526   if ([self fileExistsAtPath:_dest isDirectory:NULL]) {
  527     return [self _buildErrorWithSource:_src dest:_dest msg:7 handler:_handler
  528                  cmd:_cmd];
  529   }
  530   if (!(attrs = [self fileAttributesAtPath:_src traverseLink:NO])) {
  531     return [self _buildErrorWithSource:_src dest:_dest msg:6 handler:_handler
  532                  cmd:_cmd];
  533   }
  534   if (![self createDirectoryAtPath:_dest attributes:attrs]) {
  535     return NO;
  536   }
  537   contents   = [self->cache childAttributesAtPath:_src manager:self];
  538   enumerator = [contents objectEnumerator];
  539   {
  540     NSMutableDictionary *dict;
  541     id                  keys[3];
  542 
  543     keys[0] = @"contentHandler";
  544     keys[1] = @"attributes";
  545     keys[2] = @"sourceGID";
  546     dict    = [NSMutableDictionary dictionaryWithCapacity:[contents count]];
  547 
  548     while ((attrs = [enumerator nextObject])) {
  549       if ([[attrs objectForKey:NSFileType] isEqualToString:NSFileTypeDirectory]) {
  550         if (![self _copyPath:[attrs objectForKey:NSFilePath]
  551                    toPath:[_dest stringByAppendingPathComponent:
  552                                  [attrs objectForKey:NSFileName]] handler:_handler]) {
  553           return NO;
  554         }
  555       }
  556       else if ([[attrs objectForKey:NSFileType]
  557                        isEqualToString:NSFileTypeSymbolicLink]) {
  558         if (![self createSymbolicLinkAtPath:
  559                    [_dest stringByAppendingPathComponent:
  560                           [attrs objectForKey:NSFileName]]
  561                    pathContent:[attrs objectForKey:@"SkyLinkTarget"]])
  562           return NO;
  563                    
  564       }
  565       else if ([[attrs objectForKey:NSFileType] isEqualToString:NSFileTypeRegular]) {
  566         NSDictionary *d;
  567         id vals[3];
  568 
  569         vals[0] = [self blobHandlerAtPath:[attrs objectForKey:NSFilePath]];
  570         vals[1] = attrs;
  571         vals[2] = [attrs objectForKey:@"globalID"];
  572 
  573         d       = [NSDictionary dictionaryWithObjects:vals forKeys:keys count:3];
  574         [dict setObject:d forKey:[attrs objectForKey:NSFileName]];
  575       }
  576     }
  577     if (![self createFiles:dict atPath:_dest]) {
  578       return NO;
  579     }
  580   }
  581   [self postChangeNotificationForPath:
  582         [_dest stringByDeletingLastPathComponent]];
  583   return YES;
  584 }
  585 
  586 @end /* SkyProjectFileManager(Internals) */
  587 
  588 @implementation SkyProjectFileManager(ErrorHandling_Internals)
  589 
  590 static NSDictionary *errorDict = NULL;
  591 
  592 static NSNumber *num(int _i) {
  593   return [NSNumber numberWithInt:_i];
  594 }
  595 
  596 - (void)_initializeErrorDict {
  597   if (!errorDict) {
  598     errorDict =
  599       [[NSDictionary alloc]
  600                      initWithObjectsAndKeys:
  601                      @"try to move from/to version",                      num(1),
  602                      @"try to move root folder",                          num(2),
  603                      @"try to move do descendant",                        num(3),
  604                      @"missing source",                                   num(4),
  605                      @"missing destination",                              num(5),
  606                      @"source path doesn`t exist",                        num(6),
  607                      @"destination path already exist",                   num(7),
  608                      @"missing global id for parent folder",              num(8),
  609                      @"missing access for move",                          num(9),
  610                      @"only current owner or root can move edited files", num(10),
  611                      @"missing access for insert",                        num(11),
  612                      @"move failed",                                      num(12),
  613                      @"doc::set-folder failed",                           num(13),
  614                      @"doc::set-object-link failed",                      num(14),
  615                      @"missing path extension",                           num(15),
  616                      @"doc::checkout failed",                             num(16),
  617                      @"doc::set failed",                                  num(17),
  618                      @"doc::release failed",                              num(18),
  619                      @"doc::move failed",                                 num(19),
  620                      @"missing file",                                     num(20),
  621                      @"missing access for delete",                        num(21),
  622                      @"couldn`t delete",                                  num(22),
  623                      @"only current owner or root can delete edited files",
  624                      num(23),
  625                      @"path isn`t a directory",                           num(24),
  626                      @"couldn't create file",                             num(25),
  627                      @"missing target",                                   num(26),
  628                      @"missing directory",                                num(27),
  629                      @"couldn`t create link",                             num(28),
  630                      @"missing access for read",                          num(29),
  631                      @"directories or symbolic links has no content",     num(30),
  632                      @"try to copy do descendant",                        num(31),
  633                      @"source is a folder",                               num(32),
  634                      @"couldn't create directory",                        num(33),
  635                      @"missing path",                                     num(34),
  636                      @"missing access for write",                         num(35),
  637                      @"operation is not allowed for versions",            num(36),
  638                      @"only current owner or root can edit edited files", num(37),
  639                      @"unsupported file attributes",                      num(38),
  640                      @"missing doc",                                      num(39),
  641                      @"uncomplete document",                              num(40),
  642                      @"couldn`t autocreate document",                     num(41),
  643                      @"couldn`t delete tmp file after exception",         num(42),
  644                      @"missing propertymanager",                          num(43),
  645                      @"missing globalID",                                 num(44),
  646                      @"error during add properties",                      num(45),
  647                      @"error during delete properties",                   num(46),
  648                      @"error during update properties",                   num(47),
  649                      @"couldn`t checkout directory",                      num(48),
  650                      @"file is already in edit mode",                     num(49),
  651                      @"doc::checkout failed",                             num(50),
  652                      @"file is already released",                         num(51),
  653                      @"doc::release failed",                              num(52),
  654                      @"doc::reject failed",                               num(53),
  655                      @"missing version",                                  num(54),
  656                      @"documentversion::checkout failed",                 num(55),
  657                      @"missing blob name",                                num(56),
  658                      @"reject failed after doc::set failed",              num(57),
  659                      @"source path isn`t a directory",                    num(58),
  660                      @"destination path isn`t a directory",              num(59),
  661                      nil];
  662   }
  663 }
  664 
  665 - (NSDictionary *)errorDict {
  666   if (!errorDict)
  667     [self _initializeErrorDict];
  668   return errorDict;
  669 }
  670 
  671 static BOOL logError_value = NO;
  672 static BOOL logError_flag  = NO;
  673 
  674 static inline BOOL _logError(id self) {
  675   if (!logError_flag) {
  676     logError_flag  = YES;
  677     logError_value =
  678       [[NSUserDefaults standardUserDefaults]
  679                        boolForKey:@"SkyProjectFileManagerErrorLogEnabled"];
  680   }
  681   return logError_value;
  682 }
  683 
  684 static BOOL abortError_value = NO;
  685 static BOOL abortError_flag  = NO;
  686 
  687 static inline BOOL _abortError(id self) {
  688   if (!abortError_flag) {
  689     abortError_flag  = YES;
  690     abortError_value =
  691       [[NSUserDefaults standardUserDefaults]
  692                        boolForKey:@"SkyProjectFileManagerAbortOnErrors"];
  693   }
  694   return abortError_value;
  695 }
  696 
  697 - (BOOL)_buildErrorWithSource:(NSString *)_src dest:(NSString *)_dest
  698   msg:(int)_msgId handler:(id)_handler cmd:(SEL)_sel
  699 {
  700   return [self _buildErrorWithSource:_src dest:_dest msg:_msgId handler:_handler
  701                cmd:_sel doFlush:YES doRollback:YES];
  702 }
  703 
  704 - (BOOL)_buildErrorWithSource:(NSString *)_src dest:(NSString *)_dest
  705   msg:(int)_msgId handler:(id)_handler cmd:(SEL)_sel doFlush:(BOOL)_doFlush
  706   doRollback:(BOOL)_doRollback
  707 {
  708   NSString     *errMsg;
  709 
  710   self->lastErrorCode = _msgId;
  711   errMsg              = [[self errorDict] objectForKey:num(_msgId)];
  712   
  713   if (_handler != nil) {
  714     id           obj[3];
  715     id           key[3];
  716     int          cnt     = 0;
  717     NSDictionary *errMsg = nil;
  718     
  719     if (_src != nil) {
  720       obj[cnt] = _src;
  721       key[cnt] = @"Path";
  722       cnt++;
  723     }
  724     if (_dest != nil) {
  725       obj[cnt] = _dest;
  726       key[cnt] = @"toPath";
  727       cnt++;
  728     }
  729     if (errMsg != nil) {
  730       obj[cnt] = errMsg;
  731       key[cnt] = @"Error";
  732       cnt++;
  733     }
  734     if (_msgId) {
  735       obj[cnt] = num(_msgId);
  736       key[cnt] = @"ErrorCode";
  737       cnt++;
  738     }
  739     errMsg = [NSDictionary dictionaryWithObjects:obj forKeys:key count:cnt];
  740 
  741     if ([_handler respondsToSelector:
  742                   @selector(fileManager:shouldProceedAfterError:)]) {
  743       if ([_handler fileManager:(id)self shouldProceedAfterError:errMsg]) {
  744         return YES;
  745       }
  746     }
  747   }
  748   if (_logError(self) || _abortError(self)) {
  749     NSLog(@"ERROR(%@): _src <%@> _dest <%@> msgCode <%d> msg <%@> "
  750           @"handler <%@> exception: %@",
  751       NSStringFromSelector(_sel), _src, _dest,
  752           _msgId, errMsg, _handler, self->lastException);
  753   }
  754   if (_abortError(self))
  755     abort();
  756   
  757   if (_doRollback)
  758     [self->cache rollbackTransaction];
  759 
  760   if (_doFlush)
  761     [self flush];
  762   
  763   return NO;
  764 }
  765 
  766 @end /* SkyProjectFileManager(ErrorHandling+Internals) */
  767 
  768 @implementation SkyProjectFileManager(Locking_Internals)
  769 
  770 - (NSArray *)allVersionAttributesAtPath:(NSString *)_path {
  771   return [self->cache allVersionAttrsAtPath:_path manager:self];
  772 }
  773 
  774 @end /* SkyProjectFileManager(Locking_Internals) */
  775 
  776 @implementation SkyProjectFileManager(Removing)
  777 
  778 - (BOOL)_removeFileAttrs:(NSArray *)_paths handler:(id)_handler failed:(BOOL*)failed_
  779 {
  780   NSMutableArray *files;
  781   NSMutableArray *dirs;
  782   NSEnumerator   *enumerator;
  783   NSDictionary   *attrs;
  784 
  785   enumerator = [_paths objectEnumerator];
  786 
  787   files = [NSMutableArray array];
  788   dirs  = [NSMutableArray array];
  789   
  790   while ((attrs = [enumerator nextObject])) {
  791 
  792     if ([[attrs objectForKey:NSFileType] isEqual:NSFileTypeDirectory]) {
  793       [dirs addObject:attrs];
  794     }
  795     else {
  796       [files addObject:attrs];
  797     }
  798   }
  799   if (![self _removeFiles:files handler:_handler failed:failed_]) {
  800     return NO;
  801   }
  802   if (![self _removeDirs:dirs handler:_handler failed:failed_]) {
  803     return NO;
  804   }
  805   return YES;
  806 }
  807 
  808 - (BOOL)_removeFiles:(NSArray *)_fileAttrs handler:(id)_handler failed:(BOOL*)failed_
  809 {
  810   NSEnumerator *enumerator;
  811   NSDictionary *attrs;
  812   id           handler;
  813 
  814   if (failed_)
  815     *failed_ = NO;
  816   
  817   handler = nil;
  818   if ([_handler respondsToSelector:
  819                 @selector(fileManager:shouldProceedAfterError:)]) {
  820     handler = _handler;
  821   }
  822     
  823   enumerator = [_fileAttrs objectEnumerator];
  824 
  825   while ((attrs = [enumerator nextObject])) {
  826     NSString *_path;
  827     int      ec;
  828 
  829     _path = [attrs objectForKey:NSFilePath];
  830     
  831     if ([[attrs objectForKey:@"SkyStatus"] isEqualToString:@"edited"]) {
  832       id a, aid;
  833 
  834       a   = [[self context] valueForKey:LSAccountKey];
  835       aid = [a valueForKey:@"companyId"];
  836 
  837       if (![[attrs objectForKey:@"SkyOwnerId"] isEqual:aid] &&
  838           ([aid intValue] != 10000)) {
  839         if (![handler fileManager:(id)self 
  840               shouldProceedAfterError:er_dict(23)]) {
  841           return NO;
  842         }
  843         if (failed_)
  844           *failed_ = YES;
  845 
  846         return YES;
  847       }
  848     }
  849     NS_DURING {
  850       ec = 0;
  851 #if 1
  852       if (![self reallyDeleteFile:attrs])
  853         ec = 22;
  854 #else
  855       id d;
  856       if ((d = [self->cache genericRecordForAttrs:attrs manager:self])) {
  857 
  858         if ([[d entityName] isEqualToString:@"DocumentEditing"]) {
  859           d = [d valueForKey:@"toDoc"];
  860         }
  861         [[self context] runCommand:@"doc::delete",
  862                         @"object", d,
  863                         @"reallyDelete", [NSNumber numberWithBool:YES], nil];
  864       }
  865       else {
  866         ec = 22;
  867       }
  868 #endif    
  869     }
  870     NS_HANDLER {
  871       ec = 22;
  872       [self setLastException:localException];
  873       [self _buildErrorWithSource:_path dest:nil msg:ec handler:_handler
  874             cmd:_cmd];
  875     }
  876     NS_ENDHANDLER;
  877 
  878     if (ec) {
  879       if (![_handler fileManager:(id)self shouldProceedAfterError:er_dict(23)]) {
  880         return NO;
  881       }
  882       if (failed_)
  883         *failed_ = YES;
  884     }
  885     [self postChangeNotificationForPath:[_path stringByDeletingLastPathComponent]];
  886     [self postUnvalidateNotificationForPath:_path];
  887     [self postSkyGlobalIDWasDeleted:[attrs objectForKey:@"globalID"]];
  888   }
  889   return YES;
  890 }
  891 
  892 - (BOOL)_removeDirs:(NSArray *)_dirAttr handler:(id)_handler failed:(BOOL*)failed_ {
  893   NSEnumerator   *enumerator;
  894   NSDictionary   *attrs;
  895   NSMutableArray *dirs;
  896 
  897   dirs       = [NSMutableArray arrayWithCapacity:[_dirAttr count]];
  898   enumerator = [_dirAttr objectEnumerator];
  899 
  900   while ((attrs = [enumerator nextObject])) {
  901     NSArray *files;
  902     BOOL    failed;
  903 
  904     files = [self->cache childAttributesAtPath:[attrs objectForKey:NSFilePath]
  905                  manager:self];
  906 
  907     if (![self _removeFileAttrs:files handler:_handler failed:&failed])
  908       return NO;
  909 
  910     if (failed)
  911       continue;
  912 
  913     [dirs addObject:attrs];
  914   }
  915   return [self _removeFiles:dirs handler:_handler failed:failed_];
  916 }
  917 
  918 @end /* SkyProjectFileManager(Removing) */