macOS: copying a file on a SMB filesystem - swift

I have a RAID disk which makes its files available over CIFS/SMB. If I copy a large file (600MB) from one location on the volume to another location on the same volume using Finder (i.e., option-drag the file), it only takes a second or two.
If I try to do the same operation programmatically using the code below, it takes upwards of a minute.
let source = URL(filePath: "/Volumes/media/tmp/bigfile.dat")
let dest = URL(filePath: "/Volumes/media/finaldest/file.dat")
try FileManager.default.copyItem(at: source, to: dest)
My theory is that Finder can detect that the source and destination are on the same network volume and uses a special SMB API to do the copying server side, without having to move a bunch of bytes back and forth over the network. FileManager does not have this same optimization.
Does anybody have suggestions on how I can make my program behave like the Finder does?

Related

How to get list of files in iCloud container with swift?

After hours of hard work I could implement iCloud storage to my macOS app.
My container is displayed in iCloud. The name of the folder is correct. I can store generated pdf to all folders, but...
... I can't get a list of files of a certain folder inside this iCloud container.
I use this little snippet of code
let manager = FileManager.default
let driveURL = manager.url(forUbiquityContainerIdentifier: nil)?.appending(path: "Documents").appending(path:"Import")
try? manager.createDirectory(at: driveURL!, withIntermediateDirectories: true, attributes: [:])
let files = manager.enumerator(atPath: driveURL!.absoluteString)
files ist always empty (nil), because the folder Import doesn't exist (what's wrong, because it's there). And it should be created, if not exists.
Do I miss some settings to my project, to get access to my own folders? Or is there another, different way to get reading access?

Using ZIPFoundation without URL

In my MacOS app I am downloading an encrypted .zip file to the disk. I decrypt this file and keep the decrypted version in memory in the Data type. For security reasons the decrypted .zip will only be kept in memory.
I can successfully use ZIPFoundation's Closure based reading to extract the file contents in memory, but only by using an URL pointing to the (decrypted) .zip on disk:
guard let archive = Archive(url: url!, accessMode: .read) else { return }
Is there any way I can use the library with data only existing in memory? If not, can you point me towards a library that can handle this?
I have already tried DataCompression, but I couldn't make it work.
There's a (non-merged) Pull Request open that adds in-memory processing of ZIP archives to ZIP Foundation.
Sadly there are still some unresolved issues with in-memory writing of archives. The reading part is using fmemopen and should already work.
While the PR is not finished yet, you can have a look here: https://github.com/weichsel/ZIPFoundation/pull/78/

Where do files go when you delete them programatically with swift?

Where do files go when you delete them programatically? I deleted them with this code, but the Trash for today is empty. Is it possible to retrieve them?
let filemgr = NSFileManager.defaultManager()
do{
let filelist = try filemgr.contentsOfDirectoryAtPath(fontFolderPath)
for filename in filelist {
do{ try filemgr.removeItemAtPath(fontFolderPath+filename)} catch{}
}
}catch{}
Using the URL related API of NSFileManager you have two options:
func removeItemAtURL(_ URL: NSURL) throws
deletes the item immediately like /bin/rm in Terminal.app and has the same functionality as removeItemAtPath.
func trashItemAtURL(_ url: NSURL,
resultingItemURL outResultingURL: AutoreleasingUnsafeMutablePointer<NSURL?>) throws
moves the item to the trash folder returning the item’s location in the trash via the inout pointer.
The removeItemAtPath method deletes them. They're gone. If you want to move something to the trash, you need to use NSWorkSpace. You can see an example of moving an entire directory to the trash here: Move directory to trash
basically unixy systems manage files the same way, there is a ref count, that is the number of hard links + times the file is open... So you can rm an open file, and the file will still exist, you can write to it, and read from it, with a valid file descriptor or FILE * stream object, then when it is closed the file will actually be removed from the disk...
int fd = open("somefile", O_RDWR);
unlink("somefile"); // removes somefile from the directory listing, but not disk
write(fd, "hello", 5);
lseek(fd,0,SEEK_SET); // seek to start of file
char buffer[6] = {0};
read(fd,buffer,5); // reads in "hello"
close(fd); // last reference removed, file is removed.
if you want to move a file to the Trash, that is a different operation and specific to OS X and iOS

Sinatra example code to download a large file

I started using sinatra,
Right now I'm using the following code to handle file downloads,
It works great for small files, but when it comes to large files > 500MB
The connection disconnects in the middle.
dpath = "/some root path to file"
get '/getfile/:path' do |path|
s = path.to_s
s.gsub!("-*-","/")
fn = s.split("/").last
s = dpath +"/"+ s
send_file s,:filename => fn
end
Two things:
What does your validate method do? If it's trying to open the file in memory, you might be running out of ram on your server (especially with large files).
Where are you setting fn ? It's a local variable inside the get scope and there's nothing setting it in your code example.

Why does this code work successfully with Enumerator.fromFile?

I wrote the file transferring code as follows:
val fileContent: Enumerator[Array[Byte]] = Enumerator.fromFile(file)
val size = file.length.toString
file.delete // (1) THE FILE IS TEMPORARY SO SHOULD BE DELETED
SimpleResult(
header = ResponseHeader(200, Map(CONTENT_LENGTH -> size, CONTENT_TYPE -> "application/pdf")),
body = fileContent)
This code works successfully, even if the file size is rather large (2.6 MB),
but I'm confused because my understanding about .fromFile() is a wrapper of fromCallBack() and SimpleResult actually reads the file buffred,but the file is deleted before that.
MY easy assumption is that java.io.File.delete waits until the file gets released after the chunk reading completed, but I have never heard of that process of Java File class,
Or .fromFile() has already loaded all lines to the Enumerator instance, but it's against the fromCallBack() spec, I think.
Does anybody knows about this mechanism?
I'm guessing you are on some kind of a Unix system, OSX or Linux for example.
On a Unix:y system you can actually delete a file that is open, any filesystem entry is just a link to the actual file, and so is a file handle which you get when you open a file. The file contents won't become unreachable /deleted until the last link to it is removed.
So: it will no longer show up in the filesystem after you do file.delete but you can still read it using the InputStream that was created in Enumerator.fromFile(file) since that created a file handle. (On Linux you actually can find it through the special /proc filesystem which, among other things, contains the filehandles of each running process)
On windows I think you will get an error though, so if it is to run on multiple platforms you should probably check test your webapp on windows as well.