As I can see FileUtils.mv can only move directories within a filesystem so basically it is a rename. Is there another method that can also move between filesystems?
rename
is an atomic operation and a usual way of moving files on the same filesystem. when source and target are on different filesystems, there is no way to make the move atomic and avoid race conditions.
AFAIK stdlib doesn’t have mv
like opeation .
If you cannot use the rename
(because source and target are on different filesystems), instead of manually going through cumbersome process of finding the stats via File#info
, going through loop of reading, writing, changing attributes etc, i would suggest to use mv
utility via invoking the
system("mv src dest")
HIH
1 Like
Thanks. That would be a solution, but that also makes the code platform-dependent. (AFAIK On Windows the command would be move
)
In some other languages there is function that will hide the complexity of this operation.
e.g. I see in ruby the FileUtile.mv would do the trick. I am not sure if it is a good idea to have the same function do both, but IMHO it is a good idea to provide such a function.
1 Like
Totally with you. May I suggest you to please raise a RFC on github repo? That might help others to join the discussion and/or provide a patch for the same.
Quick search on github repo revealed below results:
opened 01:35AM - 14 May 19 UTC
kind:feature
topic:stdlib
Although it is not necessary for Crystal to mirror Ruby in every way, Ruby makes… an important distinction between `File.rename` and `FileUtils.mv`, which is the handling of files that are truly being moved (instead of simply renamed), in the sense of moving from one filesystem to another.
In this case, Ruby's `File.rename` will give a "Invalid cross-device link" error, but `FileUtils.mv` will do the right thing (copy and unlink, same as `/bin/mv`).
However, in Crystal, FileUtils.mv is just an alias of File.rename, which I did not expect. I also didn't see anything in File::Info that would help me compare the device ids of the source and target to determine whether I should rename or copy+unlink. So unless I missed something elsewhere in the API, I would need to shell out to `stat` to check the compare the device ids (or just use `/bin/mv`).
I looked through #5231 briefly and saw that FileUtils might go away, but if it does not, I was hoping that this could be changed.
Or at least, it would be helpful to expose the device id in File::Info. I tried to dig into this to see how File::Info works... I got as far as src/lib_c/aarch64-linux-gnu/c/sys/stat.cr but that's bit too low level for me.
opened 04:32PM - 23 Oct 16 UTC
closed 04:58PM - 24 Oct 16 UTC
- Make sure a similar issue doesn't exist yet: could not find an existing issue … related to `File.rename` and different filesystems.
- **Include reproducible code**: I have an external harddrive, which has a FAT32 filesystem. My OS is El Capitan 10.11.6. I'm doing a `File.rename(old_filename, new_filename)`, and it raises the following error:
```
Error renaming file '/Volumes/NEW VOLUME/Backup/Windows Installation/Downloads/q.mpl' to 'q.srt': Cross-device link (Errno)
[4299772722] *CallStack::unwind:Array(Pointer(Void)) +82
[4299772625] *CallStack#initialize:Array(Pointer(Void)) +17
[4299772584] *CallStack::new:CallStack +40
[4299753337] *raise<Errno>:NoReturn +25
[4299854086] *File::rename<String, String>:Int32 +182
[4299750576] __crystal_main +1168
[4299764136] main +40
```
- Include Crystal compiler version (`crystal -v`) and OS: `Crystal 0.19.4 (2016-10-07)`, os: El Capitan 10.11.6
- I've noticed in the implementation of `File.rename` that it delegates to LibC, haven't worked with it before, so I'm not sure if there's something that could be done about it. Maybe we could specify in the docs, that the renaming might fail across different filesystems?
Thank you for the great work you're doing on Crystal!
Unfortunately none of them addresses the cross filesystems move operation.
But its still worth a shot to re-raise this request and see how things goes
I raised a feature request
opened 04:11PM - 03 Jun 21 UTC
kind:feature
## Feature Request
- Is your feature request related to a problem? Please descr… ibe clearly and concisely what is it.
`FileUtils.mv` is an alias to `File.rename` and this works for same filesystem move operation, But will fail when moving between different filesystems.
- Describe the feature you would like, optionally illustrated by examples, and how it will solve the above problem.
Suggestion is to make `FileUtils.mv` behave like Ruby [FileUtils.mv](https://ruby-doc.org/stdlib-2.4.1/libdoc/fileutils/rdoc/FileUtils.html#method-c-mv).
- Describe considered alternative solutions, and the reasons why you have not proposed them as a solution here.
Simple solution would be to use `system("mv src dst")`, but that will be platform specific. This will works on *nix based system as they have `mv` command baked in, but on Windows it will not work, as Windows command line utility is called `move`.
- Does it break backward compatibility, if yes then what's the migration path?
No
Reference: https://forum.crystal-lang.org/t/move-directory-between-filesystems-invalid-cross-device-link/3341
Related issues: https://github.com/crystal-lang/crystal/issues/7777 , https://github.com/crystal-lang/crystal/issues/3461