Index: trunk/dasscm/dasscm
===================================================================
--- trunk/dasscm/dasscm	(revision 214)
+++ trunk/dasscm/dasscm	(revision 215)
@@ -12,5 +12,4 @@
 use File::Compare;
 use File::Copy;
-use File::Find;
 use File::stat;
 use File::Path;
@@ -28,4 +27,7 @@
 #
 
+# file to store permissions
+my $permissions_file = "/etc/permissions.d/dasscm.permission_backup";
+# configuration file
 my $config_file = "/etc/dasscm.conf";
 my $config      = ConfigFile::read_config_file($config_file);
@@ -47,7 +49,4 @@
 my $verbose = 0;
 
-# stores result from status (cvscheck)
-my %status_removedfiles = ();
-my %status_changedfiles = ();
 
 #####################################################################
@@ -62,11 +61,14 @@
     print "\n";
     print "Available subcommands:\n";
+    print "   help <subcommand>\n";
     print "   init\n";
     print "   login\n";
+    print "   up\n";
+    print "   ls\n";
     print "   add <filename>\n";
     print "   commit <filename>\n";
     print "   status <filename>\n";
     print "   diff <filename>\n";
-    print "   help <subcommand>\n";
+    print "   permissions\n";
     print "\n";
     print "preperation:\n";
@@ -108,5 +110,5 @@
         }
     }
-    print "DASSCM_REPO: " . $DASSCM_REPO . "\n";
+    if ($verbose) { print "DASSCM_REPO: " . $DASSCM_REPO . "\n"; }
 
     #
@@ -186,38 +188,51 @@
 }
 
-#
-# used by status
-# checks for differences between PROD and (local) REPO
-#
-sub cvscheck
-{
-    return unless -f;    # keine Directories
-    return if $File::Find::dir =~ /\/CVS$/;    # ignoriere CVS-Verzeichnisse
-    return
-      if $File::Find::dir =~
-      /\/\.svn/; # ignoriere Subversion Verzeichnisse (inkl. Unterverzeichnisse)
-    my $cvsworkfile = "$File::Find::dir/$_";
-
-    # Ursprungspfad ermitteln
-    # TODO: get_filename ?
-    $cvsworkfile =~ /${DASSCM_REPO}\/(.+)/;
-    my $realfile = "/" . $1;
-
-    # relativer Pfad zur CVS-Arbeitsdatei
-    my $relcvsworkfile = $1;
-
-    if ( !-r $realfile ) {
-        $status_removedfiles{"$realfile"} = $cvsworkfile;
-    } else {
-        ( -r "$cvsworkfile" ) || die("Fehler: $cvsworkfile ist nicht lesbar");
-        if ( compare( $cvsworkfile, $realfile ) != 0 ) {
-
-            # Dateien unterscheiden sich
-            #(-w $cvsworkfile) || die("failed: no Fehler: kein Schreibrecht auf $cvsworkfile");
-            # Arbeitskopie durch Kopie ersetzen
-            #copy($realfile,$cvsworkfile) || die("Fehler beim kopieren $realfile --> $cvsworkfile");
-            $status_changedfiles{"$realfile"} = $cvsworkfile;
-        }
-    }
+
+
+sub generatePermissionList
+{
+
+    # generieren der Zeilen für Permission-Savefile
+    my @files    = @_;
+    my @permlist = ();
+    foreach my $file (@files) {
+        my $info       = stat( "/" . $file ) || die "$file: stat error";
+        my $mode       = get_type( $info->mode ) & 07777;
+        my $modestring = sprintf( "%04o", $mode );
+        my $uid        = $info->uid;
+        my $uidname    = getpwuid($uid);
+        my $gid        = $info->gid;
+        my $gidname    = getgrgid($gid);
+        push(
+            @permlist,
+            sprintf( "%-55s %-17s %4d",
+                $file, "${uidname}:${gidname}", $modestring )
+        );
+    }
+    return @permlist;
+}
+
+sub get_type
+{
+
+    # Funktion übernommen aus /usr/bin/chkstat
+    my $S_IFLNK  = 0120000;    # symbolic link
+    my $S_IFREG  = 0100000;    # regular file
+    my $S_IFDIR  = 0040000;    # directory
+    my $S_IFCHAR = 0020000;    # character device
+    my $S_IFBLK  = 0060000;    # block device
+    my $S_IFFIFO = 0010000;    # fifo
+    my $S_IFSOCK = 0140000;    # socket
+    my $S_IFMT   = 0170000;    # type of file
+
+    my $S_m;
+    if    ( ( $_[0] & $S_IFMT ) == $S_IFLNK )  { $S_m = $_[0] - $S_IFLNK; }
+    elsif ( ( $_[0] & $S_IFMT ) == $S_IFREG )  { $S_m = $_[0] - $S_IFREG; }
+    elsif ( ( $_[0] & $S_IFMT ) == $S_IFDIR )  { $S_m = $_[0] - $S_IFDIR; }
+    elsif ( ( $_[0] & $S_IFMT ) == $S_IFCHAR ) { $S_m = $_[0] - $S_IFCHAR; }
+    elsif ( ( $_[0] & $S_IFMT ) == $S_IFBLK )  { $S_m = $_[0] - $S_IFBLK; }
+    elsif ( ( $_[0] & $S_IFMT ) == $S_IFFIFO ) { $S_m = $_[0] - $S_IFFIFO; }
+    elsif ( ( $_[0] & $S_IFMT ) == $S_IFSOCK ) { $S_m = $_[0] - $S_IFSOCK; }
+    $S_m;
 }
 
@@ -271,5 +286,4 @@
 
     if ( $rc_update != 0 ) {
-        print @result;
         die;
     }
@@ -282,11 +296,25 @@
     ( my $rc_update, my @result ) =
       run_command("$SVN update $svnCheckoutCredentials $update_path");
+    print @result;
     if ( $rc_update != 0 ) {
+        die;
+    }
+}
+
+sub svn_getStoredFiles( ;$ )
+{
+
+    # TODO: get_filenames?
+    #my $rel_path = shift || "";
+    #my $path = "${DASSCM_REPO}/${rel_path}";
+    my $path = ${DASSCM_REPO};
+    ( my $rc, my @result ) =
+      run_command("$SVN ls --recursive $svnCheckoutCredentials $path");
+    if ( $rc != 0 ) {
         print @result;
         die;
     }
-
-    print @result;
-
+    chomp(@result);
+    return @result;
 }
 
