]> arthur.barton.de Git - netatalk.git/blobdiff - libatalk/adouble/ad_open.c
Merge symlink branch
[netatalk.git] / libatalk / adouble / ad_open.c
index 2e1d9d856e8e35d6558bcea877451b69accca218..2785cbf17848f8b790f13d5c0d23cc033781b415 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ad_open.c,v 1.58 2009-11-12 09:39:46 didg Exp $
+ * $Id: ad_open.c,v 1.69 2010-02-10 14:05:37 franklahm Exp $
  *
  * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu)
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  *  +1-313-763-0525
  *  netatalk@itd.umich.edu
  *
- * NOTE: I don't use inline because a good compiler should be
- * able to optimize all the static below. Didier
+ */
+
+/*!
+ * @file
+ * Part of Netatalk's AppleDouble implementatation
+ * @note We don't use inlines because a good compiler should be
+ *       able to optimize all the static funcs below.
+ * @sa include/atalk/adouble.h
  */
 
 #ifdef HAVE_CONFIG_H
@@ -1008,8 +1014,8 @@ int ad_stat(const char *path, struct stat *stbuf)
     if (!p) {
         return -1;
     }
-
-    return stat( p, stbuf );
+//FIXME!
+    return lstat( p, stbuf );
 }
 
 /* ----------------
@@ -1031,7 +1037,7 @@ static int ad_chown(const char *path, struct stat *stbuf)
     if (default_uid != (uid_t)-1) {
         /* we are root (admin) */
         id = (default_uid)?default_uid:stbuf->st_uid;
-        ret = chown( path, id, stbuf->st_gid );
+        ret = lchown( path, id, stbuf->st_gid );
     }
 #endif
     return ret;
@@ -1074,9 +1080,8 @@ ad_mkdir( const char *path, int mode)
     int st_invalid;
     struct stat stbuf;
 
-#ifdef DEBUG
-    LOG(log_debug9, logtype_default, "ad_mkdir: Creating directory with mode %d", mode);
-#endif
+    LOG(log_debug, logtype_default, "ad_mkdir: creating ad-directory '%s/%s' with mode %04o",
+        getcwdpath(), path, mode);
 
     st_invalid = ad_mode_st(path, &mode, &stbuf);
     ret = mkdir( path, mode );
@@ -1204,9 +1209,44 @@ void ad_init(struct adouble *ad, int flags, int options)
     ad->ad_rlen = 0;
 }
 
-/* -------------------
- * It's not possible to open the header file O_RDONLY -- the read
- * will fail and return an error. this refcounts things now.
+/*!
+ * Open data-, metadata(header)- or ressource fork
+ *
+ * You must call ad_init() before ad_open, usually you'll just call it like this: \n
+ * @code
+ *      struct adoube ad;
+ *      ad_init(&ad, vol->v_adouble, vol->v_ad_options);
+ * @endcode
+ *
+ * @param path    Path to file or directory
+ *
+ * @param adflags ADFLAGS_DF: open data file/fork\n
+ *                ADFLAGS_HF: open header (metadata) file\n
+ *                ADFLAGS_RF: open ressource fork *** FIXME: not used ?! *** \n
+ *                ADFLAGS_CREATE: indicate creation\n
+ *                ADFLAGS_NOHF: it's not an error if header file couldn't be created\n
+ *                ADFLAGS_DIR: if path is a directory you MUST or ADFLAGS_DIR to adflags\n
+ *                ADFLAGS_NOADOUBLE: dont create adouble files if not necessary\n
+ *                ADFLAGS_RDONLY: open read only\n
+ *                ADFLAGS_OPENFORKS: check for open forks from other processes\n
+ *                ADFLAGS_MD: alias for ADFLAGS_HF\n
+ *                ADFLAGS_V1COMPAT: obsolete
+ *
+ * @param oflags  flags passed through to open syscall: \n
+ *                O_RDONLY: *** FIXME *** \n
+ *                O_RDWR: *** FIXME *** \n
+ *                O_CREAT: create fork\n
+ *                O_EXCL: fail if exists with O_CREAT
+ *
+ * @param mode    passed to open with O_CREAT
+ *
+ * @param ad      pointer to struct adouble
+ *
+ * @returns 0 on success
+ *
+ * @note It's not possible to open the header file O_RDONLY -- the read
+ *       will fail and return an error. this refcounts things now.\n
+ *       metadata(ressource)-fork only gets created with O_CREAT.
  */
 int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble  *ad)
 {
@@ -1225,6 +1265,7 @@ int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble
         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);
