]> arthur.barton.de Git - netatalk.git/blobdiff - libatalk/adouble/ad_open.c
Symlink patch from Anton Starikov
[netatalk.git] / libatalk / adouble / ad_open.c
index fe15d37c7415f8086e4ca3980681b2429d753f40..0c0e1cbb4cf06e31c0b68d6b6414ba1c4671448a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ad_open.c,v 1.56 2009-11-07 01:02:58 didg Exp $
+ * $Id: ad_open.c,v 1.60.2.1 2010-01-02 10:22:33 franklahm Exp $
  *
  * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu)
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
@@ -939,36 +939,46 @@ char
 {
     static char     modebuf[ MAXPATHLEN + 1];
     char        *slash;
-    size_t              len;
-
-    if ( (len = strlen( path )) >= MAXPATHLEN ) {
-        errno = ENAMETOOLONG;
-        return NULL;  /* can't do it */
-    }
-
     /*
      * For a path with directories in it, remove the final component
      * (path or subdirectory name) to get the name we want to stat.
      * For a path which is just a filename, use "." instead.
      */
-    strcpy( modebuf, path );
-    slash = strrchr( modebuf, '/' );
-    /* is last char a '/' */
-    if (slash && slash[1] == 0) {
-        while (modebuf < slash && slash[-1] == '/') {
-            --slash;
+    slash = strrchr( path, '/' );
+    if (slash) {
+        size_t len;
+
+        len = slash - path;
+        if (len >= MAXPATHLEN) {
+            errno = ENAMETOOLONG;
+            return NULL;  /* can't do it */
         }
-        if (modebuf < slash) {
+        memcpy( modebuf, path, len );
+        modebuf[len] = '\0';
+        /* is last char a '/' ? */
+        if (slash[1] == 0) {
+            slash = modebuf+ len;
+            /* remove them */
+            while (modebuf < slash && slash[-1] == '/') {
+                --slash;
+            }
+            if (modebuf == slash) {
+                goto use_cur;
+            }
+            *slash = '\0';
+            while (modebuf < slash && *slash != '/') {
+                --slash;
+            }
+            if (modebuf == slash) {
+                goto use_cur;
+            }
             *slash = '\0';      /* remove pathname component */
-            slash = strrchr( modebuf, '/' );
         }
+        return modebuf;
     }
-    if (slash) {
-        *slash = '\0';      /* remove pathname component */
-    } else {
-        modebuf[0] = '.';   /* use current directory */
-        modebuf[1] = '\0';
-    }
+use_cur:
+    modebuf[0] = '.';   /* use current directory */
+    modebuf[1] = '\0';
     return modebuf;
 }
 
@@ -998,8 +1008,8 @@ int ad_stat(const char *path, struct stat *stbuf)
     if (!p) {
         return -1;
     }
-
-    return stat( p, stbuf );
+//FIXME!
+    return lstat( p, stbuf );
 }
 
 /* ----------------
@@ -1168,18 +1178,30 @@ static struct adouble_fops ad_adouble = {
 
 void ad_init(struct adouble *ad, int flags, int options)
 {
-    memset( ad, 0, sizeof( struct adouble ) );
+    ad->ad_inited = 0;
     ad->ad_flags = flags;
     if (flags == AD_VERSION2_OSX) {
         ad->ad_ops = &ad_osx;
+        ad->ad_md = &ad->ad_resource_fork;
     }
     else if (flags == AD_VERSION1_SFM) {
         ad->ad_ops = &ad_sfm;
+        ad->ad_md = &ad->ad_metadata_fork;
     }
     else {
         ad->ad_ops = &ad_adouble;
+        ad->ad_md = &ad->ad_resource_fork;
     }
     ad->ad_options = options;
+
+    ad_data_fileno(ad) = -1;
+    ad_reso_fileno(ad) = -1;
+    ad_meta_fileno(ad) = -1;
+    /* following can be read even if there's no
+     * meda data.
+     */
+    memset(ad->ad_eid, 0, sizeof( ad->ad_eid ));
+    ad->ad_rlen = 0;
 }
 
 /* -------------------
@@ -1190,6 +1212,7 @@ int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble
 {
     struct stat         st_dir;
     struct stat         st_meta;
+    struct stat         st_link;
     struct stat         *pst = NULL;
     char        *ad_p;
     int         hoflags, admode;
@@ -1197,22 +1220,13 @@ int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble
     int                 open_df = 0;
 
     if (ad->ad_inited != AD_INITED) {
-        ad_data_fileno(ad) = -1;
-        ad_reso_fileno(ad) = -1;
-        adf_lock_init(&ad->ad_data_fork);
-        adf_lock_init(&ad->ad_resource_fork);
-        if (ad->ad_flags != AD_VERSION1_SFM) {
-            ad->ad_md = &ad->ad_resource_fork;
-        }
-        else {
-            adf_lock_init(&ad->ad_metadata_fork);
-            ad->ad_md = &ad->ad_metadata_fork;
-            ad_meta_fileno(ad) = -1;
-        }
         ad->ad_inited = AD_INITED;
         ad->ad_refcount = 1;
         ad->ad_open_forks = 0;
         ad->ad_adflags = adflags;
+        ad->ad_resource_fork.adf_refcount = 0;
+        ad->ad_data_fork.adf_refcount = 0;
+        ad->ad_data_fork.adf_syml=0;
     }
     else {
         ad->ad_open_forks = ((ad->ad_data_fork.adf_refcount > 0) ? ATTRBIT_DOPEN : 0);
@@ -1231,11 +1245,27 @@ int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble
                     admode = mode;
                 }
             }
-            ad->ad_data_fork.adf_fd =open( path, hoflags, admode );
+            lstat(path,&st_link);
+            if (S_ISLNK(st_link.st_mode) && (oflags == O_RDONLY)) {
+                int lsz;
+                ad->ad_data_fork.adf_syml=(char *)malloc(PATH_MAX+1);
+                lsz=readlink(path,ad->ad_data_fork.adf_syml,PATH_MAX);
+                if (lsz<=0) {
+                    free(ad->ad_data_fork.adf_syml);
+                    return -1;
+                }                
+                ad->ad_data_fork.adf_syml[lsz]=0;
+                ad->ad_data_fork.adf_syml=(char *)realloc(ad->ad_data_fork.adf_syml,lsz+1);
+                ad->ad_data_fork.adf_fd=0;
+            }else{
+                
+                ad->ad_data_fork.adf_fd =open( path, hoflags | O_NOFOLLOW, admode );
+            
             if (ad->ad_data_fork.adf_fd < 0 ) {
                 if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) {
                     hoflags = oflags;
-                    ad->ad_data_fork.adf_fd = open( path, hoflags, admode );
+                        ad->ad_data_fork.adf_fd = open( path, hoflags | O_NOFOLLOW, admode );
+                }
                 }
             }
             if ( ad->ad_data_fork.adf_fd < 0)
@@ -1247,6 +1277,7 @@ int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble
                 /* just created, set owner if admin (root) */
                 ad_chown(path, &st_dir);
             }
