Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postgres/src/backend/storage/ipc/   (Postgres Database Version 18.4©)  Datei vom 11.4.2026 mit Größe 39 kB image not shown  

Quelle  url.rs

  Sprache: Rust
 

#![cfg(feature = "std")]
#![cfg(unix)] // TODO: Use as_encoded_bytes/from_encoded_bytes_unchecked once in MSRV.
#![cfg(not(feature = "gnustep-1-7"))] // Doesn't seem to be available on GNUStep?
use core::ptr::NonNull;
use std::ffi::{CStr, CString, OsStr};
use std::os::unix::ffi::OsStrExt;
use std::path::{Path, PathBuf};

use objc2::rc::Retained;
use objc2::AnyThread;

use crate::NSURL;

const PATH_MAX: usize = 1024;

/// [`Path`] conversion.
impl NSURL {
    // FIXME(breaking): Make this private.
    pub fn from_path(
        path: &Path,
        is_directory: bool,
        // TODO: Expose this?
        base_url: Option<&NSURL>,
    ) -> Option<Retained<Self>> {
        // See comments in `CFURL::from_path`.
        let bytes = path.as_os_str().as_bytes();

        if bytes.is_empty() {
            // `initFileURLWithFileSystemRepresentation:isDirectory:relativeToURL:`,
            // checks this, but that's marked as non-null, so we'd get a panic
            // if we didn't implement the check manually ourselves.
            return None;
        }

        // TODO: Should we strip trailing \0 to fully match CoreFoundation?
        let cstr = CString::new(bytes).ok()?;
        let ptr = NonNull::new(cstr.as_ptr().cast_mut()).unwrap();

        // SAFETY: The pointer is a C string, and valid for the duration of
        // the call.
        Some(unsafe {
            Self::initFileURLWithFileSystemRepresentation_isDirectory_relativeToURL(
                Self::alloc(),
                ptr,
                is_directory,
                base_url,
            )
        })
    }

    /// Create a file url from a [`Path`].
    ///
    /// If the path is relative, it will be considered relative to the current
    /// directory.
    ///
    /// Returns `None` when given an invalid path (such as a path containing
    /// interior NUL bytes). The exact checks are not guaranteed.
    ///
    ///
    /// # Non-unicode and HFS+ support
    ///
    /// Modern Apple disk drives use APFS nowadays, which forces all paths to
    /// be valid unicode. The URL standard also uses unicode, and non-unicode
    /// parts of the URL will be percent-encoded, and the url will be given
    /// the scheme `file://`. All of this is as it should be.
    ///
    /// Unfortunately, a lot of Foundation APIs (including the `NSFileManager`
    /// and `NSData` APIs) currently assume that they can always get unicode
    /// paths _back_ by calling [`NSURL::path`] internally, which is not true.
    ///
    /// If you need to support non-unicode paths in HFS+ with these APIs, you
    /// can work around this issue by percent-encoding any non-unicode parts
    /// of the path yourself beforehand, similar to [what's done in the
    /// `trash-rs` crate](https://github.com/Byron/trash-rs/pull/127).
    /// (this function cannot do that for you, since it relies on a quirk of
    /// HFS+ that b"\xf8" and b"%F8" refer to the same file).
    ///
    ///
    /// # Examples
    ///
    /// ```
    /// use std::path::Path;
    /// use objc2_foundation::NSURL;
    ///
    /// // Absolute paths work as you'd expect.
    /// let url = NSURL::from_file_path("/tmp/file.txt").unwrap();
    /// assert_eq!(url.to_file_path().unwrap(), Path::new("/tmp/file.txt"));
    ///
    /// // Relative paths are relative to the current directory.
    /// let url = NSURL::from_file_path("foo.txt").unwrap();
    /// assert_eq!(url.to_file_path().unwrap(), std::env::current_dir().unwrap().join("foo.txt"));
    ///
    /// // Some invalid paths return `None`.
    /// assert!(NSURL::from_file_path("").is_none());
    /// // Another example of an invalid path containing interior NUL bytes.
    /// assert!(NSURL::from_file_path("/a/\0a").is_none());
    /// ```
    #[inline]
    #[doc(alias = "fileURLWithFileSystemRepresentation:isDirectory:relativeToURL:")]
    #[doc(alias = "initFileURLWithFileSystemRepresentation:isDirectory:relativeToURL:")]
    pub fn from_file_path<P: AsRef<Path>>(path: P) -> Option<Retained<Self>> {
        Self::from_path(path.as_ref(), false, None)
    }