@@ -1243,13 +1284,33 @@ 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 );
+                
+            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 && errno == ELOOP) {
+                    int lsz;
+
+                    if (oflags != O_RDONLY)
+                         return -1;
+
+                    ad->ad_data_fork.adf_syml = 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 = realloc(ad->ad_data_fork.adf_syml,lsz+1);
+                    // XX
+                    ad->ad_data_fork.adf_fd = 0;
                 }
             }
+
             if ( ad->ad_data_fork.adf_fd < 0)
                 return -1;
 
@@ -1309,11 +1370,11 @@ int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble
     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 );
         }
     }
 
@@ -1324,6 +1385,7 @@ int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble
              * here.
              * if ((oflags & O_CREAT) ==> (oflags & O_RDWR)
              */
+            LOG(log_debug, logtype_default, "ad_open: creating new adouble file: %s/%s", getcwdpath(), ad_p);
             admode = mode;
             errno = 0;
             st_invalid = ad_mode_st(ad_p, &admode, &st_dir);
@@ -1331,7 +1393,7 @@ int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble
                 admode = mode;
             }
             admode = ad_hf_mode(admode);
-            if ( errno == ENOENT && !(adflags & ADFLAGS_NOADOUBLE) && ad->ad_flags != AD_VERSION2_OSX) {
+            if ((errno == ENOENT) && (ad->ad_flags != AD_VERSION2_OSX)) {
                 if (ad->ad_ops->ad_mkrf( ad_p) < 0) {
                     return ad_error(ad, adflags);
                 }
@@ -1427,8 +1489,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);
 
@@ -1436,6 +1496,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;
@@ -1463,18 +1526,34 @@ sfm:
     return 0 ;
 }
 
-/* -----------------------------------
- * return only metadata but try very hard
+/*!
+ * @brief open metadata, possibly as root
+ *
+ * Return only metadata but try very hard ie at first try as user, then try as root.
+ *
+ * @param name  name of file/dir
+ * @param flags ADFLAGS_DIR: name is a directory \n
+ *              ADFLAGS_CREATE: force creation of header file, but only as use, not as root
+ * @param adp   pointer to struct adouble
+ *
+ * @note caller MUST pass ADFLAGS_DIR for directories. Whether ADFLAGS_CREATE really creates
+ *       a adouble file depends on various other volume options, eg. ADVOL_CACHE
  */
 int ad_metadata(const char *name, int flags, struct adouble *adp)
 {
     uid_t uid;
-    int   ret, err;
-    int   dir = flags & ADFLAGS_DIR;
+    int   ret, err, dir;
+    int   create = 0;
+
+    dir = flags & ADFLAGS_DIR;
+
+    /* Check if we shall call ad_open with O_CREAT */
+    if ( (adp->ad_options & ADVOL_CACHE)
+         && ! (adp->ad_options & ADVOL_NOADOUBLE)
+         && (flags & ADFLAGS_CREATE) )
+        create = 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 | create, 0666, adp)) < 0 && errno == EACCES) {
         uid = geteuid();
         if (seteuid(0)) {
             LOG(log_error, logtype_default, "ad_metadata(%s): seteuid failed %s", name, strerror(errno));
@@ -1560,7 +1639,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;
     }