]> arthur.barton.de Git - netatalk.git/blobdiff - libatalk/util/unix.c
Merge from branch-2-1
[netatalk.git] / libatalk / util / unix.c
index beb9ab5a3fe2958eb02e9ab7a7ea69d6d40277a6..1c131ad507c9712a4de3a18f8648795b89c950ef 100644 (file)
@@ -1,5 +1,4 @@
 /*
-  $Id: unix.c,v 1.1 2010-01-05 13:48:47 franklahm Exp $
   Copyright (c) 2010 Frank Lahm <franklahm@gmail.com>
 
   This program is free software; you can redistribute it and/or modify
   GNU General Public License for more details.
 */
 
+/*!
+ * @file
+ * Netatalk utility functions
+ */
+
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif /* HAVE_CONFIG_H */
 #include <atalk/ea.h>
 #include <atalk/afp.h>
 #include <atalk/logger.h>
-#include <atalk/volume.h>
 #include <atalk/vfs.h>
 #include <atalk/util.h>
 #include <atalk/unix.h>
 
-extern const char *getcwdpath(void)
+/*!
+ * @brief get cwd in static buffer
+ *
+ * @returns pointer to path or pointer to error messages on error
+ */
+const char *getcwdpath(void)
 {
     static char cwd[MAXPATHLEN + 1];
     char *p;
 
-    if ((p = getcwd(&cwd, MAXPATHLEN)) != NULL)
+    if ((p = getcwd(cwd, MAXPATHLEN)) != NULL)
         return p;
     else
         return strerror(errno);
 }
+
+/*!
+ * Takes a buffer with a path, strips slashs, returns basename
+ *
+ * @param p (rw) path
+ *        path may be
+ *          "[/][dir/[...]]file"
+ *        or
+ *          "[/][dir/[...]]dir/[/]"
+ *        Result is "file" or "dir" 
+ *
+ * @returns pointer to basename in path buffer, buffer is possibly modified
+ */
+char *stripped_slashes_basename(char *p)
+{
+    int i = strlen(p) - 1;
+    while (i > 0 && p[i] == '/')
+        p[i--] = 0;
+    return (strrchr(p, '/') ? strrchr(p, '/') + 1 : p);
+}
+
+/*!
+ * @brief symlink safe chdir replacement
+ *
+ * Only chdirs to dir if it doesn't contain symlinks.
+ *
+ * @returns 1 if a path element is a symlink, 0 otherwise, -1 on syserror
+ */
+int lchdir(const char *dir)
+{
+    char buf[MAXPATHLEN+1];
+    char cwd[MAXPATHLEN+1];
+    char *test;
+    int  i;
+
+    /*
+     dir is a canonical path (without "../" "./" "//" )
+     but may end with a / 
+    */
+    *cwd = 0;
+    if (*dir != '/') {
+        if (getcwd(cwd, MAXPATHLEN) == NULL)
+            return -1;
+    }
+    if (chdir(dir) != 0)
+        return -1;
+
+    /* 
+     * Cases:
+     * chdir request   | realpath result | ret
+     * (after getwcwd) |                 |
+     * =======================================
+     * /a/b/.          | /a/b            | 0
+     * /a/b/.          | /c              | 1
+     * /a/b/.          | /c/d/e/f        | 1
+     */
+    if (getcwd(buf, MAXPATHLEN) == NULL)
+        return 1;
+
+    i = 0;
+    if (*cwd) {
+        /* relative path requested, 
+         * Same directory?
+        */
+        for (; cwd[i]; i++) {
+            if (buf[i] != cwd[i])
+                return 1;
+        }
+        if (buf[i]) {
+            if (buf[i] != '/')
+                return 1;
+            i++;
+        }                    
+    }
+
+    test = &buf[i];    
+    for (i = 0; test[i]; i++) {
+        if (test[i] != dir[i]) {
+            return 1;
+        }
+    }
+    /* trailing '/' ? */
+    if (!dir[i])
+        return 0;
+
+    if (dir[i] != '/')
+        return 1;
+
+    i++;
+    if (dir[i])
+        return 1;
+
+    return 0;
+}