    /// Create a directory url from a [`Path`].
    ///
    /// This differs from [`from_file_path`][Self::from_file_path] in that the
    /// path is treated as a directory, which means that other normalization
    /// rules are applied to it (to make it end with a `/`).
    ///
    ///
    /// # Examples
    ///
    /// ```
    /// use std::path::Path;
    /// use objc2_foundation::NSURL;
    ///
    /// // Directory paths get trailing slashes appended
    /// let url = NSURL::from_directory_path("/Library").unwrap();
    /// assert_eq!(url.to_file_path().unwrap(), Path::new("/Library/"));
    ///
    /// // Unless they already have them.
    /// let url = NSURL::from_directory_path("/Library/").unwrap();
    /// assert_eq!(url.to_file_path().unwrap(), Path::new("/Library/"));
    ///
    /// // Similarly for relative paths.
    /// let url = NSURL::from_directory_path("foo").unwrap();
    /// assert_eq!(url.to_file_path().unwrap(), std::env::current_dir().unwrap().join("foo/"));
    ///
    /// // Various dots may be stripped.
    /// let url = NSURL::from_directory_path("/Library/././.").unwrap();
    /// assert_eq!(url.to_file_path().unwrap(), Path::new("/Library/"));
    ///
    /// // Though of course not if they have semantic meaning.
    /// let url = NSURL::from_directory_path("/Library/..").unwrap();
    /// assert_eq!(url.to_file_path().unwrap(), Path::new("/Library/.."));
    /// ```
    #[inline]
    #[doc(alias = "fileURLWithFileSystemRepresentation:isDirectory:relativeToURL:")]
    #[doc(alias = "initFileURLWithFileSystemRepresentation:isDirectory:relativeToURL:")]
    pub fn from_directory_path<P: AsRef<Path>>(path: P) -> Option<Retained<Self>> {
        Self::from_path(path.as_ref(), true, None)
    }

    /// Extract the path part of the URL as a `PathBuf`.
    ///
    /// This will return a path regardless of [`isFileURL`][Self::isFileURL].
    /// It is the responsibility of the caller to ensure that the URL is valid
    /// to use as a file URL.
    ///
    ///
    /// # Compatibility note
    ///
    /// This currently does not work for non-unicode paths (which are fairly
    /// rare on macOS since HFS+ was been superseded by APFS).
    ///
    /// This also currently always returns absolute paths (it converts
    /// relative URL paths to absolute), but that may change in the future.
    ///
    ///
    /// # Examples
    ///
    /// ```
    /// use std::path::Path;
    /// use objc2_foundation::{NSURL, NSString};
    ///
    /// let url = unsafe { NSURL::URLWithString(&NSString::from_str("file:///tmp/foo.txt")).unwrap() };
    /// assert_eq!(url.to_file_path().unwrap(), Path::new("/tmp/foo.txt"));
    /// ```
    ///
    /// See also the examples in [`from_file_path`][Self::from_file_path].
    #[doc(alias = "getFileSystemRepresentation:maxLength:")]
    #[doc(alias = "fileSystemRepresentation")]
    pub fn to_file_path(&self) -> Option<PathBuf> {
        let mut buf = [0u8; PATH_MAX];
        let ptr = NonNull::new(buf.as_mut_ptr()).unwrap().cast();
        // SAFETY: The provided buffer is valid.
        // We prefer getFileSystemRepresentation:maxLength: over
        // `fileSystemRepresentation`, since the former is guaranteed to
        // handle internal NUL bytes (even if there probably won't be any,
        // NSURL seems to avoid that by construction).
        let result = unsafe { self.getFileSystemRepresentation_maxLength(ptr, buf.len()) };
        if !result {
            return None;
        }

        // SAFETY: Foundation is guaranteed to null-terminate the buffer if
        // the function succeeded.
        let cstr = unsafe { CStr::from_bytes_until_nul(&buf).unwrap_unchecked() };

        let path = OsStr::from_bytes(cstr.to_bytes());
        Some(PathBuf::from(path))
    }
}

// See also CFURL's tests, they're a bit more exhaustive.
#[cfg(test)]
#[cfg(unix)]
mod tests {
    use std::os::unix::ffi::OsStrExt;

    use super::*;

    #[test]
    fn invalid_path() {
        assert_eq!(NSURL::from_file_path(""), None);
        assert_eq!(NSURL::from_file_path("/\0/a"), None);
    }

    #[test]
    fn roundtrip() {
        let path = Path::new(OsStr::from_bytes(b"/abc/def"));
        let url = NSURL::from_file_path(path).unwrap();
        assert_eq!(url.to_file_path().unwrap(), path);

        let path = Path::new(OsStr::from_bytes(b"/\x08"));
        let url = NSURL::from_file_path(path).unwrap();
        assert_eq!(url.to_file_path().unwrap(), path);

        // Non-unicode
        let path = Path::new(OsStr::from_bytes(b"/\x08"));
        let url = NSURL::from_file_path(path).unwrap();
        assert_eq!(url.to_file_path().unwrap(), path);
    }

    #[test]
    #[cfg(all(feature = "NSData", feature = "NSFileManager", feature = "NSError"))]
    #[ignore = "needs HFS+ file system"]
    fn special_paths() {
        use crate::{NSData, NSFileManager};

        let manager = NSFileManager::defaultManager();

        let path = Path::new(OsStr::from_bytes(b"\xf8"));
        // Foundation is broken, needs a different encoding to work.
        let url = NSURL::from_file_path("%F8").unwrap();

        // Create, read and remove file, using different APIs.
        std::fs::write(path, "").unwrap();
        assert_eq!(NSData::dataWithContentsOfURL(&url), Some(NSData::new()));
        manager.removeItemAtURL_error(&url).unwrap();
    }

    // Useful when testing HFS+ and non-UTF-8:
    // echo > $(echo "0000000: f8" | xxd -r)
}

Messung V0.5 in Prozent
C=47 H=91 G=72

¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet am  2026-08-25) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.