+            adf_lock_init(&ad->ad_data_fork);
         }
         else {
             /* the file is already open... but */
@@ -1288,17 +1319,19 @@ int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble
         goto sfm;
     }
 
+    memset(ad->ad_eid, 0, sizeof( ad->ad_eid ));
+    ad->ad_rlen = 0;
     ad_p = ad->ad_ops->ad_path( path, adflags );
 
     hoflags = oflags & ~(O_CREAT | O_EXCL);
     if (!(adflags & ADFLAGS_RDONLY)) {
         hoflags = (hoflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
     }
-    ad->ad_md->adf_fd = open( ad_p, hoflags, 0 );
+    ad->ad_md->adf_fd = open( ad_p, hoflags | O_NOFOLLOW, 0 );
     if (ad->ad_md->adf_fd < 0 ) {
         if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) {
             hoflags = oflags & ~(O_CREAT | O_EXCL);
-            ad->ad_md->adf_fd = open( ad_p, hoflags, 0 );
+            ad->ad_md->adf_fd = open( ad_p, hoflags | O_NOFOLLOW, 0 );
         }
     }
 
@@ -1356,8 +1389,8 @@ int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble
     }
     AD_SET(ad->ad_md->adf_off);
 
-    memset(ad->ad_eid, 0, sizeof( ad->ad_eid ));
-    ad->ad_md->adf_refcount++;
+    ad->ad_md->adf_refcount = 1;
+    adf_lock_init(ad->ad_md);
     if ((ad->ad_md->adf_flags & ( O_TRUNC | O_CREAT ))) {
         /*
          * This is a new adouble header file. Initialize the structure,
@@ -1412,8 +1445,6 @@ sfm:
 
     ad_p = ad->ad_ops->ad_path( path, ADFLAGS_RF );
 
-    hoflags = (oflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
-    ad->ad_resource_fork.adf_fd = open( ad_p, hoflags, admode );
     admode = mode;
     st_invalid = ad_mode_st(ad_p, &admode, &st_dir);
 
@@ -1421,6 +1452,9 @@ sfm:
         admode = mode;
     }
 
+    hoflags = (oflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR;
+    ad->ad_resource_fork.adf_fd = open( ad_p, hoflags, admode );
+
     if (ad->ad_resource_fork.adf_fd < 0 ) {
         if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) {
             hoflags = oflags;
@@ -1435,7 +1469,7 @@ sfm:
         errno = err;
         return -1;
     }
-
+    adf_lock_init(&ad->ad_resource_fork);
     AD_SET(ad->ad_resource_fork.adf_off);
     ad->ad_resource_fork.adf_flags = hoflags;
     if ((oflags & O_CREAT) && !st_invalid) {
@@ -1456,10 +1490,15 @@ int ad_metadata(const char *name, int flags, struct adouble *adp)
     uid_t uid;
     int   ret, err;
     int   dir = flags & ADFLAGS_DIR;
-
+    int   adouble = 0;
+    
+    if (!(flags & ADFLAGS_NOADOUBLE)) {
+      adouble = O_CREAT;
+    }
+    
     /* Open with O_CREAT, thus enumarating a dir will create missing adouble files, see: */
     /* http://marc.info/?l=netatalk-devel&m=124039156832408&w=2 */
-    if ((ret = ad_open(name, ADFLAGS_HF | dir, O_RDWR | O_CREAT, 0666, adp)) < 0 && errno == EACCES) {
+    if ((ret = ad_open(name, ADFLAGS_HF | dir, O_RDWR | adouble, 0666, adp)) < 0 && errno == EACCES) {
         uid = geteuid();
         if (seteuid(0)) {
             LOG(log_error, logtype_default, "ad_metadata(%s): seteuid failed %s", name, strerror(errno));
@@ -1545,7 +1584,7 @@ static int new_rfork(const char *path, struct adouble *ad, int adflags)
         memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort));
     }
 
-    if (stat(path, &st) < 0) {
+    if (lstat(path, &st) < 0) {
         return -1;
     }