@@ -358,12 +386,30 @@
 }
 
-#
-# add (is used for command add and commit)
-#
-sub add(@)
-{
-    check_parameter( @_, 1 );
-    check_env();
-
+sub ls(@)
+{
+    check_parameter( @_, 1 );
+    check_env();
+
+    my @files = svn_getStoredFiles(@_);
+
+    print join( "\n", @files );
+    print "\n";
+}
+
+
+sub update(@)
+{
+    check_parameter( @_, 1 );
+    check_env();
+
+    #
+    # update local repository
+    #
+    svn_update();
+}
+
+
+sub add_helper(@)
+{
     (
         my $basename,
@@ -379,7 +425,4 @@
     }
 
-    # update complete repository
-    my $retcode = run_interactive("$SVN update $svnOptions $DASSCM_REPO");
-
     copy( $filename_prod, $filename_repo ) or die $!;
 
@@ -398,4 +441,27 @@
         run_command("$SVN add $basename");
     }
+}
+
+
+
+#
+# add (is used for command add and commit)
+#
+sub add(@)
+{
+    check_parameter( @_, 1 );
+    check_env();
+
+    #
+    # update local repository
+    #
+    svn_update();
+
+    # add file
+    add_helper( $_[0] );
+    # create new permissions file
+    permissions();
+    # add permissions file
+    add_helper( $permissions_file );
 
     if ( $options{'message'} ) {
@@ -404,12 +470,14 @@
 
     # commit calls $EDITOR. uses "interactive" here, to display output
-    $retcode =
+    my $retcode =
       run_interactive(
         "$SVN commit $svnOptions --username $DASSCM_USERNAME $svnPasswordCredentials $DASSCM_REPO"
       );
 
-    print $filename_prod. "\n";
-    print $dirname_repo. "\n";
-}
+    #print $filename_prod. "\n";
+    #print $dirname_repo. "\n";
+}
+
+
 
 sub blame(@)
@@ -468,16 +536,36 @@
 
     # TODO: start at subdirectories ?
-    my $cvsworkdir = $DASSCM_REPO;
-
-    File::Find::find( \&cvscheck, $cvsworkdir );
+    my $dir = $DASSCM_REPO;
+    my @files = svn_getStoredFiles($dir);
 
     # Liste der geänderten Files ausgeben, falls nicht leer
