How to move a symlink to the trash? - cocoa

I don't see any options for the FSPathMoveObjectToTrashSync() function for not following links.
Here is what I have tried
Create a link and a file
[ 21:32:41 /tmp ] $ touch my_file
[ 21:32:45 /tmp ] $ ln -s my_file my_link
[ 21:32:52 /tmp ] $ la
total 8
drwxrwxrwt 12 root wheel 408 17 Maj 21:32 .
drwxr-xr-x# 6 root wheel 204 9 Sep 2009 ..
-rw-r--r-- 1 neoneye wheel 0 17 Maj 21:32 my_file
lrwxr-xr-x 1 neoneye wheel 7 17 Maj 21:32 my_link -> my_file
Move the link to the trash
OSStatus status = FSPathMoveObjectToTrashSync(
"/tmp/my_link",
NULL,
kFSFileOperationDefaultOptions
);
NSLog(#"status: %i", (int)status);
Output is
status: 0
However the file got removed and not the link
[ 21:32:55 /tmp ] $ la
total 8
drwxrwxrwt 11 root wheel 374 17 Maj 21:33 .
drwxr-xr-x# 6 root wheel 204 9 Sep 2009 ..
lrwxr-xr-x 1 neoneye wheel 7 17 Maj 21:32 my_link -> my_file
[ 21:33:05 /tmp ] $
How can I move move symlinks to the trash?
The Solution.. thanks to Rob Napier
NSString* path = #"/tmp/my_link";
OSStatus status = 0;
FSRef ref;
status = FSPathMakeRefWithOptions(
(const UInt8 *)[path fileSystemRepresentation],
kFSPathMakeRefDoNotFollowLeafSymlink,
&ref,
NULL
);
NSAssert((status == 0), #"failed to make FSRef");
status = FSMoveObjectToTrashSync(
&ref,
NULL,
kFSFileOperationDefaultOptions
);
NSLog(#"status: %i", (int)status);

Use FSPathMakeRefWithOptions() to generate an FSRef to the link. Then use FSMoveObjectToTrashSync() to delete it.

The other way would be to tell the NSWorkspace to “recycle” it, by sending it either a performFileOperation:source:destination:files:tag: message with the NSWorkspaceRecycleOperation operation or a recycleURLs:completionHandler: message.
I don't know how well either one of these would work on symlinks, but it's worth trying if you'd rather not deal with FSRefs.

my retro-futuristic approach
https://github.com/reklis/recycle
//
// main.swift
// recycle
//
// usage: recycle <files or directories to throw out>
//
import Foundation
import AppKit
var args = NSProcessInfo.processInfo().arguments
args.removeAtIndex(0) // first item in list is the program itself
var w = NSWorkspace.sharedWorkspace()
var fm = NSFileManager.defaultManager()
for arg in args {
let path = arg.stringByStandardizingPath;
let file = path.lastPathComponent
let source = path.stringByDeletingLastPathComponent
w.performFileOperation(NSWorkspaceRecycleOperation,
source:source,
destination: "",
files: [file],
tag: nil)
}

Related

how can find directory

when starting the tcl script a directory is created via a bash command. at the end of my script i want to read the directory name of the latest dirs. but my script does not find the newest directory but only the 2nd newest
bind pub "-|-" !aa pub:aaa
proc pub:aaa {nick host handle channel arg} {
set home "/home/user"
set bb [exec bash -c "start.sh"]
after 3000
set latest [exec bash -c "ls -td $home/jpg/*/ | head -n1"]
putnow "PRIVMSG $channel :$latest"
}
before starting it has the following folders in the directory:
drwxr-xr-x 2 user user 4096 Jun 24 18:30 aaa
drwxr-xr-x 2 user user 4096 Jun 24 18:14 bbb
after starting it has the following folders in the directory
drwxr-xr-x 2 user user 4096 Jun 24 18:30 aaa
drwxr-xr-x 2 user user 4096 Jun 24 18:14 bbb
drwxr-xr-x 2 user user 4096 Jun 24 18:35 ccc
output is :
<#testbot> aaa
it should be so
<#testbot> ccc
he finds the directory created during which the tcl script is not running
how can I display the newest, newly created directory?
regards
Instead of trying to exec out to a shell to find the most recently modified directory, I'd do it in pure tcl:
proc latest_directory {path {time mtime}} {
set dirs {}
foreach dir [glob -nocomplain -type d $path/*] {
file stat $dir s
lappend dirs $s($time) $dir
}
if {[llength $dirs] == 0} {
error "No directories found in $path"
} else {
return [lindex [lsort -integer -decreasing -stride 2 $dirs] 1]
}
}
# Then in pub:aaa
set latest [latest_directory $home/jpg]
As for why you're not getting ccc... hard to say for sure without seeing your start.sh script, but if it ends up running stuff in the background that continues after it exits, maybe it takes more than 3 seconds to create that directory?

<no location info>: error: can't find file

I am using haskell version 8.2.2 on a mac and currently have a problem to compile a file :
My terminal:
$ls
try.hs
$ ghc -o try try.hs
<no location info>: error: can't find file: try.hs
Terminal after ls -l :
total 0
-rw-rw-r--# 1 <> <> 0 Mar 23 15:54 try.hs
Terminal after ls -l# :
total 0
-rw-rw-r--# 1 <> <> 0 Mar 23 15:54 try.hs
com.apple.TextEncoding 15
com.apple.metadata:_kMDItemUserTags 42
com.apple.metadata:kMDLabel_z4p7jqbpj7dblx5lt33gtc742u 105
I suspect you have symlink'd a non-existent file to try.hs. Here is a sample of how things look in my test directory where I can see the same error as you:
% ls try.hs
try.hs
% ghc try.hs
<no location info>: error: can't find file: try.hs
% ls -l
total 0
lrwxrwxrwx. 1 <redacted> <redacted> 5 Mar 23 10:57 try.hs -> wrong
As you can see by the l at the beginning of the permissions and the -> wrong after the file name, here try.hs is a symlink to wrong. But there is no file named wrong.

Perl's retrieval of file create time incorrect

I am attempting to use perl to rename files based on the folder they are in and the time created. Files GOPR1521.MP4 and GOPR7754.MP4 were created on two different cameras at the same time and date, and I want to be able their names to indicate that. For example .../GoProTravisL/GOPR1521.mp4 created at 12:32:38 should become 123238L_GOPR1520.mp4, and GOPR7754.MP4 becomes 123239R_GOPR7754.MP4. Right now the only problem is the time stamps. I would think its a problem with being wrong timezone or hour offset, but the minutes are off too. Is there something in perl I am missing when getting time stamps? Below is the perl code, what it outputs for times for each file, and what Finder on OS X says the creation times are.
Code:
#!/usr/bin/perl
use Time::Piece;
use File::stat;
use File::Find;
use File::Basename;
use File::Spec;
#files = <$ARGV[0]/>;
find({ wanted => \&process_file, no_chdir => 1 }, #files);
sub process_file {
my($filename, $dirs, $suffix) = fileparse($_,qr/\.[^.]*/);
if ((-f $_) && ($filename ne "" )) {
#print "\n\nThis is a file: $_";
#print "\nFile: $filename";
#print "\nDIR: $dirs";
my(#parsedirs) = File::Spec->splitdir($dirs);
my #strippeddirs;
foreach my $element ( #parsedirs ) {
push #strippeddirs, $element if defined $element and $element ne '';
}
$pardir = pop(#strippeddirs);
#print "\nParse DIR: ", $pardir;
#print "\nFile creation time: ";
$timestamp = localtime(stat($_)->ctime)->strftime("%H%M%S"); #gives time stamp
print $timestamp;
$newname = $timestamp . substr($pardir,-1) ."_". $filename . $suffix;
print "\nRename: $dirs$filename$suffix to $dirs$newname\n";
#rename ($dirs . $filename . $suffix,$dirs . $newname) || die ( "Error in renaming: " . $! );
} else {
print "\n\nThis is not file: $_\n";
}
}
Output of time stamps for each file:
/Volumes/Scratch/Raw/2016-03-21/GoProTravisL/
File: GOPR1520
File creation time: 05-55-21
File: GOPR1521
File creation time: 05-56-18
File: GOPR1522
File creation time: 05-57-44
File: GOPR1523
File creation time: 05-58-49
File: GP011520
File creation time: 05-59-53
/Volumes/Scratch/Raw/2016-03-21/GoProTravisR
File: GOPR7754
File creation time: 06-02-48
File: GOPR7755
File creation time: 06-04-19
File: GOPR7756
File creation time: 06-06-27
File: GOPR7757
File creation time: 00-06-16
File: GP017754
File creation time: 00-19-30
File: GP027754
File creation time: 00-22-20
Actual file times using ls:
MacTravis:2016-03-21 travis$ ls -lR /Volumes/Scratch/Raw/2016-03-21
total 0
drwxr-xr-x 8 travis admin 272 Apr 9 21:25 GoProTravisL
drwxr-xr-x 9 travis admin 306 Apr 9 21:25 GoProTravisR
/Volumes/Scratch/Raw/2016-03-21/GoProTravisL:
total 21347376
-rw------- 1 travis admin 4001240088 Mar 21 12:04 GOPR1520.MP4
-rw------- 1 travis admin 1447364149 Mar 21 12:31 GOPR1521.MP4
-rw------- 1 travis admin 2140532053 Mar 21 12:45 GOPR1522.MP4
-rw------- 1 travis admin 1649133454 Mar 21 13:00 GOPR1523.MP4
-rw------- 1 travis admin 1691562945 Mar 21 12:21 GP011520.MP4
/Volumes/Scratch/Raw/2016-03-21/GoProTravisR:
total 31941008
-rw------- 1 travis admin 4001129586 Mar 21 12:04 GOPR7754.MP4
-rw------- 1 travis admin 2166255754 Mar 21 12:31 GOPR7755.MP4
-rw------- 1 travis admin 3202301883 Mar 21 12:45 GOPR7756.MP4
-rw------- 1 travis admin 2466803806 Mar 21 12:08 GOPR7757.MP4
-rw------- 1 travis admin 4001257192 Mar 21 11:27 GP017754.MP4
-rw------- 1 travis admin 516025454 Mar 21 11:29 GP027754.MP4
ctime is the "time of last status change", which I believe is the time the inode was last modified. It is NOT the file's creation time[1]. ls lists the file modification time, so simply change from using ctime to using mtime.
Historically, the time at which a file was created wasn't tracked by file systems used on unix file systems. Some newer file systems track it, but I am unsure how to access it (nor is it needed here).

mkdir recursion with permissions

It's a simple question, I'm writing a bash script called from cron grouping files in tar file and classifing into a dir structure.
These dir needs a special owner and permissions, and I call mkdir command thru su:
#!/bin/bash
... # shortened code
$PERMS=750
$DIR=/home/luser/0/01/012/0123
$OWNER=luser
... # shortened code
su -c "mkdir -m $PERMS -p $DIR" $OWNER
Output for ll -R /home/luser/0
/home/luser/0:
total 4
drwxr-xr-x 3 luser luser 4096 Jan 7 18:13 01
/home/luser/0/01:
total 4
drwxr-xr-x 3 luser luser 4096 Jan 7 18:13 012
/home/luser/0/01/012:
total 4
drwxr-x--- 2 luser luser 4096 Jan 7 18:13 0123
/home/luser/0/01/012/0123:
total 0
Only the deepest dir has permissions (750) setting rightly.
I don't know how deep it's the last directory and set permissions for all home's file it's too hard (too much files).
PS: I'm googled about that, but I find nothing.
You can restrict the permissions on the parent directories via umask. Here is an example:
PERMS=750
UMASK=$(echo "$PERMS" | tr "01234567" "76543210")
DIR=/home/luser/0/01/012/0123
OWNER=luser
su -c "umask $UMASK; mkdir -m $PERMS -p $DIR" $OWNER
In action:
> PERMS=750
> UMASK=$(echo "$PERMS" | tr "01234567" "76543210")
> (umask $UMASK; mkdir -m $PERMS -p 1/2/3/4)
> ll -R .
.:
drwxr-x--- 3 luser luser 4096 Jan 7 1:38 1/
./1:
drwxr-x--- 3 luser luser 4096 Jan 7 1:38 2/
./1/2:
drwxr-x--- 3 luser luser 4096 Jan 7 1:38 3/
./1/2/3:
drwxr-x--- 2 luser luser 4096 Jan 7 1:38 4/

Why does `Dir[directory_path].empty?` return `false` all the time?

Dir[directory_path].empty? returns false all the time. The behavior is the same whether or not I run irb as root:
$ ll
total 12
drwxrwxrwx 2 ndefontenay ndefontenay 4096 Aug 12 12:11 ./
drwxrwxrwx 4 ndefontenay ndefontenay 4096 Aug 5 11:45 ../
-rw-rw-r-- 1 ndefontenay ndefontenay 8 Aug 12 12:11 test
$ irb
> Dir["/opt/purge_entitlement/in"].empty?
=> false
> exit
$ sudo irb
> Dir["/opt/purge_entitlement/in"].empty?
=> false
If someone could shed some light on this problem, it would be pretty helpful.
Dir[].empty? returns false all the time
It should,because it always contains the parent directory (..), and the directory itself (.),that you didn't take care of.
This is not an answer to your question, but to avoid the problem of getting . and .. in the list, use Dir.glob instead of Dir.[]. You will probably get true for this:
Dir.glob("/opt/purge_entitlement/in/*").empty?

Resources