-    # Anzahl Elemente im Hash???
-    my @changedfiles = keys %status_changedfiles;
-
-    if ( %status_changedfiles or %status_removedfiles ) {
-        if (%status_removedfiles) {
-            print "deleted files:\n";
-            foreach my $key ( values %status_removedfiles ) {
+    if (@files) {
+
+        # stores result from status (cvscheck)
+        my %removedfiles = ();
+        my %changedfiles = ();
+
+        foreach my $file (@files) {
+
+            my $realfile    = "/" . $file;
+            my $cvsworkfile = "${DASSCM_REPO}/${file}";
+
+            if ( -d $realfile ) {
+
+                # directory. do nothing
+            } elsif ( !-r $realfile ) {
+                $removedfiles{"$realfile"} = $cvsworkfile;
+            } else {
+                ( -r "$cvsworkfile" )
+                  || die("Fehler: $cvsworkfile ist nicht lesbar");
+                if ( compare( $cvsworkfile, $realfile ) != 0 ) {
+                    $changedfiles{"$realfile"} = $cvsworkfile;
+                }
+            }
+        }
+
+        if (%removedfiles) {
+            print "deleted files (found in repository, but not in system):\n";
+            foreach my $key ( values %removedfiles ) {
                 print "$key\n";
             }
@@ -485,15 +573,64 @@
         }
 
-        if (%status_changedfiles) {
+        if (%changedfiles) {
             print "modified files:\n";
-            foreach my $key ( keys %status_changedfiles ) {
+            foreach my $key ( keys %changedfiles ) {
                 print "$key\n";
             }
         }
     } else {
-        print "no modified files found in $cvsworkdir\n";
-    }
+        print "no modified files found in $dir\n";
+    }
+
     print "\n";
-
+}
+
+
+
+sub permissions(@)
+{
+    check_parameter( @_, 1 );
+    check_env();
+
+    #
+    # update local repository
+    #
+    #svn_update();
+
+    # TODO: start at subdirectories ?
+    my $dir = $DASSCM_REPO;
+    my @files = svn_getStoredFiles($dir);
+
+    if (@files) {
+
+        # generieren der Permissions
+        my @permissions = generatePermissionList(@files);
+        my $OUTFILE;
+        my $tofile = 0;    # Status für schreiben in File
+        
+        if ( -w dirname($permissions_file) ) {
+
+            # Verzeichnis existiert => schreiben
+            print "storing permissions in file $permissions_file\n";
+            open( OUTFILE, ">$permissions_file" )
+              || die("failed to write to $permissions_file");
+            $tofile = 1;    # Merken, daß in File geschrieben wird
+            print OUTFILE "#\n";
+            print OUTFILE "# created by dasscm permissions\n";
+            print OUTFILE "# It is intended to be used for restoring permissions\n";
+        } else {
+
+            # Pfad für Sicherungsdatei existiert nicht => schreiben auf stdout
+            # Alias Filehandle für stdout erzeugen
+            *OUTFILE = *STDOUT;
+        }
+        foreach my $line (@permissions) {
+            print OUTFILE "$line\n";
+        }
+
+        if ($tofile) { 
+            close(OUTFILE);
+        }
+    }
 }
 
@@ -539,5 +676,5 @@
     # print options
     foreach my $option ( keys %options ) {
-        print $option. ": " . $options{$option} . "\n";
+        print "${option}: $options{$option}\n";
     }
 
@@ -559,4 +696,10 @@
         $command = "init";
         init(@ARGV);
+    } elsif (m/ls/i) {
+        $command = "ls";
+        ls(@ARGV);
+    } elsif (m/up/i) {
+        $command = "update";
+        update(@ARGV);
     } elsif (m/add/i) {
         $command = "add";
@@ -574,9 +717,9 @@
         $command = "status";
         status(@ARGV);
-
-        #     } elsif (m/activate/i) {
-        #         ## TODO
-        #         activate(@ARGV);
+    } elsif (m/permissions/i) {
+        $command = "permissions";
+        permissions(@ARGV);
     } else {
+        print "unknown command: $command\n\n";
         usage();
         check_env();
@@ -587,3 +730,4 @@
     # commitall
     # revert
-}
+    # activate
+}
